support call/N

This commit is contained in:
Mark Thom
2017-05-24 19:10:31 -06:00
parent 39f0f2bacb
commit 2f23541ee0
16 changed files with 2574 additions and 1362 deletions

2
Cargo.lock generated
View File

@@ -1,6 +1,6 @@
[root] [root]
name = "rusty-wam" name = "rusty-wam"
version = "0.6.3" version = "0.6.4"
dependencies = [ dependencies = [
"lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "rusty-wam" name = "rusty-wam"
version = "0.6.3" version = "0.6.4"
authors = ["Mark Thom"] authors = ["Mark Thom"]
build = "build.rs" build = "build.rs"

View File

@@ -1,18 +1,35 @@
# rusty-wam # rusty-wam
## Phase 1
An implementation of the Warren Abstract Machine in Rust, done An implementation of the Warren Abstract Machine in Rust, done
according to the progression of languages in [Warren's Abstract according to the progression of languages in [Warren's Abstract
Machine: A Tutorial Machine: A Tutorial
Reconstruction](http://wambook.sourceforge.net/wambook.pdf), ending in Reconstruction](http://wambook.sourceforge.net/wambook.pdf).
pure Prolog.
## Progress Phase 1 has been completed, in that rusty-wam implements in some form
all of the WAM book, including lists, cuts, Debray allocation, first
argument indexing, and conjunctive queries.
Prolog is implemented as a simple REPL. It is without meta- or ## Phase 2
extra-logical operators, or side effects of any kind, with the lone
exception of cut. In terms of the tutorial pacing, the work covers in Extend rusty-wam to include the following, among other features:
some form all of the WAM book, including lists, cuts, Debray
allocation, indexing, and conjunctive queries. * call/N as a built-in meta-predicate (_done_).
* ISO Prolog compliant throw/catch.
* Support for built-in and user-defined operators of all fixities,
with custom associativity and precedence.
* Bignum and floating point arithmetic.
* Standard built-in control operators (`;`, `->`, etc.).
* Attributed variables using the SICStus Prolog interface and
semantics. Implementing coroutines like `dif/2`, `freeze/2`
is easy with attributed variables.
* An occurs check.
* Built-in predicates for list processing and top-level declarative
control (`setup_call_control/3`, `call_with_inference_limit/3`,
etc.)
* Mode declarations.
* Extensions for clp(FD).
## Tutorial ## Tutorial
To enter a multi-clause predicate, the brackets ":{" and "}:" are used To enter a multi-clause predicate, the brackets ":{" and "}:" are used
@@ -91,17 +108,4 @@ prolog>
Note that the values of variables belonging to successful queries are Note that the values of variables belonging to successful queries are
printed out, on one line each. Uninstantiated variables are denoted by printed out, on one line each. Uninstantiated variables are denoted by
a number preceded by an underscore (`X = _0` is an example in the a number preceded by an underscore (`X = _0` is an example in the
above). above).
## Occurs check
There's no occurs check, but there soon will be. Currently, attempting
unification on a cyclic term succeeds, and the attempt to write the
term to a string results in an infinite loop, ie.
```
prolog> p(W, W).
prolog> ?- p(f(f(W)), W).
true
*loops to infinity*
```

View File

@@ -434,50 +434,50 @@ mod tests {
assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]])."), true); assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]])."), true);
assert_eq!(submit(&mut wam, "?- p(blah)."), true); assert_eq!(submit(&mut wam, "?- p(blah)."), true);
submit(&mut wam, "call(or(X, Y)) :- call(X). submit(&mut wam, "ind_call(or(X, Y)) :- ind_call(X).
call(trace) :- trace. ind_call(trace) :- trace.
call(or(X, Y)) :- call(Y). ind_call(or(X, Y)) :- ind_call(Y).
call(notrace) :- notrace. ind_call(notrace) :- notrace.
call(nl) :- nl. ind_call(nl) :- nl.
call(X) :- builtin(X). ind_call(X) :- builtin(X).
call(X) :- extern(X). ind_call(X) :- extern(X).
call(call(X)) :- call(X). ind_call(ind_call(X)) :- ind_call(X).
call(repeat). ind_call(repeat).
call(repeat) :- call(repeat). ind_call(repeat) :- ind_call(repeat).
call(false)."); ind_call(false).");
assert_eq!(submit(&mut wam, "?- call(repeat)."), true); assert_eq!(submit(&mut wam, "?- ind_call(repeat)."), true);
assert_eq!(submit(&mut wam, "?- call(false)."), true); assert_eq!(submit(&mut wam, "?- ind_call(false)."), true);
assert_eq!(submit(&mut wam, "?- call(call(repeat))."), true); assert_eq!(submit(&mut wam, "?- ind_call(ind_call(repeat))."), true);
assert_eq!(submit(&mut wam, "?- call(call(false))."), true); assert_eq!(submit(&mut wam, "?- ind_call(ind_call(false))."), true);
assert_eq!(submit(&mut wam, "?- call(notrace)."), false); assert_eq!(submit(&mut wam, "?- ind_call(notrace)."), false);
assert_eq!(submit(&mut wam, "?- call(nl)."), false); assert_eq!(submit(&mut wam, "?- ind_call(nl)."), false);
assert_eq!(submit(&mut wam, "?- call(builtin(X))."), false); assert_eq!(submit(&mut wam, "?- ind_call(builtin(X))."), false);
assert_eq!(submit(&mut wam, "?- call(extern(X))."), false); assert_eq!(submit(&mut wam, "?- ind_call(extern(X))."), false);
submit(&mut wam, "notrace."); submit(&mut wam, "notrace.");
submit(&mut wam, "nl."); submit(&mut wam, "nl.");
assert_eq!(submit(&mut wam, "?- call(repeat)."), true); assert_eq!(submit(&mut wam, "?- ind_call(repeat)."), true);
assert_eq!(submit(&mut wam, "?- call(false)."), true); assert_eq!(submit(&mut wam, "?- ind_call(false)."), true);
assert_eq!(submit(&mut wam, "?- call(call(repeat))."), true); assert_eq!(submit(&mut wam, "?- ind_call(ind_call(repeat))."), true);
assert_eq!(submit(&mut wam, "?- call(call(false))."), true); assert_eq!(submit(&mut wam, "?- ind_call(ind_call(false))."), true);
assert_eq!(submit(&mut wam, "?- call(notrace)."), true); assert_eq!(submit(&mut wam, "?- ind_call(notrace)."), true);
assert_eq!(submit(&mut wam, "?- call(nl)."), true); assert_eq!(submit(&mut wam, "?- ind_call(nl)."), true);
assert_eq!(submit(&mut wam, "?- call(builtin(X))."), false); assert_eq!(submit(&mut wam, "?- ind_call(builtin(X))."), false);
assert_eq!(submit(&mut wam, "?- call(extern(X))."), false); assert_eq!(submit(&mut wam, "?- ind_call(extern(X))."), false);
submit(&mut wam, "builtin(X)."); submit(&mut wam, "builtin(X).");
submit(&mut wam, "extern(x)."); submit(&mut wam, "extern(x).");
assert_eq!(submit(&mut wam, "?- call(repeat)."), true); assert_eq!(submit(&mut wam, "?- ind_call(repeat)."), true);
assert_eq!(submit(&mut wam, "?- call(false)."), true); assert_eq!(submit(&mut wam, "?- ind_call(false)."), true);
assert_eq!(submit(&mut wam, "?- call(call(repeat))."), true); assert_eq!(submit(&mut wam, "?- ind_call(ind_call(repeat))."), true);
assert_eq!(submit(&mut wam, "?- call(call(false))."), true); assert_eq!(submit(&mut wam, "?- ind_call(ind_call(false))."), true);
assert_eq!(submit(&mut wam, "?- call(notrace)."), true); assert_eq!(submit(&mut wam, "?- ind_call(notrace)."), true);
assert_eq!(submit(&mut wam, "?- call(nl)."), true); assert_eq!(submit(&mut wam, "?- ind_call(nl)."), true);
assert_eq!(submit(&mut wam, "?- call(builtin(X))."), true); assert_eq!(submit(&mut wam, "?- ind_call(builtin(X))."), true);
assert_eq!(submit(&mut wam, "?- call(extern(X))."), true); assert_eq!(submit(&mut wam, "?- ind_call(extern(X))."), true);
} }
#[test] #[test]
@@ -541,6 +541,59 @@ mod tests {
assert_eq!(submit(&mut wam, "?- p(X, Y), q(Y, X)."), true); assert_eq!(submit(&mut wam, "?- p(X, Y), q(Y, X)."), true);
assert_eq!(submit(&mut wam, "?- q(X, Y), p(Y, X)."), true); assert_eq!(submit(&mut wam, "?- q(X, Y), p(Y, X)."), true);
} }
#[test]
fn test_queries_on_call_n()
{
let mut wam = Machine::new();
submit(&mut wam, "maplist(Pred, []).
maplist(Pred, [X|Xs]) :- call(Pred, X), maplist(Pred, Xs).");
submit(&mut wam, "f(a). f(b). f(c).");
assert_eq!(submit(&mut wam, "?- maplist(f, [X,Y,Z])."), true);
assert_eq!(submit(&mut wam, "?- maplist(f, [a,Y,Z])."), true);
assert_eq!(submit(&mut wam, "?- maplist(f, [X,a,b])."), true);
assert_eq!(submit(&mut wam, "?- maplist(f, [c,a,b])."), true);
assert_eq!(submit(&mut wam, "?- maplist(f, [d,e,f])."), false);
assert_eq!(submit(&mut wam, "?- maplist(f, [])."), true);
assert_eq!(submit(&mut wam, "?- maplist(f(X), [a,b,c])."), false);
submit(&mut wam, "f(X) :- call(X), call(X).");
submit(&mut wam, "p(x). p(y).");
assert_eq!(submit(&mut wam, "?- f(p)."), false);
assert_eq!(submit(&mut wam, "?- f(p(X))."), true);
assert_eq!(submit(&mut wam, "?- f(p(x))."), true);
assert_eq!(submit(&mut wam, "?- f(p(w))."), false);
assert_eq!(submit(&mut wam, "?- f(p(X, Y))."), false);
submit(&mut wam, "f(P) :- call(P, X), call(P, Y).");
assert_eq!(submit(&mut wam, "?- f(p)."), true);
assert_eq!(submit(&mut wam, "?- f(non_existent)."), false);
submit(&mut wam, "f(P, X, Y) :- call(P, X), call(P, Y).");
assert_eq!(submit(&mut wam, "?- f(p, X, Y)."), true);
assert_eq!(submit(&mut wam, "?- f(p, x, Y)."), true);
assert_eq!(submit(&mut wam, "?- f(p, X, y)."), true);
assert_eq!(submit(&mut wam, "?- f(p, x, y)."), true);
assert_eq!(submit(&mut wam, "?- f(p, X, z)."), false);
assert_eq!(submit(&mut wam, "?- f(p, z, Y)."), false);
assert_eq!(submit(&mut wam, "?- call(p, X)."), true);
assert_eq!(submit(&mut wam, "?- call(p, x)."), true);
assert_eq!(submit(&mut wam, "?- call(p, y)."), true);
assert_eq!(submit(&mut wam, "?- call(p, z)."), false);
submit(&mut wam, "r(f(X)) :- p(X). r(g(Y)) :- p(Y).");
assert_eq!(submit(&mut wam, "?- f(r, X, Y)."), true);
assert_eq!(submit(&mut wam, "?- f(r, X, X)."), true);
assert_eq!(submit(&mut wam, "?- f(r, f(X), g(Y))."), true);
assert_eq!(submit(&mut wam, "?- f(r, j(X), h(Y))."), false);
}
} }
fn process_buffer(wam: &mut Machine, buffer: &str) fn process_buffer(wam: &mut Machine, buffer: &str)

