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

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,31 +114,61 @@ 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)]
pub enum TermRef<'a> {
AnonVar(Level),
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)
}
@@ -147,15 +177,40 @@ impl<'a> TermRef<'a> {
match self {
TermRef::AnonVar(lvl)
| TermRef::Cons(lvl, _, _, _)
| TermRef::Constant(lvl, _, _)
| TermRef::Clause(lvl, _, _, _)
| TermRef::Var(lvl, _, _) => lvl
| TermRef::Constant(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,7 +303,8 @@ Each predicate must have the same name and arity.";
let mut cg = CodeGenerator::<DebrayAllocator>::new();
let compiled_query = cg.compile_query(query);
wam.submit_query(compiled_query, cg.take_vars())
print_code(&compiled_query);
wam.submit_query(compiled_query, cg.take_vars())
}
}
}

View File

@@ -7,11 +7,10 @@ use std::vec::Vec;
enum IteratorState<'a> {
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,
@@ -245,24 +242,22 @@ impl<'a> ChunkedIterator<'a>
deep_cut_encountered: false
}
}
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,
iter: Box::new(iter),
@@ -277,15 +272,15 @@ impl<'a> ChunkedIterator<'a>
pub fn at_head(&self) -> bool {
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,9 +288,14 @@ 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;
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

@@ -247,13 +247,13 @@ impl Machine {
let e = self.ms.e;
let r = var_data.as_reg_type().reg_num();
let addr = self.ms.and_stack[e][r].clone();
heap_locs.insert(var, addr);
},
&VarData::Temp(cn, _, _) if cn == chunk_num => {
let r = var_data.as_reg_type();
let addr = self.ms[r].clone();
heap_locs.insert(var, addr);
},
_ => {}
@@ -276,21 +276,21 @@ impl Machine {
self.ms.p = CodePtr::TopLevel(cn, p);
}
self.query_stepper();
match self.ms.p {
CodePtr::TopLevel(_, p) if p > 0 => {},
_ => break
};
_ => break
};
}
}
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 {
@@ -958,22 +987,33 @@ impl MachineState {
let num_frames = self.num_frames();
self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells);
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,18 +1024,30 @@ 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 =>
self.p = self.cp,

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,26 +73,29 @@ 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
}
}
};
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 = {
@@ -83,9 +103,9 @@ Term : Term = {
<Clause> => <>,
<List> => <>,
<Var> => Term::Var(Cell::default(), <>),
"_" => Term::AnonVar
"_" => Term::AnonVar
};
Var : Var = {
r"[A-Z][A-Za-z0-9_]*" => <>.trim().to_string()
};
};

File diff suppressed because it is too large Load Diff

View File

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