From: Markus Triska Date: Sun, 7 Nov 2021 16:02:41 +0000 (+0100) Subject: ADDED: phrase_to_stream/2, writing a list of characters to a stream. X-Git-Tag: v0.9.0~30^2~7 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=893fb0e3ccd34830abaf5ce49870109a9afa217d;p=scryer-prolog.git ADDED: phrase_to_stream/2, writing a list of characters to a stream. --- diff --git a/src/lib/pio.pl b/src/lib/pio.pl index 7755918f..67e4ea34 100644 --- a/src/lib/pio.pl +++ b/src/lib/pio.pl @@ -1,17 +1,19 @@ :- module(pio, [phrase_from_file/2, phrase_from_file/3, - phrase_to_file/2]). + phrase_to_file/2, + phrase_to_stream/2 + ]). :- use_module(library(dcgs)). :- use_module(library(error)). :- use_module(library(freeze)). -:- use_module(library(iso_ext), [setup_call_cleanup/3, partial_string/3]). -:- use_module(library(lists), [member/2]). -:- use_module(library(format), [format/3]). +:- use_module(library(iso_ext), [setup_call_cleanup/3, partial_string/1, partial_string/3]). +:- use_module(library(lists), [member/2, maplist/2]). :- meta_predicate(phrase_from_file(2, ?)). :- meta_predicate(phrase_from_file(2, ?, ?)). :- meta_predicate(phrase_to_file(2, ?)). +:- meta_predicate(phrase_to_stream(2, ?)). phrase_from_file(NT, File) :- phrase_from_file(NT, File, []). @@ -46,13 +48,12 @@ reader_step(Stream, Pos, Xs0) :- ). /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - phrase_to_file(+GRBody, +File) + phrase_to_stream(+GRBody, +Stream) Emit the list of characters described by the grammar rule body - GRBody to File. File is a string, which is also the representation - used by library(files) to test for existence etc. of files. + GRBody to Stream. - An ideal implementation of phrase_to_file/2 writes each character + An ideal implementation of phrase_to_stream/2 writes each character as soon as it becomes known and no choice-points remain, and thus avoids the manifestation of the entire string in memory. See #691 for more information. @@ -64,9 +65,31 @@ reader_step(Stream, Pos, Xs0) :- represented in memory, and thus covers a large number of use cases. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +phrase_to_stream(GRBody, Stream) :- + phrase(GRBody, Cs), + ( partial_string(Cs) -> % very efficiently check for a string + true % (success is the expected case here) + ; must_be(list, Cs), + maplist(must_be(character), Cs) + ), + ( stream_property(Stream, type(binary)) -> + ( '$first_non_octet'(Cs, N) -> + domain_error(byte_char, N, phrase_to_stream/2) + ; true + ) + ; true + ), + % we use a specialised internal predicate that uses only a + % single "write" operation for efficiency. It is equivalent to + % maplist(put_char(Stream), Cs). It also works for binary streams. + '$put_chars'(Stream, Cs). + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + phrase_to_file(+GRBody, +File), writing the string described + by GRBody to File. +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + phrase_to_file(GRBody, File) :- - atom_chars(Atom, File), - phrase(GRBody, Chars), - setup_call_cleanup(open(Atom, write, Stream), - format(Stream, "~s", [Chars]), + setup_call_cleanup(open(File, write, Stream), + phrase_to_stream(GRBody, Stream), close(Stream)).