View File

@@ -18,7 +18,7 @@ pub trait Allocator<'a>
fn reset(&mut self); fn reset(&mut self);
fn reset_contents(&mut self) {} fn reset_contents(&mut self) {}
fn advance(&mut self, GenContext, &'a Term); fn advance(&mut self, GenContext, QueryTermRef<'a>);
fn advance_arg(&mut self); fn advance_arg(&mut self);
fn bindings(&self) -> &AllocVarDict<'a>; fn bindings(&self) -> &AllocVarDict<'a>;

View File

@@ -44,7 +44,7 @@ impl PredicateClause {
pub enum TopLevel { pub enum TopLevel {
Fact(Term), Fact(Term),
Predicate(Vec<PredicateClause>), Predicate(Vec<PredicateClause>),
Query(Vec<TermOrCut>), Query(Vec<QueryTerm>),
Rule(Rule) Rule(Rule)
} }
@@ -114,31 +114,61 @@ pub enum Term {
Var(Cell<VarReg>, Var) Var(Cell<VarReg>, Var)
} }
pub enum TermOrCut { pub enum QueryTerm {
CallN(Cell<VarReg>, Var, Vec<Box<Term>>),
Cut, Cut,
Term(Term) Term(Term)
} }
impl TermOrCut { impl QueryTerm {
pub fn arity(&self) -> usize { pub fn arity(&self) -> usize {
match self { match self {
&TermOrCut::Term(ref term) => term.arity(), &QueryTerm::Term(ref term) => term.arity(),
&QueryTerm::CallN(_, _, ref terms) => terms.len() + 1,
_ => 0 _ => 0
} }
} }
pub fn to_ref(&self) -> QueryTermRef {
match self {
&QueryTerm::CallN(ref cell, ref var, ref terms) =>
QueryTermRef::CallN(cell, var, terms),
&QueryTerm::Cut =>
QueryTermRef::Cut,
&QueryTerm::Term(ref term) =>
QueryTermRef::Term(term)
}
}
} }
pub struct Rule { pub struct Rule {
pub head: (Term, TermOrCut), pub head: (Term, QueryTerm),
pub clauses: Vec<TermOrCut> pub clauses: Vec<QueryTerm>
}
#[derive(Clone, Copy)]
pub enum ClauseType<'a> {
CallN(&'a Cell<VarReg>, &'a Var),
Deep(Level, &'a Cell<RegType>, &'a Atom),
Root
}
impl<'a> ClauseType<'a> {
pub fn level_of_subterms(self) -> Level {
match self {
ClauseType::CallN(_, _) => Level::Shallow,
ClauseType::Deep(_, _, _) => Level::Deep,
ClauseType::Root => Level::Shallow
}
}
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum TermRef<'a> { pub enum TermRef<'a> {
AnonVar(Level), AnonVar(Level),
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term), Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
Constant(Level, &'a Cell<RegType>, &'a Constant), Constant(Level, &'a Cell<RegType>, &'a Constant),
Clause(Level, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>), Clause(ClauseType<'a>, &'a Vec<Box<Term>>),
Var(Level, &'a Cell<VarReg>, &'a Var) Var(Level, &'a Cell<VarReg>, &'a Var)
} }
@@ -147,15 +177,40 @@ impl<'a> TermRef<'a> {
match self { match self {
TermRef::AnonVar(lvl) TermRef::AnonVar(lvl)
| TermRef::Cons(lvl, _, _, _) | TermRef::Cons(lvl, _, _, _)
| TermRef::Constant(lvl, _, _) | TermRef::Constant(lvl, _, _)
| TermRef::Clause(lvl, _, _, _) | TermRef::Var(lvl, _, _) => lvl,
| TermRef::Var(lvl, _, _) => lvl TermRef::Clause(ClauseType::Root, _) => Level::Shallow,
TermRef::Clause(ClauseType::Deep(lvl, _, _), _) => lvl,
TermRef::Clause(ClauseType::CallN(_, _), _) => Level::Shallow
} }
} }
} }
pub enum TermOrCutRef<'a> { #[derive(Clone, Copy)]
Cut, Term(&'a Term) pub enum QueryTermRef<'a> {
CallN(&'a Cell<VarReg>, &'a Var, &'a Vec<Box<Term>>),
Cut,
Term(&'a Term)
}
impl<'a> QueryTermRef<'a> {
pub fn arity(self) -> usize {
match self {
QueryTermRef::Term(term) => term.arity(),
QueryTermRef::CallN(_, _, terms) => terms.len() + 1,
_ => 0
}
}
pub fn is_callable(self) -> bool {
match self {
QueryTermRef::Term(&Term::Clause(_, _, _))
| QueryTermRef::Term(&Term::Constant(_, Constant::Atom(_)))
| QueryTermRef::CallN(_, _, _) =>
true,
_ => false
}
}
} }
pub enum ChoiceInstruction { pub enum ChoiceInstruction {
@@ -199,6 +254,8 @@ impl IndexedChoiceInstruction {
pub enum ControlInstruction { pub enum ControlInstruction {
Allocate(usize), Allocate(usize),
Call(Atom, usize, usize), Call(Atom, usize, usize),
CallN(usize),
ExecuteN(usize),
Deallocate, Deallocate,
Execute(Atom, usize), Execute(Atom, usize),
Proceed Proceed
@@ -209,6 +266,8 @@ impl ControlInstruction {
match self { match self {
&ControlInstruction::Call(_, _, _) => true, &ControlInstruction::Call(_, _, _) => true,
&ControlInstruction::Execute(_, _) => true, &ControlInstruction::Execute(_, _) => true,
&ControlInstruction::CallN(_) => true,
&ControlInstruction::ExecuteN(_) => true,
_ => false _ => false
} }
} }
@@ -435,13 +494,6 @@ impl Term {
} }
} }
pub fn subterms(&self) -> usize {
match self {
&Term::Clause(_, _, ref terms) => terms.len(),
_ => 1
}
}
pub fn name(&self) -> Option<&Atom> { pub fn name(&self) -> Option<&Atom> {
match self { match self {
&Term::Constant(_, Constant::Atom(ref atom)) &Term::Constant(_, Constant::Atom(ref atom))

View File

@@ -5,7 +5,6 @@ use prolog::indexing::*;
use prolog::iterators::*; use prolog::iterators::*;
use prolog::targets::*; use prolog::targets::*;
use std::cell::Cell;
use std::collections::HashMap; use std::collections::HashMap;
use std::vec::Vec; use std::vec::Vec;
@@ -34,7 +33,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
} }
fn update_var_count<Iter>(&mut self, iter: Iter) fn update_var_count<Iter>(&mut self, iter: Iter)
where Iter : Iterator<Item=TermRef<'a>> where Iter: Iterator<Item=TermRef<'a>>
{ {
for term in iter { for term in iter {
if let TermRef::Var(_, _, var) = term { if let TermRef::Var(_, _, var) = term {
@@ -48,62 +47,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
*self.var_count.get(var).unwrap() *self.var_count.get(var).unwrap()
} }
fn to_structure<Target>(&mut self,
lvl: Level,
cell: &'a Cell<RegType>,
term_loc: GenContext,
name: &'a Atom,
arity: usize,
target: &mut Vec<Target>)
-> Target
where Target: CompilationTarget<'a>
{
self.marker.mark_non_var(lvl, term_loc, cell, target);
Target::to_structure(lvl, name.clone(), arity, cell.get())
}
fn to_constant<Target>(&mut self,
lvl: Level,
cell: &'a Cell<RegType>,
term_loc: GenContext,
constant: &'a Constant,
target: &mut Vec<Target>)
-> Target
where Target: CompilationTarget<'a>
{
self.marker.mark_non_var(lvl, term_loc, cell, target);
Target::to_constant(lvl, constant.clone(), cell.get())
}
fn to_list<Target>(&mut self,
lvl: Level,
term_loc: GenContext,
cell: &'a Cell<RegType>,
target: &mut Vec<Target>)
-> Target
where Target: CompilationTarget<'a>
{
self.marker.mark_non_var(lvl, term_loc, cell, target);
Target::to_list(lvl, cell.get())
}
fn constant_subterm<Target>(&mut self, constant: &'a Constant) -> Target
where Target: CompilationTarget<'a>
{
Target::constant_subterm(constant.clone())
}
fn non_var_subterm<Target>(&mut self,
lvl: Level,
term_loc: GenContext,
cell: &'a Cell<RegType>,
target: &mut Vec<Target>)
-> Target
where Target: CompilationTarget<'a>
{
self.marker.mark_non_var(lvl, term_loc, cell, target);
Target::clause_arg_to_instr(cell.get())
}
fn add_or_increment_void_instr<Target>(target: &mut Vec<Target>) fn add_or_increment_void_instr<Target>(target: &mut Vec<Target>)
where Target: CompilationTarget<'a> where Target: CompilationTarget<'a>
@@ -131,11 +74,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
&Term::AnonVar => &Term::AnonVar =>
Self::add_or_increment_void_instr(target), Self::add_or_increment_void_instr(target),
&Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _) => { &Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _) => {
let instr = self.non_var_subterm(Level::Deep, term_loc, cell, target); self.marker.mark_non_var(Level::Deep, term_loc, cell, target);
target.push(instr); target.push(Target::clause_arg_to_instr(cell.get()));
}, },
&Term::Constant(_, ref constant) => &Term::Constant(_, ref constant) =>
target.push(self.constant_subterm(constant)), target.push(Target::constant_subterm(constant.clone())),
&Term::Var(ref cell, ref var) => &Term::Var(ref cell, ref var) =>
if is_exposed || self.get_var_count(var) > 1 { if is_exposed || self.get_var_count(var) > 1 {
self.marker.mark_var(var, Level::Deep, cell, term_loc, target); self.marker.mark_var(var, Level::Deep, cell, term_loc, target);
@@ -145,39 +88,51 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
}; };
} }
fn compile_target<Target>(&mut self, term: &'a Term, term_loc: GenContext, is_exposed: bool) fn compile_clause<Target>(&mut self,
-> Vec<Target> ct: ClauseType<'a>,
term_loc: GenContext,
is_exposed: bool,
terms: &'a Vec<Box<Term>>,
target: &mut Vec<Target>)
where Target: CompilationTarget<'a> where Target: CompilationTarget<'a>
{ {
let iter = Target::iter(term); match ct {
let mut target = Vec::<Target>::new(); ClauseType::CallN(_, _) =>
for subterm in terms {
self.subterm_to_instr(subterm.as_ref(), term_loc, is_exposed, target);
},
ClauseType::Deep(lvl, cell, atom) => {
self.marker.mark_non_var(lvl, term_loc, cell, target);
target.push(Target::to_structure(lvl, atom.clone(), terms.len(), cell.get()));
for subterm in terms {
self.subterm_to_instr(subterm.as_ref(), term_loc, is_exposed, target);
}
},
_ => {}
}
}
fn compile_target<Target, Iter>(&mut self, iter: Iter, term_loc: GenContext, is_exposed: bool)
-> Vec<Target>
where Target: CompilationTarget<'a>, Iter: Iterator<Item=TermRef<'a>>
{
let mut target = Vec::new();
for term in iter { for term in iter {
match term { match term {
TermRef::Clause(lvl, cell, atom, terms) => { TermRef::Clause(ct, terms) =>
let str_instr = self.to_structure(lvl, self.compile_clause(ct, term_loc, is_exposed, terms, &mut target),
cell,
term_loc,
atom,
terms.len(),
&mut target);
target.push(str_instr);
for subterm in terms {
self.subterm_to_instr(subterm.as_ref(), term_loc, is_exposed, &mut target);
}
},
TermRef::Cons(lvl, cell, head, tail) => { TermRef::Cons(lvl, cell, head, tail) => {
let list_instr = self.to_list(lvl, term_loc, cell, &mut target); self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
target.push(list_instr); target.push(Target::to_list(lvl, cell.get()));
self.subterm_to_instr(head, term_loc, is_exposed, &mut target); self.subterm_to_instr(head, term_loc, is_exposed, &mut target);
self.subterm_to_instr(tail, term_loc, is_exposed, &mut target); self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
}, },
TermRef::Constant(lvl @ Level::Shallow, cell, constant) => { TermRef::Constant(lvl @ Level::Shallow, cell, constant) => {
let const_instr = self.to_constant(lvl, cell, term_loc, constant, &mut target); self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
target.push(const_instr); target.push(Target::to_constant(lvl, constant.clone(), cell.get()));
}, },
TermRef::AnonVar(lvl @ Level::Shallow) => TermRef::AnonVar(lvl @ Level::Shallow) =>
if let GenContext::Head = term_loc { if let GenContext::Head = term_loc {
@@ -210,13 +165,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
GenContext::Last(chunk_num) GenContext::Last(chunk_num)
}; };
match term_or_cut_ref { self.update_var_count(term_or_cut_ref.post_order_iter());
&TermOrCutRef::Term(term) => { vs.mark_vars_in_chunk(term_or_cut_ref.post_order_iter(),
self.update_var_count(term.breadth_first_iter()); last_term_arity,
vs.mark_vars_in_chunk(term, last_term_arity, chunk_num, term_loc); chunk_num,
}, term_loc);
_ => {}
};
} }
} }
@@ -226,14 +179,18 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
(vs, has_deep_cut) (vs, has_deep_cut)
} }
fn add_conditional_call(compiled_query: &mut Code, term: &Term, pvs: usize) fn add_conditional_call(compiled_query: &mut Code, qt: QueryTermRef, pvs: usize)
{ {
match term { match qt {
&Term::Constant(_, Constant::Atom(ref atom)) => { QueryTermRef::CallN(_, _, terms) => {
let call = ControlInstruction::CallN(terms.len());
compiled_query.push(Line::Control(call));
},
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));
}, },
&Term::Clause(_, ref atom, ref terms) => { QueryTermRef::Term(&Term::Clause(_, ref atom, ref terms)) => {
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));
}, },
@@ -241,25 +198,30 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
} }
} }
fn lco(body: &mut Code, toc: &TermOrCut) -> usize fn lco(body: &mut Code, toc: &QueryTerm) -> usize
{ {
let last_arity = toc.arity(); let last_arity = toc.arity();
let mut dealloc_index = body.len() - 1; let mut dealloc_index = body.len() - 1;
match toc { match toc {
&TermOrCut::Term(Term::Clause(_, ref name, _)) &QueryTerm::Term(Term::Clause(_, ref name, _))
| &TermOrCut::Term(Term::Constant(_, Constant::Atom(ref name))) => | &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref name))) =>
if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() { if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() {
*ctrl = ControlInstruction::Execute(name.clone(), last_arity); *ctrl = ControlInstruction::Execute(name.clone(), last_arity);
}, },
&QueryTerm::CallN(_, _, ref terms) =>
if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() {
*ctrl = ControlInstruction::ExecuteN(terms.len());
},
_ => dealloc_index = body.len() _ => dealloc_index = body.len()
}; };
dealloc_index dealloc_index
} }
fn compile_seq(&mut self, fn compile_seq(&mut self,
clauses: &'a [TermOrCut], clauses: &'a [QueryTerm],
vs: &VariableFixtures<'a>, vs: &VariableFixtures<'a>,
body: &mut Code, body: &mut Code,
is_exposed: bool) is_exposed: bool)
@@ -270,24 +232,20 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
self.marker.reset_contents(); self.marker.reset_contents();
for (i, term) in terms.iter().enumerate() { for (i, term) in terms.iter().enumerate() {
let term_loc = if i + 1 < terms.len() {
GenContext::Mid(chunk_num)
} else {
GenContext::Last(chunk_num)
};
let mut body_appendage = match term { let mut body_appendage = match term {
&TermOrCutRef::Cut if i + 1 < terms.len() => &QueryTermRef::Cut if i + 1 < terms.len() =>
vec![Line::Cut(CutInstruction::Cut(Terminal::Non))], vec![Line::Cut(CutInstruction::Cut(Terminal::Non))],
&TermOrCutRef::Cut => &QueryTermRef::Cut =>
vec![Line::Cut(CutInstruction::Cut(Terminal::Terminal))], vec![Line::Cut(CutInstruction::Cut(Terminal::Terminal))],
&TermOrCutRef::Term(term) if i + 1 < terms.len() => { _ => {
let num_vars = vs.vars_above_threshold(i + 1); let num_vars = vs.vars_above_threshold(i + 1);
self.compile_query_line(term, self.compile_query_line(*term, term_loc, num_vars, is_exposed)
GenContext::Mid(chunk_num),
num_vars,
is_exposed)
},
&TermOrCutRef::Term(term) => {
let num_vars = vs.vars_above_threshold(i + 1);
self.compile_query_line(term,
GenContext::Last(chunk_num),
num_vars,
is_exposed)
} }
}; };
@@ -317,14 +275,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
} }
fn compile_neck_cut_or(&mut self, fn compile_neck_cut_or(&mut self,
p1: &'a TermOrCut, p1: &'a QueryTerm,
body: &mut Code, body: &mut Code,
perm_vars: usize, perm_vars: usize,
is_exposed: bool, is_exposed: bool,
at_end: bool) at_end: bool)
{ {
match p1 { match p1 {
&TermOrCut::Cut => { &QueryTerm::Cut => {
let term = if at_end { let term = if at_end {
Terminal::Terminal Terminal::Terminal
} else { } else {
@@ -333,25 +291,26 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
body.push(Line::Cut(CutInstruction::NeckCut(term))); body.push(Line::Cut(CutInstruction::NeckCut(term)));
}, },
&TermOrCut::Term(ref p1) => { _ => {
let p1 = p1.to_ref();
self.marker.advance(GenContext::Head, p1); self.marker.advance(GenContext::Head, p1);
if p1.is_clause() { let term_loc = if p1.is_callable() {
let term_loc = if p1.is_callable() { GenContext::Last(0)
GenContext::Last(0) } else {
} else { GenContext::Mid(0)
GenContext::Mid(0) };
};
body.push(Line::Query(self.compile_target(p1, term_loc, is_exposed))); let iter = p1.post_order_iter();
} body.push(Line::Query(self.compile_target(iter, term_loc, is_exposed)));
Self::add_conditional_call(body, p1, perm_vars); Self::add_conditional_call(body, p1, perm_vars);
} }
}; };
} }
fn compile_cleanup(body: &mut Code, num_clauses: usize, toc: &TermOrCut) fn compile_cleanup(body: &mut Code, num_clauses: usize, toc: &QueryTerm)
{ {
let dealloc_index = Self::lco(body, toc); let dealloc_index = Self::lco(body, toc);
@@ -369,12 +328,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
let &Rule { head: (ref p0, ref p1), ref clauses } = rule; let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
let mut code = Vec::new(); let mut code = Vec::new();
self.marker.advance(GenContext::Head, p0); self.marker.advance(GenContext::Head, QueryTermRef::Term(p0));
let perm_vars = self.compile_seq_prelude(clauses.len(), &vs, deep_cuts, &mut code); let perm_vars = self.compile_seq_prelude(clauses.len(), &vs, deep_cuts, &mut code);
if p0.is_clause() { if p0.is_clause() {
code.push(Line::Fact(self.compile_target(p0, GenContext::Head, false))); let iter = FactInstruction::iter(p0);
code.push(Line::Fact(self.compile_target(iter, GenContext::Head, false)));
} }
self.compile_neck_cut_or(p1, &mut code, perm_vars, false, clauses.len() == 0); self.compile_neck_cut_or(p1, &mut code, perm_vars, false, clauses.len() == 0);
@@ -430,12 +390,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
let (vs, _) = self.collect_var_data(iter); let (vs, _) = self.collect_var_data(iter);
self.marker.drain_var_data(vs); self.marker.drain_var_data(vs);
self.marker.advance(GenContext::Head, term); self.marker.advance(GenContext::Head, QueryTermRef::Term(term));
let mut code = Vec::new(); let mut code = Vec::new();
if term.is_clause() { if term.is_clause() {
let mut compiled_fact = self.compile_target(term, GenContext::Head, false); let iter = FactInstruction::iter(term);
let mut compiled_fact = self.compile_target(iter, GenContext::Head, false);
self.mark_unsafe_fact_vars(&mut compiled_fact); self.mark_unsafe_fact_vars(&mut compiled_fact);
code.push(Line::Fact(compiled_fact)); code.push(Line::Fact(compiled_fact));
} }
@@ -447,7 +409,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
} }
fn compile_query_line(&mut self, fn compile_query_line(&mut self,
term: &'a Term, term: QueryTermRef<'a>,
term_loc: GenContext, term_loc: GenContext,
index: usize, index: usize,
is_exposed: bool) is_exposed: bool)
@@ -457,17 +419,17 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
let mut code = Vec::new(); let mut code = Vec::new();
if term.is_clause() { let iter = term.post_order_iter();
let compiled_query = Line::Query(self.compile_target(term, term_loc, is_exposed)); let compiled_query = Line::Query(self.compile_target(iter, term_loc, is_exposed));
code.push(compiled_query);
} code.push(compiled_query);
Self::add_conditional_call(&mut code, term, index); Self::add_conditional_call(&mut code, term, index);
code code
} }
pub fn compile_query(&mut self, query: &'a Vec<TermOrCut>) -> Code pub fn compile_query(&mut self, query: &'a Vec<QueryTerm>) -> Code
{ {
let iter = ChunkedIterator::from_term_sequence(query); let iter = ChunkedIterator::from_term_sequence(query);
let (mut vs, deep_cuts) = self.collect_var_data(iter); let (mut vs, deep_cuts) = self.collect_var_data(iter);

View File

@@ -332,7 +332,7 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
self.bindings self.bindings
} }
fn advance(&mut self, _: GenContext, term: &'a Term) { fn advance(&mut self, _: GenContext, term: QueryTermRef<'a>) {
self.arg_c = 1; self.arg_c = 1;
self.temp_lb = term.arity() + 1; self.temp_lb = term.arity() + 1;
} }

