support call/N
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1,6 +1,6 @@
|
||||
[root]
|
||||
name = "rusty-wam"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
dependencies = [
|
||||
"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)",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rusty-wam"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
authors = ["Mark Thom"]
|
||||
|
||||
build = "build.rs"
|
||||
|
||||
46
README.md
46
README.md
@@ -1,18 +1,35 @@
|
||||
# rusty-wam
|
||||
|
||||
## Phase 1
|
||||
|
||||
An implementation of the Warren Abstract Machine in Rust, done
|
||||
according to the progression of languages in [Warren's Abstract
|
||||
Machine: A Tutorial
|
||||
Reconstruction](http://wambook.sourceforge.net/wambook.pdf), ending in
|
||||
pure Prolog.
|
||||
Reconstruction](http://wambook.sourceforge.net/wambook.pdf).
|
||||
|
||||
## 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
|
||||
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
|
||||
some form all of the WAM book, including lists, cuts, Debray
|
||||
allocation, indexing, and conjunctive queries.
|
||||
## Phase 2
|
||||
|
||||
Extend rusty-wam to include the following, among other features:
|
||||
|
||||
* 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
|
||||
To enter a multi-clause predicate, the brackets ":{" and "}:" are used
|
||||
@@ -92,16 +109,3 @@ Note that the values of variables belonging to successful queries are
|
||||
printed out, on one line each. Uninstantiated variables are denoted by
|
||||
a number preceded by an underscore (`X = _0` is an example in the
|
||||
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(blah)."), true);
|
||||
|
||||
submit(&mut wam, "call(or(X, Y)) :- call(X).
|
||||
call(trace) :- trace.
|
||||
call(or(X, Y)) :- call(Y).
|
||||
call(notrace) :- notrace.
|
||||
call(nl) :- nl.
|
||||
call(X) :- builtin(X).
|
||||
call(X) :- extern(X).
|
||||
call(call(X)) :- call(X).
|
||||
call(repeat).
|
||||
call(repeat) :- call(repeat).
|
||||
call(false).");
|
||||
submit(&mut wam, "ind_call(or(X, Y)) :- ind_call(X).
|
||||
ind_call(trace) :- trace.
|
||||
ind_call(or(X, Y)) :- ind_call(Y).
|
||||
ind_call(notrace) :- notrace.
|
||||
ind_call(nl) :- nl.
|
||||
ind_call(X) :- builtin(X).
|
||||
ind_call(X) :- extern(X).
|
||||
ind_call(ind_call(X)) :- ind_call(X).
|
||||
ind_call(repeat).
|
||||
ind_call(repeat) :- ind_call(repeat).
|
||||
ind_call(false).");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- call(repeat)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(false)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(call(repeat))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(call(false))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(notrace)."), false);
|
||||
assert_eq!(submit(&mut wam, "?- call(nl)."), false);
|
||||
assert_eq!(submit(&mut wam, "?- call(builtin(X))."), false);
|
||||
assert_eq!(submit(&mut wam, "?- call(extern(X))."), false);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(repeat)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(false)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(ind_call(repeat))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(ind_call(false))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(notrace)."), false);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(nl)."), false);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(builtin(X))."), false);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(extern(X))."), false);
|
||||
|
||||
submit(&mut wam, "notrace.");
|
||||
submit(&mut wam, "nl.");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- call(repeat)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(false)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(call(repeat))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(call(false))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(notrace)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(nl)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(builtin(X))."), false);
|
||||
assert_eq!(submit(&mut wam, "?- call(extern(X))."), false);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(repeat)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(false)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(ind_call(repeat))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(ind_call(false))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(notrace)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(nl)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(builtin(X))."), false);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(extern(X))."), false);
|
||||
|
||||
submit(&mut wam, "builtin(X).");
|
||||
submit(&mut wam, "extern(x).");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- call(repeat)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(false)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(call(repeat))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(call(false))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(notrace)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(nl)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(builtin(X))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- call(extern(X))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(repeat)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(false)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(ind_call(repeat))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(ind_call(false))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(notrace)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(nl)."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(builtin(X))."), true);
|
||||
assert_eq!(submit(&mut wam, "?- ind_call(extern(X))."), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -541,6 +541,59 @@ mod tests {
|
||||
assert_eq!(submit(&mut wam, "?- p(X, Y), q(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)
|
||||
|
||||
@@ -18,7 +18,7 @@ pub trait Allocator<'a>
|
||||
fn reset(&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 bindings(&self) -> &AllocVarDict<'a>;
|
||||
|
||||
@@ -44,7 +44,7 @@ impl PredicateClause {
|
||||
pub enum TopLevel {
|
||||
Fact(Term),
|
||||
Predicate(Vec<PredicateClause>),
|
||||
Query(Vec<TermOrCut>),
|
||||
Query(Vec<QueryTerm>),
|
||||
Rule(Rule)
|
||||
}
|
||||
|
||||
@@ -114,23 +114,53 @@ pub enum Term {
|
||||
Var(Cell<VarReg>, Var)
|
||||
}
|
||||
|
||||
pub enum TermOrCut {
|
||||
pub enum QueryTerm {
|
||||
CallN(Cell<VarReg>, Var, Vec<Box<Term>>),
|
||||
Cut,
|
||||
Term(Term)
|
||||
}
|
||||
|
||||
impl TermOrCut {
|
||||
impl QueryTerm {
|
||||
pub fn arity(&self) -> usize {
|
||||
match self {
|
||||
&TermOrCut::Term(ref term) => term.arity(),
|
||||
&QueryTerm::Term(ref term) => term.arity(),
|
||||
&QueryTerm::CallN(_, _, ref terms) => terms.len() + 1,
|
||||
_ => 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 head: (Term, TermOrCut),
|
||||
pub clauses: Vec<TermOrCut>
|
||||
pub head: (Term, QueryTerm),
|
||||
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)]
|
||||
@@ -138,7 +168,7 @@ pub enum TermRef<'a> {
|
||||
AnonVar(Level),
|
||||
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -148,14 +178,39 @@ impl<'a> TermRef<'a> {
|
||||
TermRef::AnonVar(lvl)
|
||||
| TermRef::Cons(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> {
|
||||
Cut, Term(&'a Term)
|
||||
#[derive(Clone, Copy)]
|
||||
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 {
|
||||
@@ -199,6 +254,8 @@ impl IndexedChoiceInstruction {
|
||||
pub enum ControlInstruction {
|
||||
Allocate(usize),
|
||||
Call(Atom, usize, usize),
|
||||
CallN(usize),
|
||||
ExecuteN(usize),
|
||||
Deallocate,
|
||||
Execute(Atom, usize),
|
||||
Proceed
|
||||
@@ -209,6 +266,8 @@ impl ControlInstruction {
|
||||
match self {
|
||||
&ControlInstruction::Call(_, _, _) => true,
|
||||
&ControlInstruction::Execute(_, _) => true,
|
||||
&ControlInstruction::CallN(_) => true,
|
||||
&ControlInstruction::ExecuteN(_) => true,
|
||||
_ => 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> {
|
||||
match self {
|
||||
&Term::Constant(_, Constant::Atom(ref atom))
|
||||
|
||||
@@ -5,7 +5,6 @@ use prolog::indexing::*;
|
||||
use prolog::iterators::*;
|
||||
use prolog::targets::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::HashMap;
|
||||
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)
|
||||
where Iter : Iterator<Item=TermRef<'a>>
|
||||
where Iter: Iterator<Item=TermRef<'a>>
|
||||
{
|
||||
for term in iter {
|
||||
if let TermRef::Var(_, _, var) = term {
|
||||
@@ -48,62 +47,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
*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>)
|
||||
where Target: CompilationTarget<'a>
|
||||
@@ -131,11 +74,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
&Term::AnonVar =>
|
||||
Self::add_or_increment_void_instr(target),
|
||||
&Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _) => {
|
||||
let instr = self.non_var_subterm(Level::Deep, term_loc, cell, target);
|
||||
target.push(instr);
|
||||
self.marker.mark_non_var(Level::Deep, term_loc, cell, target);
|
||||
target.push(Target::clause_arg_to_instr(cell.get()));
|
||||
},
|
||||
&Term::Constant(_, ref constant) =>
|
||||
target.push(self.constant_subterm(constant)),
|
||||
target.push(Target::constant_subterm(constant.clone())),
|
||||
&Term::Var(ref cell, ref var) =>
|
||||
if is_exposed || self.get_var_count(var) > 1 {
|
||||
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)
|
||||
-> Vec<Target>
|
||||
fn compile_clause<Target>(&mut self,
|
||||
ct: ClauseType<'a>,
|
||||
term_loc: GenContext,
|
||||
is_exposed: bool,
|
||||
terms: &'a Vec<Box<Term>>,
|
||||
target: &mut Vec<Target>)
|
||||
where Target: CompilationTarget<'a>
|
||||
{
|
||||
let iter = Target::iter(term);
|
||||
let mut target = Vec::<Target>::new();
|
||||
match ct {
|
||||
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 {
|
||||
match term {
|
||||
TermRef::Clause(lvl, cell, atom, terms) => {
|
||||
let str_instr = self.to_structure(lvl,
|
||||
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::Clause(ct, terms) =>
|
||||
self.compile_clause(ct, term_loc, is_exposed, terms, &mut target),
|
||||
TermRef::Cons(lvl, cell, head, tail) => {
|
||||
let list_instr = self.to_list(lvl, term_loc, cell, &mut target);
|
||||
target.push(list_instr);
|
||||
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
||||
target.push(Target::to_list(lvl, cell.get()));
|
||||
|
||||
self.subterm_to_instr(head, term_loc, is_exposed, &mut target);
|
||||
self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
|
||||
},
|
||||
TermRef::Constant(lvl @ Level::Shallow, cell, constant) => {
|
||||
let const_instr = self.to_constant(lvl, cell, term_loc, constant, &mut target);
|
||||
target.push(const_instr);
|
||||
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
||||
target.push(Target::to_constant(lvl, constant.clone(), cell.get()));
|
||||
},
|
||||
TermRef::AnonVar(lvl @ Level::Shallow) =>
|
||||
if let GenContext::Head = term_loc {
|
||||
@@ -210,13 +165,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
GenContext::Last(chunk_num)
|
||||
};
|
||||
|
||||
match term_or_cut_ref {
|
||||
&TermOrCutRef::Term(term) => {
|
||||
self.update_var_count(term.breadth_first_iter());
|
||||
vs.mark_vars_in_chunk(term, last_term_arity, chunk_num, term_loc);
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
self.update_var_count(term_or_cut_ref.post_order_iter());
|
||||
vs.mark_vars_in_chunk(term_or_cut_ref.post_order_iter(),
|
||||
last_term_arity,
|
||||
chunk_num,
|
||||
term_loc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,14 +179,18 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
(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 {
|
||||
&Term::Constant(_, Constant::Atom(ref atom)) => {
|
||||
match qt {
|
||||
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);
|
||||
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);
|
||||
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 mut dealloc_index = body.len() - 1;
|
||||
|
||||
match toc {
|
||||
&TermOrCut::Term(Term::Clause(_, ref name, _))
|
||||
| &TermOrCut::Term(Term::Constant(_, Constant::Atom(ref name))) =>
|
||||
&QueryTerm::Term(Term::Clause(_, ref name, _))
|
||||
| &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref name))) =>
|
||||
if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() {
|
||||
*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
|
||||
}
|
||||
|
||||
fn compile_seq(&mut self,
|
||||
clauses: &'a [TermOrCut],
|
||||
clauses: &'a [QueryTerm],
|
||||
vs: &VariableFixtures<'a>,
|
||||
body: &mut Code,
|
||||
is_exposed: bool)
|
||||
@@ -270,24 +232,20 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
self.marker.reset_contents();
|
||||
|
||||
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 {
|
||||
&TermOrCutRef::Cut if i + 1 < terms.len() =>
|
||||
&QueryTermRef::Cut if i + 1 < terms.len() =>
|
||||
vec![Line::Cut(CutInstruction::Cut(Terminal::Non))],
|
||||
&TermOrCutRef::Cut =>
|
||||
&QueryTermRef::Cut =>
|
||||
vec![Line::Cut(CutInstruction::Cut(Terminal::Terminal))],
|
||||
&TermOrCutRef::Term(term) if i + 1 < terms.len() => {
|
||||
_ => {
|
||||
let num_vars = vs.vars_above_threshold(i + 1);
|
||||
self.compile_query_line(term,
|
||||
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)
|
||||
self.compile_query_line(*term, term_loc, num_vars, is_exposed)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -317,14 +275,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
}
|
||||
|
||||
fn compile_neck_cut_or(&mut self,
|
||||
p1: &'a TermOrCut,
|
||||
p1: &'a QueryTerm,
|
||||
body: &mut Code,
|
||||
perm_vars: usize,
|
||||
is_exposed: bool,
|
||||
at_end: bool)
|
||||
{
|
||||
match p1 {
|
||||
&TermOrCut::Cut => {
|
||||
&QueryTerm::Cut => {
|
||||
let term = if at_end {
|
||||
Terminal::Terminal
|
||||
} else {
|
||||
@@ -333,25 +291,26 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
|
||||
body.push(Line::Cut(CutInstruction::NeckCut(term)));
|
||||
},
|
||||
&TermOrCut::Term(ref p1) => {
|
||||
_ => {
|
||||
let p1 = p1.to_ref();
|
||||
|
||||
self.marker.advance(GenContext::Head, p1);
|
||||
|
||||
if p1.is_clause() {
|
||||
let term_loc = if p1.is_callable() {
|
||||
GenContext::Last(0)
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -369,12 +328,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
||||
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);
|
||||
|
||||
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);
|
||||
@@ -430,12 +390,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
let (vs, _) = self.collect_var_data(iter);
|
||||
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();
|
||||
|
||||
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);
|
||||
code.push(Line::Fact(compiled_fact));
|
||||
}
|
||||
@@ -447,7 +409,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
}
|
||||
|
||||
fn compile_query_line(&mut self,
|
||||
term: &'a Term,
|
||||
term: QueryTermRef<'a>,
|
||||
term_loc: GenContext,
|
||||
index: usize,
|
||||
is_exposed: bool)
|
||||
@@ -457,17 +419,17 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
|
||||
let mut code = Vec::new();
|
||||
|
||||
if term.is_clause() {
|
||||
let compiled_query = Line::Query(self.compile_target(term, term_loc, is_exposed));
|
||||
let iter = term.post_order_iter();
|
||||
let compiled_query = Line::Query(self.compile_target(iter, term_loc, is_exposed));
|
||||
|
||||
code.push(compiled_query);
|
||||
}
|
||||
|
||||
Self::add_conditional_call(&mut code, term, index);
|
||||
|
||||
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 (mut vs, deep_cuts) = self.collect_var_data(iter);
|
||||
|
||||
@@ -332,7 +332,7 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
|
||||
self.bindings
|
||||
}
|
||||
|
||||
fn advance(&mut self, _: GenContext, term: &'a Term) {
|
||||
fn advance(&mut self, _: GenContext, term: QueryTermRef<'a>) {
|
||||
self.arg_c = 1;
|
||||
self.temp_lb = term.arity() + 1;
|
||||
}
|
||||
|
||||
@@ -171,15 +171,16 @@ impl<'a> VariableFixtures<'a>
|
||||
var_count
|
||||
}
|
||||
|
||||
pub fn mark_vars_in_chunk(&mut self,
|
||||
term: &'a Term,
|
||||
pub fn mark_vars_in_chunk<Iter>(&mut self,
|
||||
iter: Iter,
|
||||
last_term_arity: usize,
|
||||
chunk_num: usize,
|
||||
term_loc: GenContext)
|
||||
where Iter: Iterator<Item=TermRef<'a>>
|
||||
{
|
||||
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 {
|
||||
let mut status = self.0.remove(var)
|
||||
.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),
|
||||
&ControlInstruction::Call(ref 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 =>
|
||||
write!(f, "deallocate"),
|
||||
&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) {
|
||||
let compiled_pred = cg.compile_predicate(clauses);
|
||||
print_code(&compiled_pred);
|
||||
wam.add_predicate(clauses, compiled_pred);
|
||||
|
||||
EvalSession::EntrySuccess
|
||||
@@ -280,6 +285,7 @@ Each predicate must have the same name and arity.";
|
||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
||||
|
||||
let compiled_fact = cg.compile_fact(fact);
|
||||
print_code(&compiled_fact);
|
||||
wam.add_fact(fact, compiled_fact);
|
||||
|
||||
EvalSession::EntrySuccess
|
||||
@@ -288,6 +294,7 @@ Each predicate must have the same name and arity.";
|
||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
||||
|
||||
let compiled_rule = cg.compile_rule(rule);
|
||||
print_code(&compiled_rule);
|
||||
wam.add_rule(rule, compiled_rule);
|
||||
|
||||
EvalSession::EntrySuccess
|
||||
@@ -296,6 +303,7 @@ Each predicate must have the same name and arity.";
|
||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
||||
|
||||
let compiled_query = cg.compile_query(query);
|
||||
print_code(&compiled_query);
|
||||
wam.submit_query(compiled_query, cg.take_vars())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,10 @@ use std::vec::Vec;
|
||||
|
||||
enum IteratorState<'a> {
|
||||
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),
|
||||
InitialCons(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)
|
||||
}
|
||||
|
||||
@@ -21,7 +20,7 @@ impl<'a> IteratorState<'a> {
|
||||
&Term::AnonVar =>
|
||||
IteratorState::AnonVar(lvl),
|
||||
&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) =>
|
||||
IteratorState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()),
|
||||
&Term::Constant(ref cell, ref constant) =>
|
||||
@@ -37,46 +36,26 @@ pub struct QueryIterator<'a> {
|
||||
}
|
||||
|
||||
impl<'a> QueryIterator<'a> {
|
||||
fn push_clause(&mut self,
|
||||
lvl: Level,
|
||||
child_num: usize,
|
||||
cell: &'a Cell<RegType>,
|
||||
name: &'a Atom,
|
||||
child_terms: &'a Vec<Box<Term>>)
|
||||
fn push_clause(&mut self, child_num: usize, ct: ClauseType<'a>, child_terms: &'a Vec<Box<Term>>)
|
||||
{
|
||||
self.state_stack.push(IteratorState::Clause(lvl,
|
||||
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));
|
||||
self.state_stack.push(IteratorState::Clause(child_num, ct, child_terms));
|
||||
}
|
||||
|
||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||
self.state_stack.push(IteratorState::to_state(lvl, term));
|
||||
}
|
||||
|
||||
fn push_final_cons(&mut self,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<RegType>,
|
||||
head: &'a Term,
|
||||
tail: &'a Term)
|
||||
fn push_final_cons(&mut self, lvl: Level, cell: &'a Cell<RegType>, head: &'a Term, tail: &'a Term)
|
||||
{
|
||||
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 {
|
||||
&Term::AnonVar =>
|
||||
IteratorState::AnonVar(Level::Shallow),
|
||||
&Term::Clause(_, _, ref terms) =>
|
||||
IteratorState::RootClause(0, terms),
|
||||
IteratorState::Clause(0, ClauseType::Root, terms),
|
||||
&Term::Cons(ref cell, ref head, ref tail) =>
|
||||
IteratorState::InitialCons(Level::Shallow, cell, head.as_ref(), tail.as_ref()),
|
||||
&Term::Constant(ref cell, ref constant) =>
|
||||
@@ -87,6 +66,24 @@ impl<'a> QueryIterator<'a> {
|
||||
|
||||
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> {
|
||||
@@ -97,12 +94,21 @@ impl<'a> Iterator for QueryIterator<'a> {
|
||||
match iter_state {
|
||||
IteratorState::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() {
|
||||
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 {
|
||||
self.push_clause(lvl, child_num + 1, cell, atom, child_terms);
|
||||
self.push_subterm(Level::Deep, child_terms[child_num].as_ref());
|
||||
self.push_clause(child_num + 1, ct, child_terms);
|
||||
self.push_subterm(ct.level_of_subterms(), child_terms[child_num].as_ref());
|
||||
}
|
||||
},
|
||||
IteratorState::InitialCons(lvl, cell, head, tail) => {
|
||||
@@ -114,14 +120,6 @@ impl<'a> Iterator for QueryIterator<'a> {
|
||||
return Some(TermRef::Cons(lvl, cell, head, tail)),
|
||||
IteratorState::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) =>
|
||||
return Some(TermRef::Var(lvl, cell, var))
|
||||
};
|
||||
@@ -145,7 +143,7 @@ impl<'a> FactIterator<'a> {
|
||||
&Term::AnonVar =>
|
||||
vec![IteratorState::AnonVar(Level::Shallow)],
|
||||
&Term::Clause(_, _, ref terms) =>
|
||||
vec![IteratorState::RootClause(0, terms)],
|
||||
vec![IteratorState::Clause(0, ClauseType::Root, terms)],
|
||||
&Term::Cons(ref cell, ref head, ref tail) =>
|
||||
vec![IteratorState::InitialCons(Level::Shallow,
|
||||
cell,
|
||||
@@ -169,12 +167,21 @@ impl<'a> Iterator for FactIterator<'a> {
|
||||
match state {
|
||||
IteratorState::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 {
|
||||
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) => {
|
||||
self.push_subterm(Level::Deep, head);
|
||||
@@ -184,11 +191,6 @@ impl<'a> Iterator for FactIterator<'a> {
|
||||
},
|
||||
IteratorState::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) =>
|
||||
return Some(TermRef::Var(lvl, cell, var)),
|
||||
_ => {}
|
||||
@@ -201,7 +203,7 @@ impl<'a> Iterator for FactIterator<'a> {
|
||||
|
||||
impl Term {
|
||||
pub fn post_order_iter(&self) -> QueryIterator {
|
||||
QueryIterator::new(self)
|
||||
QueryIterator::new(QueryTermRef::Term(self))
|
||||
}
|
||||
|
||||
pub fn breadth_first_iter(&self) -> FactIterator {
|
||||
@@ -212,7 +214,7 @@ impl Term {
|
||||
pub struct ChunkedIterator<'a>
|
||||
{
|
||||
at_head: bool,
|
||||
iter: Box<Iterator<Item=TermOrCutRef<'a>> + 'a>,
|
||||
iter: Box<Iterator<Item=QueryTermRef<'a>> + 'a>,
|
||||
deep_cut_encountered: bool
|
||||
}
|
||||
|
||||
@@ -220,8 +222,8 @@ impl<'a> ChunkedIterator<'a>
|
||||
{
|
||||
pub fn from_term(term: &'a Term, at_head: bool) -> Self
|
||||
{
|
||||
let inner_iter: Box<Iterator<Item=TermOrCutRef<'a>>> =
|
||||
Box::new(once(TermOrCutRef::Term(term)));
|
||||
let inner_iter: Box<Iterator<Item=QueryTermRef<'a>>> =
|
||||
Box::new(once(QueryTermRef::Term(term)));
|
||||
|
||||
ChunkedIterator {
|
||||
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| {
|
||||
match c {
|
||||
&TermOrCut::Cut => TermOrCutRef::Cut,
|
||||
&TermOrCut::Term(ref term) => TermOrCutRef::Term(term)
|
||||
}
|
||||
});
|
||||
let iter = terms.iter().map(|c| c.to_ref());
|
||||
|
||||
ChunkedIterator {
|
||||
at_head: false,
|
||||
@@ -249,19 +246,17 @@ impl<'a> ChunkedIterator<'a>
|
||||
pub fn from_rule(rule: &'a Rule) -> Self
|
||||
{
|
||||
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 {
|
||||
&TermOrCut::Term(ref p1) => Box::new(once(TermOrCutRef::Term(p1))),
|
||||
let inner_iter : Box<Iterator<Item=QueryTermRef<'a>>> = match 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())
|
||||
};
|
||||
|
||||
let iter = iter.chain(inner_iter.chain(clauses.iter().map(|c| {
|
||||
match c {
|
||||
&TermOrCut::Cut => TermOrCutRef::Cut,
|
||||
&TermOrCut::Term(ref term) => TermOrCutRef::Term(term)
|
||||
}
|
||||
})));
|
||||
let iter = iter.chain(inner_iter.chain(clauses.iter().map(|c| c.to_ref())));
|
||||
|
||||
ChunkedIterator {
|
||||
at_head: true,
|
||||
@@ -278,14 +273,14 @@ impl<'a> ChunkedIterator<'a>
|
||||
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 arity = 0;
|
||||
|
||||
while let Some(term) = self.iter.next() {
|
||||
match term {
|
||||
TermOrCutRef::Term(inner_term) => {
|
||||
QueryTermRef::Term(inner_term) => {
|
||||
result.push(term);
|
||||
|
||||
if inner_term.is_callable() {
|
||||
@@ -293,6 +288,11 @@ impl<'a> ChunkedIterator<'a>
|
||||
break;
|
||||
}
|
||||
},
|
||||
QueryTermRef::CallN(_, _, child_terms) => {
|
||||
result.push(term);
|
||||
arity = child_terms.len() + 1;
|
||||
break;
|
||||
},
|
||||
_ => {
|
||||
result.push(term);
|
||||
self.deep_cut_encountered = true;
|
||||
@@ -307,18 +307,18 @@ impl<'a> ChunkedIterator<'a>
|
||||
impl<'a> Iterator for ChunkedIterator<'a>
|
||||
{
|
||||
// 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> {
|
||||
loop {
|
||||
match self.iter.next() {
|
||||
None => return None,
|
||||
Some(TermOrCutRef::Term(term)) if self.at_head => {
|
||||
Some(QueryTermRef::Term(term)) if self.at_head => {
|
||||
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() =>
|
||||
return Some((term.arity(), vec![TermOrCutRef::Term(term)])),
|
||||
Some(QueryTermRef::Term(term)) if term.is_callable() =>
|
||||
return Some((term.arity(), vec![QueryTermRef::Term(term)])),
|
||||
Some(term_or_cut_ref) =>
|
||||
return Some(self.take_chunk(term_or_cut_ref))
|
||||
}
|
||||
|
||||
@@ -289,8 +289,8 @@ impl Machine {
|
||||
pub fn submit_query<'a>(&mut self, code: Code, alloc_locs: AllocVarDict<'a>) -> EvalSession<'a>
|
||||
{
|
||||
let mut heap_locs = HashMap::new();
|
||||
self.cached_query = Some(code);
|
||||
|
||||
self.cached_query = Some(code);
|
||||
self.run_query(&alloc_locs, &mut heap_locs);
|
||||
|
||||
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)
|
||||
{
|
||||
match instr {
|
||||
@@ -962,18 +991,29 @@ impl MachineState {
|
||||
self.e = self.and_stack.len() - 1;
|
||||
self.p += 1;
|
||||
},
|
||||
&ControlInstruction::Call(ref name, arity, _) => {
|
||||
let compiled_tl_index = code_dir.get(&(name.clone(), arity))
|
||||
.map(|index| *index);
|
||||
&ControlInstruction::Call(ref name, arity, _) =>
|
||||
self.try_call_predicate(code_dir, name.clone(), arity),
|
||||
&ControlInstruction::CallN(arity) => {
|
||||
let addr = self.deref(self.registers[arity + 1].clone());
|
||||
|
||||
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);
|
||||
match self.store(addr) {
|
||||
Addr::Str(a) => {
|
||||
let result = self.heap[a].clone();
|
||||
|
||||
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_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 => {
|
||||
@@ -984,17 +1024,29 @@ impl MachineState {
|
||||
|
||||
self.p += 1;
|
||||
},
|
||||
&ControlInstruction::Execute(ref name, arity) => {
|
||||
let compiled_tl_index = code_dir.get(&(name.clone(), arity))
|
||||
.map(|index| *index);
|
||||
&ControlInstruction::Execute(ref name, arity) =>
|
||||
self.try_execute_predicate(code_dir, name.clone(), arity),
|
||||
&ControlInstruction::ExecuteN(arity) => {
|
||||
let addr = self.deref(self.registers[arity + 1].clone());
|
||||
|
||||
match compiled_tl_index {
|
||||
Some(compiled_tl_index) => {
|
||||
self.num_of_args = arity;
|
||||
self.b0 = self.b;
|
||||
self.p = CodePtr::DirEntry(compiled_tl_index);
|
||||
match self.store(addr) {
|
||||
Addr::Str(a) => {
|
||||
let result = self.heap[a].clone();
|
||||
|
||||
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 =>
|
||||
|
||||
@@ -129,13 +129,13 @@ impl<'a> Allocator<'a> for NaiveAllocator<'a>
|
||||
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 {
|
||||
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 {
|
||||
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)
|
||||
};
|
||||
|
||||
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 = {
|
||||
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
|
||||
let mut ts = ts;
|
||||
@@ -56,8 +73,8 @@ PredicateClause : PredicateClause = {
|
||||
<Term> "." => PredicateClause::Fact(<>)
|
||||
};
|
||||
|
||||
Query : Vec<TermOrCut> = {
|
||||
<tcs: (<TermOrCut> ",")*> <tc: TermOrCut> => {
|
||||
Query : Vec<QueryTerm> = {
|
||||
<tcs: (<QueryTerm> ",")*> <tc: QueryTerm> => {
|
||||
let mut tcs = tcs;
|
||||
tcs.push(tc);
|
||||
tcs
|
||||
@@ -65,17 +82,20 @@ Query : Vec<TermOrCut> = {
|
||||
};
|
||||
|
||||
Rule : Rule = {
|
||||
<c:Clause> ":-" <h:TermOrCut> <cs: ("," <TermOrCut>)*> =>
|
||||
<c:Clause> ":-" <h:QueryTerm> <cs: ("," <QueryTerm>)*> =>
|
||||
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)),
|
||||
h),
|
||||
clauses: cs }
|
||||
};
|
||||
|
||||
TermOrCut : TermOrCut = {
|
||||
"!" => TermOrCut::Cut,
|
||||
<Term> => TermOrCut::Term(<>)
|
||||
QueryTerm : QueryTerm = {
|
||||
<Call> => <>,
|
||||
"!" => QueryTerm::Cut,
|
||||
<Var> => QueryTerm::CallN(Cell::default(), <>, Vec::new()),
|
||||
<Clause> => QueryTerm::Term(<>),
|
||||
<Atom> => QueryTerm::Term(Term::Constant(Cell::default(), Constant::Atom(<>)))
|
||||
};
|
||||
|
||||
Term : Term = {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,7 @@ pub trait CompilationTarget<'a> {
|
||||
|
||||
fn to_void(usize) -> Self;
|
||||
fn is_void_instr(&self) -> bool;
|
||||
|
||||
fn incr_void_instr(&mut self);
|
||||
|
||||
fn constant_subterm(Constant) -> Self;
|
||||
|
||||
Reference in New Issue
Block a user