[package]
name = "rusty-wam"
-version = "0.7.3"
+version = "0.7.4"
authors = ["Mark Thom"]
[dependencies]
* Built-in and user-defined operators of all fixities, with custom
associativity and precedence (_done_).
* Bignum, rational number and floating point arithmetic (_in progress_).
-* Built-in control operators (`,`, `;`, `->`, etc.).
+* Built-in control operators (`,`, `;`, `->`, etc.) (_in progress_).
* Built-in predicates for list processing and top-level declarative
control (`setup_call_control/3`, `call_with_inference_limit/3`,
etc.)
EmptyList
}
+impl<'a> From<&'a str> for Constant {
+ fn from(input: &str) -> Constant {
+ Constant::Atom(String::from(input))
+ }
+}
+
impl fmt::Display for Constant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TryMeElse(usize)
}
+#[derive(Clone, Copy)]
pub enum Terminal {
Terminal, Non
}
Fail,
GetBall,
GetCurrentBlock,
+ GetCutPoint,
InstallNewBlock,
InternalCallN,
IsAtomic(RegType),
IsVar(RegType),
ResetBlock,
SetBall,
+ SetNeckCutPoint(Terminal),
+ SetNonNeckCutPoint(Terminal),
Succeed,
Unify,
UnwindStack
proceed!(),
fact![get_value!(temp_v!(1), 2)], // =/2, 73.
proceed!(),
- proceed!() // true/0, 75.
+ proceed!(), // true/0, 75.
+ try_me_else!(2), // ';'/2, 76.
+ execute_n!(1),
+ trust_me!(),
+ query![put_value!(temp_v!(2), 1)],
+ execute_n!(1),
+ allocate!(3), // ','/2, 81.
+ fact![get_var_in_fact!(perm_v!(2), 1),
+ get_var_in_fact!(perm_v!(1), 2)],
+ query![put_var!(perm_v!(3), 1)],
+ get_cp!(),
+ query![put_value!(perm_v!(2), 1),
+ put_value!(perm_v!(1), 2),
+ put_unsafe_value!(3, 3)],
+ deallocate!(),
+ goto!(88, 3),
+ try_me_else!(25), // ','/3, 88.
+ switch_on_term!(4, 0, 0, 0),
+ indexed_try!(4),
+ retry!(11),
+ trust!(14),
+ try_me_else!(8),
+ allocate!(3),
+ fact![get_constant!(Constant::from("!"), temp_v!(1)),
+ get_structure!(String::from(","), 2, temp_v!(2)),
+ unify_variable!(perm_v!(2)),
+ unify_variable!(perm_v!(1)),
+ get_var_in_fact!(perm_v!(3), 3)],
+ query![put_value!(perm_v!(3), 1)],
+ set_non_neck_cp!(non_terminal!()),
+ query![put_unsafe_value!(2, 1),
+ put_unsafe_value!(1, 2),
+ put_value!(perm_v!(3), 3)],
+ deallocate!(),
+ goto!(88, 3),
+ retry_me_else!(4),
+ fact![get_constant!(Constant::from("!"), temp_v!(1)),
+ get_constant!(Constant::from("!"), temp_v!(2))],
+ query![put_value!(temp_v!(3), 1)],
+ set_neck_cp!(terminal!()),
+ trust_me!(),
+ allocate!(1),
+ fact![get_constant!(Constant::from("!"), temp_v!(1)),
+ get_var_in_fact!(perm_v!(1), 2)],
+ query![put_value!(temp_v!(3), 1)],
+ set_non_neck_cp!(non_terminal!()),
+ query![put_value!(perm_v!(1), 1)],
+ deallocate!(),
+ execute_n!(1),
+ retry_me_else!(7),
+ allocate!(1),
+ fact![get_constant!(Constant::from("!"), temp_v!(2)),
+ get_var_in_fact!(perm_v!(1), 3)],
+ call_n!(1),
+ query![put_value!(perm_v!(1), 1)],
+ deallocate!(),
+ set_non_neck_cp!(terminal!()),
+ retry_me_else!(7),
+ allocate!(3),
+ fact![get_structure!(String::from(","), 2, temp_v!(2)),
+ unify_variable!(perm_v!(2)),
+ unify_variable!(perm_v!(1)),
+ get_var_in_fact!(perm_v!(3), 3)],
+ call_n!(1),
+ query![put_unsafe_value!(2, 1),
+ put_unsafe_value!(1, 2),
+ put_value!(perm_v!(3), 3)],
+ deallocate!(),
+ goto!(88, 3),
+ trust_me!(),
+ allocate!(1),
+ fact![get_var_in_fact!(perm_v!(1), 2)],
+ call_n!(1),
+ query![put_value!(perm_v!(1), 1)],
+ deallocate!(),
+ execute_n!(1),
+ allocate!(2), // (->)/2, 134.
+ get_level!(),
+ fact![get_var_in_fact!(perm_v!(2), 2)],
+ call_n!(1),
+ cut!(non_terminal!()),
+ query![put_value!(perm_v!(2), 1)],
+ deallocate!(),
+ execute_n!(1)
]
}
op_dir.insert((String::from("=:="), Fixity::In), (XFX, 700));
op_dir.insert((String::from(">="), Fixity::In), (XFX, 700));
op_dir.insert((String::from("=<"), Fixity::In), (XFX, 700));
+
+ // control operators.
+ op_dir.insert((String::from(";"), Fixity::In), (XFY, 1100));
+ op_dir.insert((String::from("->"), Fixity::In), (XFY, 1050));
// 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)
code_dir.insert((String::from("catch"), 3), (PredicateKeyType::BuiltIn, 5));
code_dir.insert((String::from("throw"), 1), (PredicateKeyType::BuiltIn, 59));
code_dir.insert((String::from("="), 2), (PredicateKeyType::BuiltIn, 73));
- code_dir.insert((String::from("true"), 0), (PredicateKeyType::BuiltIn, 75));
+ code_dir.insert((String::from("true"), 0), (PredicateKeyType::BuiltIn, 75));
+ code_dir.insert((String::from(";"), 2), (PredicateKeyType::BuiltIn, 76));
+ code_dir.insert((String::from(","), 2), (PredicateKeyType::BuiltIn, 81));
+ code_dir.insert((String::from("->"), 2), (PredicateKeyType::BuiltIn, 134));
+
(builtin_code, code_dir, op_dir)
}
self.marker.take_bindings()
}
- fn update_var_count<Iter>(&mut self, iter: Iter)
- where Iter: Iterator<Item=TermRef<'a>>
+ fn update_var_count<Iter: Iterator<Item=TermRef<'a>>>(&mut self, iter: Iter)
{
for term in iter {
if let TermRef::Var(_, _, var) = term {
self.marker.reset_arg(arity);
self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
- code.push(Line::Query(target));
+
+ if !target.is_empty() {
+ code.push(Line::Query(target));
+ }
+
vr.get().norm()
}
}
fn add_conditional_call_inlined(_: &InlinedQueryTerm, code: &mut Code)
{
code.push(proceed!());
-
- /*
- match term {
- &InlinedQueryTerm::IsAtomic(_) | &InlinedQueryTerm::IsVar(_) =>
- code.push(proceed!())
- };
- */
}
fn add_conditional_call(code: &mut Code, qt: &QueryTerm, pvs: usize)
Ok(())
}
- fn call_arith_eval(&self, term: &'a Term, target_int: usize) -> Result<ArithCont, ArithmeticError>
+ fn call_arith_eval(&self, term: &'a Term, target_int: usize)
+ -> Result<ArithCont, ArithmeticError>
{
let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings(), target_int);
evaluator.eval(term)
self.marker.reset_arg(term.arity());
let iter = term.post_order_iter();
- code.push(Line::Query(self.compile_target(iter, term_loc, is_exposed)));
+ let query = self.compile_target(iter, term_loc, is_exposed);
+
+ if !query.is_empty() {
+ code.push(Line::Query(query));
+ }
+
Self::add_conditional_call(code, term, conjunct_info.perm_vars());
},
_ => {
if let &QueryTerm::Term(ref term) = p0 {
if let &Term::Clause(_, _, _) = term {
let iter = FactInstruction::iter(term);
- code.push(Line::Fact(self.compile_target(iter, GenContext::Head, false)));
+ let fact = self.compile_target(iter, GenContext::Head, false);
+
+ if !fact.is_empty() {
+ code.push(Line::Fact(fact));
+ }
}
let iter = ChunkedIterator::from_rule_body(p1, clauses);
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));
+
+ if !compiled_fact.is_empty() {
+ code.push(Line::Fact(compiled_fact));
+ }
}
code.push(proceed!());
self.marker.reset_arg(term.arity());
let iter = term.post_order_iter();
- let compiled_query = Line::Query(self.compile_target(iter, term_loc, is_exposed));
+ let compiled_query = self.compile_target(iter, term_loc, is_exposed);
- code.push(compiled_query);
+ if !compiled_query.is_empty() {
+ code.push(Line::Query(compiled_query));
+ }
Self::add_conditional_call(code, term, index);
}
}
}
+impl fmt::Display for Terminal {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ &Terminal::Terminal =>
+ write!(f, "terminal"),
+ &Terminal::Non =>
+ write!(f, "non_terminal")
+ }
+ }
+}
impl fmt::Display for BuiltInInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "get_ball X1"),
&BuiltInInstruction::GetCurrentBlock =>
write!(f, "get_current_block X1"),
+ &BuiltInInstruction::GetCutPoint =>
+ write!(f, "get_cp"),
&BuiltInInstruction::InstallNewBlock =>
write!(f, "install_new_block"),
&BuiltInInstruction::InternalCallN =>
write!(f, "reset_block"),
&BuiltInInstruction::SetBall =>
write!(f, "set_ball"),
+ &BuiltInInstruction::SetNeckCutPoint(terminal) =>
+ write!(f, "set_neck_cp {}", terminal),
+ &BuiltInInstruction::SetNonNeckCutPoint(terminal) =>
+ write!(f, "set_non_neck_cp {}", terminal),
&BuiltInInstruction::Succeed =>
write!(f, "true"),
&BuiltInInstruction::UnwindStack =>
self.write_constant_to_var(addr, &c);
self.p += 1;
- },
+ },
+ &BuiltInInstruction::GetCutPoint => {
+ let c = Constant::Usize(self.b);
+ let addr = self[temp_v!(1)].clone();
+
+ self.write_constant_to_var(addr, &c);
+ self.p += 1;
+ },
&BuiltInInstruction::EraseBall => {
self.ball.0 = 0;
self.ball.1.truncate(0);
self.p += 1;
},
+ &BuiltInInstruction::SetNeckCutPoint(terminal) => {
+ let nb = self.store(self.deref(self[temp_v!(1)].clone()));
+
+ match nb {
+ Addr::Con(Constant::Usize(nb)) => {
+ self.b = nb;
+ self.neck_cut(terminal);
+ },
+ _ => self.fail = true
+ };
+ },
+ &BuiltInInstruction::SetNonNeckCutPoint(terminal) => {
+ let nb = self.store(self.deref(self[temp_v!(1)].clone()));
+
+ match nb {
+ Addr::Con(Constant::Usize(nb)) => {
+ self.b = nb;
+ self.non_neck_cut(terminal);
+ },
+ _ => self.fail = true
+ };
+ },
&BuiltInInstruction::CleanUpBlock => {
let nb = self.store(self.deref(self[temp_v!(1)].clone()));
}
}
- fn execute_cut_instr(&mut self, instr: &CutInstruction) {
- match instr {
- &CutInstruction::Cut(ref term) => {
- let b = self.b;
- let e = self.e;
- let b0 = self.and_stack[e].b0; // STACK[E+2+1]
+ fn non_neck_cut(&mut self, term: Terminal)
+ {
+ let b = self.b;
+ let e = self.e;
+ let b0 = self.and_stack[e].b0; // STACK[E+2+1]
- if b > b0 {
- self.b = b0;
- self.tidy_trail();
- }
+ if b > b0 {
+ self.b = b0;
+ self.tidy_trail();
+ }
- if let &Terminal::Terminal = term {
- self.p = self.cp;
- } else {
- self.p += 1;
- }
- },
+ if let Terminal::Terminal = term {
+ self.p = self.cp;
+ } else {
+ self.p += 1;
+ }
+ }
+
+ fn neck_cut(&mut self, term: Terminal)
+ {
+ let b = self.b;
+ let b0 = self.b0;
+
+ if b > b0 {
+ self.b = b0;
+ self.tidy_trail();
+ }
+
+ if let Terminal::Terminal = term {
+ self.p = self.cp;
+ } else {
+ self.p += 1;
+ }
+ }
+
+ fn execute_cut_instr(&mut self, instr: &CutInstruction) {
+ match instr {
+ &CutInstruction::Cut(term) =>
+ self.non_neck_cut(term),
&CutInstruction::GetLevel => {
let b0 = self.b0;
let e = self.e;
self.and_stack[e].b0 = b0;
self.p += 1;
},
- &CutInstruction::NeckCut(ref term) => {
- let b = self.b;
- let b0 = self.b0;
-
- if b > b0 {
- self.b = b0;
- self.tidy_trail();
- }
-
- if let &Terminal::Terminal = term {
- self.p = self.cp;
- } else {
- self.p += 1;
- }
- }
+ &CutInstruction::NeckCut(term) =>
+ self.neck_cut(term)
}
}
)
}
+macro_rules! retry_me_else {
+ ($o:expr) => (
+ Line::Choice(ChoiceInstruction::RetryMeElse($o))
+ )
+}
+
macro_rules! is_atomic {
($reg:expr) => (
Line::BuiltIn(BuiltInInstruction::IsAtomic($reg))
)
}
+macro_rules! terminal {
+ () => (
+ Terminal::Terminal
+ )
+}
+
macro_rules! non_terminal {
() => (
Terminal::Non
Line::Cut(CutInstruction::GetLevel)
)
}
+
+macro_rules! switch_on_term {
+ ($v:expr, $c:expr, $l:expr, $s:expr) => (
+ Line::Indexing(IndexingInstruction::SwitchOnTerm($v, $c, $l, $s))
+ )
+}
+
+macro_rules! indexed_try {
+ ($i:expr) => (
+ Line::IndexedChoice(IndexedChoiceInstruction::Try($i))
+ )
+}
+
+macro_rules! retry {
+ ($i:expr) => (
+ Line::IndexedChoice(IndexedChoiceInstruction::Retry($i))
+ )
+}
+
+macro_rules! trust {
+ ($i:expr) => (
+ Line::IndexedChoice(IndexedChoiceInstruction::Trust($i))
+ )
+}
+
+macro_rules! get_cp {
+ () => (
+ Line::BuiltIn(BuiltInInstruction::GetCutPoint)
+ )
+}
+
+macro_rules! set_neck_cp {
+ ($term:expr) => (
+ Line::BuiltIn(BuiltInInstruction::SetNeckCutPoint($term))
+ )
+}
+
+macro_rules! set_non_neck_cp {
+ ($term:expr) => (
+ Line::BuiltIn(BuiltInInstruction::SetNonNeckCutPoint($term))
+ )
+}
+
+macro_rules! get_constant {
+ ($c:expr, $r:expr) => (
+ FactInstruction::GetConstant(Level::Shallow, $c, $r)
+ )
+}
+
+macro_rules! get_structure {
+ ($atom:expr, $arity:expr, $r:expr) => (
+ FactInstruction::GetStructure(Level::Shallow, $atom, $arity, $r)
+ )
+}
+
+macro_rules! unify_variable {
+ ($r:expr) => (
+ FactInstruction::UnifyVariable($r)
+ )
+}