[m-dev.] for discussion: stream library v2
Peter Ross
petdr at miscrit.be
Wed Sep 27 20:42:34 AEDT 2000
Here is my final (?) implementation of a stream library.
Let me know what you think of this design, and then I will clean it all
up and get it ready for inclusion in the standard library.
Pete
-------------- next part --------------
%-----------------------------------------------------------------------------%
% Copyright (C) 2000 The University of Melbourne.
% This file may only be copied under the terms of the GNU Library General
% Public License - see the file COPYING.LIB
%-----------------------------------------------------------------------------%
%
% File: lowlevel.m.
% Main author: petdr
% Stability: exceptionally low.
%
% An impure interface for describing streams.
% We also provide an implementation for read/write one character which
% can be used to define a highlevel stream interface.
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module lowlevel.
:- interface.
:- import_module stream.
:- import_module char.
:- type lowlevel(S) ---> lowlevel(S).
:- typeclass lowlevel(S) where [
% Did an error occur processing the stream?
semipure pred lowlevel__is_error(S::ui, string::out) is semidet
].
:- typeclass lowlevel__input(S) <= lowlevel(S) where [
% Read one character from the stream described by S.
% Fail if we reach eof or some error condition.
impure pred lowlevel__read_char(S::ui, char::out) is semidet,
% Have we reached the eof for S?
semipure pred lowlevel__is_eof(S::ui) is semidet
].
:- typeclass lowlevel__output(S) <= lowlevel(S) where [
% Read one character from the current stream.
impure pred lowlevel__write_char(S::ui, char::in) is semidet
].
:- typeclass lowlevel__duplex(S)
<= (lowlevel__input(S), lowlevel__output(S)) where [].
%-----------------------------------------------------------------------------%
% Define read/write one character whose signatures obey the
% constraints of the highlevel stream type class.
:- pred low_read_char(stream__result(char),
lowlevel(S), lowlevel(S)) <= lowlevel__input(S).
:- mode low_read_char(out, di, uo) is det.
:- pred low_write_char(char, lowlevel(S), lowlevel(S)) <= lowlevel__output(S).
:- mode low_write_char(in, di, uo) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module exception.
:- pragma promise_pure(low_read_char/3).
low_read_char(Result, lowlevel(Stream), FinalStream) :-
( impure lowlevel__read_char(Stream, Chr) ->
FinalStream = lowlevel(Stream),
Result = ok(Chr)
;
( semipure lowlevel__is_error(Stream, Error) ->
FinalStream = lowlevel(Stream),
Result = error(Error)
; semipure lowlevel__is_eof(Stream) ->
FinalStream = lowlevel(Stream),
Result = eof
;
FinalStream = lowlevel(Stream),
Error = "stream not in eof or error state but read char failed.",
Result = error(Error)
)
).
%-----------------------------------------------------------------------------%
:- pragma promise_pure(low_write_char/3).
low_write_char(Chr, lowlevel(Stream), FinalStream) :-
( impure lowlevel__write_char(Stream, Chr) ->
FinalStream = lowlevel(Stream)
;
( semipure lowlevel__is_error(Stream, Err0) ->
Err = Err0
;
Err = "stream__write_char failed but there is no error message"
),
FinalStream = lowlevel(Stream),
throw(stream_error(Err))
).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
-------------- next part --------------
%-----------------------------------------------------------------------------%
% Copyright (C) 2000 The University of Melbourne.
% This file may only be copied under the terms of the GNU Library General
% Public License - see the file COPYING.LIB
%-----------------------------------------------------------------------------%
%
% File: highlevel.m.
% Main author: petdr
% Stability: exceptionally low.
%
% A pure interface for describing streams.
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module highlevel.
:- interface.
:- import_module lowlevel, stream.
:- import_module char.
:- typeclass highlevel(S) where [
].
:- typeclass highlevel__input(S) <= highlevel(S) where [
% Read one character from the stream S.
pred highlevel__read_char(stream__result(char), S, S),
mode highlevel__read_char(out, di, uo) is det
].
:- typeclass highlevel__output(S) <= highlevel(S) where [
% Write one character to the stream S.
pred highlevel__write_char(char, S, S),
mode highlevel__write_char(in, di, uo) is det
].
:- typeclass highlevel__duplex(S)
<= (highlevel__input(S), highlevel__output(S)) where [].
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
-------------- next part --------------
%-----------------------------------------------------------------------------%*
% Copyright (C) 2000 The University of Melbourne.
% This file may only be copied under the terms of the GNU Library General
% Public License - see the file COPYING.LIB
%-----------------------------------------------------------------------------%
%
% File: stream.m.
% Main author: petdr
% Stability: exceptionally high.
%
% This file provides interfaces for stream based I/O.
% This interface is built on top of the pure interface defined in
% highlevel.m
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module stream.
:- interface.
:- import_module highlevel.
:- import_module char, io, list.
% The state of the world for one stream of type S.
:- type stream(S).
% The type of exceptions thrown by this module.
:- type stream_error ---> stream_error(string).
:- type stream__result(T)
---> ok(T)
; eof
; error(string)
.
:- type stream__result
---> ok
; eof
; error(string)
.
% Given a handle to a stream construct a unique stream object
% which can be used to do IO on the stream.
% This object initialises its state of the world from the
% io__state. XXX This isn't such a good idea for string streams,
% but is for other streams.
:- pred stream__init(S::in, stream(S)::uo, io__state::di, io__state::uo) is det.
%-----------------------------------------------------------------------------%
% Predicates which require an input stream.
% Read one character from the input stream.
:- pred stream__read_char(stream__result(char)::out,
stream(S)::di, stream(S)::uo) is det <= highlevel__input(S).
% Putback one character into the input stream.
% You can putback as many characters as required.
:- pred stream__putback_char(char::in,
stream(S)::di, stream(S)::uo) is det <= highlevel__input(S).
% Reads a whitespace delimited word from the current input stream.
:- pred stream__read_word(stream__result(list(char)),
stream(S), stream(S)) <= highlevel__input(S).
:- mode stream__read_word(out, di, uo) is det.
% Reads one line of input from the current input stream.
:- pred stream__read_line(stream__result(list(char)),
stream(S), stream(S)) <= highlevel__input(S).
:- mode stream__read_line(out, di, uo) is det.
% Discards all the whitespace from the current stream.
:- pred stream__ignore_whitespace(stream__result,
stream(S), stream(S)) <= highlevel__input(S).
:- mode stream__ignore_whitespace(out, di, uo) is det.
%-----------------------------------------------------------------------------%
% Predicates which require an output stream.
% On failure these predicates will throw an stream_error exception.
% Write one char to the output stream.
:- pred stream__write_char(char::in,
stream(S)::di, stream(S)::uo) is det <= highlevel__output(S).
% Write the string to the output stream.
:- pred stream__write_string(string,
stream(S), stream(S)) <= highlevel__output(S).
:- mode stream__write_string(in, di, uo) is det.
%-----------------------------------------------------------------------------%
% Echo the input stream to the output stream.
:- pred stream__cat(stream(S)::di, stream(S)::uo,
stream(T)::di, stream(T)::uo) is det <=
(highlevel__input(S), highlevel__output(T)).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module exception, string.
:- type stream(S)
---> stream(
S, % Handle on the stream
list(char) % Putback characters
).
stream__init(S, stream(Stream, [])) --> { copy(S, Stream) }.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
stream__read_char(Result, stream(Stream0, PutbackChars),
stream(Stream, NewPutbackChars)) :-
(
PutbackChars = [],
highlevel__read_char(Result, Stream0, Stream),
NewPutbackChars = PutbackChars
;
PutbackChars = [Chr | NewPutbackChars],
Stream = Stream0,
Result = ok(Chr)
).
%-----------------------------------------------------------------------------%
stream__putback_char(Chr, stream(Stream, PutbackChars),
stream(Stream, [UniqueChr | PutbackChars])) :-
copy(Chr, UniqueChr).
%-----------------------------------------------------------------------------%
stream__write_char(Chr, stream(Stream0, Cs), stream(Stream, Cs)) :-
highlevel__write_char(Chr, Stream0, Stream).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
stream__read_word(Result) -->
stream__ignore_whitespace(WSResult),
(
{ WSResult = error(Error) },
{ Result = error(Error) }
;
{ WSResult = eof },
{ Result = eof }
;
{ WSResult = ok },
stream__read_word_2(Result)
).
:- pred read_word_2(stream__result(list(char)),
stream(S), stream(S)) <= highlevel__input(S).
:- mode read_word_2(out, di, uo) is det.
read_word_2(Result) -->
stream__read_char(CharResult),
(
{ CharResult = error(Error) },
{ Result = error(Error) }
;
{ CharResult = eof },
{ Result = eof }
;
{ CharResult = ok(Char) },
( { char__is_whitespace(Char) } ->
stream__putback_char(Char),
{ Result = ok([]) }
;
read_word_2(Result0),
(
{ Result0 = ok(Chars) },
{ Result = ok([Char | Chars]) }
;
{ Result0 = error(_) },
{ Result = Result0 }
;
{ Result0 = eof },
{ Result = ok([Char]) }
)
)
).
read_line(Result) -->
stream__read_char(CharResult),
(
{ CharResult = error(Error) },
{ Result = error(Error) }
;
{ CharResult = eof },
{ Result = eof }
;
{ CharResult = ok(Char) },
( { Char = '\n' } ->
{ Result = ok([Char]) }
;
read_line(Result0),
(
{ Result0 = ok(Chars) },
{ Result = ok([Char | Chars]) }
;
{ Result0 = error(_) },
{ Result = Result0 }
;
{ Result0 = eof },
{ Result = ok([Char]) }
)
)
).
stream__ignore_whitespace(Result) -->
stream__read_char(CharResult),
(
{ CharResult = error(Error) },
{ Result = error(Error) }
;
{ CharResult = eof },
{ Result = eof }
;
{ CharResult = ok(Char) },
( { char__is_whitespace(Char) } ->
stream__ignore_whitespace(Result)
;
stream__putback_char(Char),
{ Result = ok }
)
).
%-----------------------------------------------------------------------------%
stream__write_string(String) -->
{ string__to_char_list(String, CharList) },
list__foldl(stream__write_char, CharList).
%-----------------------------------------------------------------------------%
stream__cat(S0, S) -->
{ stream__read_char(Result, S0, S1) },
(
{ Result = ok(Char) },
stream__write_char(Char),
cat(S1, S)
;
{ Result = eof },
{ S = S1 }
;
{ Result = error(String) },
{ throw(stream_error(
string__format("stream__cat: %s.", [s(String)]))) }
).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
-------------- next part --------------
%-----------------------------------------------------------------------------%
% Copyright (C) 2000 The University of Melbourne.
% This file may only be copied under the terms of the GNU Library General
% Public License - see the file COPYING.LIB
%-----------------------------------------------------------------------------%
%
% File: stdio.m
% Main author: petdr
% Stability: exceptionally low.
%
% A stdin/stdout stream.
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module stdio.
:- interface.
:- import_module highlevel.
:- type stdio.
:- type stdio_stream == lowlevel(stdio).
:- instance highlevel(stdio_stream).
:- instance highlevel__input(stdio_stream).
:- instance highlevel__output(stdio_stream).
:- instance highlevel__duplex(stdio_stream).
:- pred stdio_stream(stdio_stream::uo) is det.
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module lowlevel.
:- import_module char.
:- type stdio ---> stdio.
stdio_stream(lowlevel(stdio)).
% Define the high-level operations using the generic operations
% from the lowlevel module.
:- instance highlevel(stdio_stream) where [].
:- instance highlevel__input(stdio_stream) where [
pred(read_char/3) is low_read_char
].
:- instance highlevel__output(stdio_stream) where [
pred(write_char/3) is low_write_char
].
:- instance highlevel__duplex(stdio_stream) where [].
% Define the lowlevel operations
:- instance lowlevel(stdio) where [
pred(lowlevel__is_error/2) is stdio__is_error
].
:- instance lowlevel__input(stdio) where [
pred(lowlevel__read_char/2) is stdio__read_char,
pred(lowlevel__is_eof/1) is stdio__is_eof
].
:- instance lowlevel__output(stdio) where [
pred(lowlevel__write_char/2) is stdio__write_char
].
:- instance lowlevel__duplex(stdio) where [].
%-----------------------------------------------------------------------------%
:- pred stdio__read_char(stdio::ui, char::out) is semidet.
:- pragma c_code(stdio__read_char(_File::ui, Chr::out),
[will_not_call_mercury, thread_safe], "{
int chr;
chr = fgetc(stdin);
if (chr == EOF) {
SUCCESS_INDICATOR = FALSE;
} else {
SUCCESS_INDICATOR = TRUE;
Chr = chr;
}
}").
%-----------------------------------------------------------------------------%
:- pred stdio__write_char(stdio::ui, char::in) is semidet.
:- pragma c_code(stdio__write_char(_File::ui, Chr::in),
[will_not_call_mercury, thread_safe], "{
if (fputc(Chr, stdout) == EOF) {
SUCCESS_INDICATOR = FALSE;
} else {
SUCCESS_INDICATOR = TRUE;
}
}").
%-----------------------------------------------------------------------------%
:- pragma c_header_code("#include <errno.h>").
:- pred stdio__is_error(stdio::ui, string::out) is semidet.
:- pragma c_code(stdio__is_error(_File::ui, Msg::out),
[will_not_call_mercury, thread_safe], "{
if (ferror(stdin) || ferror(stdout)) {
SUCCESS_INDICATOR = TRUE;
save_transient_hp();
MR_make_aligned_string_copy(Msg, strerror(errno));
restore_transient_hp();
} else {
SUCCESS_INDICATOR = FALSE;
}
}").
:- pred stdio__is_eof(stdio::ui) is semidet.
:- pragma c_code(stdio__is_eof(_File::ui),
[will_not_call_mercury, thread_safe], "{
if (feof(stdin)) {
SUCCESS_INDICATOR = TRUE;
} else {
SUCCESS_INDICATOR = FALSE;
}
}").
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
-------------- next part --------------
:- module main.
:- interface.
:- import_module io.
:- pred main(io__state::di, io__state::uo) is det.
:- implementation.
:- import_module stdio, stream.
:- import_module list.
main -->
io__write_string("Hello world.\n"),
{ stdio_stream(StdioStream) },
stream__init(StdioStream, Stream),
{ generic_io(Stream, _) }.
:- pred generic_io(stream(S)::di, stream(S)::uo) is det <= highlevel__output(S).
generic_io -->
stream__write_string("Hello world from stream library.\n").
More information about the developers
mailing list