From d3a9392421abcf03db287ce06e6eaa8a115f322c Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 12 Apr 2020 17:26:11 -0600 Subject: [PATCH] provide read_term_from_chars/2 (#334) --- src/prolog/clause_types.rs | 3 + src/prolog/lib/charsio.pl | 20 +++++- src/prolog/machine/machine_errors.rs | 20 +++++- src/prolog/machine/machine_state.rs | 59 +++++++++++++++ src/prolog/machine/system_calls.rs | 103 ++++++++++++--------------- src/prolog/read.rs | 5 +- 6 files changed, 147 insertions(+), 63 deletions(-) diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index 485928dc..7100855e 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -242,6 +242,7 @@ pub enum SystemClauseType { Maybe, QuotedToken, RawInputReadChar, + ReadTermFromChars, ResetBlock, ReturnFromVerifyAttr, SetBall, @@ -388,6 +389,7 @@ impl SystemClauseType { &SystemClauseType::NextEP => clause_name!("$nextEP"), &SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"), &SystemClauseType::ReadTerm => clause_name!("$read_term"), + &SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"), &SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"), &SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"), &SystemClauseType::RetractClause => clause_name!("$retract_clause"), @@ -508,6 +510,7 @@ impl SystemClauseType { ("$nextEP", 3) => Some(SystemClauseType::NextEP), ("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm), ("$read_term", 2) => Some(SystemClauseType::ReadTerm), + ("$read_term_from_chars", 2) => Some(SystemClauseType::ReadTermFromChars), ("$reset_block", 1) => Some(SystemClauseType::ResetBlock), ("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker), ("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey), diff --git a/src/prolog/lib/charsio.pl b/src/prolog/lib/charsio.pl index f6b2eb2e..f11ef287 100644 --- a/src/prolog/lib/charsio.pl +++ b/src/prolog/lib/charsio.pl @@ -1,4 +1,22 @@ -:- module(charsio, [write_term_to_chars/3]). +:- module(charsio, [read_term_from_chars/2, + write_term_to_chars/3]). + +:- use_module(library(iso_ext)). + +read_term_from_chars(Chars, Term) :- + ( var(Chars) -> + throw(error(instantiation_error, read_term_from_chars/2)) + ; nonvar(Term) -> + throw(error(uninstantiation_error(Term), read_term_from_chars/2)) + ; '$skip_max_list'(_, -1, Chars, Chars0), + Chars0 == [], + partial_string(Chars) -> + true + ; + throw(error(type_error(complete_string, Chars), read_term_from_chars/2)) + ), + '$read_term_from_chars'(Chars, Term). + write_term_to_chars(_, Options, _) :- var(Options), throw(error(instantiation_error, write_term_to_chars/3)). diff --git a/src/prolog/machine/machine_errors.rs b/src/prolog/machine/machine_errors.rs index f57c169a..3e366322 100644 --- a/src/prolog/machine/machine_errors.rs +++ b/src/prolog/machine/machine_errors.rs @@ -145,7 +145,8 @@ impl DomainError for Number { } impl MachineError { - pub(super) fn functor_stub(name: ClauseName, arity: usize) -> MachineStub { + pub(super) + fn functor_stub(name: ClauseName, arity: usize) -> MachineStub { functor!( "/", SharedOpDesc::new(400, YFX), @@ -153,7 +154,8 @@ impl MachineError { ) } - pub(super) fn evaluation_error(eval_error: EvalError) -> Self { + pub(super) + fn evaluation_error(eval_error: EvalError) -> Self { let stub = functor!("evaluation_error", [atom(eval_error.as_str())]); MachineError { @@ -313,6 +315,20 @@ impl MachineError { } } + pub(super) + fn uninstantiation_error(culprit: Addr) -> Self { + let stub = functor!( + "uninstantiation_error", + [addr(culprit)] + ); + + MachineError { + stub, + location: None, + from: ErrorProvenance::Received, + } + } + pub(super) fn session_error(h: usize, err: SessionError) -> Self { match err { diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index e94b039b..9f50f530 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -1,4 +1,5 @@ use prolog_parser::ast::*; +use prolog_parser::tabled_rc::*; use crate::prolog::clause_types::*; use crate::prolog::forms::*; @@ -11,6 +12,7 @@ use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::modules::*; use crate::prolog::machine::stack::*; use crate::prolog::machine::streams::*; +use crate::prolog::read::readline; use crate::prolog::rug::Integer; use downcast::Any; @@ -492,6 +494,63 @@ pub struct MachineState { } impl MachineState { + pub(crate) + fn read_term( + &mut self, + current_input_stream: &mut Stream, + indices: &mut IndexStore, + ) -> CallResult { + match self.read( + &mut parsing_stream(current_input_stream.clone()), + indices.atom_tbl.clone(), + &indices.op_dir, + ) { + Ok(term_write_result) => { + let a1 = self[temp_v!(1)]; + self.unify(Addr::HeapCell(term_write_result.heap_loc), a1); + + if self.fail { + return Ok(()); + } + + let mut list_of_var_eqs = vec![]; + + for (var, binding) in term_write_result.var_dict.into_iter().rev() { + 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); + + 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)); + } + + let a2 = self[temp_v!(2)]; + let list_offset = + Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter())); + + Ok(self.unify(list_offset, a2)) + } + Err(err) => { + if let ParserError::UnexpectedEOF = err { + std::process::exit(0); + } + + // reset the input stream after an input failure. + *current_input_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)) + } + } + } + pub(crate) fn write_term<'a>( &'a self, diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 170c02af..cd9cc86f 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -421,62 +421,6 @@ impl MachineState { }) } - fn read_term( - &mut self, - current_input_stream: &mut Stream, - indices: &mut IndexStore, - ) -> CallResult { - match self.read( - &mut parsing_stream(current_input_stream.clone()), - indices.atom_tbl.clone(), - &indices.op_dir, - ) { - Ok(term_write_result) => { - let a1 = self[temp_v!(1)]; - self.unify(Addr::HeapCell(term_write_result.heap_loc), a1); - - if self.fail { - return Ok(()); - } - - let mut list_of_var_eqs = vec![]; - - for (var, binding) in term_write_result.var_dict.into_iter().rev() { - 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); - - 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)); - } - - let a2 = self[temp_v!(2)]; - let list_offset = - Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter())); - - Ok(self.unify(list_offset, a2)) - } - Err(err) => { - if let ParserError::UnexpectedEOF = err { - std::process::exit(0); - } - - // reset the input stream after an input failure. - *current_input_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)) - } - } - } - #[inline] fn install_new_block(&mut self, r: RegType) -> usize { self.block = self.b; @@ -2479,6 +2423,15 @@ impl MachineState { self.unify(target, module); } + HeapCellValue::Addr(addr) if addr.is_ref() => { + let err = MachineError::uninstantiation_error(addr); + let stub = MachineError::functor_stub( + clause_name!("$module_of"), + 2, + ); + + return Err(self.error_form(err, stub)); + } _ => { unreachable!() } @@ -3062,6 +3015,44 @@ impl MachineState { readline::set_prompt(false); self.read_term(current_input_stream, indices)?; } + &SystemClauseType::ReadTermFromChars => { + let mut heap_pstr_iter = self.heap_pstr_iter(self[temp_v!(1)]); + let chars = heap_pstr_iter.to_string(); + + if let Addr::EmptyList = heap_pstr_iter.focus() { + let term_write_result = + match self.read( + &mut parsing_stream(Stream::from(chars)), + indices.atom_tbl.clone(), + &indices.op_dir, + ) { + Ok(term_write_result) => { + term_write_result + } + Err(e) => { + let stub = MachineError::functor_stub( + clause_name!("read_term_from_chars"), + 2, + ); + + let h = self.heap.h(); + let e = MachineError::session_error(h, SessionError::from(e)); + + return Err(self.error_form(e, stub)); + } + }; + + let result = Addr::HeapCell(term_write_result.heap_loc); + + if let Some(var) = self.store(self.deref(self[temp_v!(2)])).as_var() { + self.bind(var, result); + } else { + unreachable!() + } + } else { + unreachable!() + } + } &SystemClauseType::ResetBlock => { let addr = self.deref(self[temp_v!(1)]); self.reset_block(addr); diff --git a/src/prolog/read.rs b/src/prolog/read.rs index a04b13d1..72be1b18 100644 --- a/src/prolog/read.rs +++ b/src/prolog/read.rs @@ -208,10 +208,7 @@ impl<'a> TermWriter<'a> { &TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) | &TermRef::Var(Level::Root, ..) => { let addr = self.term_as_addr(&term, h); - - if !addr.is_heap_bound() { - self.machine_st.heap.push(HeapCellValue::Addr(addr)); - } + self.machine_st.heap.push(HeapCellValue::Addr(addr)); } &TermRef::AnonVar(_) => { if let Some((arity, site_h)) = self.queue.pop_front() { -- 2.54.0