add beginning support for ',', ';', '->'
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rusty-wam"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
authors = ["Mark Thom"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -20,7 +20,7 @@ Extend rusty-wam to include the following, among other features:
|
||||
* 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.)
|
||||
|
||||
@@ -275,6 +275,12 @@ pub enum Constant {
|
||||
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 {
|
||||
@@ -416,6 +422,7 @@ pub enum ChoiceInstruction {
|
||||
TryMeElse(usize)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Terminal {
|
||||
Terminal, Non
|
||||
}
|
||||
@@ -715,12 +722,15 @@ pub enum BuiltInInstruction {
|
||||
Fail,
|
||||
GetBall,
|
||||
GetCurrentBlock,
|
||||
GetCutPoint,
|
||||
InstallNewBlock,
|
||||
InternalCallN,
|
||||
IsAtomic(RegType),
|
||||
IsVar(RegType),
|
||||
ResetBlock,
|
||||
SetBall,
|
||||
SetNeckCutPoint(Terminal),
|
||||
SetNonNeckCutPoint(Terminal),
|
||||
Succeed,
|
||||
Unify,
|
||||
UnwindStack
|
||||
|
||||
@@ -104,7 +104,90 @@ fn get_builtins() -> Code {
|
||||
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)
|
||||
]
|
||||
}
|
||||
|
||||
@@ -149,6 +232,10 @@ pub fn build_code_dir() -> (Code, CodeDir, OpDir)
|
||||
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)
|
||||
for arity in 0 .. 63 {
|
||||
@@ -165,5 +252,9 @@ pub fn build_code_dir() -> (Code, CodeDir, OpDir)
|
||||
code_dir.insert((String::from("="), 2), (PredicateKeyType::BuiltIn, 73));
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -65,8 +65,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
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 {
|
||||
@@ -96,7 +95,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
|
||||
self.marker.reset_arg(arity);
|
||||
self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
|
||||
|
||||
if !target.is_empty() {
|
||||
code.push(Line::Query(target));
|
||||
}
|
||||
|
||||
vr.get().norm()
|
||||
}
|
||||
}
|
||||
@@ -233,13 +236,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
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)
|
||||
@@ -340,7 +336,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
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)
|
||||
@@ -421,7 +418,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
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());
|
||||
},
|
||||
_ => {
|
||||
@@ -479,7 +481,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
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);
|
||||
@@ -550,8 +556,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
let mut compiled_fact = self.compile_target(iter, GenContext::Head, false);
|
||||
|
||||
self.mark_unsafe_fact_vars(&mut compiled_fact);
|
||||
|
||||
if !compiled_fact.is_empty() {
|
||||
code.push(Line::Fact(compiled_fact));
|
||||
}
|
||||
}
|
||||
|
||||
code.push(proceed!());
|
||||
code
|
||||
@@ -567,9 +576,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -141,6 +141,16 @@ impl fmt::Display for IndexedChoiceInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -159,6 +169,8 @@ impl fmt::Display for BuiltInInstruction {
|
||||
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 =>
|
||||
@@ -171,6 +183,10 @@ impl fmt::Display for BuiltInInstruction {
|
||||
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 =>
|
||||
|
||||
@@ -1622,6 +1622,13 @@ impl MachineState {
|
||||
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);
|
||||
@@ -1659,6 +1666,28 @@ impl MachineState {
|
||||
|
||||
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()));
|
||||
|
||||
@@ -1997,9 +2026,8 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_cut_instr(&mut self, instr: &CutInstruction) {
|
||||
match instr {
|
||||
&CutInstruction::Cut(ref term) => {
|
||||
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]
|
||||
@@ -2009,20 +2037,15 @@ impl MachineState {
|
||||
self.tidy_trail();
|
||||
}
|
||||
|
||||
if let &Terminal::Terminal = term {
|
||||
if let Terminal::Terminal = term {
|
||||
self.p = self.cp;
|
||||
} else {
|
||||
self.p += 1;
|
||||
}
|
||||
},
|
||||
&CutInstruction::GetLevel => {
|
||||
let b0 = self.b0;
|
||||
let e = self.e;
|
||||
}
|
||||
|
||||
self.and_stack[e].b0 = b0;
|
||||
self.p += 1;
|
||||
},
|
||||
&CutInstruction::NeckCut(ref term) => {
|
||||
fn neck_cut(&mut self, term: Terminal)
|
||||
{
|
||||
let b = self.b;
|
||||
let b0 = self.b0;
|
||||
|
||||
@@ -2031,12 +2054,26 @@ impl MachineState {
|
||||
self.tidy_trail();
|
||||
}
|
||||
|
||||
if let &Terminal::Terminal = term {
|
||||
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(term) =>
|
||||
self.neck_cut(term)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,12 @@ macro_rules! try_me_else {
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! retry_me_else {
|
||||
($o:expr) => (
|
||||
Line::Choice(ChoiceInstruction::RetryMeElse($o))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! is_atomic {
|
||||
($reg:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::IsAtomic($reg))
|
||||
@@ -159,6 +165,12 @@ macro_rules! proceed {
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! terminal {
|
||||
() => (
|
||||
Terminal::Terminal
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! non_terminal {
|
||||
() => (
|
||||
Terminal::Non
|
||||
@@ -260,3 +272,63 @@ macro_rules! get_level {
|
||||
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)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user