add tests, update status.
This commit is contained in:
@@ -16,7 +16,7 @@ argument indexing, and conjunctive queries.
|
|||||||
Extend rusty-wam to include the following, among other features:
|
Extend rusty-wam to include the following, among other features:
|
||||||
|
|
||||||
* call/N as a built-in meta-predicate (_done_).
|
* call/N as a built-in meta-predicate (_done_).
|
||||||
* ISO Prolog compliant throw/catch (_done_).
|
* ISO Prolog compliant throw/catch (_in progress_).
|
||||||
* Built-in and user-defined operators of all fixities,
|
* Built-in and user-defined operators of all fixities,
|
||||||
with custom associativity and precedence.
|
with custom associativity and precedence.
|
||||||
* Bignum and floating point arithmetic.
|
* Bignum and floating point arithmetic.
|
||||||
|
|||||||
28
src/main.rs
28
src/main.rs
@@ -698,8 +698,32 @@ mod tests {
|
|||||||
assert_eq!(submit(&mut wam, "?- catch(f(z), x, handle(y))."), true);
|
assert_eq!(submit(&mut wam, "?- catch(f(z), x, handle(y))."), true);
|
||||||
assert_eq!(submit(&mut wam, "?- catch(f(z), x, handle(z))."), false);
|
assert_eq!(submit(&mut wam, "?- catch(f(z), x, handle(z))."), false);
|
||||||
|
|
||||||
//TODO: write more tests: multi-layered throw/catch, catch
|
submit(&mut wam, "f(X) :- throw(stuff). f(X) :- throw(other_stuff).");
|
||||||
// within catch, throw within catch, etc.
|
submit(&mut wam, "handle(stuff). handle(other_stuff).");
|
||||||
|
|
||||||
|
// this should deterministically succeed with Exception = stuff.
|
||||||
|
assert_eq!(submit(&mut wam, "?- catch(f(X), Exception, handle(Exception))."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- catch(f(X), Exception, handle(stuff))."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- catch(f(X), Exception, handle(other_stuff))."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- catch(f(X), Exception, handle(not_stuff))."), false);
|
||||||
|
|
||||||
|
submit(&mut wam, "f(success). f(X) :- catch(g(X), E, handle(E)).");
|
||||||
|
submit(&mut wam, "g(g_success). g(g_success_2). g(X) :- throw(X).");
|
||||||
|
submit(&mut wam, "handle(x). handle(y). handle(z).");
|
||||||
|
|
||||||
|
assert_eq!(submit(&mut wam, "?- catch(f(X), E, E)."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- catch(f(fail), _, _)."), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- catch(f(x), _, _)."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- catch(f(y), _, _)."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- catch(f(z), _, _)."), true);
|
||||||
|
|
||||||
|
submit(&mut wam, "f(success). f(E) :- catch(g(E), E, handle(E)).");
|
||||||
|
submit(&mut wam, "g(g_success). g(g_success_2). g(X) :- throw(X).");
|
||||||
|
submit(&mut wam, "handle(x). handle(y). handle(z). handle(v) :- throw(X).");
|
||||||
|
|
||||||
|
//TODO: fix this test. record the ball properly. currently it
|
||||||
|
// is unwound when the heap is truncated.
|
||||||
|
assert_eq!(submit(&mut wam, "?- catch(f(X), E, E)."), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -159,8 +159,10 @@ pub enum Term {
|
|||||||
|
|
||||||
pub enum QueryTerm {
|
pub enum QueryTerm {
|
||||||
CallN(Vec<Box<Term>>),
|
CallN(Vec<Box<Term>>),
|
||||||
|
Catch(Vec<Box<Term>>),
|
||||||
Cut,
|
Cut,
|
||||||
Term(Term)
|
Term(Term),
|
||||||
|
Throw(Vec<Box<Term>>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QueryTerm {
|
impl QueryTerm {
|
||||||
@@ -168,10 +170,14 @@ impl QueryTerm {
|
|||||||
match self {
|
match self {
|
||||||
&QueryTerm::CallN(ref terms) =>
|
&QueryTerm::CallN(ref terms) =>
|
||||||
QueryTermRef::CallN(terms),
|
QueryTermRef::CallN(terms),
|
||||||
|
&QueryTerm::Catch(ref terms) =>
|
||||||
|
QueryTermRef::Catch(terms),
|
||||||
&QueryTerm::Cut =>
|
&QueryTerm::Cut =>
|
||||||
QueryTermRef::Cut,
|
QueryTermRef::Cut,
|
||||||
&QueryTerm::Term(ref term) =>
|
&QueryTerm::Term(ref term) =>
|
||||||
QueryTermRef::Term(term),
|
QueryTermRef::Term(term),
|
||||||
|
&QueryTerm::Throw(ref t) =>
|
||||||
|
QueryTermRef::Throw(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,14 +190,16 @@ pub struct Rule {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum ClauseType<'a> {
|
pub enum ClauseType<'a> {
|
||||||
CallN,
|
CallN,
|
||||||
|
Catch,
|
||||||
Deep(Level, &'a Cell<RegType>, &'a Atom),
|
Deep(Level, &'a Cell<RegType>, &'a Atom),
|
||||||
Root
|
Root,
|
||||||
|
Throw
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ClauseType<'a> {
|
impl<'a> ClauseType<'a> {
|
||||||
pub fn level_of_subterms(self) -> Level {
|
pub fn level_of_subterms(self) -> Level {
|
||||||
match self {
|
match self {
|
||||||
ClauseType::CallN => Level::Shallow,
|
ClauseType::CallN | ClauseType::Catch | ClauseType::Throw => Level::Shallow,
|
||||||
ClauseType::Deep(_, _, _) => Level::Deep,
|
ClauseType::Deep(_, _, _) => Level::Deep,
|
||||||
ClauseType::Root => Level::Shallow
|
ClauseType::Root => Level::Shallow
|
||||||
}
|
}
|
||||||
@@ -216,7 +224,9 @@ impl<'a> TermRef<'a> {
|
|||||||
| TermRef::Var(lvl, _, _) => lvl,
|
| TermRef::Var(lvl, _, _) => lvl,
|
||||||
TermRef::Clause(ClauseType::Root, _) => Level::Shallow,
|
TermRef::Clause(ClauseType::Root, _) => Level::Shallow,
|
||||||
TermRef::Clause(ClauseType::Deep(lvl, _, _), _) => lvl,
|
TermRef::Clause(ClauseType::Deep(lvl, _, _), _) => lvl,
|
||||||
TermRef::Clause(ClauseType::CallN, _) => Level::Shallow
|
TermRef::Clause(ClauseType::CallN, _) => Level::Shallow,
|
||||||
|
TermRef::Clause(ClauseType::Throw, _) => Level::Shallow,
|
||||||
|
TermRef::Clause(ClauseType::Catch, _) => Level::Shallow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,13 +234,17 @@ impl<'a> TermRef<'a> {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum QueryTermRef<'a> {
|
pub enum QueryTermRef<'a> {
|
||||||
CallN(&'a Vec<Box<Term>>),
|
CallN(&'a Vec<Box<Term>>),
|
||||||
|
Catch(&'a Vec<Box<Term>>),
|
||||||
Cut,
|
Cut,
|
||||||
Term(&'a Term),
|
Term(&'a Term),
|
||||||
|
Throw(&'a Vec<Box<Term>>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> QueryTermRef<'a> {
|
impl<'a> QueryTermRef<'a> {
|
||||||
pub fn arity(self) -> usize {
|
pub fn arity(self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
|
QueryTermRef::Catch(_) => 3,
|
||||||
|
QueryTermRef::Throw(_) => 1,
|
||||||
QueryTermRef::CallN(terms) => terms.len(),
|
QueryTermRef::CallN(terms) => terms.len(),
|
||||||
QueryTermRef::Cut => 0,
|
QueryTermRef::Cut => 0,
|
||||||
QueryTermRef::Term(term) => term.arity(),
|
QueryTermRef::Term(term) => term.arity(),
|
||||||
@@ -297,19 +311,23 @@ pub enum ControlInstruction {
|
|||||||
Allocate(usize),
|
Allocate(usize),
|
||||||
Call(Atom, usize, usize),
|
Call(Atom, usize, usize),
|
||||||
CallN(usize),
|
CallN(usize),
|
||||||
|
Catch,
|
||||||
Deallocate,
|
Deallocate,
|
||||||
Execute(Atom, usize),
|
Execute(Atom, usize),
|
||||||
ExecuteN(usize),
|
ExecuteN(usize),
|
||||||
Proceed
|
Proceed,
|
||||||
|
Throw
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ControlInstruction {
|
impl ControlInstruction {
|
||||||
pub fn is_jump_instr(&self) -> bool {
|
pub fn is_jump_instr(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
&ControlInstruction::Call(_, _, _) => true,
|
&ControlInstruction::Call(_, _, _) => true,
|
||||||
&ControlInstruction::Execute(_, _) => true,
|
&ControlInstruction::Catch => true,
|
||||||
|
&ControlInstruction::Execute(_, _) => true,
|
||||||
&ControlInstruction::CallN(_) => true,
|
&ControlInstruction::CallN(_) => true,
|
||||||
&ControlInstruction::ExecuteN(_) => true,
|
&ControlInstruction::ExecuteN(_) => true,
|
||||||
|
&ControlInstruction::Throw => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,20 +24,18 @@ pub enum EvalSession<'a> {
|
|||||||
pub struct ConjunctInfo<'a> {
|
pub struct ConjunctInfo<'a> {
|
||||||
pub perm_vs: VariableFixtures<'a>,
|
pub perm_vs: VariableFixtures<'a>,
|
||||||
pub num_of_chunks: usize,
|
pub num_of_chunks: usize,
|
||||||
pub has_deep_cut: bool,
|
pub has_deep_cut: bool
|
||||||
pub has_catch: bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ConjunctInfo<'a>
|
impl<'a> ConjunctInfo<'a>
|
||||||
{
|
{
|
||||||
fn new(perm_vs: VariableFixtures<'a>, num_of_chunks: usize, has_deep_cut: bool, has_catch: bool)
|
fn new(perm_vs: VariableFixtures<'a>, num_of_chunks: usize, has_deep_cut: bool) -> Self
|
||||||
-> Self
|
|
||||||
{
|
{
|
||||||
ConjunctInfo { perm_vs, num_of_chunks, has_deep_cut, has_catch }
|
ConjunctInfo { perm_vs, num_of_chunks, has_deep_cut }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocates(&self) -> bool {
|
fn allocates(&self) -> bool {
|
||||||
self.perm_vs.size() > 0 || self.num_of_chunks > 1 || self.has_deep_cut || self.has_catch
|
self.perm_vs.size() > 0 || self.num_of_chunks > 1 || self.has_deep_cut
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perm_vars(&self) -> usize {
|
fn perm_vars(&self) -> usize {
|
||||||
@@ -45,7 +43,7 @@ impl<'a> ConjunctInfo<'a>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn perm_var_offset(&self) -> usize {
|
fn perm_var_offset(&self) -> usize {
|
||||||
self.has_deep_cut as usize + 2 * (self.has_catch as usize)
|
self.has_deep_cut as usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,14 +195,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
|
|
||||||
let num_of_chunks = iter.chunk_num();
|
let num_of_chunks = iter.chunk_num();
|
||||||
let has_deep_cut = iter.encountered_deep_cut();
|
let has_deep_cut = iter.encountered_deep_cut();
|
||||||
let has_catch = iter.encountered_catch();
|
|
||||||
|
|
||||||
vs.populate_restricting_sets();
|
vs.populate_restricting_sets();
|
||||||
vs.set_perm_vals(has_deep_cut, has_catch);
|
vs.set_perm_vals(has_deep_cut);
|
||||||
|
|
||||||
let vs = self.marker.drain_var_data(vs);
|
let vs = self.marker.drain_var_data(vs);
|
||||||
|
|
||||||
ConjunctInfo::new(vs, num_of_chunks, has_deep_cut, has_catch)
|
ConjunctInfo::new(vs, num_of_chunks, has_deep_cut)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_conditional_call(compiled_query: &mut Code, qt: QueryTermRef, pvs: usize)
|
fn add_conditional_call(compiled_query: &mut Code, qt: QueryTermRef, pvs: usize)
|
||||||
@@ -214,6 +211,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
let call = ControlInstruction::CallN(terms.len());
|
let call = ControlInstruction::CallN(terms.len());
|
||||||
compiled_query.push(Line::Control(call));
|
compiled_query.push(Line::Control(call));
|
||||||
},
|
},
|
||||||
|
QueryTermRef::Catch(_) =>
|
||||||
|
compiled_query.push(Line::Control(ControlInstruction::Catch)),
|
||||||
QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref atom))) => {
|
QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref atom))) => {
|
||||||
let call = ControlInstruction::Call(atom.clone(), 0, pvs);
|
let call = ControlInstruction::Call(atom.clone(), 0, pvs);
|
||||||
compiled_query.push(Line::Control(call));
|
compiled_query.push(Line::Control(call));
|
||||||
@@ -222,6 +221,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
let call = ControlInstruction::Call(atom.clone(), terms.len(), pvs);
|
let call = ControlInstruction::Call(atom.clone(), terms.len(), pvs);
|
||||||
compiled_query.push(Line::Control(call));
|
compiled_query.push(Line::Control(call));
|
||||||
},
|
},
|
||||||
|
QueryTermRef::Throw(_) =>
|
||||||
|
compiled_query.push(Line::Control(ControlInstruction::Throw)),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ impl<'a> VariableFixtures<'a>
|
|||||||
self.0.len()
|
self.0.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_perm_vals(&self, has_deep_cuts: bool, has_catch: bool)
|
pub fn set_perm_vals(&self, has_deep_cuts: bool)
|
||||||
{
|
{
|
||||||
let mut values_vec : Vec<_> = self.values()
|
let mut values_vec : Vec<_> = self.values()
|
||||||
.filter_map(|ref v| {
|
.filter_map(|ref v| {
|
||||||
@@ -231,7 +231,7 @@ impl<'a> VariableFixtures<'a>
|
|||||||
|
|
||||||
values_vec.sort_by_key(|ref v| v.0);
|
values_vec.sort_by_key(|ref v| v.0);
|
||||||
|
|
||||||
let offset = has_deep_cuts as usize + 2 * has_catch as usize;
|
let offset = has_deep_cuts as usize;
|
||||||
|
|
||||||
for (i, (_, cells)) in values_vec.into_iter().rev().enumerate() {
|
for (i, (_, cells)) in values_vec.into_iter().rev().enumerate() {
|
||||||
for cell in cells {
|
for cell in cells {
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ impl fmt::Display for ControlInstruction {
|
|||||||
write!(f, "call {}/{}, {}", name, arity, pvs),
|
write!(f, "call {}/{}, {}", name, arity, pvs),
|
||||||
&ControlInstruction::CallN(arity) =>
|
&ControlInstruction::CallN(arity) =>
|
||||||
write!(f, "call_N {}", arity),
|
write!(f, "call_N {}", arity),
|
||||||
|
&ControlInstruction::Catch =>
|
||||||
|
write!(f, "catch"),
|
||||||
&ControlInstruction::ExecuteN(arity) =>
|
&ControlInstruction::ExecuteN(arity) =>
|
||||||
write!(f, "execute_N {}", arity),
|
write!(f, "execute_N {}", arity),
|
||||||
&ControlInstruction::Deallocate =>
|
&ControlInstruction::Deallocate =>
|
||||||
@@ -111,7 +113,9 @@ impl fmt::Display for ControlInstruction {
|
|||||||
&ControlInstruction::Execute(ref name, arity) =>
|
&ControlInstruction::Execute(ref name, arity) =>
|
||||||
write!(f, "execute {}/{}", name, arity),
|
write!(f, "execute {}/{}", name, arity),
|
||||||
&ControlInstruction::Proceed =>
|
&ControlInstruction::Proceed =>
|
||||||
write!(f, "proceed")
|
write!(f, "proceed"),
|
||||||
|
&ControlInstruction::Throw =>
|
||||||
|
write!(f, "throw")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,10 +243,28 @@ fn rewrite_call_n(terms: &mut Vec<Box<Term>>) -> QueryTerm {
|
|||||||
QueryTerm::CallN(new_terms)
|
QueryTerm::CallN(new_terms)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rewrite_catch(terms: &mut Vec<Box<Term>>) -> QueryTerm {
|
||||||
|
let mut new_terms = Vec::with_capacity(0);
|
||||||
|
swap(&mut new_terms, terms);
|
||||||
|
|
||||||
|
QueryTerm::Catch(new_terms)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rewrite_throw(terms: &mut Vec<Box<Term>>) -> QueryTerm {
|
||||||
|
let mut new_terms = Vec::with_capacity(0);
|
||||||
|
swap(&mut new_terms, terms);
|
||||||
|
|
||||||
|
QueryTerm::Throw(new_terms)
|
||||||
|
}
|
||||||
|
|
||||||
fn rewrite_clause(name: &Atom, terms: &mut Vec<Box<Term>>) -> Option<QueryTerm>
|
fn rewrite_clause(name: &Atom, terms: &mut Vec<Box<Term>>) -> Option<QueryTerm>
|
||||||
{
|
{
|
||||||
if name == "call" {
|
if name == "call" {
|
||||||
Some(rewrite_call_n(terms))
|
Some(rewrite_call_n(terms))
|
||||||
|
} else if name == "catch" && terms.len() == 3 {
|
||||||
|
Some(rewrite_catch(terms))
|
||||||
|
} else if name == "throw" && terms.len() == 1 {
|
||||||
|
Some(rewrite_throw(terms))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -370,6 +392,7 @@ Each predicate must have the same name and arity.";
|
|||||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
||||||
|
|
||||||
let compiled_query = cg.compile_query(query);
|
let compiled_query = cg.compile_query(query);
|
||||||
|
print_code(&compiled_query);
|
||||||
wam.submit_query(compiled_query, cg.take_vars())
|
wam.submit_query(compiled_query, cg.take_vars())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,11 +72,19 @@ impl<'a> QueryIterator<'a> {
|
|||||||
|
|
||||||
fn new(term: QueryTermRef<'a>) -> Self {
|
fn new(term: QueryTermRef<'a>) -> Self {
|
||||||
match term {
|
match term {
|
||||||
QueryTermRef::CallN(child_terms) => {
|
QueryTermRef::CallN(terms) => {
|
||||||
let state = IteratorState::Clause(1, ClauseType::CallN, child_terms);
|
let state = IteratorState::Clause(1, ClauseType::CallN, terms);
|
||||||
|
QueryIterator { state_stack: vec![state] }
|
||||||
|
},
|
||||||
|
QueryTermRef::Catch(terms) => {
|
||||||
|
let state = IteratorState::Clause(0, ClauseType::Catch, terms);
|
||||||
|
QueryIterator { state_stack: vec![state] }
|
||||||
|
},
|
||||||
|
QueryTermRef::Term(term) => Self::from_term(term),
|
||||||
|
QueryTermRef::Throw(term) => {
|
||||||
|
let state = IteratorState::Clause(0, ClauseType::Throw, term);
|
||||||
QueryIterator { state_stack: vec![state] }
|
QueryIterator { state_stack: vec![state] }
|
||||||
},
|
},
|
||||||
QueryTermRef::Term(term) => Self::from_term(term),
|
|
||||||
_ => QueryIterator { state_stack: vec![] }
|
_ => QueryIterator { state_stack: vec![] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,7 +109,7 @@ impl<'a> Iterator for QueryIterator<'a> {
|
|||||||
match ct {
|
match ct {
|
||||||
ClauseType::CallN =>
|
ClauseType::CallN =>
|
||||||
self.push_subterm(Level::Shallow, child_terms[0].as_ref()),
|
self.push_subterm(Level::Shallow, child_terms[0].as_ref()),
|
||||||
ClauseType::Root =>
|
ClauseType::Root | ClauseType::Throw | ClauseType::Catch =>
|
||||||
return None,
|
return None,
|
||||||
ClauseType::Deep(_, _, _) =>
|
ClauseType::Deep(_, _, _) =>
|
||||||
return Some(TermRef::Clause(ct, child_terms))
|
return Some(TermRef::Clause(ct, child_terms))
|
||||||
@@ -211,8 +219,7 @@ pub struct ChunkedIterator<'a>
|
|||||||
{
|
{
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
iter: Box<Iterator<Item=QueryTermRef<'a>> + 'a>,
|
iter: Box<Iterator<Item=QueryTermRef<'a>> + 'a>,
|
||||||
deep_cut_encountered: bool,
|
deep_cut_encountered: bool
|
||||||
catch_encountered: bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ChunkedIterator<'a>
|
impl<'a> ChunkedIterator<'a>
|
||||||
@@ -226,7 +233,6 @@ impl<'a> ChunkedIterator<'a>
|
|||||||
term_loc: GenContext::Head,
|
term_loc: GenContext::Head,
|
||||||
iter: inner_iter,
|
iter: inner_iter,
|
||||||
deep_cut_encountered: false,
|
deep_cut_encountered: false,
|
||||||
catch_encountered: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,49 +243,34 @@ impl<'a> ChunkedIterator<'a>
|
|||||||
ChunkedIterator {
|
ChunkedIterator {
|
||||||
term_loc: GenContext::Last(0),
|
term_loc: GenContext::Last(0),
|
||||||
iter: Box::new(iter),
|
iter: Box::new(iter),
|
||||||
deep_cut_encountered: false,
|
deep_cut_encountered: false
|
||||||
catch_encountered: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn iterate_over_query_term(p1: &'a QueryTerm) -> Box<Iterator<Item=QueryTermRef<'a>> + 'a>
|
|
||||||
{
|
|
||||||
match p1 {
|
|
||||||
&QueryTerm::CallN(ref child_terms) =>
|
|
||||||
Box::new(once(QueryTermRef::CallN(child_terms))),
|
|
||||||
&QueryTerm::Term(ref p1) =>
|
|
||||||
Box::new(once(QueryTermRef::Term(p1))),
|
|
||||||
&QueryTerm::Cut =>
|
|
||||||
Box::new(once(QueryTermRef::Cut))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self
|
pub fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self
|
||||||
{
|
{
|
||||||
let inner_iter = Self::iterate_over_query_term(p1);
|
let inner_iter = Box::new(once(p1.to_ref()));
|
||||||
let iter = inner_iter.chain(clauses.iter().map(|c| c.to_ref()));
|
let iter = inner_iter.chain(clauses.iter().map(|c| c.to_ref()));
|
||||||
|
|
||||||
ChunkedIterator {
|
ChunkedIterator {
|
||||||
term_loc: GenContext::Last(0),
|
term_loc: GenContext::Last(0),
|
||||||
iter: Box::new(iter),
|
iter: Box::new(iter),
|
||||||
deep_cut_encountered: false,
|
deep_cut_encountered: false
|
||||||
catch_encountered: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_rule(rule: &'a Rule) -> Self
|
pub fn from_rule(rule: &'a Rule) -> Self
|
||||||
{
|
{
|
||||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
||||||
let iter = once(QueryTermRef::Term(p0));
|
|
||||||
|
|
||||||
let inner_iter = Self::iterate_over_query_term(p1);
|
let iter = once(QueryTermRef::Term(p0));
|
||||||
|
let inner_iter = Box::new(once(p1.to_ref()));
|
||||||
let iter = iter.chain(inner_iter.chain(clauses.iter().map(|c| c.to_ref())));
|
let iter = iter.chain(inner_iter.chain(clauses.iter().map(|c| c.to_ref())));
|
||||||
|
|
||||||
ChunkedIterator {
|
ChunkedIterator {
|
||||||
term_loc: GenContext::Head,
|
term_loc: GenContext::Head,
|
||||||
iter: Box::new(iter),
|
iter: Box::new(iter),
|
||||||
deep_cut_encountered: false,
|
deep_cut_encountered: false
|
||||||
catch_encountered: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,10 +278,6 @@ impl<'a> ChunkedIterator<'a>
|
|||||||
self.deep_cut_encountered
|
self.deep_cut_encountered
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encountered_catch(&self) -> bool {
|
|
||||||
self.catch_encountered
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn at_rule_head(&self) -> bool {
|
pub fn at_rule_head(&self) -> bool {
|
||||||
self.term_loc == GenContext::Head
|
self.term_loc == GenContext::Head
|
||||||
}
|
}
|
||||||
@@ -307,6 +294,9 @@ impl<'a> ChunkedIterator<'a>
|
|||||||
|
|
||||||
while let Some(term) = item {
|
while let Some(term) = item {
|
||||||
match term {
|
match term {
|
||||||
|
//TODO: This can refer to the term at the head of a
|
||||||
|
// goal, not technically a QueryTerm (ie. a term in a
|
||||||
|
// query). Think of a better name.
|
||||||
QueryTermRef::Term(inner_term) => {
|
QueryTermRef::Term(inner_term) => {
|
||||||
if let GenContext::Head = self.term_loc {
|
if let GenContext::Head = self.term_loc {
|
||||||
result.push(term);
|
result.push(term);
|
||||||
@@ -325,6 +315,11 @@ impl<'a> ChunkedIterator<'a>
|
|||||||
arity = child_terms.len() + 1;
|
arity = child_terms.len() + 1;
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
|
QueryTermRef::Catch(child_terms) | QueryTermRef::Throw(child_terms) => {
|
||||||
|
result.push(term);
|
||||||
|
arity = child_terms.len();
|
||||||
|
break;
|
||||||
|
},
|
||||||
QueryTermRef::Cut => {
|
QueryTermRef::Cut => {
|
||||||
result.push(term);
|
result.push(term);
|
||||||
|
|
||||||
|
|||||||
@@ -1286,6 +1286,12 @@ impl MachineState {
|
|||||||
},
|
},
|
||||||
&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),
|
||||||
|
&ControlInstruction::Catch => {
|
||||||
|
self.cp = self.p + 1;
|
||||||
|
self.num_of_args = 3;
|
||||||
|
self.b0 = self.b;
|
||||||
|
self.p = CodePtr::DirEntry(5);
|
||||||
|
},
|
||||||
&ControlInstruction::CallN(arity) =>
|
&ControlInstruction::CallN(arity) =>
|
||||||
if let Some((name, arity)) = self.setup_call_n(arity) {
|
if let Some((name, arity)) = self.setup_call_n(arity) {
|
||||||
self.try_call_predicate(code_dir, name, arity);
|
self.try_call_predicate(code_dir, name, arity);
|
||||||
@@ -1306,6 +1312,12 @@ impl MachineState {
|
|||||||
},
|
},
|
||||||
&ControlInstruction::Proceed =>
|
&ControlInstruction::Proceed =>
|
||||||
self.p = self.cp,
|
self.p = self.cp,
|
||||||
|
&ControlInstruction::Throw => {
|
||||||
|
self.cp = self.p + 1;
|
||||||
|
self.num_of_args = 1;
|
||||||
|
self.b0 = self.b;
|
||||||
|
self.p = CodePtr::DirEntry(56);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user