]> Repositorios git - scryer-prolog.git/commitdiff
Add phrase_from_stream/2 to library(pio)
authorbakaq <[email protected]>
Fri, 22 Sep 2023 00:06:02 +0000 (21:06 -0300)
committerbakaq <[email protected]>
Sun, 24 Sep 2023 17:32:44 +0000 (14:32 -0300)
src/lib/pio.pl

index fdc5bcb1e75d58afec99705b2dd49f9cdeb685a3..781f14c8e3ea1d59825ee7e3d6cff1a22c360249 100644 (file)
@@ -9,6 +9,7 @@
 
 :- module(pio, [phrase_from_file/2,
                 phrase_from_file/3,
+                phrase_from_stream/2,
                 phrase_to_file/2,
                 phrase_to_file/3,
                 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, maplist/2]).
+:- use_module(library(gensym)).
+:- use_module(library(iso_ext), [
+    bb_get/2, bb_put/2, setup_call_cleanup/3, partial_string/3, partial_string_tail/2
+]).
+:- use_module(library(lists), [length/2, member/2, maplist/2]).
 :- use_module(library(charsio), [get_n_chars/3]).
 
 :- meta_predicate(phrase_from_file(2, ?)).
 :- meta_predicate(phrase_from_file(2, ?, ?)).
+:- meta_predicate(phrase_from_stream(2, ?)).
 :- meta_predicate(phrase_to_file(2, ?)).
 :- meta_predicate(phrase_to_file(2, ?, ?)).
 :- meta_predicate(phrase_to_stream(2, ?)).
 
+
+%% phrase_from_stream(+GRBody, +Stream)
+%
+%  True if grammar rule body GRBody covers the contents of the stream,
+%  represented as a list of characters.
+
+phrase_from_stream(GRBody, Stream) :-
+    stream_to_lazy_list(Stream, Ls),
+    phrase(GRBody, Ls).
+
 %% phrase_from_file(+GRBody, +File)
 %
 %  True if grammar rule body GRBody covers the contents of File,
@@ -49,24 +64,147 @@ phrase_from_file(NT, File, Options) :-
         ;   Type = text
         ),
         setup_call_cleanup(open(File, read, Stream, [reposition(true)|Options]),
-                           (   stream_to_lazy_list(Stream, Xs),
-                               phrase(NT, Xs) ),
+                           phrase_from_stream(NT, Stream),
                            close(Stream))
-   ).
-
+    ).
 
 stream_to_lazy_list(Stream, Xs) :-
