From: Mark Thom Date: Tue, 5 May 2020 03:17:06 +0000 (-0600) Subject: adapt write_term family, add handling for EOF actions. X-Git-Tag: v0.8.123~57^2~14 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=dd247cd5418040839386422f4ed6ddd59f2208ce;p=scryer-prolog.git adapt write_term family, add handling for EOF actions. --- diff --git a/src/prolog/lib/charsio.pl b/src/prolog/lib/charsio.pl index 69a36430..e929dc81 100644 --- a/src/prolog/lib/charsio.pl +++ b/src/prolog/lib/charsio.pl @@ -124,21 +124,14 @@ read_term_from_chars(Chars, Term) :- write_term_to_chars(_, Options, _) :- var(Options), instantiation_error(write_term_to_chars/3). write_term_to_chars(Term, Options, Chars) :- - '$skip_max_list'(_, -1, Options, Options0), - ( var(Options0) -> - instantiation_error(write_term_to_chars/3) - ; nonvar(Chars) -> + builtins:parse_write_options(Options, + [IgnoreOps, MaxDepth, NumberVars, Quoted, VNNames], + write_term_to_chars/3), + ( nonvar(Chars) -> throw(error(uninstantiation_error(Chars), write_term_to_chars/3)) - ; Options0 == [] -> - true ; - type_error(list, Options, write_term_to_chars/3) + true ), - builtins:inst_member_or(Options, ignore_ops(IgnoreOps), ignore_ops(false)), - builtins:inst_member_or(Options, numbervars(NumberVars), numbervars(false)), - builtins:inst_member_or(Options, quoted(Quoted), quoted(false)), - builtins:inst_member_or(Options, variable_names(VarNames), variable_names([])), - builtins:inst_member_or(Options, max_depth(MaxDepth), max_depth(0)), term_variables(Term, Vars), extend_var_list(Vars, VarNames, NewVarNames, numbervars), - '$write_term_to_chars'(Term, IgnoreOps, NumberVars, Quoted, NewVarNames, MaxDepth, Chars). + '$write_term_to_chars'(Chars, Term, IgnoreOps, NumberVars, Quoted, NewVarNames, MaxDepth). diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index b86496b3..691d1374 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -619,100 +619,109 @@ impl MachineState { stream: Stream, indices: &mut IndexStore, ) -> CallResult { + let mut orig_stream = stream.clone(); let mut stream = self.open_parsing_stream(stream, "read_term", 3)?; - match self.read( - &mut stream, - indices.atom_tbl.clone(), - &indices.op_dir, - ) { - Ok(term_write_result) => { - let term = self[temp_v!(2)]; - self.unify(Addr::HeapCell(term_write_result.heap_loc), term); - - if self.fail { - return Ok(()); - } + loop { + match self.read( + &mut stream, + indices.atom_tbl.clone(), + &indices.op_dir, + ) { + Ok(term_write_result) => { + let term = self[temp_v!(2)]; + self.unify(Addr::HeapCell(term_write_result.heap_loc), term); + + if self.fail { + return Ok(()); + } - let mut list_of_var_eqs = vec![]; + let mut list_of_var_eqs = vec![]; - for (var, binding) in term_write_result.var_dict.into_iter() { - let var_atom = clause_name!(var.to_string(), indices.atom_tbl); + for (var, binding) in term_write_result.var_dict.into_iter() { + let var_atom = clause_name!(var.to_string(), indices.atom_tbl); - let h = self.heap.h(); - let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir); + let h = self.heap.h(); + let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir); - self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec)); - self.heap.push(HeapCellValue::Atom(var_atom, None)); - self.heap.push(HeapCellValue::Addr(binding)); + self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec)); + self.heap.push(HeapCellValue::Atom(var_atom, None)); + self.heap.push(HeapCellValue::Addr(binding)); - list_of_var_eqs.push(Addr::Str(h)); - } + list_of_var_eqs.push(Addr::Str(h)); + } - let mut var_set: IndexMap = IndexMap::new(); + let mut var_set: IndexMap = IndexMap::new(); - for addr in self.acyclic_pre_order_iter(term) { - if let Some(var) = addr.as_var() { - if !var_set.contains_key(&var) { - var_set.insert(var, true); - } else { - var_set.insert(var, false); + for addr in self.acyclic_pre_order_iter(term) { + if let Some(var) = addr.as_var() { + if !var_set.contains_key(&var) { + var_set.insert(var, true); + } else { + var_set.insert(var, false); + } } } - } - let mut var_list = vec![]; - let mut singleton_var_list = vec![]; + let mut var_list = vec![]; + let mut singleton_var_list = vec![]; - for addr in self.acyclic_pre_order_iter(term) { - if let Some(var) = addr.as_var() { - if var_set.get(&var) == Some(&true) { - singleton_var_list.push(var.as_addr()); - } + for addr in self.acyclic_pre_order_iter(term) { + if let Some(var) = addr.as_var() { + if var_set.get(&var) == Some(&true) { + singleton_var_list.push(var.as_addr()); + } - var_list.push(var.as_addr()); + var_list.push(var.as_addr()); + } } - } - let singleton_addr = self[temp_v!(3)]; - let singletons_offset = - Addr::HeapCell(self.heap.to_list(singleton_var_list.into_iter())); + let singleton_addr = self[temp_v!(3)]; + let singletons_offset = + Addr::HeapCell(self.heap.to_list(singleton_var_list.into_iter())); - self.unify(singletons_offset, singleton_addr); + self.unify(singletons_offset, singleton_addr); - if self.fail { - return Ok(()); - } + if self.fail { + return Ok(()); + } - let vars_addr = self[temp_v!(4)]; - let vars_offset = - Addr::HeapCell(self.heap.to_list(var_list.into_iter())); + let vars_addr = self[temp_v!(4)]; + let vars_offset = + Addr::HeapCell(self.heap.to_list(var_list.into_iter())); - self.unify(vars_offset, vars_addr); + self.unify(vars_offset, vars_addr); - if self.fail { - return Ok(()); - } + if self.fail { + return Ok(()); + } - let var_names_addr = self[temp_v!(5)]; - let var_names_offset = - Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter())); + let var_names_addr = self[temp_v!(5)]; + let var_names_offset = + Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter())); - Ok(self.unify(var_names_offset, var_names_addr)) - } - Err(err) => { - if let ParserError::UnexpectedEOF = err { - std::process::exit(0); + return Ok(self.unify(var_names_offset, var_names_addr)); } + Err(err) => { + if let ParserError::UnexpectedEOF = err { + self.eof_action( + self[temp_v!(2)], + &mut orig_stream, + clause_name!("read_term"), + 3 + )?; + + if orig_stream.options.eof_action == EOFAction::Reset { + if self.fail == false { + continue; + } else { + return Ok(()); + } + } + } - // reset the input stream after an input failure. - //*stream = readline::input_stream(); - - let h = self.heap.h(); - let syntax_error = MachineError::syntax_error(h, err); - let stub = MachineError::functor_stub(clause_name!("read_term"), 2); - - Err(self.error_form(syntax_error, stub)) + return Ok(()); + } } } } @@ -809,9 +818,11 @@ impl MachineState { var_names.insert(var, atom); } - _ => unreachable!(), + _ => { + } }, - _ => unreachable!(), + _ => { + } } } diff --git a/src/prolog/machine/streams.rs b/src/prolog/machine/streams.rs index 8cd7cbf0..1dbb7532 100644 --- a/src/prolog/machine/streams.rs +++ b/src/prolog/machine/streams.rs @@ -1,16 +1,16 @@ use crate::prolog_parser::ast::*; +use crate::prolog::read::PrologStream; use crate::prolog::read::readline::*; use crate::prolog::machine::machine_errors::*; use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_state::*; -use crate::prolog::read::PrologStream; use std::cell::RefCell; use std::error::Error; use std::fmt; use std::fs::File; -use std::io::{stdout, Cursor, ErrorKind, Read, Write}; +use std::io::{stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write}; use std::hash::{Hash, Hasher}; use std::net::TcpStream; use std::rc::Rc; @@ -148,6 +148,9 @@ pub struct Stream { impl From for Stream { fn from(tcp_stream: TcpStream) -> Self { + tcp_stream.set_read_timeout(None).unwrap(); + tcp_stream.set_write_timeout(None).unwrap(); + Stream { options: StreamOptions::default(), stream_inst: WrappedStreamInstance::new( @@ -322,9 +325,70 @@ impl Stream { } } } + + // returns true on success. + #[inline] + fn reset(&mut self) -> bool { + match *self.stream_inst.0.borrow_mut() { + StreamInstance::Bytes(ref mut cursor) => { + cursor.set_position(0); + true + } + StreamInstance::InputFile(ref mut file) => { + file.seek(SeekFrom::Start(0)).unwrap(); + true + } + StreamInstance::ReadlineStream(ref mut stream) => { + *stream = ReadlineStream::new(String::new()); + true + } + _ => { + false + } + } + } } impl MachineState { + #[inline] + pub(crate) + fn eof_action( + &mut self, + result: Addr, + stream: &mut Stream, + caller: ClauseName, + arity: usize, + ) -> CallResult { + match stream.options.eof_action { + EOFAction::Error => { + let stub = MachineError::functor_stub(caller, arity); + + let stream = vec![ + HeapCellValue::Stream(stream.clone()) + ]; + + let err = MachineError::permission_error( + self.heap.h(), + Permission::InputStream, + "past_end_of_stream", + stream, + ); + + Err(self.error_form(err, stub)) + } + EOFAction::EOFCode => { + let end_of_stream = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!("end_of_stream"), None) + ); + + Ok(self.unify(result, end_of_stream)) + } + EOFAction::Reset => { + Ok(self.fail = !stream.reset()) + } + } + } + pub(crate) fn to_stream_options( &self, @@ -426,14 +490,13 @@ impl MachineState { } None => { let stub = MachineError::functor_stub(clause_name!(caller), arity); - let h = self.heap.h(); let addr = self.heap.to_unifiable( HeapCellValue::Atom(atom.clone(), spec.clone()) ); return Err(self.error_form( - MachineError::existence_error(h + 1, ExistenceError::Stream(addr)), + MachineError::existence_error(self.heap.h(), ExistenceError::Stream(addr)), stub, )); } @@ -474,9 +537,9 @@ impl MachineState { stub_name: &'static str, stub_arity: usize, ) -> Result { - match parsing_stream(stream) { - Ok(stream) => { - Ok(stream) + match parsing_stream(stream.clone()) { + Ok(parsing_stream) => { + Ok(parsing_stream) } Err(e) => { let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index a0e10b25..83d4eb48 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -3949,7 +3949,7 @@ impl MachineState { stream.flush().unwrap(); } &SystemClauseType::WriteTermToChars => { - let addr = self[temp_v!(1)]; + let addr = self[temp_v!(2)]; let printer = match self.write_term(&indices.op_dir)? { @@ -3965,7 +3965,7 @@ impl MachineState { let result = printer.print(addr).result(); let chars = self.heap.put_complete_string(&result); - let result_addr = self.store(self.deref(self[temp_v!(7)])); + let result_addr = self.store(self.deref(self[temp_v!(1)])); if let Some(var) = result_addr.as_var() { self.bind(var, chars); diff --git a/src/prolog/read.rs b/src/prolog/read.rs index 28d35358..9ed6c6cb 100644 --- a/src/prolog/read.rs +++ b/src/prolog/read.rs @@ -42,6 +42,11 @@ pub mod readline { } impl ReadlineStream { + pub fn new(pending_input: String) -> Self { + let rl = Editor::<()>::new(); + ReadlineStream { rl, pending_input: Cursor::new(pending_input) } + } + pub fn input_stream(pending_input: String) -> Stream { let mut rl = Editor::<()>::new(); rl.bind_sequence(KeyPress::Tab, Cmd::Insert(1, "\t".to_string()));