]> Repositorios git - scryer-prolog.git/commitdiff
add flush_output/{0,1}, past_end_of_stream
authorMark Thom <[email protected]>
Tue, 5 May 2020 20:10:49 +0000 (14:10 -0600)
committerMark Thom <[email protected]>
Tue, 5 May 2020 20:10:49 +0000 (14:10 -0600)
src/prolog/clause_types.rs
src/prolog/lib/builtins.pl
src/prolog/machine/copier.rs
src/prolog/machine/heap.rs
src/prolog/machine/machine_indices.rs
src/prolog/machine/machine_state.rs
src/prolog/machine/streams.rs
src/prolog/machine/system_calls.rs

index e6f577e74e7bdf1d4691418e1997f1961a7fe996..bb39a35ea8118381af806fcdd7e90049662a2b95 100644 (file)
@@ -181,6 +181,7 @@ pub enum SystemClauseType {
     FetchGlobalVar,
     FetchGlobalVarWithOffset,
     FileToChars,
+    FlushOutput,
     GetChar,
     GetSingleChar,
     ResetAttrVarState,
@@ -325,6 +326,7 @@ impl SystemClauseType {
                 clause_name!("$fetch_global_var_with_offset")
             }
             &SystemClauseType::FileToChars => clause_name!("$file_to_chars"),
+            &SystemClauseType::FlushOutput => clause_name!("$flush_output"),
             &SystemClauseType::GetChar => clause_name!("$get_char"),
             &SystemClauseType::GetSingleChar => clause_name!("$get_single_char"),
             &SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
@@ -468,6 +470,7 @@ impl SystemClauseType {
             ("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
             ("$current_input", 1) => Some(SystemClauseType::CurrentInput),
             ("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
+            ("$flush_output", 1) => Some(SystemClauseType::FlushOutput),
             ("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
             ("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
             ("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef),
index f1f20f8ca2d5125ba5016469bf4472b69b1263b3..31cfa75d7ec8ea37dce839f76d820b2824b9ffbf 100644 (file)
@@ -48,13 +48,14 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
                      current_op/3, current_predicate/1,
                      current_prolog_flag/2, expand_goal/2,
                      expand_term/2, fail/0, false/0, findall/3,
-                     findall/4, get_char/1, halt/0, max_arity/1,
-                     number_chars/2, number_codes/2, once/1, op/3,
-                     open/3, open/4, read_term/2, read_term/3,
-                     repeat/0, retract/1, set_prolog_flag/2,
-                     set_input/1, set_output/1, setof/3, sub_atom/5,
-                     subsumes_term/2, term_variables/2, throw/1,
-                     true/0, unify_with_occurs_check/2, write/1,
+                     findall/4, flush_output/0, flush_output/1,
+                     get_char/1, halt/0, max_arity/1, number_chars/2,
+                     number_codes/2, once/1, op/3, open/3, open/4,
+                     read_term/2, read_term/3, repeat/0, retract/1,
+                     set_prolog_flag/2, set_input/1, set_output/1,
+                     setof/3, sub_atom/5, subsumes_term/2,
+                     term_variables/2, throw/1, true/0,
+                     unify_with_occurs_check/2, write/1,
                      write_canonical/1, write_term/2, write_term/3,
                      writeq/1]).
 
@@ -1180,4 +1181,12 @@ close(Stream, CloseOptions) :-
     '$close'(Stream, CloseOptions).
 
 close(Stream) :-
-    close(Stream, []).
+    '$close'(Stream, []).
+
+
+flush_output(S) :-
+    '$flush_output'(S).
+
+flush_output :-
+    current_output(S),
+    '$flush_output'(S).
index 08c41944317370932d170824ad2c7f8c7e5c2908..dd86173186636a3cd1711f93f317e359257b95b1 100644 (file)
@@ -1,6 +1,5 @@
 use crate::prolog::machine::machine_indices::*;
 use crate::prolog::machine::stack::*;
-use crate::prolog::machine::streams::*;
 
 use std::mem;
 use std::ops::IndexMut;
@@ -215,24 +214,6 @@ impl<T: CopierTarget> CopyTermState<T> {
         }
     }
 
-    fn copy_stream(&mut self, addr: usize) {
-        let threshold = self.target.threshold();
-
-        let trail_item = mem::replace(
-            &mut self.target[addr],
-            HeapCellValue::Addr(Addr::Stream(threshold)),
-        );
-
-        self.trail.push((
-            Ref::HeapCell(addr),
-            trail_item,
-        ));
-
-        self.target.push(HeapCellValue::Stream(Stream::null_stream()));
-
-        self.scan += 1;
-    }
-
     fn copy_structure(&mut self, addr: usize) {
         match self.target[addr].context_free_clone() {
             HeapCellValue::NamedStr(arity, name, fixity) => {
@@ -285,11 +266,12 @@ impl<T: CopierTarget> CopyTermState<T> {
                                 *self.value_at_scan() = HeapCellValue::Addr(addr);
                             }
                         }
-                        Addr::Lis(h) if h >= self.old_h => {
-                            self.scan += 1;
-                        }
                         Addr::Lis(h) => {
-                            self.copy_list(h);
+                            if h >= self.old_h {
+                                self.scan += 1;
+                            } else {
+                                self.copy_list(h);
+                            }
                         }
                         addr @ Addr::AttrVar(_) |
                         addr @ Addr::HeapCell(_) |
@@ -303,7 +285,7 @@ impl<T: CopierTarget> CopyTermState<T> {
                             self.copy_partial_string(addr, n);
                         }
                         Addr::Stream(h) => {
-                            self.copy_stream(h);
+                            *self.value_at_scan() = self.target[h].context_free_clone();
                         }
                         _ => {
                             self.scan += 1;
index 3e813fe8faaeadec608083a320f33ffe6339bb62..718cbfe3926a878f4b27eaa28b788e9c670858dc 100644 (file)
@@ -288,10 +288,10 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
             HeapCellValue::Addr(addr) => {
                 addr
             }
-            val @ HeapCellValue::Atom(..)
-          | val @ HeapCellValue::Integer(_)
-          | val @ HeapCellValue::DBRef(_)
-          | val @ HeapCellValue::Rational(_) => {
+            val @ HeapCellValue::Atom(..) |
+            val @ HeapCellValue::Integer(_) |
+            val @ HeapCellValue::DBRef(_) |
+            val @ HeapCellValue::Rational(_) => {
                 Addr::Con(self.push(val))
             }
             val @ HeapCellValue::NamedStr(..) => {
index cb43359c56cfffd2729eda6c7a9dc7bde8120e10..58ee66befc324885feb55d7bff3df79b3d2a391f 100644 (file)
@@ -443,8 +443,8 @@ impl HeapCellValue {
             &HeapCellValue::PartialString(ref pstr, has_tail) => {
                 HeapCellValue::PartialString(pstr.clone(), has_tail)
             }
-            &HeapCellValue::Stream(_) => {
-                HeapCellValue::Stream(Stream::null_stream())
+            &HeapCellValue::Stream(ref stream) => {
+                HeapCellValue::Stream(stream.clone())
             }
             &HeapCellValue::TcpListener(_) => {
                 HeapCellValue::Atom(clause_name!("$socket_server"), None)
index 691d1374213d6f4acccb31262a91e2994af027d1..e58a04ece6dc747ef7aa9e24843e2b9e3418f708 100644 (file)
@@ -619,6 +619,32 @@ impl MachineState {
         stream: Stream,
         indices: &mut IndexStore,
     ) -> CallResult {
+        let opt_err =
+            if !stream.is_input_stream() {
+                Some("stream") // 8.14.2.3 g)
+            } else if stream.options.stream_type == StreamType::Binary {
+                Some("binary_stream") // 8.14.2.3 h)
+            } else {
+                None
+            };
+
+        if let Some(err_string) = opt_err {
+            let stub = MachineError::functor_stub(clause_name!("read_term"), 3);
+
+            let addr = vec![
+                HeapCellValue::Stream(stream)
+            ];
+
+            let err = MachineError::permission_error(
+                self.heap.h(),
+                Permission::InputStream,
+                err_string,
+                addr,
+            );
+
+            return Err(self.error_form(err, stub));
+        }
+
         let mut orig_stream = stream.clone();
         let mut stream = self.open_parsing_stream(stream, "read_term", 3)?;
 
index e4df47346d322cb1e60d09c97686bd8d9e390ccc..3f09d6d102199be455307f6a3ad92ffa4dca7e0d 100644 (file)
@@ -37,7 +37,6 @@ pub enum StreamInstance {
     OutputFile(File),
     Null,
     ReadlineStream(ReadlineStream),
-    // Stdin,
     Stdout,
     TcpStream(TcpStream),
 }
@@ -154,6 +153,7 @@ impl Default for StreamOptions {
 
 #[derive(Debug, Clone, Hash)]
 pub struct Stream {
+    past_end_of_stream: bool,
     pub options: StreamOptions,
     stream_inst: WrappedStreamInstance,
 }
@@ -172,45 +172,25 @@ impl From<TcpStream> for Stream {
         tcp_stream.set_read_timeout(None).unwrap();
         tcp_stream.set_write_timeout(None).unwrap();
 
-        Stream {
-            options: StreamOptions::default(),
-            stream_inst: WrappedStreamInstance::new(
-                StreamInstance::TcpStream(tcp_stream)
-            )
-        }
+        Stream::from_inst(StreamInstance::TcpStream(tcp_stream))
     }
 }
 
 impl From<String> for Stream {
     fn from(string: String) -> Self {
-        Stream {
-            options: StreamOptions::default(),
-            stream_inst: WrappedStreamInstance::new(
-                StreamInstance::Bytes(Cursor::new(string.into_bytes()))
-            )
-        }
+        Stream::from_inst(StreamInstance::Bytes(Cursor::new(string.into_bytes())))
     }
 }
 
 impl From<ReadlineStream> for Stream {
     fn from(rl_stream: ReadlineStream) -> Self {
-        Stream {
-            options: StreamOptions::default(),
-            stream_inst: WrappedStreamInstance::new(
-                StreamInstance::ReadlineStream(rl_stream)
-            ),
-        }
+        Stream::from_inst(StreamInstance::ReadlineStream(rl_stream))
     }
 }
 
 impl From<&'static str> for Stream {
     fn from(src: &'static str) -> Stream {
-        Stream {
-            options: StreamOptions::default(),
-            stream_inst: WrappedStreamInstance::new(
-                StreamInstance::DynReadSource(Box::new(src.as_bytes()))
-            ),
-        }
+        Stream::from_inst(StreamInstance::DynReadSource(Box::new(src.as_bytes())))
     }
 }
 
@@ -230,60 +210,30 @@ impl Stream {
     }
 
     #[inline]
-    pub(crate)
-    fn stdout() -> Self {
-        Stream {
-            options: StreamOptions::default(),
-            stream_inst: WrappedStreamInstance::new(
-                StreamInstance::Stdout
-            ),
-        }
-    }
-
-    #[inline]
-    pub(crate)
-    fn from_file_as_output(file: File) -> Self {
+    fn from_inst(stream_inst: StreamInstance) -> Self {
         Stream {
+            past_end_of_stream: false,
             options: StreamOptions::default(),
-            stream_inst: WrappedStreamInstance::new(
-                StreamInstance::OutputFile(file)
-            ),
+            stream_inst: WrappedStreamInstance::new(stream_inst)
         }
     }
 
     #[inline]
     pub(crate)
-    fn from_file_as_input(file: File) -> Self {
-        Stream {
-            options: StreamOptions::default(),
-            stream_inst: WrappedStreamInstance::new(
-                StreamInstance::InputFile(file)
-            ),
-        }
+    fn stdout() -> Self {
+        Stream::from_inst(StreamInstance::Stdout)
     }
 
-/*
     #[inline]
     pub(crate)
-    fn stdin() -> Self {
-        Stream {
-            options: StreamOptions::default(),
-            stream_inst: WrappedStreamInstance::new(
-                StreamInstance::Stdin
-            ),
-        }
+    fn from_file_as_output(file: File) -> Self {
+        Stream::from_inst(StreamInstance::OutputFile(file))
     }
-*/
 
     #[inline]
     pub(crate)
-    fn null_stream() -> Self {
-        Stream {
-            options: StreamOptions::default(), // TODO: null_options?
-            stream_inst: WrappedStreamInstance::new(
-                StreamInstance::Null
-            ),
-        }
+    fn from_file_as_input(file: File) -> Self {
+        Stream::from_inst(StreamInstance::InputFile(file))
     }
 
     #[inline]
@@ -388,9 +338,10 @@ impl MachineState {
     ) -> CallResult {
         match stream.options.eof_action {
             EOFAction::Error => {
-                let stub = MachineError::functor_stub(caller, arity);
+                stream.past_end_of_stream = true;
 
-                let stream = vec![
+                let stub = MachineError::functor_stub(caller, arity);
+                let payload = vec![
                     HeapCellValue::Stream(stream.clone())
                 ];
 
@@ -398,7 +349,7 @@ impl MachineState {
                     self.heap.h(),
                     Permission::InputStream,
                     "past_end_of_stream",
-                    stream,
+                    payload,
                 );
 
                 Err(self.error_form(err, stub))
@@ -408,10 +359,12 @@ impl MachineState {
                     HeapCellValue::Atom(clause_name!("end_of_stream"), None)
                 );
 
+                stream.past_end_of_stream = true;
                 Ok(self.unify(result, end_of_stream))
             }
             EOFAction::Reset => {
-                Ok(self.fail = !stream.reset())
+                stream.past_end_of_stream = !stream.reset();
+                Ok(self.fail = stream.past_end_of_stream)
             }
         }
     }
index 7a73a1550faf6fb99a87494c229d48f3f2718b68..14df438c103e9caf9e1131228e86b86837deca54 100644 (file)
@@ -1603,8 +1603,8 @@ impl MachineState {
                 let a1 = self[temp_v!(1)];
 
                 match result {
-                    Some(Ok(b)) => {
-                        self.unify(Addr::Char(b as char), a1);
+                    Some(Ok(c)) => {
+                        self.unify(Addr::Char(c), a1);
                     }
                     Some(Err(_)) => {
                         let end_of_file = self.heap.to_unifiable(HeapCellValue::Atom(
@@ -1623,6 +1623,29 @@ impl MachineState {
                     }
                 }
             }
+            &SystemClauseType::FlushOutput => {
+                let mut stream =
+                    self.get_stream_or_alias(self[temp_v!(1)], indices, "flush_output", 1)?;
+
+                if stream.is_input_stream() {
+                    let stub = MachineError::functor_stub(clause_name!("flush_output"), 1);
+
+                    let addr = vec![
+                        HeapCellValue::Stream(stream)
+                    ];
+
+                    let err = MachineError::permission_error(
+                        self.heap.h(),
+                        Permission::OutputStream,
+                        "stream",
+                        addr,
+                    );
+
+                    return Err(self.error_form(err, stub));
+                }
+
+                stream.flush().unwrap();
+            }
             &SystemClauseType::GetSingleChar => {
                 let c = get_single_char();
 
@@ -3925,14 +3948,12 @@ impl MachineState {
 
                 if let Some(err_string) = opt_err {
                     let stub = MachineError::functor_stub(clause_name!("write_term"), 3);
-                    let h = self.heap.h();
-
-                    let addr = self.heap.to_unifiable(
+                    let addr = vec![
                         HeapCellValue::Stream(stream)
-                    );
+                    ];
 
                     let err = MachineError::permission_error(
-                        h + 1,
+                        self.heap.h(),
                         Permission::OutputStream,
                         err_string,
                         addr,