View File

@@ -171,15 +171,16 @@ impl<'a> VariableFixtures<'a>
var_count var_count
} }
pub fn mark_vars_in_chunk(&mut self, pub fn mark_vars_in_chunk<Iter>(&mut self,
term: &'a Term, iter: Iter,
last_term_arity: usize, last_term_arity: usize,
chunk_num: usize, chunk_num: usize,
term_loc: GenContext) term_loc: GenContext)
where Iter: Iterator<Item=TermRef<'a>>
{ {
let mut arg_c = 1; let mut arg_c = 1;
for term_ref in term.breadth_first_iter() { for term_ref in iter {
if let TermRef::Var(lvl, cell, var) = term_ref { if let TermRef::Var(lvl, cell, var) = term_ref {
let mut status = self.0.remove(var) let mut status = self.0.remove(var)
.unwrap_or((VarStatus::Temp(chunk_num, TempVarData::new(last_term_arity)), .unwrap_or((VarStatus::Temp(chunk_num, TempVarData::new(last_term_arity)),

View File

@@ -98,6 +98,10 @@ impl fmt::Display for ControlInstruction {
write!(f, "allocate {}", num_cells), write!(f, "allocate {}", num_cells),
&ControlInstruction::Call(ref name, arity, pvs) => &ControlInstruction::Call(ref name, arity, pvs) =>
write!(f, "call {}/{}, {}", name, arity, pvs), write!(f, "call {}/{}, {}", name, arity, pvs),
&ControlInstruction::CallN(arity) =>
write!(f, "call_N {}", arity),
&ControlInstruction::ExecuteN(arity) =>
write!(f, "execute_N {}", arity),
&ControlInstruction::Deallocate => &ControlInstruction::Deallocate =>
write!(f, "deallocate"), write!(f, "deallocate"),
&ControlInstruction::Execute(ref name, arity) => &ControlInstruction::Execute(ref name, arity) =>
@@ -265,6 +269,7 @@ pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'
if is_consistent(clauses) { if is_consistent(clauses) {
let compiled_pred = cg.compile_predicate(clauses); let compiled_pred = cg.compile_predicate(clauses);
print_code(&compiled_pred);
wam.add_predicate(clauses, compiled_pred); wam.add_predicate(clauses, compiled_pred);
EvalSession::EntrySuccess EvalSession::EntrySuccess
@@ -280,6 +285,7 @@ Each predicate must have the same name and arity.";
let mut cg = CodeGenerator::<DebrayAllocator>::new(); let mut cg = CodeGenerator::<DebrayAllocator>::new();
let compiled_fact = cg.compile_fact(fact); let compiled_fact = cg.compile_fact(fact);
print_code(&compiled_fact);
wam.add_fact(fact, compiled_fact); wam.add_fact(fact, compiled_fact);
EvalSession::EntrySuccess EvalSession::EntrySuccess
@@ -288,6 +294,7 @@ Each predicate must have the same name and arity.";
let mut cg = CodeGenerator::<DebrayAllocator>::new(); let mut cg = CodeGenerator::<DebrayAllocator>::new();
let compiled_rule = cg.compile_rule(rule); let compiled_rule = cg.compile_rule(rule);
print_code(&compiled_rule);
wam.add_rule(rule, compiled_rule); wam.add_rule(rule, compiled_rule);
EvalSession::EntrySuccess EvalSession::EntrySuccess
@@ -296,7 +303,8 @@ 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);
wam.submit_query(compiled_query, cg.take_vars()) print_code(&compiled_query);
wam.submit_query(compiled_query, cg.take_vars())
} }
} }
} }

View File

@@ -7,11 +7,10 @@ use std::vec::Vec;
enum IteratorState<'a> { enum IteratorState<'a> {
AnonVar(Level), AnonVar(Level),
Clause(Level, usize, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>), Clause(usize, ClauseType<'a>, &'a Vec<Box<Term>>),
Constant(Level, &'a Cell<RegType>, &'a Constant), Constant(Level, &'a Cell<RegType>, &'a Constant),
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term), InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term), FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
RootClause(usize, &'a Vec<Box<Term>>),
Var(Level, &'a Cell<VarReg>, &'a Var) Var(Level, &'a Cell<VarReg>, &'a Var)
} }
@@ -21,7 +20,7 @@ impl<'a> IteratorState<'a> {
&Term::AnonVar => &Term::AnonVar =>
IteratorState::AnonVar(lvl), IteratorState::AnonVar(lvl),
&Term::Clause(ref cell, ref atom, ref child_terms) => &Term::Clause(ref cell, ref atom, ref child_terms) =>
IteratorState::Clause(lvl, 0, cell, atom, child_terms), IteratorState::Clause(0, ClauseType::Deep(lvl, cell, atom), child_terms),
&Term::Cons(ref cell, ref head, ref tail) => &Term::Cons(ref cell, ref head, ref tail) =>
IteratorState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()), IteratorState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()),
&Term::Constant(ref cell, ref constant) => &Term::Constant(ref cell, ref constant) =>
@@ -37,46 +36,26 @@ pub struct QueryIterator<'a> {
} }
impl<'a> QueryIterator<'a> { impl<'a> QueryIterator<'a> {
fn push_clause(&mut self, fn push_clause(&mut self, child_num: usize, ct: ClauseType<'a>, child_terms: &'a Vec<Box<Term>>)
lvl: Level,
child_num: usize,
cell: &'a Cell<RegType>,
name: &'a Atom,
child_terms: &'a Vec<Box<Term>>)
{ {
self.state_stack.push(IteratorState::Clause(lvl, self.state_stack.push(IteratorState::Clause(child_num, ct, child_terms));
child_num,
cell,
name,
child_terms));
}
fn push_root_clause(&mut self,
child_num: usize,
child_terms: &'a Vec<Box<Term>>)
{
self.state_stack.push(IteratorState::RootClause(child_num, child_terms));
} }
fn push_subterm(&mut self, lvl: Level, term: &'a Term) { fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_stack.push(IteratorState::to_state(lvl, term)); self.state_stack.push(IteratorState::to_state(lvl, term));
} }
fn push_final_cons(&mut self, fn push_final_cons(&mut self, lvl: Level, cell: &'a Cell<RegType>, head: &'a Term, tail: &'a Term)
lvl: Level,
cell: &'a Cell<RegType>,
head: &'a Term,
tail: &'a Term)
{ {
self.state_stack.push(IteratorState::FinalCons(lvl, cell, head, tail)); self.state_stack.push(IteratorState::FinalCons(lvl, cell, head, tail));
} }
fn new(term: &'a Term) -> QueryIterator<'a> { fn from_term(term: &'a Term) -> Self {
let state = match term { let state = match term {
&Term::AnonVar => &Term::AnonVar =>
IteratorState::AnonVar(Level::Shallow), IteratorState::AnonVar(Level::Shallow),
&Term::Clause(_, _, ref terms) => &Term::Clause(_, _, ref terms) =>
IteratorState::RootClause(0, terms), IteratorState::Clause(0, ClauseType::Root, terms),
&Term::Cons(ref cell, ref head, ref tail) => &Term::Cons(ref cell, ref head, ref tail) =>
IteratorState::InitialCons(Level::Shallow, cell, head.as_ref(), tail.as_ref()), IteratorState::InitialCons(Level::Shallow, cell, head.as_ref(), tail.as_ref()),
&Term::Constant(ref cell, ref constant) => &Term::Constant(ref cell, ref constant) =>
@@ -87,6 +66,24 @@ impl<'a> QueryIterator<'a> {
QueryIterator { state_stack: vec![state] } QueryIterator { state_stack: vec![state] }
} }
fn new(term: QueryTermRef<'a>) -> Self {
match term {
QueryTermRef::CallN(cell, var, child_terms) => {
let state = IteratorState::Clause(0, ClauseType::CallN(cell, var), child_terms);
QueryIterator { state_stack: vec![state] }
},
QueryTermRef::Term(term) => Self::from_term(term),
_ => QueryIterator { state_stack: vec![] }
}
}
}
impl<'a> QueryTermRef<'a> {
pub fn post_order_iter(self) -> QueryIterator<'a> {
QueryIterator::new(self)
}
} }
impl<'a> Iterator for QueryIterator<'a> { impl<'a> Iterator for QueryIterator<'a> {
@@ -97,12 +94,21 @@ impl<'a> Iterator for QueryIterator<'a> {
match iter_state { match iter_state {
IteratorState::AnonVar(lvl) => IteratorState::AnonVar(lvl) =>
return Some(TermRef::AnonVar(lvl)), return Some(TermRef::AnonVar(lvl)),
IteratorState::Clause(lvl, child_num, cell, atom, child_terms) => { IteratorState::Clause(child_num, ct, child_terms) => {
if child_num == child_terms.len() { if child_num == child_terms.len() {
return Some(TermRef::Clause(lvl, cell, atom, child_terms)); match ct {
ClauseType::Root =>
return None,
ClauseType::Deep(_, _, _) =>
return Some(TermRef::Clause(ct, child_terms)),
ClauseType::CallN(cell, var) => {
let state = IteratorState::Var(Level::Shallow, cell, var);
self.state_stack.push(state);
}
};
} else { } else {
self.push_clause(lvl, child_num + 1, cell, atom, child_terms); self.push_clause(child_num + 1, ct, child_terms);
self.push_subterm(Level::Deep, child_terms[child_num].as_ref()); self.push_subterm(ct.level_of_subterms(), child_terms[child_num].as_ref());
} }
}, },
IteratorState::InitialCons(lvl, cell, head, tail) => { IteratorState::InitialCons(lvl, cell, head, tail) => {
@@ -114,14 +120,6 @@ impl<'a> Iterator for QueryIterator<'a> {
return Some(TermRef::Cons(lvl, cell, head, tail)), return Some(TermRef::Cons(lvl, cell, head, tail)),
IteratorState::Constant(lvl, cell, constant) => IteratorState::Constant(lvl, cell, constant) =>
return Some(TermRef::Constant(lvl, cell, constant)), return Some(TermRef::Constant(lvl, cell, constant)),
IteratorState::RootClause(child_num, child_terms) => {
if child_num == child_terms.len() {
return None;
} else {
self.push_root_clause(child_num + 1, child_terms);
self.push_subterm(Level::Shallow, child_terms[child_num].as_ref());
}
},
IteratorState::Var(lvl, cell, var) => IteratorState::Var(lvl, cell, var) =>
return Some(TermRef::Var(lvl, cell, var)) return Some(TermRef::Var(lvl, cell, var))
}; };
@@ -145,7 +143,7 @@ impl<'a> FactIterator<'a> {
&Term::AnonVar => &Term::AnonVar =>
vec![IteratorState::AnonVar(Level::Shallow)], vec![IteratorState::AnonVar(Level::Shallow)],
&Term::Clause(_, _, ref terms) => &Term::Clause(_, _, ref terms) =>
vec![IteratorState::RootClause(0, terms)], vec![IteratorState::Clause(0, ClauseType::Root, terms)],
&Term::Cons(ref cell, ref head, ref tail) => &Term::Cons(ref cell, ref head, ref tail) =>
vec![IteratorState::InitialCons(Level::Shallow, vec![IteratorState::InitialCons(Level::Shallow,
cell, cell,
@@ -169,12 +167,21 @@ impl<'a> Iterator for FactIterator<'a> {
match state { match state {
IteratorState::AnonVar(lvl) => IteratorState::AnonVar(lvl) =>
return Some(TermRef::AnonVar(lvl)), return Some(TermRef::AnonVar(lvl)),
IteratorState::Clause(lvl, _, cell, atom, child_terms) => { IteratorState::Clause(_, ct, child_terms) => {
for child_term in child_terms { for child_term in child_terms {
self.push_subterm(Level::Deep, child_term); self.push_subterm(ct.level_of_subterms(), child_term);
} }
return Some(TermRef::Clause(lvl, cell, atom, child_terms)); match ct {
ClauseType::Root =>
continue,
ClauseType::Deep(_, _, _) =>
return Some(TermRef::Clause(ct, child_terms)),
ClauseType::CallN(cell, var) => {
let state = IteratorState::Var(Level::Shallow, cell, var);
self.state_queue.push_back(state);
}
};
}, },
IteratorState::InitialCons(lvl, cell, head, tail) => { IteratorState::InitialCons(lvl, cell, head, tail) => {
self.push_subterm(Level::Deep, head); self.push_subterm(Level::Deep, head);
@@ -184,11 +191,6 @@ impl<'a> Iterator for FactIterator<'a> {
}, },
IteratorState::Constant(lvl, cell, constant) => IteratorState::Constant(lvl, cell, constant) =>
return Some(TermRef::Constant(lvl, cell, constant)), return Some(TermRef::Constant(lvl, cell, constant)),
IteratorState::RootClause(_, child_terms) => {
for child_term in child_terms {
self.push_subterm(Level::Shallow, child_term);
}
},
IteratorState::Var(lvl, cell, var) => IteratorState::Var(lvl, cell, var) =>
return Some(TermRef::Var(lvl, cell, var)), return Some(TermRef::Var(lvl, cell, var)),
_ => {} _ => {}
@@ -201,7 +203,7 @@ impl<'a> Iterator for FactIterator<'a> {
impl Term { impl Term {
pub fn post_order_iter(&self) -> QueryIterator { pub fn post_order_iter(&self) -> QueryIterator {
QueryIterator::new(self) QueryIterator::new(QueryTermRef::Term(self))
} }
pub fn breadth_first_iter(&self) -> FactIterator { pub fn breadth_first_iter(&self) -> FactIterator {
@@ -212,7 +214,7 @@ impl Term {
pub struct ChunkedIterator<'a> pub struct ChunkedIterator<'a>
{ {
at_head: bool, at_head: bool,
iter: Box<Iterator<Item=TermOrCutRef<'a>> + 'a>, iter: Box<Iterator<Item=QueryTermRef<'a>> + 'a>,
deep_cut_encountered: bool deep_cut_encountered: bool
} }
@@ -220,8 +222,8 @@ impl<'a> ChunkedIterator<'a>
{ {
pub fn from_term(term: &'a Term, at_head: bool) -> Self pub fn from_term(term: &'a Term, at_head: bool) -> Self
{ {
let inner_iter: Box<Iterator<Item=TermOrCutRef<'a>>> = let inner_iter: Box<Iterator<Item=QueryTermRef<'a>>> =
Box::new(once(TermOrCutRef::Term(term))); Box::new(once(QueryTermRef::Term(term)));
ChunkedIterator { ChunkedIterator {
at_head: at_head, at_head: at_head,
@@ -230,14 +232,9 @@ impl<'a> ChunkedIterator<'a>
} }
} }
pub fn from_term_sequence(terms: &'a [TermOrCut]) -> Self pub fn from_term_sequence(terms: &'a [QueryTerm]) -> Self
{ {
let iter = terms.iter().map(|c| { let iter = terms.iter().map(|c| c.to_ref());
match c {
&TermOrCut::Cut => TermOrCutRef::Cut,
&TermOrCut::Term(ref term) => TermOrCutRef::Term(term)
}
});
ChunkedIterator { ChunkedIterator {
at_head: false, at_head: false,
@@ -245,24 +242,22 @@ impl<'a> ChunkedIterator<'a>
deep_cut_encountered: false deep_cut_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(TermOrCutRef::Term(p0)); let iter = once(QueryTermRef::Term(p0));
let inner_iter : Box<Iterator<Item=TermOrCutRef<'a>>> = match p1 { let inner_iter : Box<Iterator<Item=QueryTermRef<'a>>> = match p1 {
&TermOrCut::Term(ref p1) => Box::new(once(TermOrCutRef::Term(p1))), &QueryTerm::CallN(ref cell, ref var, ref child_terms) =>
Box::new(once(QueryTermRef::CallN(cell, var, child_terms))),
&QueryTerm::Term(ref p1) =>
Box::new(once(QueryTermRef::Term(p1))),
_ => Box::new(empty()) _ => Box::new(empty())
}; };
let iter = iter.chain(inner_iter.chain(clauses.iter().map(|c| { let iter = iter.chain(inner_iter.chain(clauses.iter().map(|c| c.to_ref())));
match c {
&TermOrCut::Cut => TermOrCutRef::Cut,
&TermOrCut::Term(ref term) => TermOrCutRef::Term(term)
}
})));
ChunkedIterator { ChunkedIterator {
at_head: true, at_head: true,
iter: Box::new(iter), iter: Box::new(iter),
@@ -277,15 +272,15 @@ impl<'a> ChunkedIterator<'a>
pub fn at_head(&self) -> bool { pub fn at_head(&self) -> bool {
self.at_head self.at_head
} }
fn take_chunk(&mut self, term: TermOrCutRef<'a>) -> (usize, Vec<TermOrCutRef<'a>>) fn take_chunk(&mut self, term: QueryTermRef<'a>) -> (usize, Vec<QueryTermRef<'a>>)
{ {
let mut result = vec![term]; let mut result = vec![term];
let mut arity = 0; let mut arity = 0;
while let Some(term) = self.iter.next() { while let Some(term) = self.iter.next() {
match term { match term {
TermOrCutRef::Term(inner_term) => { QueryTermRef::Term(inner_term) => {
result.push(term); result.push(term);
if inner_term.is_callable() { if inner_term.is_callable() {
@@ -293,9 +288,14 @@ impl<'a> ChunkedIterator<'a>
break; break;
} }
}, },
QueryTermRef::CallN(_, _, child_terms) => {
result.push(term);
arity = child_terms.len() + 1;
break;
},
_ => { _ => {
result.push(term); result.push(term);
self.deep_cut_encountered = true; self.deep_cut_encountered = true;
} }
}; };
} }
@@ -307,18 +307,18 @@ impl<'a> ChunkedIterator<'a>
impl<'a> Iterator for ChunkedIterator<'a> impl<'a> Iterator for ChunkedIterator<'a>
{ {
// the last term arity, and the reference. // the last term arity, and the reference.
type Item = (usize, Vec<TermOrCutRef<'a>>); type Item = (usize, Vec<QueryTermRef<'a>>);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
match self.iter.next() { match self.iter.next() {
None => return None, None => return None,
Some(TermOrCutRef::Term(term)) if self.at_head => { Some(QueryTermRef::Term(term)) if self.at_head => {
self.at_head = false; self.at_head = false;
return Some(self.take_chunk(TermOrCutRef::Term(term))); return Some(self.take_chunk(QueryTermRef::Term(term)));
}, },
Some(TermOrCutRef::Term(term)) if term.is_callable() => Some(QueryTermRef::Term(term)) if term.is_callable() =>
return Some((term.arity(), vec![TermOrCutRef::Term(term)])), return Some((term.arity(), vec![QueryTermRef::Term(term)])),
Some(term_or_cut_ref) => Some(term_or_cut_ref) =>
return Some(self.take_chunk(term_or_cut_ref)) return Some(self.take_chunk(term_or_cut_ref))
} }

View File

@@ -247,13 +247,13 @@ impl Machine {
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();
heap_locs.insert(var, addr); heap_locs.insert(var, addr);
}, },
&VarData::Temp(cn, _, _) if cn == chunk_num => { &VarData::Temp(cn, _, _) if cn == chunk_num => {
let r = var_data.as_reg_type(); let r = var_data.as_reg_type();
let addr = self.ms[r].clone(); let addr = self.ms[r].clone();
heap_locs.insert(var, addr); heap_locs.insert(var, addr);
}, },
_ => {} _ => {}
@@ -276,21 +276,21 @@ impl Machine {
self.ms.p = CodePtr::TopLevel(cn, p); self.ms.p = CodePtr::TopLevel(cn, p);
} }
self.query_stepper(); self.query_stepper();
match self.ms.p { match self.ms.p {
CodePtr::TopLevel(_, p) if p > 0 => {}, CodePtr::TopLevel(_, p) if p > 0 => {},
_ => break _ => break
}; };
} }
} }
pub fn submit_query<'a>(&mut self, code: Code, alloc_locs: AllocVarDict<'a>) -> EvalSession<'a> pub fn submit_query<'a>(&mut self, code: Code, alloc_locs: AllocVarDict<'a>) -> EvalSession<'a>
{ {
let mut heap_locs = HashMap::new(); let mut heap_locs = HashMap::new();
self.cached_query = Some(code);
self.cached_query = Some(code);
self.run_query(&alloc_locs, &mut heap_locs); self.run_query(&alloc_locs, &mut heap_locs);
if self.failed() { if self.failed() {
@@ -951,6 +951,35 @@ impl MachineState {
} }
} }
fn try_call_predicate(&mut self, code_dir: &CodeDir, name: Atom, arity: usize)
{
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| *index);
match compiled_tl_index {
Some(compiled_tl_index) => {
self.cp = self.p + 1;
self.num_of_args = arity;
self.b0 = self.b;
self.p = CodePtr::DirEntry(compiled_tl_index);
},
None => self.fail = true
};
}
fn try_execute_predicate(&mut self, code_dir: &CodeDir, name: Atom, arity: usize)
{
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| *index);
match compiled_tl_index {
Some(compiled_tl_index) => {
self.num_of_args = arity;
self.b0 = self.b;
self.p = CodePtr::DirEntry(compiled_tl_index);
},
None => self.fail = true
};
}
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction) fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
{ {
match instr { match instr {
@@ -958,22 +987,33 @@ impl MachineState {
let num_frames = self.num_frames(); let num_frames = self.num_frames();
self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells); self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells);
self.e = self.and_stack.len() - 1; self.e = self.and_stack.len() - 1;
self.p += 1; self.p += 1;
}, },
&ControlInstruction::Call(ref name, arity, _) => { &ControlInstruction::Call(ref name, arity, _) =>
let compiled_tl_index = code_dir.get(&(name.clone(), arity)) self.try_call_predicate(code_dir, name.clone(), arity),
.map(|index| *index); &ControlInstruction::CallN(arity) => {
let addr = self.deref(self.registers[arity + 1].clone());
match compiled_tl_index { match self.store(addr) {
Some(compiled_tl_index) => { Addr::Str(a) => {
self.cp = self.p + 1; let result = self.heap[a].clone();
self.num_of_args = arity;
self.b0 = self.b; if let HeapCellValue::NamedStr(narity, name) = result {
self.p = CodePtr::DirEntry(compiled_tl_index); for i in 1 .. narity + 1 {
self.registers[i + narity] = self.registers[i].clone();
self.registers[i] = self.heap[a + i].as_addr(a + i);
}
self.try_call_predicate(code_dir, name, arity + narity);
} else {
self.fail = true;
}
}, },
None => self.fail = true Addr::Con(Constant::Atom(name)) =>
self.try_call_predicate(code_dir, name, arity),
_ => self.fail = true
}; };
}, },
&ControlInstruction::Deallocate => { &ControlInstruction::Deallocate => {
@@ -984,18 +1024,30 @@ impl MachineState {
self.p += 1; self.p += 1;
}, },
&ControlInstruction::Execute(ref name, arity) => { &ControlInstruction::Execute(ref name, arity) =>
let compiled_tl_index = code_dir.get(&(name.clone(), arity)) self.try_execute_predicate(code_dir, name.clone(), arity),
.map(|index| *index); &ControlInstruction::ExecuteN(arity) => {
let addr = self.deref(self.registers[arity + 1].clone());
match compiled_tl_index { match self.store(addr) {
Some(compiled_tl_index) => { Addr::Str(a) => {
self.num_of_args = arity; let result = self.heap[a].clone();
self.b0 = self.b;
self.p = CodePtr::DirEntry(compiled_tl_index); if let HeapCellValue::NamedStr(narity, name) = result {
for i in 1 .. narity + 1 {
self.registers[i + narity] = self.registers[i].clone();
self.registers[i] = self.heap[a + i].as_addr(a + i);
}
self.try_execute_predicate(code_dir, name, arity + narity);
} else {
self.fail = true;
}
}, },
None => self.fail = true Addr::Con(Constant::Atom(name)) =>
}; self.try_execute_predicate(code_dir, name, arity),
_ => self.fail = true
};
}, },
&ControlInstruction::Proceed => &ControlInstruction::Proceed =>
self.p = self.cp, self.p = self.cp,

View File

@@ -129,13 +129,13 @@ impl<'a> Allocator<'a> for NaiveAllocator<'a>
self.bindings.clear(); self.bindings.clear();
} }
fn advance(&mut self, term_loc: GenContext, term: &'a Term) { fn advance(&mut self, term_loc: GenContext, term: QueryTermRef<'a>) {
if let GenContext::Head = term_loc { if let GenContext::Head = term_loc {
self.arg_c = 1; self.arg_c = 1;
self.temp_c = max(term.subterms() + 1, self.temp_c); self.temp_c = max(term.arity() + 1, self.temp_c);
} else { } else {
self.arg_c = 1; self.arg_c = 1;
self.temp_c = term.subterms() + 1; self.temp_c = term.arity() + 1;
} }
} }

View File

@@ -19,6 +19,23 @@ BoxedTerm : Box<Term> = {
<t:Term> => Box::new(t) <t:Term> => Box::new(t)
}; };
Call : QueryTerm = {
"call" "(" <a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")"
<tss: ("," <BoxedTerm>)*> ")" => {
let mut ts = ts;
let mut tss = tss;
ts.push(t);
ts.append(&mut tss);
QueryTerm::Term(Term::Clause(Cell::default(), a, ts))
},
"call" "(" <a:Atom> <ts: ("," <BoxedTerm>)*> ")" =>
QueryTerm::Term(Term::Clause(Cell::default(), a, ts)),
"call" "(" <v:Var> <ts: ("," <BoxedTerm>)*> ")" =>
QueryTerm::CallN(Cell::default(), v, ts)
};
Clause : Term = { Clause : Term = {
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => { <a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
let mut ts = ts; let mut ts = ts;
@@ -56,26 +73,29 @@ PredicateClause : PredicateClause = {
<Term> "." => PredicateClause::Fact(<>) <Term> "." => PredicateClause::Fact(<>)
}; };
Query : Vec<TermOrCut> = { Query : Vec<QueryTerm> = {
<tcs: (<TermOrCut> ",")*> <tc: TermOrCut> => { <tcs: (<QueryTerm> ",")*> <tc: QueryTerm> => {
let mut tcs = tcs; let mut tcs = tcs;
tcs.push(tc); tcs.push(tc);
tcs tcs
} }
}; };
Rule : Rule = { Rule : Rule = {
<c:Clause> ":-" <h:TermOrCut> <cs: ("," <TermOrCut>)*> => <c:Clause> ":-" <h:QueryTerm> <cs: ("," <QueryTerm>)*> =>
Rule { head: (c, h), clauses: cs }, Rule { head: (c, h), clauses: cs },
<a:Atom> ":-" <h:TermOrCut> <cs: ("," <TermOrCut>)*> => <a:Atom> ":-" <h:QueryTerm> <cs: ("," <QueryTerm>)*> =>
Rule { head: (Term::Constant(Cell::default(), Constant::Atom(a)), Rule { head: (Term::Constant(Cell::default(), Constant::Atom(a)),
h), h),
clauses: cs } clauses: cs }
}; };
TermOrCut : TermOrCut = { QueryTerm : QueryTerm = {
"!" => TermOrCut::Cut, <Call> => <>,
<Term> => TermOrCut::Term(<>) "!" => QueryTerm::Cut,
<Var> => QueryTerm::CallN(Cell::default(), <>, Vec::new()),
<Clause> => QueryTerm::Term(<>),
<Atom> => QueryTerm::Term(Term::Constant(Cell::default(), Constant::Atom(<>)))
}; };
Term : Term = { Term : Term = {
@@ -83,9 +103,9 @@ Term : Term = {
<Clause> => <>, <Clause> => <>,
<List> => <>, <List> => <>,
<Var> => Term::Var(Cell::default(), <>), <Var> => Term::Var(Cell::default(), <>),
"_" => Term::AnonVar "_" => Term::AnonVar
}; };
Var : Var = { Var : Var = {
r"[A-Z][A-Za-z0-9_]*" => <>.trim().to_string() r"[A-Z][A-Za-z0-9_]*" => <>.trim().to_string()
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -9,11 +9,12 @@ pub trait CompilationTarget<'a> {
fn to_constant(Level, Constant, RegType) -> Self; fn to_constant(Level, Constant, RegType) -> Self;
fn to_list(Level, RegType) -> Self; fn to_list(Level, RegType) -> Self;
fn to_structure(Level, Atom, usize, RegType) -> Self; fn to_structure(Level, Atom, usize, RegType) -> Self;
fn to_void(usize) -> Self; fn to_void(usize) -> Self;
fn is_void_instr(&self) -> bool; fn is_void_instr(&self) -> bool;
fn incr_void_instr(&mut self); fn incr_void_instr(&mut self);
fn constant_subterm(Constant) -> Self; fn constant_subterm(Constant) -> Self;
fn argument_to_variable(RegType, usize) -> Self; fn argument_to_variable(RegType, usize) -> Self;
@@ -56,14 +57,14 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
_ => false _ => false
} }
} }
fn incr_void_instr(&mut self) { fn incr_void_instr(&mut self) {
match self { match self {
&mut FactInstruction::UnifyVoid(ref mut incr) => *incr += 1, &mut FactInstruction::UnifyVoid(ref mut incr) => *incr += 1,
_ => {} _ => {}
} }
} }
fn constant_subterm(constant: Constant) -> Self { fn constant_subterm(constant: Constant) -> Self {
FactInstruction::UnifyConstant(constant) FactInstruction::UnifyConstant(constant)
} }
@@ -129,7 +130,7 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
_ => {} _ => {}
} }
} }
fn constant_subterm(constant: Constant) -> Self { fn constant_subterm(constant: Constant) -> Self {
QueryInstruction::SetConstant(constant) QueryInstruction::SetConstant(constant)
} }
@@ -137,7 +138,7 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
fn argument_to_variable(arg: RegType, val: usize) -> Self { fn argument_to_variable(arg: RegType, val: usize) -> Self {
QueryInstruction::PutVariable(arg, val) QueryInstruction::PutVariable(arg, val)
} }
fn move_to_register(arg: RegType, val: usize) -> Self { fn move_to_register(arg: RegType, val: usize) -> Self {
QueryInstruction::GetVariable(arg, val) QueryInstruction::GetVariable(arg, val)
} }