fix arithmetic bugs.

This commit is contained in:
Mark Thom
2017-11-06 22:01:54 -07:00
parent 4624508fc1
commit 41d99938e7
6 changed files with 161 additions and 175 deletions

View File

@@ -1,5 +1,7 @@
use prolog::ast::*; use prolog::ast::*;
use prolog::fixtures::*; use prolog::fixtures::*;
use prolog::num::{BigInt, Zero};
use prolog::ordered_float::{OrderedFloat};
use std::cell::Cell; use std::cell::Cell;
use std::cmp::{min, max}; use std::cmp::{min, max};
@@ -93,7 +95,7 @@ impl<'a> ArithmeticEvaluator<'a> {
ArithmeticEvaluator { bindings, interm: Vec::new(), interm_c: 1 } ArithmeticEvaluator { bindings, interm: Vec::new(), interm_c: 1 }
} }
fn get_un_instr(name: &Atom, a1: ArithmeticTerm, t: ArithEvalPlace) fn get_un_instr(name: &Atom, a1: ArithmeticTerm, t: usize)
-> Result<ArithmeticInstruction, ArithmeticError> -> Result<ArithmeticInstruction, ArithmeticError>
{ {
match name.as_str() { match name.as_str() {
@@ -102,7 +104,7 @@ impl<'a> ArithmeticEvaluator<'a> {
} }
} }
fn gen_bin_instr(name: &Atom, a1: ArithmeticTerm, a2: ArithmeticTerm, t: ArithEvalPlace) fn gen_bin_instr(name: &Atom, a1: ArithmeticTerm, a2: ArithmeticTerm, t: usize)
-> Result<ArithmeticInstruction, ArithmeticError> -> Result<ArithmeticInstruction, ArithmeticError>
{ {
match name.as_str() { match name.as_str() {
@@ -124,53 +126,45 @@ impl<'a> ArithmeticEvaluator<'a> {
temp temp
} }
fn instr_from_clause(&mut self, name: &Atom, terms: &Vec<Box<Term>>, deep: bool) fn instr_from_clause(&mut self, name: &Atom, terms: &Vec<Box<Term>>)
-> Result<ArithmeticInstruction, ArithmeticError> -> Result<ArithmeticInstruction, ArithmeticError>
{ {
match terms.len() { match terms.len() {
1 => { 1 => {
let a1 = self.interm.pop().unwrap(); let a1 = self.interm.pop().unwrap();
if deep { let ninterm = if a1.interm_or(0) == 0 {
let ninterm = if a1.interm_or(0) == 0 { self.incr_interm()
self.incr_interm()
} else {
self.interm.push(a1.clone());
a1.interm_or(0)
};
Self::get_un_instr(name, a1, ArithEvalPlace::Interm(ninterm))
} else { } else {
Self::get_un_instr(name, a1, ArithEvalPlace::Reg(RegType::Temp(2))) self.interm.push(a1.clone());
} a1.interm_or(0)
};
Self::get_un_instr(name, a1, ninterm)
}, },
2 => { 2 => {
let a2 = self.interm.pop().unwrap(); let a2 = self.interm.pop().unwrap();
let a1 = self.interm.pop().unwrap(); let a1 = self.interm.pop().unwrap();
if deep { let min_interm = min(a1.interm_or(0), a2.interm_or(0));
let min_interm = min(a1.interm_or(0), a2.interm_or(0));
let ninterm = if min_interm == 0 { let ninterm = if min_interm == 0 {
let max_interm = max(a1.interm_or(0), a2.interm_or(0)); let max_interm = max(a1.interm_or(0), a2.interm_or(0));
if max_interm == 0 { if max_interm == 0 {
self.incr_interm() self.incr_interm()
} else {
self.interm.push(ArithmeticTerm::Interm(max_interm));
self.interm_c = max_interm + 1;
max_interm
}
} else { } else {
self.interm.push(ArithmeticTerm::Interm(min_interm)); self.interm.push(ArithmeticTerm::Interm(max_interm));
self.interm_c = min_interm + 1; self.interm_c = max_interm + 1;
min_interm max_interm
}; }
Self::gen_bin_instr(name, a1, a2, ArithEvalPlace::Interm(ninterm))
} else { } else {
Self::gen_bin_instr(name, a1, a2, ArithEvalPlace::Reg(RegType::Temp(2))) self.interm.push(ArithmeticTerm::Interm(min_interm));
} self.interm_c = min_interm + 1;
min_interm
};
Self::gen_bin_instr(name, a1, a2, ninterm)
}, },
_ => Err(ArithmeticError::InvalidOp) _ => Err(ArithmeticError::InvalidOp)
} }
@@ -200,7 +194,7 @@ impl<'a> ArithmeticEvaluator<'a> {
let r = if vr.get().norm().reg_num() == 0 { let r = if vr.get().norm().reg_num() == 0 {
match self.bindings.get(name) { match self.bindings.get(name) {
Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t), Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
Some(&VarData::Perm(p)) => RegType::Perm(p), Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p),
_ => return Err(ArithmeticError::UninstantiatedVar) _ => return Err(ArithmeticError::UninstantiatedVar)
} }
} else { } else {
@@ -210,11 +204,11 @@ impl<'a> ArithmeticEvaluator<'a> {
self.interm.push(ArithmeticTerm::Reg(r)); self.interm.push(ArithmeticTerm::Reg(r));
}, },
TermRef::Clause(ClauseType::Deep(_, _, name), terms) => { TermRef::Clause(ClauseType::Deep(_, _, name), terms) => {
code.push(Line::Arithmetic(self.instr_from_clause(name, terms, true)?)); code.push(Line::Arithmetic(self.instr_from_clause(name, terms)?));
}, },
TermRef::Clause(ClauseType::Root, terms) => { TermRef::Clause(ClauseType::Root, terms) => {
let name = term.name().unwrap(); let name = term.name().unwrap();
code.push(Line::Arithmetic(self.instr_from_clause(name, terms, false)?)); code.push(Line::Arithmetic(self.instr_from_clause(name, terms)?));
}, },
_ => _ =>
return Err(ArithmeticError::InvalidTerm) return Err(ArithmeticError::InvalidTerm)
@@ -223,20 +217,22 @@ impl<'a> ArithmeticEvaluator<'a> {
if let Some(arith_term) = self.interm.pop() { if let Some(arith_term) = self.interm.pop() {
match arith_term { match arith_term {
ArithmeticTerm::Integer(n) => { n @ ArithmeticTerm::Integer(_) => {
let n = Constant::Integer(n); let zero = ArithmeticTerm::Integer(BigInt::zero());
code.push(query![put_constant!(Level::Shallow, n, temp_v!(2))]); code.push(arith![add!(zero, n, 1)]);
}, },
ArithmeticTerm::Float(n) => { n @ ArithmeticTerm::Float(_) => {
let n = Constant::Float(n); let zero = ArithmeticTerm::Float(OrderedFloat(0f64));
code.push(query![put_constant!(Level::Shallow, n, temp_v!(2))]); code.push(arith![add!(zero, n, 1)]);
}, },
ArithmeticTerm::Reg(r) => r @ ArithmeticTerm::Reg(_) => {
code.push(query![put_value!(r, 2)]), let zero = ArithmeticTerm::Integer(BigInt::zero());
_ => return Err(ArithmeticError::InvalidTerm) code.push(arith![add!(zero, r, 1)]);
},
_ => {}
}; };
} }
Ok(code) Ok(code)
} }
} }

View File

@@ -556,17 +556,12 @@ impl ArithmeticTerm {
} }
} }
#[derive(Clone, Copy)]
pub enum ArithEvalPlace {
Interm(usize), Reg(RegType)
}
pub enum ArithmeticInstruction { pub enum ArithmeticInstruction {
Add(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace), Add(ArithmeticTerm, ArithmeticTerm, usize),
Sub(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace), Sub(ArithmeticTerm, ArithmeticTerm, usize),
Mul(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace), Mul(ArithmeticTerm, ArithmeticTerm, usize),
IDiv(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace), IDiv(ArithmeticTerm, ArithmeticTerm, usize),
Neg(ArithmeticTerm, ArithEvalPlace) Neg(ArithmeticTerm, usize)
} }
pub enum BuiltInInstruction { pub enum BuiltInInstruction {
@@ -588,20 +583,20 @@ pub enum BuiltInInstruction {
} }
pub enum ControlInstruction { pub enum ControlInstruction {
Allocate(usize), Allocate(usize), // num_frames.
Call(Atom, usize, usize), Call(Atom, usize, usize), // name, arity, perm_vars after threshold.
CallN(usize), CallN(usize), // arity.
CatchCall, CatchCall,
CatchExecute, CatchExecute,
Deallocate, Deallocate,
Execute(Atom, usize), Execute(Atom, usize),
ExecuteN(usize), ExecuteN(usize),
Goto(usize, usize), // p, arity. Goto(usize, usize), // p, arity.
IsCall(RegType),
IsExecute(RegType),
Proceed, Proceed,
ThrowCall, ThrowCall,
ThrowExecute, ThrowExecute,
UnifyCall,
UnifyExecute
} }
impl ControlInstruction { impl ControlInstruction {
@@ -617,8 +612,8 @@ impl ControlInstruction {
&ControlInstruction::ThrowExecute => true, &ControlInstruction::ThrowExecute => true,
&ControlInstruction::Goto(_, _) => true, &ControlInstruction::Goto(_, _) => true,
&ControlInstruction::Proceed => true, &ControlInstruction::Proceed => true,
&ControlInstruction::UnifyCall => true, &ControlInstruction::IsCall(_) => true,
&ControlInstruction::UnifyExecute => true, &ControlInstruction::IsExecute(_) => true,
_ => false _ => false
} }
} }

View File

@@ -7,6 +7,7 @@ use prolog::iterators::*;
use prolog::targets::*; use prolog::targets::*;
use std::collections::HashMap; use std::collections::HashMap;
use std::mem::swap;
use std::vec::Vec; use std::vec::Vec;
pub struct CodeGenerator<'a, TermMarker> { pub struct CodeGenerator<'a, TermMarker> {
@@ -218,9 +219,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
}, },
QueryTermRef::Catch(_) => QueryTermRef::Catch(_) =>
compiled_query.push(Line::Control(ControlInstruction::CatchCall)), compiled_query.push(Line::Control(ControlInstruction::CatchCall)),
QueryTermRef::IsAtomic(_) => QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) =>
compiled_query.push(proceed!()),
QueryTermRef::IsVar(_) =>
compiled_query.push(proceed!()), compiled_query.push(proceed!()),
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);
@@ -236,41 +235,29 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
} }
} }
fn lco(code: &mut Code, toc: QueryTermRef<'a>) -> usize fn lco(code: &mut Code) -> usize
{ {
let last_arity = toc.arity();
let mut dealloc_index = code.len() - 1; let mut dealloc_index = code.len() - 1;
match toc { if let Some(&mut Line::Control(ref mut ctrl)) = code.last_mut() {
QueryTermRef::Term(&Term::Clause(_, ref name, _)) let mut instr = ControlInstruction::Proceed;
| QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref name))) => swap(ctrl, &mut instr);
if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() {
*ctrl = ControlInstruction::Execute(name.clone(), last_arity); match instr {
}, ControlInstruction::Call(name, arity, _) =>
QueryTermRef::CallN(terms) => *ctrl = ControlInstruction::Execute(name, arity),
if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() { ControlInstruction::CallN(arity) =>
*ctrl = ControlInstruction::ExecuteN(terms.len()); *ctrl = ControlInstruction::ExecuteN(arity),
}, ControlInstruction::IsCall(r) =>
QueryTermRef::Catch(_) => *ctrl = ControlInstruction::IsExecute(r),
if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() { ControlInstruction::CatchCall =>
*ctrl = ControlInstruction::CatchExecute; *ctrl = ControlInstruction::CatchExecute,
}, ControlInstruction::ThrowCall =>
QueryTermRef::Cut => {}, *ctrl = ControlInstruction::ThrowExecute,
QueryTermRef::Throw(_) => _ => dealloc_index += 1 // = code.len()
if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() { }
*ctrl = ControlInstruction::ThrowExecute; }
},
QueryTermRef::Is(_) =>
if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() {
*ctrl = ControlInstruction::UnifyExecute;
},
QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) => {
dealloc_index = code.len();
code.push(proceed!());
},
_ => dealloc_index = code.len()
};
dealloc_index dealloc_index
} }
@@ -310,31 +297,39 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings()); let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings());
evaluator.eval(terms[1].as_ref())? evaluator.eval(terms[1].as_ref())?
}; };
code.append(&mut arith_code); code.append(&mut arith_code);
match terms[0].as_ref() { match terms[0].as_ref() {
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) =>
let mut target = Vec::new(); match self.marker.bindings().get(name) {
Some(&VarData::Temp(_, t, _)) if t != 0 =>
code.push(is_call!(temp_v!(t))),
Some(&VarData::Perm(p)) if p != 0 =>
code.push(is_call!(perm_v!(p))),
_ => {
let mut target = Vec::new();
self.marker.advance(term_loc, *term); // reset self.marker.arg_c to 1.
self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target); self.marker.advance(term_loc, *term);
self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
code.push(Line::Query(target)); code.push(Line::Query(target));
code.push(unify_call!()); code.push(is_call!(vr.get().norm()));
}, }
},
&Term::Constant(_, Constant::Float(fl)) => { &Term::Constant(_, Constant::Float(fl)) => {
code.push(query![put_constant!(Level::Shallow, code.push(query![put_constant!(Level::Shallow,
Constant::Float(fl), Constant::Float(fl),
temp_v!(1))]); temp_v!(1))]);
code.push(unify_call!()); code.push(is_call!(temp_v!(1)));
}, },
&Term::Constant(_, Constant::Integer(ref bi)) => { &Term::Constant(_, Constant::Integer(ref bi)) => {
let bi = bi.clone(); let bi = bi.clone();
code.push(query![put_constant!(Level::Shallow, code.push(query![put_constant!(Level::Shallow,
Constant::Integer(bi), Constant::Integer(bi),
temp_v!(1))]); temp_v!(1))]);
code.push(unify_call!()); code.push(is_call!(temp_v!(1)));
}, },
_ => { _ => {
return Err(ParserError::from(ArithmeticError::InvalidTerm)); return Err(ParserError::from(ArithmeticError::InvalidTerm));
@@ -357,9 +352,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
code.push(is_atomic!(RegType::Perm(p))), code.push(is_atomic!(RegType::Perm(p))),
_ => { _ => {
let mut target = Vec::new(); let mut target = Vec::new();
// reset self.marker.arg_c to 1. // reset self.marker.arg_c to 1.
self.marker.advance(term_loc, *term); self.marker.advance(term_loc, *term);
self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target); self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
code.push(Line::Query(target)); code.push(Line::Query(target));
@@ -383,9 +378,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
code.push(is_var!(RegType::Perm(p))), code.push(is_var!(RegType::Perm(p))),
_ => { _ => {
let mut target = Vec::new(); let mut target = Vec::new();
// reset self.marker.arg_c to 1. // reset self.marker.arg_c to 1.
self.marker.advance(term_loc, *term); self.marker.advance(term_loc, *term);
self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target); self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
code.push(Line::Query(target)); code.push(Line::Query(target));
@@ -419,19 +414,26 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
let perm_vars = conjunct_info.perm_vars(); let perm_vars = conjunct_info.perm_vars();
body.push(Line::Control(ControlInstruction::Allocate(perm_vars))); body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
if conjunct_info.has_deep_cut { if conjunct_info.has_deep_cut {
body.push(Line::Cut(CutInstruction::GetLevel)); body.push(Line::Cut(CutInstruction::GetLevel));
} }
} }
} }
fn compile_cleanup(body: &mut Code, conjunct_info: &ConjunctInfo, toc: QueryTermRef<'a>) fn compile_cleanup(code: &mut Code, conjunct_info: &ConjunctInfo, toc: QueryTermRef<'a>)
{ {
let dealloc_index = Self::lco(body, toc); //TODO: temporary workaround for inlined builtins.
match toc {
QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) =>
code.push(proceed!()),
_ => {}
}
let dealloc_index = Self::lco(code);
if conjunct_info.allocates() { if conjunct_info.allocates() {
body.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate)); code.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
} }
} }

