bug fixes on LCO, backtracking.

This commit is contained in:
Mark Thom
2017-12-10 01:24:23 -07:00
parent e44ad111c5
commit 37f4450c34
9 changed files with 107 additions and 106 deletions

View File

@@ -34,7 +34,7 @@ mod tests {
submit(&mut wam, "p(Z, Z)."); submit(&mut wam, "p(Z, Z).");
submit(&mut wam, "clouds(are, nice)."); submit(&mut wam, "clouds(are, nice).");
// submit returns true on failure, false on success. // submit returns false on failure, true on success.
assert_eq!(submit(&mut wam, "?- p(Z, Z)."), true); assert_eq!(submit(&mut wam, "?- p(Z, Z)."), true);
assert_eq!(submit(&mut wam, "?- p(Z, z)."), true); assert_eq!(submit(&mut wam, "?- p(Z, z)."), true);
assert_eq!(submit(&mut wam, "?- p(Z, w)."), true); assert_eq!(submit(&mut wam, "?- p(Z, w)."), true);

View File

@@ -317,7 +317,7 @@ pub enum Term {
pub enum InlinedQueryTerm { pub enum InlinedQueryTerm {
CompareNumber(CompareNumberQT, Vec<Box<Term>>), CompareNumber(CompareNumberQT, Vec<Box<Term>>),
IsAtomic(Vec<Box<Term>>), IsAtomic(Vec<Box<Term>>),
IsVar(Vec<Box<Term>>) IsVar(Vec<Box<Term>>),
} }
impl InlinedQueryTerm { impl InlinedQueryTerm {
@@ -325,7 +325,7 @@ impl InlinedQueryTerm {
match self { match self {
&InlinedQueryTerm::CompareNumber(_, _) => 2, &InlinedQueryTerm::CompareNumber(_, _) => 2,
&InlinedQueryTerm::IsAtomic(_) => 1, &InlinedQueryTerm::IsAtomic(_) => 1,
&InlinedQueryTerm::IsVar(_) => 1 &InlinedQueryTerm::IsVar(_) => 1,
} }
} }
} }
@@ -344,8 +344,8 @@ pub enum QueryTerm {
CallN(Vec<Box<Term>>), CallN(Vec<Box<Term>>),
Catch(Vec<Box<Term>>), Catch(Vec<Box<Term>>),
Cut, Cut,
Is(Vec<Box<Term>>),
Inlined(InlinedQueryTerm), Inlined(InlinedQueryTerm),
Is(Vec<Box<Term>>),
Term(Term), Term(Term),
Throw(Vec<Box<Term>>) Throw(Vec<Box<Term>>)
} }
@@ -756,8 +756,6 @@ impl ControlInstruction {
&ControlInstruction::ThrowExecute => true, &ControlInstruction::ThrowExecute => true,
&ControlInstruction::Goto(_, _) => true, &ControlInstruction::Goto(_, _) => true,
&ControlInstruction::Proceed => true, &ControlInstruction::Proceed => true,
&ControlInstruction::IsCall(_, _) => true,
&ControlInstruction::IsExecute(_, _) => true,
_ => false _ => false
} }
} }
@@ -963,10 +961,6 @@ pub struct Heap {
} }
impl Heap { impl Heap {
pub fn new() -> Self {
Heap { heap: vec![], h : 0 }
}
pub fn with_capacity(cap: usize) -> Self { pub fn with_capacity(cap: usize) -> Self {
Heap { heap: vec![HeapCellValue::Str(0); cap], h: 0 } Heap { heap: vec![HeapCellValue::Str(0); cap], h: 0 }
} }

View File

@@ -280,12 +280,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
*ctrl = ControlInstruction::Execute(name, arity), *ctrl = ControlInstruction::Execute(name, arity),
ControlInstruction::CallN(arity) => ControlInstruction::CallN(arity) =>
*ctrl = ControlInstruction::ExecuteN(arity), *ctrl = ControlInstruction::ExecuteN(arity),
ControlInstruction::IsCall(r, at) =>
*ctrl = ControlInstruction::IsExecute(r, at),
ControlInstruction::CatchCall => ControlInstruction::CatchCall =>
*ctrl = ControlInstruction::CatchExecute, *ctrl = ControlInstruction::CatchExecute,
ControlInstruction::ThrowCall => ControlInstruction::ThrowCall =>
*ctrl = ControlInstruction::ThrowExecute, *ctrl = ControlInstruction::ThrowExecute,
ControlInstruction::IsCall(r, at) =>
*ctrl = ControlInstruction::IsExecute(r, at),
ControlInstruction::Proceed => {}, ControlInstruction::Proceed => {},
_ => dealloc_index += 1 // = code.len() _ => dealloc_index += 1 // = code.len()
} }
@@ -376,10 +376,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
Line::Cut(CutInstruction::Cut(is_terminal)) Line::Cut(CutInstruction::Cut(is_terminal))
}); });
}, },
&QueryTerm::Inlined(ref term) =>
self.compile_inlined(term, term_loc, code)?,
&QueryTerm::Is(ref terms) => { &QueryTerm::Is(ref terms) => {
let (mut acode, at) = try!(self.call_arith_eval(terms[1].as_ref(), 1)); let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?;
code.append(&mut acode); code.append(&mut acode);
match terms[0].as_ref() { match terms[0].as_ref() {
@@ -405,11 +403,20 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
temp_v!(1))]); temp_v!(1))]);
code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1)))); code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))));
}, },
&Term::Constant(_, Constant::Rational(ref r)) => {
let r = r.clone();
code.push(query![put_constant!(Level::Shallow,
Constant::Rational(r),
temp_v!(1))]);
code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))));
},
_ => { _ => {
code.push(fail!()); code.push(fail!());
} }
} }
}, },
&QueryTerm::Inlined(ref term) =>
self.compile_inlined(term, term_loc, code)?,
_ if chunk_num == 0 => { _ if chunk_num == 0 => {
self.marker.reset_arg(term.arity()); self.marker.reset_arg(term.arity());

View File

@@ -279,7 +279,7 @@ impl<'a> VariableFixtures<'a>
{ {
for term_ref in head.breadth_first_iter() { for term_ref in head.breadth_first_iter() {
match term_ref { match term_ref {
TermRef::Var(_, cell, _) => { TermRef::Var(Level::Shallow, cell, _) => {
unsafe_vars.remove(&cell.get().norm()); unsafe_vars.remove(&cell.get().norm());
}, },
_ => {} _ => {}

View File

@@ -114,16 +114,16 @@ impl fmt::Display for ControlInstruction {
write!(f, "execute {}/{}", name, arity), write!(f, "execute {}/{}", name, arity),
&ControlInstruction::Goto(p, arity) => &ControlInstruction::Goto(p, arity) =>
write!(f, "goto {}/{}", p, arity), write!(f, "goto {}/{}", p, arity),
&ControlInstruction::IsCall(r, ref at) =>
write!(f, "is_call {}, {}", r, at),
&ControlInstruction::IsExecute(r, ref at) =>
write!(f, "is_execute {}, {}", r, at),
&ControlInstruction::Proceed => &ControlInstruction::Proceed =>
write!(f, "proceed"), write!(f, "proceed"),
&ControlInstruction::ThrowCall => &ControlInstruction::ThrowCall =>
write!(f, "call_throw"), write!(f, "call_throw"),
&ControlInstruction::ThrowExecute => &ControlInstruction::ThrowExecute =>
write!(f, "execute_throw"), write!(f, "execute_throw"),
&ControlInstruction::IsCall(r, ref at) =>
write!(f, "is_call {}, {}", r, at),
&ControlInstruction::IsExecute(r, ref at) =>
write!(f, "is_execute {}, {}", r, at),
} }
} }
} }

View File

@@ -11,6 +11,7 @@ use prolog::or_stack::*;
use prolog::ordered_float::OrderedFloat; use prolog::ordered_float::OrderedFloat;
use prolog::fixtures::*; use prolog::fixtures::*;
use std::cmp::max;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::vec::Vec; use std::vec::Vec;
@@ -325,6 +326,7 @@ impl Machine {
self.ms.execute_fact_instr(&fact_instr); self.ms.execute_fact_instr(&fact_instr);
} }
self.ms.p += 1; self.ms.p += 1;
}, },
&Line::Indexing(ref indexing_instr) => &Line::Indexing(ref indexing_instr) =>
@@ -339,6 +341,7 @@ impl Machine {
self.ms.execute_query_instr(&query_instr); self.ms.execute_query_instr(&query_instr);
} }
self.ms.p += 1; self.ms.p += 1;
} }
} }
@@ -398,6 +401,7 @@ impl Machine {
match var_data { match var_data {
&VarData::Perm(_) => { &VarData::Perm(_) => {
let e = self.ms.e; let e = self.ms.e;
let r = var_data.as_reg_type().reg_num(); let r = var_data.as_reg_type().reg_num();
let addr = self.ms.and_stack[e][r].clone(); let addr = self.ms.and_stack[e][r].clone();
@@ -641,8 +645,9 @@ impl MachineState {
} }
} }
fn num_frames(&self) -> usize { fn next_global_index(&self) -> usize {
self.and_stack.len() + self.or_stack.len() max(if self.and_stack.len() > 0 { self.and_stack[self.e].global_index } else { 0 },
if self.b > 0 { self.or_stack[self.b - 1].global_index } else { 0 }) + 1
} }
fn store(&self, a: Addr) -> Addr { fn store(&self, a: Addr) -> Addr {
@@ -860,7 +865,7 @@ impl MachineState {
match at { match at {
&ArithmeticTerm::Reg(r) => { &ArithmeticTerm::Reg(r) => {
let addr = self[r].clone(); let addr = self[r].clone();
let item = self.deref(addr); let item = self.store(self.deref(addr));
match item { match item {
Addr::Con(Constant::Integer(bi)) => Addr::Con(Constant::Integer(bi)) =>
@@ -1663,6 +1668,7 @@ impl MachineState {
if nb > 0 && self.or_stack[b].b == nb { if nb > 0 && self.or_stack[b].b == nb {
self.b = self.or_stack[nb - 1].b; self.b = self.or_stack[nb - 1].b;
self.or_stack.truncate(self.b);
} }
self.p += 1; self.p += 1;
@@ -1691,6 +1697,8 @@ impl MachineState {
}, },
&BuiltInInstruction::UnwindStack => { &BuiltInInstruction::UnwindStack => {
self.b = self.block; self.b = self.block;
self.or_stack.truncate(self.b);
self.fail = true; self.fail = true;
}, },
&BuiltInInstruction::IsAtomic(r) => { &BuiltInInstruction::IsAtomic(r) => {
@@ -1732,35 +1740,33 @@ impl MachineState {
{ {
match instr { match instr {
&ControlInstruction::Allocate(num_cells) => { &ControlInstruction::Allocate(num_cells) => {
if let Some(ref or_fr) = self.or_stack.top() { let gi = self.next_global_index();
let and_gi = if self.and_stack.len() > self.e {
self.and_stack[self.e].global_index
} else {
0
};
if and_gi <= or_fr.global_index { self.p += 1;
self.e = or_fr.e;
}
}
if self.e + 1 < self.and_stack.len() { if self.e + 1 < self.and_stack.len() {
let and_gi = self.and_stack[self.e].global_index;
let or_gi = self.or_stack.top()
.map(|or_fr| or_fr.global_index)
.unwrap_or(0);
if and_gi > or_gi {
let index = self.e + 1; let index = self.e + 1;
self.and_stack[index].e = self.e; self.and_stack[index].e = self.e;
self.and_stack[index].cp = self.cp; self.and_stack[index].cp = self.cp;
self.and_stack[index].global_index = gi;
self.and_stack.resize(index, num_cells); self.and_stack.resize(index, num_cells);
self.e = index; self.e = index;
} else {
let num_frames = self.num_frames();
self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells); return;
}
}
self.and_stack.push(gi, self.e, self.cp, num_cells);
self.e = self.and_stack.len() - 1; self.e = self.and_stack.len() - 1;
};
self.p += 1;
}, },
&ControlInstruction::Call(ref name, arity, _) => &ControlInstruction::Call(ref name, arity, _) =>
self.try_call_predicate(code_dir, name.clone(), arity), self.try_call_predicate(code_dir, name.clone(), arity),
@@ -1798,15 +1804,6 @@ impl MachineState {
self.b0 = self.b; self.b0 = self.b;
self.p = CodePtr::DirEntry(p); self.p = CodePtr::DirEntry(p);
}, },
&ControlInstruction::Proceed =>
self.p = self.cp,
&ControlInstruction::ThrowCall => {
self.cp = self.p + 1;
self.goto_throw();
},
&ControlInstruction::ThrowExecute => {
self.goto_throw();
},
&ControlInstruction::IsCall(r, ref at) => { &ControlInstruction::IsCall(r, ref at) => {
let a1 = self[r].clone(); let a1 = self[r].clone();
let a2 = try_or_fail!(self, self.get_number(at)); let a2 = try_or_fail!(self, self.get_number(at));
@@ -1820,7 +1817,16 @@ impl MachineState {
self.unify(a1, Addr::Con(Constant::from(a2))); self.unify(a1, Addr::Con(Constant::from(a2)));
self.p = self.cp; self.p = self.cp;
} },
&ControlInstruction::Proceed =>
self.p = self.cp,
&ControlInstruction::ThrowCall => {
self.cp = self.p + 1;
self.goto_throw();
},
&ControlInstruction::ThrowExecute => {
self.goto_throw();
},
}; };
} }
@@ -1829,9 +1835,9 @@ impl MachineState {
match instr { match instr {
&IndexedChoiceInstruction::Try(l) => { &IndexedChoiceInstruction::Try(l) => {
let n = self.num_of_args; let n = self.num_of_args;
let num_frames = self.num_frames(); let gi = self.next_global_index();
self.or_stack.push(num_frames + 1, self.or_stack.push(gi,
self.e, self.e,
self.cp, self.cp,
self.b, self.b,
@@ -1899,7 +1905,7 @@ impl MachineState {
self.heap.truncate(self.or_stack[b].h); self.heap.truncate(self.or_stack[b].h);
self.b = self.or_stack[b].b; self.b = self.or_stack[b].b;
self.or_stack.pop(); self.or_stack.truncate(self.b);
self.hb = self.heap.h; self.hb = self.heap.h;
self.p += l; self.p += l;
@@ -1912,9 +1918,9 @@ impl MachineState {
match instr { match instr {
&ChoiceInstruction::TryMeElse(offset) => { &ChoiceInstruction::TryMeElse(offset) => {
let n = self.num_of_args; let n = self.num_of_args;
let num_frames = self.num_frames(); let gi = self.next_global_index();
self.or_stack.push(num_frames + 1, self.or_stack.push(gi,
self.e, self.e,
self.cp, self.cp,
self.b, self.b,
@@ -1983,7 +1989,7 @@ impl MachineState {
self.b = self.or_stack[b].b; self.b = self.or_stack[b].b;
self.or_stack.pop(); self.or_stack.truncate(self.b);
self.hb = self.heap.h; self.hb = self.heap.h;
self.p += 1; self.p += 1;

View File

@@ -135,14 +135,6 @@ macro_rules! is_var {
) )
} }
/*
macro_rules! retry_me_else {
($o:expr) => (
Line::Choice(ChoiceInstruction::RetryMeElse($o))
)
}
*/
macro_rules! trust_me { macro_rules! trust_me {
() => ( () => (
Line::Choice(ChoiceInstruction::TrustMe) Line::Choice(ChoiceInstruction::TrustMe)

View File

@@ -78,8 +78,10 @@ impl OrStack {
self.0.last() self.0.last()
} }
pub fn pop(&mut self) { // truncate expects a 1-indexed new_b, ie.
self.0.pop(); // the value b of MachineState.
pub fn truncate(&mut self, new_b: usize) {
self.0.truncate(new_b);
} }
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {