optimized up to section 5.10
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1,6 +1,6 @@
|
||||
[root]
|
||||
name = "rusty-wam"
|
||||
version = "0.5.7"
|
||||
version = "0.5.10"
|
||||
dependencies = [
|
||||
"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)",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rusty-wam"
|
||||
version = "0.5.7"
|
||||
version = "0.5.10"
|
||||
authors = ["Mark Thom"]
|
||||
|
||||
build = "build.rs"
|
||||
|
||||
@@ -11,8 +11,8 @@ pure 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
|
||||
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
|
||||
only two data types currently supported.
|
||||
end of section 5.9, skipping past 5.4. Atoms and lists are the only
|
||||
two data types currently supported.
|
||||
|
||||
While proper environment trimming code is emitted by the code
|
||||
generator, it has no effect on the bytecode WAM, which lacks
|
||||
@@ -21,7 +21,7 @@ frames.
|
||||
|
||||
## Tutorial
|
||||
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,
|
||||
```
|
||||
|
||||
19
src/main.rs
19
src/main.rs
@@ -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(Z, Y, X).").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]
|
||||
@@ -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, Y, X).").failed_query(), false);
|
||||
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]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::cell::Cell;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::{Add, AddAssign};
|
||||
use std::vec::Vec;
|
||||
@@ -40,7 +41,7 @@ pub enum Level {
|
||||
Deep, Shallow
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum RegType {
|
||||
Perm(usize),
|
||||
Temp(usize)
|
||||
@@ -141,6 +142,7 @@ pub enum FactInstruction {
|
||||
GetValue(RegType, usize),
|
||||
GetVariable(RegType, usize),
|
||||
UnifyConstant(Constant),
|
||||
UnifyLocalValue(RegType),
|
||||
UnifyVariable(RegType),
|
||||
UnifyValue(RegType),
|
||||
UnifyVoid(usize)
|
||||
@@ -150,9 +152,11 @@ pub enum QueryInstruction {
|
||||
PutConstant(Level, Constant, RegType),
|
||||
PutList(Level, RegType),
|
||||
PutStructure(Level, Atom, usize, RegType),
|
||||
PutUnsafeValue(usize, usize),
|
||||
PutValue(RegType, usize),
|
||||
PutVariable(RegType, usize),
|
||||
SetConstant(Constant),
|
||||
SetLocalValue(RegType),
|
||||
SetVariable(RegType),
|
||||
SetValue(RegType),
|
||||
SetVoid(usize)
|
||||
@@ -196,6 +200,7 @@ impl<'a> From<&'a Line> for LineOrCodeOffset<'a> {
|
||||
|
||||
pub type Code = Vec<Line>;
|
||||
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Addr {
|
||||
Con(Constant),
|
||||
@@ -220,6 +225,13 @@ impl Addr {
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_protected(&self, e: usize) -> bool {
|
||||
match self {
|
||||
&Addr::StackCell(fr, _) if fr > e => false,
|
||||
_ => true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)]
|
||||
pub enum CodePtr {
|
||||
DirEntry(usize),
|
||||
|
||||
@@ -250,7 +250,8 @@ enum VarStatus {
|
||||
}
|
||||
|
||||
pub struct CodeGenerator<'a> {
|
||||
marker: TermMarker<'a>
|
||||
marker: TermMarker<'a>,
|
||||
var_count: HashMap<&'a Var, usize>
|
||||
}
|
||||
|
||||
type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
|
||||
@@ -258,37 +259,41 @@ type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>;
|
||||
|
||||
impl<'a> CodeGenerator<'a> {
|
||||
pub fn new() -> Self {
|
||||
CodeGenerator { marker: TermMarker::new() }
|
||||
CodeGenerator { marker: TermMarker::new(),
|
||||
var_count: HashMap::new() }
|
||||
}
|
||||
|
||||
pub fn vars(&self) -> &HashMap<&Var, VarReg> {
|
||||
&self.marker.bindings
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn count_vars(term: &Term) -> HashMap<&Var, usize> {
|
||||
fn update_var_count<Iter>(&mut self, iter: Iter)
|
||||
where Iter : Iterator<Item=TermRef<'a>>
|
||||
{
|
||||
let mut var_count = HashMap::new();
|
||||
|
||||
for term in term.breadth_first_iter() {
|
||||
if let TermRef::Var(_, _, ref var) = term {
|
||||
let entry = var_count.entry(*var).or_insert(0);
|
||||
for term in iter {
|
||||
if let TermRef::Var(_, _, var) = term {
|
||||
if self.marker.contains_var(var) {
|
||||
var_count.insert(var, 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
let entry = var_count.entry(var).or_insert(0);
|
||||
*entry += 1;
|
||||
}
|
||||
}
|
||||
|
||||
var_count
|
||||
self.var_count = var_count;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn all_singleton_vars(terms: &Vec<Box<Term>>,
|
||||
var_count: &HashMap<&Var, usize>)
|
||||
-> bool
|
||||
fn all_singleton_vars(&self, terms: &Vec<Box<Term>>) -> bool
|
||||
{
|
||||
for term in terms {
|
||||
match term.as_ref() {
|
||||
&Term::AnonVar => {},
|
||||
&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
|
||||
@@ -298,7 +303,6 @@ impl<'a> CodeGenerator<'a> {
|
||||
true
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn void_subterms<Target>(subterms: usize) -> Target
|
||||
where Target: CompilationTarget<'a>
|
||||
{
|
||||
@@ -416,7 +420,6 @@ impl<'a> CodeGenerator<'a> {
|
||||
{
|
||||
let iter = Target::iter(term);
|
||||
let mut target = Vec::new();
|
||||
let var_count = Self::count_vars(term);
|
||||
|
||||
for term in iter {
|
||||
match term {
|
||||
@@ -424,7 +427,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
target.push(self.to_structure(lvl, cell, atom, terms.len()));
|
||||
|
||||
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()));
|
||||
continue;
|
||||
}
|
||||
@@ -547,7 +550,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
|
||||
for &(term_status, _) in vs.values() {
|
||||
if let VarStatus::Permanent(i) = term_status {
|
||||
if i >= index {
|
||||
if i > index {
|
||||
var_count += 1;
|
||||
}
|
||||
}
|
||||
@@ -556,36 +559,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
var_count
|
||||
}
|
||||
|
||||
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, 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.
|
||||
fn lco(body: &mut Code, rule: &'a Rule) -> usize {
|
||||
let last_arity = rule.last_clause().arity();
|
||||
let mut dealloc_index = body.len() - 1;
|
||||
|
||||
@@ -599,6 +573,103 @@ impl<'a> CodeGenerator<'a> {
|
||||
_ => 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(®) {
|
||||
*found = true;
|
||||
},
|
||||
&mut QueryInstruction::SetValue(reg) =>
|
||||
if let Some(found) = unsafe_vars.get_mut(®) {
|
||||
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 {
|
||||
body.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
|
||||
}
|
||||
@@ -606,18 +677,51 @@ impl<'a> CodeGenerator<'a> {
|
||||
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(®) {
|
||||
if !*found {
|
||||
*found = true;
|
||||
*fact_instr = FactInstruction::UnifyLocalValue(reg);
|
||||
}
|
||||
},
|
||||
&mut FactInstruction::UnifyVariable(reg) => {
|
||||
if let Some(found) = unsafe_vars.get_mut(®) {
|
||||
*found = true;
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_fact(&mut self, term: &'a Term) -> Code {
|
||||
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);
|
||||
|
||||
compiled_fact.push(proceed);
|
||||
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.update_var_count(term.breadth_first_iter());
|
||||
|
||||
let mut compiled_query = vec![Line::Query(self.compile_target(term, false))];
|
||||
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 {
|
||||
self.marker.advance(term);
|
||||
self.update_var_count(term.breadth_first_iter());
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ impl fmt::Display for FactInstruction {
|
||||
write!(f, "unify_constant {}", constant),
|
||||
&FactInstruction::UnifyVariable(ref r) =>
|
||||
write!(f, "unify_variable {}", r),
|
||||
&FactInstruction::UnifyLocalValue(ref r) =>
|
||||
write!(f, "unify_local_value {}", r),
|
||||
&FactInstruction::UnifyValue(ref r) =>
|
||||
write!(f, "unify_value {}", r),
|
||||
&FactInstruction::UnifyVoid(n) =>
|
||||
@@ -67,12 +69,16 @@ impl fmt::Display for QueryInstruction {
|
||||
write!(f, "put_structure {}/{}, {}", name, arity, r),
|
||||
&QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
||||
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) =>
|
||||
write!(f, "put_value {}, A{}", x, a),
|
||||
&QueryInstruction::PutVariable(ref x, ref a) =>
|
||||
write!(f, "put_variable {}, A{}", x, a),
|
||||
&QueryInstruction::SetConstant(ref constant) =>
|
||||
write!(f, "set_constant {}", constant),
|
||||
&QueryInstruction::SetLocalValue(ref r) =>
|
||||
write!(f, "set_local_value {}", r),
|
||||
&QueryInstruction::SetVariable(ref r) =>
|
||||
write!(f, "set_variable {}", r),
|
||||
&QueryInstruction::SetValue(ref r) =>
|
||||
@@ -213,6 +219,7 @@ pub fn eval(wam: &mut Machine, buffer: &str) -> EvalResult
|
||||
&Ok(TopLevel::Predicate(ref clauses)) => {
|
||||
if is_consistent(clauses) {
|
||||
let compiled_pred = cg.compile_predicate(clauses);
|
||||
print_code(&compiled_pred);
|
||||
wam.add_predicate(clauses, compiled_pred);
|
||||
|
||||
EvalResult::EntrySuccess
|
||||
@@ -226,11 +233,13 @@ Each predicate must have the same name and arity.";
|
||||
},
|
||||
&Ok(TopLevel::Fact(ref fact)) => {
|
||||
let compiled_fact = cg.compile_fact(&fact);
|
||||
print_code(&compiled_fact);
|
||||
wam.add_fact(fact, compiled_fact);
|
||||
EvalResult::EntrySuccess
|
||||
},
|
||||
&Ok(TopLevel::Rule(ref rule)) => {
|
||||
let compiled_rule = cg.compile_rule(&rule);
|
||||
print_code(&compiled_rule);
|
||||
wam.add_rule(rule, compiled_rule);
|
||||
EvalResult::EntrySuccess
|
||||
},
|
||||
|
||||
@@ -463,6 +463,7 @@ impl MachineState {
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
|
||||
&FactInstruction::GetList(_, reg) => {
|
||||
let addr = self.deref(self[reg].clone());
|
||||
|
||||
@@ -536,10 +537,14 @@ impl MachineState {
|
||||
let addr = self.deref(Addr::HeapCell(self.s));
|
||||
|
||||
match self.store(addr) {
|
||||
Addr::HeapCell(hc) =>
|
||||
self.heap[hc] = HeapCellValue::Con(c.clone()),
|
||||
Addr::StackCell(fr, sc) =>
|
||||
self.and_stack[fr][sc] = Addr::Con(c.clone()),
|
||||
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;
|
||||
@@ -569,6 +574,39 @@ impl MachineState {
|
||||
|
||||
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) => {
|
||||
let s = self.s;
|
||||
|
||||
@@ -615,21 +653,63 @@ impl MachineState {
|
||||
self[reg] = Addr::Str(self.h);
|
||||
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) =>
|
||||
self.registers[arg] = self[norm].clone(),
|
||||
&QueryInstruction::PutVariable(norm, arg) => {
|
||||
let h = self.h;
|
||||
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h)));
|
||||
match norm {
|
||||
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.registers[arg] = Addr::HeapCell(h);
|
||||
self[norm] = Addr::HeapCell(h);
|
||||
self.registers[arg] = Addr::HeapCell(h);
|
||||
|
||||
self.h += 1;
|
||||
self.h += 1;
|
||||
}
|
||||
};
|
||||
},
|
||||
&QueryInstruction::SetConstant(ref constant) => {
|
||||
self.heap.push(HeapCellValue::Con(constant.clone()));
|
||||
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) => {
|
||||
let h = self.h;
|
||||
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h)));
|
||||
|
||||
Reference in New Issue
Block a user