-        stream_property(Stream, position(Pos)),
-        freeze(Xs, reader_step(Stream, Pos, Xs)).
-
-reader_step(Stream, Pos, Xs0) :-
-        set_stream_position(Stream, Pos),
-        (   at_end_of_stream(Stream)
-        ->  Xs0 = []
-        ;   get_n_chars(Stream, 4096, Cs),
-            partial_string(Cs, Xs0, Xs),
-            stream_to_lazy_list(Stream, Xs)
-        ).
+    stream_property(Stream, reposition(Rep)),
+    (   Rep = true ->
+        stream_to_lazy_list_repositionable(Stream, Xs)
+    ;   stream_to_lazy_list_buffer(Stream, Xs)
+    ).
+
+stream_to_lazy_list_repositionable(Stream, Xs) :-
+    stream_property(Stream, position(Pos)),
+    freeze(Xs, reader_step_repositionable(Stream, Pos, Xs)).
+
+reader_step_repositionable(Stream, Pos, Xs0) :-
+    set_stream_position(Stream, Pos),
+    (   at_end_of_stream(Stream)
+    ->  Xs0 = []
+    ;   get_n_chars(Stream, 4096, Cs),
+        partial_string(Cs, Xs0, Xs),
+        stream_to_lazy_list_repositionable(Stream, Xs)
+    ).
+
+stream_to_lazy_list_buffer(Stream, Ls) :-
+    get_stream_buffer_position(Stream, Pos),
+    freeze(Ls, render_step_buffer(Stream, Pos, Ls)).
+
+render_step_buffer(Stream, Pos, Ls) :-
+    set_stream_buffer_position(Stream, Pos),
+    (   buffer_at_end_of_stream(Stream) ->
+        Ls = []
+    ;   buffer_get_n_chars(Stream, 4096, Chars),
+        partial_string(Chars, Ls, Ls0),
+        stream_to_lazy_list_buffer(Stream, Ls0)
+    ).
+
+buffer_at_end_of_stream(Stream) :-
+    stream_bufferids(Stream, _, BufferPosId, _),
+    bb_get(BufferPosId, Pos),
+    Pos = eof.
+
+get_stream_buffer_position(Stream, Pos) :-
+    stream_bufferids(Stream, _, BufferPosId, _),
+    bb_get(BufferPosId, Pos).
+
+set_stream_buffer_position(Stream, Pos) :-
+    stream_bufferids(Stream, _, BufferPosId, _),
+    bb_put(BufferPosId, Pos).
+
+buffer_get_n_chars(Stream, N, Chars) :-
+    stream_bufferids(Stream, BufferId, BufferPosId, BufferLenId),
+    buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N),
+    bb_get(BufferId, Buffer),
+    bb_get(BufferPosId, BufferPos),
+    (   BufferPos = eof ->
+        Chars = []
+    ;   string_get_n_chars(Buffer, BufferPos, N, Chars),
+        length(Chars, NChars),
+        (   NChars = 0 ->
+            BufferPos1 = eof
+        ;   BufferPos1 is BufferPos + NChars
+        ),
+        bb_put(BufferPosId, BufferPos1)
+    ).
+
+buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N) :-
+    bb_get(BufferPosId, BufferPos),
+    bb_get(BufferLenId, BufferLen),
+    (   BufferLen < BufferPos + N ->
+        bb_get(BufferId, Buffer),
+        (
+            (   var(Buffer) ->
+                BufferTail = Buffer
+            ;   partial_string_last_tail(Buffer, BufferTail)
+            ) ->
+            (   at_end_of_stream(Stream) ->
+                BufferTail = [],
+                bb_put(BufferId, Buffer)
+            ;   get_n_chars(Stream, 4096, Chars),
+                length(Chars, NChars),
+                partial_string(Chars, BufferTail, _),
+                bb_put(BufferId, Buffer),
+                BufferLen1 is BufferLen + NChars,
+                bb_put(BufferLenId, BufferLen1),
+                buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N)
+            )
+        ;   true
+        )
+    ;   true
+    ).
+
+partial_string_last_tail(PartialString, PartialStringTail) :-
+    partial_string_tail(PartialString, PartialStringTail0),
+    (   var(PartialStringTail0) ->
+        PartialStringTail = PartialStringTail0
+    ;   partial_string_last_tail(PartialStringTail0, PartialStringTail)
+    ).
+
+string_get_n_chars([], _, _, []).
+string_get_n_chars([S|Ss], BufferPos, N, Chars) :-
+    (   BufferPos = 0 ->
+        string_get_n_chars_([S|Ss], N, Chars)
+    ;   BufferPos1 is BufferPos - 1,
+        string_get_n_chars(Ss, BufferPos1, N, Chars)
+    ).
+
+string_get_n_chars_([], _, []).
+string_get_n_chars_([S|Ss], N, Chars) :-
+    (   N = 0 ->
+        Chars = []
+    ;   N = 1 ->
+        % This case is needed to not break the tail of the partial string
+        Chars = [S]
+    ;   Chars = [S|Cs],
+        N1 is N - 1,
+        string_get_n_chars_(Ss, N1, Cs)
+    ).
+
+stream_bufferids(Stream, BufferId, BufferPosId, BufferLenId) :-
+    (   bb_get(streams_buffers, _) ->
+        true
+    ;   bb_put(streams_buffers, [])
+    ),
+    bb_get(streams_buffers, StreamsBuffers),
+    (   member(
+            stream_buffer(Stream, BufferId, BufferPosId, BufferLenId),
+            StreamsBuffers
+        ) ->
+        true
+    ;   gensym(buffer, BufferId),
+        gensym(buffer_pos, BufferPosId),
+        gensym(buffer_len, BufferLenId),
+        bb_put(
+            streams_buffers,
+            [stream_buffer(Stream, BufferId, BufferPosId, BufferLenId)|StreamsBuffers]
+        ),
+        bb_put(BufferId, _),
+        bb_put(BufferPosId, 0),
+        bb_put(BufferLenId, 0)
+    ).
 
 %% phrase_to_stream(+GRBody, +Stream)
 %