use prolog::ast::*;
use prolog::fixtures::*;
+use prolog::num::{BigInt, Zero};
+use prolog::ordered_float::{OrderedFloat};
use std::cell::Cell;
use std::cmp::{min, max};
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>
{
match name.as_str() {
}
}
- 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>
{
match name.as_str() {
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>
{
match terms.len() {
1 => {
let a1 = self.interm.pop().unwrap();
- if deep {
- let ninterm = if a1.interm_or(0) == 0 {
- self.incr_interm()
- } else {
- self.interm.push(a1.clone());
- a1.interm_or(0)
- };
-
- Self::get_un_instr(name, a1, ArithEvalPlace::Interm(ninterm))
+ let ninterm = if a1.interm_or(0) == 0 {
+ self.incr_interm()
} 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 => {
let a2 = 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 max_interm = max(a1.interm_or(0), a2.interm_or(0));
+ let ninterm = if min_interm == 0 {
+ let max_interm = max(a1.interm_or(0), a2.interm_or(0));
- if max_interm == 0 {
- self.incr_interm()
- } else {
- self.interm.push(ArithmeticTerm::Interm(max_interm));
- self.interm_c = max_interm + 1;
- max_interm
- }
+ if max_interm == 0 {
+ self.incr_interm()
} else {
- self.interm.push(ArithmeticTerm::Interm(min_interm));
- self.interm_c = min_interm + 1;
- min_interm
- };
-
- Self::gen_bin_instr(name, a1, a2, ArithEvalPlace::Interm(ninterm))
+ self.interm.push(ArithmeticTerm::Interm(max_interm));
+ self.interm_c = max_interm + 1;
+ max_interm
+ }
} 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)
}
let r = if vr.get().norm().reg_num() == 0 {
match self.bindings.get(name) {
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)
}
} else {
self.interm.push(ArithmeticTerm::Reg(r));
},
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) => {
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)
if let Some(arith_term) = self.interm.pop() {
match arith_term {
- ArithmeticTerm::Integer(n) => {
- let n = Constant::Integer(n);
- code.push(query![put_constant!(Level::Shallow, n, temp_v!(2))]);
+ n @ ArithmeticTerm::Integer(_) => {
+ let zero = ArithmeticTerm::Integer(BigInt::zero());
+ code.push(arith![add!(zero, n, 1)]);
+ },
+ n @ ArithmeticTerm::Float(_) => {
+ let zero = ArithmeticTerm::Float(OrderedFloat(0f64));
+ code.push(arith![add!(zero, n, 1)]);
},
- ArithmeticTerm::Float(n) => {
- let n = Constant::Float(n);
- code.push(query![put_constant!(Level::Shallow, n, temp_v!(2))]);
+ r @ ArithmeticTerm::Reg(_) => {
+ let zero = ArithmeticTerm::Integer(BigInt::zero());
+ code.push(arith![add!(zero, r, 1)]);
},
- ArithmeticTerm::Reg(r) =>
- code.push(query![put_value!(r, 2)]),
- _ => return Err(ArithmeticError::InvalidTerm)
+ _ => {}
};
}
-
+
Ok(code)
}
}
}
}
-#[derive(Clone, Copy)]
-pub enum ArithEvalPlace {
- Interm(usize), Reg(RegType)
-}
-
pub enum ArithmeticInstruction {
- Add(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace),
- Sub(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace),
- Mul(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace),
- IDiv(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace),
- Neg(ArithmeticTerm, ArithEvalPlace)
+ Add(ArithmeticTerm, ArithmeticTerm, usize),
+ Sub(ArithmeticTerm, ArithmeticTerm, usize),
+ Mul(ArithmeticTerm, ArithmeticTerm, usize),
+ IDiv(ArithmeticTerm, ArithmeticTerm, usize),
+ Neg(ArithmeticTerm, usize)
}
pub enum BuiltInInstruction {
}
pub enum ControlInstruction {
- Allocate(usize),
- Call(Atom, usize, usize),
- CallN(usize),
+ Allocate(usize), // num_frames.
+ Call(Atom, usize, usize), // name, arity, perm_vars after threshold.
+ CallN(usize), // arity.
CatchCall,
CatchExecute,
Deallocate,
Execute(Atom, usize),
ExecuteN(usize),
Goto(usize, usize), // p, arity.
+ IsCall(RegType),
+ IsExecute(RegType),
Proceed,
ThrowCall,
- ThrowExecute,
- UnifyCall,
- UnifyExecute
+ ThrowExecute,
}
impl ControlInstruction {
&ControlInstruction::ThrowExecute => true,
&ControlInstruction::Goto(_, _) => true,
&ControlInstruction::Proceed => true,
- &ControlInstruction::UnifyCall => true,
- &ControlInstruction::UnifyExecute => true,
+ &ControlInstruction::IsCall(_) => true,
+ &ControlInstruction::IsExecute(_) => true,
_ => false
}
}
use prolog::targets::*;
use std::collections::HashMap;
+use std::mem::swap;
use std::vec::Vec;
pub struct CodeGenerator<'a, TermMarker> {
},
QueryTermRef::Catch(_) =>
compiled_query.push(Line::Control(ControlInstruction::CatchCall)),
- QueryTermRef::IsAtomic(_) =>
- compiled_query.push(proceed!()),
- QueryTermRef::IsVar(_) =>
+ QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) =>
compiled_query.push(proceed!()),
QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref atom))) => {
let call = ControlInstruction::Call(atom.clone(), 0, pvs);
}
}
- 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;
- match toc {
- QueryTermRef::Term(&Term::Clause(_, ref name, _))
- | QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref name))) =>
- if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() {
- *ctrl = ControlInstruction::Execute(name.clone(), last_arity);
- },
- QueryTermRef::CallN(terms) =>
- if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() {
- *ctrl = ControlInstruction::ExecuteN(terms.len());
- },
- QueryTermRef::Catch(_) =>
- if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() {
- *ctrl = ControlInstruction::CatchExecute;
- },
- QueryTermRef::Cut => {},
- QueryTermRef::Throw(_) =>
- 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()
- };
-
+ if let Some(&mut Line::Control(ref mut ctrl)) = code.last_mut() {
+ let mut instr = ControlInstruction::Proceed;
+ swap(ctrl, &mut instr);
+
+ match instr {
+ ControlInstruction::Call(name, arity, _) =>
+ *ctrl = ControlInstruction::Execute(name, arity),
+ ControlInstruction::CallN(arity) =>
+ *ctrl = ControlInstruction::ExecuteN(arity),
+ ControlInstruction::IsCall(r) =>
+ *ctrl = ControlInstruction::IsExecute(r),
+ ControlInstruction::CatchCall =>
+ *ctrl = ControlInstruction::CatchExecute,
+ ControlInstruction::ThrowCall =>
+ *ctrl = ControlInstruction::ThrowExecute,
+ _ => dealloc_index += 1 // = code.len()
+ }
+ }
+
dealloc_index
}
let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings());
evaluator.eval(terms[1].as_ref())?
};
-
+
code.append(&mut arith_code);
match terms[0].as_ref() {
- &Term::Var(ref vr, ref name) => {
- let mut target = Vec::new();
+ &Term::Var(ref vr, ref name) =>
+ 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);
- self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
+ // reset self.marker.arg_c to 1.
+ 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(unify_call!());
- },
+ code.push(Line::Query(target));
+ code.push(is_call!(vr.get().norm()));
+ }
+ },
&Term::Constant(_, Constant::Float(fl)) => {
code.push(query![put_constant!(Level::Shallow,
Constant::Float(fl),
temp_v!(1))]);
- code.push(unify_call!());
+ code.push(is_call!(temp_v!(1)));
},
&Term::Constant(_, Constant::Integer(ref bi)) => {
let bi = bi.clone();
code.push(query![put_constant!(Level::Shallow,
Constant::Integer(bi),
temp_v!(1))]);
- code.push(unify_call!());
+ code.push(is_call!(temp_v!(1)));
},
_ => {
return Err(ParserError::from(ArithmeticError::InvalidTerm));
code.push(is_atomic!(RegType::Perm(p))),
_ => {
let mut target = Vec::new();
-
+
// 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);
code.push(Line::Query(target));
code.push(is_var!(RegType::Perm(p))),
_ => {
let mut target = Vec::new();
-
+
// 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);
code.push(Line::Query(target));
let perm_vars = conjunct_info.perm_vars();
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
-
+
if conjunct_info.has_deep_cut {
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() {
- body.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
+ code.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
}
}
write!(f, "call_throw"),
&ControlInstruction::ThrowExecute =>
write!(f, "execute_throw"),
- &ControlInstruction::UnifyCall =>
- write!(f, "unify_call"),
- &ControlInstruction::UnifyExecute =>
- write!(f, "unify_execute"),
+ &ControlInstruction::IsCall(r) =>
+ write!(f, "is_call {}", r),
+ &ControlInstruction::IsExecute(r) =>
+ write!(f, "is_execute {}", r),
}
}
}
}
}
-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 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&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) =>
- write!(f, "sub {}, {}, {}", a1, a2, t),
+ write!(f, "sub {}, {}, @{}", a1, a2, 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) =>
- write!(f, "idiv {}, {}, {}", a1, a2, t),
+ write!(f, "idiv {}, {}, @{}", a1, a2, t),
&ArithmeticInstruction::Neg(ref a, ref t) =>
- write!(f, "neg {}, {}", a, t)
+ write!(f, "neg {}, @{}", a, t)
}
}
}
Ok(pred) => pred,
Err(e) => return EvalSession::ParserError(e)
};
-
+
wam.add_predicate(clauses, compiled_pred)
},
&TopLevel::Fact(ref fact) => {
Ok(rule) => rule,
Err(e) => return EvalSession::ParserError(e)
};
-
+
wam.add_rule(rule, compiled_rule)
},
&TopLevel::Query(ref query) => {
Ok(query) => query,
Err(e) => return EvalSession::ParserError(e)
};
-
+
wam.submit_query(compiled_query, cg.take_vars())
}
}
Ref::HeapCell(r) =>
self.heap[r] = HeapCellValue::Ref(Ref::HeapCell(r)),
Ref::StackCell(fr, sc) =>
- self.and_stack[fr][sc] = Addr::StackCell(fr, sc)
+ self.and_stack[fr][sc] = Addr::StackCell(fr, sc)
}
}
}
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::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) {
match instr {
&ArithmeticInstruction::Add(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
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;
},
&ArithmeticInstruction::Sub(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
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;
},
&ArithmeticInstruction::Mul(ref a1, ref a2, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
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;
},
&ArithmeticInstruction::IDiv(ref a1, ref a2, t) => {
return;
}
- self.assign_arith(t, Number::Integer(n1 / n2));
+ self.interms[t - 1] = Number::Integer(n1 / n2);
self.p += 1;
},
_ => {
&ArithmeticInstruction::Neg(ref a1, t) => {
let n1 = try_or_fail!(self, self.get_number(a1));
- self.assign_arith(t, - n1);
+ self.interms[t - 1] = - n1;
self.p += 1;
}
};
let d = self.deref(self[r].clone());
match d {
- Addr::HeapCell(_) | Addr::StackCell(_,_) =>
- self.p += 1,
+ Addr::HeapCell(_) | Addr::StackCell(_,_) => self.p += 1,
_ => self.fail = true
};
},
self.p += 1;
},
&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;
}
};
}
- 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)
{
match instr {
- &ControlInstruction::Allocate(num_cells) => {
+ &ControlInstruction::Allocate(num_cells) => {
let num_frames = self.num_frames();
self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells);
&ControlInstruction::ThrowExecute => {
self.goto_throw();
},
- &ControlInstruction::UnifyCall => {
- self.inline_unify();
+ &ControlInstruction::IsCall(r) => {
+ let a1 = self[r].clone();
+ let a2 = Addr::Con(Constant::from(self.interms[0].clone()));
+
+ self.unify(a1, a2);
self.p += 1;
},
- &ControlInstruction::UnifyExecute => {
- self.inline_unify();
+ &ControlInstruction::IsExecute(r) => {
+ let a1 = self[r].clone();
+ let a2 = Addr::Con(Constant::from(self.interms[0].clone()));
+
+ self.unify(a1, a2);
self.p = self.cp;
- }
+ }
};
}
)
}
+macro_rules! arith {
+ ($x:expr) => (
+ Line::Arithmetic($x)
+ )
+}
+
macro_rules! string {
($str:expr) => {
vec![HeapCellValue::Con(Constant::String(String::from($str)))]
)
}
+macro_rules! add {
+ ($r1:expr, $r2:expr, $t:expr) => (
+ ArithmeticInstruction::Add($r1, $r2, $t)
+ )
+}
+
macro_rules! try_me_else {
($o:expr) => (
Line::Choice(ChoiceInstruction::TryMeElse($o))
)
}
-macro_rules! unify_call {
- () => (
- Line::Control(ControlInstruction::UnifyCall)
+macro_rules! is_call {
+ ($r:expr) => (
+ Line::Control(ControlInstruction::IsCall($r))
)
}