View File

@@ -107,10 +107,10 @@ impl fmt::Display for ControlInstruction {
write!(f, "call_throw"), write!(f, "call_throw"),
&ControlInstruction::ThrowExecute => &ControlInstruction::ThrowExecute =>
write!(f, "execute_throw"), write!(f, "execute_throw"),
&ControlInstruction::UnifyCall => &ControlInstruction::IsCall(r) =>
write!(f, "unify_call"), write!(f, "is_call {}", r),
&ControlInstruction::UnifyExecute => &ControlInstruction::IsExecute(r) =>
write!(f, "unify_execute"), write!(f, "is_execute {}", r),
} }
} }
} }
@@ -203,30 +203,19 @@ impl fmt::Display for ArithmeticTerm {
} }
} }
impl fmt::Display for ArithEvalPlace {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ArithEvalPlace::Reg(r) =>
write!(f, "{}", r),
&ArithEvalPlace::Interm(i) =>
write!(f, "@{}", i)
}
}
}
impl fmt::Display for ArithmeticInstruction { impl fmt::Display for ArithmeticInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&ArithmeticInstruction::Add(ref a1, ref a2, ref t) => &ArithmeticInstruction::Add(ref a1, ref a2, ref t) =>
write!(f, "add {}, {}, {}", a1, a2, t), write!(f, "add {}, {}, @{}", a1, a2, t),
&ArithmeticInstruction::Sub(ref a1, ref a2, ref t) => &ArithmeticInstruction::Sub(ref a1, ref a2, ref t) =>
write!(f, "sub {}, {}, {}", a1, a2, t), write!(f, "sub {}, {}, @{}", a1, a2, t),
&ArithmeticInstruction::Mul(ref a1, ref a2, ref t) => &ArithmeticInstruction::Mul(ref a1, ref a2, ref t) =>
write!(f, "mul {}, {}, {}", a1, a2, t), write!(f, "mul {}, {}, @{}", a1, a2, t),
&ArithmeticInstruction::IDiv(ref a1, ref a2, ref t) => &ArithmeticInstruction::IDiv(ref a1, ref a2, ref t) =>
write!(f, "idiv {}, {}, {}", a1, a2, t), write!(f, "idiv {}, {}, @{}", a1, a2, t),
&ArithmeticInstruction::Neg(ref a, ref t) => &ArithmeticInstruction::Neg(ref a, ref t) =>
write!(f, "neg {}, {}", a, t) write!(f, "neg {}, @{}", a, t)
} }
} }
} }
@@ -343,7 +332,7 @@ pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'
Ok(pred) => pred, Ok(pred) => pred,
Err(e) => return EvalSession::ParserError(e) Err(e) => return EvalSession::ParserError(e)
}; };
wam.add_predicate(clauses, compiled_pred) wam.add_predicate(clauses, compiled_pred)
}, },
&TopLevel::Fact(ref fact) => { &TopLevel::Fact(ref fact) => {
@@ -359,7 +348,7 @@ pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'
Ok(rule) => rule, Ok(rule) => rule,
Err(e) => return EvalSession::ParserError(e) Err(e) => return EvalSession::ParserError(e)
}; };
wam.add_rule(rule, compiled_rule) wam.add_rule(rule, compiled_rule)
}, },
&TopLevel::Query(ref query) => { &TopLevel::Query(ref query) => {
@@ -369,7 +358,7 @@ pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'
Ok(query) => query, Ok(query) => query,
Err(e) => return EvalSession::ParserError(e) Err(e) => return EvalSession::ParserError(e)
}; };
wam.submit_query(compiled_query, cg.take_vars()) wam.submit_query(compiled_query, cg.take_vars())
} }
} }

