[root]
name = "rusty-wam"
-version = "0.6.6"
+version = "0.6.7"
dependencies = [
"lalrpop 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-util 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
[package]
name = "rusty-wam"
-version = "0.6.6"
+version = "0.6.7"
authors = ["Mark Thom"]
build = "build.rs"
Extend rusty-wam to include the following, among other features:
* call/N as a built-in meta-predicate (_done_).
-* ISO Prolog compliant throw/catch.
+* ISO Prolog compliant throw/catch (_done_).
* Built-in and user-defined operators of all fixities,
with custom associativity and precedence.
* Bignum and floating point arithmetic.
assert_eq!(submit(&mut wam, "?- call(call(call(call(call(call)))))."), false);
assert_eq!(submit(&mut wam, "?- call(call(call(call(call(call(p(X)))))))."), true);
}
+
+ #[test]
+ fn test_queries_on_exceptions()
+ {
+ let mut wam = Machine::new();
+
+ submit(&mut wam, "f(a). f(_) :- throw(stuff).");
+ submit(&mut wam, "handle(stuff).");
+
+ assert_eq!(submit(&mut wam, "?- catch(f(X), Exception, handle(Exception))."), true);
+
+ submit(&mut wam, "f(a). f(X) :- g(X).");
+ submit(&mut wam, "g(x). g(y). g(z).");
+ submit(&mut wam, "handle(x). handle(y).");
+
+ assert_eq!(submit(&mut wam, "?- catch(f(X), X, handle(X))."), true);
+ assert_eq!(submit(&mut wam, "?- catch(f(a), _, handle(X))."), true);
+ assert_eq!(submit(&mut wam, "?- catch(f(b), _, handle(X))."), false);
+
+ submit(&mut wam, "g(x). g(X) :- throw(x).");
+
+ assert_eq!(submit(&mut wam, "?- catch(f(X), x, handle(X))."), true);
+ assert_eq!(submit(&mut wam, "?- catch(f(X), x, handle(z))."), true);
+ assert_eq!(submit(&mut wam, "?- catch(f(z), x, handle(x))."), true);
+ assert_eq!(submit(&mut wam, "?- catch(f(z), x, handle(y))."), true);
+ assert_eq!(submit(&mut wam, "?- catch(f(z), x, handle(z))."), false);
+
+ //TODO: write more tests: multi-layered throw/catch, catch
+ // within catch, throw within catch, etc.
+ }
}
fn process_buffer(wam: &mut Machine, buffer: &str)
fn bindings_mut(&mut self) -> &mut AllocVarDict<'a>;
fn take_bindings(self) -> AllocVarDict<'a>;
-
+
fn drain_var_data(&mut self, vs: VariableFixtures<'a>) -> VariableFixtures<'a>
{
let mut perm_vs = VariableFixtures::new();
GenContext::Head => 0,
GenContext::Mid(cn) | GenContext::Last(cn) => cn
}
- }
+ }
}
pub enum PredicateClause {
ref mut clauses })
=>
{
- iter = Box::new(once(head));
+ iter = Box::new(iter.chain(once(head)));
iter = Box::new(iter.chain(clauses.iter_mut()));
},
_ => {}
},
_ => {}
}
-
+
iter
}
}
#[derive(Clone, Hash, PartialEq, Eq)]
pub enum Constant {
Atom(Atom),
+ UInt64(usize),
EmptyList
}
}
impl QueryTerm {
- pub fn arity(&self) -> usize {
- match self {
- &QueryTerm::Term(ref term) => term.arity(),
- &QueryTerm::CallN(ref terms) => terms.len(),
- _ => 0
- }
- }
-
pub fn to_ref(&self) -> QueryTermRef {
match self {
&QueryTerm::CallN(ref terms) =>
&QueryTerm::Cut =>
QueryTermRef::Cut,
&QueryTerm::Term(ref term) =>
- QueryTermRef::Term(term)
+ QueryTermRef::Term(term),
}
}
}
#[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(ClauseType<'a>, &'a Vec<Box<Term>>),
match self {
TermRef::AnonVar(lvl)
| TermRef::Cons(lvl, _, _, _)
- | TermRef::Constant(lvl, _, _)
+ | TermRef::Constant(lvl, _, _)
| TermRef::Var(lvl, _, _) => lvl,
TermRef::Clause(ClauseType::Root, _) => Level::Shallow,
TermRef::Clause(ClauseType::Deep(lvl, _, _), _) => lvl,
pub enum QueryTermRef<'a> {
CallN(&'a Vec<Box<Term>>),
Cut,
- Term(&'a Term)
+ Term(&'a Term),
}
impl<'a> QueryTermRef<'a> {
pub fn arity(self) -> usize {
match self {
- QueryTermRef::Term(term) => term.arity(),
QueryTermRef::CallN(terms) => terms.len(),
- _ => 0
+ QueryTermRef::Cut => 0,
+ QueryTermRef::Term(term) => term.arity(),
}
}
-
- pub fn is_callable(self) -> bool {
- match self {
- QueryTermRef::Term(&Term::Clause(_, _, _))
- | QueryTermRef::Term(&Term::Constant(_, Constant::Atom(_)))
- | QueryTermRef::CallN(_) => true,
- _ => false
- }
- }
}
pub enum ChoiceInstruction {
}
}
-pub enum BuiltInInstruction {
- InternalCallN
+pub enum BuiltInInstruction {
+ CleanUpBlock,
+ CopyTerm,
+ Fail,
+ GetBall,
+ GetCurrentBlock,
+ Goto(usize, usize),
+ InstallNewBlock,
+ InternalCallN,
+ IsAtomic,
+ IsVar,
+ ResetBlock,
+ SetBall,
+ Unify,
+ UnwindStack
}
pub enum ControlInstruction {
Allocate(usize),
Call(Atom, usize, usize),
CallN(usize),
- ExecuteN(usize),
Deallocate,
Execute(Atom, usize),
+ ExecuteN(usize),
Proceed
}
_ => None
}
}
-
+
pub fn arity(&self) -> usize {
match self {
&Term::Clause(_, _, ref child_terms) => child_terms.len(),
}
}
}
-
--- /dev/null
+use prolog::ast::*;
+
+use std::collections::HashMap;
+
+pub type PredicateKey = (Atom, usize); // name, arity, type.
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub enum PredicateKeyType {
+ BuiltIn,
+ User
+}
+
+pub type CodeDir = HashMap<PredicateKey, (PredicateKeyType, usize)>;
+
+fn get_builtins() -> Code {
+ vec![internal_call_n!(), // callN/N, 0.
+ is_atomic!(), // atomic/1, 1.
+ proceed!(),
+ is_var!(), // var/1, 3.
+ proceed!(),
+ allocate!(4), // catch/3, 5.
+ query![get_var_in_query!(perm_v!(2), 1),
+ get_var_in_query!(perm_v!(3), 2),
+ get_var_in_query!(perm_v!(1), 3),
+ put_var!(perm_v!(4), 1)],
+ get_current_block!(),
+ query![put_value!(perm_v!(2), 1),
+ put_value!(perm_v!(3), 2),
+ put_value!(perm_v!(1), 3),
+ put_unsafe_value!(4, 4)],
+ deallocate!(),
+ goto!(11, 4),
+ try_me_else!(9), // catch/4, 11.
+ allocate!(3),
+ query![get_var_in_query!(perm_v!(3), 1),
+ get_var_in_query!(perm_v!(2), 4),
+ put_var!(perm_v!(1), 1)],
+ install_new_block!(),
+ query![put_value!(perm_v!(3), 1)],
+ call_n!(1),
+ query![put_value!(perm_v!(2), 1),
+ put_unsafe_value!(1, 2)],
+ deallocate!(),
+ goto!(42, 2), // goto end_block/2 at 42.
+ trust_me!(),
+ allocate!(4),
+ query![get_var_in_query!(perm_v!(2), 2),
+ get_var_in_query!(perm_v!(1), 3),
+ get_var_in_query!(temp_v!(2), 1),
+ put_value!(temp_v!(4), 1)],
+ reset_block!(),
+ query![put_var!(perm_v!(4), 1)],
+ get_ball!(),
+ query![put_value!(perm_v!(4), 1),
+ put_var!(perm_v!(3), 2)],
+ copy_term!(),
+ query![put_unsafe_value!(3, 1),
+ put_value!(perm_v!(2), 2),
+ put_value!(perm_v!(1), 3)],
+ deallocate!(),
+ goto!(31, 2), // goto handle_ball/2.
+ try_me_else!(10), // handle_ball/2, 31.
+ allocate!(2),
+ get_level!(),
+ query![get_var_in_query!(perm_v!(2), 3)],
+ unify!(),
+ cut!(non_terminal!()),
+ query![put_value!(perm_v!(2), 1)],
+ deallocate!(),
+ execute_n!(1),
+ trust_me!(),
+ unwind_stack!(),
+ try_me_else!(8), // end_block/2, 42.
+ allocate!(1),
+ query![get_var_in_query!(perm_v!(1), 1),
+ put_value!(temp_v!(2), 1)],
+ clean_up_block!(),
+ query![put_value!(perm_v!(1), 1)],
+ deallocate!(),
+ reset_block!(),
+ proceed!(),
+ trust_me!(),
+ allocate!(0),
+ query![get_var_in_query!(temp_v!(3), 1),
+ put_value!(temp_v!(2), 1)],
+ reset_block!(),
+ deallocate!(),
+ goto!(58, 0), // goto false.
+ set_ball!(), // throw/1, 56.
+ unwind_stack!(),
+ fail!(), // false/0, 58.
+ proceed!(),
+ try_me_else!(7), // not/1, 60.
+ allocate!(1),
+ get_level!(),
+ call_n!(1),
+ cut!(non_terminal!()),
+ deallocate!(),
+ goto!(58, 0), // goto false.
+ trust_me!(),
+ proceed!(),
+ copy_term!(), // copy_term/2, 69.
+ proceed!()]
+}
+
+pub fn build_code_dir() -> (Code, CodeDir) {
+ let mut code_dir = HashMap::new();
+ let builtin_code = get_builtins();
+
+ // there are 63 registers in the VM, so call/N is defined for all 0 <= N <= 62
+ // (an extra register is needed for the predicate name)
+ for arity in 0 .. 63 {
+ code_dir.insert((String::from("call"), arity), (PredicateKeyType::BuiltIn, 0));
+ }
+
+ code_dir.insert((String::from("atomic"), 1), (PredicateKeyType::BuiltIn, 1));
+ code_dir.insert((String::from("var"), 1), (PredicateKeyType::BuiltIn, 3));
+ code_dir.insert((String::from("false"), 0), (PredicateKeyType::BuiltIn, 58));
+ code_dir.insert((String::from("not"), 1), (PredicateKeyType::BuiltIn, 60));
+ code_dir.insert((String::from("copy_term"), 2), (PredicateKeyType::BuiltIn, 69));
+ code_dir.insert((String::from("catch"), 3), (PredicateKeyType::BuiltIn, 5));
+ code_dir.insert((String::from("throw"), 1), (PredicateKeyType::BuiltIn, 56));
+
+ (builtin_code, code_dir)
+}
SubsequentQuerySuccess,
}
+pub struct ConjunctInfo<'a> {
+ pub perm_vs: VariableFixtures<'a>,
+ pub num_of_chunks: usize,
+ pub has_deep_cut: bool,
+ pub has_catch: bool
+}
+
+impl<'a> ConjunctInfo<'a>
+{
+ fn new(perm_vs: VariableFixtures<'a>, num_of_chunks: usize, has_deep_cut: bool, has_catch: bool)
+ -> Self
+ {
+ ConjunctInfo { perm_vs, num_of_chunks, has_deep_cut, has_catch }
+ }
+
+ fn allocates(&self) -> bool {
+ self.perm_vs.size() > 0 || self.num_of_chunks > 1 || self.has_deep_cut || self.has_catch
+ }
+
+ fn perm_vars(&self) -> usize {
+ self.perm_vs.size() + self.perm_var_offset()
+ }
+
+ fn perm_var_offset(&self) -> usize {
+ self.has_deep_cut as usize + 2 * (self.has_catch as usize)
+ }
+}
+
impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
{
pub fn new() -> Self {
*self.var_count.get(var).unwrap()
}
-
fn add_or_increment_void_instr<Target>(target: &mut Vec<Target>)
where Target: CompilationTarget<'a>
{
target
}
- fn collect_var_data(&mut self, iter: ChunkedIterator<'a>) -> (VariableFixtures<'a>, bool)
+ fn collect_var_data(&mut self, mut iter: ChunkedIterator<'a>) -> ConjunctInfo<'a>
{
let mut vs = VariableFixtures::new();
- let has_deep_cut = iter.contains_deep_cut();
- let has_head = iter.at_head();
+ let at_rule_head = iter.at_rule_head();
- for (chunk_num, (last_term_arity, terms)) in iter.enumerate() {
+ while let Some((chunk_num, last_term_arity, terms)) = iter.next() {
for (i, term_or_cut_ref) in terms.iter().enumerate() {
- let term_loc = if chunk_num == 0 && i == 0 && has_head {
+ let term_loc = if chunk_num == 0 && i == 0 && at_rule_head {
GenContext::Head
} else if i < terms.len() - 1 {
GenContext::Mid(chunk_num)
}
}
+ let num_of_chunks = iter.chunk_num();
+ let has_deep_cut = iter.encountered_deep_cut();
+ let has_catch = iter.encountered_catch();
+
vs.populate_restricting_sets();
- vs.set_perm_vals(has_deep_cut);
+ vs.set_perm_vals(has_deep_cut, has_catch);
- (vs, has_deep_cut)
+ let vs = self.marker.drain_var_data(vs);
+
+ ConjunctInfo::new(vs, num_of_chunks, has_deep_cut, has_catch)
}
fn add_conditional_call(compiled_query: &mut Code, qt: QueryTermRef, pvs: usize)
{
- match qt {
+ match qt {
QueryTermRef::CallN(terms) => {
let call = ControlInstruction::CallN(terms.len());
compiled_query.push(Line::Control(call));
}
}
- fn lco(body: &mut Code, toc: &QueryTerm) -> usize
+ fn lco(body: &mut Code, toc: QueryTermRef<'a>) -> usize
{
let last_arity = toc.arity();
let mut dealloc_index = body.len() - 1;
match toc {
- &QueryTerm::Term(Term::Clause(_, ref name, _))
- | &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref name))) =>
+ QueryTermRef::Term(&Term::Clause(_, ref name, _))
+ | QueryTermRef::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) =>
+ QueryTermRef::CallN(terms) =>
if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() {
*ctrl = ControlInstruction::ExecuteN(terms.len());
},
}
fn compile_seq(&mut self,
- clauses: &'a [QueryTerm],
- vs: &VariableFixtures<'a>,
+ iter: ChunkedIterator<'a>,
+ conjunct_info: &ConjunctInfo<'a>,
body: &mut Code,
is_exposed: bool)
{
- let iter = ChunkedIterator::from_term_sequence(clauses);
-
- for (chunk_num, (_, terms)) in iter.enumerate() {
- self.marker.reset_contents();
-
- for (i, term) in terms.iter().enumerate() {
+ for (chunk_num, _, terms) in iter {
+ 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 {
- &QueryTermRef::Cut if i + 1 < terms.len() =>
- vec![Line::Cut(CutInstruction::Cut(Terminal::Non))],
- &QueryTermRef::Cut =>
- vec![Line::Cut(CutInstruction::Cut(Terminal::Terminal))],
+ match term {
+ &QueryTermRef::Cut if i + 1 < terms.len() => {
+ body.push(if chunk_num == 0 {
+ Line::Cut(CutInstruction::NeckCut(Terminal::Non))
+ } else {
+ Line::Cut(CutInstruction::Cut(Terminal::Non))
+ });
+ },
+ &QueryTermRef::Cut => {
+ body.push(if chunk_num == 0 {
+ Line::Cut(CutInstruction::NeckCut(Terminal::Terminal))
+ } else {
+ Line::Cut(CutInstruction::Cut(Terminal::Terminal))
+ });
+ },
+ _ if chunk_num == 0 => {
+ self.marker.advance(GenContext::Head, *term);
+
+ let iter = term.post_order_iter();
+ body.push(Line::Query(self.compile_target(iter, term_loc, is_exposed)));
+ Self::add_conditional_call(body, *term, conjunct_info.perm_vars());
+ },
_ => {
- let num_vars = vs.vars_above_threshold(i + 1);
- self.compile_query_line(*term, term_loc, num_vars, is_exposed)
- }
+ let num_vars = conjunct_info.perm_vs.vars_above_threshold(i + 1);
+ self.compile_query_line(*term, term_loc, body, num_vars, is_exposed);
+ },
};
- body.append(&mut body_appendage);
+ self.marker.reset_contents();
}
}
}
- fn compile_seq_prelude(&mut self,
- num_clauses: usize,
- vs: &VariableFixtures<'a>,
- deep_cuts: bool,
- body: &mut Code)
- -> usize
+ fn compile_seq_prelude(&mut self, conjunct_info: &ConjunctInfo, body: &mut Code)
{
- if num_clauses > 0 {
- let perm_vars = vs.vars_above_threshold(0) + deep_cuts as usize;
+ if conjunct_info.allocates() {
+ let perm_vars = conjunct_info.perm_vars();
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
- if deep_cuts {
+ if conjunct_info.has_deep_cut {
body.push(Line::Cut(CutInstruction::GetLevel));
}
-
- return perm_vars;
}
-
- 0
}
- fn compile_neck_cut_or(&mut self,
- p1: &'a QueryTerm,
- body: &mut Code,
- perm_vars: usize,
- is_exposed: bool,
- at_end: bool)
- {
- match p1 {
- &QueryTerm::Cut => {
- let term = if at_end {
- Terminal::Terminal
- } else {
- Terminal::Non
- };
-
- body.push(Line::Cut(CutInstruction::NeckCut(term)));
- },
- _ => {
- let p1 = p1.to_ref();
-
- self.marker.advance(GenContext::Head, p1);
-
- let term_loc = if p1.is_callable() {
- GenContext::Last(0)
- } else {
- GenContext::Mid(0)
- };
-
- 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: &QueryTerm)
+ fn compile_cleanup(body: &mut Code, conjunct_info: &ConjunctInfo, toc: QueryTermRef<'a>)
{
let dealloc_index = Self::lco(body, toc);
- if num_clauses > 0 {
+ if conjunct_info.allocates() {
body.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
}
}
pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Code
{
let iter = ChunkedIterator::from_rule(rule);
- let (mut vs, deep_cuts) = self.collect_var_data(iter);
- vs = self.marker.drain_var_data(vs);
+ let conjunct_info = self.collect_var_data(iter);
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
let mut code = Vec::new();
self.marker.advance(GenContext::Head, QueryTermRef::Term(p0));
-
- let perm_vars = self.compile_seq_prelude(clauses.len(), &vs, deep_cuts, &mut code);
+ self.compile_seq_prelude(&conjunct_info, &mut code);
if p0.is_clause() {
let iter = FactInstruction::iter(p0);
code.push(Line::Fact(self.compile_target(iter, GenContext::Head, false)));
}
- self.compile_neck_cut_or(p1, &mut code, perm_vars, false, clauses.len() == 0);
- self.compile_seq(clauses, &vs, &mut code, false);
+ let iter = ChunkedIterator::from_rule_body(p1, clauses);
+ self.compile_seq(iter, &conjunct_info, &mut code, false);
- if perm_vars > 0 {
+ if conjunct_info.allocates() {
let index = if let &Line::Control(_) = code.last().unwrap() {
code.len() - 2
} else {
};
if let &mut Line::Query(ref mut query) = &mut code[index] {
- vs.mark_unsafe_vars_in_rule(p0, query);
+ conjunct_info.perm_vs.mark_unsafe_vars_in_rule(p0, query);
}
}
- Self::compile_cleanup(&mut code, clauses.len(), clauses.last().unwrap_or(p1));
-
+ Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1).to_ref());
code
}
pub fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code
{
- let iter = ChunkedIterator::from_term(term, true);
- let (vs, _) = self.collect_var_data(iter);
- self.marker.drain_var_data(vs);
-
+ let iter = ChunkedIterator::from_fact(term);
+
+ self.collect_var_data(iter);
self.marker.advance(GenContext::Head, QueryTermRef::Term(term));
let mut code = Vec::new();
fn compile_query_line(&mut self,
term: QueryTermRef<'a>,
term_loc: GenContext,
+ code: &mut Code,
index: usize,
is_exposed: bool)
- -> Code
{
self.marker.advance(term_loc, term);
- let mut code = Vec::new();
-
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
+ Self::add_conditional_call(code, term, index);
}
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);
- let p1 = query.first().unwrap();
-
- vs = self.marker.drain_var_data(vs);
+ let conjunct_info = self.collect_var_data(iter);
- let mut code = Vec::new();
- let perm_vars = self.compile_seq_prelude(query.len() - 1,
- &vs,
- deep_cuts,
- &mut code);
+ let mut code = Vec::new();
+ self.compile_seq_prelude(&conjunct_info, &mut code);
- self.compile_neck_cut_or(p1, &mut code, perm_vars, true, query.len() == 1);
- self.compile_seq(&query[1 .. ], &vs, &mut code, true);
+ let iter = ChunkedIterator::from_term_sequence(query);
+ self.compile_seq(iter, &conjunct_info, &mut code, true);
- if perm_vars > 0 {
+ if conjunct_info.allocates() {
let index = if let &Line::Control(_) = code.last().unwrap() {
code.len() - 2
} else {
};
if let &mut Line::Query(ref mut query) = &mut code[index] {
- vs.mark_unsafe_vars_in_query(query);
+ conjunct_info.perm_vs.mark_unsafe_vars_in_query(query);
}
}
- Self::compile_cleanup(&mut code, query.len() - 1, query.last().unwrap());
-
+ Self::compile_cleanup(&mut code, &conjunct_info, query.last().unwrap().to_ref());
code
}
self.0.values()
}
- pub fn set_perm_vals(&self, has_deep_cuts: bool)
+ pub fn size(&self) -> usize {
+ self.0.len()
+ }
+
+ pub fn set_perm_vals(&self, has_deep_cuts: bool, has_catch: bool)
{
let mut values_vec : Vec<_> = self.values()
.filter_map(|ref v| {
values_vec.sort_by_key(|ref v| v.0);
- let offset = has_deep_cuts as usize;
+ let offset = has_deep_cuts as usize + 2 * has_catch as usize;
for (i, (_, cells)) in values_vec.into_iter().rev().enumerate() {
for cell in cells {
&Constant::Atom(ref atom) =>
write!(f, "{}", atom),
&Constant::EmptyList =>
- write!(f, "[]")
+ write!(f, "[]"),
+ &Constant::UInt64(integer) =>
+ write!(f, "u{}", integer)
}
}
}
}
}
+/*
+// Wait until constexprs are supported in stable before trying to
+// switch to this.
+
+struct ClauseRewriter { field: fn(&mut Vec<Box<Term>>) -> QueryTerm }
+
+impl Clone for ClauseRewriter {
+ fn clone(&self) -> Self {
+ ClauseRewriter { field: self.field }
+ }
+}
+
+struct ClauseRewriters {
+ rewriter_map: HashMap<&'static str, ClauseRewriter>
+}
+
+impl ClauseRewriters {
+ fn new() -> Self {
+ let mut rewriter_map =
+ [("call", ClauseRewriter { field: rewrite_call_N })]//,
+ //("catch", rewrite_catch),
+ //("throw", rewrite_throw)]
+ .iter().cloned().collect();
+
+ ClauseRewriters { rewriter_map: rewriter_map }
+ }
+
+ fn get(&self, name: &str) -> Option<&ClauseRewriter> {
+ self.rewriter_map.get(name)
+ }
+}
+*/
+
+fn rewrite_call_n(terms: &mut Vec<Box<Term>>) -> QueryTerm {
+ let mut new_terms = Vec::with_capacity(0);
+ swap(&mut new_terms, terms);
+
+ QueryTerm::CallN(new_terms)
+}
+
+fn rewrite_clause(name: &Atom, terms: &mut Vec<Box<Term>>) -> Option<QueryTerm>
+{
+ if name == "call" {
+ Some(rewrite_call_n(terms))
+ } else {
+ None
+ }
+}
+
pub fn parse_code(input: &str) -> Option<TopLevel>
{
match parse_TopLevel(input) {
Ok(mut tl) => {
for query in tl.query_iter_mut() {
- let cts = match query {
- &mut QueryTerm::Term(Term::Clause(_, ref name, ref mut cts)) => {
- if name == "call" {
- let mut new_cts = Vec::with_capacity(0);
- swap(&mut new_cts, cts);
-
- Some(new_cts)
- } else {
- None
- }
- },
+ let new_query = match query {
+ &mut QueryTerm::Term(Term::Clause(_, ref name, ref mut cts)) =>
+ rewrite_clause(name, cts),
+ &mut QueryTerm::Term(Term::Var(_, _)) =>
+ Some(QueryTerm::CallN(Vec::new())),
_ => None
};
- if let Some(cts) = cts {
- swap(&mut QueryTerm::CallN(cts), query);
+ if let Some(mut new_query) = new_query {
+ swap(&mut new_query, query);
}
}
pub fn print_code(code: &Code) {
for clause in code {
match clause {
- &Line::BuiltIn(_) => {},
&Line::Fact(ref fact) =>
for fact_instr in fact {
println!("{}", fact_instr);
},
+ &Line::BuiltIn(_) => {},
&Line::Cut(ref cut) =>
println!("{}", cut),
&Line::Choice(ref choice) =>
if is_consistent(clauses) {
let compiled_pred = cg.compile_predicate(clauses);
- wam.add_predicate(clauses, compiled_pred)
+ wam.add_predicate(clauses, compiled_pred)
} else {
let msg = r"Error: predicate is inconsistent.
Each predicate must have the same name and arity.";
-
+
EvalSession::EntryFailure(String::from(msg))
}
},
fn from_term(term: &'a Term) -> Self {
let state = match term {
&Term::AnonVar =>
- IteratorState::AnonVar(Level::Shallow),
+ //IteratorState::AnonVar(Level::Shallow),
+ return QueryIterator { state_stack: vec![] },
&Term::Clause(_, _, ref 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) =>
- IteratorState::Constant(Level::Shallow, cell, constant),
+ &Term::Cons(_, _, _) =>
+ //IteratorState::InitialCons(Level::Shallow, cell, head.as_ref(), tail.as_ref()),
+ return QueryIterator { state_stack: vec![] },
+ &Term::Constant(_, _) =>
+ //IteratorState::Constant(Level::Shallow, cell, constant),
+ return QueryIterator { state_stack: vec![] },
&Term::Var(ref cell, ref var) =>
IteratorState::Var(Level::Shallow, cell, var)
};
self.push_subterm(ct.level_of_subterms(), child_term);
}
- match ct {
+ match ct {
ClauseType::Deep(_, _, _) =>
return Some(TermRef::Clause(ct, child_terms)),
_ =>
pub struct ChunkedIterator<'a>
{
- at_head: bool,
+ term_loc: GenContext,
iter: Box<Iterator<Item=QueryTermRef<'a>> + 'a>,
- deep_cut_encountered: bool
+ deep_cut_encountered: bool,
+ catch_encountered: bool
}
impl<'a> ChunkedIterator<'a>
{
- pub fn from_term(term: &'a Term, at_head: bool) -> Self
+ pub fn from_fact(term: &'a Term) -> Self
{
let inner_iter: Box<Iterator<Item=QueryTermRef<'a>>> =
Box::new(once(QueryTermRef::Term(term)));
ChunkedIterator {
- at_head: at_head,
+ term_loc: GenContext::Head,
iter: inner_iter,
- deep_cut_encountered: false
+ deep_cut_encountered: false,
+ catch_encountered: false
}
}
let iter = terms.iter().map(|c| c.to_ref());
ChunkedIterator {
- at_head: false,
+ term_loc: GenContext::Last(0),
iter: Box::new(iter),
- deep_cut_encountered: false
+ deep_cut_encountered: false,
+ catch_encountered: false
}
}
- pub fn from_rule(rule: &'a Rule) -> Self
+ fn iterate_over_query_term(p1: &'a QueryTerm) -> Box<Iterator<Item=QueryTermRef<'a>> + 'a>
{
- let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
- let iter = once(QueryTermRef::Term(p0));
-
- let inner_iter : Box<Iterator<Item=QueryTermRef<'a>>> = match p1 {
+ match p1 {
&QueryTerm::CallN(ref child_terms) =>
Box::new(once(QueryTermRef::CallN(child_terms))),
&QueryTerm::Term(ref p1) =>
Box::new(once(QueryTermRef::Term(p1))),
- _ => Box::new(empty())
- };
+ &QueryTerm::Cut =>
+ Box::new(once(QueryTermRef::Cut))
+ }
+ }
+
+ pub fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self
+ {
+ let inner_iter = Self::iterate_over_query_term(p1);
+ let iter = inner_iter.chain(clauses.iter().map(|c| c.to_ref()));
+
+ ChunkedIterator {
+ term_loc: GenContext::Last(0),
+ iter: Box::new(iter),
+ deep_cut_encountered: false,
+ catch_encountered: false
+ }
+ }
+
+ pub fn from_rule(rule: &'a Rule) -> Self
+ {
+ let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
+ let iter = once(QueryTermRef::Term(p0));
+ let inner_iter = Self::iterate_over_query_term(p1);
let iter = iter.chain(inner_iter.chain(clauses.iter().map(|c| c.to_ref())));
ChunkedIterator {
- at_head: true,
+ term_loc: GenContext::Head,
iter: Box::new(iter),
- deep_cut_encountered: false
+ deep_cut_encountered: false,
+ catch_encountered: false
}
}
- pub fn contains_deep_cut(&self) -> bool {
+ pub fn encountered_deep_cut(&self) -> bool {
self.deep_cut_encountered
}
- pub fn at_head(&self) -> bool {
- self.at_head
+ pub fn encountered_catch(&self) -> bool {
+ self.catch_encountered
+ }
+
+ pub fn at_rule_head(&self) -> bool {
+ self.term_loc == GenContext::Head
+ }
+
+ pub fn chunk_num(&self) -> usize {
+ self.term_loc.chunk_num()
}
- fn take_chunk(&mut self, term: QueryTermRef<'a>) -> (usize, Vec<QueryTermRef<'a>>)
+ fn take_chunk(&mut self, term: QueryTermRef<'a>, mut result: Vec<QueryTermRef<'a>>)
+ -> (usize, usize, Vec<QueryTermRef<'a>>)
{
- let mut result = vec![term];
- let mut arity = 0;
+ let mut arity = 0;
+ let mut item = Some(term);
- while let Some(term) = self.iter.next() {
+ while let Some(term) = item {
match term {
QueryTermRef::Term(inner_term) => {
- result.push(term);
+ if let GenContext::Head = self.term_loc {
+ result.push(term);
+ self.term_loc = GenContext::Last(0);
+ } else {
+ result.push(term);
- if inner_term.is_callable() {
- arity = inner_term.arity();
- break;
+ if inner_term.is_callable() {
+ arity = inner_term.arity();
+ break;
+ }
}
},
QueryTermRef::CallN(child_terms) => {
result.push(term);
arity = child_terms.len() + 1;
break;
- },
- _ => {
+ },
+ QueryTermRef::Cut => {
result.push(term);
- self.deep_cut_encountered = true;
- }
+
+ if self.term_loc.chunk_num() > 0 {
+ self.deep_cut_encountered = true;
+ }
+ },
};
+
+ item = self.iter.next();
}
- (arity, result)
+ let chunk_num = self.term_loc.chunk_num();
+
+ if let &mut GenContext::Last(ref mut chunk_num) = &mut self.term_loc {
+ *chunk_num += 1;
+ }
+
+ (chunk_num, arity, result)
}
}
impl<'a> Iterator for ChunkedIterator<'a>
{
- // the last term arity, and the reference.
- type Item = (usize, Vec<QueryTermRef<'a>>);
+ // the chunk number, last term arity, and vector of references.
+ type Item = (usize, usize, Vec<QueryTermRef<'a>>);
fn next(&mut self) -> Option<Self::Item> {
- loop {
- match self.iter.next() {
- None => return None,
- Some(QueryTermRef::Term(term)) if self.at_head => {
- self.at_head = false;
- return Some(self.take_chunk(QueryTermRef::Term(term)));
- },
- Some(QueryTermRef::Term(term)) if term.is_callable() =>
- return Some((term.arity(), vec![QueryTermRef::Term(term)])),
- Some(QueryTermRef::CallN(child_terms)) =>
- return Some((child_terms.len() + 1, vec![QueryTermRef::CallN(child_terms)])),
- Some(term_or_cut_ref) =>
- return Some(self.take_chunk(term_or_cut_ref))
- }
- }
+ self.iter.next().map(|term| self.take_chunk(term, Vec::new()))
}
}
use prolog::ast::*;
+use prolog::builtins::*;
use prolog::codegen::*;
use prolog::heapview::*;
use prolog::and_stack::*;
trail: Vec<Ref>,
tr: usize,
hb: usize,
+ block: usize, // an offset into the OR stack.
+ ball: Addr
}
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-enum PredicateKeyType {
- BuiltIn,
- User
-}
-
-type PredicateKey = (Atom, usize); // name, arity, type.
-
-type CodeDir = HashMap<PredicateKey, (PredicateKeyType, usize)>;
-
pub struct Machine {
ms: MachineState,
code: Code,
impl Machine {
pub fn new() -> Self {
- let mut code_dir = HashMap::new();
- let code = vec![Line::BuiltIn(BuiltInInstruction::InternalCallN)];
-
- // there are 64 registers in the VM, so call/N is defined for all 0 <= N <= 63
- // (an extra register is needed for the predicate name)
- for arity in 0 .. 64 {
- code_dir.insert((String::from("call"), arity), (PredicateKeyType::BuiltIn, 0));
- }
+ let (code, code_dir) = build_code_dir();
Machine {
ms: MachineState::new(),
};
match instr {
- &Line::BuiltIn(ref builtin_instr) =>
- self.ms.execute_builtin_instr(&self.code_dir, builtin_instr),
+ &Line::BuiltIn(ref built_in_instr) =>
+ self.ms.execute_built_in_instr(&self.code_dir, built_in_instr),
&Line::Choice(ref choice_instr) =>
self.ms.execute_choice_instr(choice_instr),
&Line::Cut(ref cut_instr) =>
while let Some(view) = viewer.next() {
match view {
+ CellView::Con(&Constant::UInt64(integer)) =>
+ result += integer.to_string().as_str(),
CellView::Con(&Constant::EmptyList) =>
result += "[]",
CellView::Con(&Constant::Atom(ref atom)) =>
result += atom.as_str(),
- CellView::HeapVar(cell_num) | CellView::StackVar(_, cell_num) => {
+ CellView::HeapVar(cell_num) => {
result += "_";
result += cell_num.to_string().as_str();
},
+ CellView::StackVar(_, cell_num) => {
+ result += "s_";
+ result += cell_num.to_string().as_str();
+ },
CellView::Str(_, ref name) =>
result += name.as_str(),
CellView::TToken(TToken::Bar) => {
trail: Vec::new(),
tr: 0,
hb: 0,
+ block: 0,
+ ball: Addr::Con(Constant::UInt64(0))
}
}
}
}
+ fn write_constant_to_var(&mut self, addr: Addr, c: &Constant) {
+ let addr = self.deref(addr);
+
+ match self.store(addr) {
+ Addr::HeapCell(hc) => {
+ self.heap[hc] = HeapCellValue::Con(c.clone());
+ self.trail(Ref::HeapCell(hc));
+ },
+ Addr::StackCell(fr, sc) => {
+ self.and_stack[fr][sc] = Addr::Con(c.clone());
+ self.trail(Ref::StackCell(fr, sc));
+ },
+ Addr::Con(c1) => {
+ if c1 != *c {
+ self.fail = true;
+ }
+ },
+ _ => self.fail = true
+ };
+ }
+
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
match instr {
- &FactInstruction::GetConstant(_, ref constant, reg) => {
- let addr = self.deref(self[reg].clone());
-
- match self.store(addr) {
- Addr::HeapCell(hc) => {
- self.heap[hc] = HeapCellValue::Con(constant.clone());
- self.trail(Ref::HeapCell(hc));
- },
- Addr::StackCell(fr, sc) => {
- self.and_stack[fr][sc] = Addr::Con(constant.clone());
- self.trail(Ref::StackCell(fr, sc));
- },
- Addr::Con(c) => {
- if c != *constant {
- self.fail = true;
- }
- },
- _ => self.fail = true
- };
+ &FactInstruction::GetConstant(_, ref c, reg) => {
+ let addr = self[reg].clone();
+ self.write_constant_to_var(addr, c);
},
&FactInstruction::GetList(_, reg) => {
let addr = self.deref(self[reg].clone());
&FactInstruction::UnifyConstant(ref c) => {
match self.mode {
MachineMode::Read => {
- let addr = self.deref(Addr::HeapCell(self.s));
-
- match self.store(addr) {
- Addr::HeapCell(hc) => {
- self.heap[hc] = HeapCellValue::Con(c.clone());
- self.trail(Ref::HeapCell(hc));
- },
- Addr::StackCell(fr, sc) => {
- self.and_stack[fr][sc] = Addr::Con(c.clone());
- self.trail(Ref::StackCell(fr, sc));
- },
- Addr::Con(c1) => {
- if c1 != *c {
- self.fail = true;
- }
- },
- _ => self.fail = true
- };
+ let addr = Addr::HeapCell(self.s);
+ self.write_constant_to_var(addr, c);
},
MachineMode::Write => {
self.heap.push(HeapCellValue::Con(c.clone()));
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.1);
-
+
match compiled_tl_index {
Some(compiled_tl_index) => {
self.num_of_args = arity;
};
}
+ // copy_term(L1, L2) uses Cheney's algorithm to copy the term at
+ // L1 to L2. forwarding_terms is kept to restore the innards of L1
+ // after it's been copied to L2.
+ fn copy_term(&mut self, a: Addr)
+ {
+ let mut forward_trail = Vec::new(); // list of (Ref, HeapCellValue) items.
+ let mut scan = self.h;
+ let old_h = self.h;
+
+ self.heap.push(HeapCellValue::from(a));
+ self.h += 1;
+
+ while scan < self.h {
+ match self.heap[scan].clone() {
+ HeapCellValue::Con(_) | HeapCellValue::NamedStr(_, _) =>
+ scan += 1,
+ HeapCellValue::Lis(a) => {
+ let hcv = self.heap[a].clone();
+ self.heap.push(hcv);
+
+ let hcv = self.heap[a+1].clone();
+ self.heap.push(hcv);
+
+ self.heap[scan] = HeapCellValue::Lis(self.h);
+
+ self.h += 2;
+ scan += 1;
+ },
+ HeapCellValue::Ref(r) => {
+ let ra = Addr::from(r);
+ let rd = self.store(self.deref(ra.clone()));
+
+ match rd {
+ Addr::HeapCell(hc) if hc >= old_h => {
+ self.heap[scan] = HeapCellValue::Ref(Ref::HeapCell(hc));
+ scan += 1;
+ },
+ _ if ra == rd => {
+ self.heap[scan] = HeapCellValue::Ref(Ref::HeapCell(scan));
+
+ match r {
+ Ref::HeapCell(hc) =>
+ self.heap[hc] = HeapCellValue::Ref(Ref::HeapCell(scan)),
+ Ref::StackCell(fr, sc) =>
+ self.and_stack[fr][sc] = Addr::HeapCell(scan),
+ };
+
+ forward_trail.push((r, HeapCellValue::Ref(r)));
+ scan += 1;
+ },
+ _ => self.heap[scan] = HeapCellValue::from(rd)
+ }
+ },
+ HeapCellValue::Str(s) => {
+ match self.heap[s].clone() {
+ HeapCellValue::NamedStr(arity, name) => {
+ self.heap[scan] = HeapCellValue::Str(self.h);
+ self.heap[s] = HeapCellValue::Str(self.h);
+
+ forward_trail.push((Ref::HeapCell(s),
+ HeapCellValue::NamedStr(arity, name.clone())));
+
+ self.heap.push(HeapCellValue::NamedStr(arity, name));
+ self.h += 1;
+
+ for i in 0 .. arity {
+ let hcv = self.heap[s + 1 + i].clone();
+ self.heap.push(hcv);
+ self.h += 1;
+ }
+
+ },
+ HeapCellValue::Str(o) =>
+ self.heap[scan] = HeapCellValue::Str(o),
+ _ => {}
+ }
+
+ scan += 1;
+ }
+ };
+ }
+
+ for (r, hcv) in forward_trail {
+ match r {
+ Ref::HeapCell(hc) => self.heap[hc] = hcv,
+ Ref::StackCell(fr, sc) => self.and_stack[fr][sc] = hcv.as_addr(0)
+ }
+ }
+ }
+
fn handle_internal_call_n(&mut self, code_dir: &CodeDir)
{
let arity = self.num_of_args + 1;
if arity > 1 {
self.registers[arity - 1] = pred;
- if let Some((name, arity)) = self.setup_call_n(arity - 1) {
+ if let Some((name, arity)) = self.setup_call_n(arity - 1) {
self.try_execute_predicate(code_dir, name, arity);
}
} else {
Some((name, arity + narity - 1))
}
+ fn has_null_ball(&self) -> bool
+ {
+ if let &Addr::Con(Constant::UInt64(0)) = &self.ball {
+ true
+ } else {
+ false
+ }
+ }
+
+ fn execute_built_in_instr(&mut self, code_dir: &CodeDir, instr: &BuiltInInstruction)
+ {
+ match instr {
+ &BuiltInInstruction::CopyTerm => {
+ let old_h = self.h;
+ let a = self[temp_v!(1)].clone();
+ self.copy_term(a);
+
+ let a2 = self[temp_v!(2)].clone();
+ self.unify(Addr::HeapCell(old_h), a2);
+
+ self.p += 1;
+ },
+ &BuiltInInstruction::GetCurrentBlock => {
+ let c = Constant::UInt64(self.block);
+ let addr = self[temp_v!(1)].clone();
+
+ self.write_constant_to_var(addr, &c);
+ self.p += 1;
+ },
+ &BuiltInInstruction::Unify => {
+ let a1 = self[temp_v!(1)].clone();
+ let a2 = self[temp_v!(2)].clone();
+
+ self.unify(a1, a2);
+ self.p += 1;
+ },
+ &BuiltInInstruction::GetBall => {
+ let addr = self.store(self.deref(self[temp_v!(1)].clone()));
+ let ball = self.ball.clone();
+
+ if self.has_null_ball() {
+ self.fail = true;
+ return;
+ }
+
+ match addr.as_ref() {
+ Some(r) => {
+ self.bind(r, ball);
+ self.p += 1;
+ },
+ _ => self.fail = true
+ };
+ },
+ &BuiltInInstruction::SetBall => {
+ self.ball = self[temp_v!(1)].clone();
+ self.p += 1;
+ },
+ &BuiltInInstruction::CleanUpBlock => {
+ let nb = self.store(self.deref(self[temp_v!(1)].clone()));
+
+ match nb {
+ Addr::Con(Constant::UInt64(nb)) => {
+ let b = self.b - 1;
+
+ if nb > 0 && self.or_stack[b].b == nb {
+ self.b = self.or_stack[nb - 1].b;
+ }
+
+ self.p += 1;
+ },
+ _ => self.fail = true
+ };
+ },
+ &BuiltInInstruction::InstallNewBlock => {
+ self.block = self.b;
+ let c = Constant::UInt64(self.block);
+ let addr = self[temp_v!(1)].clone();
+
+ self.write_constant_to_var(addr, &c);
+ self.p += 1;
+ },
+ &BuiltInInstruction::ResetBlock => {
+ let addr = self.deref(self[temp_v!(1)].clone());
+
+ match self.store(addr) {
+ Addr::Con(Constant::UInt64(b)) => {
+ self.block = b;
+ self.p += 1;
+ },
+ _ => self.fail = true
+ };
+ },
+ &BuiltInInstruction::UnwindStack => {
+ self.b = self.block;
+ self.fail = true;
+ },
+ &BuiltInInstruction::IsAtomic => {
+ let d = self.deref(self[temp_v!(1)].clone());
+
+ match d {
+ Addr::Con(_) => self.p += 1,
+ _ => self.fail = true
+ };
+ },
+ &BuiltInInstruction::IsVar => {
+ let d = self.deref(self[temp_v!(1)].clone());
+
+ match d {
+ Addr::HeapCell(_) | Addr::StackCell(_,_) =>
+ self.p += 1,
+ _ => self.fail = true
+ };
+ },
+ &BuiltInInstruction::InternalCallN =>
+ self.handle_internal_call_n(code_dir),
+ &BuiltInInstruction::Fail => {
+ self.fail = true;
+ self.p += 1;
+ },
+ &BuiltInInstruction::Goto(p, arity) => {
+ self.num_of_args = arity;
+ self.b0 = self.b;
+ self.p = CodePtr::DirEntry(p);
+ }
+ };
+ }
+
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
{
match instr {
};
}
- fn execute_builtin_instr(&mut self, code_dir: &CodeDir, instr: &BuiltInInstruction)
- {
- match instr {
- &BuiltInInstruction::InternalCallN => self.handle_internal_call_n(code_dir)
- }
- }
-
fn execute_choice_instr(&mut self, instr: &ChoiceInstruction)
{
match instr {
self.num_of_args);
self.b = self.or_stack.len();
- let b = self.b - 1;
+ let b = self.b - 1;
for i in 1 .. n + 1 {
self.or_stack[b][i] = self.registers[i].clone();
--- /dev/null
+macro_rules! internal_call_n {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::InternalCallN)
+ )
+}
+
+macro_rules! allocate {
+ ($cells:expr) => (
+ Line::Control(ControlInstruction::Allocate($cells))
+ )
+}
+
+macro_rules! deallocate {
+ () => (
+ Line::Control(ControlInstruction::Deallocate)
+ )
+}
+
+macro_rules! query {
+ [$($x:expr),+] => (
+ Line::Query(vec![$($x),+])
+ )
+}
+
+macro_rules! temp_v {
+ ($x:expr) => (
+ RegType::Temp($x)
+ )
+}
+
+macro_rules! perm_v {
+ ($x:expr) => (
+ RegType::Perm($x)
+ )
+}
+
+macro_rules! get_var_in_query {
+ ($r:expr, $arg:expr) => (
+ QueryInstruction::GetVariable($r, $arg)
+ )
+}
+
+macro_rules! put_var {
+ ($r:expr, $arg:expr) => (
+ QueryInstruction::PutVariable($r, $arg)
+ )
+}
+
+macro_rules! put_value {
+ ($r:expr, $arg:expr) => (
+ QueryInstruction::PutValue($r, $arg)
+ )
+}
+
+macro_rules! put_unsafe_value {
+ ($r:expr, $arg:expr) => (
+ QueryInstruction::PutUnsafeValue($r, $arg)
+ )
+}
+
+macro_rules! try_me_else {
+ ($o:expr) => (
+ Line::Choice(ChoiceInstruction::TryMeElse($o))
+ )
+}
+
+macro_rules! is_atomic {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::IsAtomic)
+ )
+}
+
+macro_rules! is_var {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::IsVar)
+ )
+}
+
+/*
+macro_rules! retry_me_else {
+ ($o:expr) => (
+ Line::Choice(ChoiceInstruction::RetryMeElse($o))
+ )
+}
+ */
+
+macro_rules! trust_me {
+ () => (
+ Line::Choice(ChoiceInstruction::TrustMe)
+ )
+}
+
+macro_rules! call_n {
+ ($arity:expr) => (
+ Line::Control(ControlInstruction::CallN($arity))
+ )
+}
+
+macro_rules! execute_n {
+ ($arity:expr) => (
+ Line::Control(ControlInstruction::ExecuteN($arity))
+ )
+}
+
+macro_rules! proceed {
+ () => (
+ Line::Control(ControlInstruction::Proceed)
+ )
+}
+
+macro_rules! non_terminal {
+ () => (
+ Terminal::Non
+ )
+}
+
+macro_rules! cut {
+ ($term:expr) => (
+ Line::Cut(CutInstruction::Cut($term))
+ )
+}
+
+macro_rules! get_current_block {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::GetCurrentBlock)
+ )
+}
+
+macro_rules! install_new_block {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::InstallNewBlock)
+ )
+}
+
+macro_rules! goto {
+ ($line:expr, $arity:expr) => (
+ Line::BuiltIn(BuiltInInstruction::Goto($line, $arity))
+ )
+}
+
+macro_rules! reset_block {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::ResetBlock)
+ )
+}
+
+macro_rules! get_ball {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::GetBall)
+ )
+}
+
+macro_rules! unify {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::Unify)
+ )
+}
+
+macro_rules! unwind_stack {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::UnwindStack)
+ )
+}
+
+macro_rules! clean_up_block {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::CleanUpBlock)
+ )
+}
+
+macro_rules! set_ball {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::SetBall)
+ )
+}
+
+macro_rules! fail {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::Fail)
+ )
+}
+
+macro_rules! copy_term {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::CopyTerm)
+ )
+}
+
+macro_rules! get_level {
+ () => (
+ Line::Cut(CutInstruction::GetLevel)
+ )
+}
pub mod indexing;
pub mod io;
pub mod iterators;
+#[macro_use]
+pub mod macros;
pub mod naive_allocator;
pub mod prolog_parser;
pub mod machine;
pub mod or_stack;
pub mod targets;
+
+pub mod builtins;