From f9b53856ac36c4799de369a49adff59fdb46f602 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 19 Jan 2018 00:08:55 -0700 Subject: [PATCH] add callable `is/2` --- src/prolog/arithmetic.rs | 5 +- src/prolog/ast.rs | 5 +- src/prolog/builtins.rs | 4 +- src/prolog/heap_iter.rs | 67 +++- src/prolog/heap_print.rs | 6 +- src/prolog/io.rs | 2 + src/prolog/machine/machine_state.rs | 505 +++++++++++++++------------- src/prolog/macros.rs | 6 + 8 files changed, 353 insertions(+), 247 deletions(-) diff --git a/src/prolog/arithmetic.rs b/src/prolog/arithmetic.rs index 91451fcb..e7445828 100644 --- a/src/prolog/arithmetic.rs +++ b/src/prolog/arithmetic.rs @@ -80,13 +80,13 @@ pub struct ArithmeticEvaluator<'a> { pub trait ArithmeticTermIter<'a> { type Iter : Iterator, ArithmeticError>>; - fn iter(&self) -> Result; + fn iter(self) -> Result; } impl<'a> ArithmeticTermIter<'a> for &'a Term { type Iter = ArithInstructionIterator<'a>; - fn iter(&self) -> Result { + fn iter(self) -> Result { ArithInstructionIterator::new(self) } } @@ -223,3 +223,4 @@ impl<'a> ArithmeticEvaluator<'a> Ok((code, self.interm.pop())) } } + diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index 475792e6..1c244325 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -539,7 +539,7 @@ impl Number { } } -enum NumberPair { +pub enum NumberPair { Float(OrderedFloat, OrderedFloat), Integer(Rc, Rc), Rational(Rc>, Rc>) @@ -586,7 +586,7 @@ impl NumberPair { } } - fn from(n1: Number, n2: Number) -> NumberPair + pub fn from(n1: Number, n2: Number) -> NumberPair { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => @@ -746,6 +746,7 @@ pub enum BuiltInInstruction { InternalCallN, IsAtomic(RegType), IsInteger(RegType), + IsOnHeap, IsVar(RegType), ResetBlock, SetBall, diff --git a/src/prolog/builtins.rs b/src/prolog/builtins.rs index 0ccd6a6c..119a1184 100644 --- a/src/prolog/builtins.rs +++ b/src/prolog/builtins.rs @@ -275,6 +275,8 @@ fn get_builtins(atom_tbl: TabledData) -> Code { deallocate!(), goto!(173, 3), // goto arg_/3. display!(), // display/1, 192. + proceed!(), + is_on_heap!(), // is/2, 194. proceed!() ] } @@ -347,8 +349,8 @@ pub fn build_code_dir(atom_tbl: TabledData) -> (Code, CodeDir, OpDir) code_dir.insert((tabled_rc!("functor", atom_tbl), 3), (PredicateKeyType::BuiltIn, 146)); code_dir.insert((tabled_rc!("arg", atom_tbl), 3), (PredicateKeyType::BuiltIn, 150)); code_dir.insert((tabled_rc!("integer", atom_tbl), 1), (PredicateKeyType::BuiltIn, 147)); - code_dir.insert((tabled_rc!("display", atom_tbl), 1), (PredicateKeyType::BuiltIn, 192)); + code_dir.insert((tabled_rc!("is", atom_tbl), 2), (PredicateKeyType::BuiltIn, 194)); (builtin_code, code_dir, op_dir) } diff --git a/src/prolog/heap_iter.rs b/src/prolog/heap_iter.rs index 99f0b1cf..ae76ac6d 100644 --- a/src/prolog/heap_iter.rs +++ b/src/prolog/heap_iter.rs @@ -3,21 +3,18 @@ use prolog::machine::machine_state::MachineState; use std::vec::Vec; -pub struct HeapCellIterator<'a> { +pub struct HeapCellPreOrderIterator<'a> { machine_st : &'a MachineState, state_stack : Vec } -impl<'a> HeapCellIterator<'a> { +impl<'a> HeapCellPreOrderIterator<'a> { pub fn new(machine_st: &'a MachineState, r: Ref) -> Self { - let mut iter = HeapCellIterator { + HeapCellPreOrderIterator { machine_st, - state_stack: vec![] - }; - - iter.state_stack.push(r); - iter + state_stack: vec![r] + } } // called under the assumption that the location at r is about to @@ -64,11 +61,11 @@ impl<'a> HeapCellIterator<'a> { self.follow_heap(s); // record terms of structure. Addr::HeapCell(s) } - } + } } } -impl<'a> Iterator for HeapCellIterator<'a> { +impl<'a> Iterator for HeapCellPreOrderIterator<'a> { type Item = HeapCellValue; fn next(&mut self) -> Option { @@ -86,3 +83,53 @@ impl<'a> Iterator for HeapCellIterator<'a> { } } } + +pub struct HeapCellPostOrderIterator<'a> { + pre_iter: HeapCellPreOrderIterator<'a>, + parent_stack: Vec<(usize, HeapCellValue)> // number of children, parent node. +} + +impl<'a> HeapCellPostOrderIterator<'a> { + pub fn new(pre_iter: HeapCellPreOrderIterator<'a>) -> Self { + HeapCellPostOrderIterator { + pre_iter, + parent_stack: vec![] + } + } +} + +impl<'a> Iterator for HeapCellPostOrderIterator<'a> { + type Item = HeapCellValue; + + fn next(&mut self) -> Option { + loop { + if let Some((child_count, node)) = self.parent_stack.pop() { + if child_count == 0 { + return Some(node); + } + + self.parent_stack.push((child_count - 1, node)); + } + + if let Some(item) = self.pre_iter.next() { + match item { + HeapCellValue::NamedStr(arity, name, fix) => + self.parent_stack.push((arity, HeapCellValue::NamedStr(arity, name, fix))), + HeapCellValue::Addr(Addr::Lis(a)) => + self.parent_stack.push((2, HeapCellValue::Addr(Addr::Lis(a)))), + child_node => { + return Some(child_node); + } + } + } else { + return None; + } + } + } +} + +impl MachineState { + pub fn post_order_iter<'a>(&'a self, r: Ref) -> HeapCellPostOrderIterator<'a> { + HeapCellPostOrderIterator::new(HeapCellPreOrderIterator::new(self, r)) + } +} diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 89dc9a03..07ddbd2e 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -146,14 +146,16 @@ impl HeapCellValueFormatter for TermFormatter { pub struct HeapCellPrinter<'a, Formatter, Outputter> { formatter: Formatter, outputter: Outputter, - iter: HeapCellIterator<'a>, + iter: HeapCellPreOrderIterator<'a>, state_stack: Vec } impl<'a, Formatter: HeapCellValueFormatter, Outputter: HeapCellValueOutputter> HeapCellPrinter<'a, Formatter, Outputter> { - pub fn new(iter: HeapCellIterator<'a>, formatter: Formatter, outputter: Outputter) -> Self { + pub fn new(iter: HeapCellPreOrderIterator<'a>, formatter: Formatter, outputter: Outputter) + -> Self + { HeapCellPrinter { formatter, outputter, iter, state_stack: vec![] } } diff --git a/src/prolog/io.rs b/src/prolog/io.rs index d7e870f8..fc1f9eeb 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -185,6 +185,8 @@ impl fmt::Display for BuiltInInstruction { write!(f, "is_atomic {}", r), &BuiltInInstruction::IsInteger(r) => write!(f, "is_integer {}", r), + &BuiltInInstruction::IsOnHeap => + write!(f, "call_is A1, A2"), &BuiltInInstruction::IsVar(r) => write!(f, "is_var {}", r), &BuiltInInstruction::ResetBlock => diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 10825999..3b286b94 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -49,7 +49,7 @@ impl<'a> CopierTarget for DuplicateTerm<'a> { } fn push(&mut self, hcv: HeapCellValue) { - self.state.heap.push(hcv); + self.state.heap.push(hcv); } fn store(&self, a: Addr) -> Addr { @@ -233,7 +233,7 @@ impl MachineState { } } - pub(crate) fn deref(&self, mut a: Addr) -> Addr { + pub(crate) fn deref(&self, mut a: Addr) -> Addr { loop { let value = self.store(a.clone()); @@ -258,11 +258,11 @@ impl MachineState { self.trail(r1); } - + fn print_var(&self, r: Ref, fmt: Fmt, output: Outputter) -> Outputter where Fmt: HeapCellValueFormatter, Outputter: HeapCellValueOutputter - { - let iter = HeapCellIterator::new(&self, r); + { + let iter = HeapCellPreOrderIterator::new(&self, r); let printer = HeapCellPrinter::new(iter, fmt, output); printer.print() @@ -283,7 +283,7 @@ impl MachineState { self.print_var(Ref::StackCell(fr, sc), fmt, output) } } - + fn unify(&mut self, a1: Addr, a2: Addr) { let mut pdl = vec![a1, a2]; @@ -443,8 +443,8 @@ impl MachineState { }; } - fn get_number(&self, at: &ArithmeticTerm) -> Result> { - + fn get_number(&self, at: &ArithmeticTerm) -> Result> { + match at { &ArithmeticTerm::Reg(r) => { let addr = self[r].clone(); @@ -485,7 +485,7 @@ impl MachineState { } } - fn signed_bitwise_op(&mut self, n1: &BigInt, n2: &BigInt, t: usize, f: Op) + fn signed_bitwise_op(&self, n1: &BigInt, n2: &BigInt, f: Op) -> Rc where Op: FnOnce(&BigUint, &BigUint) -> BigUint { let n1_b = n1.to_signed_bytes_le(); @@ -494,9 +494,218 @@ impl MachineState { let u_n1 = BigUint::from_bytes_le(&n1_b); let u_n2 = BigUint::from_bytes_le(&n2_b); - let result = BigInt::from_signed_bytes_le(&f(&u_n1, &u_n2).to_bytes_le()); + Rc::new(BigInt::from_signed_bytes_le(&f(&u_n1, &u_n2).to_bytes_le())) + } + + fn arith_eval_by_metacall(&self) -> Result> + { + let instantiation_err = functor!(self.atom_tbl.clone(), "instantiation_error", 1, + [heap_atom!("(is)/2", self.atom_tbl.clone())]); + + let a = self[temp_v!(2)].clone(); + + if let &Addr::Con(Constant::Number(ref n)) = &a { + return Ok(n.clone()); + } + + let r = match a { + Addr::Str(h) | Addr::HeapCell(h) => Ok(Ref::HeapCell(h)), + Addr::StackCell(fr, sc) => Ok(Ref::StackCell(fr, sc)), + _ => Err(instantiation_err.clone()) + }?; + + let mut interms: Vec = Vec::with_capacity(64); + + for heap_val in self.post_order_iter(r) { + match heap_val { + HeapCellValue::NamedStr(2, name, Some(Fixity::In)) => { + let a2 = interms.pop().unwrap(); + let a1 = interms.pop().unwrap(); + + match name.as_str() { + "+" => interms.push(a1 + a2), + "-" => interms.push(a1 - a2), + "*" => interms.push(a1 * a2), + "rdiv" => + match NumberPair::from(a1, a2) { + NumberPair::Rational(r1, r2) => + interms.push(Number::Rational(self.rdiv(r1, r2)?)), + _ => + return Err(instantiation_err) + }, + "//" => interms.push(Number::Integer(self.idiv(a1, a2)?)), + "div" => interms.push(Number::Integer(self.fidiv(a1, a2)?)), + ">>" => interms.push(Number::Integer(self.shr(a1, a2)?)), + "<<" => interms.push(Number::Integer(self.shl(a1, a2)?)), + "/\\" => interms.push(Number::Integer(self.and(a1, a2)?)), + "\\/" => interms.push(Number::Integer(self.or(a1, a2)?)), + "xor" => interms.push(Number::Integer(self.xor(a1, a2)?)), + "mod" => interms.push(Number::Integer(self.modulus(a1, a2)?)), + "rem" => interms.push(Number::Integer(self.remainder(a1, a2)?)), + _ => return Err(instantiation_err) + } + }, + HeapCellValue::NamedStr(1, name, Some(Fixity::Pre)) => { + let a1 = interms.pop().unwrap(); + + match name.as_str() { + "-" => interms.push(- a1), + _ => return Err(instantiation_err) + } + }, + HeapCellValue::Addr(Addr::Con(Constant::Number(n))) => + interms.push(n), + _ => + return Err(instantiation_err) + } + }; + + Ok(interms.pop().unwrap()) + } + + fn rdiv(&self, r1: Rc>, r2: Rc>) + -> Result>, Vec> + { + if *r2 == Ratio::zero() { + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("zero_divisor", self.atom_tbl.clone())])) + } else { + Ok(Rc::new(&*r1 / &*r2)) + } + } + + fn fidiv(&self, n1: Number, n2: Number) -> Result, Vec> + { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => + if *n2 == BigInt::zero() { + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("zero_divisor", self.atom_tbl.clone())])) + } else { + Ok(Rc::new(n1.div_floor(&n2))) + }, + _ => Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + } + } + + fn idiv(&self, n1: Number, n2: Number) -> Result, Vec> + { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => + if *n2 == BigInt::zero() { + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("zero_divisor", self.atom_tbl.clone())])) + } else { + Ok(Rc::new(&*n1 / &*n2)) + }, + _ => + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + } + } + + fn div(&self, n1: Number, n2: Number) -> Result> + { + if n2.is_zero() { + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("zero_divisor", self.atom_tbl.clone())])) + } else { + Ok(n1 / n2) + } + } + + fn shr(&self, n1: Number, n2: Number) -> Result, Vec> + { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => + match n2.to_usize() { + Some(n2) => Ok(Rc::new(&*n1 >> n2)), + _ => Ok(Rc::new(&*n1 >> usize::max_value())) + }, + _ => + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + } + } + + fn shl(&self, n1: Number, n2: Number) -> Result, Vec> + { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => + match n2.to_usize() { + Some(n2) => Ok(Rc::new(&*n1 << n2)), + _ => Ok(Rc::new(&*n1 << usize::max_value())) + }, + _ => + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + } + } + + fn xor(&self, n1: Number, n2: Number) -> Result, Vec> + { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => + Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 ^ u_n2)), + _ => + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + } + } + + fn and(&self, n1: Number, n2: Number) -> Result, Vec> + { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => + Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 & u_n2)), + _ => + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + } + } - self.interms[t - 1] = Number::Integer(Rc::new(result)); + fn modulus(&self, n1: Number, n2: Number) -> Result, Vec> + { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => + if *n2 == BigInt::zero() { + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("zero_divisor", self.atom_tbl.clone())])) + } else { + Ok(Rc::new(n1.mod_floor(&n2))) + }, + _ => + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + } + } + + fn remainder(&self, n1: Number, n2: Number) -> Result, Vec> + { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => + if *n2 == BigInt::zero() { + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("zero_divisor", self.atom_tbl.clone())])) + } else { + Ok(Rc::new(&*n1 % &*n2)) + }, + _ => + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + } + } + + fn or(&self, n1: Number, n2: Number) -> Result, Vec> + { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => + Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 & u_n2)), + _ => + Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, + [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + } } pub(super) fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) { @@ -526,74 +735,22 @@ impl MachineState { let r1 = try_or_fail!(self, self.get_rational(a1)); let r2 = try_or_fail!(self, self.get_rational(a2)); - if *r2 == Ratio::zero() { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("zero_divisor", atom_tbl)])); - return; - } - - self.interms[t - 1] = Number::Rational(Rc::new(&*r1 / &*r2)); + self.interms[t - 1] = Number::Rational(try_or_fail!(self, self.rdiv(r1, r2))); self.p += 1; }, &ArithmeticInstruction::FIDiv(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)); - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => { - if *n2 == BigInt::zero() { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("zero_divisor", atom_tbl)])); - return; - } - - self.interms[t - 1] = Number::Integer(Rc::new(n1.div_floor(&n2))); - }, - _ => { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("expected_integer_args", atom_tbl)])); - return; - } - } - + self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.fidiv(n1, n2))); self.p += 1; }, &ArithmeticInstruction::IDiv(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)); - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => { - if *n2 == BigInt::zero() { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("zero_divisor", atom_tbl)])); - return; - } - - self.interms[t - 1] = Number::Integer(Rc::new(&*n1 / &*n2)); - self.p += 1; - }, - _ => { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("expected_integer_args", atom_tbl)])); - return; - } - } + self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.idiv(n1, n2))); + self.p += 1; }, &ArithmeticInstruction::Neg(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); @@ -605,175 +762,56 @@ impl MachineState { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - if n2.is_zero() { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("zero_divisor", atom_tbl)])); - return; - } - - self.interms[t - 1] = n1 / n2; + self.interms[t - 1] = try_or_fail!(self, self.div(n1, n2)); self.p += 1; }, &ArithmeticInstruction::Shr(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)); - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => - match n2.to_usize() { - Some(n2) => self.interms[t - 1] = Number::Integer(Rc::new(&*n1 >> n2)), - _ => self.interms[t - 1] = Number::Integer(Rc::new(&*n1 >> usize::max_value())) - }, - _ => { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("expected_integer_args", atom_tbl)])); - return; - } - } - + self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.shr(n1, n2))); self.p += 1; }, &ArithmeticInstruction::Shl(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)); - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => - match n2.to_usize() { - Some(n2) => self.interms[t - 1] = Number::Integer(Rc::new(&*n1 << n2)), - _ => self.interms[t - 1] = Number::Integer(Rc::new(&*n1 << usize::max_value())) - }, - _ => { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("expected_integer_args", atom_tbl)])); - return; - } - } - + self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.shl(n1, n2))); self.p += 1; }, &ArithmeticInstruction::Xor(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)); - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => - self.signed_bitwise_op(&*n1, &*n2, t, |u_n1, u_n2| u_n1 ^ u_n2), - _ => { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("expected_integer_args", atom_tbl)])); - return; - } - }; - + self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.xor(n1, n2))); self.p += 1; }, &ArithmeticInstruction::And(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)); - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => - self.signed_bitwise_op(&*n1, &*n2, t, |u_n1, u_n2| u_n1 & u_n2), - _ => { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("expected_integer_args", atom_tbl)])); - return; - } - }; - + self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.and(n1, n2))); self.p += 1; }, &ArithmeticInstruction::Or(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)); - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => - self.signed_bitwise_op(&*n1, &*n2, t, |u_n1, u_n2| u_n1 | u_n2), - _ => { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("expected_integer_args", atom_tbl)])); - return; - } - }; - + self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.or(n1, n2))); self.p += 1; }, &ArithmeticInstruction::Mod(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)); - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => { - if *n2 == BigInt::zero() { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("zero_divisor", atom_tbl)])); - return; - } - - self.interms[t - 1] = Number::Integer(Rc::new(n1.mod_floor(&n2))); - }, - _ => { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("expected_integer_args", atom_tbl)])); - return; - } - } - + self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.modulus(n1, n2))); self.p += 1; }, &ArithmeticInstruction::Rem(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)); - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => { - if *n2 == BigInt::zero() { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("zero_divisor", atom_tbl)])); - return; - } - - self.interms[t - 1] = Number::Integer(Rc::new(&*n1 % &*n2)); - }, - _ => { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "evaluation_error", - 1, - [heap_atom!("expected_integer_args", atom_tbl)])); - return; - } - } - + self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.remainder(n1, n2))); self.p += 1; } }; @@ -1142,9 +1180,9 @@ impl MachineState { fn throw_exception(&mut self, hcv: Vec) { let h = self.heap.h; - + self.registers[1] = Addr::HeapCell(h); - + self.heap.append(hcv); self.goto_throw(); } @@ -1222,7 +1260,7 @@ impl MachineState { fn try_get_arg(&mut self) -> Result<(), Vec> { let a1 = self.store(self.deref(self[temp_v!(1)].clone())); - + if let Addr::Con(Constant::Number(Number::Integer(i))) = a1 { let a2 = self.store(self.deref(self[temp_v!(2)].clone())); @@ -1233,13 +1271,13 @@ impl MachineState { Some(i) if 1 <= i && i <= arity => { let a3 = self[temp_v!(3)].clone(); let h_a = Addr::HeapCell(o + i); - + self.unify(a3, h_a); }, _ => self.fail = true }, _ => self.fail = true - }; + }; } else { return Err(functor!(self.atom_tbl, "type_error", @@ -1250,7 +1288,7 @@ impl MachineState { Ok(()) } - + pub(super) fn execute_built_in_instr(&mut self, code_dir: &CodeDir, instr: &BuiltInInstruction) { match instr { @@ -1269,8 +1307,8 @@ impl MachineState { }; self.p += 1; - }, - &BuiltInInstruction::GetArg => + }, + &BuiltInInstruction::GetArg => try_or_fail!(self, { let val = self.try_get_arg(); self.p = self.cp; @@ -1312,7 +1350,14 @@ impl MachineState { &BuiltInInstruction::GetCutPoint(r) => { let c = Constant::Usize(self.b); self[r] = Addr::Con(c); - + + self.p += 1; + }, + &BuiltInInstruction::IsOnHeap => { + let a1 = self[temp_v!(1)].clone(); + let result = try_or_fail!(self, self.arith_eval_by_metacall()); + + self.unify(a1, Addr::Con(Constant::Number(result))); self.p += 1; }, &BuiltInInstruction::SetBall => { @@ -1432,13 +1477,13 @@ impl MachineState { match a1.clone() { Addr::Str(o) => match self.heap[o].clone() { - HeapCellValue::NamedStr(arity, name, _) => { + HeapCellValue::NamedStr(arity, name, _) => { let name = Addr::Con(Constant::Atom(name)); // A2 let arity = Addr::Con(Constant::Number(rc_integer!(arity))); let a2 = self[temp_v!(2)].clone(); self.unify(a2, name); - + if !self.fail { let a3 = self[temp_v!(3)].clone(); self.unify(a3, arity); @@ -1460,26 +1505,26 @@ impl MachineState { return Ok(()); } }; - + self.heap.push(HeapCellValue::NamedStr(arity, name, None)); for _ in 0 .. arity { let h = self.heap.h; self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); } - - self.unify(a1, f_a); + + self.unify(a1, f_a); } else { return Err(functor!(self.atom_tbl, "instantiation_error", 0, [])); } } else { return Err(functor!(self.atom_tbl, "instantiation_error", 0, [])); - } + } }, _ => { let a2 = self[temp_v!(2)].clone(); self.unify(a1, a2); - + if !self.fail { let a3 = self[temp_v!(3)].clone(); self.unify(a3, Addr::Con(Constant::Number(rc_integer!(0)))); @@ -1503,9 +1548,9 @@ impl MachineState { gadget.duplicate_term(a1); } - self.unify(Addr::HeapCell(old_h), a2); + self.unify(Addr::HeapCell(old_h), a2); } - + pub(super) fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction) { match instr { @@ -1513,7 +1558,7 @@ impl MachineState { let gi = self.next_global_index(); self.p += 1; - + if self.e + 1 < self.and_stack.len() { let and_gi = self.and_stack[self.e].global_index; let or_gi = self.or_stack.top() @@ -1526,15 +1571,15 @@ impl MachineState { self.and_stack[index].e = self.e; self.and_stack[index].cp = self.cp; self.and_stack[index].global_index = gi; - + self.and_stack.resize(index, num_cells); self.e = index; - + return; } } - + self.and_stack.push(gi, self.e, self.cp, num_cells); self.e = self.and_stack.len() - 1; }, @@ -1568,28 +1613,28 @@ impl MachineState { }, &ControlInstruction::Deallocate => { let e = self.e; - + self.cp = self.and_stack[e].cp; - self.e = self.and_stack[e].e; - + self.e = self.and_stack[e].e; + self.p += 1; }, - &ControlInstruction::DisplayCall => { + &ControlInstruction::DisplayCall => { let output = self.print_term(&self[temp_v!(1)], DisplayFormatter {}, PrinterOutputter::new()); - + println!("{}", output.result()); - + self.p += 1; }, - &ControlInstruction::DisplayExecute => { + &ControlInstruction::DisplayExecute => { let output = self.print_term(&self[temp_v!(1)], DisplayFormatter {}, PrinterOutputter::new()); - + println!("{}", output.result()); - + self.p = self.cp; }, &ControlInstruction::DuplicateTermCall => { @@ -1634,7 +1679,7 @@ impl MachineState { let a1 = self[r].clone(); let a2 = try_or_fail!(self, self.get_number(at)); - self.unify(a1, Addr::Con(Constant::Number(a2))); + self.unify(a1, Addr::Con(Constant::Number(a2))); self.p = self.cp; }, &ControlInstruction::Proceed => @@ -1655,7 +1700,7 @@ impl MachineState { &IndexedChoiceInstruction::Try(l) => { let n = self.num_of_args; let gi = self.next_global_index(); - + self.or_stack.push(gi, self.e, self.cp, @@ -1738,7 +1783,7 @@ impl MachineState { &ChoiceInstruction::TryMeElse(offset) => { let n = self.num_of_args; let gi = self.next_global_index(); - + self.or_stack.push(gi, self.e, self.cp, @@ -1827,7 +1872,7 @@ impl MachineState { self.tidy_trail(); } - self.p += 1; + self.p += 1; }, &CutInstruction::GetLevel => { let b0 = self.b0; @@ -1846,7 +1891,7 @@ impl MachineState { self.tidy_trail(); } - self.p += 1; + self.p += 1; } } } diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 9d13ee21..94d4cdca 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -417,3 +417,9 @@ macro_rules! display { Line::Control(ControlInstruction::DisplayCall) ) } + +macro_rules! is_on_heap { + () => ( + Line::BuiltIn(BuiltInInstruction::IsOnHeap) + ) +} -- 2.54.0