fix arithmetic bugs.
This commit is contained in:
@@ -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,17 +217,19 @@ 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)]);
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,40 +235,28 @@ 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
|
||||||
}
|
}
|
||||||
@@ -314,27 +301,35 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
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));
|
||||||
@@ -426,12 +421,19 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,19 +1497,15 @@ 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 {
|
||||||
@@ -1575,12 +1561,18 @@ 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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user