View File

@@ -765,7 +765,7 @@ impl MachineState {
Ref::HeapCell(r) => Ref::HeapCell(r) =>
self.heap[r] = HeapCellValue::Ref(Ref::HeapCell(r)), self.heap[r] = HeapCellValue::Ref(Ref::HeapCell(r)),
Ref::StackCell(fr, sc) => Ref::StackCell(fr, sc) =>
self.and_stack[fr][sc] = Addr::StackCell(fr, sc) self.and_stack[fr][sc] = Addr::StackCell(fr, sc)
} }
} }
} }
@@ -848,42 +848,33 @@ impl MachineState {
Err("is/2: variable not instantiated to number.") Err("is/2: variable not instantiated to number.")
} }
}, },
&ArithmeticTerm::Interm(i) => Ok(self.interms[i].clone()), &ArithmeticTerm::Interm(i) => Ok(self.interms[i-1].clone()),
&ArithmeticTerm::Float(fl) => Ok(Number::Float(fl)), &ArithmeticTerm::Float(fl) => Ok(Number::Float(fl)),
&ArithmeticTerm::Integer(ref bi) => Ok(Number::Integer(bi.clone())) &ArithmeticTerm::Integer(ref bi) => Ok(Number::Integer(bi.clone()))
} }
} }
fn assign_arith(&mut self, t: ArithEvalPlace, n: Number) {
match t {
ArithEvalPlace::Reg(r) =>
self[r] = Addr::Con(Constant::from(n)),
ArithEvalPlace::Interm(i) =>
self.interms[i] = n
}
}
fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) { fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) {
match instr { match instr {
&ArithmeticInstruction::Add(ref a1, ref a2, t) => { &ArithmeticInstruction::Add(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1)); let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2)); let n2 = try_or_fail!(self, self.get_number(a2));
self.assign_arith(t, n1 + n2); self.interms[t - 1] = n1 + n2;
self.p += 1; self.p += 1;
}, },
&ArithmeticInstruction::Sub(ref a1, ref a2, t) => { &ArithmeticInstruction::Sub(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1)); let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2)); let n2 = try_or_fail!(self, self.get_number(a2));
self.assign_arith(t, n1 - n2); self.interms[t - 1] = n1 - n2;
self.p += 1; self.p += 1;
}, },
&ArithmeticInstruction::Mul(ref a1, ref a2, t) => { &ArithmeticInstruction::Mul(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1)); let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2)); let n2 = try_or_fail!(self, self.get_number(a2));
self.assign_arith(t, n1 * n2); self.interms[t - 1] = n1 * n2;
self.p += 1; self.p += 1;
}, },
&ArithmeticInstruction::IDiv(ref a1, ref a2, t) => { &ArithmeticInstruction::IDiv(ref a1, ref a2, t) => {
@@ -899,7 +890,7 @@ impl MachineState {
return; return;
} }
self.assign_arith(t, Number::Integer(n1 / n2)); self.interms[t - 1] = Number::Integer(n1 / n2);
self.p += 1; self.p += 1;
}, },
_ => { _ => {
@@ -913,7 +904,7 @@ impl MachineState {
&ArithmeticInstruction::Neg(ref a1, t) => { &ArithmeticInstruction::Neg(ref a1, t) => {
let n1 = try_or_fail!(self, self.get_number(a1)); let n1 = try_or_fail!(self, self.get_number(a1));
self.assign_arith(t, - n1); self.interms[t - 1] = - n1;
self.p += 1; self.p += 1;
} }
}; };
@@ -1492,8 +1483,7 @@ impl MachineState {
let d = self.deref(self[r].clone()); let d = self.deref(self[r].clone());
match d { match d {
Addr::HeapCell(_) | Addr::StackCell(_,_) => Addr::HeapCell(_) | Addr::StackCell(_,_) => self.p += 1,
self.p += 1,
_ => self.fail = true _ => self.fail = true
}; };
}, },
@@ -1507,23 +1497,19 @@ impl MachineState {
self.p += 1; self.p += 1;
}, },
&BuiltInInstruction::Unify => { &BuiltInInstruction::Unify => {
self.inline_unify(); let a1 = self[temp_v!(1)].clone();
let a2 = self[temp_v!(2)].clone();
self.unify(a1, a2);
self.p += 1; self.p += 1;
} }
}; };
} }
fn inline_unify(&mut self) {
let a1 = self[temp_v!(1)].clone();
let a2 = self[temp_v!(2)].clone();
self.unify(a1, a2);
}
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction) fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
{ {
match instr { match instr {
&ControlInstruction::Allocate(num_cells) => { &ControlInstruction::Allocate(num_cells) => {
let num_frames = self.num_frames(); let num_frames = self.num_frames();
self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells); self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells);
@@ -1575,14 +1561,20 @@ impl MachineState {
&ControlInstruction::ThrowExecute => { &ControlInstruction::ThrowExecute => {
self.goto_throw(); self.goto_throw();
}, },
&ControlInstruction::UnifyCall => { &ControlInstruction::IsCall(r) => {
self.inline_unify(); let a1 = self[r].clone();
let a2 = Addr::Con(Constant::from(self.interms[0].clone()));
self.unify(a1, a2);
self.p += 1; self.p += 1;
}, },
&ControlInstruction::UnifyExecute => { &ControlInstruction::IsExecute(r) => {
self.inline_unify(); let a1 = self[r].clone();
let a2 = Addr::Con(Constant::from(self.interms[0].clone()));
self.unify(a1, a2);
self.p = self.cp; self.p = self.cp;
} }
}; };
} }

View File

@@ -22,6 +22,12 @@ macro_rules! query {
) )
} }
macro_rules! arith {
($x:expr) => (
Line::Arithmetic($x)
)
}
macro_rules! string { macro_rules! string {
($str:expr) => { ($str:expr) => {
vec![HeapCellValue::Con(Constant::String(String::from($str)))] vec![HeapCellValue::Con(Constant::String(String::from($str)))]
@@ -105,6 +111,12 @@ macro_rules! put_unsafe_value {
) )
} }
macro_rules! add {
($r1:expr, $r2:expr, $t:expr) => (
ArithmeticInstruction::Add($r1, $r2, $t)
)
}
macro_rules! try_me_else { macro_rules! try_me_else {
($o:expr) => ( ($o:expr) => (
Line::Choice(ChoiceInstruction::TryMeElse($o)) Line::Choice(ChoiceInstruction::TryMeElse($o))
@@ -209,9 +221,9 @@ macro_rules! unify {
) )
} }
macro_rules! unify_call { macro_rules! is_call {
() => ( ($r:expr) => (
Line::Control(ControlInstruction::UnifyCall) Line::Control(ControlInstruction::IsCall($r))
) )
} }