From: Mark Thom Date: Tue, 5 May 2020 20:10:49 +0000 (-0600) Subject: add flush_output/{0,1}, past_end_of_stream X-Git-Tag: v0.8.123~57^2~12 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=53ae8b9bd1cd1de4f6a76f352326aad6b930aca0;p=scryer-prolog.git add flush_output/{0,1}, past_end_of_stream --- diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index e6f577e7..bb39a35e 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -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), diff --git a/src/prolog/lib/builtins.pl b/src/prolog/lib/builtins.pl index f1f20f8c..31cfa75d 100644 --- a/src/prolog/lib/builtins.pl +++ b/src/prolog/lib/builtins.pl @@ -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). diff --git a/src/prolog/machine/copier.rs b/src/prolog/machine/copier.rs index 08c41944..dd861731 100644 --- a/src/prolog/machine/copier.rs +++ b/src/prolog/machine/copier.rs @@ -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 CopyTermState { } } - 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 CopyTermState { *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 CopyTermState { 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; diff --git a/src/prolog/machine/heap.rs b/src/prolog/machine/heap.rs index 3e813fe8..718cbfe3 100644 --- a/src/prolog/machine/heap.rs +++ b/src/prolog/machine/heap.rs @@ -288,10 +288,10 @@ impl HeapTemplate { 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(..) => { diff --git a/src/prolog/machine/machine_indices.rs b/src/prolog/machine/machine_indices.rs index cb43359c..58ee66be 100644 --- a/src/prolog/machine/machine_indices.rs +++ b/src/prolog/machine/machine_indices.rs @@ -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) diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 691d1374..e58a04ec 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -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)?; diff --git a/src/prolog/machine/streams.rs b/src/prolog/machine/streams.rs index e4df4734..3f09d6d1 100644 --- a/src/prolog/machine/streams.rs +++ b/src/prolog/machine/streams.rs @@ -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 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 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 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) } } } diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 7a73a155..14df438c 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -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,