support call/N
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -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)",
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
48
README.md
48
README.md
@@ -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*
|
|
||||||
```
|
|
||||||
123
src/main.rs
123
src/main.rs
@@ -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)
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)),
|
||||||
|
|||||||
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user