bug fixes on LCO, backtracking.
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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 }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|
||||||
|
|||||||
@@ -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());
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|||||||
@@ -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),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
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;
|
||||||
|
|
||||||
|
self.and_stack[index].e = self.e;
|
||||||
|
self.and_stack[index].cp = self.cp;
|
||||||
|
self.and_stack[index].global_index = gi;
|
||||||
|
|
||||||
|
self.and_stack.resize(index, num_cells);
|
||||||
|
|
||||||
|
self.e = index;
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.e + 1 < self.and_stack.len() {
|
self.and_stack.push(gi, self.e, self.cp, num_cells);
|
||||||
let index = self.e + 1;
|
self.e = self.and_stack.len() - 1;
|
||||||
|
|
||||||
self.and_stack[index].e = self.e;
|
|
||||||
self.and_stack[index].cp = self.cp;
|
|
||||||
|
|
||||||
self.and_stack.resize(index, num_cells);
|
|
||||||
|
|
||||||
self.e = index;
|
|
||||||
} else {
|
|
||||||
let num_frames = self.num_frames();
|
|
||||||
|
|
||||||
self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells);
|
|
||||||
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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user