optimized up to section 5.10

This commit is contained in:
Mark Thom
2017-03-25 01:58:54 -06:00
parent 24b60eb2c6
commit d65970ee57
8 changed files with 321 additions and 76 deletions

2
Cargo.lock generated
View File

@@ -1,6 +1,6 @@
[root] [root]
name = "rusty-wam" name = "rusty-wam"
version = "0.5.7" version = "0.5.10"
dependencies = [ dependencies = [
"lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop-util 0.12.5 (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.5.7" version = "0.5.10"
authors = ["Mark Thom"] authors = ["Mark Thom"]
build = "build.rs" build = "build.rs"

View File

@@ -11,8 +11,8 @@ pure Prolog.
Pure Prolog is implemented as a simple REPL. "Pure Prolog" is Prolog Pure Prolog is implemented as a simple REPL. "Pure Prolog" is Prolog
without cut, meta- or extra-logical operators, or side effects of any without cut, meta- or extra-logical operators, or side effects of any
kind. In terms of the tutorial pacing, the work has progressed to the kind. In terms of the tutorial pacing, the work has progressed to the
to the end of section 5.7, skipping past 5.4. Atoms and lists are the end of section 5.9, skipping past 5.4. Atoms and lists are the only
only two data types currently supported. two data types currently supported.
While proper environment trimming code is emitted by the code While proper environment trimming code is emitted by the code
generator, it has no effect on the bytecode WAM, which lacks generator, it has no effect on the bytecode WAM, which lacks
@@ -21,7 +21,7 @@ frames.
## Tutorial ## Tutorial
To enter a multi-clause predicate, the brackets ":{" and "}:" are used To enter a multi-clause predicate, the brackets ":{" and "}:" are used
as delimiters. They must be entirely contained with their own lines. as delimiters. They must be contained entirely within their own lines.
For example, For example,
``` ```

View File

@@ -8,13 +8,13 @@ use prolog::machine::*;
mod tests { mod tests {
use super::*; use super::*;
use prolog::ast::*; use prolog::ast::*;
fn submit(wam: &mut Machine, buffer: &str) -> EvalResult { fn submit(wam: &mut Machine, buffer: &str) -> EvalResult {
let result = eval(wam, buffer); let result = eval(wam, buffer);
wam.reset(); wam.reset();
result result
} }
#[test] #[test]
fn test_queries_on_facts() { fn test_queries_on_facts() {
let mut wam = Machine::new(); let mut wam = Machine::new();
@@ -90,6 +90,13 @@ mod tests {
assert_eq!(submit(&mut wam, "?- p(f(X, g(Y), Z), g(Z), h).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(f(X, g(Y), Z), g(Z), h).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(Z, Y, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(Z, Y, X).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(f(X, Y, Z), Y, h).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(f(X, Y, Z), Y, h).").failed_query(), false);
submit(&mut wam, "p(_, f(_, Y, _)) :- h(Y).");
submit(&mut wam, "h(y).");
assert_eq!(submit(&mut wam, "?- p(_, f(_, Y, _)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(_, f(_, y, _)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(_, f(_, z, _)).").failed_query(), true);
} }
#[test] #[test]
@@ -110,7 +117,7 @@ mod tests {
assert_eq!(submit(&mut wam, "?- p(c, d, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(c, d, X).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(a, a, a).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(a, a, a).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(b, c, d).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(b, c, d).").failed_query(), true);
submit(&mut wam, "p(X, a). p(X, Y) :- q(Z), p(X, X)."); submit(&mut wam, "p(X, a). p(X, Y) :- q(Z), p(X, X).");
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false);
@@ -137,7 +144,7 @@ mod tests {
assert_eq!(submit(&mut wam, "?- p(a, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(a, X).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(b, a).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(b, a).").failed_query(), true);
submit(&mut wam, "p(X, Y, Z) :- q(X), r(Y), s(Z). submit(&mut wam, "p(X, Y, Z) :- q(X), r(Y), s(Z).
p(a, b, Z) :- q(Z)."); p(a, b, Z) :- q(Z).");
submit(&mut wam, "q(x)."); submit(&mut wam, "q(x).");
@@ -154,7 +161,7 @@ mod tests {
submit(&mut wam, "s(x, t)."); submit(&mut wam, "s(x, t).");
submit(&mut wam, "t(y, u)."); submit(&mut wam, "t(y, u).");
assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(x).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(x).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(y).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(y).").failed_query(), false);
@@ -173,6 +180,18 @@ mod tests {
assert_eq!(submit(&mut wam, "?- p(X, X, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, X, X).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(X, Y, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y, X).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(f(f(X)), h(f(X)), Y).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(f(f(X)), h(f(X)), Y).").failed_query(), true);
submit(&mut wam, "p(X) :- f(Y), g(Y), i(X, Y).");
submit(&mut wam, "g(f(a)). g(f(b)). g(f(c)).");
submit(&mut wam, "f(f(a)). f(f(b)). f(f(c)).");
submit(&mut wam, "i(X, X).");
assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false);
submit(&mut wam, "p(X) :- f(f(Y)), g(Y, f(Y)), i(X, f(Y)).");
submit(&mut wam, "g(Y, f(Y)) :- g(f(Y)).");
assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false);
} }
#[test] #[test]
@@ -224,7 +243,7 @@ mod tests {
fn prolog_repl() { fn prolog_repl() {
let mut wam = Machine::new(); let mut wam = Machine::new();
loop { loop {
print!("prolog> "); print!("prolog> ");
@@ -239,7 +258,7 @@ fn prolog_repl() {
let result = eval(&mut wam, buffer.trim()); let result = eval(&mut wam, buffer.trim());
print(&mut wam, result); print(&mut wam, result);
wam.reset(); wam.reset();
} }
} }

View File

@@ -1,4 +1,5 @@
use std::cell::Cell; use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::{Add, AddAssign}; use std::ops::{Add, AddAssign};
use std::vec::Vec; use std::vec::Vec;
@@ -40,7 +41,7 @@ pub enum Level {
Deep, Shallow Deep, Shallow
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum RegType { pub enum RegType {
Perm(usize), Perm(usize),
Temp(usize) Temp(usize)
@@ -83,7 +84,7 @@ impl VarReg {
pub fn is_temp(self) -> bool { pub fn is_temp(self) -> bool {
!self.norm().is_perm() !self.norm().is_perm()
} }
pub fn root_register(self) -> usize { pub fn root_register(self) -> usize {
match self { match self {
VarReg::ArgAndNorm(_, root) => root, VarReg::ArgAndNorm(_, root) => root,
@@ -139,8 +140,9 @@ pub enum FactInstruction {
GetList(Level, RegType), GetList(Level, RegType),
GetStructure(Level, Atom, usize, RegType), GetStructure(Level, Atom, usize, RegType),
GetValue(RegType, usize), GetValue(RegType, usize),
GetVariable(RegType, usize), GetVariable(RegType, usize),
UnifyConstant(Constant), UnifyConstant(Constant),
UnifyLocalValue(RegType),
UnifyVariable(RegType), UnifyVariable(RegType),
UnifyValue(RegType), UnifyValue(RegType),
UnifyVoid(usize) UnifyVoid(usize)
@@ -150,9 +152,11 @@ pub enum QueryInstruction {
PutConstant(Level, Constant, RegType), PutConstant(Level, Constant, RegType),
PutList(Level, RegType), PutList(Level, RegType),
PutStructure(Level, Atom, usize, RegType), PutStructure(Level, Atom, usize, RegType),
PutUnsafeValue(usize, usize),
PutValue(RegType, usize), PutValue(RegType, usize),
PutVariable(RegType, usize), PutVariable(RegType, usize),
SetConstant(Constant), SetConstant(Constant),
SetLocalValue(RegType),
SetVariable(RegType), SetVariable(RegType),
SetValue(RegType), SetValue(RegType),
SetVoid(usize) SetVoid(usize)
@@ -196,6 +200,7 @@ impl<'a> From<&'a Line> for LineOrCodeOffset<'a> {
pub type Code = Vec<Line>; pub type Code = Vec<Line>;
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum Addr { pub enum Addr {
Con(Constant), Con(Constant),
@@ -220,6 +225,13 @@ impl Addr {
_ => None _ => None
} }
} }
pub fn is_protected(&self, e: usize) -> bool {
match self {
&Addr::StackCell(fr, _) if fr > e => false,
_ => true
}
}
} }
impl From<Ref> for Addr { impl From<Ref> for Addr {
@@ -275,6 +287,26 @@ impl HeapCellValue {
} }
} }
impl PartialOrd for Ref {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (*self, *other) {
(Ref::HeapCell(hc1), Ref::HeapCell(hc2)) =>
Some(hc1.cmp(&hc2)),
(Ref::HeapCell(_), _) =>
Some(Ordering::Less),
(Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) =>
if fr1 < fr2 {
Some(Ordering::Less)
} else if fr1 == fr2 {
Some(sc1.cmp(&sc2))
} else {
Some(Ordering::Greater)
},
_ => Some(Ordering::Greater)
}
}
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum CodePtr { pub enum CodePtr {
DirEntry(usize), DirEntry(usize),

View File

@@ -250,7 +250,8 @@ enum VarStatus {
} }
pub struct CodeGenerator<'a> { pub struct CodeGenerator<'a> {
marker: TermMarker<'a> marker: TermMarker<'a>,
var_count: HashMap<&'a Var, usize>
} }
type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>); type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
@@ -258,37 +259,41 @@ type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>;
impl<'a> CodeGenerator<'a> { impl<'a> CodeGenerator<'a> {
pub fn new() -> Self { pub fn new() -> Self {
CodeGenerator { marker: TermMarker::new() } CodeGenerator { marker: TermMarker::new(),
var_count: HashMap::new() }
} }
pub fn vars(&self) -> &HashMap<&Var, VarReg> { pub fn vars(&self) -> &HashMap<&Var, VarReg> {
&self.marker.bindings &self.marker.bindings
} }
#[allow(dead_code)] fn update_var_count<Iter>(&mut self, iter: Iter)
fn count_vars(term: &Term) -> HashMap<&Var, usize> { where Iter : Iterator<Item=TermRef<'a>>
{
let mut var_count = HashMap::new(); let mut var_count = HashMap::new();
for term in term.breadth_first_iter() { for term in iter {
if let TermRef::Var(_, _, ref var) = term { if let TermRef::Var(_, _, var) = term {
let entry = var_count.entry(*var).or_insert(0); if self.marker.contains_var(var) {
var_count.insert(var, 2);
continue;
}
let entry = var_count.entry(var).or_insert(0);
*entry += 1; *entry += 1;
} }
} }
var_count self.var_count = var_count;
} }
#[allow(dead_code)] fn all_singleton_vars(&self, terms: &Vec<Box<Term>>) -> bool
fn all_singleton_vars(terms: &Vec<Box<Term>>,
var_count: &HashMap<&Var, usize>)
-> bool
{ {
for term in terms { for term in terms {
match term.as_ref() { match term.as_ref() {
&Term::AnonVar => {}, &Term::AnonVar => {},
&Term::Var(ref cell, ref var) if cell.get().is_temp() => &Term::Var(ref cell, ref var) if cell.get().is_temp() =>
if var_count.get(var).unwrap() != &1 { if self.var_count.get(var).unwrap() != &1 {
return false; return false;
}, },
_ => return false _ => return false
@@ -298,7 +303,6 @@ impl<'a> CodeGenerator<'a> {
true true
} }
#[allow(dead_code)]
fn void_subterms<Target>(subterms: usize) -> Target fn void_subterms<Target>(subterms: usize) -> Target
where Target: CompilationTarget<'a> where Target: CompilationTarget<'a>
{ {
@@ -416,7 +420,6 @@ impl<'a> CodeGenerator<'a> {
{ {
let iter = Target::iter(term); let iter = Target::iter(term);
let mut target = Vec::new(); let mut target = Vec::new();
let var_count = Self::count_vars(term);
for term in iter { for term in iter {
match term { match term {
@@ -424,7 +427,7 @@ impl<'a> CodeGenerator<'a> {
target.push(self.to_structure(lvl, cell, atom, terms.len())); target.push(self.to_structure(lvl, cell, atom, terms.len()));
if !has_exposed_vars { if !has_exposed_vars {
if Self::all_singleton_vars(terms, &var_count) { if self.all_singleton_vars(terms) {
target.push(Self::void_subterms(terms.len())); target.push(Self::void_subterms(terms.len()));
continue; continue;
} }
@@ -547,7 +550,7 @@ impl<'a> CodeGenerator<'a> {
for &(term_status, _) in vs.values() { for &(term_status, _) in vs.values() {
if let VarStatus::Permanent(i) = term_status { if let VarStatus::Permanent(i) = term_status {
if i >= index { if i > index {
var_count += 1; var_count += 1;
} }
} }
@@ -556,36 +559,7 @@ impl<'a> CodeGenerator<'a> {
var_count var_count
} }
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code { fn lco(body: &mut Code, rule: &'a Rule) -> usize {
let vs = Self::mark_perm_vars(&rule);
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
let perm_vars = Self::vars_above_threshold(&vs, 1);
let mut body = Vec::new();
if clauses.len() > 0 {
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
}
self.marker.advance(p0);
body.push(Line::Fact(self.compile_target(p0, false)));
self.marker.advance_at_head(p1);
body.push(Line::Query(self.compile_target(p1, false)));
Self::add_conditional_call(&mut body, p1, perm_vars);
body = clauses.iter().enumerate()
.map(|(i, ref term)| {
let num_vars = Self::vars_above_threshold(&vs, i+2);
self.compile_internal_query(term, num_vars)
})
.fold(body, |mut body, ref mut cqs| {
body.append(cqs);
body
});
// now perform LCO.
let last_arity = rule.last_clause().arity(); let last_arity = rule.last_clause().arity();
let mut dealloc_index = body.len() - 1; let mut dealloc_index = body.len() - 1;
@@ -599,6 +573,103 @@ impl<'a> CodeGenerator<'a> {
_ => dealloc_index = body.len() _ => dealloc_index = body.len()
}; };
dealloc_index
}
fn mark_unsafe_query_vars(head: &Term,
vs: &VariableFixtures,
query: &mut CompiledQuery)
{
let mut unsafe_vars = HashMap::new();
for &(_, ref cb) in vs.values() {
if !cb.is_empty() {
let index = cb.first().unwrap().get().norm();
unsafe_vars.insert(index, false);
}
}
for term_ref in head.breadth_first_iter() {
match term_ref {
TermRef::Var(_, cell, _) => {
unsafe_vars.remove(&cell.get().norm());
},
_ => {}
};
}
for query_instr in query.iter_mut() {
match query_instr {
&mut QueryInstruction::PutValue(RegType::Perm(i), arg) =>
if let Some(found) = unsafe_vars.get_mut(&RegType::Perm(i)) {
if !*found {
*found = true;
*query_instr = QueryInstruction::PutUnsafeValue(i, arg);
}
},
&mut QueryInstruction::SetVariable(reg)
| &mut QueryInstruction::PutVariable(reg, _) =>
if let Some(found) = unsafe_vars.get_mut(&reg) {
*found = true;
},
&mut QueryInstruction::SetValue(reg) =>
if let Some(found) = unsafe_vars.get_mut(&reg) {
if !*found {
*found = true;
*query_instr = QueryInstruction::SetLocalValue(reg);
}
},
_ => {}
};
}
}
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
let vs = Self::mark_perm_vars(&rule);
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
let perm_vars = Self::vars_above_threshold(&vs, 0);
let mut body = Vec::new();
if clauses.len() > 0 {
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
}
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
self.update_var_count(iter);
self.marker.advance(p0);
body.push(Line::Fact(self.compile_target(p0, false)));
self.marker.advance_at_head(p1);
body.push(Line::Query(self.compile_target(p1, false)));
Self::add_conditional_call(&mut body, p1, perm_vars);
body = clauses.iter().enumerate()
.map(|(i, ref term)| {
let num_vars = Self::vars_above_threshold(&vs, i+1);
self.compile_internal_query(term, num_vars)
})
.fold(body, |mut body, ref mut cqs| {
body.append(cqs);
body
});
if clauses.len() > 0 {
let mut index = body.len() - 1;
if let &Line::Control(_) = body.last().unwrap() {
index -= 1;
}
if let &mut Line::Query(ref mut query) = &mut body[index] {
Self::mark_unsafe_query_vars(p0, &vs, query);
}
}
let dealloc_index = Self::lco(&mut body, &rule);
if clauses.len() > 0 { if clauses.len() > 0 {
body.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate)); body.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
} }
@@ -606,18 +677,51 @@ impl<'a> CodeGenerator<'a> {
body body
} }
fn mark_unsafe_fact_vars(fact: &mut CompiledFact, bindings: &HashMap<&Var, VarReg>)
{
let mut unsafe_vars = HashMap::new();
for var_reg in bindings.values() {
unsafe_vars.insert(var_reg.norm(), false);
}
for fact_instr in fact.iter_mut() {
match fact_instr {
&mut FactInstruction::UnifyValue(reg) =>
if let Some(found) = unsafe_vars.get_mut(&reg) {
if !*found {
*found = true;
*fact_instr = FactInstruction::UnifyLocalValue(reg);
}
},
&mut FactInstruction::UnifyVariable(reg) => {
if let Some(found) = unsafe_vars.get_mut(&reg) {
*found = true;
}
},
_ => {}
};
}
}
pub fn compile_fact(&mut self, term: &'a Term) -> Code { pub fn compile_fact(&mut self, term: &'a Term) -> Code {
self.marker.advance(term); self.marker.advance(term);
self.update_var_count(term.breadth_first_iter());
let mut compiled_fact = vec![Line::Fact(self.compile_target(term, false))]; let mut compiled_fact = self.compile_target(term, false);
Self::mark_unsafe_fact_vars(&mut compiled_fact, self.vars());
let mut compiled_fact = vec![Line::Fact(compiled_fact)];
let proceed = Line::Control(ControlInstruction::Proceed); let proceed = Line::Control(ControlInstruction::Proceed);
compiled_fact.push(proceed); compiled_fact.push(proceed);
compiled_fact compiled_fact
} }
fn compile_internal_query(&mut self, term: &'a Term, index: usize) -> Code { fn compile_internal_query(&mut self, term: &'a Term, index: usize) -> Code
{
self.marker.advance(term); self.marker.advance(term);
self.update_var_count(term.breadth_first_iter());
let mut compiled_query = vec![Line::Query(self.compile_target(term, false))]; let mut compiled_query = vec![Line::Query(self.compile_target(term, false))];
Self::add_conditional_call(&mut compiled_query, term, index); Self::add_conditional_call(&mut compiled_query, term, index);
@@ -627,9 +731,10 @@ impl<'a> CodeGenerator<'a> {
pub fn compile_query(&mut self, term: &'a Term) -> Code { pub fn compile_query(&mut self, term: &'a Term) -> Code {
self.marker.advance(term); self.marker.advance(term);
self.update_var_count(term.breadth_first_iter());
let mut compiled_query = vec![Line::Query(self.compile_target(term, true))]; let mut compiled_query = vec![Line::Query(self.compile_target(term, true))];
Self::add_conditional_call(&mut compiled_query, term, 1); Self::add_conditional_call(&mut compiled_query, term, 0);
compiled_query compiled_query
} }

View File

@@ -44,6 +44,8 @@ impl fmt::Display for FactInstruction {
write!(f, "unify_constant {}", constant), write!(f, "unify_constant {}", constant),
&FactInstruction::UnifyVariable(ref r) => &FactInstruction::UnifyVariable(ref r) =>
write!(f, "unify_variable {}", r), write!(f, "unify_variable {}", r),
&FactInstruction::UnifyLocalValue(ref r) =>
write!(f, "unify_local_value {}", r),
&FactInstruction::UnifyValue(ref r) => &FactInstruction::UnifyValue(ref r) =>
write!(f, "unify_value {}", r), write!(f, "unify_value {}", r),
&FactInstruction::UnifyVoid(n) => &FactInstruction::UnifyVoid(n) =>
@@ -67,12 +69,16 @@ impl fmt::Display for QueryInstruction {
write!(f, "put_structure {}/{}, {}", name, arity, r), write!(f, "put_structure {}/{}, {}", name, arity, r),
&QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) => &QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()), write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()),
&QueryInstruction::PutUnsafeValue(y, a) =>
write!(f, "put_unsafe_value Y{}, A{}", y, a),
&QueryInstruction::PutValue(ref x, ref a) => &QueryInstruction::PutValue(ref x, ref a) =>
write!(f, "put_value {}, A{}", x, a), write!(f, "put_value {}, A{}", x, a),
&QueryInstruction::PutVariable(ref x, ref a) => &QueryInstruction::PutVariable(ref x, ref a) =>
write!(f, "put_variable {}, A{}", x, a), write!(f, "put_variable {}, A{}", x, a),
&QueryInstruction::SetConstant(ref constant) => &QueryInstruction::SetConstant(ref constant) =>
write!(f, "set_constant {}", constant), write!(f, "set_constant {}", constant),
&QueryInstruction::SetLocalValue(ref r) =>
write!(f, "set_local_value {}", r),
&QueryInstruction::SetVariable(ref r) => &QueryInstruction::SetVariable(ref r) =>
write!(f, "set_variable {}", r), write!(f, "set_variable {}", r),
&QueryInstruction::SetValue(ref r) => &QueryInstruction::SetValue(ref r) =>
@@ -213,6 +219,7 @@ pub fn eval(wam: &mut Machine, buffer: &str) -> EvalResult
&Ok(TopLevel::Predicate(ref clauses)) => { &Ok(TopLevel::Predicate(ref clauses)) => {
if is_consistent(clauses) { if is_consistent(clauses) {
let compiled_pred = cg.compile_predicate(clauses); let compiled_pred = cg.compile_predicate(clauses);
print_code(&compiled_pred);
wam.add_predicate(clauses, compiled_pred); wam.add_predicate(clauses, compiled_pred);
EvalResult::EntrySuccess EvalResult::EntrySuccess
@@ -226,16 +233,18 @@ Each predicate must have the same name and arity.";
}, },
&Ok(TopLevel::Fact(ref fact)) => { &Ok(TopLevel::Fact(ref fact)) => {
let compiled_fact = cg.compile_fact(&fact); let compiled_fact = cg.compile_fact(&fact);
print_code(&compiled_fact);
wam.add_fact(fact, compiled_fact); wam.add_fact(fact, compiled_fact);
EvalResult::EntrySuccess EvalResult::EntrySuccess
}, },
&Ok(TopLevel::Rule(ref rule)) => { &Ok(TopLevel::Rule(ref rule)) => {
let compiled_rule = cg.compile_rule(&rule); let compiled_rule = cg.compile_rule(&rule);
print_code(&compiled_rule);
wam.add_rule(rule, compiled_rule); wam.add_rule(rule, compiled_rule);
EvalResult::EntrySuccess EvalResult::EntrySuccess
}, },
&Ok(TopLevel::Query(ref query)) => { &Ok(TopLevel::Query(ref query)) => {
let compiled_query = cg.compile_query(&query); let compiled_query = cg.compile_query(&query);
wam.run_query(compiled_query, &cg) wam.run_query(compiled_query, &cg)
}, },
&Err(_) => { &Err(_) => {

View File

@@ -463,6 +463,7 @@ impl MachineState {
_ => self.fail = true _ => self.fail = true
}; };
}, },
&FactInstruction::GetList(_, reg) => { &FactInstruction::GetList(_, reg) => {
let addr = self.deref(self[reg].clone()); let addr = self.deref(self[reg].clone());
@@ -536,10 +537,14 @@ impl MachineState {
let addr = self.deref(Addr::HeapCell(self.s)); let addr = self.deref(Addr::HeapCell(self.s));
match self.store(addr) { match self.store(addr) {
Addr::HeapCell(hc) => Addr::HeapCell(hc) => {
self.heap[hc] = HeapCellValue::Con(c.clone()), self.heap[hc] = HeapCellValue::Con(c.clone());
Addr::StackCell(fr, sc) => self.trail(Ref::HeapCell(hc));
self.and_stack[fr][sc] = Addr::Con(c.clone()), },
Addr::StackCell(fr, sc) => {
self.and_stack[fr][sc] = Addr::Con(c.clone());
self.trail(Ref::StackCell(fr, sc));
},
Addr::Con(c1) => { Addr::Con(c1) => {
if c1 != *c { if c1 != *c {
self.fail = true; self.fail = true;
@@ -569,6 +574,39 @@ impl MachineState {
self.s += 1; self.s += 1;
}, },
&FactInstruction::UnifyLocalValue(reg) => {
let s = self.s;
match self.mode {
MachineMode::Read => {
let reg_addr = self[reg].clone();
self.unify(reg_addr, Addr::HeapCell(s));
},
MachineMode::Write => {
let addr = self.deref(self[reg].clone());
let h = self.h;
if let Addr::HeapCell(hc) = addr {
if hc < h {
let val = self.heap[hc].clone();
self.heap.push(val);
self.h += 1;
self.s += 1;
return;
}
}
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h)));
self.bind(Ref::HeapCell(h), addr);
self.h += 1;
}
};
self.s += 1;
},
&FactInstruction::UnifyValue(reg) => { &FactInstruction::UnifyValue(reg) => {
let s = self.s; let s = self.s;
@@ -615,21 +653,63 @@ impl MachineState {
self[reg] = Addr::Str(self.h); self[reg] = Addr::Str(self.h);
self.h += 1; self.h += 1;
}, },
&QueryInstruction::PutUnsafeValue(n, arg) => {
let e = self.e;
let addr = self.deref(Addr::StackCell(e, n));
if addr.is_protected(e) {
self.registers[arg] = self.store(addr);
} else {
let h = self.h;
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h)));
self.bind(Ref::HeapCell(h), addr);
self.registers[arg] = self.heap[h].as_addr(h);
self.h += 1;
}
},
&QueryInstruction::PutValue(norm, arg) => &QueryInstruction::PutValue(norm, arg) =>
self.registers[arg] = self[norm].clone(), self.registers[arg] = self[norm].clone(),
&QueryInstruction::PutVariable(norm, arg) => { &QueryInstruction::PutVariable(norm, arg) => {
let h = self.h; match norm {
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h))); RegType::Perm(n) => {
let e = self.e;
self[norm] = Addr::StackCell(e, n);
self.registers[arg] = self[norm].clone();
},
RegType::Temp(_) => {
let h = self.h;
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h)));
self[norm] = Addr::HeapCell(h); self[norm] = Addr::HeapCell(h);
self.registers[arg] = Addr::HeapCell(h); self.registers[arg] = Addr::HeapCell(h);
self.h += 1; self.h += 1;
}
};
}, },
&QueryInstruction::SetConstant(ref constant) => { &QueryInstruction::SetConstant(ref constant) => {
self.heap.push(HeapCellValue::Con(constant.clone())); self.heap.push(HeapCellValue::Con(constant.clone()));
self.h += 1; self.h += 1;
}, },
&QueryInstruction::SetLocalValue(reg) => {
let addr = self.deref(self[reg].clone());
let h = self.h;
if let Addr::HeapCell(hc) = addr {
if hc < h {
self.heap.push(HeapCellValue::from(addr));
self.h += 1;
return;
}
}
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h)));
self.bind(Ref::HeapCell(h), addr);
self.h += 1;
},
&QueryInstruction::SetVariable(reg) => { &QueryInstruction::SetVariable(reg) => {
let h = self.h; let h = self.h;
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h))); self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h)));
@@ -681,7 +761,7 @@ impl MachineState {
}, },
&ControlInstruction::Deallocate => { &ControlInstruction::Deallocate => {
let e = self.e; let e = self.e;
self.cp = self.and_stack[e].cp; self.cp = self.and_stack[e].cp;
self.e = self.and_stack[e].e; self.e = self.and_stack[e].e;