From 7eb0de7f52fb543994adcca7fef46742d70246ad Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 28 Nov 2019 00:45:13 -0700 Subject: [PATCH] preserve heap contents in between goal expansions (#240, #241) --- Cargo.lock | 6 ++-- Cargo.toml | 2 +- src/prolog/machine/term_expansion.rs | 48 +++++++--------------------- src/prolog/machine/toplevel.rs | 48 ++++++++++++++++------------ 4 files changed, 42 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48178a56..dd192cb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -311,7 +311,7 @@ dependencies = [ [[package]] name = "prolog_parser" -version = "0.8.35" +version = "0.8.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -447,7 +447,7 @@ dependencies = [ "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "prolog_parser 0.8.35 (registry+https://github.com/rust-lang/crates.io-index)", + "prolog_parser 0.8.36 (registry+https://github.com/rust-lang/crates.io-index)", "ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustyline 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -590,7 +590,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6" "checksum ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum prolog_parser 0.8.35 (registry+https://github.com/rust-lang/crates.io-index)" = "1bc16334ea998d54f73cda14254fe546c57ae0c6c990263d50f7efd6ae10ea9d" +"checksum prolog_parser 0.8.36 (registry+https://github.com/rust-lang/crates.io-index)" = "fea0ae985b51f28cb3582469fbe9318e238d504a7358d90eb671f0d772fb5061" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" diff --git a/Cargo.toml b/Cargo.toml index 676e1707..30099863 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ libc = "0.2.62" nix = "0.15.0" num-rug-adapter = { optional = true, version = "0.1.1" } ordered-float = "0.5.0" -prolog_parser = { version = "0.8.35", default-features = false } +prolog_parser = { version = "0.8.36", default-features = false } ref_thread_local = "0.0.0" rug = { version = "1.4.0", optional = true } rustyline = "5.0.3" diff --git a/src/prolog/machine/term_expansion.rs b/src/prolog/machine/term_expansion.rs index f8ef4ed3..f322f712 100644 --- a/src/prolog/machine/term_expansion.rs +++ b/src/prolog/machine/term_expansion.rs @@ -257,7 +257,6 @@ impl<'a, R: Read> TermStream<'a, R> { self.enqueue_term(term)? } None => { - let term = self.run_goal_expanders(&mut machine_st, op_dir, term)?; return Ok(term); } }; @@ -281,40 +280,6 @@ impl<'a, R: Read> TermStream<'a, R> { } } - pub(crate) fn run_goal_expanders( - &mut self, - machine_st: &mut MachineState, - op_dir: &OpDir, - term: Term, - ) -> Result { - match term { - Term::Clause(cell, name, mut terms, arity) => { - let mut new_terms = { - let old_terms = match (name.as_str(), terms.len()) { - (":-", 2) => { - let comma_term = *terms.pop().unwrap(); - unfold_by_str(comma_term, ",") - } - ("?-", 1) => unfold_by_str(*terms.pop().unwrap(), ","), - _ => return Ok(Term::Clause(cell, name, terms, arity)), - }; - - self.expand_goals(machine_st, op_dir, VecDeque::from(old_terms))? - }; - - let initial_term = new_terms.pop().unwrap(); - terms.push(Box::new(fold_by_str( - new_terms.into_iter(), - initial_term, - clause_name!(","), - ))); - - Ok(Term::Clause(cell, name, terms, arity)) - } - _ => Ok(term), - } - } - pub(super) fn expand_goals( &mut self, @@ -374,6 +339,15 @@ impl MachineState { output } + // reset the machine, but keep the heap contents as they were. + // this prevents clashes between underscored variable names + // in the same query. + fn reset_with_heap_preservation(&mut self) { + let heap = self.heap.take(); + self.reset(); + self.heap = heap; + } + fn try_expand_term( &mut self, wam: &mut Machine, @@ -398,7 +372,7 @@ impl MachineState { ); if self.fail { - self.reset(); + self.reset_with_heap_preservation(); None } else { let TermWriteResult { var_dict, .. } = term_write_result; @@ -406,7 +380,7 @@ impl MachineState { self.heap_locs = var_dict; let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir); - self.reset(); + self.reset_with_heap_preservation(); Some(output.result()) } } diff --git a/src/prolog/machine/toplevel.rs b/src/prolog/machine/toplevel.rs index a01d3dd8..ea91d1e6 100644 --- a/src/prolog/machine/toplevel.rs +++ b/src/prolog/machine/toplevel.rs @@ -60,8 +60,8 @@ impl<'a, 'b, 'c, R: Read> CompositeIndices<'a, 'b, 'c, R> { IndexSource::TermStream => &mut self.term_stream.wam.indices.code_dir, IndexSource::Local(ref mut indices) => &mut indices.code_dir, } - } - + } + fn static_code_dir(&self) -> Option<&CodeDir> { match self.static_code_dir { Some(IndexSource::TermStream) => Some(&self.term_stream.wam.indices.code_dir), @@ -84,7 +84,7 @@ impl<'a, 'b, 'c, R: Read> CompositeIndices<'a, 'b, 'c, R> { self.local_code_dir().insert((name.clone(), arity), idx.clone()); idx } else { - let idx = CodeIndex::default(); + let idx = CodeIndex::default(); self.local_code_dir().insert((name.clone(), arity), idx.clone()); idx } @@ -240,7 +240,7 @@ fn setup_module_export( } else { Err(ParserError::InvalidModuleDecl) } - }) + }) } fn setup_module_decl( @@ -259,7 +259,7 @@ fn setup_module_decl( while let Term::Cons(_, t1, t2) = export_list { let module_export = setup_module_export(*t1, atom_tbl.clone())?; - + exports.push(module_export); export_list = *t2; } @@ -327,9 +327,14 @@ fn setup_qualified_import( } } -fn is_consistent(tl: &TopLevel, clauses: &Vec) -> bool { +fn is_consistent( + name: Option, + arity: usize, + clauses: &Vec, +) -> bool +{ match clauses.first() { - Some(ref cl) => tl.name() == cl.name() && tl.arity() == cl.arity(), + Some(ref cl) => name == cl.name() && arity == cl.arity(), None => true, } } @@ -342,18 +347,18 @@ fn merge_clauses(tls: &mut VecDeque) -> Result TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => return Ok(tl), TopLevel::Declaration(_) if clauses.is_empty() => return Ok(tl), TopLevel::Query(_) => return Err(ParserError::InconsistentEntry), - TopLevel::Fact(..) if is_consistent(&tl, &clauses) => + TopLevel::Fact(..) if is_consistent(tl.name(), tl.arity(), &clauses) => if let TopLevel::Fact(fact, line_num, col_num) = tl { let clause = PredicateClause::Fact(fact, line_num, col_num); clauses.push(clause); }, - TopLevel::Rule(..) if is_consistent(&tl, &clauses) => { + TopLevel::Rule(..) if is_consistent(tl.name(), tl.arity(), &clauses) => { if let TopLevel::Rule(rule, line_num, col_num) = tl { let clause = PredicateClause::Rule(rule, line_num, col_num); clauses.push(clause); } } - TopLevel::Predicate(_) if is_consistent(&tl, &clauses) => { + TopLevel::Predicate(_) if is_consistent(tl.name(), tl.arity(), &clauses) => { if let TopLevel::Predicate(pred) = tl { clauses.extend(pred.clauses().into_iter()) } @@ -751,11 +756,11 @@ impl RelationWorker { if name.as_str() == "," { let term = Term::Clause(cell, name, terms, op_spec); let mut subterms = unfold_by_str(term, ","); - + while let Some(subterm) = subterms.pop() { work_queue.push_front(Box::new(subterm)); } - + continue; } else { term = Term::Clause(cell, name, terms, op_spec); @@ -769,7 +774,7 @@ impl RelationWorker { query_terms.push(self.pre_query_term(indices, term)?); } } - + Ok(query_terms) } @@ -974,7 +979,7 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> { &mut self, indices: &mut IndexStore, preds: &mut Vec, - ) -> Result<(), SessionError> { + ) -> Result<(), SessionError> { let mut indices = CompositeIndices::new( &mut self.term_stream, IndexSource::Local(indices), @@ -1020,17 +1025,18 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> { while !self.term_stream.eof()? { let term = self.term_stream.read_term(&indices.op_dir)?; - let (mut tl, new_rel_worker) = self.try_term_to_tl(indices, term)?; - - if tl.is_end_of_file_atom() { - tl = TopLevel::Declaration(Declaration::EndOfFile); - } - + // if is_consistent is false, preds is non-empty. - if !is_consistent(&tl, &preds) { + if !is_consistent(term.predicate_name(), term.predicate_arity(), &preds) { self.process_result(indices, &mut preds)?; self.take_dynamic_clauses(); } + + let (mut tl, new_rel_worker) = self.try_term_to_tl(indices, term)?; + + if tl.is_end_of_file_atom() { + tl = TopLevel::Declaration(Declaration::EndOfFile); + } self.rel_worker.absorb(new_rel_worker); -- 2.54.0