support call/N

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

2
Cargo.lock generated
View File

@@ -1,6 +1,6 @@
[root]
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)",

View File

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

View File

@@ -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*
```

View File

@@ -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)

View File

@@ -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>;

View File

@@ -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))

View File

@@ -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))) =>
if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() {
*ctrl = ControlInstruction::Execute(name.clone(), last_arity);
},
&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)
};
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));
code.push(compiled_query);
}
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);

View File

@@ -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;
}

View File

@@ -171,15 +171,16 @@ impl<'a> VariableFixtures<'a>
var_count
}
pub fn mark_vars_in_chunk(&mut self,
term: &'a Term,
last_term_arity: usize,
chunk_num: usize,
term_loc: GenContext)
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)),

View File

@@ -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())
}
}

View File

@@ -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))
}

View File

@@ -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 =>

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;