From 194e5dc94e53cf7bbfccee4e41d03a99df45af95 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 26 Mar 2020 22:01:23 -0600 Subject: [PATCH] initial commit for merge --- Cargo.lock | 6 +- Cargo.toml | 2 +- src/prolog/arithmetic.rs | 34 +- src/prolog/forms.rs | 33 +- src/prolog/heap_iter.rs | 183 +- src/prolog/heap_print.rs | 457 ++-- src/prolog/indexing.rs | 10 +- src/prolog/instructions.rs | 475 ++-- src/prolog/machine/arithmetic_ops.rs | 786 ++++++ src/prolog/machine/attributed_variables.rs | 13 +- src/prolog/machine/copier.rs | 64 +- src/prolog/machine/dynamic_database.rs | 94 +- src/prolog/machine/heap.rs | 197 +- src/prolog/machine/machine_errors.rs | 484 ++-- src/prolog/machine/machine_indices.rs | 213 +- src/prolog/machine/machine_state.rs | 174 +- src/prolog/machine/machine_state_impl.rs | 2628 +++++++++----------- src/prolog/machine/mod.rs | 38 +- src/prolog/machine/partial_string.rs | 172 +- src/prolog/machine/streams.rs | 20 +- src/prolog/machine/system_calls.rs | 2058 +++++++++------ src/prolog/macros.rs | 200 +- src/prolog/read.rs | 27 +- src/prolog/toplevel.pl | 1 + src/prolog/write.rs | 18 +- 25 files changed, 5092 insertions(+), 3295 deletions(-) create mode 100644 src/prolog/machine/arithmetic_ops.rs diff --git a/Cargo.lock b/Cargo.lock index 61c28d82..0fe6e3f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -444,8 +444,7 @@ dependencies = [ [[package]] name = "prolog_parser" -version = "0.8.47" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.8.48" dependencies = [ "lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -580,7 +579,7 @@ dependencies = [ "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "prolog_parser 0.8.47 (registry+https://github.com/rust-lang/crates.io-index)", + "prolog_parser 0.8.48", "ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustyline 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -791,7 +790,6 @@ dependencies = [ "checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" "checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum prolog_parser 0.8.47 (registry+https://github.com/rust-lang/crates.io-index)" = "2cf575fc8b91b2d9a9487f13655cffb6f697a5294b74de9b24b6a5fbe987e229" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" diff --git a/Cargo.toml b/Cargo.toml index 50f1882b..7c3338f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ libc = "0.2.62" nix = "0.15.0" num-rug-adapter = { optional = true, version = "0.1.1" } ordered-float = "0.5.0" -prolog_parser = { version = "0.8.47", default-features = false } +prolog_parser = { version = "0.8.48", path = "../prolog_parser", default-features = false } ref_thread_local = "0.0.0" rug = { version = "1.4.0", optional = true } rustyline = "6.0.0" diff --git a/src/prolog/arithmetic.rs b/src/prolog/arithmetic.rs index 4c126d77..3520cb1b 100644 --- a/src/prolog/arithmetic.rs +++ b/src/prolog/arithmetic.rs @@ -399,23 +399,27 @@ impl Add for Number { fn add(self, rhs: Number) -> Self::Output { match (self, rhs) { - (Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Integer(n1 + n2)), // add_i + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::Integer(Rc::new(Integer::from(&*n1) + &*n2))) // add_i + } (Number::Integer(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { + | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?)) } (Number::Integer(n1), Number::Rational(n2)) - | (Number::Rational(n2), Number::Integer(n1)) => { - Ok(Number::Rational(Rational::from(n1) + n2)) + | (Number::Rational(n2), Number::Integer(n1)) => { + Ok(Number::Rational(Rc::new(Rational::from(&*n1) + &*n2))) } (Number::Rational(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { + | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?)) } (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => { Ok(Number::Float(add_f(f1, f2)?)) } - (Number::Rational(r1), Number::Rational(r2)) => Ok(Number::Rational(r1 + r2)), + (Number::Rational(r1), Number::Rational(r2)) => { + Ok(Number::Rational(Rc::new(Rational::from(&*r1) + &*r2))) + } } } } @@ -425,9 +429,9 @@ impl Neg for Number { fn neg(self) -> Self::Output { match self { - Number::Integer(n) => Number::Integer(-n), + Number::Integer(n) => Number::Integer(Rc::new(-Integer::from(&*n))), Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)), - Number::Rational(r) => Number::Rational(-r), + Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))), } } } @@ -445,14 +449,16 @@ impl Mul for Number { fn mul(self, rhs: Number) -> Self::Output { match (self, rhs) { - (Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Integer(n1 * n2)), // mul_i + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::Integer(Rc::new(Integer::from(&*n1) * &*n2))) // mul_i + } (Number::Integer(n1), Number::Float(OrderedFloat(n2))) | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { Ok(Number::Float(mul_f(float_i_to_f(&n1)?, n2)?)) } (Number::Integer(n1), Number::Rational(n2)) | (Number::Rational(n2), Number::Integer(n1)) => { - Ok(Number::Rational(Rational::from(n1) * n2)) + Ok(Number::Rational(Rc::new(Rational::from(&*n1) * &*n2))) } (Number::Rational(n1), Number::Float(OrderedFloat(n2))) | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { @@ -461,7 +467,9 @@ impl Mul for Number { (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => { Ok(Number::Float(mul_f(f1, f2)?)) } - (Number::Rational(r1), Number::Rational(r2)) => Ok(Number::Rational(r1 * r2)), + (Number::Rational(r1), Number::Rational(r2)) => { + Ok(Number::Rational(Rc::new(Rational::from(&*r1) * &*r2))) + } } } } @@ -539,8 +547,8 @@ impl Ord for Number { } // Computes n ^ power. Ignores the sign of power. -pub fn binary_pow(mut n: Integer, power: Integer) -> Integer { - let mut power = power.abs(); +pub fn binary_pow(mut n: Integer, power: &Integer) -> Integer { + let mut power = Integer::from(power.abs_ref()); if power == 0 { return Integer::from(1); diff --git a/src/prolog/forms.rs b/src/prolog/forms.rs index 9c402bd2..4f569227 100644 --- a/src/prolog/forms.rs +++ b/src/prolog/forms.rs @@ -576,8 +576,8 @@ pub struct Module { #[derive(Clone, PartialEq, Eq)] pub enum Number { Float(OrderedFloat), - Integer(Integer), - Rational(Rational), + Integer(Rc), + Rational(Rc), } impl Default for Number { @@ -586,48 +586,51 @@ impl Default for Number { } } -impl Number { - pub fn to_constant(self) -> Constant { +impl Into for Number { + #[inline] + fn into(self) -> HeapCellValue { match self { - Number::Integer(n) => Constant::Integer(n), - Number::Float(f) => Constant::Float(f), - Number::Rational(r) => Constant::Rational(r), + Number::Integer(n) => HeapCellValue::Integer(n), + Number::Float(f) => HeapCellValue::Addr(Addr::Float(f)), + Number::Rational(r) => HeapCellValue::Rational(r), } } +} +impl Number { #[inline] pub fn is_positive(&self) -> bool { match self { - &Number::Integer(ref n) => n > &0, + &Number::Integer(ref n) => &**n > &0, &Number::Float(OrderedFloat(f)) => f.is_sign_positive(), - &Number::Rational(ref r) => r > &0, + &Number::Rational(ref r) => &**r > &0, } } #[inline] pub fn is_negative(&self) -> bool { match self { - &Number::Integer(ref n) => n < &0, + &Number::Integer(ref n) => &**n < &0, &Number::Float(OrderedFloat(f)) => f.is_sign_negative(), - &Number::Rational(ref r) => r < &0, + &Number::Rational(ref r) => &**r < &0, } } #[inline] pub fn is_zero(&self) -> bool { match self { - &Number::Integer(ref n) => n == &0, + &Number::Integer(ref n) => &**n == &0, &Number::Float(f) => f == OrderedFloat(0f64), - &Number::Rational(ref r) => r == &0, + &Number::Rational(ref r) => &**r == &0, } } #[inline] pub fn abs(self) -> Self { match self { - Number::Integer(n) => Number::Integer(n.abs()), + Number::Integer(n) => Number::Integer(Rc::new(Integer::from(n.abs_ref()))), Number::Float(f) => Number::Float(OrderedFloat(f.abs())), - Number::Rational(r) => Number::Rational(r.abs()), + Number::Rational(r) => Number::Rational(Rc::new(Rational::from(r.abs_ref()))), } } } diff --git a/src/prolog/heap_iter.rs b/src/prolog/heap_iter.rs index 0c3630e6..57434fd9 100644 --- a/src/prolog/heap_iter.rs +++ b/src/prolog/heap_iter.rs @@ -1,5 +1,3 @@ -use prolog_parser::ast::*; - use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_state::*; @@ -22,25 +20,33 @@ impl<'a> HCPreOrderIterator<'a> { } } + #[inline] pub fn machine_st(&self) -> &MachineState { &self.machine_st } fn follow_heap(&mut self, h: usize) -> Addr { match &self.machine_st.heap[h] { - HeapCellValue::NamedStr(arity, _, _) => { - for idx in (1..arity + 1).rev() { + &HeapCellValue::NamedStr(arity, _, _) => { + for idx in (1 .. arity + 1).rev() { self.state_stack.push(Addr::HeapCell(h + idx)); } Addr::Str(h) } - HeapCellValue::Addr(ref a) => { - self.follow(a.clone()) + &HeapCellValue::Addr(a) => { + self.follow(a) } HeapCellValue::PartialString(_) => { self.follow(Addr::PStrLocation(h, 0)) } + HeapCellValue::Atom(..) | HeapCellValue::DBRef(_) + | HeapCellValue::Integer(_) | HeapCellValue::Rational(_) => { + Addr::Con(h) + } + HeapCellValue::Stream(_) => { + Addr::Stream(h) + } } } @@ -51,30 +57,6 @@ impl<'a> HCPreOrderIterator<'a> { let da = self.machine_st.store(self.machine_st.deref(addr)); match da { - Addr::Con(Constant::String(n, s)) => { - if !self.machine_st.machine_flags().double_quotes.is_atom() { - if s.len() > n { - if let Some(c) = s[n ..].chars().next() { - let o = c.len_utf8(); - - self.state_stack.push(Addr::Con(Constant::String(n+o, s.clone()))); - - if self.machine_st.machine_flags().double_quotes.is_codes() { - self.state_stack.push(Addr::Con(Constant::CharCode(c as u32))); - } else { - self.state_stack.push(Addr::Con(Constant::Char(c))); - } - } - } else { - return Addr::Con(Constant::EmptyList); - } - } - - Addr::Con(Constant::String(n, s)) - } - Addr::Con(_) | Addr::DBRef(_) | Addr::Stream(_) => { - da - } Addr::Lis(a) => { self.state_stack.push(Addr::HeapCell(a + 1)); self.state_stack.push(Addr::HeapCell(a)); @@ -83,16 +65,14 @@ impl<'a> HCPreOrderIterator<'a> { } Addr::PStrLocation(h, n) => { if let HeapCellValue::PartialString(ref pstr) = &self.machine_st.heap[h] { - let s = pstr.block_as_str(); - - if let Some(c) = s[n ..].chars().next() { - if pstr.len() > n + c.len_utf8() { + if let Some(c) = pstr.range_from(n ..).next() { + if !pstr.at_end(n + c.len_utf8()) { self.state_stack.push(Addr::PStrLocation(h, n + c.len_utf8())); } else { self.state_stack.push(Addr::HeapCell(h + 1)); } - self.state_stack.push(Addr::Con(Constant::Char(c))); + self.state_stack.push(Addr::Char(c)); } else { unreachable!() } @@ -102,66 +82,52 @@ impl<'a> HCPreOrderIterator<'a> { Addr::PStrLocation(h, n) } - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) => { - da - } Addr::Str(s) => { self.follow_heap(s) // record terms of structure. } + Addr::Con(h) => { + if let HeapCellValue::PartialString(_) = &self.machine_st.heap[h] { + self.state_stack.push(Addr::HeapCell(h + 1)); + } + + Addr::Con(h) + } + da => { + da + } } } } impl<'a> Iterator for HCPreOrderIterator<'a> { - type Item = HeapCellValue; + type Item = Addr; fn next(&mut self) -> Option { - self.state_stack.pop().map(|a| match self.follow(a) { - Addr::HeapCell(h) => { - HeapCellValue::Addr(self.machine_st.heap[h].as_addr(h)) - } - Addr::Str(s) => { - match &self.machine_st.heap[s] { - val @ HeapCellValue::NamedStr(..) => { - val.clone() - } - _ => { - unreachable!() - } - } - } - Addr::StackCell(fr, sc) => { - HeapCellValue::Addr(self.machine_st.stack.index_and_frame(fr)[sc].clone()) - } - da => { - HeapCellValue::Addr(da) - } - }) + self.state_stack.pop().map(|a| self.follow(a)) } } pub trait MutStackHCIterator -where - Self: Iterator, +where Self: Iterator { fn stack(&mut self) -> &mut Vec; } -pub struct HCPostOrderIterator { - base_iter: HCIter, - parent_stack: Vec<(usize, HeapCellValue)>, // number of children, parent node. +pub struct HCPostOrderIterator<'a> { + base_iter: HCPreOrderIterator<'a>, + parent_stack: Vec<(usize, Addr)>, // number of children, parent node. } -impl Deref for HCPostOrderIterator { - type Target = HCIter; +impl<'a> Deref for HCPostOrderIterator<'a> { + type Target = HCPreOrderIterator<'a>; fn deref(&self) -> &Self::Target { &self.base_iter } } -impl> HCPostOrderIterator { - pub fn new(base_iter: HCIter) -> Self { +impl<'a> HCPostOrderIterator<'a> { + pub fn new(base_iter: HCPreOrderIterator<'a>) -> Self { HCPostOrderIterator { base_iter, parent_stack: vec![], @@ -169,8 +135,8 @@ impl> HCPostOrderIterator { } } -impl> Iterator for HCPostOrderIterator { - type Item = HeapCellValue; +impl<'a> Iterator for HCPostOrderIterator<'a> { + type Item = Addr; fn next(&mut self) -> Option { loop { @@ -183,15 +149,23 @@ impl> Iterator for HCPostOrderIterator 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); + match self.base_iter.machine_st.heap.index_addr(&item).as_ref() { + &HeapCellValue::NamedStr(arity, ..) => { + self.parent_stack.push((arity, item)); + } + &HeapCellValue::Addr(Addr::Lis(a)) => { + self.parent_stack.push((2, Addr::Lis(a))); + } + &HeapCellValue::Addr(Addr::PStrLocation(h, n)) => { + if let HeapCellValue::PartialString(ref pstr) = &self.machine_st.heap[h] { + let c = pstr.range_from(n ..).next().unwrap(); + self.parent_stack.push((2, Addr::PStrLocation(h, n + c.len_utf8()))); + } else { + unreachable!() + } + } + _ => { + return Some(item); } } } else { @@ -201,21 +175,16 @@ impl> Iterator for HCPostOrderIterator = HCPostOrderIterator>; - impl MachineState { pub fn pre_order_iter<'a>(&'a self, a: Addr) -> HCPreOrderIterator<'a> { HCPreOrderIterator::new(self, a) } - pub fn post_order_iter<'a>(&'a self, a: Addr) -> HCProperPostOrderIterator<'a> { + pub fn post_order_iter<'a>(&'a self, a: Addr) -> HCPostOrderIterator<'a> { HCPostOrderIterator::new(HCPreOrderIterator::new(self, a)) } - pub fn acyclic_pre_order_iter<'a>( - &'a self, - a: Addr, - ) -> HCAcyclicIterator> { + pub fn acyclic_pre_order_iter<'a>(&'a self, a: Addr,) -> HCAcyclicIterator<'a> { HCAcyclicIterator::new(HCPreOrderIterator::new(self, a)) } @@ -223,7 +192,7 @@ impl MachineState { &'a self, a1: Addr, a2: Addr, - ) -> HCZippedAcyclicIterator> { + ) -> HCZippedAcyclicIterator<'a> { HCZippedAcyclicIterator::new( HCPreOrderIterator::new(self, a1), HCPreOrderIterator::new(self, a2), @@ -237,13 +206,13 @@ impl<'a> MutStackHCIterator for HCPreOrderIterator<'a> { } } -pub struct HCAcyclicIterator { - iter: HCIter, +pub struct HCAcyclicIterator<'a> { + iter: HCPreOrderIterator<'a>, seen: IndexSet, } -impl HCAcyclicIterator { - pub fn new(iter: HCIter) -> Self { +impl<'a> HCAcyclicIterator<'a> { + pub fn new(iter: HCPreOrderIterator<'a>) -> Self { HCAcyclicIterator { iter, seen: IndexSet::new(), @@ -251,19 +220,17 @@ impl HCAcyclicIterator { } } -impl Deref for HCAcyclicIterator { - type Target = HCIter; +impl<'a> Deref for HCAcyclicIterator<'a> { + type Target = HCPreOrderIterator<'a>; fn deref(&self) -> &Self::Target { &self.iter } } -impl Iterator for HCAcyclicIterator -where - HCIter: Iterator + MutStackHCIterator, +impl<'a> Iterator for HCAcyclicIterator<'a> { - type Item = HeapCellValue; + type Item = Addr; fn next(&mut self) -> Option { while let Some(addr) = self.iter.stack().pop() { @@ -279,15 +246,15 @@ where } } -pub struct HCZippedAcyclicIterator { - i1: HCIter, - i2: HCIter, +pub struct HCZippedAcyclicIterator<'a> { + i1: HCPreOrderIterator<'a>, + i2: HCPreOrderIterator<'a>, seen: IndexSet<(Addr, Addr)>, pub first_to_expire: Ordering, } -impl HCZippedAcyclicIterator { - pub fn new(i1: HCIter, i2: HCIter) -> Self { +impl<'a> HCZippedAcyclicIterator<'a> { + pub fn new(i1: HCPreOrderIterator<'a>, i2: HCPreOrderIterator<'a>) -> Self { HCZippedAcyclicIterator { i1, i2, @@ -297,11 +264,9 @@ impl HCZippedAcyclicIterator { } } -impl Iterator for HCZippedAcyclicIterator -where - HCIter: Iterator + MutStackHCIterator, +impl<'a> Iterator for HCZippedAcyclicIterator<'a> { - type Item = (HeapCellValue, HeapCellValue); + type Item = (Addr, Addr); fn next(&mut self) -> Option { while let (Some(a1), Some(a2)) = (self.i1.stack().pop(), self.i2.stack().pop()) { @@ -324,7 +289,9 @@ where self.first_to_expire = Ordering::Less; None } - _ => None, + _ => { + None + } } } } diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index eeb53794..0ccc155b 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -3,6 +3,7 @@ use prolog_parser::ast::*; use crate::prolog::clause_types::*; use crate::prolog::forms::*; use crate::prolog::heap_iter::*; +use crate::prolog::machine::heap::*; use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_state::*; use crate::prolog::ordered_float::OrderedFloat; @@ -88,14 +89,17 @@ impl<'a> HCPreOrderIterator<'a> { */ fn leftmost_leaf_has_property

(&self, property_check: P) -> bool where - P: Fn(Constant) -> bool, + P: Fn(Addr, &Heap) -> bool, { let mut addr = match self.state_stack.last().cloned() { Some(addr) => addr, None => return false, }; - let mut parent_spec = DirectedOp::Left(clause_name!("-"), SharedOpDesc::new(200, FY)); + let mut parent_spec = DirectedOp::Left( + clause_name!("-"), + SharedOpDesc::new(200, FY), + ); loop { match self.machine_st.store(self.machine_st.deref(addr)) { @@ -110,29 +114,28 @@ impl<'a> HCPreOrderIterator<'a> { parent_spec = DirectedOp::Right(name.clone(), spec.clone()); } } - _ => return false, + _ => { + return false; + } }, - Addr::Con(Constant::Integer(n)) => return property_check(Constant::Integer(n)), - Addr::Con(Constant::Float(n)) => return property_check(Constant::Float(n)), - Addr::Con(Constant::Rational(n)) => return property_check(Constant::Rational(n)), - _ => return false, + addr => { + return property_check(addr, &self.machine_st.heap); + } } } } fn immediate_leaf_has_property

(&self, property_check: P) -> bool where - P: Fn(Constant) -> bool, + P: Fn(Addr, &Heap) -> bool, { let addr = match self.state_stack.last().cloned() { Some(addr) => addr, None => return false, }; - match self.machine_st.store(self.machine_st.deref(addr)) { - Addr::Con(c) => property_check(c), - _ => false, - } + let addr = self.machine_st.store(self.machine_st.deref(addr)); + property_check(addr, &self.machine_st.heap) } } @@ -261,13 +264,29 @@ fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool { #[inline] fn negated_op_needs_bracketing(iter: &HCPreOrderIterator, op: &Option) -> bool { if let &Some(ref op) = op { - op.is_negative_sign() - && iter.leftmost_leaf_has_property(|c| match c { - Constant::Integer(n) => n > 0, - Constant::Float(f) => f > OrderedFloat(0f64), - Constant::Rational(r) => r > 0, - _ => false, - }) + op.is_negative_sign() && iter.leftmost_leaf_has_property(|addr, heap| { + match addr { + Addr::Con(h) => { + match &heap[h] { + HeapCellValue::Integer(ref n) => { + &**n > &0 + } + &HeapCellValue::Rational(ref r) => { + &**r > &0 + } + _ => { + false + } + } + } + Addr::Float(f) => { + f > OrderedFloat(0f64) + } + _ => { + false + } + } + }) } else { false } @@ -293,8 +312,16 @@ fn numbervar(n: Integer) -> Var { impl MachineState { pub fn numbervar(&self, offset: &Integer, addr: Addr) -> Option { match self.store(self.deref(addr)) { - Addr::Con(Constant::Integer(ref n)) if n >= &0 => { - Some(numbervar(Integer::from(offset + n))) + Addr::Con(h) => { + if let &HeapCellValue::Integer(ref n) = &self.heap[h] { + if &**n >= &0 { + Some(numbervar(Integer::from(offset + &**n))) + } else { + None + } + } else { + None + } } _ => { None @@ -823,7 +850,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { fn check_for_seen( &mut self, iter: &mut HCPreOrderIterator, - ) -> Option { + ) -> Option { iter.stack().last().cloned().and_then(|addr| { let addr = self.machine_st.store(self.machine_st.deref(addr)); @@ -848,7 +875,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } None => { let offset = match functor_location(&addr) { - Some(offset) => offset, + Some(offset) => { + offset + } None => { return iter.next(); } @@ -969,7 +998,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } fn print_char(&mut self, is_quoted: bool, c: char) - { + { if non_quoted_token(once(c)) { let c = char_to_string(false, c); @@ -993,178 +1022,130 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } - fn print_constant( + fn print_string_as_str( &mut self, - iter: &mut HCPreOrderIterator, - max_depth: usize, - c: Constant, - op: &Option, + mut h: usize, + mut offset: usize, + quoted: bool, ) { - match c { - Constant::Atom(atom, spec) => { - if let Some(_) = fetch_atom_op_spec(atom.clone(), spec, self.op_dir) { - let mut result = String::new(); - - if let Some(ref op) = op { - if self.outputter.ends_with(&format!(" {}", op.as_str())) { - result.push(' '); - } - - result.push('('); - } - - result += &self.print_op_addendum(atom.as_str()); - - if op.is_some() { - result.push(')'); - } + self.push_char('"'); - push_space_if_amb!(self, &result, { - self.append_str(&result); - }); - } else { - push_space_if_amb!(self, atom.as_str(), { - self.print_atom(&atom); - }); - } - } - Constant::CharCode(c) => { - self.append_str(&format!("{}", c as u32)); - } - Constant::Char(c) => { - self.print_char(self.quoted, c); - } - Constant::CutPoint(b) => { - self.append_str(&format!("{}", b)); - } - Constant::EmptyList => { - self.append_str("[]"); - } - Constant::Integer(n) => { - self.print_number(Number::Integer(n), op); - } - Constant::Float(n) => { - self.print_number(Number::Float(n), op); - } - Constant::Rational(n) => { - self.print_number(Number::Rational(n), op); - } - Constant::String(n, s) if self.print_strings_as_strs => { - self.print_string_as_str(iter, n, s); - } - Constant::String(n, s) => { - self.print_string(iter, max_depth, n, s); - } - Constant::Usize(i) => { - self.append_str(&format!("u{}", i)); - } + while let HeapCellValue::PartialString(ref pstr) = &self.machine_st.heap[h] { + let atom = String::from_iter(pstr.range_from(offset ..).map(|c| { + char_to_string(quoted, c) + })); + + self.append_str(&atom); + + h += 2; + offset = 0; } - } - - fn print_string_as_str( - &mut self, - iter: &mut HCPreOrderIterator, - offset: usize, - s: Rc, - ) { - let atom = String::from_iter(s[offset ..].chars().map(|c| { - char_to_string(true, c) - })); self.push_char('"'); - self.append_str(&atom); - self.push_char('"'); - - // eliminate lingering elements on the iterator stack (the - // head and tail) which are there to treat the string as a - // list. - iter.stack().pop(); - iter.stack().pop(); } fn print_string( &mut self, - iter: &mut HCPreOrderIterator, mut max_depth: usize, - offset: usize, - s: Rc) + mut h: usize, + mut offset: usize, + ) { if !self.machine_st.machine_flags().double_quotes.is_atom() { if self.check_max_depth(&mut max_depth) { self.state_stack.push(TokenOrRedirect::Atom(clause_name!("..."))); return; } + + while let HeapCellValue::PartialString(ref pstr) = &self.machine_st.heap[h] { + if pstr.at_end(offset) && !self.at_cdr("") { + if let HeapCellValue::Addr(Addr::EmptyList) = &self.machine_st.heap[h+1] { + self.append_str("[]"); + break; + } else { + h += 2; + offset = 0; + } + } else if self.ignore_ops { + let iter: Box> = + if self.max_depth == 0 { + Box::new(pstr.range_from(offset ..)) + } else { + Box::new(pstr.range_from(offset ..).take(max_depth)) + }; - if s.len() <= offset && !self.at_cdr("") { - self.append_str("[]"); - } else if self.ignore_ops { - let mut char_count = 0; - let mut byte_len = 0; + let mut char_count = 0; + let mut byte_len = 0; - let iter: Box> = - if self.max_depth == 0 { - Box::new(s[offset ..].chars()) - } else { - Box::new(s[offset ..].chars().take(max_depth)) - }; + for c in iter { + self.print_char(self.quoted, '.'); + self.push_char('('); - for c in iter { - self.print_char(self.quoted, '.'); - self.push_char('('); + self.print_char(self.quoted, c); + self.push_char(','); - self.print_char(self.quoted, c); - self.push_char(','); + char_count += 1; + byte_len += c.len_utf8(); + } - char_count += 1; - byte_len += c.len_utf8(); - } + let mut at_end = false; + + if self.max_depth > 0 && !pstr.at_end(offset + byte_len) { + self.append_str("..."); + at_end = true; + } else { + if let HeapCellValue::Addr(Addr::EmptyList) = &self.machine_st.heap[h+1] { + self.append_str("[]"); + at_end = true; + } + } - if self.max_depth > 0 && byte_len < s[offset ..].len() { - self.append_str("..."); - } else { - self.append_str("[]"); - } + for _ in 0 .. char_count { + self.push_char(')'); + } - for _ in 0 .. char_count { - self.push_char(')'); - } - } else { - self.push_char('['); + if at_end { + break; + } - let iter: Box> = - if self.max_depth == 0 { - Box::new(s[offset ..].chars()) - } else { - Box::new(s[offset ..].chars().take(max_depth)) - }; + max_depth -= char_count; + } else { + self.push_char('['); - let mut byte_len = 0; + let iter: Box> = + if self.max_depth == 0 { + Box::new(pstr.range_from(offset ..)) + } else { + Box::new(pstr.range_from(offset ..).take(max_depth)) + }; - for c in iter { - self.print_char(false, c); - self.push_char(','); + let mut byte_len = 0; + let mut char_count = 0; - byte_len += c.len_utf8(); - } + for c in iter { + self.print_char(false, c); + self.push_char(','); + + byte_len += c.len_utf8(); + char_count += 1; + } - if self.max_depth > 0 && byte_len < s[offset ..].len() { - self.append_str("...|...]"); - } else { - self.outputter.truncate(self.outputter.len() - ','.len_utf8()); - self.push_char(']'); + if self.max_depth > 0 && !pstr.at_end(offset + byte_len) { + self.append_str("...|...]"); + break; + } else { + self.outputter.truncate(self.outputter.len() - ','.len_utf8()); + self.push_char(']'); + } + + max_depth -= char_count; } - } - iter.stack().pop(); - iter.stack().pop(); + h += 2; + offset = 0; + } } else { - let atom = String::from_iter(s[offset ..].chars().map(|c| { - char_to_string(self.quoted, c) - })); - - self.push_char('"'); - self.append_str(&atom); - self.push_char('"'); + self.print_string_as_str(h, 0, self.quoted); } } @@ -1217,21 +1198,22 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { max_depth: usize, ) { let add_brackets = if !self.ignore_ops { - negated_operand - || if let Some(ref op) = op { - if self.numbervars && arity == 1 && name.as_str() == "$VAR" { - !iter.immediate_leaf_has_property(|c| match c { - Constant::Integer(n) => n >= 0, - Constant::Float(f) => f >= OrderedFloat(0f64), - Constant::Rational(r) => r >= 0, - _ => false, - }) && needs_bracketing(&spec, op) - } else { - needs_bracketing(&spec, op) - } + negated_operand || if let Some(ref op) = op { + if self.numbervars && arity == 1 && name.as_str() == "$VAR" { + !iter.immediate_leaf_has_property(|addr, heap| { + match heap.index_addr(&addr).as_ref() { + &HeapCellValue::Integer(ref n) => &**n >= &0, + &HeapCellValue::Addr(Addr::Float(f)) => f >= OrderedFloat(0f64), + &HeapCellValue::Rational(ref r) => &**r >= &0, + _ => false + } + }) && needs_bracketing(&spec, op) } else { - is_functor_redirect && spec.prec() >= 1000 + needs_bracketing(&spec, op) } + } else { + is_functor_redirect && spec.prec() >= 1000 + } } else { false }; @@ -1264,49 +1246,134 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { ) { let negated_operand = negated_op_needs_bracketing(iter, &op); - let heap_val = match self.check_for_seen(iter) { - Some(heap_val) => heap_val, + let addr = match self.check_for_seen(iter) { + Some(addr) => addr, None => return, }; - - match heap_val { - HeapCellValue::NamedStr(arity, name, spec) => { + + match self.machine_st.heap.index_addr(&addr).as_ref() { + &HeapCellValue::NamedStr(arity, ref name, ref spec) => { let spec = fetch_op_spec(name.clone(), arity, spec.clone(), self.op_dir); if let Some(spec) = spec { self.handle_op_as_struct( - name, + name.clone(), arity, iter, &op, is_functor_redirect, - spec, + spec.clone(), negated_operand, max_depth, ); } else { push_space_if_amb!(self, name.as_str(), { - let ct = ClauseType::from(name, arity, spec); + let ct = ClauseType::from(name.clone(), arity, spec); self.format_clause(iter, max_depth, arity, ct); }); } } - HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) => { + &HeapCellValue::Atom(ref atom, ref spec) => { + if let Some(_) = fetch_atom_op_spec(atom.clone(), spec.clone(), self.op_dir) { + let mut result = String::new(); + + if let Some(ref op) = op { + if self.outputter.ends_with(&format!(" {}", op.as_str())) { + result.push(' '); + } + + result.push('('); + } + + result += &self.print_op_addendum(atom.as_str()); + + if op.is_some() { + result.push(')'); + } + + push_space_if_amb!(self, &result, { + self.append_str(&result); + }); + } else { + push_space_if_amb!(self, atom.as_str(), { + self.print_atom(&atom); + }); + } + } + &HeapCellValue::Addr(Addr::CharCode(c)) => { + self.append_str(&format!("{}", c as u32)); + } + &HeapCellValue::Addr(Addr::Char(c)) => { + self.print_char(self.quoted, c); + } + &HeapCellValue::Addr(Addr::CutPoint(b)) => { + self.append_str(&format!("{}", b)); + } + &HeapCellValue::Addr(Addr::EmptyList) => { if !self.at_cdr("") { self.append_str("[]"); } } - HeapCellValue::Addr(Addr::Con(c)) => { - self.print_constant(iter, max_depth, c, &op); + &HeapCellValue::Addr(Addr::Float(n)) => { + self.print_number(Number::Float(n), &op); + } + &HeapCellValue::Addr(Addr::Usize(u)) => { + self.append_str(&format!("{}", u)); } - HeapCellValue::Addr(Addr::Lis(_)) | HeapCellValue::Addr(Addr::PStrLocation(..)) => { + &HeapCellValue::Addr(Addr::PStrLocation(..)) + if !self.machine_st.flags.double_quotes.is_atom() => { + if self.ignore_ops { + self.format_struct(iter, max_depth, 2, clause_name!(".")); + } else { + self.push_list(iter, max_depth); + } + } + &HeapCellValue::Addr(Addr::PStrLocation(h, n)) => { + if let HeapCellValue::PartialString(_) = &self.machine_st.heap[h] { + self.print_string(max_depth, h, n); + + iter.stack().pop(); + iter.stack().pop(); + } else { + unreachable!() + } + } + &HeapCellValue::Addr(Addr::Lis(_)) => { if self.ignore_ops { self.format_struct(iter, max_depth, 2, clause_name!(".")); } else { self.push_list(iter, max_depth); } } - HeapCellValue::Addr(Addr::Stream(stream)) => { + &HeapCellValue::Addr(addr) => { + if let Some(offset_str) = self.offset_as_string(iter, addr) { + push_space_if_amb!(self, &offset_str, { + self.append_str(offset_str.as_str()); + }) + } + } + &HeapCellValue::Integer(ref n) => { + self.print_number(Number::Integer(n.clone()), &op); + } + &HeapCellValue::Rational(ref n) => { + self.print_number(Number::Rational(n.clone()), &op); + } + &HeapCellValue::PartialString(_) + if self.print_strings_as_strs => { + if let Addr::Con(h) = addr { + self.print_string_as_str(h, 0, true); + } else { + unreachable!() + } + } + &HeapCellValue::PartialString(_) => { + if let Addr::Con(h) = addr { + self.print_string(max_depth, h, 0); + } else { + unreachable!() + } + } + &HeapCellValue::Stream(ref stream) => { if let Some(alias) = &stream.options.alias { self.print_atom(alias); } else { @@ -1317,17 +1384,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } } - HeapCellValue::Addr(addr) => { - if let Some(offset_str) = self.offset_as_string(iter, addr) { - push_space_if_amb!(self, &offset_str, { - self.append_str(offset_str.as_str()); - }) - } - } _ => { - // This is the partial string case. We never clone a partial string - // for printing purposes, so.. this. - unreachable!() } } } diff --git a/src/prolog/indexing.rs b/src/prolog/indexing.rs index fe694d19..2bcfc6c3 100644 --- a/src/prolog/indexing.rs +++ b/src/prolog/indexing.rs @@ -63,11 +63,11 @@ impl CodeOffsets { let is_initial_index = self.lists.is_empty(); self.lists.push(Self::add_index(is_initial_index, index)); } - &Term::Constant(_, Constant::String(n, ref s)) => { + &Term::Constant(_, Constant::String(ref s)) => { let is_initial_index = self.lists.is_empty(); self.lists.push(Self::add_index(is_initial_index, index)); - let constant = Constant::String(n, s.clone()); + let constant = Constant::String(s.clone()); let code = self.constants.entry(constant).or_insert(Vec::new()); let is_initial_index = code.is_empty(); @@ -75,9 +75,11 @@ impl CodeOffsets { } &Term::Constant(_, ref constant) => { if let Constant::Atom(ref name, _) = constant { - if !name.as_str().is_empty() && name.as_str().chars().skip(1).next().is_none() { + if name.is_char() { let c = name.as_str().chars().next().unwrap(); - let code = self.constants.entry(Constant::Char(c)).or_insert(vec![]); + let code = self.constants + .entry(Constant::Char(c)) + .or_insert(vec![]); code.push(Self::add_index(code.is_empty(), index)); } diff --git a/src/prolog/instructions.rs b/src/prolog/instructions.rs index 31d9dc4a..eb6db521 100644 --- a/src/prolog/instructions.rs +++ b/src/prolog/instructions.rs @@ -2,28 +2,29 @@ use prolog_parser::ast::*; use crate::prolog::clause_types::*; use crate::prolog::forms::*; +use crate::prolog::machine::heap::*; use crate::prolog::machine::machine_errors::MachineStub; use crate::prolog::machine::machine_indices::*; - use crate::prolog::rug::Integer; use indexmap::IndexMap; use std::collections::VecDeque; +use std::rc::Rc; fn reg_type_into_functor(r: RegType) -> MachineStub { match r { - RegType::Temp(r) => functor!("x", 1, [heap_integer!(Integer::from(r))]), - RegType::Perm(r) => functor!("y", 1, [heap_integer!(Integer::from(r))]), + RegType::Temp(r) => functor!("x", [integer(r)]), + RegType::Perm(r) => functor!("y", [integer(r)]), } } impl Level { fn into_functor(self) -> MachineStub { match self { - Level::Root => functor!("level", 1, [heap_atom!("root")]), - Level::Shallow => functor!("level", 1, [heap_atom!("shallow")]), - Level::Deep => functor!("level", 1, [heap_atom!("deep")]), + Level::Root => functor!("level", [atom("root")]), + Level::Shallow => functor!("level", [atom("shallow")]), + Level::Deep => functor!("level", [atom("deep")]), } } } @@ -31,11 +32,15 @@ impl Level { impl ArithmeticTerm { fn into_functor(&self) -> MachineStub { match self { - &ArithmeticTerm::Reg(r) => reg_type_into_functor(r), + &ArithmeticTerm::Reg(r) => { + reg_type_into_functor(r) + } &ArithmeticTerm::Interm(i) => { - functor!("intermediate", 1, [heap_integer!(Integer::from(i))]) + functor!("intermediate", [integer(i)]) + } + &ArithmeticTerm::Number(ref n) => { + vec![n.clone().into()] } - &ArithmeticTerm::Number(ref n) => vec![heap_con!(n.clone().to_constant())], } } } @@ -52,18 +57,20 @@ impl ChoiceInstruction { pub fn to_functor(&self) -> MachineStub { match self { &ChoiceInstruction::TryMeElse(offset) => { - functor!("try_me_else", 1, [heap_integer!(Integer::from(offset))]) + functor!("try_me_else", [integer(offset)]) } &ChoiceInstruction::RetryMeElse(offset) => { - functor!("retry_me_else", 1, [heap_integer!(Integer::from(offset))]) + functor!("retry_me_else", [integer(offset)]) + } + &ChoiceInstruction::TrustMe => { + functor!("trust_me") + } + &ChoiceInstruction::DefaultRetryMeElse(offset) => { + functor!("default_retry_me_else", [integer(offset)]) + } + &ChoiceInstruction::DefaultTrustMe => { + functor!("default_trust_me") } - &ChoiceInstruction::TrustMe => vec![heap_atom!("trust_me")], - &ChoiceInstruction::DefaultRetryMeElse(offset) => functor!( - "default_retry_me_else", - 1, - [heap_integer!(Integer::from(offset))] - ), - &ChoiceInstruction::DefaultTrustMe => vec![heap_atom!("default_trust_me")], } } } @@ -79,21 +86,20 @@ impl CutInstruction { pub fn to_functor(&self, h: usize) -> MachineStub { match self { &CutInstruction::Cut(r) => { - let mut stub = functor!("cut", 1, [heap_str!(h + 2)]); - stub.append(&mut reg_type_into_functor(r)); - stub + let rt_stub = reg_type_into_functor(r); + functor!("cut", [aux(h, 0)], [rt_stub]) } &CutInstruction::GetLevel(r) => { - let mut stub = functor!("get_level", 1, [heap_str!(h + 2)]); - stub.append(&mut reg_type_into_functor(r)); - stub + let rt_stub = reg_type_into_functor(r); + functor!("get_level", [aux(h, 0)], [rt_stub]) } &CutInstruction::GetLevelAndUnify(r) => { - let mut stub = functor!("get_level_and_unify", 1, [heap_str!(h + 2)]); - stub.append(&mut reg_type_into_functor(r)); - stub + let rt_stub = reg_type_into_functor(r); + functor!("get_level_and_unify", [aux(h, 0)], [rt_stub]) + } + &CutInstruction::NeckCut => { + functor!("neck_cut") } - &CutInstruction::NeckCut => vec![heap_atom!("neck_cut")], } } } @@ -122,13 +128,13 @@ impl IndexedChoiceInstruction { pub fn to_functor(&self) -> MachineStub { match self { &IndexedChoiceInstruction::Try(offset) => { - functor!("try", 1, [heap_integer!(Integer::from(offset))]) + functor!("try", [integer(offset)]) } &IndexedChoiceInstruction::Trust(offset) => { - functor!("trust", 1, [heap_integer!(Integer::from(offset))]) + functor!("trust", [integer(offset)]) } &IndexedChoiceInstruction::Retry(offset) => { - functor!("retry", 1, [heap_integer!(Integer::from(offset))]) + functor!("retry", [integer(offset)]) } } } @@ -219,15 +225,12 @@ fn arith_instr_unary_functor( t: usize, ) -> MachineStub { let at_stub = at.into_functor(); - - let mut stub = functor!( + + functor!( name, - 2, - [heap_cell!(h + 4), heap_integer!(Integer::from(t))] - ); - - stub.extend(at_stub.into_iter()); - stub + [aux(h, 0), integer(t)], + [at_stub] + ) } fn arith_instr_bin_functor( @@ -240,20 +243,11 @@ fn arith_instr_bin_functor( let at_1_stub = at_1.into_functor(); let at_2_stub = at_2.into_functor(); - let mut stub = functor!( - name, - 3, - [ - heap_cell!(h + 4), - heap_cell!(h + 4 + at_1_stub.len()), - heap_integer!(Integer::from(t)) - ] - ); - - stub.extend(at_1_stub.into_iter()); - stub.extend(at_2_stub.into_iter()); - - stub + functor!( + name, + [aux(h, 0), aux(h, 1), integer(t)], + [at_1_stub, at_2_stub] + ) } impl ArithmeticInstruction { @@ -319,17 +313,39 @@ impl ArithmeticInstruction { &ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => { arith_instr_bin_functor(h, "gcd", at_1, at_2, t) } - &ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", at, t), - &ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t), - &ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t), - &ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t), - &ArithmeticInstruction::Log(ref at, t) => arith_instr_unary_functor(h, "log", at, t), - &ArithmeticInstruction::Exp(ref at, t) => arith_instr_unary_functor(h, "exp", at, t), - &ArithmeticInstruction::ACos(ref at, t) => arith_instr_unary_functor(h, "acos", at, t), - &ArithmeticInstruction::ASin(ref at, t) => arith_instr_unary_functor(h, "asin", at, t), - &ArithmeticInstruction::ATan(ref at, t) => arith_instr_unary_functor(h, "atan", at, t), - &ArithmeticInstruction::Sqrt(ref at, t) => arith_instr_unary_functor(h, "sqrt", at, t), - &ArithmeticInstruction::Abs(ref at, t) => arith_instr_unary_functor(h, "abs", at, t), + &ArithmeticInstruction::Sign(ref at, t) => { + arith_instr_unary_functor(h, "sign", at, t) + } + &ArithmeticInstruction::Cos(ref at, t) => { + arith_instr_unary_functor(h, "cos", at, t) + } + &ArithmeticInstruction::Sin(ref at, t) => { + arith_instr_unary_functor(h, "sin", at, t) + } + &ArithmeticInstruction::Tan(ref at, t) => { + arith_instr_unary_functor(h, "tan", at, t) + } + &ArithmeticInstruction::Log(ref at, t) => { + arith_instr_unary_functor(h, "log", at, t) + } + &ArithmeticInstruction::Exp(ref at, t) => { + arith_instr_unary_functor(h, "exp", at, t) + } + &ArithmeticInstruction::ACos(ref at, t) => { + arith_instr_unary_functor(h, "acos", at, t) + } + &ArithmeticInstruction::ASin(ref at, t) => { + arith_instr_unary_functor(h, "asin", at, t) + } + &ArithmeticInstruction::ATan(ref at, t) => { + arith_instr_unary_functor(h, "atan", at, t) + } + &ArithmeticInstruction::Sqrt(ref at, t) => { + arith_instr_unary_functor(h, "sqrt", at, t) + } + &ArithmeticInstruction::Abs(ref at, t) => { + arith_instr_unary_functor(h, "abs", at, t) + } &ArithmeticInstruction::Float(ref at, t) => { arith_instr_unary_functor(h, "float", at, t) } @@ -345,8 +361,12 @@ impl ArithmeticInstruction { &ArithmeticInstruction::Floor(ref at, t) => { arith_instr_unary_functor(h, "floor", at, t) } - &ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor(h, "-", at, t), - &ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor(h, "+", at, t), + &ArithmeticInstruction::Neg(ref at, t) => { + arith_instr_unary_functor(h, "-", at, t) + } + &ArithmeticInstruction::Plus(ref at, t) => { + arith_instr_unary_functor(h, "+", at, t) + } &ArithmeticInstruction::BitwiseComplement(ref at, t) => { arith_instr_unary_functor(h, "\\", at, t) } @@ -378,29 +398,23 @@ impl ControlInstruction { pub fn to_functor(&self) -> MachineStub { match self { &ControlInstruction::Allocate(num_frames) => { - functor!("allocate", 1, [heap_integer!(Integer::from(num_frames))]) - } - &ControlInstruction::CallClause(ref ct, arity, _, false, _) => functor!( - "call", - 2, - [ - heap_con!(Constant::Atom(ct.name(), None)), - heap_integer!(Integer::from(arity)) - ] - ), - &ControlInstruction::CallClause(ref ct, arity, _, true, _) => functor!( - "execute", - 2, - [ - heap_con!(Constant::Atom(ct.name(), None)), - heap_integer!(Integer::from(arity)) - ] - ), - &ControlInstruction::Deallocate => vec![heap_atom!("deallocate")], + functor!("allocate", [integer(num_frames)]) + } + &ControlInstruction::CallClause(ref ct, arity, _, false, _) => { + functor!("call", [clause_name(ct.name()), integer(arity)]) + } + &ControlInstruction::CallClause(ref ct, arity, _, true, _) => { + functor!("execute", [clause_name(ct.name()), integer(arity)]) + } + &ControlInstruction::Deallocate => { + functor!("deallocate") + } &ControlInstruction::JmpBy(_, offset, ..) => { - functor!("jmp_by", 1, [heap_integer!(Integer::from(offset))]) + functor!("jmp_by", [integer(offset)]) + } + &ControlInstruction::Proceed => { + functor!("proceed") } - &ControlInstruction::Proceed => vec![heap_atom!("proceed")], } } } @@ -420,26 +434,27 @@ impl From for Line { impl IndexingInstruction { pub fn to_functor(&self) -> MachineStub { match self { - &IndexingInstruction::SwitchOnTerm(vars, constants, lists, structures) => functor!( - "switch_on_term", - 4, - [ - heap_integer!(Integer::from(vars)), - heap_integer!(Integer::from(constants)), - heap_integer!(Integer::from(lists)), - heap_integer!(Integer::from(structures)) - ] - ), - &IndexingInstruction::SwitchOnConstant(constants, _) => functor!( - "switch_on_constant", - 1, - [heap_integer!(Integer::from(constants))] - ), - &IndexingInstruction::SwitchOnStructure(structures, _) => functor!( - "switch_on_structure", - 1, - [heap_integer!(Integer::from(structures))] - ), + &IndexingInstruction::SwitchOnTerm(vars, constants, lists, structures) => { + functor!( + "switch_on_term", + [integer(vars), + integer(constants), + integer(lists), + integer(structures)] + ) + } + &IndexingInstruction::SwitchOnConstant(constants, _) => { + functor!( + "switch_on_constant", + [integer(constants)] + ) + } + &IndexingInstruction::SwitchOnStructure(structures, _) => { + functor!( + "switch_on_structure", + [integer(structures)] + ) + } } } } @@ -461,86 +476,85 @@ pub enum FactInstruction { impl FactInstruction { pub fn to_functor(&self, h: usize) -> MachineStub { match self { - &FactInstruction::GetConstant(lvl, ref constant, r) => { - let mut stub = functor!( + &FactInstruction::GetConstant(lvl, ref c, r) => { + let lvl_stub = lvl.into_functor(); + let rt_stub = reg_type_into_functor(r); + + functor!( "get_constant", - 3, - [ - heap_str!(h + 4), - heap_con!(constant.clone()), - heap_str!(h + 6) - ] - ); - - stub.append(&mut lvl.into_functor()); - stub.append(&mut reg_type_into_functor(r)); - - stub + [aux(h, 0), constant(c), aux(h, 1)], + [lvl_stub, rt_stub] + ) } &FactInstruction::GetList(lvl, r) => { - let mut stub = functor!("get_list", 2, [heap_str!(h + 3), heap_str!(h + 5)]); - stub.append(&mut lvl.into_functor()); - stub.append(&mut reg_type_into_functor(r)); + let lvl_stub = lvl.into_functor(); + let rt_stub = reg_type_into_functor(r); - stub + functor!( + "get_list", + [aux(h, 0), aux(h, 1)], + [lvl_stub, rt_stub] + ) } &FactInstruction::GetStructure(ref ct, arity, r) => { - let mut stub = functor!( - "get_structure", - 3, - [ - heap_con!(Constant::Atom(ct.name(), None)), - heap_integer!(Integer::from(arity)), - heap_str!(h + 4) - ] - ); - stub.append(&mut reg_type_into_functor(r)); + let rt_stub = reg_type_into_functor(r); - stub + functor!( + "get_structure", + [clause_name(ct.name()), integer(arity), aux(h, 0)], + [rt_stub] + ) } &FactInstruction::GetValue(r, arg) => { - let mut stub = functor!( - "get_value", - 2, - [heap_str!(h + 3), heap_integer!(Integer::from(arg))] - ); - stub.append(&mut reg_type_into_functor(r)); + let rt_stub = reg_type_into_functor(r); - stub + functor!( + "get_value", + [aux(h, 0), integer(arg)], + [rt_stub] + ) } &FactInstruction::GetVariable(r, arg) => { - let mut stub = functor!( - "get_variable", - 2, - [heap_str!(h + 3), heap_integer!(Integer::from(arg))] - ); - stub.append(&mut reg_type_into_functor(r)); + let rt_stub = reg_type_into_functor(r); - stub + functor!( + "get_variable", + [aux(h, 0), integer(arg)], + [rt_stub] + ) } - &FactInstruction::UnifyConstant(ref constant) => { - functor!("unify_constant", 1, [heap_con!(constant.clone())]) + &FactInstruction::UnifyConstant(ref c) => { + functor!("unify_constant", [constant(c)], []) } &FactInstruction::UnifyLocalValue(r) => { - let mut stub = functor!("unify_local_value", 1, [heap_str!(h + 2)]); - stub.append(&mut reg_type_into_functor(r)); - - stub + let rt_stub = reg_type_into_functor(r); + + functor!( + "unify_local_value", + [aux(h, 0)], + [rt_stub] + ) } &FactInstruction::UnifyVariable(r) => { - let mut stub = functor!("unify_variable", 1, [heap_str!(h + 2)]); - stub.append(&mut reg_type_into_functor(r)); + let rt_stub = reg_type_into_functor(r); - stub + functor!( + "unify_variable", + [aux(h, 0)], + [rt_stub] + ) } &FactInstruction::UnifyValue(r) => { - let mut stub = functor!("unify_value", 1, [heap_str!(h + 2)]); - stub.append(&mut reg_type_into_functor(r)); - - stub + let rt_stub = reg_type_into_functor(r); + + functor!( + "unify_value", + [aux(h, 0)], + [rt_stub] + ) } &FactInstruction::UnifyVoid(vars) => { - functor!("unify_void", 1, [heap_integer!(Integer::from(vars))]) + functor!("unify_void", [integer(vars)]) } } } @@ -567,103 +581,96 @@ impl QueryInstruction { match self { &QueryInstruction::PutUnsafeValue(norm, arg) => functor!( "put_unsafe_value", - 2, - [ - heap_integer!(Integer::from(norm)), - heap_integer!(Integer::from(arg)) - ] + [integer(norm), integer(arg)] ), - &QueryInstruction::PutConstant(lvl, ref constant, r) => { - let mut stub = functor!( - "put_constant", - 3, - [ - heap_str!(h + 4), - heap_con!(constant.clone()), - heap_str!(h + 6) - ] - ); - - stub.append(&mut lvl.into_functor()); - stub.append(&mut reg_type_into_functor(r)); + &QueryInstruction::PutConstant(lvl, ref c, r) => { + let lvl_stub = lvl.into_functor(); + let rt_stub = reg_type_into_functor(r); - stub + functor!( + "put_constant", + [aux(h, 0), constant(c), aux(h, 1)], + [lvl_stub, rt_stub] + ) } &QueryInstruction::PutList(lvl, r) => { - let mut stub = functor!("put_list", 2, [heap_str!(h + 3), heap_str!(h + 5)]); - - stub.append(&mut lvl.into_functor()); - stub.append(&mut reg_type_into_functor(r)); - - stub + let lvl_stub = lvl.into_functor(); + let rt_stub = reg_type_into_functor(r); + + functor!( + "put_list", + [aux(h, 0), aux(h, 1)], + [lvl_stub, rt_stub] + ) } &QueryInstruction::PutStructure(ref ct, arity, r) => { - let mut stub = functor!( - "put_structure", - 3, - [ - heap_con!(Constant::Atom(ct.name(), None)), - heap_integer!(Integer::from(arity)), - heap_str!(h + 4) - ] - ); + let rt_stub = reg_type_into_functor(r); - stub.append(&mut reg_type_into_functor(r)); - stub + functor!( + "put_structure", + [clause_name(ct.name()), integer(arity), aux(h, 0)], + [rt_stub] + ) } &QueryInstruction::PutValue(r, arg) => { - let mut stub = functor!( - "put_value", - 2, - [heap_str!(h + 3), heap_integer!(Integer::from(arg))] - ); + let rt_stub = reg_type_into_functor(r); - stub.append(&mut reg_type_into_functor(r)); - stub + functor!( + "put_value", + [aux(h, 0), integer(arg)], + [rt_stub] + ) } &QueryInstruction::GetVariable(r, arg) => { - let mut stub = functor!( - "get_variable", - 2, - [heap_str!(h + 3), heap_integer!(Integer::from(arg))] - ); + let rt_stub = reg_type_into_functor(r); - stub.append(&mut reg_type_into_functor(r)); - stub + functor!( + "get_variable", + [aux(h, 0), integer(arg)], + [rt_stub] + ) } &QueryInstruction::PutVariable(r, arg) => { - let mut stub = functor!( - "put_variable", - 2, - [heap_str!(h + 3), heap_integer!(Integer::from(arg))] - ); + let rt_stub = reg_type_into_functor(r); - stub.append(&mut reg_type_into_functor(r)); - stub + functor!( + "put_variable", + [aux(h, 0), integer(arg)], + [rt_stub] + ) } - &QueryInstruction::SetConstant(ref constant) => { - functor!("set_constant", 1, [heap_con!(constant.clone())]) + &QueryInstruction::SetConstant(ref c) => { + functor!("set_constant", [constant(c)], []) } &QueryInstruction::SetLocalValue(r) => { - let mut stub = functor!("set_local_value", 1, [heap_str!(h + 2)]); - - stub.append(&mut reg_type_into_functor(r)); - stub + let rt_stub = reg_type_into_functor(r); + + functor!( + "set_local_value", + [aux(h, 0)], + [rt_stub] + ) } &QueryInstruction::SetVariable(r) => { - let mut stub = functor!("set_variable", 1, [heap_str!(h + 2)]); + let rt_stub = reg_type_into_functor(r); - stub.append(&mut reg_type_into_functor(r)); - stub + functor!( + "set_variable", + [aux(h, 0)], + [rt_stub] + ) } &QueryInstruction::SetValue(r) => { - let mut stub = functor!("set_value", 1, [heap_str!(h + 2)]); + let rt_stub = reg_type_into_functor(r); - stub.append(&mut reg_type_into_functor(r)); - stub + functor!( + "set_value", + [aux(h, 0)], + [rt_stub] + ) } &QueryInstruction::SetVoid(vars) => { - functor!("set_void", 1, [heap_integer!(Integer::from(vars))]) + functor!("set_void", [integer(vars)]) } } } diff --git a/src/prolog/machine/arithmetic_ops.rs b/src/prolog/machine/arithmetic_ops.rs new file mode 100644 index 00000000..647c88b8 --- /dev/null +++ b/src/prolog/machine/arithmetic_ops.rs @@ -0,0 +1,786 @@ +use crate::prolog_parser::ast::*; + +use crate::prolog::arithmetic::*; +use crate::prolog::clause_types::*; +use crate::prolog::forms::*; +use crate::prolog::machine::machine_errors::*; +use crate::prolog::machine::machine_indices::*; +use crate::prolog::machine::machine_state::*; +use crate::prolog::ordered_float::*; +use crate::prolog::rug::{Integer, Rational}; + +use std::cmp; +use std::f64; +use std::mem; +use std::rc::Rc; + +#[macro_export] +macro_rules! try_numeric_result { + ($s: ident, $e: expr, $caller: expr) => ( + match $e { + Ok(val) => { + Ok(val) + } + Err(e) => { + let caller_copy = + $caller.iter().map(|v| v.context_free_clone()).collect(); + + Err($s.error_form(MachineError::evaluation_error(e), caller_copy)) + } + } + ); +} + +impl MachineState { + pub(crate) + fn get_number(&mut self, at: &ArithmeticTerm) -> Result { + match at { + &ArithmeticTerm::Reg(r) => { + self.arith_eval_by_metacall(r) + } + &ArithmeticTerm::Interm(i) => Ok(mem::replace( + &mut self.interms[i - 1], + Number::Integer(Rc::new(Integer::from(0))), + )), + &ArithmeticTerm::Number(ref n) => { + Ok(n.clone()) + } + } + } + + pub(super) + fn rational_from_number( + &self, + n: Number, + ) -> Result, MachineError> { + match n { + Number::Rational(r) => { + Ok(r) + } + Number::Float(OrderedFloat(f)) => { + match Rational::from_f64(f) { + Some(r) => { + Ok(Rc::new(r)) + } + None => { + Err(MachineError::instantiation_error()) + } + } + } + Number::Integer(n) => { + Ok(Rc::new(Rational::from(&*n))) + } + } + } + + pub(crate) + fn get_rational( + &mut self, + at: &ArithmeticTerm, + caller: MachineStub, + ) -> Result<(Rc, MachineStub), MachineStub> { + let n = self.get_number(at)?; + + match self.rational_from_number(n) { + Ok(r) => Ok((r, caller)), + Err(e) => Err(self.error_form(e, caller)) + } + } + + pub(crate) + fn arith_eval_by_metacall(&self, r: RegType) -> Result { + let a = self[r].clone(); + + let caller = MachineError::functor_stub(clause_name!("(is)"), 2); + let mut interms: Vec = Vec::with_capacity(64); + + for addr in self.post_order_iter(a) { + match self.heap.index_addr(&addr).as_ref() { + &HeapCellValue::NamedStr(2, ref name, _) => { + let a2 = interms.pop().unwrap(); + let a1 = interms.pop().unwrap(); + + match name.as_str() { + "+" => interms.push(try_numeric_result!(self, a1 + a2, caller)?), + "-" => interms.push(try_numeric_result!(self, a1 - a2, caller)?), + "*" => interms.push(try_numeric_result!(self, a1 * a2, caller)?), + "/" => interms.push(self.div(a1, a2)?), + "**" => interms.push(self.pow(a1, a2, "(is)")?), + "^" => interms.push(self.int_pow(a1, a2)?), + "max" => interms.push(self.max(a1, a2)?), + "min" => interms.push(self.min(a1, a2)?), + "rdiv" => { + let r1 = self.rational_from_number(a1); + let r2 = r1.and_then(|r1| { + self.rational_from_number(a2).map(|r2| (r1, r2)) + }); + + match r2 { + Ok((r1, r2)) => { + let result = Number::Rational(Rc::new(self.rdiv(r1, r2)?)); + interms.push(result); + } + Err(e) => { + return Err(self.error_form(e, caller)); + } + } + } + "//" => interms.push(Number::Integer(Rc::new(self.idiv(a1, a2)?))), + "div" => interms.push(Number::Integer(Rc::new(self.int_floor_div(a1, a2)?))), + ">>" => interms.push(Number::Integer(Rc::new(self.shr(a1, a2)?))), + "<<" => interms.push(Number::Integer(Rc::new(self.shl(a1, a2)?))), + "/\\" => interms.push(Number::Integer(Rc::new(self.and(a1, a2)?))), + "\\/" => interms.push(Number::Integer(Rc::new(self.or(a1, a2)?))), + "xor" => interms.push(Number::Integer(Rc::new(self.xor(a1, a2)?))), + "mod" => interms.push(Number::Integer(Rc::new(self.modulus(a1, a2)?))), + "rem" => interms.push(Number::Integer(Rc::new(self.remainder(a1, a2)?))), + "atan2" => interms.push(Number::Float(OrderedFloat(self.atan2(a1, a2)?))), + "gcd" => interms.push(Number::Integer(Rc::new(self.gcd(a1, a2)?))), + _ => { + return Err(self.error_form(MachineError::instantiation_error(), caller)) + } + } + } + &HeapCellValue::NamedStr(1, ref name, _) => { + let a1 = interms.pop().unwrap(); + + match name.as_str() { + "-" => interms.push(-a1), + "+" => interms.push(a1), + "cos" => interms.push(Number::Float(OrderedFloat(self.cos(a1)?))), + "sin" => interms.push(Number::Float(OrderedFloat(self.sin(a1)?))), + "tan" => interms.push(Number::Float(OrderedFloat(self.tan(a1)?))), + "sqrt" => interms.push(Number::Float(OrderedFloat(self.sqrt(a1)?))), + "log" => interms.push(Number::Float(OrderedFloat(self.log(a1)?))), + "exp" => interms.push(Number::Float(OrderedFloat(self.exp(a1)?))), + "acos" => interms.push(Number::Float(OrderedFloat(self.acos(a1)?))), + "asin" => interms.push(Number::Float(OrderedFloat(self.asin(a1)?))), + "atan" => interms.push(Number::Float(OrderedFloat(self.atan(a1)?))), + "abs" => interms.push(a1.abs()), + "float" => interms.push(Number::Float(OrderedFloat(self.float(a1)?))), + "truncate" => interms.push(Number::Integer(Rc::new(self.truncate(a1)))), + "round" => interms.push(Number::Integer(Rc::new(self.round(a1)?))), + "ceiling" => interms.push(Number::Integer(Rc::new(self.ceiling(a1)))), + "floor" => interms.push(Number::Integer(Rc::new(self.floor(a1)))), + "\\" => interms.push(Number::Integer(Rc::new(self.bitwise_complement(a1)?))), + "sign" => interms.push(Number::Integer(Rc::new(self.sign(a1)))), + _ => { + return Err(self.error_form(MachineError::instantiation_error(), caller)); + } + } + } + &HeapCellValue::Integer(ref n) => { + interms.push(Number::Integer(n.clone())) + } + &HeapCellValue::Addr(Addr::Float(n)) => { + interms.push(Number::Float(n)) + } + &HeapCellValue::Rational(ref n) => { + interms.push(Number::Rational(n.clone())) + } + &HeapCellValue::Atom(ref name, _) if name.as_str() == "pi" => { + interms.push(Number::Float(OrderedFloat(f64::consts::PI))) + } + _ => { + return Err(self.error_form( + MachineError::instantiation_error(), + caller, + )); + } + } + } + + Ok(interms.pop().unwrap()) + } + + pub(crate) + fn rdiv(&self, r1: Rc, r2: Rc) -> Result { + if &*r2 == &0 { + let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2); + Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) + } else { + Ok(Rational::from(&*r1 / &*r2)) + } + } + + pub(crate) + fn int_floor_div(&self, n1: Number, n2: Number) -> Result { + match n1 / n2 { + Ok(result) => Ok(rnd_i(&result).to_owned()), + Err(e) => { + let stub = MachineError::functor_stub(clause_name!("(div)"), 2); + Err(self.error_form( + MachineError::evaluation_error( + e + ), + stub + )) + } + } + } + + pub(crate) + fn idiv(&self, n1: Number, n2: Number) -> Result { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + let stub = MachineError::functor_stub(clause_name!("(//)"), 2); + + Err(self.error_form( + MachineError::evaluation_error( + EvalError::ZeroDivisor + ), + stub, + )) + } else { + Ok(<(Integer, Integer)>::from(n1.div_rem_ref(&*n2)).0) + } + } + (Number::Integer(_), n2) => { + let stub = MachineError::functor_stub(clause_name!("(//)"), 2); + + Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n2, + ), + stub, + )) + } + (n1, _) => { + let stub = MachineError::functor_stub(clause_name!("(//)"), 2); + + Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n1, + ), + stub, + )) + } + } + } + + pub(crate) + fn div(&self, n1: Number, n2: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(/)"), 2); + + if n2.is_zero() { + Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) + } else { + try_numeric_result!(self, n1 / n2, stub) + } + } + + pub(crate) + fn atan2(&self, n1: Number, n2: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + + if n1.is_zero() && n2.is_zero() { + Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)) + } else { + let f1 = self.float(n1)?; + let f2 = self.float(n2)?; + + self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.atan2(f2)) + } + } + + pub(crate) + fn int_pow(&self, n1: Number, n2: Number) -> Result { + if n1.is_zero() && n2.is_negative() { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); + } + + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => { + if &*n1 != &1 && &*n2 < &0 { + let n = Number::Integer(n1); + let stub = MachineError::functor_stub(clause_name!("^"), 2); + + Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Float, + n + ), + stub, + )) + } else { + Ok(Number::Integer(Rc::new(binary_pow(n1.as_ref().clone(), n2.as_ref())))) + } + } + (n1, Number::Integer(n2)) => { + let f1 = self.float(n1)?; + let f2 = self.float(Number::Integer(n2))?; + + self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) + .map(|f| Number::Float(OrderedFloat(f))) + } + (n1, n2) => { + let f2 = self.float(n2)?; + + if n1.is_negative() && f2 != f2.floor() { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + return Err( + self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub) + ); + } + + let f1 = self.float(n1)?; + self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) + .map(|f| Number::Float(OrderedFloat(f))) + } + } + } + + pub(crate) + fn gcd(&self, n1: Number, n2: Number) -> Result { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Integer::from(n1.gcd_ref(&n2))) + } + (Number::Float(f), _) | (_, Number::Float(f)) => { + let n = Number::Float(f); + let stub = MachineError::functor_stub(clause_name!("gcd"), 2); + + Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n + ), + stub, + )) + } + (Number::Rational(r), _) | (_, Number::Rational(r)) => { + let n = Number::Rational(r); + let stub = MachineError::functor_stub(clause_name!("gcd"), 2); + + Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n, + ), + stub, + )) + } + } + } + + pub(crate) + fn float_pow(&self, n1: Number, n2: Number) -> Result { + let f1 = result_f(&n1, rnd_f); + let f2 = result_f(&n2, rnd_f); + + let stub = MachineError::functor_stub(clause_name!("(**)"), 2); + + let f1 = try_numeric_result!(self, f1, stub)?; + let f2 = try_numeric_result!(self, f2, stub)?; + + let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))), rnd_f); + + Ok(Number::Float(OrderedFloat(try_numeric_result!( + self, result, stub + )?))) + } + + pub(crate) + fn pow(&self, n1: Number, n2: Number, culprit: &'static str) -> Result { + if n2.is_negative() && n1.is_zero() { + let stub = MachineError::functor_stub(clause_name!(culprit), 2); + return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); + } + + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::Integer(Rc::new(binary_pow(n1.as_ref().clone(), &*n2)))) + } + (n1, n2) => { + self.float_pow(n1, n2) + } + } + } + + pub(crate) + fn unary_float_fn_template(&self, n1: Number, f: FloatFn) -> Result + where + FloatFn: Fn(f64) -> f64, + { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + + let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?; + let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f); + + try_numeric_result!(self, f1, stub) + } + + pub(crate) + fn sin(&self, n1: Number) -> Result { + self.unary_float_fn_template(n1, |f| f.sin()) + } + + pub(crate) + fn cos(&self, n1: Number) -> Result { + self.unary_float_fn_template(n1, |f| f.cos()) + } + + pub(crate) + fn tan(&self, n1: Number) -> Result { + self.unary_float_fn_template(n1, |f| f.tan()) + } + + pub(crate) + fn log(&self, n1: Number) -> Result { + self.unary_float_fn_template(n1, |f| f.log(f64::consts::E)) + } + + pub(crate) + fn exp(&self, n1: Number) -> Result { + self.unary_float_fn_template(n1, |f| f.exp()) + } + + pub(crate) + fn asin(&self, n1: Number) -> Result { + self.unary_float_fn_template(n1, |f| f.asin()) + } + + pub(crate) + fn acos(&self, n1: Number) -> Result { + self.unary_float_fn_template(n1, |f| f.acos()) + } + + pub(crate) + fn atan(&self, n1: Number) -> Result { + self.unary_float_fn_template(n1, |f| f.atan()) + } + + pub(crate) + fn sqrt(&self, n1: Number) -> Result { + if n1.is_negative() { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); + } + + self.unary_float_fn_template(n1, |f| f.sqrt()) + } + + pub(crate) + fn float(&self, n: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + try_numeric_result!(self, result_f(&n, rnd_f), stub) + } + + pub(crate) + fn floor(&self, n1: Number) -> Integer { + rnd_i(&n1).to_owned() + } + + pub(crate) + fn ceiling(&self, n1: Number) -> Integer { + -self.floor(-n1) + } + + pub(crate) + fn truncate(&self, n: Number) -> Integer { + if n.is_negative() { + -self.floor(n.abs()) + } else { + self.floor(n) + } + } + + pub(crate) + fn round(&self, n: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + + let result = n + Number::Float(OrderedFloat(0.5f64)); + let result = try_numeric_result!(self, result, stub)?; + + Ok(self.floor(result)) + } + + pub(crate) + fn shr(&self, n1: Number, n2: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(>>)"), 2); + + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => + match n2.to_u32() { + Some(n2) => Ok(Integer::from(&*n1 >> n2)), + _ => Ok(Integer::from(&*n1 >> u32::max_value())), + }, + (Number::Integer(_), n2) => Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n2, + ), + stub, + )), + (n1, _) => Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n1, + ), + stub, + )), + } + } + + pub(crate) + fn shl(&self, n1: Number, n2: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(<<)"), 2); + + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { + Some(n2) => Ok(Integer::from(&*n1 << n2)), + _ => Ok(Integer::from(&*n1 << u32::max_value())), + }, + (Number::Integer(_), n2) => Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n2, + ), + stub, + )), + (n1, _) => Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n1, + ), + stub, + )), + } + } + + pub(crate) + fn bitwise_complement(&self, n1: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(\\)"), 2); + + match n1 { + Number::Integer(n1) => Ok(Integer::from(!&*n1)), + _ => Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n1, + ), + stub, + )), + } + } + + pub(crate) + fn xor(&self, n1: Number, n2: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(xor)"), 2); + + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Integer::from(&*n1 ^ &*n2)) + } + (Number::Integer(_), n2) => { + Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n2 + ), + stub, + )) + } + (n1, _) => { + Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n1 + ), + stub, + )) + } + } + } + + pub(crate) + fn and(&self, n1: Number, n2: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(/\\)"), 2); + + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => Ok(Integer::from(&*n1 & &*n2)), + (Number::Integer(_), n2) => Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n2, + ), + stub, + )), + (n1, _) => Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n1, + ), + stub, + )), + } + } + + pub(crate) + fn modulus(&self, x: Number, y: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(mod)"), 2); + + match (x, y) { + (Number::Integer(x), Number::Integer(y)) => { + if &*y == &0 { + Err(self.error_form( + MachineError::evaluation_error(EvalError::ZeroDivisor), + stub, + )) + } else { + Ok(<(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1) + } + } + (Number::Integer(_), n2) => Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n2, + ), + stub, + )), + (n1, _) => Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n1, + ), + stub, + )), + } + } + + pub(crate) + fn max(&self, n1: Number, n2: Number) -> Result { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => { + if n1 > n2 { + Ok(Number::Integer(n1)) + } else { + Ok(Number::Integer(n2)) + } + } + (n1, n2) => { + let stub = MachineError::functor_stub(clause_name!("max"), 2); + + let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?; + let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?; + + Ok(Number::Float(cmp::max(OrderedFloat(f1), OrderedFloat(f2)))) + } + } + } + + pub(crate) + fn min(&self, n1: Number, n2: Number) -> Result { + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => { + if n1 < n2 { + Ok(Number::Integer(n1)) + } else { + Ok(Number::Integer(n2)) + } + } + (n1, n2) => { + let stub = MachineError::functor_stub(clause_name!("max"), 2); + + let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?; + let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?; + + Ok(Number::Float(cmp::min(OrderedFloat(f1), OrderedFloat(f2)))) + } + } + } + + pub(crate) + fn sign(&self, n: Number) -> Integer { + if n.is_positive() { + Integer::from(1) + } else if n.is_negative() { + Integer::from(-1) + } else { + Integer::from(0) + } + } + + pub(crate) + fn remainder(&self, n1: Number, n2: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(rem)"), 2); + + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(self + .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) + } else { + Ok(Integer::from(&*n1 % &*n2)) + } + } + (Number::Integer(_), n2) => Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n2, + ), + stub, + )), + (n1, _) => Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n1, + ), + stub, + )), + } + } + + pub(crate) + fn or(&self, n1: Number, n2: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(\\/)"), 2); + + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Integer::from(&*n1 | &*n2)) + } + (Number::Integer(_), n2) => { + Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n2, + ), + stub, + )) + } + (n1, _) => { + Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n1 + ), + stub, + )) + } + } + } +} diff --git a/src/prolog/machine/attributed_variables.rs b/src/prolog/machine/attributed_variables.rs index 44ebbe0b..f21c8926 100644 --- a/src/prolog/machine/attributed_variables.rs +++ b/src/prolog/machine/attributed_variables.rs @@ -1,5 +1,6 @@ use crate::prolog::machine::*; +use std::cmp::Ordering; use std::vec::IntoIter; pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl"); @@ -66,7 +67,7 @@ impl MachineState { .attr_var_init .bindings .iter() - .map(|(ref h, _)| Addr::AttrVar(*h)); + .map(|(ref h, _)| HeapCellValue::Addr(Addr::AttrVar(*h))); let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); @@ -74,7 +75,7 @@ impl MachineState { .attr_var_init .bindings .drain(0 ..) - .map(|(_, addr)| addr); + .map(|(_, addr)| HeapCellValue::Addr(addr)); let value_list_addr = Addr::HeapCell(self.heap.to_list(iter)); (var_list_addr, value_list_addr) @@ -100,7 +101,9 @@ impl MachineState { }) .collect(); - attr_vars.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2)); + attr_vars.sort_unstable_by(|a1, a2| { + self.compare_term_test(a1, a2).unwrap_or(Ordering::Less) + }); self.term_dedup(&mut attr_vars); attr_vars.into_iter() @@ -117,9 +120,9 @@ impl MachineState { } self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = - Addr::Con(Constant::CutPoint(self.b0)); + Addr::CutPoint(self.b0); self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = - Addr::Con(Constant::Usize(self.num_of_args)); + Addr::Usize(self.num_of_args); self.verify_attributes(); diff --git a/src/prolog/machine/copier.rs b/src/prolog/machine/copier.rs index a08cb87a..724b6c54 100644 --- a/src/prolog/machine/copier.rs +++ b/src/prolog/machine/copier.rs @@ -1,6 +1,8 @@ use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::stack::*; +use crate::prolog::machine::streams::*; +use std::mem; use std::ops::IndexMut; type Trail = Vec<(Ref, HeapCellValue)>; @@ -11,12 +13,13 @@ pub enum AttrVarPolicy { StripAttributes } -pub(crate) trait CopierTarget: IndexMut { - fn threshold(&self) -> usize; - fn push(&mut self, val: HeapCellValue); - fn store(&self, val: Addr) -> Addr; +pub(crate) +trait CopierTarget: IndexMut { fn deref(&self, val: Addr) -> Addr; + fn push(&mut self, val: HeapCellValue); fn stack(&mut self) -> &mut Stack; + fn store(&self, val: Addr) -> Addr; + fn threshold(&self) -> usize; } pub(crate) @@ -75,15 +78,15 @@ impl CopyTermState { *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold)); let ra = self.target[addr].as_addr(threshold); - let rd = self.target.store(self.target.deref(ra.clone())); + let rd = self.target.store(self.target.deref(ra)); - self.target.push(HeapCellValue::Addr(ra.clone())); + self.target.push(HeapCellValue::Addr(ra)); let hcv = HeapCellValue::Addr(self.target[addr + 1].as_addr(addr + 1)); self.target.push(hcv); - match rd.clone() { + match rd { Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { self.target[threshold] = HeapCellValue::Addr(rd) @@ -129,18 +132,18 @@ impl CopyTermState { fn copy_partial_string(&mut self, addr: usize, n: usize) { let threshold = self.target.threshold(); + let tail_addr = self.target[addr + 1].as_addr(addr + 1); + + let trail_item = mem::replace( + &mut self.target[addr + 1], + HeapCellValue::Addr(Addr::PStrLocation(threshold, 0)), + ); self.trail.push(( Ref::HeapCell(addr + 1), - self.target[addr + 1].clone(), + trail_item, )); - let tail_addr = self.target[addr + 1].as_addr(addr + 1); - - self.target[addr + 1] = HeapCellValue::Addr( - Addr::PStrLocation(threshold, 0) - ); - let pstr = match &self.target[addr] { HeapCellValue::PartialString(ref pstr) => { @@ -205,7 +208,7 @@ impl CopyTermState { if let AttrVarPolicy::DeepCopy = self.attr_var_policy { self.target.push(HeapCellValue::Addr(Addr::AttrVar(threshold))); - let list_val = self.target[h + 1].clone(); + let list_val = self.target[h + 1].context_free_clone(); self.target.push(list_val); } } @@ -214,9 +217,9 @@ impl CopyTermState { } fn copy_var(&mut self, addr: Addr) { - let rd = self.target.store(self.target.deref(addr.clone())); + let rd = self.target.store(self.target.deref(addr)); - match rd.clone() { + match rd { Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { *self.value_at_scan() = HeapCellValue::Addr(rd); self.scan += 1; @@ -232,7 +235,7 @@ impl CopyTermState { } fn copy_structure(&mut self, addr: usize) { - match self.target[addr].clone() { + match self.target[addr].context_free_clone() { HeapCellValue::NamedStr(arity, name, fixity) => { let threshold = self.target.threshold(); @@ -247,7 +250,7 @@ impl CopyTermState { self.target.push(HeapCellValue::NamedStr(arity, name, fixity)); for i in 0..arity { - let hcv = self.target[addr + 1 + i].clone(); + let hcv = self.target[addr + 1 + i].context_free_clone(); self.target.push(hcv); } } @@ -266,13 +269,18 @@ impl CopyTermState { while self.scan < self.target.threshold() { match self.value_at_scan() { - HeapCellValue::NamedStr(..) => { - self.scan += 1; - } - HeapCellValue::Addr(ref addr) => { - match addr.clone() { - Addr::Lis(addr) => { - self.copy_list(addr); + &mut HeapCellValue::Addr(addr) => { + match addr { + Addr::Con(h) => { + self.target.push(self.target[h].context_free_clone()); + self.scan += 1; + } + Addr::Stream(_) => { + self.target.push(HeapCellValue::Stream(Stream::null_stream())); + self.scan += 1; + } + Addr::Lis(h) => { + self.copy_list(h); } addr @ Addr::AttrVar(_) | addr @ Addr::HeapCell(_) @@ -285,12 +293,12 @@ impl CopyTermState { Addr::PStrLocation(addr, n) => { self.copy_partial_string_from(addr, n); } - Addr::Con(_) | Addr::DBRef(_) | Addr::Stream(_) => { + _ => { self.scan += 1; } } } - HeapCellValue::PartialString(_) => { + _ => { self.scan += 1; } } diff --git a/src/prolog/machine/dynamic_database.rs b/src/prolog/machine/dynamic_database.rs index e5151589..e82aaa04 100644 --- a/src/prolog/machine/dynamic_database.rs +++ b/src/prolog/machine/dynamic_database.rs @@ -41,12 +41,22 @@ impl Machine { let arity = self.machine_st[arity].clone(); let name = match self.machine_st.store(self.machine_st.deref(name)) { - Addr::Con(Constant::Atom(name, _)) => name, + Addr::Con(h) => + if let HeapCellValue::Atom(ref name, _) = &self.machine_st.heap[h] { + name.clone() + } else { + unreachable!() + }, _ => unreachable!(), }; let arity = match self.machine_st.store(self.machine_st.deref(arity)) { - Addr::Con(Constant::Integer(arity)) => arity.to_usize().unwrap(), + Addr::Con(h) => + if let HeapCellValue::Integer(ref arity) = &self.machine_st.heap[h] { + arity.to_usize().unwrap() + } else { + unreachable!() + }, _ => unreachable!(), }; @@ -91,7 +101,7 @@ impl Machine { let (name, arity) = self.get_predicate_key(name, arity); self.make_undefined(name.clone(), arity); - + self.indices.remove_code_index((name.clone(), arity)); self.indices.remove_clause_subsection(name.owning_module(), name, arity); } @@ -101,16 +111,21 @@ impl Machine { let module_addr = self.machine_st[module].clone(); let module_name = match self.machine_st.store(self.machine_st.deref(module_addr)) { - Addr::Con(Constant::Atom(module, _)) => match self.indices.modules.get_mut(&module) { - Some(ref mut module) => { - module.code_dir.remove(&(name.clone(), arity)); - module.module_decl.name.clone() - } - _ => { - self.machine_st.fail = true; - return; - } - }, + Addr::Con(h) => + if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] { + match self.indices.modules.get_mut(module) { + Some(ref mut module) => { + module.code_dir.remove(&(name.clone(), arity)); + module.module_decl.name.clone() + } + _ => { + self.machine_st.fail = true; + return; + } + } + } else { + unreachable!() + }, _ => unreachable!(), }; @@ -162,21 +177,34 @@ impl Machine { place.push_to_queue(&mut addrs, added_clause); self.print_new_dynamic_clause(addrs, name.clone(), arity) } - Err(err) => return self.machine_st.throw_exception(err), + Err(err) => { + return self.machine_st.throw_exception(err); + } }; - self.handle_eval_result_from_dynamic_compile(pred_str, name, arity, place.predicate_name()); + self.handle_eval_result_from_dynamic_compile( + pred_str, + name, + arity, + place.predicate_name(), + ); } fn set_module_atom_tbl(&mut self, module_addr: Addr, name: &mut ClauseName) -> bool { let atom_tbl = match self.machine_st.store(self.machine_st.deref(module_addr)) { - Addr::Con(Constant::Atom(module, _)) => match self.indices.modules.get(&module) { - Some(ref module) => module.atom_tbl.clone(), - None => { + Addr::Con(h) => + if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] { + match self.indices.modules.get(module) { + Some(ref module) => module.atom_tbl.clone(), + None => { + self.machine_st.fail = true; + return false; + } + } + } else { self.machine_st.fail = true; return false; - } - }, + }, _ => unreachable!(), }; @@ -204,7 +232,12 @@ impl Machine { fn retract_from_dynamic_predicate_in_module(&mut self) { let index = self.machine_st[temp_v!(3)].clone(); let index = match self.machine_st.store(self.machine_st.deref(index)) { - Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(), + Addr::Con(h) => + if let HeapCellValue::Integer(ref n) = &self.machine_st.heap[h] { + n.to_usize().unwrap() + } else { + unreachable!() + }, _ => unreachable!(), }; @@ -224,7 +257,9 @@ impl Machine { self.print_new_dynamic_clause(addrs, name.clone(), arity) } - Err(err) => return self.machine_st.throw_exception(err), + Err(err) => { + return self.machine_st.throw_exception(err); + } }; self.handle_eval_result_from_dynamic_compile( @@ -239,8 +274,15 @@ impl Machine { fn retract_from_dynamic_predicate(&mut self) { let index = self.machine_st[temp_v!(3)].clone(); let index = match self.machine_st.store(self.machine_st.deref(index)) { - Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(), - _ => unreachable!(), + Addr::Con(h) => + if let HeapCellValue::Integer(n) = &self.machine_st.heap[h] { + n.to_usize().unwrap() + } else { + unreachable!() + }, + _ => { + unreachable!() + } }; let (name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2)); @@ -257,7 +299,9 @@ impl Machine { self.print_new_dynamic_clause(addrs, name.clone(), arity) } - Err(err) => return self.machine_st.throw_exception(err), + Err(err) => { + return self.machine_st.throw_exception(err); + } }; self.handle_eval_result_from_dynamic_compile( diff --git a/src/prolog/machine/heap.rs b/src/prolog/machine/heap.rs index 17ccd387..d8d39036 100644 --- a/src/prolog/machine/heap.rs +++ b/src/prolog/machine/heap.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use crate::prolog_parser::ast::*; +use crate::prolog_parser::ast::Constant; use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::partial_string::*; @@ -140,17 +140,175 @@ impl HeapTemplate { #[inline] pub(crate) - fn push(&mut self, val: HeapCellValue) { + fn clone(&self, h: usize) -> HeapCellValue { + match &self[h] { + &HeapCellValue::Addr(addr) => { + HeapCellValue::Addr(addr) + } + &HeapCellValue::Atom(ref name, ref op) => { + HeapCellValue::Atom(name.clone(), op.clone()) + } + &HeapCellValue::DBRef(ref db_ref) => { + HeapCellValue::DBRef(db_ref.clone()) + } + &HeapCellValue::Integer(ref n) => { + HeapCellValue::Integer(n.clone()) + } + &HeapCellValue::NamedStr(arity, ref name, ref op) => { + HeapCellValue::NamedStr(arity, name.clone(), op.clone()) + } + &HeapCellValue::Rational(ref r) => { + HeapCellValue::Rational(r.clone()) + } + &HeapCellValue::PartialString(_) => { + HeapCellValue::Addr(Addr::PStrLocation(h, 0)) + } + &HeapCellValue::Stream(_) => { + HeapCellValue::Addr(Addr::Stream(h)) + } + } + } + + #[inline] + pub(crate) + fn put_constant(&mut self, c: Constant) -> Addr { + match c { + Constant::Atom(name, op) => { + Addr::Con(self.push(HeapCellValue::Atom(name, op))) + } + Constant::Char(c) => { + self.push(HeapCellValue::Addr(Addr::Char(c))); + Addr::Char(c) + } + Constant::CharCode(c) => { + self.push(HeapCellValue::Addr(Addr::CharCode(c))); + Addr::CharCode(c) + } + Constant::CutPoint(cp) => { + self.push(HeapCellValue::Addr(Addr::CutPoint(cp))); + Addr::CutPoint(cp) + } + Constant::EmptyList => { + self.push(HeapCellValue::Addr(Addr::EmptyList)); + Addr::EmptyList + } + Constant::Integer(n) => { + Addr::Con(self.push(HeapCellValue::Integer(n))) + } + Constant::Rational(r) => { + Addr::Con(self.push(HeapCellValue::Rational(r))) + } + Constant::Float(f) => { + self.push(HeapCellValue::Addr(Addr::Float(f))); + Addr::Float(f) + } + Constant::String(s) => { + let addr = self.allocate_pstr(&s); + let h = self.h(); + + self[h - 1] = HeapCellValue::Addr(Addr::EmptyList); + addr + } + Constant::Usize(n) => { + self.push(HeapCellValue::Addr(Addr::Usize(n))); + Addr::Usize(n) + } + } + } + + #[inline] + pub(crate) + fn push(&mut self, val: HeapCellValue) -> usize { + let h = self.h(); + unsafe { let new_top = self.buf.new_block(mem::size_of::()); ptr::write(self.buf.top as *mut _, val); self.buf.top = new_top; } + + h + } + + #[inline] + pub(crate) + fn rational_at(&self, h: usize) -> bool { + if let HeapCellValue::Rational(_) = &self[h] { + true + } else { + false + } + } + + #[inline] + pub(crate) + fn integer_at(&self, h: usize) -> bool { + if let HeapCellValue::Integer(_) = &self[h] { + true + } else { + false + } + } + + #[inline] + pub(crate) + fn atom_at(&self, h: usize) -> bool { + if let HeapCellValue::Atom(..) = &self[h] { + true + } else { + false + } } #[inline] pub(crate) - fn allocate_pstr(&mut self, mut src: &str) -> Option { + fn to_unifiable(&mut self, non_heap_value: HeapCellValue) -> Addr { + match non_heap_value { + HeapCellValue::Addr(addr) => { + addr + } + val @ HeapCellValue::Atom(..) + | val @ HeapCellValue::Integer(_) + | val @ HeapCellValue::DBRef(_) + | val @ HeapCellValue::Rational(_) => { + Addr::Con(self.push(val)) + } + val @ HeapCellValue::NamedStr(..) => { + Addr::Str(self.push(val)) + } + val @ HeapCellValue::Stream(..) => { + Addr::Stream(self.push(val)) + } + val @ HeapCellValue::PartialString(_) => { + let h = self.push(val); + self.push(HeapCellValue::Addr(Addr::EmptyList)); + + Addr::Con(h) + } + } + } + + #[inline] + pub(crate) + fn allocate_pstr(&mut self, src: &str) -> Addr { + self.write_pstr(src) + .unwrap_or_else(|| { + let h = self.h(); + + self.push(HeapCellValue::PartialString( + PartialString::empty() + )); + + self.push(HeapCellValue::Addr( + Addr::HeapCell(h + 1) + )); + + Addr::PStrLocation(h, 0) + }) + } + + #[inline] + fn write_pstr(&mut self, mut src: &str) -> Option { let orig_h = self.h(); loop { @@ -245,17 +403,21 @@ impl HeapTemplate { } pub(crate) - fn to_list>(&mut self, values: Iter) -> usize { + fn to_list(&mut self, values: Iter) -> usize + where Iter: Iterator, + SrcT: Into + { let head_addr = self.h(); + let mut h = head_addr; - for value in values { - let h = self.h(); - + for value in values.map(|v| v.into()) { self.push(HeapCellValue::Addr(Addr::Lis(h + 1))); - self.push(HeapCellValue::Addr(value)); + self.push(value); + + h += mem::size_of::() * 2; } - self.push(HeapCellValue::Addr(Addr::Con(Constant::EmptyList))); + self.push(HeapCellValue::Addr(Addr::EmptyList)); head_addr } @@ -286,8 +448,8 @@ impl HeapTemplate { pub(crate) fn to_local_code_ptr(&self, addr: &Addr) -> Option { let extract_integer = |s: usize| -> Option { - match self[s].as_addr(s) { - Addr::Con(Constant::Integer(n)) => n.to_usize(), + match &self[s] { + &HeapCellValue::Integer(ref n) => n.to_usize(), _ => None } }; @@ -327,6 +489,19 @@ impl HeapTemplate { _ => None } } + + #[inline] + pub + fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> { + match addr { + &Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) => { + RefOrOwned::Borrowed(&self[h]) + } + addr => { + RefOrOwned::Owned(HeapCellValue::Addr(*addr)) + } + } + } } impl Index for HeapTemplate { diff --git a/src/prolog/machine/machine_errors.rs b/src/prolog/machine/machine_errors.rs index 315e1eee..0a352a66 100644 --- a/src/prolog/machine/machine_errors.rs +++ b/src/prolog/machine/machine_errors.rs @@ -1,6 +1,7 @@ use prolog_parser::ast::*; -use crate::prolog::forms::PredicateKey; +use crate::prolog::forms::{Number, PredicateKey}; +use crate::prolog::machine::heap::*; use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_state::*; use crate::prolog::rug::Integer; @@ -21,35 +22,118 @@ pub(super) struct MachineError { from: ErrorProvenance, } -impl MachineError { - pub(super) fn functor_stub(name: ClauseName, arity: usize) -> MachineStub { - let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None))); - functor!( - "/", - 2, - [name, heap_integer!(Integer::from(arity))], - SharedOpDesc::new(400, YFX) - ) +pub(super) +trait TypeError { + fn type_error(self, h: usize, valid_type: ValidType) -> MachineError; +} + +impl TypeError for Addr { + fn type_error(self, _: usize, valid_type: ValidType) -> MachineError { + let stub = functor!( + "type_error", + [atom(valid_type.as_str()), addr(self)] + ); + + MachineError { + stub, + location: None, + from: ErrorProvenance::Received + } } +} + +impl TypeError for MachineStub { + fn type_error(self, h: usize, valid_type: ValidType) -> MachineError { + let stub = functor!( + "type_error", + [atom(valid_type.as_str()), aux(h, 0)], + [self] + ); - pub(super) fn evaluation_error(eval_error: EvalError) -> Self { - let stub = functor!("evaluation_error", 1, [heap_atom!(eval_error.as_str())]); MachineError { stub, location: None, - from: ErrorProvenance::Received, + from: ErrorProvenance::Constructed } } +} - pub(super) - fn type_error(valid_type: ValidType, culprit: Addr) -> Self { +impl TypeError for Number { + fn type_error(self, _h: usize, valid_type: ValidType) -> MachineError { let stub = functor!( "type_error", - 2, - [ - heap_atom!(valid_type.as_str()), - HeapCellValue::Addr(culprit) - ] + [atom(valid_type.as_str()), number(self)] + ); + + MachineError { + stub, + location: None, + from: ErrorProvenance::Received + } + } +} + +pub(super) +trait PermissionError { + fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError; +} + +impl PermissionError for Addr { + fn permission_error(self, _: usize, index_str: &'static str, perm: Permission) -> MachineError { + let stub = functor!( + "permission_error", + [atom(perm.as_str()), atom(index_str), addr(self)] + ); + + MachineError { + stub, + location: None, + from: ErrorProvenance::Received + } + } +} + +impl PermissionError for MachineStub { + fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError { + let stub = functor!( + "permission_error", + [atom(perm.as_str()), atom(index_str), aux(h, 0)], + [self] + ); + + MachineError { + stub, + location: None, + from: ErrorProvenance::Constructed + } + } +} + +pub(super) +trait DomainError { + fn domain_error(self, error: DomainErrorType) -> MachineError; +} + +impl DomainError for Addr { + fn domain_error(self, error: DomainErrorType) -> MachineError { + let stub = functor!( + "domain_error", + [atom(error.as_str()), addr(self)] + ); + + MachineError { + stub, + location: None, + from: ErrorProvenance::Received, + } + } +} + +impl DomainError for Number { + fn domain_error(self, error: DomainErrorType) -> MachineError { + let stub = functor!( + "domain_error", + [atom(error.as_str()), number(self)] ); MachineError { @@ -58,6 +142,31 @@ impl MachineError { from: ErrorProvenance::Received, } } +} + +impl MachineError { + pub(super) fn functor_stub(name: ClauseName, arity: usize) -> MachineStub { + functor!( + "/", + SharedOpDesc::new(400, YFX), + [clause_name(name), integer(arity)] + ) + } + + pub(super) fn evaluation_error(eval_error: EvalError) -> Self { + let stub = functor!("evaluation_error", [atom(eval_error.as_str())]); + + MachineError { + stub, + location: None, + from: ErrorProvenance::Received, + } + } + + pub(super) + fn type_error(h: usize, valid_type: ValidType, culprit: T) -> Self { + culprit.type_error(h, valid_type) + } pub(super) fn module_resolution_error( @@ -66,31 +175,24 @@ impl MachineError { name: ClauseName, arity: usize, ) -> Self { - let mod_name = HeapCellValue::Addr(Addr::Con(Constant::Atom(mod_name, None))); - let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None))); - - let mut stub = functor!( - "evaluation_error", - 1, - [HeapCellValue::Addr(Addr::HeapCell(h + 2))] + let res_stub = functor!( + ":", + SharedOpDesc::new(600, XFY), + [clause_name(mod_name), clause_name(name)] ); - stub.append(&mut functor!( + let ind_stub = functor!( "/", - 2, - [ - HeapCellValue::Addr(Addr::HeapCell(h + 2 + 3)), - heap_integer!(Integer::from(arity)) - ], - SharedOpDesc::new(400, YFX) - )); - - stub.append(&mut functor!( - ":", - 2, - [mod_name, name], - SharedOpDesc::new(600, XFY) - )); + SharedOpDesc::new(400, YFX), + [aux(h + 2, 0), integer(arity)], + [res_stub] + ); + + let stub = functor!( + "evaluation_error", + [aux(h, 0)], + [ind_stub] + ); MachineError { stub, @@ -103,23 +205,29 @@ impl MachineError { fn existence_error(h: usize, err: ExistenceError) -> Self { match err { ExistenceError::Module(name) => { - let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None))); - let stub = functor!("existence_error", 2, [heap_atom!("module"), name]); + let stub = functor!( + "existence_error", + [atom("module"), clause_name(name)] + ); MachineError { stub, location: None, - from: ErrorProvenance::Constructed, + from: ErrorProvenance::Received, } } ExistenceError::Procedure(name, arity) => { - let mut stub = functor!( - "existence_error", - 2, - [heap_atom!("procedure"), heap_str!(3 + h)] + let culprit = functor!( + "/", + SharedOpDesc::new(400, YFX), + [clause_name(name), integer(arity)] ); - stub.append(&mut Self::functor_stub(name, arity)); + let stub = functor!( + "existence_error", + [atom("procedure"), aux(h, 0)], + [culprit] + ); MachineError { stub, @@ -127,96 +235,112 @@ impl MachineError { from: ErrorProvenance::Constructed, } } - ExistenceError::Stream(addr) => { - let culprit = HeapCellValue::Addr(addr); - let stub = functor!("existence_error", 2, [heap_atom!("stream"), culprit]); + ExistenceError::Stream(culprit) => { + let stub = functor!( + "existence_error", + [atom("stream"), addr(culprit)] + ); MachineError { stub, location: None, - from: ErrorProvenance::Constructed, + from: ErrorProvenance::Received, } } } } pub(super) - fn session_error(h: usize, err: SessionError) -> Self { + fn permission_error( + h: usize, + err: Permission, + index_str: &'static str, + culprit: T, + ) -> Self { + culprit.permission_error( + h, + index_str, + err, + ) + } + + fn arithmetic_error(h: usize, err: ArithmeticError) -> Self { match err { - SessionError::ParserError(err) => Self::syntax_error(h, err), - SessionError::CannotOverwriteBuiltIn(pred_str) - | SessionError::CannotOverwriteImport(pred_str) => { - Self::permission_error( - PermissionError::Modify, - "private_procedure", - Addr::Con(Constant::Atom(pred_str, None)), - ) + ArithmeticError::UninstantiatedVar => { + Self::instantiation_error() } - SessionError::InvalidFileName(filename) => { - Self::existence_error(h, ExistenceError::Module(filename)) - } - SessionError::ModuleDoesNotContainExport(..) => Self::permission_error( - PermissionError::Access, - "private_procedure", - Addr::Con(atom!("module_does_not_contain_claimed_export")), - ), - SessionError::ModuleNotFound => Self::permission_error( - PermissionError::Access, - "private_procedure", - Addr::Con(atom!("module_does_not_exist")), - ), - SessionError::OpIsInfixAndPostFix(op) => { - Self::permission_error( - PermissionError::Create, - "operator", - Addr::Con(Constant::Atom(op, None)), - ) + ArithmeticError::NonEvaluableFunctor(name, arity) => { + let culprit = functor!( + "/", + SharedOpDesc::new(400, YFX), + [constant(h, &name), integer(arity)] + ); + + Self::type_error(h, ValidType::Evaluable, culprit) } - _ => unreachable!(), } } + #[inline] pub(super) - fn permission_error( - err: PermissionError, - index_str: &'static str, - culprit: Addr, - ) -> Self { - let culprit = HeapCellValue::Addr(culprit); - - let err = vec![heap_atom!(err.as_str()), heap_atom!(index_str), culprit]; - let mut stub = functor!("permission_error", 3); - - stub.extend(err.into_iter()); + fn domain_error(error: DomainErrorType, culprit: T) -> Self { + culprit.domain_error(error) + } + + pub(super) + fn instantiation_error() -> Self { + let stub = functor!("instantiation_error"); MachineError { stub, location: None, - from: ErrorProvenance::Constructed, + from: ErrorProvenance::Received, } } - fn arithmetic_error(h: usize, err: ArithmeticError) -> Self { + pub(super) + fn session_error(h: usize, err: SessionError) -> Self { match err { - ArithmeticError::UninstantiatedVar => Self::instantiation_error(), - ArithmeticError::NonEvaluableFunctor(name, arity) => { - let name = HeapCellValue::Addr(Addr::Con(name)); - let culprit = functor!( - "/", - 2, - [name, heap_integer!(Integer::from(arity))], - SharedOpDesc::new(400, YFX) - ); - - let mut stub = Self::type_error(ValidType::Evaluable, Addr::HeapCell(3 + h)).stub; - stub.extend(culprit.into_iter()); - - MachineError { - stub, - location: None, - from: ErrorProvenance::Constructed, - } + SessionError::ParserError(err) => { + Self::syntax_error(h, err) } + SessionError::CannotOverwriteBuiltIn(pred_str) + | SessionError::CannotOverwriteImport(pred_str) => { + Self::permission_error( + h, + Permission::Modify, + "private_procedure", + functor!(clause_name(pred_str)), + ) + } + SessionError::InvalidFileName(filename) => { + Self::existence_error(h, ExistenceError::Module(filename)) + } + SessionError::ModuleDoesNotContainExport(..) => { + Self::permission_error( + h, + Permission::Access, + "private_procedure", + functor!("module_does_not_contain_claimed_export"), + ) + } + SessionError::ModuleNotFound => { + Self::permission_error( + h, + Permission::Access, + "private_procedure", + functor!("modules_does_not_exist"), + ) + } + SessionError::OpIsInfixAndPostFix(op) => { + Self::permission_error( + h, + Permission::Create, + "operator", + functor!(clause_name(op)), + ) + } + _ => unreachable!(), } } @@ -227,50 +351,25 @@ impl MachineError { } let location = err.line_and_col_num(); - let err = vec![heap_atom!(err.as_str())]; - - let mut stub = if err.len() == 1 { - functor!("syntax_error", 1) - } else { - functor!("syntax_error", 1, [heap_str!(h + 2)]) - }; - - stub.extend(err.into_iter()); - - MachineError { - stub, - location, - from: ErrorProvenance::Constructed, - } - } - - pub(super) - fn domain_error(error: DomainError, culprit: Addr) -> Self { + let stub = functor!(err.as_str()); + let stub = functor!( - "domain_error", - 2, - [heap_atom!(error.as_str()), HeapCellValue::Addr(culprit)] + "syntax_error", + [aux(h, 0)], + [stub] ); - MachineError { - stub, - location: None, - from: ErrorProvenance::Received, - } - } - pub(super) - fn instantiation_error() -> Self { - let stub = functor!("instantiation_error"); MachineError { stub, - location: None, - from: ErrorProvenance::Received, + location, + from: ErrorProvenance::Constructed, } } pub(super) fn representation_error(flag: RepFlag) -> Self { - let stub = functor!("representation_error", 1, [heap_atom!(flag.as_str())]); + let stub = functor!("representation_error", [atom(flag.as_str())]); + MachineError { stub, location: None, @@ -296,7 +395,7 @@ impl MachineError { } #[derive(Clone, Copy)] -pub enum PermissionError { +pub enum Permission { Access, Create, InputStream, @@ -304,14 +403,14 @@ pub enum PermissionError { OutputStream, } -impl PermissionError { +impl Permission { pub fn as_str(self) -> &'static str { match self { - PermissionError::Access => "access", - PermissionError::Create => "create", - PermissionError::InputStream => "input", - PermissionError::Modify => "modify", - PermissionError::OutputStream => "output", + Permission::Access => "access", + Permission::Create => "create", + Permission::InputStream => "input", + Permission::Modify => "modify", + Permission::OutputStream => "output", } } } @@ -363,18 +462,18 @@ impl ValidType { } #[derive(Clone, Copy)] -pub enum DomainError { +pub enum DomainErrorType { NotLessThanZero, Stream, StreamOrAlias, } -impl DomainError { +impl DomainErrorType { pub fn as_str(self) -> &'static str { match self { - DomainError::NotLessThanZero => "not_less_than_zero", - DomainError::Stream => "stream", - DomainError::StreamOrAlias => "stream_or_alias", + DomainErrorType::NotLessThanZero => "not_less_than_zero", + DomainErrorType::Stream => "stream", + DomainErrorType::StreamOrAlias => "stream_or_alias", } } } @@ -424,20 +523,20 @@ impl EvalError { } // used by '$skip_max_list'. +#[derive(Clone, Copy)] pub(super) enum CycleSearchResult { EmptyList, NotList, - PartialList(usize, Ref), // the list length (up to max), and an offset into the heap. - ProperList(usize), // the list length. - CompleteString(usize, Rc), // the string length (in bytes), the string. - UntouchedString(usize, Rc), // the cut off, past which is the untouched string. + PartialList(usize, Ref), // the list length (up to max), and an offset into the heap. + ProperList(usize), // the list length. PStrLocation(usize, usize, usize), // the list length (up to max), the heap offset, byte offset into the string. - UntouchedList(usize), // the address of an uniterated Addr::Lis(address). + UntouchedList(usize), // the address of an uniterated Addr::Lis(address). } impl MachineState { // see 8.4.3 of Draft Technical Corrigendum 2. - pub(super) fn check_sort_errors(&self) -> CallResult { + pub(super) + fn check_sort_errors(&self) -> CallResult { let stub = MachineError::functor_stub(clause_name!("sort"), 2); let list = self.store(self.deref(self[temp_v!(1)].clone())); let sorted = self.store(self.deref(self[temp_v!(2)].clone())); @@ -447,14 +546,14 @@ impl MachineState { return Err(self.error_form(MachineError::instantiation_error(), stub)) } CycleSearchResult::NotList => { - return Err(self.error_form(MachineError::type_error(ValidType::List, list), stub)) + return Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub)) } _ => {} }; match self.detect_cycles(sorted.clone()) { CycleSearchResult::NotList if !sorted.is_ref() => { - Err(self.error_form(MachineError::type_error(ValidType::List, sorted), stub)) + Err(self.error_form(MachineError::type_error(0, ValidType::List, sorted), stub)) } _ => Ok(()), } @@ -465,7 +564,7 @@ impl MachineState { match self.detect_cycles(list.clone()) { CycleSearchResult::NotList if !list.is_ref() => { - Err(self.error_form(MachineError::type_error(ValidType::List, list), stub)) + Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub)) } _ => { let mut addr = list; @@ -474,18 +573,23 @@ impl MachineState { let mut new_l = l; loop { - match self.heap[new_l].clone() { - HeapCellValue::Addr(Addr::Str(l)) => new_l = l, + match self.heap.clone(new_l) { + HeapCellValue::Addr(Addr::Str(l)) => { + new_l = l; + } HeapCellValue::NamedStr(2, ref name, Some(_)) - if name.as_str() == "-" => - { - break + if name.as_str() == "-" => { + break; + } + HeapCellValue::Addr(Addr::HeapCell(_)) => { + break; + } + HeapCellValue::Addr(Addr::StackCell(..)) => { + break; } - HeapCellValue::Addr(Addr::HeapCell(_)) => break, - HeapCellValue::Addr(Addr::StackCell(..)) => break, _ => { return Err(self.error_form( - MachineError::type_error(ValidType::Pair, Addr::HeapCell(l)), + MachineError::type_error(0, ValidType::Pair, Addr::HeapCell(l)), stub, )) } @@ -501,9 +605,11 @@ impl MachineState { } // see 8.4.4 of Draft Technical Corrigendum 2. - pub(super) fn check_keysort_errors(&self) -> CallResult { + pub(super) + fn check_keysort_errors(&self) -> CallResult { let stub = MachineError::functor_stub(clause_name!("keysort"), 2); - let pairs = self.store(self.deref(self[temp_v!(1)].clone())); + + let pairs = self.store(self.deref(self[temp_v!(1)].clone())); let sorted = self.store(self.deref(self[temp_v!(2)].clone())); match self.detect_cycles(pairs.clone()) { @@ -511,7 +617,7 @@ impl MachineState { Err(self.error_form(MachineError::instantiation_error(), stub)) } CycleSearchResult::NotList => { - Err(self.error_form(MachineError::type_error(ValidType::List, pairs), stub)) + Err(self.error_form(MachineError::type_error(0, ValidType::List, pairs), stub)) } _ => Ok(()), }?; @@ -519,7 +625,8 @@ impl MachineState { self.check_for_list_pairs(sorted) } - pub(super) fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub { + pub(super) + fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub { let location = err.location; let err_len = err.len(); @@ -535,21 +642,17 @@ impl MachineState { if let Some((line_num, _)) = location { let colon_op_desc = Some(SharedOpDesc::new(600, XFY)); - stub.extend( - vec![ - HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc), - HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len)), - heap_integer!(Integer::from(line_num)), - ] - .into_iter(), - ); + stub.push(HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc)); + stub.push(HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len))); + stub.push(HeapCellValue::Integer(Rc::new(Integer::from(line_num)))); } stub.extend(src.into_iter()); stub } - pub(super) fn throw_exception(&mut self, err: MachineStub) { + pub(super) + fn throw_exception(&mut self, err: MachineStub) { let h = self.heap.h(); self.ball.boundary = 0; @@ -602,4 +705,5 @@ impl From for EvalSession { fn from(err: ParserError) -> Self { EvalSession::from(SessionError::ParserError(err)) } + } diff --git a/src/prolog/machine/machine_indices.rs b/src/prolog/machine/machine_indices.rs index e0c26d5a..b2dff159 100644 --- a/src/prolog/machine/machine_indices.rs +++ b/src/prolog/machine/machine_indices.rs @@ -7,11 +7,13 @@ use crate::prolog::forms::*; use crate::prolog::machine::code_repo::CodeRepo; use crate::prolog::machine::Ball; use crate::prolog::machine::heap::*; +use crate::prolog::machine::machine_state::*; use crate::prolog::machine::partial_string::*; use crate::prolog::machine::raw_block::RawBlockTraits; use crate::prolog::machine::streams::Stream; use crate::prolog::instructions::*; -use crate::prolog::rug::Integer; +use crate::prolog::ordered_float::OrderedFloat; +use crate::prolog::rug::{Integer, Rational}; use indexmap::IndexMap; @@ -39,20 +41,35 @@ pub enum DBRef { ), } -#[derive(Clone, PartialEq, Eq, Hash)] +// 7.2 +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum TermOrderCategory { + Variable, + FloatingPoint, + Integer, + Atom, + Compound, +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum Addr { AttrVar(usize), - Con(Constant), - DBRef(DBRef), + Char(char), + CharCode(u32), + Con(usize), + CutPoint(usize), + EmptyList, + Float(OrderedFloat), Lis(usize), HeapCell(usize), + PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes. StackCell(usize, usize), Str(usize), - PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes. - Stream(Stream), + Stream(usize), + Usize(usize), } -#[derive(Clone, Copy, Hash, Eq, PartialEq)] +#[derive(Clone, Copy, Hash, Eq, PartialEq, PartialOrd)] pub enum Ref { AttrVar(usize), HeapCell(usize), @@ -69,6 +86,28 @@ impl Ref { } } +impl Ord for Ref { + fn cmp(&self, other: &Ref) -> Ordering { + match (self, other) { + (Ref::AttrVar(h1), Ref::AttrVar(h2)) + | (Ref::HeapCell(h1), Ref::HeapCell(h2)) + | (Ref::HeapCell(h1), Ref::AttrVar(h2)) + | (Ref::AttrVar(h1), Ref::HeapCell(h2)) => { + h1.cmp(&h2) + } + (Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) => { + fr1.cmp(&fr2).then_with(|| sc1.cmp(&sc2)) + } + (Ref::StackCell(..), _) => { + Ordering::Greater + } + (_, Ref::StackCell(..)) => { + Ordering::Less + } + } + } +} + impl PartialEq for Addr { fn eq(&self, r: &Ref) -> bool { self.as_var() == Some(*r) @@ -133,6 +172,83 @@ impl Addr { } } + pub(super) + fn order_category(&self, heap: &Heap) -> Option { + match self { + Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => { + Some(TermOrderCategory::Variable) + } + Addr::Float(_) => { + Some(TermOrderCategory::FloatingPoint) + } + &Addr::Con(h) => { + match &heap[h] { + HeapCellValue::Atom(..) => { + Some(TermOrderCategory::Atom) + } + HeapCellValue::Integer(_) => { + Some(TermOrderCategory::Integer) + } + HeapCellValue::Rational(_) => { + Some(TermOrderCategory::Integer) + } + HeapCellValue::DBRef(_) => { + None + } + _ => { + unreachable!() + } + } + } + Addr::Char(_) | Addr::CharCode(_) | Addr::EmptyList => { + Some(TermOrderCategory::Atom) + } + Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => { + Some(TermOrderCategory::Compound) + } + Addr::CutPoint(_) | Addr::Usize(_) | Addr::Stream(_) => { + None + } + } + } + + pub fn as_constant(&self, machine_st: &MachineState) -> Option { + match self { + &Addr::Char(c) => { + Some(Constant::Char(c)) + } + &Addr::CharCode(c) => { + Some(Constant::CharCode(c)) + } + &Addr::Con(h) => { + match &machine_st.heap[h] { + &HeapCellValue::Atom(ref name, ref op) => { + Some(Constant::Atom(name.clone(), op.clone())) + } + &HeapCellValue::Integer(ref n) => { + Some(Constant::Integer(n.clone())) + } + &HeapCellValue::Rational(ref n) => { + Some(Constant::Rational(n.clone())) + } + _ => { + None + } + } + } + &Addr::Float(f) => { + Some(Constant::Float(f)) + } + &Addr::PStrLocation(h, n) => { + machine_st.to_complete_string(h, n) + .map(|s| Constant::String(Rc::new(s))) + } + _ => { + None + } + } + } + pub fn is_protected(&self, e: usize) -> bool { match self { &Addr::StackCell(addr, _) if addr >= e => false, @@ -209,29 +325,78 @@ impl From for TrailRef { } } -#[derive(Clone, PartialEq)] pub enum HeapCellValue { Addr(Addr), + Atom(ClauseName, Option), + DBRef(DBRef), + Integer(Rc), NamedStr(usize, ClauseName, Option), // arity, name, precedence/Specifier if it has one. + Rational(Rc), PartialString(PartialString), + Stream(Stream), } impl HeapCellValue { + #[inline] pub fn as_addr(&self, focus: usize) -> Addr { match self { HeapCellValue::Addr(ref a) => { a.clone() } + HeapCellValue::Atom(..) | HeapCellValue::DBRef(..) | HeapCellValue::Integer(..) | + HeapCellValue::Rational(..) => { + Addr::Con(focus) + } HeapCellValue::NamedStr(_, _, _) => { Addr::Str(focus) } HeapCellValue::PartialString(_) => { Addr::PStrLocation(focus, 0) } + HeapCellValue::Stream(_) => { + Addr::Stream(focus) + } + } + } + + #[inline] + pub fn context_free_clone(&self) -> HeapCellValue { + match self { + &HeapCellValue::Addr(addr) => { + HeapCellValue::Addr(addr) + } + &HeapCellValue::Atom(ref name, ref op) => { + HeapCellValue::Atom(name.clone(), op.clone()) + } + &HeapCellValue::DBRef(ref db_ref) => { + HeapCellValue::DBRef(db_ref.clone()) + } + &HeapCellValue::Integer(ref n) => { + HeapCellValue::Integer(n.clone()) + } + &HeapCellValue::NamedStr(arity, ref name, ref op) => { + HeapCellValue::NamedStr(arity, name.clone(), op.clone()) + } + &HeapCellValue::Rational(ref r) => { + HeapCellValue::Rational(r.clone()) + } + &HeapCellValue::PartialString(ref pstr) => { + HeapCellValue::PartialString(pstr.clone()) + } + &HeapCellValue::Stream(_) => { + HeapCellValue::Stream(Stream::null_stream()) + } } } } +impl From for HeapCellValue { + #[inline] + fn from(value: Addr) -> HeapCellValue { + HeapCellValue::Addr(value) + } +} + #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] pub enum IndexPtr { DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined. @@ -407,37 +572,31 @@ impl LocalCodePtr { LocalCodePtr::DirEntry(p) => { heap.append(functor!( "dir_entry", - 1, - [heap_integer!(Integer::from(*p))] + [integer(*p)] )); } LocalCodePtr::InSituDirEntry(p) => { heap.append(functor!( "in_situ_dir_entry", - 1, - [heap_integer!(Integer::from(*p))] + [integer(*p)] )); } LocalCodePtr::TopLevel(chunk_num, offset) => { heap.append(functor!( "top_level", - 2, - [heap_integer!(Integer::from(*chunk_num)), - heap_integer!(Integer::from(*offset))] + [integer(*chunk_num), integer(*offset)] )); } LocalCodePtr::UserGoalExpansion(p) => { heap.append(functor!( "user_goal_expansion", - 1, - [heap_integer!(Integer::from(*p))] + [integer(*p)] )); } LocalCodePtr::UserTermExpansion(p) => { heap.append(functor!( "user_term_expansion", - 1, - [heap_integer!(Integer::from(*p))] + [integer(*p)] )); } } @@ -449,8 +608,12 @@ impl LocalCodePtr { impl PartialOrd for CodePtr { fn partial_cmp(&self, other: &CodePtr) -> Option { match (self, other) { - (&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => l1.partial_cmp(l2), - _ => Some(Ordering::Greater), + (&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => { + l1.partial_cmp(l2) + } + _ => { + Some(Ordering::Greater) + } } } } @@ -465,8 +628,12 @@ impl PartialOrd for LocalCodePtr { | (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => { p1.partial_cmp(p2) } - (_, &LocalCodePtr::TopLevel(_, _)) => Some(Ordering::Less), - _ => Some(Ordering::Greater), + (_, &LocalCodePtr::TopLevel(_, _)) => { + Some(Ordering::Less) + } + _ => { + Some(Ordering::Greater) + } } } } diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index ec6efb5f..2c4a5367 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -18,7 +18,6 @@ use std::cmp::Ordering; use std::io::Write; use std::mem; use std::ops::{Index, IndexMut}; -use std::rc::Rc; pub struct Ball { pub(super) boundary: usize, @@ -58,11 +57,11 @@ impl Ball { for heap_value in self.stub.iter_from(0) { stub.push(match heap_value { - HeapCellValue::Addr(ref addr) => { - HeapCellValue::Addr(addr.clone() - diff) + &HeapCellValue::Addr(addr) => { + HeapCellValue::Addr(addr - diff) } heap_value => { - heap_value.clone() + heap_value.context_free_clone() } }); } @@ -185,8 +184,12 @@ impl<'a> CopierTarget for CopyBallTerm<'a> { let index = h - self.heap_boundary; self.stub[index].as_addr(h) } - Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc].clone(), - addr => addr, + Addr::StackCell(fr, sc) => { + self.stack.index_and_frame(fr)[sc].clone() + } + addr => { + addr + } } } @@ -250,8 +253,6 @@ pub(super) enum HeapPtr { HeapCell(usize), PStrChar(usize, usize), PStrLocation(usize, usize), - StringChar(usize, Rc), - StringLocation(usize, Rc), } impl HeapPtr { @@ -259,30 +260,23 @@ impl HeapPtr { pub(super) fn read(&self, heap: &Heap) -> Addr { match self { - &HeapPtr::HeapCell(h) => - Addr::HeapCell(h), - &HeapPtr::PStrChar(h, n) => + &HeapPtr::HeapCell(h) => { + Addr::HeapCell(h) + } + &HeapPtr::PStrChar(h, n) => { if let HeapCellValue::PartialString(ref pstr) = &heap[h] { - let s = pstr.block_as_str(); - - if let Some(c) = s[n ..].chars().next() { - Addr::Con(Constant::Char(c)) + if let Some(c) = pstr.range_from(n ..).next() { + Addr::Char(c) } else { Addr::HeapCell(h + 1) } } else { unreachable!() - }, - &HeapPtr::PStrLocation(h, n) => - Addr::PStrLocation(h, n), - &HeapPtr::StringChar(n, ref s) => - if let Some(c) = s[n ..].chars().next() { - Addr::Con(Constant::Char(c)) - } else { - Addr::Con(Constant::EmptyList) - }, - &HeapPtr::StringLocation(n, ref s) => - Addr::Con(Constant::String(n, s.clone())), + } + } + &HeapPtr::PStrLocation(h, n) => { + Addr::PStrLocation(h, n) + } } } } @@ -330,29 +324,27 @@ impl MachineState { let addr = self.store(self.deref(addr.clone())); match addr { - Addr::Con(Constant::String(n, ref s)) - if self.flags.double_quotes.is_chars() => { - if s.len() < n { - chars += &s[n ..]; - } - - if iter.next().is_some() { - return Err(MachineError::type_error(ValidType::Character, addr.clone())); - } - } - Addr::Con(Constant::Char(c)) => { + Addr::Char(c) => { chars.push(c); + continue; } - Addr::Con(Constant::Atom(ref name, _)) - if name.as_str().len() == 1 => { - chars += name.as_str(); + Addr::Con(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + if name.is_char() { + chars += name.as_str(); + continue; + } } + } _ => { - return Err( - MachineError::type_error(ValidType::Character, addr.clone()) - ); } - } + }; + + let h = self.heap.h(); + + return Err( + MachineError::type_error(h, ValidType::Character, addr) + ); } Ok(chars) @@ -738,32 +730,36 @@ pub(crate) trait CallPolicy: Any { let a2 = machine_st[temp_v!(2)].clone(); let a3 = machine_st[temp_v!(3)].clone(); - let c = match machine_st.compare_term_test(&a2, &a3) { - Ordering::Greater => { + let atom = match machine_st.compare_term_test(&a2, &a3) { + Some(Ordering::Greater) => { let spec = fetch_atom_op_spec(clause_name!(">"), None, &indices.op_dir); - Addr::Con(Constant::Atom(clause_name!(">"), spec)) + HeapCellValue::Atom(clause_name!(">"), spec) } - Ordering::Equal => { + Some(Ordering::Equal) => { let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir); - Addr::Con(Constant::Atom(clause_name!("="), spec)) + HeapCellValue::Atom(clause_name!("="), spec) } - Ordering::Less => { + None | Some(Ordering::Less) => { let spec = fetch_atom_op_spec(clause_name!("<"), None, &indices.op_dir); - Addr::Con(Constant::Atom(clause_name!("<"), spec)) + HeapCellValue::Atom(clause_name!("<"), spec) } }; - machine_st.unify(a1, c); + let h = machine_st.heap.h(); + + machine_st.heap.push(atom); + machine_st.unify(a1, Addr::Con(h)); + return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::CompareTerm(qt) => { machine_st.compare_term(qt); return_from_clause!(machine_st.last_call, machine_st) } - &BuiltInClauseType::Nl => { + &BuiltInClauseType::Nl => { write!(current_output_stream, "\n").unwrap(); current_output_stream.flush().unwrap(); - + return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::Read => { @@ -811,11 +807,12 @@ pub(crate) trait CallPolicy: Any { let a1 = machine_st[temp_v!(1)].clone(); let a2 = machine_st[temp_v!(2)].clone(); - machine_st.fail = if let Ordering::Equal = machine_st.compare_term_test(&a1, &a2) { - true - } else { - false - }; + machine_st.fail = + if let Some(Ordering::Equal) = machine_st.compare_term_test(&a1, &a2) { + true + } else { + false + }; return_from_clause!(machine_st.last_call, machine_st) } @@ -825,7 +822,10 @@ pub(crate) trait CallPolicy: Any { let stub = MachineError::functor_stub(clause_name!("sort"), 2); let mut list = machine_st.try_from_list(temp_v!(1), stub)?; - list.sort_unstable_by(|a1, a2| machine_st.compare_term_test(a1, a2)); + list.sort_unstable_by(|a1, a2| { + machine_st.compare_term_test(a1, a2).unwrap_or(Ordering::Less) + }); + machine_st.term_dedup(&mut list); let heap_addr = Addr::HeapCell(machine_st.heap.to_list(list.into_iter())); @@ -847,7 +847,9 @@ pub(crate) trait CallPolicy: Any { key_pairs.push((key, val.clone())); } - key_pairs.sort_by(|a1, a2| machine_st.compare_term_test(&a1.0, &a2.0)); + key_pairs.sort_by(|a1, a2| { + machine_st.compare_term_test(&a1.0, &a2.0).unwrap_or(Ordering::Less) + }); let key_pairs = key_pairs.into_iter().map(|kp| kp.1); let heap_addr = Addr::HeapCell(machine_st.heap.to_list(key_pairs)); @@ -859,9 +861,11 @@ pub(crate) trait CallPolicy: Any { } &BuiltInClauseType::Is(r, ref at) => { let a1 = machine_st[r].clone(); - let a2 = machine_st.get_number(at)?; + let n2 = machine_st.get_number(at)?; + + let n2 = Addr::Con(machine_st.heap.push(n2.into())); + machine_st.unify(a1, n2); - machine_st.unify(a1, Addr::Con(a2.to_constant())); return_from_clause!(machine_st.last_call, machine_st) } } @@ -935,11 +939,13 @@ pub(crate) trait CallPolicy: Any { } } ClauseType::Hook(_) | ClauseType::System(_) => { - let name = Addr::Con(Constant::Atom(name, None)); + let name = functor!(clause_name(name)); let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); - return Err(machine_st - .error_form(MachineError::type_error(ValidType::Callable, name), stub)); + return Err(machine_st.error_form( + MachineError::type_error(machine_st.heap.h(), ValidType::Callable, name), + stub, + )); } }; } @@ -997,7 +1003,7 @@ impl CallPolicy for CWILCallPolicy { current_input_stream, current_output_stream )?; - + self.increment(machine_st) } @@ -1016,7 +1022,7 @@ impl CallPolicy for CWILCallPolicy { current_input_stream, current_output_stream, )?; - + self.increment(machine_st) } } @@ -1035,7 +1041,8 @@ pub(crate) struct CWILCallPolicy { } impl CWILCallPolicy { - pub(crate) fn new_in_place(policy: &mut Box) { + pub(crate) + fn new_in_place(policy: &mut Box) { let mut prev_policy: Box = Box::new(DefaultCallPolicy {}); mem::swap(&mut prev_policy, policy); @@ -1045,6 +1052,7 @@ impl CWILCallPolicy { limits: vec![], inference_limit_exceeded: false, }; + *policy = Box::new(new_policy); } @@ -1056,10 +1064,10 @@ impl CWILCallPolicy { if let Some(&(ref limit, bp)) = self.limits.last() { if self.count == *limit { self.inference_limit_exceeded = true; + return Err(functor!( "inference_limit_exceeded", - 1, - [HeapCellValue::Addr(Addr::Con(Constant::Usize(bp)))] + [addr(Addr::Usize(bp))] )); } else { self.count += 1; @@ -1069,7 +1077,8 @@ impl CWILCallPolicy { Ok(()) } - pub(crate) fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer { + pub(crate) + fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer { limit += &self.count; match self.limits.last().cloned() { @@ -1080,7 +1089,8 @@ impl CWILCallPolicy { &self.count } - pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer { + pub(crate) + fn remove_limit(&mut self, b: usize) -> &Integer { if let Some((_, bp)) = self.limits.last().cloned() { if bp == b { self.limits.pop(); @@ -1090,11 +1100,13 @@ impl CWILCallPolicy { &self.count } - pub(crate) fn is_empty(&self) -> bool { + pub(crate) + fn is_empty(&self) -> bool { self.limits.is_empty() } - pub(crate) fn into_inner(&mut self) -> Box { + pub(crate) + fn into_inner(&mut self) -> Box { let mut new_inner: Box = Box::new(DefaultCallPolicy {}); mem::swap(&mut self.prev_policy, &mut new_inner); new_inner @@ -1108,11 +1120,11 @@ pub(crate) trait CutPolicy: Any { downcast!(dyn CutPolicy); -fn cut_body(machine_st: &mut MachineState, addr: Addr) -> bool { +fn cut_body(machine_st: &mut MachineState, addr: &Addr) -> bool { let b = machine_st.b; match addr { - Addr::Con(Constant::CutPoint(b0)) | Addr::Con(Constant::Usize(b0)) => { + &Addr::CutPoint(b0) | &Addr::Usize(b0) => { if b > b0 { machine_st.b = b0; machine_st.tidy_trail(); @@ -1131,13 +1143,13 @@ pub(crate) struct DefaultCutPolicy {} pub(super) fn deref_cut(machine_st: &mut MachineState, r: RegType) { let addr = machine_st.store(machine_st.deref(machine_st[r].clone())); - cut_body(machine_st, addr); + cut_body(machine_st, &addr); } impl CutPolicy for DefaultCutPolicy { fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool { let addr = machine_st[r].clone(); - cut_body(machine_st, addr) + cut_body(machine_st, &addr) } } @@ -1175,7 +1187,7 @@ impl SCCCutPolicy { let (idx, arity) = if machine_st.block < prev_block { (dir_entry!(self.r_c_w_h), 0) } else { - machine_st[temp_v!(1)] = Addr::Con(Constant::Usize(b_cutoff)); + machine_st[temp_v!(1)] = Addr::Usize(b_cutoff); (dir_entry!(self.r_c_wo_h), 1) }; @@ -1198,7 +1210,7 @@ impl CutPolicy for SCCCutPolicy { let b = machine_st.b; match machine_st[r].clone() { - Addr::Con(Constant::Usize(b0)) | Addr::Con(Constant::CutPoint(b0)) => { + Addr::Usize(b0) | Addr::CutPoint(b0) => { if b > b0 { machine_st.b = b0; machine_st.tidy_trail(); diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index b8a4d69c..fd721fa1 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -1,7 +1,6 @@ use prolog_parser::ast::*; use prolog_parser::tabled_rc::*; -use crate::prolog::arithmetic::*; use crate::prolog::clause_types::*; use crate::prolog::forms::*; use crate::prolog::heap_iter::*; @@ -17,25 +16,13 @@ use crate::prolog::machine::machine_state::*; use crate::prolog::machine::stack::*; use crate::prolog::machine::streams::*; use crate::prolog::ordered_float::*; -use crate::prolog::rug::{Integer, Rational}; +use crate::prolog::rug::Integer; use indexmap::{IndexMap, IndexSet}; -use std::cmp::{max, min, Ordering}; -use std::f64; -use std::iter::FromIterator; -use std::mem; +use std::cmp::Ordering; use std::rc::Rc; -macro_rules! try_numeric_result { - ($s: ident, $e: expr, $caller: expr) => {{ - match $e { - Ok(val) => Ok(val), - Err(e) => Err($s.error_form(MachineError::evaluation_error(e), $caller)), - } - }}; -} - macro_rules! try_or_fail { ($s:ident, $e:expr) => {{ match $e { @@ -132,7 +119,7 @@ impl MachineState { } Addr::PStrLocation(h, n) => { if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] { - if pstr.len() > n { + if !pstr.at_end(n) { Addr::PStrLocation(h, n) } else { Addr::HeapCell(h + 1) @@ -217,38 +204,14 @@ impl MachineState { } } - fn deconstruct_chars( - &mut self, - s: Rc, - string_offset: usize, - list_cell: usize, - pdl: &mut Vec, - ) -> bool { - if s.len() > string_offset { - if let Some(c) = s[string_offset ..].chars().next() { - pdl.push(Addr::Con(Constant::String(string_offset + c.len_utf8(), s))); - pdl.push(Addr::HeapCell(list_cell + 1)); - - pdl.push(Addr::Con(Constant::Char(c))); - pdl.push(Addr::HeapCell(list_cell)); - - return true; - } - } - - false - } - fn bind_with_occurs_check(&mut self, r: Ref, addr: Addr) { let mut fail = false; - for value in self.acyclic_pre_order_iter(addr.clone()) { - if let HeapCellValue::Addr(addr) = value { - if let Some(inner_r) = addr.as_var() { - if r == inner_r { - fail = true; - break; - } + for addr in self.acyclic_pre_order_iter(addr) { + if let Some(inner_r) = addr.as_var() { + if r == inner_r { + fail = true; + break; } } } @@ -303,91 +266,54 @@ impl MachineState { self.fail = true; } - (Addr::Lis(a1), Addr::Con(Constant::String(n, s))) - | (Addr::Con(Constant::String(n, s)), Addr::Lis(a1)) - if !self.flags.double_quotes.is_atom() => - { - if self.deconstruct_chars(s, n, a1, &mut pdl) { - continue; - } - - self.fail = true; - } - (Addr::Con(Constant::EmptyList), Addr::Con(Constant::String(n, ref s))) - | (Addr::Con(Constant::String(n, ref s)), Addr::Con(Constant::EmptyList)) - if !self.flags.double_quotes.is_atom() => - { - if n >= s.len() { - continue; - } - - self.fail = true; - } (Addr::PStrLocation(h, n), Addr::Lis(l)) | (Addr::Lis(l), Addr::PStrLocation(h, n)) => { if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] { - let s = pstr.block_as_str(); - - if let Some(c) = s[n ..].chars().next() { + if let Some(c) = pstr.range_from(n ..).next() { pdl.push(Addr::PStrLocation(h, n + c.len_utf8())); pdl.push(Addr::HeapCell(l + 1)); - pdl.push(Addr::Con(Constant::Char(c))); + pdl.push(Addr::Char(c)); pdl.push(Addr::HeapCell(l)); + } else { + unreachable!() } + } else { + unreachable!() } } - (Addr::PStrLocation(h, n), Addr::Con(Constant::String(n1, s))) - | (Addr::Con(Constant::String(n1, s)), Addr::PStrLocation(h, n)) - if self.flags.double_quotes.is_chars() => { - if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] { - let pstr_s = pstr.block_as_str(); - - let pstr_len = pstr_s[n ..].len(); - let s_len = s[n1 ..].len(); - let m_len = std::cmp::min(s_len, pstr_len); - - if pstr_s[n .. n + m_len] == s[n1 .. n1 + m_len] { - if s_len <= pstr_len { - pdl.push(Addr::Con(Constant::EmptyList)); - pdl.push(Addr::PStrLocation(h, n + m_len)); - } else { - pdl.push(Addr::Con(Constant::String(n1 + m_len, s))); - pdl.push(Addr::HeapCell(h + 1)); - } - - continue; - } - - self.fail = true; - break; - } - } (Addr::PStrLocation(h1, n1), Addr::PStrLocation(h2, n2)) => { if let HeapCellValue::PartialString(ref pstr1) = &self.heap[h1] { if let HeapCellValue::PartialString(ref pstr2) = &self.heap[h2] { - let pstr_s1 = pstr1.block_as_str(); - let pstr_s2 = pstr2.block_as_str(); + let pstr1_iter = pstr1.range_from(n1 ..); + let pstr2_iter = pstr2.range_from(n2 ..); - let pstr_s1_len = pstr_s1[n1 ..].len(); - let pstr_s2_len = pstr_s2[n2 ..].len(); - let m_len = std::cmp::min(pstr_s1_len, pstr_s2_len); + let mut m_len = 0; - if pstr_s1[n1 .. n1 + m_len] == pstr_s2[n2 .. n2 + m_len] { - if pstr_s1_len <= pstr_s2_len { - pdl.push(Addr::HeapCell(h1 + 1)); - pdl.push(Addr::PStrLocation(h2, n2 + m_len)); - } else { - pdl.push(Addr::HeapCell(h2 + 1)); - pdl.push(Addr::PStrLocation(h1, n1 + m_len)); + for (c1, c2) in pstr1_iter.zip(pstr2_iter) { + if c1 != c2 { + self.fail = true; + return; } - continue; + m_len += 1; + } + + if pstr1.at_end(n1 + m_len) { + pdl.push(Addr::HeapCell(h1 + 1)); + pdl.push(Addr::PStrLocation(h2, n2 + m_len)); + } else { + pdl.push(Addr::HeapCell(h2 + 1)); + pdl.push(Addr::PStrLocation(h1, n1 + m_len)); } self.fail = true; break; + } else { + unreachable!() } + } else { + unreachable!() } } (Addr::Lis(a1), Addr::Lis(a2)) => { @@ -397,7 +323,7 @@ impl MachineState { pdl.push(Addr::HeapCell(a1 + 1)); pdl.push(Addr::HeapCell(a2 + 1)); } - (Addr::Con(ref c1), Addr::Con(ref c2)) => { + (Addr::Con(c1), Addr::Con(c2)) => { if c1 != c2 { self.fail = true; } @@ -474,85 +400,45 @@ impl MachineState { self.fail = true; } - (Addr::Lis(a1), Addr::Con(Constant::String(n, s))) - | (Addr::Con(Constant::String(n, s)), Addr::Lis(a1)) - if !self.flags.double_quotes.is_atom() => { - if self.deconstruct_chars(s, n, a1, &mut pdl) { - continue; - } - - self.fail = true; - } - (Addr::Con(Constant::EmptyList), Addr::Con(Constant::String(n, ref s))) - | (Addr::Con(Constant::String(n, ref s)), Addr::Con(Constant::EmptyList)) - if !self.flags.double_quotes.is_atom() => - { - if n >= s.len() { - continue; - } - - self.fail = true; - } (Addr::PStrLocation(h, n), Addr::Lis(l)) | (Addr::Lis(l), Addr::PStrLocation(h, n)) => { - if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] { - let s = pstr.block_as_str(); - - if let Some(c) = s[n ..].chars().next() { - pdl.push(Addr::PStrLocation(h, n + c.len_utf8())); - pdl.push(Addr::HeapCell(l + 1)); - - pdl.push(Addr::Con(Constant::Char(c))); - pdl.push(Addr::HeapCell(l)); - } - } + if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] { + if let Some(c) = pstr.range_from(n ..).next() { + pdl.push(Addr::PStrLocation(h, n + c.len_utf8())); + pdl.push(Addr::HeapCell(l + 1)); + + pdl.push(Addr::Char(c)); + pdl.push(Addr::HeapCell(l)); + } else { + unreachable!() + } + } else { + unreachable!() + } } - (Addr::PStrLocation(h, n), Addr::Con(Constant::String(n1, s))) - | (Addr::Con(Constant::String(n1, s)), Addr::PStrLocation(h, n)) - if self.flags.double_quotes.is_chars() => { - if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] { - let pstr_s = pstr.block_as_str(); - - let pstr_len = pstr_s[n ..].len(); - let s_len = s[n1 ..].len(); - let m_len = std::cmp::min(s_len, pstr_len); - - if pstr_s[n .. n + m_len] == s[n1 .. n1 + m_len] { - if s_len <= pstr_len { - pdl.push(Addr::Con(Constant::EmptyList)); - pdl.push(Addr::PStrLocation(h, n + m_len)); - } else { - pdl.push(Addr::Con(Constant::String(n1 + m_len, s))); - pdl.push(Addr::HeapCell(h + 1)); - } - - continue; - } - - self.fail = true; - break; - } - } (Addr::PStrLocation(h1, n1), Addr::PStrLocation(h2, n2)) => { if let HeapCellValue::PartialString(ref pstr1) = &self.heap[h1] { if let HeapCellValue::PartialString(ref pstr2) = &self.heap[h2] { - let pstr_s1 = pstr1.block_as_str(); - let pstr_s2 = pstr2.block_as_str(); + let pstr1_iter = pstr1.range_from(n1 ..); + let pstr2_iter = pstr2.range_from(n2 ..); - let pstr_s1_len = pstr_s1[n1 ..].len(); - let pstr_s2_len = pstr_s2[n2 ..].len(); - let m_len = std::cmp::min(pstr_s1_len, pstr_s2_len); + let mut m_len = 0; - if pstr_s1[n1 .. n1 + m_len] == pstr_s2[n2 .. n2 + m_len] { - if pstr_s1_len <= pstr_s2_len { - pdl.push(Addr::HeapCell(h1 + 1)); - pdl.push(Addr::PStrLocation(h2, n2 + m_len)); - } else { - pdl.push(Addr::HeapCell(h2 + 1)); - pdl.push(Addr::PStrLocation(h1, n1 + m_len)); + for (c1, c2) in pstr1_iter.zip(pstr2_iter) { + if c1 != c2 { + self.fail = true; + return; } - continue; + m_len += 1; + } + + if pstr1.at_end(n1 + m_len) { + pdl.push(Addr::HeapCell(h1 + 1)); + pdl.push(Addr::PStrLocation(h2, n2 + m_len)); + } else { + pdl.push(Addr::HeapCell(h2 + 1)); + pdl.push(Addr::PStrLocation(h1, n1 + m_len)); } self.fail = true; @@ -567,7 +453,7 @@ impl MachineState { pdl.push(Addr::HeapCell(a1 + 1)); pdl.push(Addr::HeapCell(a2 + 1)); } - (Addr::Con(ref c1), Addr::Con(ref c2)) => { + (Addr::Con(c1), Addr::Con(c2)) => { if c1 != c2 { self.fail = true; } @@ -597,6 +483,45 @@ impl MachineState { } } + pub(super) + fn to_complete_string(&self, h: usize, n: usize) -> Option { + if self.is_cyclic_term(Addr::PStrLocation(h, n)) { + return None; + } + + let mut addr = Addr::PStrLocation(h, n); + let mut result = String::new(); + + loop { + match addr { + Addr::EmptyList => { + break; + } + Addr::Lis(l) if !self.flags.double_quotes.is_atom() => { + if let &HeapCellValue::Addr(Addr::Char(c)) = &self.heap[l] { + result.push(c); + addr = self.store(self.deref(Addr::HeapCell(l + 1))); + } else { + return None; + } + } + Addr::PStrLocation(h, n) => { + if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] { + result.extend(pstr.range_from(n ..)); + addr = self.store(self.deref(Addr::HeapCell(h + 1))); + } else { + unreachable!() + } + } + _ => { + return None; + } + } + } + + Some(result) + } + pub(super) fn trail(&mut self, r: TrailRef) { match r { @@ -638,29 +563,21 @@ impl MachineState { HeapPtr::HeapCell(ref mut h) => { *h += rhs; } - HeapPtr::PStrChar(h, n) | HeapPtr::PStrLocation(h, n) => { - match &self.heap[*h] { + &mut HeapPtr::PStrChar(h, ref mut n) + | &mut HeapPtr::PStrLocation(h, ref mut n) => { + match &self.heap[h] { HeapCellValue::PartialString(ref pstr) => { - let s = pstr.block_as_str(); - - for c in s[*n ..].chars().take(rhs) { + for c in pstr.range_from(*n ..).take(rhs) { *n += c.len_utf8(); } - self.s = HeapPtr::PStrLocation(*h, *n); + self.s = HeapPtr::PStrLocation(h, *n); } _ => { unreachable!() } } } - HeapPtr::StringChar(n, s) | HeapPtr::StringLocation(n, s) => { - for c in s[*n ..].chars().take(rhs) { - *n += c.len_utf8(); - } - - self.s = HeapPtr::StringLocation(*n, s.clone()); - } } } @@ -726,665 +643,162 @@ impl MachineState { self.trail.truncate(self.tr); } - pub(super) fn write_constant_to_var(&mut self, addr: Addr, c: Constant) { + pub(super) + fn write_constant_to_var(&mut self, addr: Addr, c: &Constant) { match self.store(self.deref(addr)) { - Addr::Con(c1) => - self.fail = self.eq_test(Addr::Con(c), Addr::Con(c1)), - Addr::Lis(l) => - self.unify(Addr::Lis(l), Addr::Con(c)), - addr => { - if let Some(r) = addr.as_var() { - self.bind(r, Addr::Con(c)); + Addr::Con(c1) => { + self.fail = match &self.heap[c1] { + HeapCellValue::Atom(ref n1, ref op1) => { + if let Constant::Atom(ref n2, ref op2) = c { + !(n1 == n2 && op1 == op2) + } else { + true + } + } + HeapCellValue::Integer(ref n1) => { + if let Constant::Integer(ref n2) = c { + n1 != n2 + } else { + true + } + } + HeapCellValue::Rational(ref r1) => { + if let Constant::Rational(ref r2) = c { + r1 != r2 + } else { + true + } + } + HeapCellValue::PartialString(_) => { + self.to_complete_string(c1, 0).map(|s1| { + if let Constant::String(ref s2) = c { + &s1 != &**s2 + } else { + true + } + }).unwrap_or(true) + } + _ => { + unreachable!() + } + }; + } + Addr::EmptyList => { + if let Constant::EmptyList = c { } else { self.fail = true; } } - }; - } - - pub(super) fn get_number(&mut self, at: &ArithmeticTerm) -> Result { - match at { - &ArithmeticTerm::Reg(r) => self.arith_eval_by_metacall(r), - &ArithmeticTerm::Interm(i) => Ok(mem::replace( - &mut self.interms[i - 1], - Number::Integer(Integer::from(0)), - )), - &ArithmeticTerm::Number(ref n) => Ok(n.clone()), - } - } - - fn rational_from_number( - &self, - n: Number, - caller: &MachineStub, - ) -> Result { - match n { - Number::Rational(r) => Ok(r), - Number::Float(OrderedFloat(f)) => Rational::from_f64(f).ok_or_else(|| { - self.error_form(MachineError::instantiation_error(), caller.clone()) - }), - Number::Integer(n) => Ok(Rational::from(n)), - } - } - - fn get_rational( - &mut self, - at: &ArithmeticTerm, - caller: &MachineStub, - ) -> Result { - let n = self.get_number(at)?; - self.rational_from_number(n, caller) - } - - pub(super) fn arith_eval_by_metacall(&self, r: RegType) -> Result { - let a = self[r].clone(); - - let caller = MachineError::functor_stub(clause_name!("(is)"), 2); - let mut interms: Vec = Vec::with_capacity(64); - - for heap_val in self.post_order_iter(a) { - match heap_val { - HeapCellValue::NamedStr(2, name, _) => { - let a2 = interms.pop().unwrap(); - let a1 = interms.pop().unwrap(); - - match name.as_str() { - "+" => interms.push(try_numeric_result!(self, a1 + a2, caller.clone())?), - "-" => interms.push(try_numeric_result!(self, a1 - a2, caller.clone())?), - "*" => interms.push(try_numeric_result!(self, a1 * a2, caller.clone())?), - "/" => interms.push(self.div(a1, a2)?), - "**" => interms.push(self.pow(a1, a2, "(is)")?), - "^" => interms.push(self.int_pow(a1, a2)?), - "max" => interms.push(self.max(a1, a2)?), - "min" => interms.push(self.min(a1, a2)?), - "rdiv" => { - let r1 = self.rational_from_number(a1, &caller)?; - let r2 = self.rational_from_number(a2, &caller)?; - - let result = Number::Rational(self.rdiv(r1, r2)?); - interms.push(result) - } - "//" => interms.push(Number::Integer(self.idiv(a1, a2)?)), - "div" => interms.push(Number::Integer(self.int_floor_div(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)?)), - "atan2" => interms.push(Number::Float(OrderedFloat(self.atan2(a1, a2)?))), - "gcd" => interms.push(Number::Integer(self.gcd(a1, a2)?)), - _ => { - return Err(self.error_form(MachineError::instantiation_error(), caller)) - } - } - } - HeapCellValue::NamedStr(1, name, _) => { - let a1 = interms.pop().unwrap(); - - match name.as_str() { - "-" => interms.push(-a1), - "+" => interms.push(a1), - "cos" => interms.push(Number::Float(OrderedFloat(self.cos(a1)?))), - "sin" => interms.push(Number::Float(OrderedFloat(self.sin(a1)?))), - "tan" => interms.push(Number::Float(OrderedFloat(self.tan(a1)?))), - "sqrt" => interms.push(Number::Float(OrderedFloat(self.sqrt(a1)?))), - "log" => interms.push(Number::Float(OrderedFloat(self.log(a1)?))), - "exp" => interms.push(Number::Float(OrderedFloat(self.exp(a1)?))), - "acos" => interms.push(Number::Float(OrderedFloat(self.acos(a1)?))), - "asin" => interms.push(Number::Float(OrderedFloat(self.asin(a1)?))), - "atan" => interms.push(Number::Float(OrderedFloat(self.atan(a1)?))), - "abs" => interms.push(a1.abs()), - "float" => interms.push(Number::Float(OrderedFloat(self.float(a1)?))), - "truncate" => interms.push(Number::Integer(self.truncate(a1))), - "round" => interms.push(Number::Integer(self.round(a1)?)), - "ceiling" => interms.push(Number::Integer(self.ceiling(a1))), - "floor" => interms.push(Number::Integer(self.floor(a1))), - "\\" => interms.push(Number::Integer(self.bitwise_complement(a1)?)), - "sign" => interms.push(Number::Integer(self.sign(a1))), - _ => { - return Err(self.error_form(MachineError::instantiation_error(), caller)) - } + Addr::Lis(l) if !self.flags.double_quotes.is_atom() => { + let addr = self.heap.put_constant(c.clone()); + self.unify(Addr::Lis(l), addr); + } + Addr::PStrLocation(h, n) => { + self.fail = self.to_complete_string(h, n).map(|s1| { + if let Constant::String(ref s2) = c { + &s1 != &**s2 + } else { + true } - } - HeapCellValue::Addr(Addr::Con(Constant::Integer(n))) => { - interms.push(Number::Integer(n)) - } - HeapCellValue::Addr(Addr::Con(Constant::Float(n))) => { - interms.push(Number::Float(n)) - } - HeapCellValue::Addr(Addr::Con(Constant::Rational(n))) => { - interms.push(Number::Rational(n)) - } - HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) - if name.as_str() == "pi" => - { - interms.push(Number::Float(OrderedFloat(f64::consts::PI))) - } - _ => { - return Err(self.error_form(MachineError::instantiation_error(), caller)); - } + }).unwrap_or(true); } - } - - Ok(interms.pop().unwrap()) - } - - fn rdiv(&self, r1: Rational, r2: Rational) -> Result { - let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2); - - if r2 == 0 { - Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(r1 / r2) - } - } - - fn int_floor_div(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(div)"), 2); - - match n1 / n2 { - Ok(result) => Ok(rnd_i(&result).to_owned()), - Err(e) => Err(self.error_form(MachineError::evaluation_error(e), stub)), - } - } - - fn idiv(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(//)"), 2); - - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => { - if n2 == 0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) + addr => { + if let Some(r) = addr.as_var() { + let addr = self.heap.put_constant(c.clone()); + self.bind(r, addr); } else { - Ok(n1.div_rem(n2).0) + self.fail = true; } } - (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n2.to_constant())), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n1.to_constant())), - stub, - )), - } - } - - fn div(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(/)"), 2); - - if n2.is_zero() { - Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - try_numeric_result!(self, n1 / n2, stub) - } + }; } - fn atan2(&self, n1: Number, n2: Number) -> Result { + pub(super) + fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) { let stub = MachineError::functor_stub(clause_name!("(is)"), 2); - if n1.is_zero() && n2.is_zero() { - Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)) - } else { - let f1 = self.float(n1)?; - let f2 = self.float(n2)?; - - self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.atan2(f2)) - } - } - - fn int_pow(&self, n1: Number, n2: Number) -> Result { - if n1.is_zero() && n2.is_negative() { - let stub = MachineError::functor_stub(clause_name!("(is)"), 2); - return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); - } + 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)); - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => { - if n1 != 1 && n2 < 0 { - let n = Addr::Con(Constant::Integer(n1)); - let stub = MachineError::functor_stub(clause_name!("^"), 2); + self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 + n2, stub)); + 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)); - Err(self.error_form(MachineError::type_error(ValidType::Float, n), stub)) - } else { - Ok(Number::Integer(binary_pow(n1, n2))) - } + self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 - n2, stub)); + self.p += 1; } - (n1, Number::Integer(n2)) => { - let f1 = self.float(n1)?; - let f2 = self.float(Number::Integer(n2))?; + &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.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) - .map(|f| Number::Float(OrderedFloat(f))) + self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 * n2, stub)); + self.p += 1; } - (n1, n2) => { - let f2 = self.float(n2)?; + &ArithmeticInstruction::Max(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)); - if n1.is_negative() && f2 != f2.floor() { - let stub = MachineError::functor_stub(clause_name!("(is)"), 2); - return Err( - self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub) - ); - } + self.interms[t - 1] = try_or_fail!(self, self.max(n1, n2)); + self.p += 1; + } + &ArithmeticInstruction::Min(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)); - let f1 = self.float(n1)?; - self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) - .map(|f| Number::Float(OrderedFloat(f))) + self.interms[t - 1] = try_or_fail!(self, self.min(n1, n2)); + self.p += 1; } - } - } + &ArithmeticInstruction::IntPow(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)); - fn gcd(&self, n1: Number, n2: Number) -> Result { - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(n1.gcd(&n2)) + self.interms[t - 1] = try_or_fail!(self, self.int_pow(n1, n2)); + self.p += 1; } - (Number::Float(f), _) | (_, Number::Float(f)) => { - let n = Addr::Con(Constant::Float(f)); - let stub = MachineError::functor_stub(clause_name!("gcd"), 2); + &ArithmeticInstruction::Gcd(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)); - Err(self.error_form(MachineError::type_error(ValidType::Integer, n), stub)) + self.interms[t - 1] = + Number::Integer(Rc::new(try_or_fail!(self, self.gcd(n1, n2)))); + self.p += 1; } - (Number::Rational(r), _) | (_, Number::Rational(r)) => { - let n = Addr::Con(Constant::Rational(r)); - let stub = MachineError::functor_stub(clause_name!("gcd"), 2); + &ArithmeticInstruction::Pow(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)); - Err(self.error_form(MachineError::type_error(ValidType::Integer, n), stub)) + self.interms[t - 1] = try_or_fail!(self, self.pow(n1, n2, "(**)")); + self.p += 1; } - } - } + &ArithmeticInstruction::RDiv(ref a1, ref a2, t) => { + let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2); - fn float_pow(&self, n1: Number, n2: Number) -> Result { - let f1 = result_f(&n1, rnd_f); - let f2 = result_f(&n2, rnd_f); + let (r1, stub) = try_or_fail!(self, self.get_rational(a1, stub)); + let (r2, _) = try_or_fail!(self, self.get_rational(a2, stub)); - let stub = MachineError::functor_stub(clause_name!("(**)"), 2); + self.interms[t - 1] = + Number::Rational(Rc::new(try_or_fail!(self, self.rdiv(r1, r2)))); + self.p += 1; + } + &ArithmeticInstruction::IntFloorDiv(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)); - let f1 = try_numeric_result!(self, f1, stub.clone())?; - let f2 = try_numeric_result!(self, f2, stub.clone())?; - - let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))), rnd_f); - - Ok(Number::Float(OrderedFloat(try_numeric_result!( - self, result, stub - )?))) - } - - fn pow(&self, n1: Number, n2: Number, culprit: &'static str) -> Result { - if n2.is_negative() && n1.is_zero() { - let stub = MachineError::functor_stub(clause_name!(culprit), 2); - return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); - } - - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Integer(binary_pow(n1, n2))), - (n1, n2) => self.float_pow(n1, n2), - } - } - - fn unary_float_fn_template(&self, n1: Number, f: FloatFn) -> Result - where - FloatFn: Fn(f64) -> f64, - { - let stub = MachineError::functor_stub(clause_name!("(is)"), 2); - - let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub.clone())?; - let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f); - - try_numeric_result!(self, f1, stub) - } - - fn sin(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.sin()) - } - - fn cos(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.cos()) - } - - fn tan(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.tan()) - } - - fn log(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.log(f64::consts::E)) - } - - fn exp(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.exp()) - } - - fn asin(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.asin()) - } - - fn acos(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.acos()) - } - - fn atan(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.atan()) - } - - fn sqrt(&self, n1: Number) -> Result { - if n1.is_negative() { - let stub = MachineError::functor_stub(clause_name!("(is)"), 2); - return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); - } - - self.unary_float_fn_template(n1, |f| f.sqrt()) - } - - fn float(&self, n: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(is)"), 2); - try_numeric_result!(self, result_f(&n, rnd_f), stub) - } - - fn floor(&self, n1: Number) -> Integer { - rnd_i(&n1).to_owned() - } - - fn ceiling(&self, n1: Number) -> Integer { - -self.floor(-n1) - } - - fn truncate(&self, n: Number) -> Integer { - if n.is_negative() { - -self.floor(n.abs()) - } else { - self.floor(n) - } - } - - fn round(&self, n: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(is)"), 2); - - let result = n + Number::Float(OrderedFloat(0.5f64)); - let result = try_numeric_result!(self, result, stub)?; - - Ok(self.floor(result)) - } - - fn shr(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(>>)"), 2); - - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { - Some(n2) => Ok(n1 >> n2), - _ => Ok(n1 >> u32::max_value()), - }, - (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n2.to_constant())), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n1.to_constant())), - stub, - )), - } - } - - fn shl(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(<<)"), 2); - - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { - Some(n2) => Ok(n1 << n2), - _ => Ok(n1 << u32::max_value()), - }, - (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n2.to_constant())), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n1.to_constant())), - stub, - )), - } - } - - fn bitwise_complement(&self, n1: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(\\)"), 2); - - match n1 { - Number::Integer(n1) => Ok(!n1), - _ => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n1.to_constant())), - stub, - )), - } - } - - fn xor(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(xor)"), 2); - - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => Ok(n1 ^ n2), - (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n2.to_constant())), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n1.to_constant())), - stub, - )), - } - } - - fn and(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(/\\)"), 2); - - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => Ok(n1 & n2), - (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n2.to_constant())), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n1.to_constant())), - stub, - )), - } - } - - fn modulus(&self, x: Number, y: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(mod)"), 2); - - match (x, y) { - (Number::Integer(x), Number::Integer(y)) => { - if y == 0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(x.div_rem_floor(y).1) - } - } - (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n2.to_constant())), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n1.to_constant())), - stub, - )), - } - } - - fn max(&self, n1: Number, n2: Number) -> Result { - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => { - if n1 > n2 { - Ok(Number::Integer(n1)) - } else { - Ok(Number::Integer(n2)) - } - } - (n1, n2) => { - let stub = MachineError::functor_stub(clause_name!("max"), 2); - - let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub.clone())?; - let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?; - - Ok(Number::Float(max(OrderedFloat(f1), OrderedFloat(f2)))) - } - } - } - - fn min(&self, n1: Number, n2: Number) -> Result { - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => { - if n1 < n2 { - Ok(Number::Integer(n1)) - } else { - Ok(Number::Integer(n2)) - } - } - (n1, n2) => { - let stub = MachineError::functor_stub(clause_name!("max"), 2); - - let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub.clone())?; - let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?; - - Ok(Number::Float(min(OrderedFloat(f1), OrderedFloat(f2)))) - } - } - } - - fn sign(&self, n: Number) -> Integer { - if n.is_positive() { - Integer::from(1) - } else if n.is_negative() { - Integer::from(-1) - } else { - Integer::from(0) - } - } - - fn remainder(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(rem)"), 2); - - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => { - if n2 == 0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(n1 % n2) - } - } - (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n2.to_constant())), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n1.to_constant())), - stub, - )), - } - } - - fn or(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(\\/)"), 2); - - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => Ok(n1 | n2), - (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n2.to_constant())), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(ValidType::Integer, Addr::Con(n1.to_constant())), - stub, - )), - } - } - - pub(super) - fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) { - let stub = MachineError::functor_stub(clause_name!("(is)"), 2); - - 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.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 + n2, stub)); - 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.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 - n2, stub)); - 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.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 * n2, stub)); - self.p += 1; - } - &ArithmeticInstruction::Max(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.interms[t - 1] = try_or_fail!(self, self.max(n1, n2)); - self.p += 1; - } - &ArithmeticInstruction::Min(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.interms[t - 1] = try_or_fail!(self, self.min(n1, n2)); - self.p += 1; - } - &ArithmeticInstruction::IntPow(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.interms[t - 1] = try_or_fail!(self, self.int_pow(n1, n2)); - self.p += 1; - } - &ArithmeticInstruction::Gcd(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.interms[t - 1] = Number::Integer(try_or_fail!(self, self.gcd(n1, n2))); - self.p += 1; - } - &ArithmeticInstruction::Pow(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.interms[t - 1] = try_or_fail!(self, self.pow(n1, n2, "(**)")); - self.p += 1; - } - &ArithmeticInstruction::RDiv(ref a1, ref a2, t) => { - let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2); - - let r1 = try_or_fail!(self, self.get_rational(a1, &stub)); - let r2 = try_or_fail!(self, self.get_rational(a2, &stub)); - - self.interms[t - 1] = Number::Rational(try_or_fail!(self, self.rdiv(r1, r2))); - self.p += 1; - } - &ArithmeticInstruction::IntFloorDiv(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.interms[t - 1] = + Number::Integer(Rc::new(try_or_fail!(self, self.int_floor_div(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)); self.interms[t - 1] = - Number::Integer(try_or_fail!(self, self.int_floor_div(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)); - - self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.idiv(n1, n2))); + Number::Integer(Rc::new(try_or_fail!(self, self.idiv(n1, n2)))); self.p += 1; } &ArithmeticInstruction::Abs(ref a1, t) => { @@ -1396,7 +810,7 @@ impl MachineState { &ArithmeticInstruction::Sign(ref a1, t) => { let n = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Integer(self.sign(n)); + self.interms[t - 1] = Number::Integer(Rc::new(self.sign(n))); self.p += 1; } &ArithmeticInstruction::Neg(ref a1, t) => { @@ -1409,7 +823,7 @@ impl MachineState { let n1 = try_or_fail!(self, self.get_number(a1)); self.interms[t - 1] = - Number::Integer(try_or_fail!(self, self.bitwise_complement(n1))); + Number::Integer(Rc::new(try_or_fail!(self, self.bitwise_complement(n1)))); self.p += 1; } &ArithmeticInstruction::Div(ref a1, ref a2, t) => { @@ -1423,49 +837,56 @@ impl MachineState { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.shr(n1, n2))); + self.interms[t - 1] = + Number::Integer(Rc::new(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)); - self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.shl(n1, n2))); + self.interms[t - 1] = + Number::Integer(Rc::new(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)); - self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.xor(n1, n2))); + self.interms[t - 1] = + Number::Integer(Rc::new(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)); - self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.and(n1, n2))); + self.interms[t - 1] = + Number::Integer(Rc::new(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)); - self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.or(n1, n2))); + self.interms[t - 1] = + Number::Integer(Rc::new(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)); - self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.modulus(n1, n2))); + self.interms[t - 1] = + Number::Integer(Rc::new(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)); - self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.remainder(n1, n2))); + self.interms[t - 1] = + Number::Integer(Rc::new(try_or_fail!(self, self.remainder(n1, n2)))); self.p += 1; } &ArithmeticInstruction::Cos(ref a1, t) => { @@ -1544,25 +965,29 @@ impl MachineState { &ArithmeticInstruction::Truncate(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Integer(self.truncate(n1)); + self.interms[t - 1] = + Number::Integer(Rc::new(self.truncate(n1))); self.p += 1; } &ArithmeticInstruction::Round(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.round(n1))); + self.interms[t - 1] = + Number::Integer(Rc::new(try_or_fail!(self, self.round(n1)))); self.p += 1; } &ArithmeticInstruction::Ceiling(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Integer(self.ceiling(n1)); + self.interms[t - 1] = + Number::Integer(Rc::new(self.ceiling(n1))); self.p += 1; } &ArithmeticInstruction::Floor(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Integer(self.floor(n1)); + self.interms[t - 1] = + Number::Integer(Rc::new(self.floor(n1))); self.p += 1; } &ArithmeticInstruction::Plus(ref a1, t) => { @@ -1579,23 +1004,12 @@ impl MachineState { match instr { &FactInstruction::GetConstant(_, ref c, reg) => { let addr = self[reg].clone(); - self.write_constant_to_var(addr, c.clone()); + self.write_constant_to_var(addr, c); } &FactInstruction::GetList(_, reg) => { let addr = self.store(self.deref(self[reg].clone())); match addr { - Addr::Con(Constant::String(n, s)) => - match self.flags.double_quotes { - DoubleQuotes::Chars | DoubleQuotes::Codes - if s.len() > n => { - self.s = HeapPtr::StringChar(n, s); - self.mode = MachineMode::Read; - } - _ => { - self.fail = true - } - }, Addr::PStrLocation(h, n) => { self.s = HeapPtr::PStrChar(h, n); self.mode = MachineMode::Read; @@ -1647,7 +1061,9 @@ impl MachineState { _ => self.fail = true, }; } - &FactInstruction::GetVariable(norm, arg) => self[norm] = self.registers[arg].clone(), + &FactInstruction::GetVariable(norm, arg) => { + self[norm] = self.registers[arg].clone(); + } &FactInstruction::GetValue(norm, arg) => { let norm_addr = self[norm].clone(); let reg_addr = self.registers[arg].clone(); @@ -1658,10 +1074,10 @@ impl MachineState { match self.mode { MachineMode::Read => { let addr = self.s.read(&self.heap); - self.write_constant_to_var(addr, c.clone()); + self.write_constant_to_var(addr, c); } MachineMode::Write => { - self.heap.push(HeapCellValue::Addr(Addr::Con(c.clone()))); + self.heap.put_constant(c.clone()); } }; @@ -1692,7 +1108,7 @@ impl MachineState { if let Addr::HeapCell(hc) = addr { if hc < h { - let val = self.heap[hc].clone(); + let val = self.heap.clone(hc); self.heap.push(val); self.increment_s_ptr(1); @@ -1711,7 +1127,7 @@ impl MachineState { &FactInstruction::UnifyValue(reg) => { match self.mode { MachineMode::Read => { - let reg_addr = self[reg].clone(); + let reg_addr = self[reg]; self.unify(reg_addr, self.s.read(&self.heap)); } MachineMode::Write => { @@ -1741,38 +1157,31 @@ impl MachineState { fn execute_indexing_instr(&mut self, instr: &IndexingInstruction) { match instr { &IndexingInstruction::SwitchOnTerm(v, c, l, s) => { - let a1 = self.registers[1].clone(); - let addr = self.store(self.deref(a1)); + let addr = self[temp_v!(1)]; + let addr = self.store(self.deref(addr)); let offset = match addr { Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) | Addr::Stream(_) => { - v - } - Addr::Con(Constant::String(n, ref s)) => { + v + } + Addr::PStrLocation(..) => { if !self.flags.double_quotes.is_atom() { - if n >= s.len() { - c - } else { - l - } + l } else { c } } - Addr::Con(_) => { - c - } - Addr::Lis(_) | Addr::PStrLocation(..) => { + Addr::Char(_) | Addr::CharCode(_) | Addr::Con(_) | Addr::CutPoint(_) + | Addr::EmptyList | Addr::Float(_) | Addr::Usize(_) => { + c + } + Addr::Lis(_) => { l } Addr::Str(_) => { s } - Addr::DBRef(_) => { - self.fail = true; - return; - } }; match offset { @@ -1781,16 +1190,21 @@ impl MachineState { }; } &IndexingInstruction::SwitchOnConstant(_, ref hm) => { - let a1 = self.registers[1].clone(); - let addr = self.store(self.deref(a1)); + let addr = self[temp_v!(1)]; + let addr = self.store(self.deref(addr)); - let offset = match addr { - Addr::Con(constant) => match hm.get(&constant) { - Some(offset) => *offset, - _ => 0, - }, - _ => 0, - }; + let offset = + match addr.as_constant(&self) { + Some(c) => { + match hm.get(&c) { + Some(offset) => *offset, + _ => 0, + } + } + None => { + 0 + } + }; match offset { 0 => self.fail = true, @@ -1812,7 +1226,9 @@ impl MachineState { 0 } } - _ => 0, + _ => { + 0 + } }; match offset { @@ -1825,11 +1241,15 @@ impl MachineState { pub(super) fn execute_query_instr(&mut self, instr: &QueryInstruction) { match instr { - &QueryInstruction::GetVariable(norm, arg) => self[norm] = self.registers[arg].clone(), - &QueryInstruction::PutConstant(_, ref constant, reg) => { - self[reg] = Addr::Con(constant.clone()) + &QueryInstruction::GetVariable(norm, arg) => { + self[norm] = self.registers[arg].clone(); + } + &QueryInstruction::PutConstant(_, ref c, reg) => { + self[reg] = self.heap.put_constant(c.clone()); + } + &QueryInstruction::PutList(_, reg) => { + self[reg] = Addr::Lis(self.heap.h()); } - &QueryInstruction::PutList(_, reg) => self[reg] = Addr::Lis(self.heap.h()), &QueryInstruction::PutStructure(ref ct, arity, reg) => { let h = self.heap.h(); @@ -1851,14 +1271,16 @@ impl MachineState { self.registers[arg] = self.heap[h].as_addr(h); } } - &QueryInstruction::PutValue(norm, arg) => self.registers[arg] = self[norm].clone(), + &QueryInstruction::PutValue(norm, arg) => { + self.registers[arg] = self[norm].clone(); + } &QueryInstruction::PutVariable(norm, arg) => { match norm { RegType::Perm(n) => { let e = self.e; self[norm] = Addr::StackCell(e, n); - self.registers[arg] = self[norm].clone(); + self.registers[arg] = self[norm]; } RegType::Temp(_) => { let h = self.heap.h(); @@ -1870,10 +1292,10 @@ impl MachineState { }; } &QueryInstruction::SetConstant(ref c) => { - self.heap.push(HeapCellValue::Addr(Addr::Con(c.clone()))); + self.heap.put_constant(c.clone()); } &QueryInstruction::SetLocalValue(reg) => { - let addr = self.deref(self[reg].clone()); + let addr = self.deref(self[reg]); let h = self.heap.h(); if addr < Ref::HeapCell(h) { @@ -1933,14 +1355,15 @@ impl MachineState { } pub(super) fn setup_call_n(&mut self, arity: usize) -> Option { - let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); let addr = self.store(self.deref(self.registers[arity].clone())); let (name, narity) = match addr { Addr::Str(a) => { - let result = self.heap[a].clone(); + let result = self.heap.clone(a); if let HeapCellValue::NamedStr(narity, name, _) = result { + let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); + if narity + arity > 63 { let representation_error = self.error_form( MachineError::representation_error(RepFlag::MaxArity), @@ -1965,19 +1388,34 @@ impl MachineState { return None; } } - Addr::Con(Constant::Atom(name, _)) => (name, 0), + Addr::Con(h) => + match &self.heap[h] { + HeapCellValue::Atom(ref name, _) => { + (name.clone(), 0) + } + _ => { + self.fail = true; + return None; + } + } Addr::HeapCell(_) | Addr::StackCell(_, _) => { - let instantiation_error = - self.error_form(MachineError::instantiation_error(), stub); - self.throw_exception(instantiation_error); + let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); + let instantiation_error = self.error_form( + MachineError::instantiation_error(), + stub, + ); + self.throw_exception(instantiation_error); return None; } _ => { - let type_error = - self.error_form(MachineError::type_error(ValidType::Callable, addr), stub); - self.throw_exception(type_error); + let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); + let type_error = self.error_form( + MachineError::type_error(self.heap.h(), ValidType::Callable, addr), + stub, + ); + self.throw_exception(type_error); return None; } }; @@ -2016,116 +1454,109 @@ impl MachineState { // arg(+N, +Term, ?Arg) pub(super) fn try_arg(&mut self) -> CallResult { let stub = MachineError::functor_stub(clause_name!("arg"), 3); - let n = self.store(self.deref(self[temp_v!(1)].clone())); + let n = self.store(self.deref(self[temp_v!(1)])); match n { - Addr::HeapCell(_) | Addr::StackCell(..) => - // 8.5.2.3 a) - { + Addr::HeapCell(_) | Addr::StackCell(..) => { // 8.5.2.3 a) return Err(self.error_form(MachineError::instantiation_error(), stub)) } - Addr::Con(Constant::Integer(n)) => { - if n < 0 { - // 8.5.2.3 e) - let n = Addr::Con(Constant::Integer(n)); - let dom_err = MachineError::domain_error(DomainError::NotLessThanZero, n); - - return Err(self.error_form(dom_err, stub)); - } + Addr::Con(h) => { + if let HeapCellValue::Integer(n) = self.heap.clone(h) { + if &*n < &0 { // 8.5.2.3 e) + let n = Number::Integer(n); + let dom_err = MachineError::domain_error( + DomainErrorType::NotLessThanZero, + n, + ); - let n = match n.to_usize() { - Some(n) => n, - None => { - self.fail = true; - return Ok(()); + return Err(self.error_form(dom_err, stub)); } - }; - let term = self.store(self.deref(self[temp_v!(2)].clone())); + let n = match n.to_usize() { + Some(n) => n, + None => { + self.fail = true; + return Ok(()); + } + }; - match term { - Addr::HeapCell(_) | Addr::StackCell(..) => - // 8.5.2.3 b) - { - return Err(self.error_form(MachineError::instantiation_error(), stub)) - } - Addr::Str(o) => match self.heap[o].clone() { - HeapCellValue::NamedStr(arity, _, _) if 1 <= n && n <= arity => { - let a3 = self[temp_v!(3)].clone(); - let h_a = Addr::HeapCell(o + n); + let term = self.store(self.deref(self[temp_v!(2)].clone())); - self.unify(a3, h_a); + match term { + Addr::HeapCell(_) | Addr::StackCell(..) => { // 8.5.2.3 b) + return Err(self.error_form(MachineError::instantiation_error(), stub)) } - _ => self.fail = true, - }, - Addr::Lis(l) => { - if n == 1 || n == 2 { - let a3 = self[temp_v!(3)].clone(); - let h_a = Addr::HeapCell(l + n - 1); + Addr::Str(o) => match self.heap.clone(o) { + HeapCellValue::NamedStr(arity, _, _) if 1 <= n && n <= arity => { + let a3 = self[temp_v!(3)].clone(); + let h_a = Addr::HeapCell(o + n); - self.unify(a3, h_a); - } else { - self.fail = true; - } - } - Addr::PStrLocation(h, offset) => { - if n == 1 || n == 2 { - let a3 = self[temp_v!(3)].clone(); - let h_a = - if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] { - let s = pstr.block_as_str(); + self.unify(a3, h_a); + } + _ => self.fail = true, + }, + Addr::Lis(l) => { + if n == 1 || n == 2 { + let a3 = self[temp_v!(3)].clone(); + let h_a = Addr::HeapCell(l + n - 1); - if let Some(c) = s[offset ..].chars().next() { - if n == 1 { - Addr::Con(Constant::Char(c)) + self.unify(a3, h_a); + } else { + self.fail = true; + } + } + Addr::PStrLocation(h, offset) => { + if n == 1 || n == 2 { + let a3 = self[temp_v!(3)].clone(); + let h_a = + if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] { + if let Some(c) = pstr.range_from(offset ..).next() { + if n == 1 { + Addr::Char(c) + } else { + Addr::PStrLocation(h, offset + c.len_utf8()) + } } else { - Addr::PStrLocation(h, offset + c.len_utf8()) + unreachable!() } } else { unreachable!() - } - } else { - unreachable!() - }; + }; - self.unify(a3, h_a); - } else { - self.fail = true; - } - } - Addr::Con(Constant::String(o, ref s)) - if !self.flags.double_quotes.is_atom() && !s[o ..].is_empty() => - { - if n == 1 || n == 2 { - let a3 = self[temp_v!(3)].clone(); - let c = s[o ..].chars().next().unwrap(); - - let h_a = if n == 1 { - Addr::Con(Constant::Char(c)) + self.unify(a3, h_a); } else { - Addr::Con(Constant::String(o + c.len_utf8(), s.clone())) - }; - - self.unify(a3, h_a); - } else { - self.fail = true; + self.fail = true; + } + } + _ => { // 8.5.2.3 d) + return Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Compound, + term, + ), + stub, + )) } } - _ => - // 8.5.2.3 d) - { - return Err(self.error_form( - MachineError::type_error(ValidType::Compound, term), - stub, - )) - } + } else { + return Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + Addr::Con(h), + ), + stub, + )) } } - _ => - // 8.5.2.3 c) - { + _ => { // 8.5.2.3 c) return Err(self.error_form( - MachineError::type_error(ValidType::Integer, n), + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + n, + ), stub, )) } @@ -2155,18 +1586,21 @@ impl MachineState { let a2 = self[temp_v!(2)].clone(); match self.compare_term_test(&a1, &a2) { - Ordering::Greater => match qt { + Some(Ordering::Greater) => match qt { CompareTermQT::GreaterThan | CompareTermQT::GreaterThanOrEqual => return, _ => self.fail = true, }, - Ordering::Equal => match qt { + Some(Ordering::Equal) => match qt { CompareTermQT::GreaterThanOrEqual | CompareTermQT::LessThanOrEqual => return, _ => self.fail = true, }, - Ordering::Less => match qt { + Some(Ordering::Less) => match qt { CompareTermQT::LessThan | CompareTermQT::LessThanOrEqual => return, _ => self.fail = true, }, + None => { + self.fail = true; + } }; } @@ -2177,35 +1611,74 @@ impl MachineState { while let Some((v1, v2)) = iter.next() { match (v1, v2) { - (HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) => - if ar1 != ar2 || n1 != n2 { - return true; - }, - (HeapCellValue::Addr(Addr::PStrLocation(..)), - HeapCellValue::Addr(Addr::PStrLocation(..))) => - continue, - (HeapCellValue::Addr(Addr::PStrLocation(..)), - HeapCellValue::Addr(Addr::Con(Constant::String(..)))) - | (HeapCellValue::Addr(Addr::Con(Constant::String(..))), - HeapCellValue::Addr(Addr::PStrLocation(..))) - if self.flags.double_quotes.is_chars() => { + (Addr::Str(s1), Addr::Str(s2)) => { + if let HeapCellValue::NamedStr(ar1, n1, _) = &self.heap[s1] { + if let HeapCellValue::NamedStr(ar2, n2, _) = &self.heap[s2] { + if ar1 != ar2 || n1 != n2 { + return true; + } + } else { + unreachable!() + } + } else { + unreachable!() + } + } + (Addr::PStrLocation(..), Addr::Lis(_)) + | (Addr::Lis(_), Addr::PStrLocation(..)) + if !self.flags.double_quotes.is_atom() => { continue; } - (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Lis(_))) => - continue, - (HeapCellValue::Addr(Addr::Con(Constant::EmptyList)), - HeapCellValue::Addr(Addr::Con(Constant::String(n, s)))) - | (HeapCellValue::Addr(Addr::Con(Constant::String(n, s))), - HeapCellValue::Addr(Addr::Con(Constant::EmptyList))) => - return match self.flags.double_quotes { - DoubleQuotes::Atom => true, - _ => n < s.len() - }, - (HeapCellValue::Addr(a1), HeapCellValue::Addr(a2)) => + (Addr::PStrLocation(..), Addr::PStrLocation(..)) => { + continue; + } + (Addr::Lis(_), Addr::Lis(_)) => { + continue; + } + (Addr::Con(h1), Addr::Con(h2)) => { + match (&self.heap[h1], &self.heap[h2]) { + ( + &HeapCellValue::Integer(ref n1), + &HeapCellValue::Integer(ref n2), + ) => { + if n1 != n2 { + return true; + } + } + ( + &HeapCellValue::Rational(ref n1), + &HeapCellValue::Rational(ref n2), + ) => { + if n1 != n2 { + return true; + } + } + ( + &HeapCellValue::DBRef(ref db_ref_1), + &HeapCellValue::DBRef(ref db_ref_2), + ) => { + if db_ref_1 != db_ref_2 { + return true; + } + } + ( + &HeapCellValue::Atom(ref n1, ref spec_1), + &HeapCellValue::Atom(ref n2, ref spec_2), + ) => { + if n1 != n2 || spec_1 != spec_2 { + return true; + } + } + _ => { + return true; + } + } + } + (a1, a2) => { if a1 != a2 { return true; - }, - _ => return true, + } + } } } @@ -2213,340 +1686,383 @@ impl MachineState { iter.first_to_expire != Ordering::Equal } - pub(super) fn compare_term_test(&self, a1: &Addr, a2: &Addr) -> Ordering { + pub(super) fn compare_term_test(&self, a1: &Addr, a2: &Addr) -> Option { let mut iter = self.zipped_acyclic_pre_order_iter(a1.clone(), a2.clone()); while let Some((v1, v2)) = iter.next() { - match (v1, v2) { - ( - HeapCellValue::Addr(Addr::Lis(_)), - HeapCellValue::Addr(Addr::PStrLocation(..)), - ) - | ( - HeapCellValue::Addr(Addr::PStrLocation(..)), - HeapCellValue::Addr(Addr::Lis(_)), - ) - | ( - HeapCellValue::Addr(Addr::PStrLocation(..)), - HeapCellValue::Addr(Addr::PStrLocation(..)), - ) => { - } - ( - HeapCellValue::Addr(Addr::PStrLocation(..)), - HeapCellValue::Addr(Addr::Con(Constant::String(..))), - ) - | ( - HeapCellValue::Addr(Addr::Con(Constant::String(..))), - HeapCellValue::Addr(Addr::PStrLocation(..)), - ) if self.flags.double_quotes.is_chars() => { - } - ( - HeapCellValue::Addr(Addr::Lis(_)), - HeapCellValue::Addr(Addr::Con(Constant::String(..))), - ) - | ( - HeapCellValue::Addr(Addr::Con(Constant::String(..))), - HeapCellValue::Addr(Addr::Lis(_)), - ) if !self.flags.double_quotes.is_atom() => { - } - ( - HeapCellValue::Addr(Addr::Con(Constant::EmptyList)), - HeapCellValue::Addr(Addr::Con(Constant::String(n, ref s))), - ) if !self.flags.double_quotes.is_atom() => { - if s[n ..].is_empty() { - return Ordering::Equal; - } else { - return Ordering::Greater; - } - } - ( - HeapCellValue::Addr(Addr::Con(Constant::Char(c1))), - HeapCellValue::Addr(Addr::Con(Constant::Char(c2))), - ) => { - if c1 != c2 { - return c1.cmp(&c2); - } - } - ( - HeapCellValue::Addr(Addr::Con(Constant::Atom(atom, _))), - HeapCellValue::Addr(Addr::Con(Constant::Char(c))), - ) => { - return if atom.as_str().chars().count() == 1 { - atom.as_str().chars().next().cmp(&Some(c)) - } else { - Ordering::Greater - } - } - ( - HeapCellValue::Addr(Addr::Con(Constant::Char(c))), - HeapCellValue::Addr(Addr::Con(Constant::Atom(atom, _))), - ) => { - return if atom.as_str().chars().count() == 1 { - Some(c).cmp(&atom.as_str().chars().next()) - } else { - Ordering::Less + let order_cat_v1 = v1.order_category(&self.heap); + let order_cat_v2 = v2.order_category(&self.heap); + + if order_cat_v1 != order_cat_v1 { + return Some(order_cat_v1.cmp(&order_cat_v2)); + } + + match order_cat_v1 { + Some(TermOrderCategory::Variable) => { + let v1 = v1.as_var().unwrap(); + let v2 = v2.as_var().unwrap(); + + if v1 != v2 { + return Some(v1.cmp(&v2)); } } - ( - HeapCellValue::Addr(Addr::Con(Constant::String(n, ref s))), - HeapCellValue::Addr(Addr::Con(Constant::EmptyList)), - ) if !self.flags.double_quotes.is_atom() => { - if s[n ..].is_empty() { - return Ordering::Equal; + Some(TermOrderCategory::FloatingPoint) => { + if let Addr::Float(f1) = v1 { + if let Addr::Float(f2) = v2 { + return Some(f1.cmp(&f2)); + } else { + unreachable!() + } } else { - return Ordering::Less; - } - } - ( - HeapCellValue::Addr(Addr::HeapCell(hc1)), - HeapCellValue::Addr(Addr::HeapCell(hc2)), - ) - | ( - HeapCellValue::Addr(Addr::AttrVar(hc1)), - HeapCellValue::Addr(Addr::HeapCell(hc2)), - ) - | ( - HeapCellValue::Addr(Addr::HeapCell(hc1)), - HeapCellValue::Addr(Addr::AttrVar(hc2)), - ) - | ( - HeapCellValue::Addr(Addr::AttrVar(hc1)), - HeapCellValue::Addr(Addr::AttrVar(hc2)), - ) => { - if hc1 != hc2 { - return hc1.cmp(&hc2); - } - } - (HeapCellValue::Addr(Addr::HeapCell(_)), _) - | (HeapCellValue::Addr(Addr::AttrVar(_)), _) => { - return Ordering::Less; - } - ( - HeapCellValue::Addr(Addr::StackCell(fr1, sc1)), - HeapCellValue::Addr(Addr::StackCell(fr2, sc2)), - ) => { - if fr1 > fr2 { - return Ordering::Greater; - } else if fr1 < fr2 || sc1 < sc2 { - return Ordering::Less; - } else if sc1 > sc2 { - return Ordering::Greater; - } - } - ( - HeapCellValue::Addr(Addr::StackCell(..)), - HeapCellValue::Addr(Addr::HeapCell(_)), - ) - | ( - HeapCellValue::Addr(Addr::StackCell(..)), - HeapCellValue::Addr(Addr::AttrVar(_)), - ) => { - return Ordering::Greater; - } - (HeapCellValue::Addr(Addr::StackCell(..)), _) => { - return Ordering::Less; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::Integer(..))), - HeapCellValue::Addr(Addr::HeapCell(_)), - ) - | ( - HeapCellValue::Addr(Addr::Con(Constant::Integer(..))), - HeapCellValue::Addr(Addr::AttrVar(_)), - ) => { - return Ordering::Greater; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::Integer(..))), - HeapCellValue::Addr(Addr::StackCell(..)), - ) => { - return Ordering::Greater; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::Integer(n1))), - HeapCellValue::Addr(Addr::Con(Constant::Integer(n2))), - ) => { - if n1 != n2 { - return n1.cmp(&n2); - } - } - (HeapCellValue::Addr(Addr::Con(Constant::Integer(_))), _) => { - return Ordering::Less; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::Float(..))), - HeapCellValue::Addr(Addr::HeapCell(_)), - ) - | ( - HeapCellValue::Addr(Addr::Con(Constant::Float(..))), - HeapCellValue::Addr(Addr::AttrVar(_)), - ) => { - return Ordering::Greater; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::Float(..))), - HeapCellValue::Addr(Addr::StackCell(..)), - ) => { - return Ordering::Greater; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::Float(n1))), - HeapCellValue::Addr(Addr::Con(Constant::Float(n2))), - ) => { - if n1 != n2 { - return n1.cmp(&n2); - } - } - (HeapCellValue::Addr(Addr::Con(Constant::Float(_))), _) => return Ordering::Less, - ( - HeapCellValue::Addr(Addr::Con(Constant::Rational(..))), - HeapCellValue::Addr(Addr::HeapCell(_)), - ) - | ( - HeapCellValue::Addr(Addr::Con(Constant::Rational(..))), - HeapCellValue::Addr(Addr::AttrVar(_)), - ) => { - return Ordering::Greater; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::Rational(..))), - HeapCellValue::Addr(Addr::StackCell(..)), - ) => { - return Ordering::Greater; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::Rational(n1))), - HeapCellValue::Addr(Addr::Con(Constant::Rational(n2))), - ) => { - if n1 != n2 { - return n1.cmp(&n2); + unreachable!() } } - (HeapCellValue::Addr(Addr::Con(Constant::Rational(_))), _) => { - return Ordering::Less - } - ( - HeapCellValue::Addr(Addr::Con(Constant::String(..))), - HeapCellValue::Addr(Addr::HeapCell(_)), - ) - | ( - HeapCellValue::Addr(Addr::Con(Constant::String(..))), - HeapCellValue::Addr(Addr::AttrVar(_)), - ) => { - return Ordering::Greater; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::String(..))), - HeapCellValue::Addr(Addr::StackCell(..)), - ) => { - return Ordering::Greater; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::String(..))), - HeapCellValue::Addr(Addr::Con(Constant::Integer(_))), - ) => { - return Ordering::Greater; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::String(..))), - HeapCellValue::Addr(Addr::Con(Constant::Rational(_))), - ) => { - return Ordering::Greater; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::String(..))), - HeapCellValue::Addr(Addr::Con(Constant::Float(_))), - ) => { - return Ordering::Greater; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::String(n1, s1))), - HeapCellValue::Addr(Addr::Con(Constant::String(n2, s2))), - ) => { - return s1[n1 ..].cmp(&s2[n2 ..]); - } - (HeapCellValue::Addr(Addr::Con(Constant::String(..))), _) => { - return Ordering::Less; - } - ( - HeapCellValue::Addr(Addr::Con(Constant::Atom(..))), - HeapCellValue::Addr(Addr::HeapCell(_)), - ) - | ( - HeapCellValue::Addr(Addr::Con(Constant::Atom(..))), - HeapCellValue::Addr(Addr::AttrVar(_)), - ) => return Ordering::Greater, - ( - HeapCellValue::Addr(Addr::Con(Constant::Atom(..))), - HeapCellValue::Addr(Addr::StackCell(..)), - ) => return Ordering::Greater, - ( - HeapCellValue::Addr(Addr::Con(Constant::Atom(..))), - HeapCellValue::Addr(Addr::Con(Constant::Float(_))), - ) => return Ordering::Greater, - ( - HeapCellValue::Addr(Addr::Con(Constant::Atom(..))), - HeapCellValue::Addr(Addr::Con(Constant::Integer(_))), - ) => return Ordering::Greater, - ( - HeapCellValue::Addr(Addr::Con(Constant::Atom(..))), - HeapCellValue::Addr(Addr::Con(Constant::Rational(_))), - ) => return Ordering::Greater, - ( - HeapCellValue::Addr(Addr::Con(Constant::Atom(..))), - HeapCellValue::Addr(Addr::Con(Constant::String(..))), - ) => return Ordering::Greater, - ( - HeapCellValue::Addr(Addr::Con(Constant::Atom(s1, _))), - HeapCellValue::Addr(Addr::Con(Constant::Atom(s2, _))), - ) => { - if s1 != s2 { - return s1.cmp(&s2); + Some(TermOrderCategory::Integer) => { + match (v1, v2) { + ( + Addr::Con(h1), + Addr::Con(h2), + ) => { + match (&self.heap[h1], &self.heap[h2]) { + ( + HeapCellValue::Integer(ref n1), + HeapCellValue::Integer(ref n2), + ) => { + if &*n1 != &*n2 { + return Some(n1.cmp(&*n2)); + } + } + ( + HeapCellValue::Rational(ref n1), + HeapCellValue::Integer(ref n2), + ) => { + if &**n1 != &**n2 { + return n1.as_ref().partial_cmp(n2.as_ref()); + } + } + ( + HeapCellValue::Integer(ref n1), + HeapCellValue::Rational(ref n2), + ) => { + if &**n1 != &**n2 { + return n1.as_ref().partial_cmp(n2.as_ref()); + } + } + ( + HeapCellValue::Rational(ref r1), + HeapCellValue::Rational(ref r2), + ) => { + if &*r1 != &*r2 { + return Some(r1.cmp(r2)); + } + } + _ => { + unreachable!() + } + } + } + _ => { + unreachable!() + } } } - (HeapCellValue::Addr(Addr::Con(Constant::Atom(..))), _) => { - return Ordering::Less; - } - (HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) => { - if ar1 < ar2 { - return Ordering::Less; - } else if ar1 > ar2 { - return Ordering::Greater; - } else if n1 != n2 { - return n1.cmp(&n2); + Some(TermOrderCategory::Atom) => { + match (v1, v2) { + ( + Addr::Con(h1), + Addr::Con(h2), + ) => { + if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { + if let HeapCellValue::Atom(ref n2, _) = &self.heap[h2] { + if n1 != n2 { + return Some(n1.cmp(&n2)); + } + } else { + unreachable!() + } + } else { + unreachable!() + } + } + ( + Addr::Con(h1), + Addr::Char(c), + ) => { + if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { + if n1.is_char() { + if n1.as_str().chars().next() != Some(c) { + return Some(n1.as_str().chars().next().cmp(&Some(c))); + } + } else { + return Some(Ordering::Greater); + } + } else { + unreachable!() + } + } + ( + Addr::Char(c), + Addr::Con(h1), + ) => { + if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { + if n1.is_char() { + if n1.as_str().chars().next() != Some(c) { + return Some(Some(c).cmp(&n1.as_str().chars().next())); + } + } else { + return Some(Ordering::Less); + } + } else { + unreachable!() + } + } + ( + Addr::Con(h), + Addr::CharCode(c), + ) => { + let c = std::char::from_u32(c).unwrap(); + + if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] { + if n1.is_char() { + if n1.as_str().chars().next() != Some(c) { + return Some(n1.as_str().chars().next().cmp(&Some(c))); + } + } else { + return Some(Ordering::Greater); + } + } else { + unreachable!() + } + } + ( + Addr::CharCode(c), + Addr::Con(h), + ) => { + let c = std::char::from_u32(c).unwrap(); + + if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] { + if n1.is_char() { + if n1.as_str().chars().next() != Some(c) { + return Some(Some(c).cmp(&n1.as_str().chars().next())); + } + } else { + return Some(Ordering::Less); + } + } else { + unreachable!() + } + } + ( + Addr::EmptyList, + Addr::Con(h), + ) => { + if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] { + if "[]" != n1.as_str() { + return Some("[]".cmp(n1.as_str())); + } + } else { + unreachable!() + } + } + ( + Addr::Con(h), + Addr::EmptyList, + ) => { + if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] { + if "[]" != n1.as_str() { + return Some(n1.as_str().cmp("[]")); + } + } else { + unreachable!() + } + } + ( + Addr::Char(c1), + Addr::Char(c2), + ) => { + if c1 != c2 { + return Some(c1.cmp(&c2)); + } + } + ( + Addr::CharCode(c1), + Addr::CharCode(c2), + ) => { + if c1 != c2 { + return Some(c1.cmp(&c2)); + } + } + ( + Addr::Char(c1), + Addr::CharCode(c2), + ) => { + let c2 = std::char::from_u32(c2).unwrap(); + + if c1 != c2 { + return Some(c1.cmp(&c2)); + } + } + ( + Addr::CharCode(c1), + Addr::Char(c2), + ) => { + let c1 = std::char::from_u32(c1).unwrap(); + + if c1 != c2 { + return Some(c1.cmp(&c2)); + } + } + ( + Addr::Char(c), + Addr::EmptyList, + ) => { + return if c == '[' { + Some(Ordering::Less) + } else { + Some(c.cmp(&'[')) + }; + } + ( + Addr::EmptyList, + Addr::Char(c), + ) => { + return if c == '[' { + Some(Ordering::Greater) + } else { + Some('['.cmp(&c)) + }; + } + ( + Addr::CharCode(c), + Addr::EmptyList, + ) => { + let c = std::char::from_u32(c).unwrap(); + + return if c == '[' { + Some(Ordering::Less) + } else { + Some(c.cmp(&'[')) + }; + } + ( + Addr::EmptyList, + Addr::CharCode(c), + ) => { + let c = std::char::from_u32(c).unwrap(); + + return if c == '[' { + Some(Ordering::Greater) + } else { + Some('['.cmp(&c)) + }; + } + _ => { + return None; + } } } - (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Lis(_))) => { - continue; - } - (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::NamedStr(ar, n, _)) - | (HeapCellValue::NamedStr(ar, n, _), HeapCellValue::Addr(Addr::Lis(_))) => { - if ar == 2 && n.as_str() == "." { - continue; - } else if ar < 2 { - return Ordering::Greater; - } else if ar > 2 { - return Ordering::Less; - } else { - return n.as_str().cmp("."); + Some(TermOrderCategory::Compound) => { + match (v1, v2) { + ( + Addr::Lis(_), + Addr::Lis(_), + ) => { + } + ( + Addr::PStrLocation(..), + Addr::PStrLocation(..), + ) => { + } + ( + Addr::Str(h1), + Addr::Str(h2), + ) => { + if let HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[h1] { + if let HeapCellValue::NamedStr(a2, ref n2, _) = &self.heap[h2] { + if a1 != a2 || n1.as_str() != n2.as_str() { + return Some(a1.cmp(&a2).then_with(|| n1.as_str().cmp(n2.as_str()))); + } + } else { + unreachable!() + } + } else { + unreachable!() + } + } + ( + Addr::Lis(_), + Addr::PStrLocation(..), + ) | + ( + Addr::PStrLocation(..), + Addr::Lis(_), + ) if !self.flags.double_quotes.is_atom() => { + } + ( + Addr::Lis(_), + Addr::Str(s), + ) => { + if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { + if a1 != 2 || n1.as_str() != "." { + return Some(a1.cmp(&2).then_with(|| n1.as_str().cmp("."))); + } + } else { + unreachable!() + } + } + ( + Addr::Str(s), + Addr::Lis(_), + ) => { + if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { + if a1 != 2 || n1.as_str() != "." { + return Some(2.cmp(&a1).then_with(|| ".".cmp(n1.as_str()))); + } + } else { + unreachable!() + } + } + ( + Addr::PStrLocation(..), + Addr::Str(s), + ) if !self.flags.double_quotes.is_atom() => { + if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { + if a1 != 2 || n1.as_str() != "." { + return Some(a1.cmp(&2).then_with(|| n1.as_str().cmp("."))); + } + } else { + unreachable!() + } + } + ( + Addr::Str(s), + Addr::PStrLocation(..), + ) if !self.flags.double_quotes.is_atom() => { + if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { + if a1 != 2 || n1.as_str() != "." { + return Some(2.cmp(&a1).then_with(|| ".".cmp(n1.as_str()))); + } + } else { + unreachable!() + } + } + _ => { + return None; + } } } - (HeapCellValue::NamedStr(..), _) => { - return Ordering::Greater; - } - (HeapCellValue::Addr(Addr::Lis(_)), _) => { - return Ordering::Greater; + None => { + return None; } - _ => {} } } - iter.first_to_expire + Some(iter.first_to_expire) } pub(super) fn reset_block(&mut self, addr: Addr) { match self.store(addr) { - Addr::Con(Constant::Usize(b)) => self.block = b, + Addr::Usize(b) => self.block = b, _ => self.fail = true, }; } @@ -2563,8 +2079,14 @@ impl MachineState { let d = self.store(self.deref(self[r1].clone())); match d { - Addr::Con(Constant::Atom(..)) | Addr::Con(Constant::Char(_)) => self.p += 1, - Addr::Con(Constant::EmptyList) => self.p += 1, + Addr::Con(h) => + if let HeapCellValue::Atom(..) = &self.heap[h] { + self.p += 1; + } else { + self.fail = true; + }, + Addr::Char(_) => self.p += 1, + Addr::EmptyList => self.p += 1, _ => self.fail = true, }; } @@ -2580,22 +2102,36 @@ impl MachineState { let d = self.store(self.deref(self[r1].clone())); match d { - Addr::Con(Constant::Integer(_)) => self.p += 1, - Addr::Con(Constant::CharCode(_)) => self.p += 1, - Addr::Con(Constant::Char(_)) - if self.flags.double_quotes.is_codes() => self.p += 1, - Addr::Con(Constant::Rational(r)) => { - if r.denom() == &1 { - self.p += 1; - } else { - self.fail = true; + Addr::Con(h) => { + match &self.heap[h] { + HeapCellValue::Integer(_) => { + self.p += 1; + } + HeapCellValue::Rational(ref r) => { + if r.denom() == &1 { + self.p += 1; + } else { + self.fail = true; + } + } + _ => { + self.fail = true; + } } } - _ => self.fail = true, + Addr::CharCode(_) => { + self.p += 1; + } + Addr::Char(_) if self.flags.double_quotes.is_codes() => { + self.p += 1; + } + _ => { + self.fail = true; + } }; } &InlinedClauseType::IsCompound(r1) => { - let d = self.store(self.deref(self[r1].clone())); + let d = self.store(self.deref(self[r1])); match d { Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => self.p += 1, @@ -2606,7 +2142,7 @@ impl MachineState { let d = self.store(self.deref(self[r1].clone())); match d { - Addr::Con(Constant::Float(_)) => self.p += 1, + Addr::Float(_) => self.p += 1, _ => self.fail = true, }; } @@ -2614,15 +2150,23 @@ impl MachineState { let d = self.store(self.deref(self[r1].clone())); match d { - Addr::Con(Constant::Rational(_)) => self.p += 1, - _ => self.fail = true, + Addr::Con(h) => { + if let HeapCellValue::Rational(_) = &self.heap[h] { + self.p += 1; + } else { + self.fail = true; + } + } + _ => { + self.fail = true; + } }; } &InlinedClauseType::IsString(r1) => { let d = self.store(self.deref(self[r1].clone())); match d { - Addr::Con(Constant::String(..)) => self.p += 1, + Addr::PStrLocation(..) => self.p += 1, _ => self.fail = true, }; } @@ -2653,29 +2197,31 @@ impl MachineState { } } - fn try_functor_unify_components(&mut self, name: Addr, arity: Addr) { - let a2 = self[temp_v!(2)].clone(); - let a3 = self[temp_v!(3)].clone(); - - self.unify(a2, name); - - if !self.fail { - self.unify(a3, arity); - } - } - fn try_functor_compound_case( &mut self, name: ClauseName, arity: usize, spec: Option, ) { - let name = Addr::Con(Constant::Atom(name, spec)); - let arity = Addr::Con(Constant::Integer(Integer::from(arity))); - + let name = self.heap.to_unifiable(HeapCellValue::Atom(name, spec)); self.try_functor_unify_components(name, arity); } + fn try_functor_unify_components( + &mut self, + name: Addr, + arity: usize, + ) { + let a2 = self[temp_v!(2)]; + let a3 = self[temp_v!(3)]; + + self.unify(a2, name); + + if !self.fail { + self.unify(a3, Addr::Usize(arity)); + } + } + fn try_functor_fabricate_struct( &mut self, name: ClauseName, @@ -2689,10 +2235,7 @@ impl MachineState { let f_a = if name.as_str() == "." && arity == 2 { Addr::Lis(self.heap.h()) } else { - let h = self.heap.h(); - self.heap.push(HeapCellValue::NamedStr(arity as usize, name, spec)); - - Addr::Str(h) + self.heap.to_unifiable(HeapCellValue::NamedStr(arity as usize, name, spec)) }; for _ in 0..arity { @@ -2703,41 +2246,56 @@ impl MachineState { self.bind(r, f_a); } - pub(super) fn try_functor(&mut self, indices: &IndexStore) -> CallResult { + pub(super) + fn try_functor(&mut self, indices: &IndexStore) -> CallResult { let stub = MachineError::functor_stub(clause_name!("functor"), 3); - let a1 = self.store(self.deref(self[temp_v!(1)].clone())); + let a1 = self.store(self.deref(self[temp_v!(1)])); - match a1.clone() { - Addr::Stream(_) | Addr::DBRef(_) => self.fail = true, - Addr::Con(Constant::String(n, ref s)) - if !self.flags.double_quotes.is_atom() && !s[n ..].is_empty() => - { - let shared_op_desc = fetch_op_spec(clause_name!("."), 2, None, &indices.op_dir); - self.try_functor_compound_case(clause_name!("."), 2, shared_op_desc) - } - Addr::Con(_) => self - .try_functor_unify_components(a1, Addr::Con(Constant::Integer(Integer::from(0)))), - Addr::Str(o) => match self.heap[o].clone() { + match a1 { + Addr::Stream(_) => { + self.fail = true; + } + Addr::Char(_) | Addr::CharCode(_) | Addr::Con(_) | Addr::Float(_) => { + self.try_functor_unify_components(a1, 0); + } + Addr::Str(o) => match self.heap.clone(o) { HeapCellValue::NamedStr(arity, name, spec) => { let spec = fetch_op_spec(name.clone(), arity, spec, &indices.op_dir); self.try_functor_compound_case(name, arity, spec) } - _ => self.fail = true, + _ => { + self.fail = true; + } }, Addr::Lis(_) | Addr::PStrLocation(..) => { - let shared_op_desc = fetch_op_spec(clause_name!("."), 2, None, &indices.op_dir); - self.try_functor_compound_case(clause_name!("."), 2, shared_op_desc) + let spec = fetch_op_spec(clause_name!("."), 2, None, &indices.op_dir); + self.try_functor_compound_case(clause_name!("."), 2, spec) } Addr::AttrVar(..) | Addr::HeapCell(_) | Addr::StackCell(..) => { - let name = self.store(self.deref(self[temp_v!(2)].clone())); - let arity = self.store(self.deref(self[temp_v!(3)].clone())); + let name = self.store(self.deref(self[temp_v!(2)])); + let arity = self.store(self.deref(self[temp_v!(3)])); if name.is_ref() || arity.is_ref() { // 8.5.1.3 a) & 8.5.1.3 b) return Err(self.error_form(MachineError::instantiation_error(), stub)); } - if let Addr::Con(Constant::Integer(arity)) = arity { + if let Addr::Con(h) = arity { + let arity = if let HeapCellValue::Integer(ref n) = &self.heap[h] { + n.clone() + } else { + return Err( + self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + arity, + ), + stub, + ) + ); + }; + let arity = match arity.to_isize() { Some(arity) => arity, None => { @@ -2747,56 +2305,78 @@ impl MachineState { }; if arity > MAX_ARITY as isize { - let rep_err = MachineError::representation_error(RepFlag::MaxArity); // 8.5.1.3 f) + let rep_err = MachineError::representation_error(RepFlag::MaxArity); return Err(self.error_form(rep_err, stub)); } else if arity < 0 { // 8.5.1.3 g) - let arity = Integer::from(arity); + let arity = Number::Integer(Rc::new(Integer::from(arity))); let dom_err = MachineError::domain_error( - DomainError::NotLessThanZero, - Addr::Con(Constant::Integer(arity)), + DomainErrorType::NotLessThanZero, + arity, ); + return Err(self.error_form(dom_err, stub)); } match name { - Addr::Con(_) if arity == 0 => self.unify(a1, name), - Addr::Con(Constant::Atom(name, spec)) => self.try_functor_fabricate_struct( - name, - arity, - spec, - &indices.op_dir, - a1.as_var().unwrap(), - ), - Addr::Con(Constant::Char(c)) => { - let name = clause_name!(c.to_string(), indices.atom_tbl); + Addr::Con(_) if arity == 0 => { + self.unify(a1, name); + } + Addr::Con(h) => { + if let HeapCellValue::Atom(name, spec) = self.heap.clone(h) { + self.try_functor_fabricate_struct( + name, + arity, + spec, + &indices.op_dir, + a1.as_var().unwrap(), + ); + } else { + // 8.5.1.3 e) + return Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Atom, + name, + ), + stub, + )) + } + } + Addr::Char(c) => { self.try_functor_fabricate_struct( - name, + clause_name!(c.to_string(), indices.atom_tbl), arity, None, &indices.op_dir, a1.as_var().unwrap(), ); } - Addr::Con(_) => { - return Err(self - .error_form(MachineError::type_error(ValidType::Atom, name), stub)) - } // 8.5.1.3 e) _ => { return Err(self.error_form( - MachineError::type_error(ValidType::Atomic, name), + MachineError::type_error(self.heap.h(), ValidType::Atomic, name), stub, - )) + )); } // 8.5.1.3 c) - }; + } } else if !arity.is_ref() { // 8.5.1.3 d) return Err( - self.error_form(MachineError::type_error(ValidType::Integer, arity), stub) + self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + arity, + ), + stub, + ) ); } } + _ => { + self.fail = true; + } }; Ok(()) @@ -2805,14 +2385,14 @@ impl MachineState { pub(super) fn term_dedup(&self, list: &mut Vec) { let mut result = vec![]; - for a2 in list.iter().cloned() { - if let Some(a1) = result.last().cloned() { - if self.compare_term_test(&a1, &a2) == Ordering::Equal { + for a2 in list.iter() { + if let Some(a1) = result.last() { + if self.compare_term_test(&a1, &a2) == Some(Ordering::Equal) { continue; } } - result.push(a2); + result.push(*a2); } *list = result; @@ -2824,33 +2404,26 @@ impl MachineState { r: RegType, caller: MachineStub, ) -> Result, MachineStub> { - let a1 = self.store(self.deref(self[r].clone())); + let a1 = self.store(self.deref(self[r])); match a1.clone() { Addr::Lis(l) => { self.try_from_inner_list(vec![], l, caller, a1) } - Addr::Con(Constant::String(n, ref s)) - if !self.flags.double_quotes.is_atom() => { - if s.len() > n { - Ok(Vec::from_iter(s[n ..].chars().map(|c| { - Addr::Con(Constant::Char(c)) - }))) - } else { - Ok(vec![]) - } - } Addr::PStrLocation(h, n) => { self.try_from_partial_string(vec![], h, n, caller, a1) } - Addr::HeapCell(_) | Addr::StackCell(..) => { + Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => { Err(self.error_form(MachineError::instantiation_error(), caller)) } - Addr::Con(Constant::EmptyList) => { + Addr::EmptyList => { Ok(vec![]) } _ => { - Err(self.error_form(MachineError::type_error(ValidType::List, a1), caller)) + Err(self.error_form( + MachineError::type_error(self.heap.h(), ValidType::List, a1), + caller, + )) } } } @@ -2873,19 +2446,13 @@ impl MachineState { result.push(self.heap[hcp].as_addr(hcp)); l = hcp + 1; } - Addr::Con(Constant::String(n, ref s)) - if !self.flags.double_quotes.is_atom() => - { - result.push(Addr::Con(Constant::String(n, s.clone()))); - break; - } Addr::PStrLocation(h, n) => { return self.try_from_partial_string(result, h, n, caller, a1); } - Addr::Con(Constant::EmptyList) => { + Addr::EmptyList => { break; } - Addr::HeapCell(_) | Addr::StackCell(..) => { + Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => { return Err(self.error_form( MachineError::instantiation_error(), caller, @@ -2893,14 +2460,14 @@ impl MachineState { } _ => { return Err(self.error_form( - MachineError::type_error(ValidType::List, a1), + MachineError::type_error(self.heap.h(), ValidType::List, a1), caller, )) } }, _ => { return Err(self.error_form( - MachineError::type_error(ValidType::List, a1), + MachineError::type_error(self.heap.h(), ValidType::List, a1), caller, )) } @@ -2920,20 +2487,12 @@ impl MachineState { ) -> Result, MachineStub> { loop { if let HeapCellValue::PartialString(ref pstr) = &self.heap[h] { - let s = pstr.block_as_str(); - - chars.extend(s[n ..].chars().map(|c| Addr::Con(Constant::Char(c)))); + chars.extend(pstr.range_from(n ..).map(Addr::Char)); let tail = self.heap[h + 1].as_addr(h + 1); match self.store(self.deref(tail)) { - Addr::Con(Constant::EmptyList) => { - return Ok(chars); - } - Addr::Con(Constant::String(n, ref s)) - if !self.flags.double_quotes.is_atom() => - { - chars.push(Addr::Con(Constant::String(n, s.clone()))); + Addr::EmptyList => { return Ok(chars); } Addr::Lis(l) => { @@ -2945,7 +2504,7 @@ impl MachineState { } _ => { return Err(self.error_form( - MachineError::type_error(ValidType::List, a1), + MachineError::type_error(self.heap.h(), ValidType::List, a1), caller, )) } @@ -2964,16 +2523,34 @@ impl MachineState { Addr::HeapCell(_) | Addr::StackCell(..) => { Err(self.error_form(MachineError::instantiation_error(), stub)) } - Addr::Str(s) => match self.heap[s].clone() { - HeapCellValue::NamedStr(2, ref name, Some(_)) if *name == clause_name!("-") => { - Ok(Addr::HeapCell(s + 1)) + Addr::Str(s) => { + match self.heap.clone(s) { + HeapCellValue::NamedStr(2, ref name, Some(_)) + if *name == clause_name!("-") => { + Ok(Addr::HeapCell(s + 1)) + } + _ => { + Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Pair, + self.heap[s].as_addr(s), + ), + stub, + )) + } } - _ => Err(self.error_form( - MachineError::type_error(ValidType::Pair, self.heap[s].as_addr(s)), + } + a => { + Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Pair, + a, + ), stub, - )), - }, - a => Err(self.error_form(MachineError::type_error(ValidType::Pair, a), stub)), + )) + } } } @@ -2984,100 +2561,167 @@ impl MachineState { let a2 = self[temp_v!(2)].clone(); copy_term(CopyTerm::new(self), a1, attr_var_policy); + self.unify(Addr::HeapCell(old_h), a2); } // returns true on failure. pub(super) fn structural_eq_test(&self) -> bool { - let a1 = self[temp_v!(1)].clone(); - let a2 = self[temp_v!(2)].clone(); + let a1 = self[temp_v!(1)]; + let a2 = self[temp_v!(2)]; let mut var_pairs = IndexMap::new(); let iter = self.zipped_acyclic_pre_order_iter(a1, a2); for (v1, v2) in iter { - match (v1, v2) { + match ( + self.heap.index_addr(&v1).as_ref(), + self.heap.index_addr(&v2).as_ref(), + ) { ( HeapCellValue::Addr(Addr::Lis(_)), - HeapCellValue::Addr(Addr::Con(Constant::String(..))), + HeapCellValue::Addr(Addr::PStrLocation(..)), ) | ( - HeapCellValue::Addr(Addr::Con(Constant::String(..))), + HeapCellValue::Addr(Addr::PStrLocation(..)), HeapCellValue::Addr(Addr::Lis(_)), ) if !self.flags.double_quotes.is_atom() => { - continue; } ( - HeapCellValue::Addr(Addr::Con(Constant::String(n, ref s))), - HeapCellValue::Addr(Addr::Con(Constant::EmptyList)), - ) - | ( - HeapCellValue::Addr(Addr::Con(Constant::EmptyList)), - HeapCellValue::Addr(Addr::Con(Constant::String(n, ref s))), - ) if !self.flags.double_quotes.is_atom() => { - if !s[n ..].is_empty() { - return true; - } - } - (HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) => { + HeapCellValue::NamedStr(ar1, n1, _), + HeapCellValue::NamedStr(ar2, n2, _), + ) => { if ar1 != ar2 || n1 != n2 { return true; } } - (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Lis(_))) => { - continue; + ( + HeapCellValue::Addr(Addr::Lis(_)), + HeapCellValue::Addr(Addr::Lis(_)), + ) => { } ( - HeapCellValue::Addr(v1 @ Addr::HeapCell(_)), - HeapCellValue::Addr(v2 @ Addr::AttrVar(_)), + &HeapCellValue::Addr(v1 @ Addr::HeapCell(_)), + &HeapCellValue::Addr(v2 @ Addr::AttrVar(_)), ) | ( - HeapCellValue::Addr(v1 @ Addr::StackCell(..)), - HeapCellValue::Addr(v2 @ Addr::AttrVar(_)), + &HeapCellValue::Addr(v1 @ Addr::StackCell(..)), + &HeapCellValue::Addr(v2 @ Addr::AttrVar(_)), ) | ( - HeapCellValue::Addr(v1 @ Addr::AttrVar(_)), - HeapCellValue::Addr(v2 @ Addr::AttrVar(_)), + &HeapCellValue::Addr(v1 @ Addr::AttrVar(_)), + &HeapCellValue::Addr(v2 @ Addr::AttrVar(_)), ) | ( - HeapCellValue::Addr(v1 @ Addr::AttrVar(_)), - HeapCellValue::Addr(v2 @ Addr::HeapCell(_)), + &HeapCellValue::Addr(v1 @ Addr::AttrVar(_)), + &HeapCellValue::Addr(v2 @ Addr::HeapCell(_)), ) | ( - HeapCellValue::Addr(v1 @ Addr::AttrVar(_)), - HeapCellValue::Addr(v2 @ Addr::StackCell(..)), + &HeapCellValue::Addr(v1 @ Addr::AttrVar(_)), + &HeapCellValue::Addr(v2 @ Addr::StackCell(..)), ) | ( - HeapCellValue::Addr(v1 @ Addr::HeapCell(_)), - HeapCellValue::Addr(v2 @ Addr::HeapCell(_)), + &HeapCellValue::Addr(v1 @ Addr::HeapCell(_)), + &HeapCellValue::Addr(v2 @ Addr::HeapCell(_)), ) | ( - HeapCellValue::Addr(v1 @ Addr::HeapCell(_)), - HeapCellValue::Addr(v2 @ Addr::StackCell(..)), + &HeapCellValue::Addr(v1 @ Addr::HeapCell(_)), + &HeapCellValue::Addr(v2 @ Addr::StackCell(..)), ) | ( - HeapCellValue::Addr(v1 @ Addr::StackCell(..)), - HeapCellValue::Addr(v2 @ Addr::StackCell(..)), + &HeapCellValue::Addr(v1 @ Addr::StackCell(..)), + &HeapCellValue::Addr(v2 @ Addr::StackCell(..)), ) | ( - HeapCellValue::Addr(v1 @ Addr::StackCell(..)), - HeapCellValue::Addr(v2 @ Addr::HeapCell(_)), + &HeapCellValue::Addr(v1 @ Addr::StackCell(..)), + &HeapCellValue::Addr(v2 @ Addr::HeapCell(_)), ) => - match (var_pairs.get(&v1).cloned(), var_pairs.get(&v2).cloned()) { - (Some(ref v2_p), Some(ref v1_p)) if *v1_p == v1 && *v2_p == v2 => continue, - (Some(_), _) | (_, Some(_)) => return true, + match (var_pairs.get(&v1), var_pairs.get(&v2)) { + (Some(ref v2_p), Some(ref v1_p)) if **v1_p == v1 && **v2_p == v2 => { + continue; + } + (Some(_), _) | (_, Some(_)) => { + return true; + } (None, None) => { - var_pairs.insert(v1.clone(), v2.clone()); + var_pairs.insert(v1, v2); var_pairs.insert(v2, v1); } }, - (HeapCellValue::Addr(a1), HeapCellValue::Addr(a2)) => { + ( + HeapCellValue::PartialString(ref pstr1), + HeapCellValue::PartialString(ref pstr2), + ) => { + let pstr1_iter = pstr1.range_from(0 ..); + let pstr2_iter = pstr2.range_from(0 ..); + + for (c1, c2) in pstr1_iter.zip(pstr2_iter) { + if c1 != c2 { + return true; + } + } + } + ( + HeapCellValue::Addr(Addr::PStrLocation(..)), + HeapCellValue::Addr(Addr::PStrLocation(..)), + ) => { + } + ( + HeapCellValue::Integer(n1), + HeapCellValue::Integer(n2), + ) => { + if &*n1 != &*n2 { + return true; + } + } + ( + HeapCellValue::Rational(n1), + HeapCellValue::Rational(n2), + ) => { + if &*n1 != &*n2 { + return true; + } + } + ( + HeapCellValue::Integer(ref n1), + HeapCellValue::Rational(ref n2), + ) | + ( + HeapCellValue::Rational(ref n2), + HeapCellValue::Integer(ref n1), + ) => { + if n1.as_ref().partial_cmp(&**n2) == Some(Ordering::Equal) { + return true; + } + } + ( + HeapCellValue::Atom(ref n1, ref spec_1), + HeapCellValue::Atom(ref n2, ref spec_2), + ) => { + if n1 != n2 || spec_1 != spec_2 { + return true; + } + } + ( + HeapCellValue::DBRef(ref db_ref_1), + HeapCellValue::DBRef(ref db_ref_2), + ) => { + if db_ref_1 != db_ref_2 { + return true; + } + } + ( + HeapCellValue::Addr(a1), + HeapCellValue::Addr(a2), + ) => { if a1 != a2 { return true; } } - _ => return true, + _ => { + return true; + } } } @@ -3091,9 +2735,9 @@ impl MachineState { for v in self.acyclic_pre_order_iter(a) { match v { - HeapCellValue::Addr(Addr::HeapCell(..)) => return true, - HeapCellValue::Addr(Addr::StackCell(..)) => return true, - HeapCellValue::Addr(Addr::AttrVar(..)) => return true, + Addr::HeapCell(..) => return true, + Addr::StackCell(..) => return true, + Addr::AttrVar(..) => return true, _ => {} } } @@ -3367,7 +3011,7 @@ impl MachineState { &CutInstruction::GetLevel(r) => { let b0 = self.b0; - self[r] = Addr::Con(Constant::CutPoint(b0)); + self[r] = Addr::CutPoint(b0); self.p += 1; } &CutInstruction::GetLevelAndUnify(r) => { diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index 8ee64136..7271c150 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -19,13 +19,15 @@ pub mod machine_errors; pub mod machine_indices; pub(super) mod machine_state; pub mod modules; -mod partial_string; +pub mod partial_string; mod raw_block; mod stack; pub(crate) mod streams; pub(super) mod term_expansion; pub mod toplevel; +#[macro_use] +mod arithmetic_ops; #[macro_use] mod machine_state_impl; mod system_calls; @@ -340,8 +342,8 @@ impl Machine { // the first of these is the path to the scryer-prolog executable, so skip // it. for filename in env::args().skip(1) { - let atom = atom!(filename, self.indices.atom_tbl); - filename_atoms.push(Addr::Con(atom)); + let atom = clause_name!(filename, self.indices.atom_tbl); + filename_atoms.push(HeapCellValue::Atom(atom, None)); } let list_addr = @@ -547,14 +549,14 @@ impl Machine { HeapCellValue::NamedStr(arity, ref name, _) if *arity == 2 && name.as_str() == "/" => { let name = match &self.machine_st.heap[s+1] { - &HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) => + &HeapCellValue::Atom(ref name, _) => name.clone(), _ => unreachable!() }; let arity = match &self.machine_st.heap[s+2] { - &HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) => + &HeapCellValue::Integer(ref arity) => arity.to_usize().unwrap(), _ => unreachable!() @@ -565,21 +567,21 @@ impl Machine { HeapCellValue::NamedStr(arity, ref name, _) if *arity == 3 && name.as_str() == "op" => { let name = match &self.machine_st.heap[s+3] { - &HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) => + &HeapCellValue::Atom(ref name, _) => name.clone(), _ => unreachable!() }; let spec = match &self.machine_st.heap[s+2] { - &HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) => + &HeapCellValue::Atom(ref name, _) => name.clone(), _ => unreachable!() }; let prec = match &self.machine_st.heap[s+1] { - &HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) => + &HeapCellValue::Integer(ref arity) => arity.to_usize().unwrap(), _ => unreachable!() @@ -610,9 +612,13 @@ impl Machine { let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); let module_spec = self.machine_st[temp_v!(1)].clone(); - let name = match self.machine_st.store(self.machine_st.deref(module_spec)) { - Addr::Con(Constant::Atom(name, _)) => name, - _ => unreachable!() + let name = { + let addr = self.machine_st.store(self.machine_st.deref(module_spec)); + + match self.machine_st.heap.index_addr(&addr).as_ref() { + HeapCellValue::Atom(name, _) => name.clone(), + _ => unreachable!(), + } }; let load_result = match to_src(name) { @@ -653,9 +659,13 @@ impl Machine { let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); let module_spec = self.machine_st[temp_v!(1)].clone(); - let name = match self.machine_st.store(self.machine_st.deref(module_spec)) { - Addr::Con(Constant::Atom(name, _)) => name, - _ => unreachable!() + let name = { + let addr = self.machine_st.store(self.machine_st.deref(module_spec)); + + match self.machine_st.heap.index_addr(&addr).as_ref() { + HeapCellValue::Atom(name, _) => name.clone(), + _ => unreachable!(), + } }; let exports = match self.extract_module_export_list() { diff --git a/src/prolog/machine/partial_string.rs b/src/prolog/machine/partial_string.rs index 49be0f6e..32015030 100644 --- a/src/prolog/machine/partial_string.rs +++ b/src/prolog/machine/partial_string.rs @@ -1,26 +1,11 @@ -use crate::prolog::machine::raw_block::*; - +use std::alloc; use std::mem; use std::ptr; -use std::slice; +use std::ops::{Range, RangeFrom}; use std::str; -pub(crate) struct PartialStringTraits {} - -impl RawBlockTraits for PartialStringTraits { - #[inline] - fn init_size() -> usize { - 0 - } - - #[inline] - fn align() -> usize { - mem::align_of::() - } -} - pub struct PartialString { - pub(super) buf: RawBlock, + buf: *const u8, } impl Clone for PartialString { @@ -30,17 +15,10 @@ impl Clone for PartialString { } } -impl PartialEq for PartialString { - #[inline] - fn eq(&self, other: &Self) -> bool { - self as *const _ == other as *const _ - } -} - -fn scan_for_terminator(src: &str) -> usize { +fn scan_for_terminator>(iter: Iter) -> usize { let mut terminator_idx = 0; - for c in src.chars() { + for c in iter { if c == '\u{0}' { break; } @@ -51,11 +29,82 @@ fn scan_for_terminator(src: &str) -> usize { terminator_idx } +pub struct PStrIter { + buf: *const u8, +} + +impl PStrIter { + #[inline] + fn from(buf: *const u8, idx: usize) -> Self { + PStrIter { + buf: (buf as usize + idx) as *const _ + } + } +} + +impl Iterator for PStrIter { + type Item = char; + + fn next(&mut self) -> Option { + unsafe { + let b = ptr::read(self.buf); + + if b == 0u8 { + return None; + } + + let c = ptr::read(self.buf as *const char); + self.buf = self.buf.offset(c.len_utf8() as isize); + + Some(c) + } + } +} + +pub struct PStrIterBounded { + buf: *const u8, + end: *const u8, +} + +impl PStrIterBounded { + #[inline] + fn from(buf: *const u8, start: usize, end: usize) -> Self { + PStrIterBounded { + buf: (buf as usize + start) as *const _, + end: (buf as usize + end) as *const _, + } + } +} + +impl Iterator for PStrIterBounded { + type Item = char; + + fn next(&mut self) -> Option { + unsafe { + if self.buf >= self.end { + return None; + } + + let b = ptr::read(self.buf); + + if b == 0u8 { + return None; + } + + let c = ptr::read(self.buf as *const char); + self.buf = self.buf.offset(c.len_utf8() as isize); + + Some(c) + } + } +} + impl PartialString { + #[inline] pub(super) fn new(src: &str) -> Option<(Self, &str)> { let pstr = PartialString { - buf: RawBlock::with_capacity(src.len() + '\u{0}'.len_utf8()), + buf: ptr::null_mut(), }; unsafe { @@ -63,22 +112,34 @@ impl PartialString { } } + #[inline] + pub(super) + fn empty() -> Self { + PartialString { + buf: "\u{0}".as_bytes()[0] as *const _, + } + } + unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> { - let terminator_idx = scan_for_terminator(src); + let terminator_idx = scan_for_terminator(src.chars()); if terminator_idx == 0 { return None; } - let new_top = self.buf.new_block(terminator_idx + '\u{0}'.len_utf8()); + let layout = alloc::Layout::from_size_align_unchecked( + src.len() + '\u{0}'.len_utf8(), + mem::align_of::(), + ); + + self.buf = alloc::alloc(layout) as *const _; ptr::copy( src.as_ptr(), - self.buf.top as *mut _, + self.buf as *mut _, terminator_idx, ); - self.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _; self.write_terminator_at(terminator_idx); Some(if terminator_idx != src.len() { @@ -88,26 +149,40 @@ impl PartialString { }) } + #[inline] + pub(crate) + fn iter(&self) -> PStrIter { + PStrIter { + buf: self.buf, + } + } + pub(super) fn clone_from_offset(&self, n: usize) -> Self { let mut pstr = PartialString { - buf: RawBlock::with_capacity(self.len() + '\u{0}'.len_utf8()), + buf: ptr::null_mut(), }; unsafe { - let len = if self.len() > n { self.len() - n } else { 0 }; - let new_top = pstr.buf.new_block(len + '\u{0}'.len_utf8()); + let len = scan_for_terminator(self.range_from(0 ..)); + let len = if len > n { len - n } else { 0 }; + + let layout = alloc::Layout::from_size_align_unchecked( + len + '\u{0}'.len_utf8(), + mem::align_of::(), + ); + + pstr.buf = alloc::alloc(layout); if len > 0 { ptr::copy( - (self.buf.base as usize + n) as *mut u8, - pstr.buf.base as *mut _, + (self.buf as usize + n) as *const u8, + pstr.buf as *mut _, len, ); } pstr.write_terminator_at(len); - pstr.buf.top = (new_top as usize - '\u{0}'.len_utf8()) as *const _; } pstr @@ -118,23 +193,26 @@ impl PartialString { fn write_terminator_at(&mut self, index: usize) { unsafe { ptr::write( - (self.buf.base as usize + index) as *mut u8, + (self.buf as usize + index) as *mut u8, 0u8, ); } } #[inline] - pub(crate) - fn block_as_str(&self) -> &str { - unsafe { - let slice = slice::from_raw_parts(self.buf.base, self.len()); - str::from_utf8(slice).unwrap() - } + pub fn range(&self, index: Range) -> PStrIterBounded { + PStrIterBounded::from(self.buf, index.start, index.end) } #[inline] - pub fn len(&self) -> usize { - self.buf.top as usize - self.buf.base as usize + pub fn range_from(&self, index: RangeFrom) -> PStrIter { + PStrIter::from(self.buf, index.start) + } + + #[inline] + pub fn at_end(&self, end_n: usize) -> bool { + unsafe { + ptr::read((self.buf as usize + end_n) as *const u8) == 0u8 + } } } diff --git a/src/prolog/machine/streams.rs b/src/prolog/machine/streams.rs index b8cd4247..1653defb 100644 --- a/src/prolog/machine/streams.rs +++ b/src/prolog/machine/streams.rs @@ -29,7 +29,8 @@ pub enum EOFAction { pub enum StreamInstance { Bytes(Cursor>), DynReadSource(Box), - File(File), + File(File), + Null, ReadlineStream(ReadlineStream), Stdin, Stdout, @@ -201,6 +202,17 @@ impl Stream { } } + #[inline] + pub(crate) + fn null_stream() -> Self { + Stream { + options: StreamOptions::default(), // TODO: null_options? + stream_inst: WrappedStreamInstance::new( + StreamInstance::Null + ), + } + } + #[inline] pub(crate) fn is_stdout(&self) -> bool { @@ -233,7 +245,7 @@ impl Stream { match *self.stream_inst.0.borrow() { StreamInstance::Stdin | StreamInstance::TcpStream(_) - | StreamInstance::Bytes(_) + | StreamInstance::Bytes(_) | StreamInstance::ReadlineStream(_) | StreamInstance::DynReadSource(_) | StreamInstance::File(_) => { @@ -251,7 +263,7 @@ impl Stream { match *self.stream_inst.0.borrow() { StreamInstance::Stdout | StreamInstance::TcpStream(_) - | StreamInstance::Bytes(_) + | StreamInstance::Bytes(_) | StreamInstance::File(_) => { true } @@ -283,7 +295,7 @@ impl Read for Stream { StreamInstance::Stdin => { stdin().read(buf) } - StreamInstance::Stdout => { + StreamInstance::Stdout | StreamInstance::Null => { Err(std::io::Error::new( ErrorKind::PermissionDenied, StreamError::ReadFromOutputStream, diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index c222ea11..9f927da2 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -22,6 +22,7 @@ use crate::ref_thread_local::RefThreadLocal; use indexmap::{IndexMap, IndexSet}; +use std::cmp; use std::io::{stdout, Write}; use std::iter::once; use std::mem; @@ -111,7 +112,7 @@ impl BrentAlgState { Addr::PStrLocation(h, n) => { CycleSearchResult::PStrLocation(self.steps, h, n) } - Addr::Con(Constant::EmptyList) => { + Addr::EmptyList => { CycleSearchResult::ProperList(self.steps) } _ => { @@ -131,8 +132,8 @@ fn is_builtin_predicate(name: &ClauseName) -> bool { impl MachineState { // a step in Brent's algorithm. fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option { - match self.store(self.deref(brent_st.hare.clone())) { - Addr::Con(Constant::EmptyList) => { + match self.store(self.deref(brent_st.hare)) { + Addr::EmptyList => { Some(CycleSearchResult::ProperList(brent_st.steps)) } addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => { @@ -141,19 +142,10 @@ impl MachineState { addr.as_var().unwrap(), )) } - Addr::Con(Constant::String(n, s)) if !self.flags.double_quotes.is_atom() => { - if let Some(c) = s.chars().next() { - brent_st.step(Addr::Con(Constant::String(n + c.len_utf8(), s))) - } else { - Some(CycleSearchResult::CompleteString(s.len(), s)) - } - } Addr::PStrLocation(h, n) => { match &self.heap[h] { HeapCellValue::PartialString(ref pstr) => { - let s = pstr.block_as_str(); - - if let Some(c) = s[n ..].chars().next() { + if let Some(c) = pstr.range_from(n ..).next() { brent_st.step(Addr::PStrLocation(h, n + c.len_utf8())) } else { unreachable!() @@ -188,34 +180,29 @@ impl MachineState { Addr::PStrLocation(h, _) => { return CycleSearchResult::UntouchedList(h); } - Addr::Con(Constant::EmptyList) => { + Addr::EmptyList => { return CycleSearchResult::EmptyList; } - Addr::Con(Constant::String(0, ref s)) - if max_steps > 0 && !self.flags.double_quotes.is_atom() => { - if max_steps >= s.len() { - return CycleSearchResult::CompleteString(s.len(), s.clone()); + Addr::Con(h) if max_steps > 0 => { + if let HeapCellValue::PartialString(_) = &self.heap[h] { + if !self.flags.double_quotes.is_atom() { + Addr::PStrLocation(h, 0) } else { - return CycleSearchResult::UntouchedString(max_steps, s.clone()); + return CycleSearchResult::NotList; } + } else { + return CycleSearchResult::NotList; } - Addr::Con(Constant::String(0, ref s)) - if !self.flags.double_quotes.is_atom() => { - return CycleSearchResult::UntouchedString(0, s.clone()); - } - Addr::Con(Constant::String(n, ref s)) - if max_steps > 0 && !self.flags.double_quotes.is_atom() => { - if max_steps >= s.len() - n { - let s = Rc::new(String::from(&s[n ..])); - return CycleSearchResult::CompleteString(s.len(), s); - } else { - return CycleSearchResult::UntouchedString(max_steps, s.clone()); + } + Addr::Con(h) => { + if let HeapCellValue::PartialString(_) = &self.heap[h] { + if !self.flags.double_quotes.is_atom() { + return CycleSearchResult::UntouchedList(h); } } - Addr::Con(Constant::String(n, ref s)) - if !self.flags.double_quotes.is_atom() => { - return CycleSearchResult::UntouchedString(n, s.clone()); - } + + return CycleSearchResult::NotList; + } _ => { return CycleSearchResult::NotList; } @@ -241,18 +228,22 @@ impl MachineState { Addr::Lis(offset) => { Addr::Lis(offset) } - Addr::Con(Constant::EmptyList) => { + Addr::EmptyList => { return CycleSearchResult::EmptyList; } Addr::PStrLocation(h, n) => { Addr::PStrLocation(h, n) } - Addr::Con(Constant::String(0, ref s)) if !self.flags.double_quotes.is_atom() => { - return CycleSearchResult::CompleteString(s.len(), s.clone()); - } - Addr::Con(Constant::String(n, ref s)) if !self.flags.double_quotes.is_atom() => { - let s = Rc::new(String::from(&s[n ..])); - return CycleSearchResult::CompleteString(s.len(), s); + Addr::Con(h) => { + if let HeapCellValue::PartialString(_) = &self.heap[h] { + if !self.flags.double_quotes.is_atom() { + Addr::PStrLocation(h, 0) + } else { + return CycleSearchResult::NotList; + } + } else { + return CycleSearchResult::NotList; + } } _ => { return CycleSearchResult::NotList; @@ -269,76 +260,86 @@ impl MachineState { } fn finalize_skip_max_list(&mut self, n: usize, addr: Addr) { - let target_n = self[temp_v!(1)].clone(); - self.unify(Addr::Con(Constant::Integer(Integer::from(n))), target_n); + let target_n = self[temp_v!(1)]; + self.unify(Addr::Usize(n), target_n); if !self.fail { - let xs = self[temp_v!(4)].clone(); + let xs = self[temp_v!(4)]; self.unify(addr, xs); } } - pub(super) fn skip_max_list(&mut self) -> CallResult { - let max_steps = self.store(self.deref(self[temp_v!(2)].clone())); + fn skip_max_list_result(&mut self, max_steps: &Integer) { + let search_result = + if let Some(max_steps) = max_steps.to_isize() { + if max_steps == -1 { + self.detect_cycles(self[temp_v!(3)]) + } else { + self.detect_cycles_with_max( + max_steps as usize, + self[temp_v!(3)], + ) + } + } else { + self.detect_cycles(self[temp_v!(3)]) + }; - match max_steps { - Addr::Con(Constant::Integer(ref max_steps)) => { - if max_steps.to_isize().map(|i| i >= -1).unwrap_or(false) { - let n = self.store(self.deref(self[temp_v!(1)].clone())); + match search_result { + CycleSearchResult::PStrLocation(steps, h, n) => { + self.finalize_skip_max_list(steps, Addr::PStrLocation(h, n)); + } + CycleSearchResult::UntouchedList(l) => { + self.finalize_skip_max_list(0, Addr::Lis(l)) + } + CycleSearchResult::EmptyList => { + self.finalize_skip_max_list(0, Addr::EmptyList) + } + CycleSearchResult::PartialList(n, r) => { + self.finalize_skip_max_list(n, r.as_addr()) + } + CycleSearchResult::ProperList(steps) => { + self.finalize_skip_max_list(steps, Addr::EmptyList) + } + CycleSearchResult::NotList => { + let xs0 = self[temp_v!(3)]; + self.finalize_skip_max_list(0, xs0); + } + }; + } - match n { - Addr::Con(Constant::Integer(ref n)) if n == &0 => { - let xs0 = self[temp_v!(3)].clone(); - let xs = self[temp_v!(4)].clone(); + pub(super) fn skip_max_list(&mut self) -> CallResult { + let max_steps = self.store(self.deref(self[temp_v!(2)])); - self.unify(xs0, xs); - } - _ => { - let search_result = - if let Some(max_steps) = max_steps.to_isize() { - if max_steps == -1 { - self.detect_cycles(self[temp_v!(3)].clone()) + match max_steps { + Addr::Con(h) if self.heap.integer_at(h) => { + if let HeapCellValue::Integer(ref max_steps) = self.heap.clone(h) { + if max_steps.to_isize().map(|i| i >= -1).unwrap_or(false) { + let n = self.store(self.deref(self[temp_v!(1)])); + + match n { + Addr::Con(h) if self.heap.integer_at(h) => { + if let HeapCellValue::Integer(ref n) = &self.heap[h] { + if n.as_ref() == &0 { + let xs0 = self[temp_v!(3)]; + let xs = self[temp_v!(4)]; + + self.unify(xs0, xs); } else { - self.detect_cycles_with_max( - max_steps as usize, - self[temp_v!(3)].clone(), - ) + self.skip_max_list_result(max_steps.as_ref()); } } else { - self.detect_cycles(self[temp_v!(3)].clone()) - }; - - match search_result { - CycleSearchResult::PStrLocation(steps, h, n) => { - self.finalize_skip_max_list(steps, Addr::PStrLocation(h, n)); - } - CycleSearchResult::CompleteString(n, _) => { - self.finalize_skip_max_list(n, Addr::Con(Constant::EmptyList)); - } - CycleSearchResult::UntouchedString(n, s) => { - self.finalize_skip_max_list(0, Addr::Con(Constant::String(n, s))); - } - CycleSearchResult::UntouchedList(l) => { - self.finalize_skip_max_list(0, Addr::Lis(l)) - } - CycleSearchResult::EmptyList => { - self.finalize_skip_max_list(0, Addr::Con(Constant::EmptyList)) - } - CycleSearchResult::PartialList(n, r) => { - self.finalize_skip_max_list(n, r.as_addr()) - } - CycleSearchResult::ProperList(steps) => { - self.finalize_skip_max_list(steps, Addr::Con(Constant::EmptyList)) - } - CycleSearchResult::NotList => { - let xs0 = self[temp_v!(3)].clone(); - self.finalize_skip_max_list(0, xs0); + unreachable!() } } + _ => { + self.skip_max_list_result(max_steps.as_ref()); + } } + } else { + self.fail = true; } } else { - self.fail = true; + unreachable!() } } Addr::HeapCell(_) | Addr::StackCell(..) => { @@ -348,7 +349,14 @@ impl MachineState { addr => { let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4); return Err( - self.error_form(MachineError::type_error(ValidType::Integer, addr), stub) + self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + addr + ), + stub, + ) ); } }; @@ -357,50 +365,60 @@ impl MachineState { } fn get_stream_or_alias( - &self, + &mut self, addr: Addr, indices: &IndexStore, caller: &'static str, ) -> Result { Ok(match addr { - Addr::Con(Constant::Atom(atom, op_spec)) => { - match indices.stream_aliases.get(&atom) { - Some(stream) => { - stream.clone() - } - None => { - let stub = MachineError::functor_stub(clause_name!(caller), 1); - let addr = Addr::Con(Constant::Atom(atom, op_spec)); + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref atom, ref spec) = self.heap.clone(h) { + match indices.stream_aliases.get(atom) { + Some(stream) => { + stream.clone() + } + None => { + let stub = MachineError::functor_stub(clause_name!(caller), 1); + let h = self.heap.h(); - let h = self.heap.h(); - - return Err(self.error_form( - MachineError::existence_error(h, ExistenceError::Stream(addr)), - stub, - )); + let addr = self.heap.to_unifiable( + HeapCellValue::Atom(atom.clone(), spec.clone()) + ); + + return Err(self.error_form( + MachineError::existence_error(h + 1, ExistenceError::Stream(addr)), + stub, + )); + } } + } else { + unreachable!() } } - Addr::Stream(stream) => { - stream + Addr::Stream(h) => { + if let HeapCellValue::Stream(ref stream) = &self.heap[h] { + stream.clone() + } else { + unreachable!() + } } _ => { let stub = MachineError::functor_stub(clause_name!(caller), 1); - + return Err(self.error_form( - MachineError::domain_error(DomainError::StreamOrAlias, addr), + MachineError::domain_error(DomainErrorType::StreamOrAlias, addr), stub, )); } - }) + }) } - fn read_term(&mut self, - current_input_stream: &mut Stream, - indices: &mut IndexStore) - -> CallResult - { + fn read_term( + &mut self, + current_input_stream: &mut Stream, + indices: &mut IndexStore, + ) -> CallResult { match self.read( &mut parsing_stream(current_input_stream.clone()), indices.atom_tbl.clone(), @@ -418,13 +436,12 @@ impl MachineState { for (var, binding) in term_write_result.var_dict.into_iter().rev() { let var_atom = clause_name!(var.to_string(), indices.atom_tbl); - let var_atom = Constant::Atom(var_atom, None); let h = self.heap.h(); let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir); self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec)); - self.heap.push(HeapCellValue::Addr(Addr::Con(var_atom))); + self.heap.push(HeapCellValue::Atom(var_atom, None)); self.heap.push(HeapCellValue::Addr(binding)); list_of_var_eqs.push(Addr::Str(h)); @@ -460,7 +477,7 @@ impl MachineState { let c = Constant::Usize(self.block); let addr = self[r].clone(); - self.write_constant_to_var(addr, c); + self.write_constant_to_var(addr, &c); self.block } @@ -497,7 +514,7 @@ impl MachineState { AddrConstr: Fn(usize) -> Addr, { match self.store(self.deref(self[temp_v!(1)].clone())) { - Addr::Con(Constant::Usize(lh_offset)) => { + Addr::Usize(lh_offset) => { if lh_offset >= self.lifted_heap.h() { self.lifted_heap.truncate(lh_offset); } else { @@ -528,9 +545,22 @@ impl MachineState { let a2 = self[temp_v!(2)].clone(); if let Some(r) = a2.as_var() { - let spec = - get_clause_spec(name.clone(), *arity, composite_op!(&indices.op_dir)); - self.bind(r, Addr::DBRef(DBRef::NamedPred(name.clone(), *arity, spec))); + let spec = get_clause_spec( + name.clone(), + *arity, + composite_op!(&indices.op_dir), + ); + + let addr = self.heap.to_unifiable(HeapCellValue::DBRef( + DBRef::NamedPred( + name.clone(), + *arity, + spec, + ) + )); + + self.bind(r, addr); + return; } } @@ -551,16 +581,19 @@ impl MachineState { let a2 = self[temp_v!(2)].clone(); if let Some(r) = a2.as_var() { - self.bind( - r, - Addr::DBRef(DBRef::Op( - *priority, - *spec, - name.clone(), - op_dir.clone(), - SharedOpDesc::new(*priority, *spec), - )), + let addr = self.heap.to_unifiable( + HeapCellValue::DBRef( + DBRef::Op( + *priority, + *spec, + name.clone(), + op_dir.clone(), + SharedOpDesc::new(*priority, *spec) + ), + ), ); + + self.bind(r, addr); } else { self.fail = true; } @@ -572,7 +605,7 @@ impl MachineState { } fn int_to_char_code( - &mut self, + &self, n: &Integer, stub: &'static str, arity: usize, @@ -627,16 +660,19 @@ impl MachineState { return Err(self.error_form(err, stub)); } Ok(Term::Constant(_, Constant::Rational(n))) => { - self.unify(nx, Addr::Con(Constant::Rational(n))) + let addr = self.heap.put_constant(Constant::Rational(n)); + self.unify(nx, addr); } Ok(Term::Constant(_, Constant::Float(n))) => { - self.unify(nx, Addr::Con(Constant::Float(n))) + let addr = self.heap.put_constant(Constant::Float(n)); + self.unify(nx, addr); } Ok(Term::Constant(_, Constant::Integer(n))) => { - self.unify(nx, Addr::Con(Constant::Integer(n))) + let addr = self.heap.put_constant(Constant::Integer(n)); + self.unify(nx, addr); } Ok(Term::Constant(_, Constant::CharCode(c))) => { - self.unify(nx, Addr::Con(Constant::CharCode(c))) + self.unify(nx, Addr::CharCode(c)) } _ => { let err = ParserError::ParseBigInt(0, 0); @@ -652,7 +688,11 @@ impl MachineState { } fn fetch_attribute_goals(&mut self, mut attr_goals: Vec) { - attr_goals.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2)); + attr_goals.sort_unstable_by(|a1, a2| { + self.compare_term_test(a1, a2) + .unwrap_or(cmp::Ordering::Less) + }); + self.term_dedup(&mut attr_goals); let attr_goals = Addr::HeapCell(self.heap.to_list(attr_goals.into_iter())); @@ -684,8 +724,8 @@ impl MachineState { // adjust cut point to occur after call_continuation. if num_cells > 0 { - if let Addr::Con(Constant::CutPoint(_)) = self.heap[s+2].as_addr(s+2) { - and_frame[1] = Addr::Con(Constant::CutPoint(self.b)); + if let Addr::CutPoint(_) = self.heap[s+2].as_addr(s+2) { + and_frame[1] = Addr::CutPoint(self.b); } else { and_frame[1] = self.heap[s+2].as_addr(s+2); } @@ -735,7 +775,12 @@ impl MachineState { &SystemClauseType::BindFromRegister => { let reg = self.store(self.deref(self[temp_v!(2)].clone())); let n = match reg { - Addr::Con(Constant::Integer(n)) => n.to_usize(), + Addr::Con(h) => + if let HeapCellValue::Integer(ref n) = &self.heap[h] { + n.to_usize() + } else { + unreachable!() + } _ => unreachable!() }; @@ -766,15 +811,21 @@ impl MachineState { return Ok(()); } &SystemClauseType::CurrentInput => { - let addr = self.store(self.deref(self[temp_v!(1)].clone())); + let addr = self.store(self.deref(self[temp_v!(1)])); + let stream = current_input_stream.clone(); match addr { addr if addr.is_ref() => { - self.unify(Addr::Stream(stream), addr); + let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); + self.unify(stream, addr); } Addr::Stream(other_stream) => { - self.fail = stream != other_stream; + if let HeapCellValue::Stream(ref other_stream) = &self.heap[other_stream] { + self.fail = current_input_stream != other_stream; + } else { + unreachable!() + } } addr => { let stub = MachineError::functor_stub( @@ -783,7 +834,7 @@ impl MachineState { ); let err = MachineError::domain_error( - DomainError::Stream, + DomainErrorType::Stream, addr, ); @@ -797,10 +848,15 @@ impl MachineState { match addr { addr if addr.is_ref() => { - self.unify(Addr::Stream(stream), addr); + let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); + self.unify(stream, addr); } Addr::Stream(other_stream) => { - self.fail = stream != other_stream; + if let HeapCellValue::Stream(ref other_stream) = &self.heap[other_stream] { + self.fail = current_output_stream != other_stream; + } else { + unreachable!() + } } addr => { let stub = MachineError::functor_stub( @@ -809,7 +865,7 @@ impl MachineState { ); let err = MachineError::domain_error( - DomainError::Stream, + DomainErrorType::Stream, addr, ); @@ -826,55 +882,72 @@ impl MachineState { let a1 = self[temp_v!(1)].clone(); match self.store(self.deref(a1)) { - Addr::Con(Constant::Char(c)) => { - let iter = once(Addr::Con(Constant::Char(c))); + Addr::Char(c) => { + let iter = once(Addr::Char(c)); let list_of_chars = Addr::HeapCell(self.heap.to_list(iter)); - let a2 = self[temp_v!(2)].clone(); + let a2 = self[temp_v!(2)]; self.unify(a2, list_of_chars); } - Addr::Con(Constant::Atom(name, _)) => { - let iter = name.as_str().chars().map(|c| Addr::Con(Constant::Char(c))); - let list_of_chars = Addr::HeapCell(self.heap.to_list(iter)); + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { + let iter = name.as_str().chars().map(|c| Addr::Char(c)); + let list_of_chars = Addr::HeapCell(self.heap.to_list(iter)); - let a2 = self[temp_v!(2)].clone(); + let a2 = self[temp_v!(2)]; - match self.store(self.deref(a2)) { - Addr::Con(Constant::String(..)) - if !self.flags.double_quotes.is_chars() => { - self.fail = true; + match self.store(self.deref(a2)) { + Addr::PStrLocation(..) + if !self.flags.double_quotes.is_chars() => { + self.fail = true; + } + a2 => { + self.unify(a2, list_of_chars); } - a2 => { - self.unify(a2, list_of_chars); } + } else { + unreachable!() } } - Addr::Con(Constant::EmptyList) => { + Addr::EmptyList => { let a2 = self[temp_v!(2)].clone(); let chars = vec![ - Addr::Con(Constant::Char('[')), - Addr::Con(Constant::Char(']')), + Addr::Char('['), + Addr::Char(']'), ]; - let list_of_chars = Addr::HeapCell(self.heap.to_list(chars.into_iter())); + let list_of_chars = + Addr::HeapCell(self.heap.to_list(chars.into_iter())); self.unify(a2, list_of_chars); } - ref addr if addr.is_ref() => { + addr if addr.is_ref() => { let stub = MachineError::functor_stub(clause_name!("atom_chars"), 2); - match self.try_from_list(temp_v!(2), stub.clone()) { - Err(e) => return Err(e), - Ok(addrs) => match self.try_char_list(addrs) { - Ok(string) => { - let chars = clause_name!(string, indices.atom_tbl); - self.unify( - addr.clone(), - Addr::Con(Constant::Atom(chars, None)), - ); + match self.try_from_list(temp_v!(2), stub) { + Err(e) => { + return Err(e); + } + Ok(addrs) => { + match self.try_char_list(addrs) { + Ok(string) => { + let chars = clause_name!(string, indices.atom_tbl); + let atom = self.heap.to_unifiable( + HeapCellValue::Atom(chars, None) + ); + + self.unify(addr, atom); + } + Err(err) => { + let stub = MachineError::functor_stub( + clause_name!("atom_chars"), + 2, + ); + + return Err(self.error_form(err, stub)); + } } - Err(err) => return Err(self.error_form(err, stub)), - }, + } } } _ => unreachable!(), @@ -884,47 +957,51 @@ impl MachineState { let a1 = self[temp_v!(1)].clone(); match self.store(self.deref(a1)) { - Addr::Con(Constant::Char(c)) => { - let iter = once(Addr::Con(Constant::CharCode(c as u32))); + Addr::Char(c) => { + let iter = once(Addr::CharCode(c as u32)); let list_of_codes = Addr::HeapCell(self.heap.to_list(iter)); let a2 = self[temp_v!(2)].clone(); self.unify(a2, list_of_codes); } - Addr::Con(Constant::Atom(name, _)) => { - let a2 = self[temp_v!(2)].clone(); + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { + let a2 = self[temp_v!(2)]; - match self.store(self.deref(a2)) { - a2 @ Addr::Con(Constant::String(..)) => { - if !self.flags.double_quotes.is_codes() { - self.fail = true; - } else { + match self.store(self.deref(a2)) { + a2 @ Addr::PStrLocation(..) => { + if !self.flags.double_quotes.is_codes() { + self.fail = true; + } else { + let iter = name + .as_str() + .chars() + .map(|c| Addr::Char(c)); + + let list_of_codes = Addr::HeapCell(self.heap.to_list(iter)); + + self.unify(a2, list_of_codes); + } + } + a2 => { let iter = name .as_str() .chars() - .map(|c| Addr::Con(Constant::Char(c))); + .map(|c| Addr::CharCode(c as u32)); let list_of_codes = Addr::HeapCell(self.heap.to_list(iter)); self.unify(a2, list_of_codes); } } - a2 => { - let iter = name - .as_str() - .chars() - .map(|c| Addr::Con(Constant::CharCode(c as u32))); - - let list_of_codes = Addr::HeapCell(self.heap.to_list(iter)); - - self.unify(a2, list_of_codes); - } + } else { + unreachable!() } } - Addr::Con(Constant::EmptyList) => { + Addr::EmptyList => { let chars = vec![ - Addr::Con(Constant::CharCode('[' as u32)), - Addr::Con(Constant::CharCode(']' as u32)), + Addr::CharCode('[' as u32), + Addr::CharCode(']' as u32), ]; let list_of_codes = Addr::HeapCell(self.heap.to_list(chars.into_iter())); @@ -932,35 +1009,48 @@ impl MachineState { self.unify(a2, list_of_codes); } - ref addr if addr.is_ref() => { + addr if addr.is_ref() => { let stub = MachineError::functor_stub(clause_name!("atom_codes"), 2); - match self.try_from_list(temp_v!(2), stub.clone()) { + match self.try_from_list(temp_v!(2), stub) { Err(e) => return Err(e), Ok(addrs) => { let mut chars = String::new(); for addr in addrs { match addr { - Addr::Con(Constant::Integer(n)) => { - let c = self.int_to_char_code(&n, "atom_codes", 2)?; - chars.push(std::char::from_u32(c).unwrap()); + Addr::Con(h) if self.heap.integer_at(h) => { + if let HeapCellValue::Integer(ref n) = &self.heap[h] { + let c = self.int_to_char_code(&n, "atom_codes", 2)?; + chars.push(std::char::from_u32(c).unwrap()); + } else { + unreachable!() + } } - Addr::Con(Constant::CharCode(c)) => { + Addr::CharCode(c) => { chars.push(std::char::from_u32(c).unwrap()); } _ => { + let stub = MachineError::functor_stub( + clause_name!("atom_codes"), + 2, + ); + let err = MachineError::type_error( + self.heap.h(), ValidType::Integer, - addr.clone(), + addr, ); + return Err(self.error_form(err, stub)); } } } let chars = clause_name!(chars, indices.atom_tbl); - self.unify(addr.clone(), Addr::Con(Constant::Atom(chars, None))); + let chars = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); + + self.unify(addr, chars); } } } @@ -968,19 +1058,33 @@ impl MachineState { }; } &SystemClauseType::AtomLength => { - let a1 = self[temp_v!(1)].clone(); + let a1 = self.store(self.deref(self[temp_v!(1)])); let atom = match self.store(self.deref(a1)) { - Addr::Con(Constant::Atom(name, _)) => name, - Addr::Con(Constant::EmptyList) => clause_name!("[]"), - Addr::Con(Constant::Char(c)) => clause_name!(c.to_string(), indices.atom_tbl), - _ => unreachable!(), + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + name.clone() + } else { + unreachable!() + } + } + Addr::EmptyList => { + clause_name!("[]") + } + Addr::Char(c) => { + clause_name!(c.to_string(), indices.atom_tbl) + } + _ => { + unreachable!() + } }; let len = Integer::from(atom.as_str().chars().count()); - let a2 = self[temp_v!(2)].clone(); + let len = self.heap.to_unifiable(HeapCellValue::Integer(Rc::new(len))); + + let a2 = self[temp_v!(2)]; - self.unify(a2, Addr::Con(Constant::Integer(len))); + self.unify(a2, len); } &SystemClauseType::CallAttributeGoals => { let p = self.attr_var_init.project_attrs_loc; @@ -1018,18 +1122,36 @@ impl MachineState { &SystemClauseType::CharsToNumber => { let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); - match self.try_from_list(temp_v!(1), stub.clone()) { - Err(e) => return Err(e), - Ok(addrs) => match self.try_char_list(addrs) { - Ok(string) => self.parse_number_from_string(string, indices, stub)?, - Err(err) => return Err(self.error_form(err, stub)), - }, + match self.try_from_list(temp_v!(1), stub) { + Err(e) => { + return Err(e); + } + Ok(addrs) => { + match self.try_char_list(addrs) { + Ok(string) => { + let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); + self.parse_number_from_string(string, indices, stub)?; + } + Err(err) => { + let stub = MachineError::functor_stub( + clause_name!("number_chars"), + 2, + ); + + return Err(self.error_form(err, stub)); + } + } + } } } &SystemClauseType::CreatePartialString => { - let atom = match self.store(self.deref(self[temp_v!(1)].clone())) { - Addr::Con(Constant::Atom(atom, _)) => { - atom + let atom = match self.store(self.deref(self[temp_v!(1)])) { + Addr::Con(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + name.clone() + } else { + unreachable!() + } } _ => { unreachable!() @@ -1037,27 +1159,14 @@ impl MachineState { }; let h = self.heap.h(); - let pstr = - match self.heap.allocate_pstr(atom.as_str()) { - Some(pstr_addr) => { - pstr_addr - } - None => { - let stub = MachineError::functor_stub(clause_name!("partial_string"), 3); - let err = MachineError::representation_error( - RepFlag::Character, - ); - - return Err(self.error_form(err, stub)); - } - }; + let pstr = self.heap.allocate_pstr(atom.as_str()); let pstr_tail = self.heap[h + 1].as_addr(h + 1); - - self.unify(self[temp_v!(2)].clone(), pstr); + + self.unify(self[temp_v!(2)], pstr); if !self.fail { - self.unify(self[temp_v!(3)].clone(), pstr_tail); + self.unify(self[temp_v!(3)], pstr_tail); } } &SystemClauseType::IsPartialString => { @@ -1072,13 +1181,13 @@ impl MachineState { } } &SystemClauseType::PartialStringTail => { - let pstr = self.store(self.deref(self[temp_v!(1)].clone())); + let pstr = self.store(self.deref(self[temp_v!(1)])); match pstr { Addr::PStrLocation(h, _) => { let tail = self.heap[h + 1].as_addr(h + 1); - let target = self[temp_v!(2)].clone(); - + let target = self[temp_v!(2)]; + self.unify(tail, target); } _ => { @@ -1087,34 +1196,55 @@ impl MachineState { } } &SystemClauseType::NumberToChars => { - let n = self[temp_v!(1)].clone(); - let chs = self[temp_v!(2)].clone(); + let n = self[temp_v!(1)]; + let chs = self[temp_v!(2)]; let string = match self.store(self.deref(n)) { - Addr::Con(Constant::Float(OrderedFloat(n))) => format!("{0:<20?}", n), - Addr::Con(Constant::Integer(n)) => n.to_string(), - _ => unreachable!(), + Addr::Float(OrderedFloat(n)) => { + format!("{0:<20?}", n) + } + Addr::Con(h) if self.heap.integer_at(h) => { + if let HeapCellValue::Integer(ref n) = &self.heap[h] { + n.to_string() + } else { + unreachable!() + } + } + _ => { + unreachable!() + } }; - let chars = string.trim().chars().map(|c| Addr::Con(Constant::Char(c))); + let chars = string.trim().chars().map(|c| Addr::Char(c)); let char_list = Addr::HeapCell(self.heap.to_list(chars)); self.unify(char_list, chs); } &SystemClauseType::NumberToCodes => { - let n = self[temp_v!(1)].clone(); - let chs = self[temp_v!(2)].clone(); + let n = self[temp_v!(1)]; + let chs = self[temp_v!(2)]; let string = match self.store(self.deref(n)) { - Addr::Con(Constant::Float(OrderedFloat(n))) => format!("{0:<20?}", n), - Addr::Con(Constant::Integer(n)) => n.to_string(), - _ => unreachable!(), + Addr::Float(OrderedFloat(n)) => { + format!("{0:<20?}", n) + } + Addr::Con(h) if self.heap.integer_at(h) => { + if let HeapCellValue::Integer(ref n) = &self.heap[h] { + n.to_string() + } else { + unreachable!() + } + } + _ => { + unreachable!() + } }; let codes = string .trim() .chars() - .map(|c| Addr::Con(Constant::CharCode(c as u32))); + .map(|c| Addr::CharCode(c as u32)); + let codes_list = Addr::HeapCell(self.heap.to_list(codes)); self.unify(codes_list, chs); @@ -1122,14 +1252,26 @@ impl MachineState { &SystemClauseType::CodesToNumber => { let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); - match self.try_from_list(temp_v!(1), stub.clone()) { - Err(e) => return Err(e), - Ok(addrs) => match self.try_char_list(addrs) { - Ok(chars) => { - self.parse_number_from_string(chars, indices, stub)? + match self.try_from_list(temp_v!(1), stub) { + Err(e) => { + return Err(e); + } + Ok(addrs) => { + match self.try_char_list(addrs) { + Ok(chars) => { + let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); + self.parse_number_from_string(chars, indices, stub)?; + } + Err(err) => { + let stub = MachineError::functor_stub( + clause_name!("number_codes"), + 2, + ); + + return Err(self.error_form(err, stub)); + } } - Err(err) => return Err(self.error_form(err, stub)), - }, + } } } &SystemClauseType::ModuleAssertDynamicPredicateToFront => { @@ -1148,43 +1290,55 @@ impl MachineState { } &SystemClauseType::LiftedHeapLength => { let a1 = self[temp_v!(1)].clone(); - let lh_len = Addr::Con(Constant::Usize(self.lifted_heap.h())); + let lh_len = Addr::Usize(self.lifted_heap.h()); self.unify(a1, lh_len); } &SystemClauseType::CharCode => { - let a1 = self[temp_v!(1)].clone(); + let a1 = self[temp_v!(1)]; match self.store(self.deref(a1)) { - Addr::Con(Constant::Atom(name, _)) => { - let c = name.as_str().chars().next().unwrap(); - let a2 = self[temp_v!(2)].clone(); - let c = Integer::from(c as u32); + Addr::Con(h) if self.heap.atom_at(h) => { + let c = + if let HeapCellValue::Atom(name, _) = &self.heap[h] { + if name.is_char() { + name.as_str().chars().next().unwrap() + } else { + self.fail = true; + return Ok(()); + } + } else { + unreachable!() + }; - self.unify(Addr::Con(Constant::Integer(c)), a2); + let a2 = self[temp_v!(2)]; + self.unify(Addr::CharCode(c as u32), a2); } - Addr::Con(Constant::Char(c)) => { - let a2 = self[temp_v!(2)].clone(); - let c = Integer::from(c as u32); - - self.unify(Addr::Con(Constant::Integer(c)), a2); + Addr::Char(c) => { + let a2 = self[temp_v!(2)]; + self.unify(Addr::CharCode(c as u32), a2); } addr if addr.is_ref() => { - let a2 = self[temp_v!(2)].clone(); + let a2 = self[temp_v!(2)]; match self.store(self.deref(a2)) { - Addr::Con(Constant::CharCode(code)) => { + Addr::CharCode(code) => { if let Some(c) = std::char::from_u32(code) { - self.unify(Addr::Con(Constant::Char(c)), addr); + self.unify(Addr::Char(c), addr); } else { self.fail = true; } } - Addr::Con(Constant::Integer(n)) => { - let c = self.int_to_char_code(&n, "char_code", 2)?; + Addr::Con(h) if self.heap.integer_at(h) => { + let c = + if let HeapCellValue::Integer(n) = &self.heap[h] { + self.int_to_char_code(&n, "char_code", 2)? + } else { + unreachable!() + }; if let Some(c) = std::char::from_u32(c) { - self.unify(Addr::Con(Constant::Char(c)), addr); + self.unify(Addr::Char(c), addr); } else { self.fail = true; } @@ -1199,7 +1353,7 @@ impl MachineState { let addr = self.store(self.deref(self[temp_v!(1)].clone())); match addr { - Addr::Con(Constant::Usize(old_b)) | Addr::Con(Constant::CutPoint(old_b)) => { + Addr::Usize(old_b) | Addr::CutPoint(old_b) => { let prev_b = self.stack.index_or_frame(self.b).prelude.b; let prev_b = self.stack.index_or_frame(prev_b).prelude.b; @@ -1214,14 +1368,22 @@ impl MachineState { self.copy_term(AttrVarPolicy::StripAttributes); } &SystemClauseType::FetchGlobalVar => { - let key = self[temp_v!(1)].clone(); + let key = self[temp_v!(1)]; let key = match self.store(self.deref(key)) { - Addr::Con(Constant::Atom(atom, _)) => atom, - _ => unreachable!(), + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { + atom.clone() + } else { + unreachable!() + } + } + _ => { + unreachable!() + } }; - let addr = self[temp_v!(2)].clone(); + let addr = self[temp_v!(2)]; match indices.global_variables.get_mut(&key) { Some((ref mut ball, None)) => { @@ -1241,11 +1403,19 @@ impl MachineState { let key = self[temp_v!(1)].clone(); let key = match self.store(self.deref(key)) { - Addr::Con(Constant::Atom(atom, _)) => atom, - _ => unreachable!(), + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { + atom.clone() + } else { + unreachable!() + } + } + _ => { + unreachable!() + } }; - let addr = self[temp_v!(2)].clone(); + let addr = self[temp_v!(2)]; match indices.global_variables.get_mut(&key) { Some((ref mut ball, ref mut offset @ None)) => { @@ -1260,7 +1430,7 @@ impl MachineState { Some((_, Some(h))) => { let offset = self[temp_v!(3)].clone(); - self.unify(offset, Addr::Con(Constant::Usize(*h))); + self.unify(offset, Addr::Usize(*h)); if !self.fail { self.unify(addr, Addr::HeapCell(*h)); @@ -1278,10 +1448,16 @@ impl MachineState { let a1 = self[temp_v!(1)].clone(); match result { - Some(Ok(b)) => self.unify(Addr::Con(Constant::Char(b as char)), a1), + Some(Ok(b)) => { + self.unify(Addr::Char(b as char), a1); + } Some(Err(_)) => { - let end_of_file = clause_name!("end_of_file"); - self.unify(a1, Addr::Con(Constant::Atom(end_of_file, None))); + let end_of_file = self.heap.to_unifiable(HeapCellValue::Atom( + clause_name!("end_of_file"), + None, + )); + + self.unify(a1, end_of_file); } None => { let stub = MachineError::functor_stub(clause_name!("get_char"), 1); @@ -1293,11 +1469,17 @@ impl MachineState { } } &SystemClauseType::GetModuleClause => { - let module = self[temp_v!(3)].clone(); - let head = self[temp_v!(1)].clone(); + let module = self[temp_v!(3)]; + let head = self[temp_v!(1)]; let module = match self.store(self.deref(module)) { - Addr::Con(Constant::Atom(module, _)) => module, + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(module, _) = &self.heap[h] { + module.clone() + } else { + unreachable!() + } + } _ => { self.fail = true; return Ok(()); @@ -1305,35 +1487,52 @@ impl MachineState { }; let subsection = match self.store(self.deref(head)) { - Addr::Str(s) => match self.heap[s].clone() { - HeapCellValue::NamedStr(arity, name, ..) => { - indices.get_clause_subsection(module, name, arity) + Addr::Str(s) => match &self.heap[s] { + &HeapCellValue::NamedStr(arity, ref name, ..) => { + indices.get_clause_subsection(module, name.clone(), arity) + } + _ => { + unreachable!() } - _ => unreachable!(), }, - Addr::Con(Constant::Atom(name, _)) => { - indices.get_clause_subsection(module, name, 0) + Addr::Con(h) => { + if let HeapCellValue::Atom(name, _) = &self.heap[h] { + indices.get_clause_subsection(module, name.clone(), 0) + } else { + unreachable!() + } + } + + _ => { + unreachable!() } - _ => unreachable!(), }; match subsection { Some(dynamic_predicate_info) => { self.execute_at_index( 2, - dir_entry!(dynamic_predicate_info.clauses_subsection_p) + dir_entry!(dynamic_predicate_info.clauses_subsection_p), ); + return Ok(()); } - None => self.fail = true, + None => { + self.fail = true; + } } } &SystemClauseType::ModuleHeadIsDynamic => { - let module = self[temp_v!(2)].clone(); - let head = self[temp_v!(1)].clone(); + let module = self[temp_v!(2)]; + let head = self[temp_v!(1)]; let module = match self.store(self.deref(module)) { - Addr::Con(Constant::Atom(module, _)) => module, + Addr::Con(h) if self.heap.atom_at(h) => + if let HeapCellValue::Atom(module, _) = &self.heap[h] { + module.clone() + } else { + unreachable!() + } _ => { self.fail = true; return Ok(()); @@ -1341,14 +1540,20 @@ impl MachineState { }; self.fail = !match self.store(self.deref(head)) { - Addr::Str(s) => match self.heap[s].clone() { - HeapCellValue::NamedStr(arity, name, ..) => { - indices.get_clause_subsection(module, name, arity).is_some() + Addr::Str(s) => match &self.heap[s] { + &HeapCellValue::NamedStr(arity, ref name, ..) => { + indices.get_clause_subsection(module, name.clone(), arity) + .is_some() } _ => unreachable!(), }, - Addr::Con(Constant::Atom(name, _)) => { - indices.get_clause_subsection(module, name, 0).is_some() + Addr::Con(h) => { + if let HeapCellValue::Atom(name, _) = &self.heap[h] { + indices.get_clause_subsection(module, name.clone(), 0) + .is_some() + } else { + unreachable!() + } } _ => unreachable!(), }; @@ -1357,22 +1562,29 @@ impl MachineState { let head = self[temp_v!(1)].clone(); self.fail = !match self.store(self.deref(head)) { - Addr::Str(s) => match self.heap[s].clone() { - HeapCellValue::NamedStr(arity, name, ..) => indices - .get_clause_subsection(name.owning_module(), name, arity) + Addr::Str(s) => match &self.heap[s] { + &HeapCellValue::NamedStr(arity, ref name, ..) => indices + .get_clause_subsection(name.owning_module(), name.clone(), arity) .is_some(), _ => unreachable!(), }, - Addr::Con(Constant::Atom(name, _)) => indices - .get_clause_subsection(name.owning_module(), name, 0) - .is_some(), - _ => unreachable!(), + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(name, _) = &self.heap[h] { + indices.get_clause_subsection(name.owning_module(), name.clone(), 0) + .is_some() + } else { + unreachable!() + } + } + _ => { + unreachable!() + } }; } &SystemClauseType::CopyToLiftedHeap => { - match self.store(self.deref(self[temp_v!(1)].clone())) { - Addr::Con(Constant::Usize(lh_offset)) => { - let copy_target = self[temp_v!(2)].clone(); + match self.store(self.deref(self[temp_v!(1)])) { + Addr::Usize(lh_offset) => { + let copy_target = self[temp_v!(2)]; let old_threshold = self.copy_findall_solution(lh_offset, copy_target); let new_threshold = self.lifted_heap.h() - lh_offset; @@ -1389,17 +1601,19 @@ impl MachineState { } } } - _ => self.fail = true, + _ => { + self.fail = true; + } } } &SystemClauseType::DeleteAttribute => { - let ls0 = self.store(self.deref(self[temp_v!(1)].clone())); + let ls0 = self.store(self.deref(self[temp_v!(1)])); if let Addr::Lis(l1) = ls0 { if let Addr::Lis(l2) = self.store(self.deref(Addr::HeapCell(l1 + 1))) { let old_addr = self.heap[l1 + 1].as_addr(l1 + 1); - let tail = self.store(self.deref(Addr::HeapCell(l2 + 1))); + let tail = if tail.is_ref() { Addr::HeapCell(l1 + 1) } else { @@ -1418,11 +1632,11 @@ impl MachineState { } } &SystemClauseType::DeleteHeadAttribute => { - let addr = self.store(self.deref(self[temp_v!(1)].clone())); + let addr = self.store(self.deref(self[temp_v!(1)])); match addr { Addr::AttrVar(h) => { - let addr = self.heap[h + 1].as_addr(h + 1).clone(); + let addr = self.heap[h + 1].as_addr(h + 1); let addr = self.store(self.deref(addr)); match addr { @@ -1444,52 +1658,81 @@ impl MachineState { } } &SystemClauseType::DynamicModuleResolution(narity) => { - let module_name = self.store(self.deref(self[temp_v!(1 + narity)].clone())); - - if let Addr::Con(Constant::Atom(module_name, _)) = module_name { - match self.store(self.deref(self[temp_v!(2 + narity)].clone())) { - Addr::Str(a) => { - if let HeapCellValue::NamedStr(arity, name, _) = self.heap[a].clone() { - for i in (arity + 1 .. arity + narity + 1).rev() { - self.registers[i] = self.registers[i - arity].clone(); - } + let module_name = self.store(self.deref(self[temp_v!(1 + narity)])); - for i in 1 .. arity + 1 { - self.registers[i] = self.heap[a + i].as_addr(a + i); - } + let module_name = match module_name { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref module_name, _) = self.heap[h] { + module_name.clone() + } else { + unreachable!() + } + } + _ => { + unreachable!() + } + }; - return self.module_lookup( - indices, - (name, arity + narity), - module_name, - true, - ); + match self.store(self.deref(self[temp_v!(2 + narity)])) { + Addr::Str(a) => { + if let HeapCellValue::NamedStr(arity, name, _) = self.heap.clone(a) { + for i in (arity + 1 .. arity + narity + 1).rev() { + self.registers[i] = self.registers[i - arity]; } + + for i in 1 .. arity + 1 { + self.registers[i] = self.heap[a + i].as_addr(a + i); + } + + return self.module_lookup( + indices, + (name, arity + narity), + module_name, + true, + ); + } else { + unreachable!() } - Addr::Con(Constant::Atom(name, _)) => { - return self.module_lookup(indices, (name, narity), module_name, true) + } + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { + return self.module_lookup( + indices, + (name.clone(), narity), + module_name, + true, + ); + } else { + unreachable!() } - addr => { - let stub = MachineError::functor_stub(clause_name!("(:)"), 2); + } + addr => { + let stub = MachineError::functor_stub(clause_name!("(:)"), 2); - let type_error = MachineError::type_error(ValidType::Callable, addr); - let type_error = self.error_form(type_error, stub); + let type_error = MachineError::type_error( + self.heap.h(), + ValidType::Callable, + addr, + ); - return Err(type_error); - } + let type_error = self.error_form(type_error, stub); + return Err(type_error); } - }; + } } &SystemClauseType::EnqueueAttributeGoal => { - let addr = self[temp_v!(1)].clone(); + let addr = self[temp_v!(1)]; self.attr_var_init.attribute_goals.push(addr); } &SystemClauseType::EnqueueAttributedVar => { - let addr = self[temp_v!(1)].clone(); + let addr = self[temp_v!(1)]; match self.store(self.deref(addr)) { - Addr::AttrVar(h) => self.attr_var_init.attr_var_queue.push(h), - _ => {} + Addr::AttrVar(h) => { + self.attr_var_init.attr_var_queue.push(h); + } + _ => { + } } } &SystemClauseType::ExpandGoal => { @@ -1501,12 +1744,12 @@ impl MachineState { return Ok(()); } &SystemClauseType::GetNextDBRef => { - let a1 = self[temp_v!(1)].clone(); + let a1 = self[temp_v!(1)]; match self.store(self.deref(a1)) { addr @ Addr::HeapCell(_) - | addr @ Addr::StackCell(..) - | addr @ Addr::AttrVar(_) => { + | addr @ Addr::StackCell(..) + | addr @ Addr::AttrVar(_) => { let mut iter = indices.code_dir.iter(); while let Some(((name, arity), _)) = iter.next() { @@ -1519,29 +1762,46 @@ impl MachineState { *arity, composite_op!(&indices.op_dir), ); + let db_ref = DBRef::NamedPred(name.clone(), *arity, spec); let r = addr.as_var().unwrap(); - self.bind(r, Addr::DBRef(db_ref)); + let addr = self.heap.to_unifiable( + HeapCellValue::DBRef(db_ref) + ); + + self.bind(r, addr); + return return_from_clause!(self.last_call, self); } self.fail = true; } - Addr::DBRef(DBRef::Op(..)) => self.fail = true, - Addr::DBRef(ref db_ref) => self.get_next_db_ref(&indices, db_ref), + Addr::Con(h) => { + match self.heap.clone(h) { + HeapCellValue::DBRef(DBRef::Op(..)) => { + self.fail = true; + } + HeapCellValue::DBRef(ref db_ref) => { + self.get_next_db_ref(indices, db_ref); + } + _ => { + self.fail = true; + } + } + } _ => { self.fail = true; } - }; + } } &SystemClauseType::GetNextOpDBRef => { - let a1 = self[temp_v!(1)].clone(); + let a1 = self[temp_v!(1)]; match self.store(self.deref(a1)) { addr @ Addr::HeapCell(_) - | addr @ Addr::StackCell(..) - | addr @ Addr::AttrVar(_) => { + | addr @ Addr::StackCell(..) + | addr @ Addr::AttrVar(_) => { let mut unossified_op_dir = OssifiedOpDir::new(); unossified_op_dir.extend(indices.op_dir.iter().filter_map( @@ -1571,9 +1831,13 @@ impl MachineState { ossified_op_dir.clone(), SharedOpDesc::new(*priority, *spec), ); + let r = addr.as_var().unwrap(); + let addr = self.heap.to_unifiable( + HeapCellValue::DBRef(db_ref) + ); - self.bind(r, Addr::DBRef(db_ref)); + self.bind(r, addr); } None => { self.fail = true; @@ -1581,106 +1845,159 @@ impl MachineState { } } } - Addr::DBRef(DBRef::NamedPred(..)) => self.fail = true, - Addr::DBRef(ref db_ref) => self.get_next_db_ref(&indices, db_ref), + Addr::Con(h) => { + match self.heap.clone(h) { + HeapCellValue::DBRef(DBRef::NamedPred(..)) => { + self.fail = true; + } + HeapCellValue::DBRef(ref db_ref) => { + self.get_next_db_ref(indices, db_ref); + } + _ => { + self.fail = true; + } + } + } _ => { self.fail = true; } } } &SystemClauseType::LookupDBRef => { - let a1 = self[temp_v!(1)].clone(); + let a1 = self[temp_v!(1)]; match self.store(self.deref(a1)) { - Addr::DBRef(db_ref) => match db_ref { - DBRef::NamedPred(name, arity, spec) => { - let a2 = self[temp_v!(2)].clone(); - let a3 = self[temp_v!(3)].clone(); - - let arity = Integer::from(arity); + Addr::Con(h) => { + match self.heap.clone(h) { + HeapCellValue::DBRef(DBRef::NamedPred(name, arity, spec)) => { + let a2 = self[temp_v!(2)]; + let a3 = self[temp_v!(3)]; + + let atom = self.heap.to_unifiable( + HeapCellValue::Atom(name, spec) + ); - self.unify(a2, Addr::Con(Constant::Atom(name, spec))); + self.unify(a2, atom); - if !self.fail { - self.unify(a3, Addr::Con(Constant::Integer(arity))); + if !self.fail { + self.unify(a3, Addr::Usize(arity)); + } + } + _ => { + self.fail = true; } } - _ => self.fail = true, - }, - _ => self.fail = true, + } + _ => { + self.fail = true; + } } } &SystemClauseType::LookupOpDBRef => { - let a1 = self[temp_v!(1)].clone(); + let a1 = self[temp_v!(1)]; match self.store(self.deref(a1)) { - Addr::DBRef(db_ref) => match db_ref { - DBRef::Op(priority, spec, name, _, shared_op_desc) => { - let prec = self[temp_v!(2)].clone(); - let specifier = self[temp_v!(3)].clone(); - let op = self[temp_v!(4)].clone(); - - let spec = match spec { - FX => "fx", - FY => "fy", - XF => "xf", - YF => "yf", - XFX => "xfx", - XFY => "xfy", - YFX => "yfx", - _ => { - self.fail = true; - return Ok(()); - } - }; + Addr::Con(h) => { + match self.heap.clone(h) { + HeapCellValue::DBRef(DBRef::Op( + priority, + spec, + name, + _, + shared_op_desc, + )) => { + let prec = self[temp_v!(2)]; + let specifier = self[temp_v!(3)]; + let op = self[temp_v!(4)]; + + let spec = match spec { + FX => "fx", + FY => "fy", + XF => "xf", + YF => "yf", + XFX => "xfx", + XFY => "xfy", + YFX => "yfx", + _ => { + self.fail = true; + return Ok(()); + } + }; + + let a3 = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!(spec), None) + ); - let a2 = Integer::from(priority); - let a3 = Addr::Con(Constant::Atom(clause_name!(spec), None)); - let a4 = Addr::Con(Constant::Atom(name, Some(shared_op_desc))); + let a4 = self.heap.to_unifiable( + HeapCellValue::Atom(name, Some(shared_op_desc)) + ); - self.unify(Addr::Con(Constant::Integer(a2)), prec); + self.unify(Addr::Usize(priority), prec); - if !self.fail { - self.unify(a3, specifier); - } + if !self.fail { + self.unify(a3, specifier); + } - if !self.fail { - self.unify(a4, op); + if !self.fail { + self.unify(a4, op); + } + } + _ => { + self.fail = true; } } - _ => self.fail = true, - }, - _ => self.fail = true, + } + _ => { + self.fail = true; + } } } &SystemClauseType::Maybe => { let result = { let mut rand = RANDOM_STATE.borrow_mut(); - rand.bits(1) == 0 }; self.fail = result; } &SystemClauseType::OpDeclaration => { - let priority = self[temp_v!(1)].clone(); - let specifier = self[temp_v!(2)].clone(); - let op = self[temp_v!(3)].clone(); + let priority = self[temp_v!(1)]; + let specifier = self[temp_v!(2)]; + let op = self[temp_v!(3)]; let priority = match self.store(self.deref(priority)) { - Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(), - _ => unreachable!(), + Addr::Con(h) if self.heap.integer_at(h) => + if let HeapCellValue::Integer(ref n) = &self.heap[h] { + n.to_usize().unwrap() + } else { + unreachable!() + }, + _ => + unreachable!(), }; let specifier = match self.store(self.deref(specifier)) { - Addr::Con(Constant::Atom(name, _)) => name, - _ => unreachable!(), + Addr::Con(h) if self.heap.atom_at(h) => + if let HeapCellValue::Atom(ref specifier, _) = &self.heap[h] { + specifier.clone() + } else { + unreachable!() + }, + _ => + unreachable!(), }; let op = match self.store(self.deref(op)) { - Addr::Con(Constant::Atom(name, _)) => name, - Addr::Con(Constant::Char(c)) => clause_name!(c.to_string(), indices.atom_tbl), - _ => unreachable!(), + Addr::Char(c) => + clause_name!(c.to_string(), indices.atom_tbl), + Addr::Con(h) if self.heap.atom_at(h) => + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + name.clone() + } else { + unreachable!() + }, + _ => + unreachable!(), }; let module = op.owning_module(); @@ -1697,7 +2014,8 @@ impl MachineState { }); match result { - Ok(()) => {} + Ok(()) => { + } Err(e) => { // 8.14.3.3 l) let e = MachineError::session_error(self.heap.h(), e); @@ -1712,7 +2030,7 @@ impl MachineState { self.truncate_if_no_lifted_heap_diff(|h| Addr::HeapCell(h)) } &SystemClauseType::TruncateIfNoLiftedHeapGrowth => { - self.truncate_if_no_lifted_heap_diff(|_| Addr::Con(Constant::EmptyList)) + self.truncate_if_no_lifted_heap_diff(|_| Addr::EmptyList) } &SystemClauseType::ClearAttributeGoals => { self.attr_var_init.attribute_goals.clear(); @@ -1726,90 +2044,101 @@ impl MachineState { self.fetch_attribute_goals(attr_goals); } &SystemClauseType::GetAttributedVariableList => { - let attr_var = self.store(self.deref(self[temp_v!(1)].clone())); - let attr_var_list = match attr_var { - Addr::AttrVar(h) => h + 1, - attr_var @ Addr::HeapCell(_) | attr_var @ Addr::StackCell(..) => { - // create an AttrVar in the heap. - let h = self.heap.h(); + let attr_var = self.store(self.deref(self[temp_v!(1)])); + let attr_var_list = + match attr_var { + Addr::AttrVar(h) => { + h + 1 + } + attr_var @ Addr::HeapCell(_) + | attr_var @ Addr::StackCell(..) => { + // create an AttrVar in the heap. + let h = self.heap.h(); - self.heap.push(HeapCellValue::Addr(Addr::AttrVar(h))); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h + 1))); + self.heap.push(HeapCellValue::Addr(Addr::AttrVar(h))); + self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h + 1))); - self.bind(Ref::AttrVar(h), attr_var); - h + 1 - } - _ => { - self.fail = true; - return Ok(()); - } - }; + self.bind(Ref::AttrVar(h), attr_var); + h + 1 + } + _ => { + self.fail = true; + return Ok(()); + } + }; - let list_addr = self[temp_v!(2)].clone(); + let list_addr = self[temp_v!(2)]; self.unify(Addr::HeapCell(attr_var_list), list_addr); } &SystemClauseType::GetAttrVarQueueDelimiter => { - let addr = self[temp_v!(1)].clone(); - let value = Addr::Con(Constant::Usize(self.attr_var_init.attr_var_queue.len())); + let addr = self[temp_v!(1)]; + let value = Addr::Usize(self.attr_var_init.attr_var_queue.len()); self.unify(addr, value); } &SystemClauseType::GetAttrVarQueueBeyond => { - let addr = self[temp_v!(1)].clone(); + let addr = self[temp_v!(1)]; match self.store(self.deref(addr)) { - Addr::Con(Constant::Usize(b)) => { + Addr::Usize(b) => { let iter = self.gather_attr_vars_created_since(b); let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); - let list_addr = self[temp_v!(2)].clone(); + let list_addr = self[temp_v!(2)]; self.unify(var_list_addr, list_addr); } - Addr::Con(Constant::Integer(n)) => { - if let Some(b) = n.to_usize() { - let iter = self.gather_attr_vars_created_since(b); + Addr::Con(h) if self.heap.integer_at(h) => { + if let HeapCellValue::Integer(n) = self.heap.clone(h) { + if let Some(b) = n.to_usize() { + let iter = self.gather_attr_vars_created_since(b); - let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); - let list_addr = self[temp_v!(2)].clone(); + let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); + let list_addr = self[temp_v!(2)].clone(); - self.unify(var_list_addr, list_addr); + self.unify(var_list_addr, list_addr); + } else { + self.fail = true; + } } else { - self.fail = true; + unreachable!() } } - _ => self.fail = true, + _ => { + self.fail = true; + } } } &SystemClauseType::GetContinuationChunk => { - let e = self.store(self.deref(self[temp_v!(1)].clone())); + let e = self.store(self.deref(self[temp_v!(1)])); - let e = if let Addr::Con(Constant::Usize(e)) = e { + let e = if let Addr::Usize(e) = e { e } else { self.fail = true; return Ok(()); }; - let p_functor = self.store(self.deref(self[temp_v!(2)].clone())); + let p_functor = self.store(self.deref(self[temp_v!(2)])); let p = self.heap.to_local_code_ptr(&p_functor).unwrap(); - let num_cells = match code_repo.lookup_instr(self.last_call, &CodePtr::Local(p)) { - Some(line) => { - let perm_vars = match line.as_ref() { - Line::Control(ref ctrl_instr) => ctrl_instr.perm_vars(), - _ => None - }; + let num_cells = + match code_repo.lookup_instr(self.last_call, &CodePtr::Local(p)) { + Some(line) => { + let perm_vars = match line.as_ref() { + Line::Control(ref ctrl_instr) => ctrl_instr.perm_vars(), + _ => None + }; - perm_vars.unwrap() - } - _ => unreachable!() - }; + perm_vars.unwrap() + } + _ => unreachable!() + }; let mut addrs = vec![]; for index in 1 .. num_cells + 1 { - addrs.push(self.stack.index_and_frame(e)[index].clone()); + addrs.push(self.stack.index_and_frame(e)[index]); } let chunk = Addr::HeapCell(self.heap.h()); @@ -1823,19 +2152,19 @@ impl MachineState { self.heap.push(HeapCellValue::Addr(p_functor)); self.heap.extend(addrs.into_iter().map(HeapCellValue::Addr)); - self.unify(self[temp_v!(3)].clone(), chunk); + self.unify(self[temp_v!(3)], chunk); } &SystemClauseType::GetLiftedHeapFromOffsetDiff => { - let lh_offset = self[temp_v!(1)].clone(); + let lh_offset = self[temp_v!(1)]; match self.store(self.deref(lh_offset)) { - Addr::Con(Constant::Usize(lh_offset)) => { + Addr::Usize(lh_offset) => { if lh_offset >= self.lifted_heap.h() { - let solutions = self[temp_v!(2)].clone(); - let diff = self[temp_v!(3)].clone(); + let solutions = self[temp_v!(2)]; + let diff = self[temp_v!(3)]; - self.unify(solutions, Addr::Con(Constant::EmptyList)); - self.unify(diff, Addr::Con(Constant::EmptyList)); + self.unify(solutions, Addr::EmptyList); + self.unify(diff, Addr::EmptyList); } else { let h = self.heap.h(); let mut last_index = h; @@ -1845,14 +2174,10 @@ impl MachineState { match value { HeapCellValue::Addr(ref addr) => { - self.heap.push(HeapCellValue::Addr(addr.clone() + h)); - } - HeapCellValue::PartialString(ref pstr) => { - let new_pstr = pstr.clone(); - self.heap.push(HeapCellValue::PartialString(new_pstr)); + self.heap.push(HeapCellValue::Addr(*addr + h)); } value => { - self.heap.push(value.clone()); + self.heap.push(value.context_free_clone()); } } } @@ -1860,72 +2185,90 @@ impl MachineState { if last_index < self.heap.h() { let addr_opt = if let HeapCellValue::Addr(ref addr) = &self.heap[last_index] { - Some(addr.clone()) + Some(*addr) } else { None }; addr_opt.map(|addr| { - let diff = self[temp_v!(3)].clone(); + let diff = self[temp_v!(3)]; self.unify(diff, addr); }); } self.lifted_heap.truncate(lh_offset); - let solutions = self[temp_v!(2)].clone(); + let solutions = self[temp_v!(2)]; self.unify(Addr::HeapCell(h), solutions); } } - _ => self.fail = true, + _ => { + self.fail = true; + } } } &SystemClauseType::GetLiftedHeapFromOffset => { - let lh_offset = self[temp_v!(1)].clone(); + let lh_offset = self[temp_v!(1)]; match self.store(self.deref(lh_offset)) { - Addr::Con(Constant::Usize(lh_offset)) => { + Addr::Usize(lh_offset) => { if lh_offset >= self.lifted_heap.h() { - let solutions = self[temp_v!(2)].clone(); - self.unify(solutions, Addr::Con(Constant::EmptyList)); + let solutions = self[temp_v!(2)]; + self.unify(solutions, Addr::EmptyList); } else { let h = self.heap.h(); for addr in self.lifted_heap.iter_from(lh_offset) { match addr { HeapCellValue::Addr(ref addr) => { - self.heap.push(HeapCellValue::Addr(addr.clone() + h)) - } - HeapCellValue::PartialString(ref pstr) => { - let new_pstr = pstr.clone(); - self.heap.push(HeapCellValue::PartialString(new_pstr)); + self.heap.push(HeapCellValue::Addr(*addr + h)); } value => { - self.heap.push(value.clone()); + self.heap.push(value.context_free_clone()); } } } self.lifted_heap.truncate(lh_offset); - let solutions = self[temp_v!(2)].clone(); + let solutions = self[temp_v!(2)]; self.unify(Addr::HeapCell(h), solutions); } } - _ => self.fail = true, + _ => { + self.fail = true; + } } } &SystemClauseType::GetDoubleQuotes => { - let a1 = self[temp_v!(1)].clone(); + let a1 = self[temp_v!(1)]; match self.flags.double_quotes { - DoubleQuotes::Chars => self.unify(a1, Addr::Con(atom!("chars"))), - DoubleQuotes::Atom => self.unify(a1, Addr::Con(atom!("atom"))), - DoubleQuotes::Codes => self.unify(a1, Addr::Con(atom!("codes"))), + DoubleQuotes::Chars => { + let atom = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!("chars"), None) + ); + + self.unify(a1, atom); + } + DoubleQuotes::Atom => { + let atom = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!("atom"), None) + ); + + self.unify(a1, atom); + } + DoubleQuotes::Codes => { + let atom = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!("codes"), None) + ); + + self.unify(a1, atom); + } } } &SystemClauseType::GetSCCCleaner => { - let dest = self[temp_v!(1)].clone(); + let dest = self[temp_v!(1)]; match cut_policy.downcast_mut::().ok() { Some(sgc_policy) => { @@ -1936,7 +2279,7 @@ impl MachineState { self.block = prev_b; if let Some(r) = dest.as_var() { - self.bind(r, addr.clone()); + self.bind(r, addr); return return_from_clause!(self.last_call, self); } } else { @@ -1949,9 +2292,11 @@ impl MachineState { self.fail = true; } - &SystemClauseType::Halt => std::process::exit(0), + &SystemClauseType::Halt => { + std::process::exit(0); + } &SystemClauseType::InstallSCCCleaner => { - let addr = self[temp_v!(1)].clone(); + let addr = self[temp_v!(1)]; let b = self.b; let prev_block = self.block; @@ -1973,65 +2318,104 @@ impl MachineState { } &SystemClauseType::InstallInferenceCounter => { // A1 = B, A2 = L - let a1 = self.store(self.deref(self[temp_v!(1)].clone())); - let a2 = self.store(self.deref(self[temp_v!(2)].clone())); + let a1 = self.store(self.deref(self[temp_v!(1)])); + let a2 = self.store(self.deref(self[temp_v!(2)])); if call_policy.downcast_ref::().is_err() { CWILCallPolicy::new_in_place(call_policy); } - match (a1, a2.clone()) { - (Addr::Con(Constant::Usize(bp)), Addr::Con(Constant::Integer(n))) - | (Addr::Con(Constant::CutPoint(bp)), Addr::Con(Constant::Integer(n))) => { - match call_policy.downcast_mut::().ok() { - Some(call_policy) => { - let count = call_policy.add_limit(n, bp); - let count = Addr::Con(Constant::Integer(count.clone())); + match (a1, a2) { + (Addr::Usize(bp), Addr::Con(h)) + | (Addr::CutPoint(bp), Addr::Con(h)) + if self.heap.integer_at(h) => { + if let HeapCellValue::Integer(n) = self.heap.clone(h) { + match call_policy.downcast_mut::().ok() { + Some(call_policy) => { + let count = call_policy.add_limit(Integer::from(&*n), bp); + let count = self.heap.to_unifiable( + HeapCellValue::Integer(Rc::new(count.clone())) + ); - let a3 = self[temp_v!(3)].clone(); + let a3 = self[temp_v!(3)]; - self.unify(a3, count); + self.unify(a3, count); + } + None => { + panic!( + "install_inference_counter: should have installed \\ + CWILCallPolicy." + ) + } + } + } else { + unreachable!() } - None => panic!( - "install_inference_counter: should have installed \\ - CWILCallPolicy." - ), } - } _ => { let stub = MachineError::functor_stub( clause_name!("call_with_inference_limit"), 3, ); - let type_error = - self.error_form(MachineError::type_error(ValidType::Integer, a2), stub); + + let type_error = self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + a2, + ), + stub, + ); + self.throw_exception(type_error) } }; } &SystemClauseType::ModuleExists => { - let module = self.store(self.deref(self[temp_v!(1)].clone())); + let module = self.store(self.deref(self[temp_v!(1)])); match module { - Addr::Con(Constant::Atom(ref name, _)) => { - self.fail = !indices.modules.contains_key(name); + Addr::Con(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + self.fail = !indices.modules.contains_key(name); + } else { + unreachable!() + } + } + _ => { + unreachable!() } - _ => unreachable!() }; } &SystemClauseType::ModuleOf => { - let module = self.store(self.deref(self[temp_v!(2)].clone())); + let module = self.store(self.deref(self[temp_v!(2)])); match module { - Addr::Con(Constant::Atom(name, _)) => { - let module = Addr::Con(Constant::Atom(name.owning_module(), None)); - let target = self[temp_v!(1)].clone(); + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { + let module = self.heap.to_unifiable( + HeapCellValue::Atom( + name.owning_module(), + None + ), + ); - self.unify(target, module); + let target = self[temp_v!(1)]; + + self.unify(target, module); + } else { + unreachable!() + } } - Addr::Str(s) => match self.heap[s].clone() { + Addr::Str(s) => match self.heap.clone(s) { HeapCellValue::NamedStr(_, name, ..) => { - let module = Addr::Con(Constant::Atom(name.owning_module(), None)); + let module = self.heap.to_unifiable( + HeapCellValue::Atom( + name.owning_module(), + None + ), + ); + let target = self[temp_v!(1)].clone(); self.unify(target, module); @@ -2040,28 +2424,36 @@ impl MachineState { unreachable!() } }, - _ => self.fail = true, + _ => { + self.fail = true; + } }; } &SystemClauseType::NoSuchPredicate => { - let head = self[temp_v!(1)].clone(); + let head = self[temp_v!(1)]; self.fail = match self.store(self.deref(head)) { - Addr::Str(s) => match self.heap[s].clone() { - HeapCellValue::NamedStr(arity, name, op_spec) => { + Addr::Str(s) => match &self.heap[s] { + &HeapCellValue::NamedStr(arity, ref name, ref spec) => { let module = name.owning_module(); - indices.predicate_exists(name, module, arity, op_spec) + indices.predicate_exists(name.clone(), module, arity, spec.clone()) + } + _ => { + unreachable!() } - _ => unreachable!(), }, - Addr::Con(Constant::Atom(name, spec)) => { - let module = name.owning_module(); - let spec = fetch_atom_op_spec(name.clone(), spec, &indices.op_dir); + Addr::Con(h) if self.heap.atom_at(h) => { + if let &HeapCellValue::Atom(ref name, ref spec) = &self.heap[h] { + let module = name.owning_module(); + let spec = fetch_atom_op_spec(name.clone(), spec.clone(), &indices.op_dir); - indices.predicate_exists(name, module, 0, spec) + indices.predicate_exists(name.clone(), module, 0, spec) + } else { + unreachable!() + } } head => { - let err = MachineError::type_error(ValidType::Callable, head); + let err = MachineError::type_error(self.heap.h(), ValidType::Callable, head); let stub = MachineError::functor_stub(clause_name!("clause"), 2); return Err(self.error_form(err, stub)); @@ -2069,8 +2461,8 @@ impl MachineState { }; } &SystemClauseType::RedoAttrVarBinding => { - let var = self.store(self.deref(self[temp_v!(1)].clone())); - let value = self.store(self.deref(self[temp_v!(2)].clone())); + let var = self.store(self.deref(self[temp_v!(1)])); + let value = self.store(self.deref(self[temp_v!(2)])); match var { Addr::AttrVar(h) => { @@ -2090,75 +2482,92 @@ impl MachineState { self.heap[h] = HeapCellValue::Addr(value); } } - _ => unreachable!() + _ => { + unreachable!() + } } } &SystemClauseType::ResetGlobalVarAtKey => { - let key = self[temp_v!(1)].clone(); + let key = self[temp_v!(1)]; - let key = match self.store(self.deref(key)) { - Addr::Con(Constant::Atom(atom, _)) => atom, - _ => unreachable!(), - }; - - indices.global_variables.swap_remove(&key); + match self.store(self.deref(key)) { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref key, _) = &self.heap[h] { + indices.global_variables.swap_remove(key); + } else { + unreachable!() + } + } + _ => { + unreachable!() + } + } } &SystemClauseType::ResetGlobalVarAtOffset => { - let key = self[temp_v!(1)].clone(); + let key = self[temp_v!(1)]; let key = match self.store(self.deref(key)) { - Addr::Con(Constant::Atom(atom, _)) => atom, - _ => unreachable!(), + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref key, _) = &self.heap[h] { + key.clone() + } else { + unreachable!() + } + } + _ => { + unreachable!() + } }; - let value = self[temp_v!(2)].clone(); + let value = self[temp_v!(2)]; let mut ball = Ball::new(); - let h = self.heap.h(); - ball.boundary = h; + ball.boundary = self.heap.h(); + copy_term( CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut ball.stub), value, AttrVarPolicy::DeepCopy, ); - let offset = self[temp_v!(3)].clone(); + let offset = self[temp_v!(3)]; match self.store(self.deref(offset)) { - Addr::Con(Constant::Usize(offset)) => { - indices.global_variables.insert(key, (ball, Some(offset))) + Addr::Usize(offset) => { + indices.global_variables.insert(key, (ball, Some(offset))); } _ => { - indices.global_variables.insert(key, (ball, None)) + indices.global_variables.insert(key, (ball, None)); } - }; + } }, &SystemClauseType::ResetAttrVarState => { self.attr_var_init.reset(); } &SystemClauseType::RemoveCallPolicyCheck => { - let restore_default = match call_policy.downcast_mut::().ok() { - Some(call_policy) => { - let a1 = self.store(self.deref(self[temp_v!(1)].clone())); - - match a1 { - Addr::Con(Constant::Usize(bp)) | Addr::Con(Constant::CutPoint(bp)) => { - if call_policy.is_empty() && bp == self.b { - Some(call_policy.into_inner()) - } else { - None + let restore_default = + match call_policy.downcast_mut::().ok() { + Some(call_policy) => { + let a1 = self.store(self.deref(self[temp_v!(1)])); + + match a1 { + Addr::Usize(bp) | Addr::CutPoint(bp) => { + if call_policy.is_empty() && bp == self.b { + Some(call_policy.into_inner()) + } else { + None + } + } + _ => { + panic!("remove_call_policy_check: expected Usize in A1."); } - } - _ => { - panic!("remove_call_policy_check: expected Usize in A1."); } } - } - None => panic!( - "remove_call_policy_check: requires \\ - CWILCallPolicy." - ), - }; + None => panic!( + "remove_call_policy_check: requires \\ + CWILCallPolicy." + ), + }; if let Some(new_policy) = restore_default { *call_policy = new_policy; @@ -2167,14 +2576,16 @@ impl MachineState { &SystemClauseType::RemoveInferenceCounter => { match call_policy.downcast_mut::().ok() { Some(call_policy) => { - let a1 = self.store(self.deref(self[temp_v!(1)].clone())); + let a1 = self.store(self.deref(self[temp_v!(1)])); match a1 { - Addr::Con(Constant::Usize(bp)) | Addr::Con(Constant::CutPoint(bp)) => { + Addr::Usize(bp) | Addr::CutPoint(bp) => { let count = call_policy.remove_limit(bp); - let count = Addr::Con(Constant::Integer(count.clone())); + let count = self.heap.to_unifiable( + HeapCellValue::Integer(Rc::new(count.clone())), + ); - let a2 = self[temp_v!(2)].clone(); + let a2 = self[temp_v!(2)]; self.unify(a2, count); } @@ -2189,7 +2600,9 @@ impl MachineState { ), } } - &SystemClauseType::REPL(repl_code_ptr) => return self.repl_redirect(repl_code_ptr), + &SystemClauseType::REPL(repl_code_ptr) => { + return self.repl_redirect(repl_code_ptr); + } &SystemClauseType::ModuleRetractClause => { let p = self.cp; let trans_type = DynamicTransactionType::ModuleRetract; @@ -2209,14 +2622,14 @@ impl MachineState { let frame_len = self.stack.index_and_frame(e).prelude.univ_prelude.num_cells; for i in 1 .. frame_len - 1 { - self[RegType::Temp(i)] = self.stack.index_and_frame(e)[i].clone(); + self[RegType::Temp(i)] = self.stack.index_and_frame(e)[i]; } - if let &Addr::Con(Constant::CutPoint(b0)) = &self.stack.index_and_frame(e)[frame_len - 1] { + if let &Addr::CutPoint(b0) = &self.stack.index_and_frame(e)[frame_len - 1] { self.b0 = b0; } - if let &Addr::Con(Constant::Usize(num_of_args)) = &self.stack.index_and_frame(e)[frame_len] { + if let &Addr::Usize(num_of_args) = &self.stack.index_and_frame(e)[frame_len] { self.num_of_args = num_of_args; } @@ -2246,32 +2659,50 @@ impl MachineState { deref_cut(self, r) } &SystemClauseType::SetInput => { - let addr = self.store(self.deref(self[temp_v!(1)].clone())); + let addr = self.store(self.deref(self[temp_v!(1)])); let stream = self.get_stream_or_alias(addr, indices, "set_input")?; if stream.is_output_stream() { - let stub = MachineError::functor_stub(clause_name!("set_input"), 1); + let stub = MachineError::functor_stub( + clause_name!("set_input"), + 1, + ); + + let user_alias = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!("user"), None), + ); + let err = MachineError::permission_error( - PermissionError::InputStream, + self.heap.h(), + Permission::InputStream, "stream", - Addr::Stream(stream), + user_alias, ); return Err(self.error_form(err, stub)); } - + *current_input_stream = stream; } &SystemClauseType::SetOutput => { - let addr = self.store(self.deref(self[temp_v!(1)].clone())); + let addr = self.store(self.deref(self[temp_v!(1)])); let stream = self.get_stream_or_alias(addr, indices, "set_output")?; if stream.is_input_stream() { - let stub = MachineError::functor_stub(clause_name!("set_input"), 1); + let stub = MachineError::functor_stub( + clause_name!("set_input"), + 1, + ); + + let user_alias = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!("user"), None), + ); + let err = MachineError::permission_error( - PermissionError::OutputStream, + self.heap.h(), + Permission::OutputStream, "stream", - Addr::Stream(stream), + user_alias, ); return Err(self.error_form(err, stub)); @@ -2279,55 +2710,80 @@ impl MachineState { *current_output_stream = stream; } - &SystemClauseType::SetDoubleQuotes => match self[temp_v!(1)].clone() { - Addr::Con(Constant::Atom(ref atom, _)) if atom.as_str() == "chars" => { - self.flags.double_quotes = DoubleQuotes::Chars - } - Addr::Con(Constant::Atom(ref atom, _)) if atom.as_str() == "atom" => { - self.flags.double_quotes = DoubleQuotes::Atom - } - Addr::Con(Constant::Atom(ref atom, _)) if atom.as_str() == "codes" => { - self.flags.double_quotes = DoubleQuotes::Codes + &SystemClauseType::SetDoubleQuotes => { + match self[temp_v!(1)] { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { + self.flags.double_quotes = + match atom.as_str() { + "atom" => DoubleQuotes::Atom, + "chars" => DoubleQuotes::Chars, + "codes" => DoubleQuotes::Codes, + _ => { + self.fail = true; + return Ok(()); + } + }; + } else { + unreachable!() + } + } + _ => { + self.fail = true; + } } - _ => self.fail = true, - }, + } &SystemClauseType::InferenceLevel => { - let a1 = self[temp_v!(1)].clone(); - let a2 = self.store(self.deref(self[temp_v!(2)].clone())); + let a1 = self[temp_v!(1)]; + let a2 = self.store(self.deref(self[temp_v!(2)])); match a2 { - Addr::Con(Constant::CutPoint(bp)) | Addr::Con(Constant::Usize(bp)) => { + Addr::CutPoint(bp) | Addr::Usize(bp) => { let prev_b = self.stack.index_or_frame(self.b).prelude.b; if prev_b <= bp { - let a2 = Addr::Con(atom!("!")); + let a2 = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!("!"), None) + ); + self.unify(a1, a2); } else { - let a2 = Addr::Con(atom!("true")); + let a2 = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!("true"), None) + ); + self.unify(a1, a2); } } - _ => self.fail = true, - }; + _ => { + self.fail = true; + } + } } &SystemClauseType::CleanUpBlock => { - let nb = self.store(self.deref(self[temp_v!(1)].clone())); + let nb = self.store(self.deref(self[temp_v!(1)])); match nb { - Addr::Con(Constant::Usize(nb)) => { + Addr::Usize(nb) => { let b = self.b; if nb > 0 && self.stack.index_or_frame(b).prelude.b == nb { self.b = self.stack.index_or_frame(nb).prelude.b; } } - _ => self.fail = true, + _ => { + self.fail = true; + } }; } - &SystemClauseType::EraseBall => self.ball.reset(), - &SystemClauseType::Fail => self.fail = true, + &SystemClauseType::EraseBall => { + self.ball.reset(); + } + &SystemClauseType::Fail => { + self.fail = true; + } &SystemClauseType::GetBall => { - let addr = self.store(self.deref(self[temp_v!(1)].clone())); + let addr = self.store(self.deref(self[temp_v!(1)])); let h = self.heap.h(); if self.ball.stub.h() > 0 { @@ -2347,46 +2803,65 @@ impl MachineState { } &SystemClauseType::GetCurrentBlock => { let c = Constant::Usize(self.block); - let addr = self[temp_v!(1)].clone(); + let addr = self[temp_v!(1)]; - self.write_constant_to_var(addr, c); + self.write_constant_to_var(addr, &c); } &SystemClauseType::GetBValue => { - let a1 = self[temp_v!(1)].clone(); - let a2 = Addr::Con(Constant::Usize(self.b)); + let a1 = self[temp_v!(1)]; + let a2 = Addr::Usize(self.b); self.unify(a1, a2); } &SystemClauseType::GetClause => { - let head = self[temp_v!(1)].clone(); + let head = self[temp_v!(1)]; let subsection = match self.store(self.deref(head)) { - Addr::Str(s) => match self.heap[s].clone() { - HeapCellValue::NamedStr(arity, name, ..) => { - indices.get_clause_subsection(name.owning_module(), name, arity) + Addr::Str(s) => match &self.heap[s] { + &HeapCellValue::NamedStr(arity, ref name, ..) => { + indices.get_clause_subsection( + name.owning_module(), + name.clone(), + arity, + ) + } + _ => { + unreachable!() } - _ => unreachable!(), }, - Addr::Con(Constant::Atom(name, _)) => { - indices.get_clause_subsection(name.owning_module(), name, 0) + Addr::Con(h) if self.heap.atom_at(h) => { + if let &HeapCellValue::Atom(ref name, _) = &self.heap[h] { + indices.get_clause_subsection( + name.owning_module(), + name.clone(), + 0, + ) + } else { + unreachable!() + } + } + _ => { + unreachable!() } - _ => unreachable!(), }; match subsection { Some(dynamic_predicate_info) => { self.execute_at_index( 2, - dir_entry!(dynamic_predicate_info.clauses_subsection_p) + dir_entry!(dynamic_predicate_info.clauses_subsection_p), ); + return Ok(()); } - _ => unreachable!(), + _ => { + unreachable!() + } } } &SystemClauseType::GetCutPoint => { - let a1 = self[temp_v!(1)].clone(); - let a2 = Addr::Con(Constant::CutPoint(self.b0)); + let a1 = self[temp_v!(1)]; + let a2 = Addr::CutPoint(self.b0); self.unify(a1, a2); } @@ -2410,34 +2885,41 @@ impl MachineState { ContinueResult::PrintWithMaxDepth => 'p', }; - let target = self[temp_v!(1)].clone(); - self.unify(Addr::Con(Constant::Char(c)), target); + let target = self[temp_v!(1)]; + self.unify(Addr::Char(c), target); } &SystemClauseType::NextEP => { - let first_arg = self.store(self.deref(self[temp_v!(1)].clone())); + let first_arg = self.store(self.deref(self[temp_v!(1)])); match first_arg { - Addr::Con(Constant::Atom(ref name, _)) - if name.as_str() == "first" => { - if self.e == 0 { - self.fail = true; - return Ok(()); - } + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref name, _) = self.heap.clone(h) { + if name.as_str() == "first" { + if self.e == 0 { + self.fail = true; + return Ok(()); + } - let cp = (self.stack.index_and_frame(self.e).prelude.cp - 1).unwrap(); + let cp = (self.stack.index_and_frame(self.e).prelude.cp - 1).unwrap(); - let e = self.stack.index_and_frame(self.e).prelude.e; - let e = Addr::Con(Constant::Usize(e)); + let e = self.stack.index_and_frame(self.e).prelude.e; + let e = Addr::Usize(e); - let p = cp.as_functor(&mut self.heap); + let p = cp.as_functor(&mut self.heap); - self.unify(self[temp_v!(2)].clone(), e); + self.unify(self[temp_v!(2)], e); - if !self.fail { - self.unify(self[temp_v!(3)].clone(), p); + if !self.fail { + self.unify(self[temp_v!(3)], p); + } + } else { + unreachable!() } - }, - Addr::Con(Constant::Usize(e)) => { + } else { + unreachable!() + } + } + Addr::Usize(e) => { if e == 0 { self.fail = true; return Ok(()); @@ -2450,22 +2932,26 @@ impl MachineState { let p = cp.as_functor(&mut self.heap); let e = self.stack.index_and_frame(e).prelude.e; - let e = Addr::Con(Constant::Usize(e)); + let e = Addr::Usize(e); - self.unify(self[temp_v!(2)].clone(), e); + self.unify(self[temp_v!(2)], e); if !self.fail { - self.unify(self[temp_v!(3)].clone(), p); + self.unify(self[temp_v!(3)], p); } } - _ => unreachable!() + _ => { + unreachable!() + } } } &SystemClauseType::PointsToContinuationResetMarker => { - let addr = self.store(self.deref(self[temp_v!(1)].clone())); + let addr = self.store(self.deref(self[temp_v!(1)])); let p = match self.heap.to_local_code_ptr(&addr) { - Some(p) => p + 1, + Some(p) => { + p + 1 + } None => { self.fail = true; return Ok(()); @@ -2480,10 +2966,10 @@ impl MachineState { return Ok(()); } &SystemClauseType::QuotedToken => { - let addr = self.store(self.deref(self[temp_v!(1)].clone())); + let addr = self.store(self.deref(self[temp_v!(1)])); match addr { - Addr::Con(Constant::CharCode(c)) => { + Addr::CharCode(c) => { self.fail = match std::char::from_u32(c) { Some(c) => { non_quoted_token(once(c)) @@ -2493,11 +2979,13 @@ impl MachineState { } }; } - Addr::Con(Constant::Char(c)) => { + Addr::Char(c) => { self.fail = non_quoted_token(once(c)); } - Addr::Con(Constant::Atom(atom, _)) => { - self.fail = non_quoted_token(atom.as_str().chars()); + Addr::Con(h) => { + if let HeapCellValue::Atom(atom, _) = &self.heap[h] { + self.fail = non_quoted_token(atom.as_str().chars()); + } } _ => { self.fail = true; @@ -2516,33 +3004,46 @@ impl MachineState { self.read_term(current_input_stream, indices)?; } &SystemClauseType::ResetBlock => { - let addr = self.deref(self[temp_v!(1)].clone()); + let addr = self.deref(self[temp_v!(1)]); self.reset_block(addr); } &SystemClauseType::ResetContinuationMarker => { - self[temp_v!(3)] = Addr::Con(Constant::Atom(clause_name!("none"), None)); - let h = self.heap.h(); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); + self[temp_v!(3)] = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!("none"), None) + ); + + self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); self[temp_v!(4)] = Addr::HeapCell(h); } - &SystemClauseType::SetBall => - self.set_ball(), + &SystemClauseType::SetBall => { + self.set_ball(); + } &SystemClauseType::SetSeed => { - let seed = self.store(self.deref(self[temp_v!(1)].clone())); + let seed = self.store(self.deref(self[temp_v!(1)])); let seed = match seed { - Addr::Con(Constant::Integer(n)) => - n, - Addr::Con(Constant::CharCode(c)) => - Integer::from(c), - Addr::Con(Constant::Rational(r)) => { - if r.denom() == &1 { - r.numer().clone() + Addr::CharCode(c) => { + Integer::from(c) + } + Addr::Con(h) if self.heap.integer_at(h) => { + if let HeapCellValue::Integer(ref n) = &self.heap[h] { + Integer::from(&**n) } else { - self.fail = true; - return Ok(()); + unreachable!() + } + } + Addr::Con(h) if self.heap.rational_at(h) => { + if let HeapCellValue::Rational(r) = &self.heap[h] { + if r.denom() == &1 { + r.numer().clone() + } else { + self.fail = true; + return Ok(()); + } + } else { + unreachable!() } } _ => { @@ -2559,17 +3060,26 @@ impl MachineState { return Err(err); }, &SystemClauseType::StoreGlobalVar => { - let key = self[temp_v!(1)].clone(); + let key = self[temp_v!(1)]; let key = match self.store(self.deref(key)) { - Addr::Con(Constant::Atom(atom, _)) => atom, - _ => unreachable!(), + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { + atom.clone() + } else { + unreachable!() + } + } + _ => { + unreachable!() + } }; - let value = self[temp_v!(2)].clone(); + let value = self[temp_v!(2)]; let mut ball = Ball::new(); ball.boundary = self.heap.h(); + copy_term( CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut ball.stub), value, @@ -2579,18 +3089,27 @@ impl MachineState { indices.global_variables.insert(key, (ball, None)); } &SystemClauseType::StoreGlobalVarWithOffset => { - let key = self[temp_v!(1)].clone(); + let key = self[temp_v!(1)]; let key = match self.store(self.deref(key)) { - Addr::Con(Constant::Atom(atom, _)) => atom, - _ => unreachable!(), + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { + atom.clone() + } else { + unreachable!() + } + } + _ => { + unreachable!() + } }; - let value = self[temp_v!(2)].clone(); + let value = self[temp_v!(2)]; let mut ball = Ball::new(); let h = self.heap.h(); ball.boundary = h; + copy_term( CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut ball.stub), value.clone(), @@ -2599,40 +3118,39 @@ impl MachineState { let stub = ball.copy_and_align(h); self.heap.extend(stub.into_iter()); + indices.global_variables.insert(key, (ball, Some(h))); self.unify(value, Addr::HeapCell(h)); } - &SystemClauseType::Succeed => {} + &SystemClauseType::Succeed => { + } &SystemClauseType::TermVariables => { - let a1 = self[temp_v!(1)].clone(); + let a1 = self[temp_v!(1)]; let mut seen_vars = IndexSet::new(); - for item in self.acyclic_pre_order_iter(a1) { - match item { - HeapCellValue::Addr(addr) => { - if addr.is_ref() { - seen_vars.insert(addr); - } - } - _ => {} + for addr in self.acyclic_pre_order_iter(a1) { + if addr.is_ref() { + seen_vars.insert(addr); } } let outcome = Addr::HeapCell(self.heap.to_list(seen_vars.into_iter())); - let a2 = self[temp_v!(2)].clone(); + let a2 = self[temp_v!(2)]; self.unify(a2, outcome); } &SystemClauseType::TruncateLiftedHeapTo => { - match self.store(self.deref(self[temp_v!(1)].clone())) { - Addr::Con(Constant::Usize(lh_offset)) => self.lifted_heap.truncate(lh_offset), - _ => self.fail = true, + match self.store(self.deref(self[temp_v!(1)])) { + Addr::Usize(lh_offset) => + self.lifted_heap.truncate(lh_offset), + _ => + self.fail = true, } } &SystemClauseType::UnifyWithOccursCheck => { - let a1 = self[temp_v!(1)].clone(); - let a2 = self[temp_v!(2)].clone(); + let a1 = self[temp_v!(1)]; + let a2 = self[temp_v!(2)]; self.unify_with_occurs_check(a1, a2); } @@ -2652,20 +3170,40 @@ impl MachineState { e = self.stack.index_and_frame(e).prelude.e; } } - &SystemClauseType::UnwindStack => self.unwind_stack(), - &SystemClauseType::Variant => self.fail = self.structural_eq_test(), + &SystemClauseType::UnwindStack => { + self.unwind_stack(); + } + &SystemClauseType::Variant => { + self.fail = self.structural_eq_test(); + } &SystemClauseType::WAMInstructions => { - let name = self[temp_v!(1)].clone(); - let arity = self[temp_v!(2)].clone(); + let name = self[temp_v!(1)]; + let arity = self[temp_v!(2)]; let name = match self.store(self.deref(name)) { - Addr::Con(Constant::Atom(name, _)) => name, - _ => unreachable!(), + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { + atom.clone() + } else { + unreachable!() + } + } + _ => { + unreachable!() + } }; let arity = match self.store(self.deref(arity)) { - Addr::Con(Constant::Integer(n)) => n, - _ => unreachable!(), + Addr::Con(h) if self.heap.integer_at(h) => { + if let HeapCellValue::Integer(ref n) = &self.heap[h] { + n.clone() + } else { + unreachable!() + } + } + _ => { + unreachable!() + } }; let first_idx = match indices @@ -2684,6 +3222,7 @@ impl MachineState { h, ExistenceError::Procedure(name, arity), ); + let err = self.error_form(err, stub); self.throw_exception(err); @@ -2699,6 +3238,7 @@ impl MachineState { h, ExistenceError::Procedure(name, arity), ); + let err = self.error_form(err, stub); self.throw_exception(err); @@ -2727,39 +3267,55 @@ impl MachineState { self.unify(listing, listing_var); } &SystemClauseType::WriteTerm => { - let addr = self[temp_v!(1)].clone(); + let addr = self[temp_v!(1)]; - let ignore_ops = self.store(self.deref(self[temp_v!(2)].clone())); - let numbervars = self.store(self.deref(self[temp_v!(3)].clone())); - let quoted = self.store(self.deref(self[temp_v!(4)].clone())); - let max_depth = self.store(self.deref(self[temp_v!(6)].clone())); + let ignore_ops = self.store(self.deref(self[temp_v!(2)])); + let numbervars = self.store(self.deref(self[temp_v!(3)])); + let quoted = self.store(self.deref(self[temp_v!(4)])); + let max_depth = self.store(self.deref(self[temp_v!(6)])); let mut printer = HCPrinter::new(&self, &indices.op_dir, PrinterOutputter::new()); - if let &Addr::Con(Constant::Atom(ref name, ..)) = &ignore_ops { - printer.ignore_ops = name.as_str() == "true"; + if let &Addr::Con(h) = &ignore_ops { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + printer.ignore_ops = name.as_str() == "true"; + } else { + unreachable!() + } } - if let &Addr::Con(Constant::Atom(ref name, ..)) = &numbervars { - printer.numbervars = name.as_str() == "true"; + if let &Addr::Con(h) = &numbervars { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + printer.numbervars = name.as_str() == "true"; + } else { + unreachable!() + } } - if let &Addr::Con(Constant::Atom(ref name, ..)) = "ed { - printer.quoted = name.as_str() == "true"; + if let &Addr::Con(h) = "ed { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + printer.quoted = name.as_str() == "true"; + } else { + unreachable!() + } } - if let &Addr::Con(Constant::Integer(ref n)) = &max_depth { - if let Some(n) = n.to_usize() { - printer.max_depth = n; + if let &Addr::Con(h) = &max_depth { + if let HeapCellValue::Integer(ref n) = &self.heap[h] { + if let Some(n) = n.to_usize() { + printer.max_depth = n; + } else { + self.fail = true; + return Ok(()); + } } else { - self.fail = true; - return Ok(()); + unreachable!() } } let stub = MachineError::functor_stub(clause_name!("write_term"), 2); - match self.try_from_list(temp_v!(5), stub.clone()) { + match self.try_from_list(temp_v!(5), stub) { Ok(addrs) => { let mut var_names: IndexMap = IndexMap::new(); @@ -2773,8 +3329,14 @@ impl MachineState { let var = self.heap[s + 2].as_addr(s + 2); let atom = match self.store(self.deref(atom)) { - Addr::Con(Constant::Atom(atom, _)) => atom.to_string(), - Addr::Con(Constant::Char(c)) => c.to_string(), + Addr::Con(h) => { + if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { + atom.to_string() + } else { + unreachable!() + } + } + Addr::Char(c) => c.to_string(), _ => unreachable!(), }; diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 7968aa34..a024d606 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -4,54 +4,180 @@ macro_rules! interm { }; } -macro_rules! heap_str { - ($s:expr) => { - HeapCellValue::Addr(Addr::Str($s)) - }; -} - -macro_rules! heap_integer { - ($i:expr) => { - HeapCellValue::Addr(Addr::Con(Constant::Integer($i))) - }; -} - -macro_rules! heap_cell { - ($i:expr) => { - HeapCellValue::Addr(Addr::HeapCell($i)) - }; +/* A simple macro to count the arguments in a variadic list + * of token trees. + */ +macro_rules! count_tt { + () => { 0 }; + ($odd:tt $($a:tt $b:tt)*) => { (count_tt!($($a)*) << 1) | 1 }; + ($($a:tt $even:tt)*) => { count_tt!($($a)*) << 1 }; } -macro_rules! heap_con { - ($i:expr) => { - HeapCellValue::Addr(Addr::Con($i)) - }; -} +macro_rules! functor { + ($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({ + { + #[allow(unused_variables, unused_mut)] + let mut addendum = Heap::new(); + let arity = count_tt!($($dt) +); + let aux_lens = [$($aux.len()),*]; + + let mut result = + vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)), + $(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ]; + + $( + result.extend($aux.into_iter()); + )* + + result.extend(addendum.into_iter()); + result + } + }); + ($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+]) => ({ + { + #[allow(unused_variables, unused_mut)] + let mut addendum = Heap::new(); + let arity = count_tt!($($dt) +); + + let mut result = + vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)), + $(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ]; + + result.extend(addendum.into_iter()); + result + } + }); + ($name:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({ + { + #[allow(unused_variables, unused_mut)] + let mut addendum = Heap::new(); + let arity = count_tt!($($dt) +); + let aux_lens = [$($aux.len()),*]; + + let mut result = + vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None), + $(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ]; + + $( + result.extend($aux.into_iter()); + )* + + result.extend(addendum.into_iter()); + result + } + }); + ($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({ + { + let arity = count_tt!($($dt) +); -macro_rules! heap_atom { - ($name:expr) => { - HeapCellValue::Addr(Addr::Con(atom!($name))) - }; - ($name:expr, $tbl:expr) => { - HeapCellValue::Addr(Addr::Con(atom!($name, $tbl))) - }; + vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None), + $(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ] + } + }); + ($name:expr, $fixity:expr) => ( + vec![ HeapCellValue::Atom(clause_name!($name), Some($fixity)) ] + ); + (clause_name($name:expr)) => ( + vec![ HeapCellValue::Atom($name, None) ] + ); + ($name:expr) => ( + vec![ HeapCellValue::Atom(clause_name!($name), None) ] + ); } -macro_rules! functor { - ($name:expr) => ( - vec![ heap_atom!($name) ] +macro_rules! functor_term { + (aux(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ + HeapCellValue::Addr(Addr::HeapCell($arity + 1)) + }); + (aux($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ + let len: usize = $aux_lens[0 .. $e].iter().sum(); + HeapCellValue::Addr(Addr::HeapCell($arity + 1 + len)) + }); + (aux($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ + HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1)) + }); + (aux($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ + let len: usize = $aux_lens[0 .. $e].iter().sum(); + HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1 + len)) + }); + (addr($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( + HeapCellValue::Addr($e) + ); + (constant($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( + from_constant!($e, $h, $arity, $aux_lens, $addendum) + ); + (constant($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( + from_constant!($e, 0, $arity, $aux_lens, $addendum) + ); + (number($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( + $e.into() + ); + /* + (string($s:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({ + let len: usize = $aux_lens.iter().sum(); + let h = len + $arity + 1 + $addendum.h(); + + $addendum.allocate_pstr(&$s); + + HeapCell::PStrLocation(h, 0) + }); + */ + (integer($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ( + HeapCellValue::Integer(Rc::new(Integer::from($e))) ); - ($name:expr, $len:expr) => ( - vec![ HeapCellValue::NamedStr($len, clause_name!($name), None) ] + (clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ( + HeapCellValue::Atom($e, None) ); - ($name:expr, $len:expr, [$($args:expr),*]) => ( - vec![ HeapCellValue::NamedStr($len, clause_name!($name), None), $($args),* ] + (atom($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ( + HeapCellValue::Atom(clause_name!($e), None) ); - ($name:expr, $len:expr, [$($args:expr),*], $fix: expr) => ( - vec![ HeapCellValue::NamedStr($len, clause_name!($name), Some($fix)), $($args),* ] + ($e:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => ( + $e ); } +macro_rules! from_constant { + ($e:expr, $over_h:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => ({ + match $e { + &Constant::Atom(ref name, ref op) => { + HeapCellValue::Atom(name.clone(), op.clone()) + } + &Constant::Char(c) => { + HeapCellValue::Addr(Addr::Char(c)) + } + &Constant::CharCode(c) => { + HeapCellValue::Addr(Addr::CharCode(c)) + } + &Constant::CutPoint(cp) => { + HeapCellValue::Addr(Addr::CutPoint(cp)) + } + &Constant::Integer(ref n) => { + HeapCellValue::Integer(n.clone()) + } + &Constant::Rational(ref r) => { + HeapCellValue::Rational(r.clone()) + } + &Constant::Float(f) => { + HeapCellValue::Addr(Addr::Float(f)) + } + &Constant::String(ref s) => { + let len: usize = $aux_lens.iter().sum(); + let h = len + $arity + 1 + $addendum.h() + $over_h; + + $addendum.put_constant(Constant::String(s.clone())); + + HeapCellValue::Addr(Addr::PStrLocation(h, 0)) + } + &Constant::Usize(u) => { + HeapCellValue::Addr(Addr::Usize(u)) + } + &Constant::EmptyList => { + HeapCellValue::Addr(Addr::EmptyList) + } + } + }) +} + macro_rules! is_atom { ($r:expr) => { call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtom($r)), 1, 0) diff --git a/src/prolog/read.rs b/src/prolog/read.rs index 32d45224..33bea7cd 100644 --- a/src/prolog/read.rs +++ b/src/prolog/read.rs @@ -4,6 +4,7 @@ use prolog_parser::tabled_rc::TabledData; use crate::prolog::forms::*; use crate::prolog::iterators::*; +use crate::prolog::machine::heap::Heap; use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_state::MachineState; use crate::prolog::machine::streams::Stream; @@ -13,12 +14,20 @@ use std::collections::VecDeque; type SubtermDeque = VecDeque<(usize, usize)>; impl<'a> TermRef<'a> { - fn as_addr(&self, h: usize) -> Addr { + fn as_addr(&self, heap: &mut Heap, h: usize) -> Addr { match self { - &TermRef::AnonVar(_) | &TermRef::Var(..) => Addr::HeapCell(h), - &TermRef::Cons(..) => Addr::HeapCell(h), - &TermRef::Constant(_, _, c) => Addr::Con(c.clone()), - &TermRef::Clause(..) => Addr::Str(h), + &TermRef::AnonVar(_) | &TermRef::Var(..) => { + Addr::HeapCell(h) + } + &TermRef::Cons(..) => { + Addr::HeapCell(h) + } + &TermRef::Constant(_, _, c) => { + heap.put_constant(c.clone()) + } + &TermRef::Clause(..) => { + Addr::Str(h) + } } } } @@ -131,7 +140,7 @@ fn modify_head_of_queue( h: usize, ) { if let Some((arity, site_h)) = queue.pop_front() { - machine_st.heap[site_h] = HeapCellValue::Addr(term.as_addr(h)); + machine_st.heap[site_h] = HeapCellValue::Addr(term.as_addr(&mut machine_st.heap, h)); if arity > 1 { queue.push_front((arity - 1, site_h + 1)); @@ -180,10 +189,12 @@ pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> } } &TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) => { - machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h))) + let value = HeapCellValue::Addr(term.as_addr(&mut machine_st.heap, h)); + machine_st.heap.push(value); } &TermRef::Var(Level::Root, ..) => { - machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h))) + let value = HeapCellValue::Addr(term.as_addr(&mut machine_st.heap, h)); + machine_st.heap.push(value); } &TermRef::AnonVar(_) => { if let Some((arity, site_h)) = queue.pop_front() { diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index 3abadd7c..659a3ae6 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -43,6 +43,7 @@ ). '$submit_query_and_print_results'(Term0, VarList) :- + write('oh brother'), nl, ( expand_goals(Term0, Term) -> true ; Term0 = Term ), diff --git a/src/prolog/write.rs b/src/prolog/write.rs index dd91a4b0..e3e018c7 100644 --- a/src/prolog/write.rs +++ b/src/prolog/write.rs @@ -143,6 +143,10 @@ impl fmt::Display for HeapCellValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &HeapCellValue::Addr(ref addr) => write!(f, "{}", addr), + &HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()), + &HeapCellValue::DBRef(ref db_ref) => write!(f, "{}", db_ref), + &HeapCellValue::Integer(ref n) => write!(f, "{}", n), + &HeapCellValue::Rational(ref n) => write!(f, "{}", n), &HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!( f, "{}/{} (op, priority: {}, spec: {})", @@ -155,7 +159,10 @@ impl fmt::Display for HeapCellValue { write!(f, "{}/{}", name.as_str(), arity) } &HeapCellValue::PartialString(ref pstr) => { - write!(f, "pstr ( buf: {} )", pstr.block_as_str()) + write!(f, "pstr ( buf: 0x{:x} )", (pstr as *const _) as usize) + } + &HeapCellValue::Stream(ref stream) => { + write!(f, "$stream({})", stream.as_ptr() as usize) } } } @@ -175,15 +182,20 @@ impl fmt::Display for DBRef { impl fmt::Display for Addr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + &Addr::Char(c) => write!(f, "Addr::Char({})", c), + &Addr::CharCode(c) => write!(f, "Addr::CharCode({})", c), + &Addr::EmptyList => write!(f, "Addr::EmptyList"), + &Addr::Float(fl) => write!(f, "Addr::Float({})", fl), + &Addr::CutPoint(cp) => write!(f, "Addr::CutPoint({})", cp), &Addr::Con(ref c) => write!(f, "Addr::Con({})", c), - &Addr::DBRef(ref db_ref) => write!(f, "Addr::DBRef({})", db_ref), &Addr::Lis(l) => write!(f, "Addr::Lis({})", l), &Addr::AttrVar(h) => write!(f, "Addr::AttrVar({})", h), &Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h), &Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc), &Addr::Str(s) => write!(f, "Addr::Str({})", s), &Addr::PStrLocation(h, n) => write!(f, "Addr::PStrLocation({}, {})", h, n), - &Addr::Stream(ref stream) => write!(f, "Addr::Stream({})", stream.as_ptr() as usize), + &Addr::Stream(stream) => write!(f, "Addr::Stream({})", stream), + &Addr::Usize(cp) => write!(f, "Addr::Usize({})", cp), } } } -- 2.54.0