From 531d8b3352b61d562bf1e0b09b351b95243a7bc9 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 27 Apr 2019 00:40:00 -0600 Subject: [PATCH] re: issue #120 --- Cargo.toml | 2 +- src/prolog/heap_print.rs | 1 + src/prolog/machine/machine_state.rs | 30 +++++++++++++++----- src/prolog/machine/machine_state_impl.rs | 23 ++++++++++++++++ src/prolog/machine/system_calls.rs | 35 ++++++++---------------- src/prolog/machine/toplevel.rs | 30 ++++++++++---------- src/tests.rs | 2 +- 7 files changed, 74 insertions(+), 49 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8374e5be..4bdfe967 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scryer-prolog" -version = "0.8.67" +version = "0.8.68" authors = ["Mark Thom "] repository = "https://github.com/mthom/scryer-prolog" description = "A modern Prolog implementation written mostly in Rust." diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 431f698b..bb1dba0d 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -137,6 +137,7 @@ impl<'a> HCPreOrderIterator<'a> { fn char_to_string(c: char) -> String { match c { + '\'' => "\\'".to_string(), '\n' => "\\n".to_string(), '\r' => "\\r".to_string(), '\t' => "\\t".to_string(), diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 4e064c61..fd6b8c92 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -320,6 +320,26 @@ fn try_in_situ(machine_st: &mut MachineState, name: ClauseName, arity: usize, } } +pub(super) fn try_char_list(addrs: Vec) -> Result +{ + let mut chars = String::new(); + + for addr in addrs.iter() { + match addr { + &Addr::Con(Constant::Char(c)) => + chars.push(c), + &Addr::Con(Constant::Atom(ref name, _)) + if name.as_str().len() == 1 => { + chars += name.as_str(); + }, + _ => + return Err(MachineError::type_error(ValidType::Character, addr.clone())) + } + } + + Ok(chars) +} + pub(crate) type CallResult = Result<(), Vec>; pub(crate) trait CallPolicy: Any { @@ -635,15 +655,11 @@ pub(crate) trait CallPolicy: Any { return_from_clause!(machine_st.last_call, machine_st) }, &BuiltInClauseType::PartialString => { - let a1 = machine_st[temp_v!(1)].clone(); + let mut s = machine_st.try_string_list(temp_v!(1))?; let a2 = machine_st[temp_v!(2)].clone(); - if let Addr::Con(Constant::String(s)) = a1 { - s.set_expandable(true); - machine_st.write_constant_to_var(a2, Constant::String(s)); - } else { - machine_st.fail = true; - } + s.set_expandable(true); + machine_st.write_constant_to_var(a2, Constant::String(s)); return_from_clause!(machine_st.last_call, machine_st) }, diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 33d862a0..70427a65 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -2165,6 +2165,29 @@ impl MachineState { *list = result; } + pub(super) + fn try_string_list(&self, r: RegType) -> Result { + let a1 = self[r].clone(); + let a1 = self.store(self.deref(a1)); + + if let Addr::Con(Constant::String(s)) = a1 { + return Ok(s); + } else { + let stub = MachineError::functor_stub(clause_name!("partial_string"), 2); + + match self.try_from_list(r, stub.clone()) { + Ok(addrs) => + Ok(StringList::new(match try_char_list(addrs) { + Ok(string) => string, + Err(err) => { + return Err(self.error_form(err, stub)); + } + }, false)), + Err(err) => return Err(err) + } + } + } + pub(super) fn try_from_list(&self, r: RegType, caller: MachineStub) -> Result, MachineStub> { diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index a0f8b042..508b946e 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -9,7 +9,7 @@ use prolog::machine::copier::*; use prolog::machine::machine_errors::*; use prolog::machine::machine_indices::*; use prolog::machine::machine_state::*; -use prolog::machine::toplevel::to_op_decl; +use prolog::machine::toplevel::{to_op_decl}; use prolog::num::{FromPrimitive, ToPrimitive, Zero}; use prolog::num::bigint::{BigInt}; use prolog::read::{PrologStream, readline}; @@ -35,7 +35,7 @@ impl BrentAlgState { } } -impl MachineState { +impl MachineState { // a step in Brent's algorithm. fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option { @@ -393,28 +393,15 @@ impl MachineState { match self.try_from_list(temp_v!(2), stub.clone()) { Err(e) => return Err(e), - Ok(addrs) => { - let mut chars = String::new(); - - for addr in addrs.iter() { - match addr { - &Addr::Con(Constant::Char(c)) => - chars.push(c), - &Addr::Con(Constant::Atom(ref name, _)) - if name.as_str().len() == 1 => { - chars += name.as_str(); - }, - _ => { - let err = MachineError::type_error(ValidType::Character, - addr.clone()); - return Err(self.error_form(err, stub)); - } - } - } - - let chars = clause_name!(chars, indices.atom_tbl); - self.unify(addr.clone(), Addr::Con(Constant::Atom(chars, None))); - } + Ok(addrs) => + match try_char_list(addrs) { + Ok(string) => { + let chars = clause_name!(string, indices.atom_tbl); + self.unify(addr.clone(), Addr::Con(Constant::Atom(chars, None))); + }, + Err(err) => + return Err(self.error_form(err, stub)) + } } }, _ => unreachable!() diff --git a/src/prolog/machine/toplevel.rs b/src/prolog/machine/toplevel.rs index 65ed9c9a..2949b8eb 100644 --- a/src/prolog/machine/toplevel.rs +++ b/src/prolog/machine/toplevel.rs @@ -390,13 +390,15 @@ pub enum TopLevelPacket { } struct RelationWorker { + flags: MachineFlags, dynamic_clauses: Vec<(Term, Term)>, // Head, Body. queue: VecDeque>, } impl RelationWorker { - fn new() -> Self { + fn new(flags: MachineFlags) -> Self { RelationWorker { dynamic_clauses: vec![], + flags, queue: VecDeque::new() } } @@ -538,14 +540,8 @@ impl RelationWorker { Err(ParserError::InadmissibleQueryTerm) }, ("partial_string", 2) => { - if let Term::Constant(_, Constant::String(_)) = *terms[0].clone() { - if let Term::Var(..) = *terms[1].clone() { - let ct = ClauseType::BuiltIn(BuiltInClauseType::PartialString); - return Ok(QueryTerm::Clause(Cell::default(), ct, terms, false)); - } - } - - Err(ParserError::InadmissibleQueryTerm) + let ct = ClauseType::BuiltIn(BuiltInClauseType::PartialString); + return Ok(QueryTerm::Clause(Cell::default(), ct, terms, false)); }, _ => { let ct = indices.get_clause_type(name, terms.len(), fixity); @@ -768,11 +764,11 @@ impl RelationWorker { } } -fn term_to_toplevel(term_stream: &mut TermStream, code_dir: &mut CodeDir, term: Term) +fn term_to_toplevel(term_stream: &mut TermStream, code_dir: &mut CodeDir, term: Term, flags: MachineFlags) -> Result<(TopLevel, RelationWorker), ParserError> where R: Read { - let mut rel_worker = RelationWorker::new(); + let mut rel_worker = RelationWorker::new(flags); let mut indices = composite_indices!(false, term_stream.indices, code_dir); let tl = rel_worker.try_term_to_tl(&mut indices, term, true)?; @@ -784,6 +780,7 @@ pub fn stream_to_toplevel(mut buffer: ParsingStream, wam: &mut Machine) -> Result { + let flags = wam.machine_flags(); let mut term_stream = TermStream::new(&mut buffer, wam.indices.atom_tbl(), wam.machine_flags(), &mut wam.indices, &mut wam.policies, &mut wam.code_repo); @@ -791,9 +788,9 @@ fn stream_to_toplevel(mut buffer: ParsingStream, wam: &mut Machine) term_stream.add_to_top("?- "); let term = term_stream.read_term(&OpDir::new())?; - let mut code_dir = CodeDir::new(); + let mut code_dir = CodeDir::new(); - let (tl, mut rel_worker) = term_to_toplevel(&mut term_stream, &mut code_dir, term)?; + let (tl, mut rel_worker) = term_to_toplevel(&mut term_stream, &mut code_dir, term, flags)?; rel_worker.expand_queue_contents(&mut term_stream, &OpDir::new())?; let mut indices = composite_indices!(false, term_stream.indices, &mut code_dir); @@ -823,7 +820,7 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> { indices, policies, code_repo); TopLevelBatchWorker { term_stream, - rel_worker: RelationWorker::new(), + rel_worker: RelationWorker::new(flags), results: vec![], dynamic_clause_map: HashMap::new(), in_module: false } @@ -832,7 +829,7 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> { fn try_term_to_tl(&self, indices: &mut IndexStore, term: Term) -> Result<(TopLevel, RelationWorker), SessionError> { - let mut new_rel_worker = RelationWorker::new(); + let mut new_rel_worker = RelationWorker::new(self.rel_worker.flags); let mut indices = composite_indices!(self.in_module, indices, &self.term_stream.indices.code_dir); @@ -877,7 +874,8 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> { } } - pub fn consume(&mut self, indices: &mut IndexStore) -> Result, SessionError> + pub fn consume(&mut self, indices: &mut IndexStore) + -> Result, SessionError> { let mut preds = vec![]; diff --git a/src/tests.rs b/src/tests.rs index 5f9e8270..4ea95c81 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -2391,7 +2391,7 @@ fn test_queries_on_string_lists() assert_prolog_success!(&mut wam, "partial_string(\"appendy\", X), f(X).", [["X = [a, p, p, e, n, d, y, ' ', j, o, n, e, s]"], ["X = [a, p, p, e, n, d, y, ' ', s, m, i, t, h, e, r, s, ' ', j, o, n, e, s]"], - ["X = [a, p, p, e, n, d, y, ' ', o, ''', t, o, o, l, e]"]]); + ["X = [a, p, p, e, n, d, y, ' ', o, '\\'', t, o, o, l, e]"]]); assert_prolog_success!(&mut wam, "partial_string(\"abc\", X), partial_string(\"abcdef\", X).", [["X = [a, b, c, d, e, f | _]"]]); -- 2.54.0