preserve heap contents in between goal expansions (#240, #241)

This commit is contained in:
Mark Thom
2019-11-28 00:45:13 -07:00
parent 9ae901bd0d
commit 7eb0de7f52
4 changed files with 42 additions and 62 deletions

View File

@@ -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<Term, ParserError> {
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())
}
}

View File

@@ -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<PredicateClause>) -> bool {
fn is_consistent(
name: Option<ClauseName>,
arity: usize,
clauses: &Vec<PredicateClause>,
) -> 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<TopLevel>) -> Result<TopLevel, ParserError>
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<PredicateClause>,
) -> 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)?;
// if is_consistent is false, preds is non-empty.
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);
}
// if is_consistent is false, preds is non-empty.
if !is_consistent(&tl, &preds) {
self.process_result(indices, &mut preds)?;
self.take_dynamic_clauses();
}
}
self.rel_worker.absorb(new_rel_worker);