]> Repositorios git - scryer-prolog.git/commitdiff
add callable `is/2`
authorMark Thom <[email protected]>
Fri, 19 Jan 2018 07:08:55 +0000 (00:08 -0700)
committerMark Thom <[email protected]>
Fri, 19 Jan 2018 07:08:55 +0000 (00:08 -0700)
src/prolog/arithmetic.rs
src/prolog/ast.rs
src/prolog/builtins.rs
src/prolog/heap_iter.rs
src/prolog/heap_print.rs
src/prolog/io.rs
src/prolog/machine/machine_state.rs
src/prolog/macros.rs

index 91451fcb49b2d012cca285335fb34f2a3f28a8a2..e7445828943fc724e78eb3f851c5e52368d2bb7a 100644 (file)
@@ -80,13 +80,13 @@ pub struct ArithmeticEvaluator<'a> {
 pub trait ArithmeticTermIter<'a> {
     type Iter : Iterator<Item=Result<ArithTermRef<'a>, ArithmeticError>>;
 
-    fn iter(&self) -> Result<Self::Iter, ArithmeticError>;
+    fn iter(self) -> Result<Self::Iter, ArithmeticError>;
 }
 
 impl<'a> ArithmeticTermIter<'a> for &'a Term {
     type Iter = ArithInstructionIterator<'a>;
 
-    fn iter(&self) -> Result<Self::Iter, ArithmeticError> {
+    fn iter(self) -> Result<Self::Iter, ArithmeticError> {
         ArithInstructionIterator::new(self)
     }
 }
@@ -223,3 +223,4 @@ impl<'a> ArithmeticEvaluator<'a>
         Ok((code, self.interm.pop()))
     }
 }
+
index 475792e6ae480d6a6bc94acbd4e681589a23c4e0..1c2443251cd87ca5bdc5e4decb0aac388e893495 100644 (file)
@@ -539,7 +539,7 @@ impl Number {
     }    
 }
 
-enum NumberPair {
+pub enum NumberPair {
     Float(OrderedFloat<f64>, OrderedFloat<f64>),
     Integer(Rc<BigInt>, Rc<BigInt>),
     Rational(Rc<Ratio<BigInt>>, Rc<Ratio<BigInt>>)
@@ -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,
index 0ccd6a6c11d0be0f3d05ad5fd898b7e5dd22d316..119a118465a9e09f6d23029ecdba9c629915c115 100644 (file)
@@ -275,6 +275,8 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> 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<Atom>) -> (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)
 }
index 99f0b1cf54a85cfeb8070d708cd24a016b46105f..ae76ac6d78ad5dba5a8867a95db3c38002d1b880 100644 (file)
@@ -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<Ref>
 }
 
-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<Self::Item> {
@@ -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<Self::Item> {
+        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))
+    }
+}
index 89dc9a0368b8e768260c792bddd9961d2688a55b..07ddbd2ee1421b6a39064cd07b077c3d9460ee21 100644 (file)
@@ -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<TokenOrRedirect>
 }
 
 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![] }
     }
 
index d7e870f8e58b1c501e21a57e76482f110f2c2ce6..fc1f9eeb454ab70bac9680a011b4d5de83d68240 100644 (file)
@@ -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 =>
index 108259996ac1b7d82cf255dd13f152b7c1d6b955..3b286b9406b928d972362ae44b31d754ea07d7cc 100644 (file)
@@ -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<Fmt, Outputter>(&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<Number, Vec<HeapCellValue>> {        
-        
+    fn get_number(&self, at: &ArithmeticTerm) -> Result<Number, Vec<HeapCellValue>> {
+
         match at {
             &ArithmeticTerm::Reg(r) => {
                 let addr = self[r].clone();
@@ -485,7 +485,7 @@ impl MachineState {
         }
     }
 
-    fn signed_bitwise_op<Op>(&mut self, n1: &BigInt, n2: &BigInt, t: usize, f: Op)
+    fn signed_bitwise_op<Op>(&self, n1: &BigInt, n2: &BigInt, f: Op) -> Rc<BigInt>
         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<Number, Vec<HeapCellValue>>
+    {        
+        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<Number> = 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<Ratio<BigInt>>, r2: Rc<Ratio<BigInt>>)
+            -> Result<Rc<Ratio<BigInt>>, Vec<HeapCellValue>>
+    {
+        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<Rc<BigInt>, Vec<HeapCellValue>>
+    {
+        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<Rc<BigInt>, Vec<HeapCellValue>>
+    {
+        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<Number, Vec<HeapCellValue>>
+    {
+        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<Rc<BigInt>, Vec<HeapCellValue>>
+    {
+        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<Rc<BigInt>, Vec<HeapCellValue>>
+    {
+        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<Rc<BigInt>, Vec<HeapCellValue>>
+    {
+        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<Rc<BigInt>, Vec<HeapCellValue>>
+    {
+        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<Rc<BigInt>, Vec<HeapCellValue>>
+    {
+        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<Rc<BigInt>, Vec<HeapCellValue>>
+    {
+        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<Rc<BigInt>, Vec<HeapCellValue>>
+    {
+        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<HeapCellValue>) {
         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<HeapCellValue>>
     {
         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;
             }
         }
     }
index 9d13ee213fac32543690df1811e661f9ceb28db2..94d4cdca1c290da63b7cd36236149dae7043c585 100644 (file)
@@ -417,3 +417,9 @@ macro_rules! display {
         Line::Control(ControlInstruction::DisplayCall)
     )
 }
+
+macro_rules! is_on_heap {
+    () => (
+        Line::BuiltIn(BuiltInInstruction::IsOnHeap)
+    )
+}