inline atomic and var.

This commit is contained in:
Mark Thom
2017-11-03 20:41:01 -06:00
parent 2abec91360
commit 57cc8ccac9
10 changed files with 105 additions and 45 deletions

2
Cargo.lock generated
View File

@@ -1,6 +1,6 @@
[root] [root]
name = "rusty-wam" name = "rusty-wam"
version = "0.7.0" version = "0.7.1"
dependencies = [ dependencies = [
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "rusty-wam" name = "rusty-wam"
version = "0.7.0" version = "0.7.1"
authors = ["Mark Thom"] authors = ["Mark Thom"]
[dependencies] [dependencies]

View File

@@ -54,6 +54,7 @@ The following predicates are built-in to rusty-wam.
* (\\+)/1 * (\\+)/1
* (=)/2 * (=)/2
* throw/1 * throw/1
* true/0
* var/1 * var/1
## Tutorial ## Tutorial

View File

@@ -47,7 +47,7 @@ pub trait Allocator<'a>
fn get(&self, var: &'a Var) -> RegType { fn get(&self, var: &'a Var) -> RegType {
self.bindings().get(var).unwrap().as_reg_type() self.bindings().get(var).unwrap().as_reg_type()
} }
fn record_register(&mut self, var: &'a Var, r: RegType) { fn record_register(&mut self, var: &'a Var, r: RegType) {
match self.bindings_mut().get_mut(var).unwrap() { match self.bindings_mut().get_mut(var).unwrap() {

View File

@@ -273,10 +273,12 @@ pub enum Term {
Var(Cell<VarReg>, Var) Var(Cell<VarReg>, Var)
} }
pub enum QueryTerm { pub enum QueryTerm {
CallN(Vec<Box<Term>>), CallN(Vec<Box<Term>>),
Catch(Vec<Box<Term>>), Catch(Vec<Box<Term>>),
Cut, Cut,
IsAtomic(Vec<Box<Term>>),
IsVar(Vec<Box<Term>>),
Term(Term), Term(Term),
Throw(Vec<Box<Term>>) Throw(Vec<Box<Term>>)
} }
@@ -290,6 +292,10 @@ impl QueryTerm {
QueryTermRef::Catch(terms), QueryTermRef::Catch(terms),
&QueryTerm::Cut => &QueryTerm::Cut =>
QueryTermRef::Cut, QueryTermRef::Cut,
&QueryTerm::IsAtomic(ref terms) =>
QueryTermRef::IsAtomic(terms.first().unwrap()),
&QueryTerm::IsVar(ref terms) =>
QueryTermRef::IsVar(terms.first().unwrap()),
&QueryTerm::Term(ref term) => &QueryTerm::Term(ref term) =>
QueryTermRef::Term(term), QueryTermRef::Term(term),
&QueryTerm::Throw(ref t) => &QueryTerm::Throw(ref t) =>
@@ -314,10 +320,9 @@ pub enum ClauseType<'a> {
impl<'a> ClauseType<'a> { impl<'a> ClauseType<'a> {
pub fn level_of_subterms(self) -> Level { pub fn level_of_subterms(self) -> Level {
match self { match self {
ClauseType::CallN | ClauseType::Catch | ClauseType::Throw => Level::Shallow,
ClauseType::Deep(_, _, _) => Level::Deep, ClauseType::Deep(_, _, _) => Level::Deep,
ClauseType::Root => Level::Shallow, _ => Level::Shallow
} }
} }
} }
@@ -338,11 +343,8 @@ impl<'a> TermRef<'a> {
| TermRef::Cons(lvl, _, _, _) | TermRef::Cons(lvl, _, _, _)
| TermRef::Constant(lvl, _, _) | TermRef::Constant(lvl, _, _)
| TermRef::Var(lvl, _, _) => lvl, | TermRef::Var(lvl, _, _) => lvl,
TermRef::Clause(ClauseType::Root, _) => Level::Shallow,
TermRef::Clause(ClauseType::Deep(lvl, _, _), _) => lvl, TermRef::Clause(ClauseType::Deep(lvl, _, _), _) => lvl,
TermRef::Clause(ClauseType::CallN, _) => Level::Shallow, _ => Level::Shallow
TermRef::Clause(ClauseType::Throw, _) => Level::Shallow,
TermRef::Clause(ClauseType::Catch, _) => Level::Shallow
} }
} }
} }
@@ -352,6 +354,8 @@ pub enum QueryTermRef<'a> {
CallN(&'a Vec<Box<Term>>), CallN(&'a Vec<Box<Term>>),
Catch(&'a Vec<Box<Term>>), Catch(&'a Vec<Box<Term>>),
Cut, Cut,
IsAtomic(&'a Term),
IsVar(&'a Term),
Term(&'a Term), Term(&'a Term),
Throw(&'a Vec<Box<Term>>) Throw(&'a Vec<Box<Term>>)
} }
@@ -361,6 +365,8 @@ impl<'a> QueryTermRef<'a> {
match self { match self {
QueryTermRef::Catch(_) => 3, QueryTermRef::Catch(_) => 3,
QueryTermRef::Throw(_) => 1, QueryTermRef::Throw(_) => 1,
QueryTermRef::IsAtomic(_) => 1,
QueryTermRef::IsVar(_) => 1,
QueryTermRef::CallN(terms) => terms.len(), QueryTermRef::CallN(terms) => terms.len(),
QueryTermRef::Cut => 0, QueryTermRef::Cut => 0,
QueryTermRef::Term(term) => term.arity(), QueryTermRef::Term(term) => term.arity(),
@@ -415,10 +421,11 @@ pub enum BuiltInInstruction {
GetCurrentBlock, GetCurrentBlock,
InstallNewBlock, InstallNewBlock,
InternalCallN, InternalCallN,
IsAtomic, IsAtomic(RegType),
IsVar, IsVar(RegType),
ResetBlock, ResetBlock,
SetBall, SetBall,
Succeed,
Unify, Unify,
UnwindStack UnwindStack
} }
@@ -432,7 +439,7 @@ pub enum ControlInstruction {
Deallocate, Deallocate,
Execute(Atom, usize), Execute(Atom, usize),
ExecuteN(usize), ExecuteN(usize),
Goto(usize, usize), Goto(usize, usize), // p, arity.
Proceed, Proceed,
ThrowCall, ThrowCall,
ThrowExecute ThrowExecute

View File

@@ -18,9 +18,9 @@ pub type CodeDir = HashMap<PredicateKey, (PredicateKeyType, usize)>;
fn get_builtins() -> Code { fn get_builtins() -> Code {
vec![internal_call_n!(), // callN/N, 0. vec![internal_call_n!(), // callN/N, 0.
is_atomic!(), // atomic/1, 1. is_atomic!(temp_v!(1)), // atomic/1, 1.
proceed!(), proceed!(),
is_var!(), // var/1, 3. is_var!(temp_v!(1)), // var/1, 3.
proceed!(), proceed!(),
allocate!(4), // catch/3, 5. allocate!(4), // catch/3, 5.
fact![get_var_in_fact!(perm_v!(2), 1), fact![get_var_in_fact!(perm_v!(2), 1),
@@ -104,6 +104,7 @@ fn get_builtins() -> Code {
proceed!(), proceed!(),
fact![get_value!(temp_v!(1), 2)], // =/2, 73. fact![get_value!(temp_v!(1), 2)], // =/2, 73.
proceed!(), proceed!(),
succeed!(), // true/0, 75.
] ]
} }
@@ -134,6 +135,7 @@ pub fn build_code_dir() -> (Code, CodeDir, OpDir)
code_dir.insert((String::from("catch"), 3), (PredicateKeyType::BuiltIn, 5)); 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("throw"), 1), (PredicateKeyType::BuiltIn, 59));
code_dir.insert((String::from("="), 2), (PredicateKeyType::BuiltIn, 73)); code_dir.insert((String::from("="), 2), (PredicateKeyType::BuiltIn, 73));
code_dir.insert((String::from("true"), 0), (PredicateKeyType::BuiltIn, 75));
(builtin_code, code_dir, op_dir) (builtin_code, code_dir, op_dir)
} }

View File

@@ -207,13 +207,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
fn add_conditional_call(compiled_query: &mut Code, qt: QueryTermRef, pvs: usize) fn add_conditional_call(compiled_query: &mut Code, qt: QueryTermRef, pvs: usize)
{ {
match qt { match qt {
QueryTermRef::CallN(terms) => { QueryTermRef::CallN(terms) => {
let call = ControlInstruction::CallN(terms.len()); let call = ControlInstruction::CallN(terms.len());
compiled_query.push(Line::Control(call)); compiled_query.push(Line::Control(call));
}, },
QueryTermRef::Catch(_) => QueryTermRef::Catch(_) =>
compiled_query.push(Line::Control(ControlInstruction::CatchCall)), compiled_query.push(Line::Control(ControlInstruction::CatchCall)),
QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref atom))) => { QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref atom))) => {
let call = ControlInstruction::Call(atom.clone(), 0, pvs); let call = ControlInstruction::Call(atom.clone(), 0, pvs);
compiled_query.push(Line::Control(call)); compiled_query.push(Line::Control(call));
@@ -228,31 +228,31 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
} }
} }
fn lco(body: &mut Code, toc: QueryTermRef<'a>) -> usize fn lco(code: &mut Code, toc: QueryTermRef<'a>) -> usize
{ {
let last_arity = toc.arity(); let last_arity = toc.arity();
let mut dealloc_index = body.len() - 1; let mut dealloc_index = code.len() - 1;
match toc { match toc {
QueryTermRef::Term(&Term::Clause(_, ref name, _)) QueryTermRef::Term(&Term::Clause(_, ref name, _))
| QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref name))) => | QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref name))) =>
if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() { if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() {
*ctrl = ControlInstruction::Execute(name.clone(), last_arity); *ctrl = ControlInstruction::Execute(name.clone(), last_arity);
}, },
QueryTermRef::CallN(terms) => QueryTermRef::CallN(terms) =>
if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() { if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() {
*ctrl = ControlInstruction::ExecuteN(terms.len()); *ctrl = ControlInstruction::ExecuteN(terms.len());
}, },
QueryTermRef::Catch(_) => QueryTermRef::Catch(_) =>
if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() { if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() {
*ctrl = ControlInstruction::CatchExecute; *ctrl = ControlInstruction::CatchExecute;
}, },
QueryTermRef::Cut => {}, QueryTermRef::Cut => {},
QueryTermRef::Throw(_) => QueryTermRef::Throw(_) =>
if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() { if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() {
*ctrl = ControlInstruction::ThrowExecute; *ctrl = ControlInstruction::ThrowExecute;
}, },
_ => dealloc_index = body.len() _ => dealloc_index = code.len()
}; };
dealloc_index dealloc_index
@@ -261,7 +261,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
fn compile_seq(&mut self, fn compile_seq(&mut self,
iter: ChunkedIterator<'a>, iter: ChunkedIterator<'a>,
conjunct_info: &ConjunctInfo<'a>, conjunct_info: &ConjunctInfo<'a>,
body: &mut Code, code: &mut Code,
is_exposed: bool) is_exposed: bool)
{ {
for (chunk_num, _, terms) in iter { for (chunk_num, _, terms) in iter {
@@ -275,29 +275,63 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
match term { match term {
&QueryTermRef::Cut if i + 1 < terms.len() => { &QueryTermRef::Cut if i + 1 < terms.len() => {
body.push(if chunk_num == 0 { code.push(if chunk_num == 0 {
Line::Cut(CutInstruction::NeckCut(Terminal::Non)) Line::Cut(CutInstruction::NeckCut(Terminal::Non))
} else { } else {
Line::Cut(CutInstruction::Cut(Terminal::Non)) Line::Cut(CutInstruction::Cut(Terminal::Non))
}); });
}, },
&QueryTermRef::Cut => { &QueryTermRef::Cut => {
body.push(if chunk_num == 0 { code.push(if chunk_num == 0 {
Line::Cut(CutInstruction::NeckCut(Terminal::Terminal)) Line::Cut(CutInstruction::NeckCut(Terminal::Terminal))
} else { } else {
Line::Cut(CutInstruction::Cut(Terminal::Terminal)) Line::Cut(CutInstruction::Cut(Terminal::Terminal))
}); });
}, },
&QueryTermRef::IsAtomic(term) =>
match term {
&Term::AnonVar | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => {
code.push(goto!(61, 0)); // goto false/0.
},
&Term::Constant(_, _) => {
code.push(goto!(75, 0)); // goto succeed/0.
},
&Term::Var(ref vr, ref name) => {
let mut target = Vec::new();
self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
code.push(Line::Query(target));
code.push(is_atomic!(vr.get().norm()));
}
},
&QueryTermRef::IsVar(term) =>
match term {
&Term::Constant(_, _) | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => {
code.push(goto!(61, 0)); // goto false/0.
},
&Term::AnonVar => {
code.push(goto!(75, 0)); // goto succeed/0.
},
&Term::Var(ref vr, ref name) => {
let mut target = Vec::new();
self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
code.push(Line::Query(target));
code.push(is_var!(vr.get().norm()));
}
},
_ if chunk_num == 0 => { _ if chunk_num == 0 => {
self.marker.advance(GenContext::Head, *term); self.marker.advance(GenContext::Head, *term);
let iter = term.post_order_iter(); let iter = term.post_order_iter();
body.push(Line::Query(self.compile_target(iter, term_loc, is_exposed))); code.push(Line::Query(self.compile_target(iter, term_loc, is_exposed)));
Self::add_conditional_call(body, *term, conjunct_info.perm_vars()); Self::add_conditional_call(code, *term, conjunct_info.perm_vars());
}, },
_ => { _ => {
let num_vars = conjunct_info.perm_vs.vars_above_threshold(i + 1); let num_vars = conjunct_info.perm_vs.vars_above_threshold(i + 1);
self.compile_query_line(*term, term_loc, body, num_vars, is_exposed); self.compile_query_line(*term, term_loc, code, num_vars, is_exposed);
}, },
}; };
@@ -393,7 +427,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
pub fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code pub fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code
{ {
let iter = ChunkedIterator::from_fact(term); let iter = ChunkedIterator::from_fact(term);
self.collect_var_data(iter); self.collect_var_data(iter);
self.marker.advance(GenContext::Head, QueryTermRef::Term(term)); self.marker.advance(GenContext::Head, QueryTermRef::Term(term));

View File

@@ -77,7 +77,8 @@ impl<'a> QueryIterator<'a> {
let state = IteratorState::Clause(0, ClauseType::Catch, terms); let state = IteratorState::Clause(0, ClauseType::Catch, terms);
QueryIterator { state_stack: vec![state] } QueryIterator { state_stack: vec![state] }
}, },
QueryTermRef::Term(term) => Self::from_term(term), QueryTermRef::IsAtomic(term) | QueryTermRef::IsVar(term) | QueryTermRef::Term(term) =>
Self::from_term(term),
QueryTermRef::Throw(term) => { QueryTermRef::Throw(term) => {
let state = IteratorState::Clause(0, ClauseType::Throw, term); let state = IteratorState::Clause(0, ClauseType::Throw, term);
QueryIterator { state_stack: vec![state] } QueryIterator { state_stack: vec![state] }
@@ -106,10 +107,10 @@ impl<'a> Iterator for QueryIterator<'a> {
match ct { match ct {
ClauseType::CallN => ClauseType::CallN =>
self.push_subterm(Level::Shallow, child_terms[0].as_ref()), self.push_subterm(Level::Shallow, child_terms[0].as_ref()),
ClauseType::Root | ClauseType::Throw | ClauseType::Catch =>
return None,
ClauseType::Deep(_, _, _) => ClauseType::Deep(_, _, _) =>
return Some(TermRef::Clause(ct, child_terms)) return Some(TermRef::Clause(ct, child_terms)),
_ =>
return None
}; };
} else { } else {
self.push_clause(child_num + 1, ct, child_terms); self.push_clause(child_num + 1, ct, child_terms);
@@ -317,6 +318,8 @@ impl<'a> ChunkedIterator<'a>
arity = child_terms.len(); arity = child_terms.len();
break; break;
}, },
QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) =>
result.push(term),
QueryTermRef::Cut => { QueryTermRef::Cut => {
result.push(term); result.push(term);

View File

@@ -421,10 +421,14 @@ impl Machine {
self.query_stepper(); self.query_stepper();
match self.ms.p { match self.ms.p {
CodePtr::TopLevel(_, p) if p > 0 => {}, CodePtr::TopLevel(_, p) if p > 0 => {},
_ => break _ => break
}; };
} }
if let CodePtr::TopLevel(cn, _) = self.ms.p {
self.record_var_places(cn, alloc_locs, heap_locs);
}
} }
fn fail<'a>(&mut self) -> EvalSession<'a> fn fail<'a>(&mut self) -> EvalSession<'a>
@@ -1388,16 +1392,16 @@ impl MachineState {
self.b = self.block; self.b = self.block;
self.fail = true; self.fail = true;
}, },
&BuiltInInstruction::IsAtomic => { &BuiltInInstruction::IsAtomic(r) => {
let d = self.deref(self[temp_v!(1)].clone()); let d = self.deref(self[r].clone());
match d { match d {
Addr::Con(_) => self.p += 1, Addr::Con(_) => self.p += 1,
_ => self.fail = true _ => self.fail = true
}; };
}, },
&BuiltInInstruction::IsVar => { &BuiltInInstruction::IsVar(r) => {
let d = self.deref(self[temp_v!(1)].clone()); let d = self.deref(self[r].clone());
match d { match d {
Addr::HeapCell(_) | Addr::StackCell(_,_) => Addr::HeapCell(_) | Addr::StackCell(_,_) =>
@@ -1410,6 +1414,9 @@ impl MachineState {
&BuiltInInstruction::Fail => { &BuiltInInstruction::Fail => {
self.fail = true; self.fail = true;
self.p += 1; self.p += 1;
},
&BuiltInInstruction::Succeed => {
self.p += 1;
} }
}; };
} }

View File

@@ -100,14 +100,14 @@ macro_rules! try_me_else {
} }
macro_rules! is_atomic { macro_rules! is_atomic {
() => ( ($reg:expr) => (
Line::BuiltIn(BuiltInInstruction::IsAtomic) Line::BuiltIn(BuiltInInstruction::IsAtomic($reg))
) )
} }
macro_rules! is_var { macro_rules! is_var {
() => ( ($reg:expr) => (
Line::BuiltIn(BuiltInInstruction::IsVar) Line::BuiltIn(BuiltInInstruction::IsVar($reg))
) )
} }
@@ -221,6 +221,12 @@ macro_rules! fail {
) )
} }
macro_rules! succeed {
() => (
Line::BuiltIn(BuiltInInstruction::Succeed)
)
}
macro_rules! duplicate_term { macro_rules! duplicate_term {
() => ( () => (
Line::BuiltIn(BuiltInInstruction::DuplicateTerm) Line::BuiltIn(BuiltInInstruction::DuplicateTerm)