From: Mark Thom Date: Mon, 6 Apr 2020 02:32:16 +0000 (-0600) Subject: use fixnums in place of bignums where possible X-Git-Tag: v0.8.119~26 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=d76ae413c45ef094f87c77f792457832843cfaba;p=scryer-prolog.git use fixnums in place of bignums where possible --- diff --git a/Cargo.lock b/Cargo.lock index ea022e95..526c4fc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -444,7 +444,7 @@ dependencies = [ [[package]] name = "prolog_parser" -version = "0.8.48" +version = "0.8.49" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -580,7 +580,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.48 (registry+https://github.com/rust-lang/crates.io-index)", + "prolog_parser 0.8.49 (registry+https://github.com/rust-lang/crates.io-index)", "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 +791,7 @@ 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.48 (registry+https://github.com/rust-lang/crates.io-index)" = "301d67e5905691f8d5dc5f08c8c6e12cf849a12bea779af8b5221c35b89faf95" +"checksum prolog_parser 0.8.49 (registry+https://github.com/rust-lang/crates.io-index)" = "82f46113e58039861f82f6b6cdaca94c0997eda2c7317a4c4f13d549c4601eec" "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 b8a57623..76c6c6e2 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.48", default-features = false } +prolog_parser = { version = "0.8.49", default-features = false } ref_thread_local = "0.0.0" rug = { version = "1.4.0", optional = true } rustyline = "6.0.0" \ No newline at end of file diff --git a/src/prolog/arithmetic.rs b/src/prolog/arithmetic.rs index 3520cb1b..3b84bf30 100644 --- a/src/prolog/arithmetic.rs +++ b/src/prolog/arithmetic.rs @@ -6,6 +6,7 @@ use crate::prolog::forms::*; use crate::prolog::instructions::*; use crate::prolog::iterators::*; +use crate::prolog::machine::heap::*; use crate::prolog::machine::machine_errors::*; use crate::prolog::machine::machine_indices::*; @@ -15,6 +16,7 @@ use crate::prolog::rug::{Assign, Integer, Rational}; use std::cell::Cell; use std::cmp::{max, min, Ordering}; +use std::convert::TryFrom; use std::f64; use std::num::FpCategory; use std::ops::{Add, Div, Mul, Neg, Sub}; @@ -262,6 +264,9 @@ impl<'a> ArithmeticEvaluator<'a> { fn push_constant(&mut self, c: &Constant) -> Result<(), ArithmeticError> { match c { + &Constant::Fixnum(n) => self + .interm + .push(ArithmeticTerm::Number(Number::Fixnum(n))), &Constant::Integer(ref n) => self .interm .push(ArithmeticTerm::Number(Number::Integer(n.clone()))), @@ -316,18 +321,25 @@ impl<'a> ArithmeticEvaluator<'a> { } // integer division rounding function -- 9.1.3.1. -pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Integer> { +pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Number> { match n { - &Number::Integer(ref n) => RefOrOwned::Borrowed(n), + &Number::Integer(_) => { + RefOrOwned::Borrowed(n) + } &Number::Float(OrderedFloat(f)) => { - RefOrOwned::Owned(Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0))) + RefOrOwned::Owned(Number::from( + Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0)) + )) + } + &Number::Fixnum(n) => { + RefOrOwned::Owned(Number::from(n)) } &Number::Rational(ref r) => { let r_ref = r.fract_floor_ref(); let (mut fract, mut floor) = (Rational::new(), Integer::new()); - (&mut fract, &mut floor).assign(r_ref); - RefOrOwned::Owned(floor) + + RefOrOwned::Owned(Number::from(floor)) } } } @@ -335,6 +347,7 @@ pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Integer> { // floating point rounding function -- 9.1.4.1. pub fn rnd_f(n: &Number) -> f64 { match n { + &Number::Fixnum(n) => n as f64, &Number::Integer(ref n) => n.to_f64(), &Number::Float(OrderedFloat(f)) => f, &Number::Rational(ref r) => r.to_f64(), @@ -370,22 +383,32 @@ where } } +#[inline] +fn float_fn_to_f(n: isize) -> Result { + classify_float(n as f64, rnd_f) +} + +#[inline] fn float_i_to_f(n: &Integer) -> Result { classify_float(n.to_f64(), rnd_f) } +#[inline] fn float_r_to_f(r: &Rational) -> Result { classify_float(r.to_f64(), rnd_f) } +#[inline] fn add_f(f1: f64, f2: f64) -> Result, EvalError> { Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?)) } +#[inline] fn mul_f(f1: f64, f2: f64) -> Result, EvalError> { Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?)) } +#[inline] fn div_f(f1: f64, f2: f64) -> Result, EvalError> { if FpCategory::Zero == f2.classify() { Err(EvalError::ZeroDivisor) @@ -399,8 +422,27 @@ impl Add for Number { fn add(self, rhs: Number) -> Self::Output { match (self, rhs) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + Ok(if let Some(result) = n1.checked_add(n2) { + Number::Fixnum(result) + } else { + Number::from(Integer::from(n1) + Integer::from(n2)) + }) + } + (Number::Fixnum(n1), Number::Integer(n2)) | + (Number::Integer(n2), Number::Fixnum(n1)) => { + Ok(Number::from(Integer::from(n1) + &*n2)) + } + (Number::Fixnum(n1), Number::Rational(n2)) | + (Number::Rational(n2), Number::Fixnum(n1)) => { + Ok(Number::from(Rational::from(n1) + &*n2)) + } + (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) | + (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => { + Ok(Number::Float(add_f(float_fn_to_f(n1)?, n2)?)) + } (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::Integer(Rc::new(Integer::from(&*n1) + &*n2))) // add_i + Ok(Number::from(Integer::from(&*n1) + &*n2)) // add_i } (Number::Integer(n1), Number::Float(OrderedFloat(n2))) | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { @@ -408,7 +450,7 @@ impl Add for Number { } (Number::Integer(n1), Number::Rational(n2)) | (Number::Rational(n2), Number::Integer(n1)) => { - Ok(Number::Rational(Rc::new(Rational::from(&*n1) + &*n2))) + Ok(Number::from(Rational::from(&*n1) + &*n2)) } (Number::Rational(n1), Number::Float(OrderedFloat(n2))) | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { @@ -418,7 +460,7 @@ impl Add for Number { Ok(Number::Float(add_f(f1, f2)?)) } (Number::Rational(r1), Number::Rational(r2)) => { - Ok(Number::Rational(Rc::new(Rational::from(&*r1) + &*r2))) + Ok(Number::from(Rational::from(&*r1) + &*r2)) } } } @@ -429,6 +471,7 @@ impl Neg for Number { fn neg(self) -> Self::Output { match self { + Number::Fixnum(n) => Number::Fixnum(-n), Number::Integer(n) => Number::Integer(Rc::new(-Integer::from(&*n))), Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)), Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))), @@ -449,6 +492,25 @@ impl Mul for Number { fn mul(self, rhs: Number) -> Self::Output { match (self, rhs) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + Ok(if let Some(result) = n1.checked_mul(n2) { + Number::Fixnum(result) + } else { + Number::from(Integer::from(n1) * Integer::from(n2)) + }) + } + (Number::Fixnum(n1), Number::Integer(n2)) | + (Number::Integer(n2), Number::Fixnum(n1)) => { + Ok(Number::from(Integer::from(n1) * &*n2)) + } + (Number::Fixnum(n1), Number::Rational(n2)) | + (Number::Rational(n2), Number::Fixnum(n1)) => { + Ok(Number::from(Rational::from(n1) * &*n2)) + } + (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) | + (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => { + Ok(Number::Float(mul_f(float_fn_to_f(n1)?, n2)?)) + } (Number::Integer(n1), Number::Integer(n2)) => { Ok(Number::Integer(Rc::new(Integer::from(&*n1) * &*n2))) // mul_i } @@ -479,24 +541,72 @@ impl Div for Number { fn div(self, rhs: Number) -> Self::Output { match (self, rhs) { - (Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Float(div_f( - float_i_to_f(&n1)?, - float_i_to_f(&n2)?, - )?)), + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + Ok(Number::Float(div_f( + float_fn_to_f(n1)?, + float_fn_to_f(n2)?, + )?)) + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + Ok(Number::Float(div_f( + float_fn_to_f(n1)?, + float_i_to_f(&n2)?, + )?)) + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + Ok(Number::Float(div_f( + float_i_to_f(&n1)?, + float_fn_to_f(n2)?, + )?)) + } + (Number::Fixnum(n1), Number::Rational(n2)) => { + Ok(Number::Float(div_f( + float_fn_to_f(n1)?, + float_r_to_f(&n2)?, + )?)) + } + (Number::Rational(n1), Number::Fixnum(n2)) => { + Ok(Number::Float(div_f( + float_r_to_f(&n1)?, + float_fn_to_f(n2)?, + )?)) + } + (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) => { + Ok(Number::Float(div_f( + float_fn_to_f(n1)?, + n2, + )?)) + } + (Number::Float(OrderedFloat(n1)), Number::Fixnum(n2)) => { + Ok(Number::Float(div_f( + n1, + float_fn_to_f(n2)?, + )?)) + } + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::Float(div_f( + float_i_to_f(&n1)?, + float_i_to_f(&n2)?, + )?)) + } (Number::Integer(n1), Number::Float(OrderedFloat(n2))) => { Ok(Number::Float(div_f(float_i_to_f(&n1)?, n2)?)) } (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { Ok(Number::Float(div_f(n2, float_i_to_f(&n1)?)?)) } - (Number::Integer(n1), Number::Rational(n2)) => Ok(Number::Float(div_f( - float_i_to_f(&n1)?, - float_r_to_f(&n2)?, - )?)), - (Number::Rational(n2), Number::Integer(n1)) => Ok(Number::Float(div_f( - float_r_to_f(&n2)?, - float_i_to_f(&n1)?, - )?)), + (Number::Integer(n1), Number::Rational(n2)) => { + Ok(Number::Float(div_f( + float_i_to_f(&n1)?, + float_r_to_f(&n2)?, + )?)) + } + (Number::Rational(n2), Number::Integer(n1)) => { + Ok(Number::Float(div_f( + float_r_to_f(&n2)?, + float_i_to_f(&n1)?, + )?)) + } (Number::Rational(n1), Number::Float(OrderedFloat(n2))) => { Ok(Number::Float(div_f(float_r_to_f(&n1)?, n2)?)) } @@ -514,25 +624,47 @@ impl Div for Number { } } -impl PartialOrd for Number { - fn partial_cmp(&self, rhs: &Number) -> Option { +impl PartialEq for Number { + fn eq(&self, rhs: &Self) -> bool { match (self, rhs) { - (&Number::Integer(ref n1), &Number::Integer(ref n2)) => Some(n1.cmp(n2)), - (&Number::Integer(_), Number::Float(_)) => Some(Ordering::Greater), - (&Number::Float(_), &Number::Integer(_)) => Some(Ordering::Less), - (&Number::Integer(_), &Number::Rational(_)) => Some(Ordering::Greater), - (&Number::Rational(_), &Number::Integer(_)) => Some(Ordering::Less), - (&Number::Rational(_), Number::Float(_)) => Some(Ordering::Greater), - (&Number::Float(_), &Number::Rational(_)) => Some(Ordering::Less), - (&Number::Float(f1), &Number::Float(f2)) => Some(f1.cmp(&f2)), - (&Number::Rational(ref r1), &Number::Rational(ref r2)) => Some(r1.cmp(&r2)), + (&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2), + (&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.eq(&**n2), + (&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2), + (&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.eq(&**n2), + (&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2), + (&Number::Fixnum(_), &Number::Float(OrderedFloat(_))) => false, + (&Number::Float(OrderedFloat(_)), &Number::Fixnum(_)) => false, + (&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.eq(n2), + (&Number::Integer(_), Number::Float(_)) => false, + (&Number::Float(_), &Number::Integer(_)) => false, + (&Number::Integer(_), &Number::Rational(_)) => false, + (&Number::Rational(_), &Number::Integer(_)) => false, + (&Number::Rational(_), Number::Float(_)) => false, + (&Number::Float(_), &Number::Rational(_)) => false, + (&Number::Float(f1), &Number::Float(f2)) => f1.eq(&f2), + (&Number::Rational(ref r1), &Number::Rational(ref r2)) => r1.eq(&r2), } } } +impl Eq for Number {} + +impl PartialOrd for Number { + fn partial_cmp(&self, rhs: &Number) -> Option { + Some(self.cmp(rhs)) + } +} + impl Ord for Number { fn cmp(&self, rhs: &Number) -> Ordering { match (self, rhs) { + (&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.cmp(&n2), + (&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1).cmp(&*n2), + (Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2)), + (&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1).cmp(&*n2), + (Number::Rational(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Rational::from(n2)), + (&Number::Fixnum(_), &Number::Float(OrderedFloat(_))) => Ordering::Greater, + (&Number::Float(OrderedFloat(_)), &Number::Fixnum(_)) => Ordering::Less, (&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2), (&Number::Integer(_), Number::Float(_)) => Ordering::Greater, (&Number::Float(_), &Number::Integer(_)) => Ordering::Less, @@ -546,6 +678,78 @@ impl Ord for Number { } } +impl<'a> TryFrom<(Addr, &'a Heap)> for Number { + type Error = (); + + fn try_from((addr, heap): (Addr, &'a Heap)) -> Result { + match addr { + Addr::CharCode(c) => { + Ok(Number::from(c as isize)) + } + Addr::Fixnum(n) => { + Ok(Number::from(n)) + } + Addr::Float(n) => { + Ok(Number::Float(n)) + } + Addr::Usize(n) => { + if let Ok(n) = isize::try_from(n) { + Ok(Number::from(n)) + } else { + Ok(Number::from(Integer::from(n))) + } + } + Addr::Con(h) => { + Number::try_from(&heap[h]) + } + _ => { + Err(()) + } + } + } +} + +impl<'a> TryFrom<&'a HeapCellValue> for Number { + type Error = (); + + fn try_from(value: &'a HeapCellValue) -> Result { + match value { + HeapCellValue::Addr(addr) => { + match addr { + &Addr::CharCode(c) => { + Ok(Number::from(c as isize)) + } + &Addr::Fixnum(n) => { + Ok(Number::from(n)) + } + &Addr::Float(n) => { + Ok(Number::Float(n)) + } + &Addr::Usize(n) => { + if let Ok(n) = isize::try_from(n) { + Ok(Number::from(n)) + } else { + Ok(Number::from(Integer::from(n))) + } + } + _ => { + Err(()) + } + } + } + HeapCellValue::Integer(n) => { + Ok(Number::Integer(n.clone())) + } + HeapCellValue::Rational(n) => { + Ok(Number::Rational(n.clone())) + } + _ => { + Err(()) + } + } + } +} + // Computes n ^ power. Ignores the sign of power. pub fn binary_pow(mut n: Integer, power: &Integer) -> Integer { let mut power = Integer::from(power.abs_ref()); diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index 5068ffc2..4abdd8fd 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -159,7 +159,6 @@ pub enum SystemClauseType { AtomCodes, AtomLength, BindFromRegister, - CallAttributeGoals, CallContinuation, CharCode, CharsToNumber, @@ -179,7 +178,6 @@ pub enum SystemClauseType { EnqueueAttributedVar, ExpandGoal, ExpandTerm, - FetchAttributeGoals, FetchGlobalVar, FetchGlobalVarWithOffset, GetChar, @@ -277,7 +275,6 @@ impl SystemClauseType { &SystemClauseType::AtomCodes => clause_name!("$atom_codes"), &SystemClauseType::AtomLength => clause_name!("$atom_length"), &SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"), - &SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"), &SystemClauseType::CallContinuation => clause_name!("$call_continuation"), &SystemClauseType::CharCode => clause_name!("$char_code"), &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"), @@ -308,7 +305,6 @@ impl SystemClauseType { &SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"), &SystemClauseType::ExpandTerm => clause_name!("$expand_term"), &SystemClauseType::ExpandGoal => clause_name!("$expand_goal"), - &SystemClauseType::FetchAttributeGoals => clause_name!("$fetch_attribute_goals"), &SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"), &SystemClauseType::FetchGlobalVarWithOffset => { clause_name!("$fetch_global_var_with_offset") @@ -429,7 +425,6 @@ impl SystemClauseType { ("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack), ("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront), ("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack), - ("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals), ("$call_continuation", 1) => Some(SystemClauseType::CallContinuation), ("$char_code", 2) => Some(SystemClauseType::CharCode), ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber), @@ -456,7 +451,6 @@ impl SystemClauseType { ("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString), ("$expand_term", 2) => Some(SystemClauseType::ExpandTerm), ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal), - ("$fetch_attribute_goals", 1) => Some(SystemClauseType::FetchAttributeGoals), ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar), ("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset), ("$get_char", 1) => Some(SystemClauseType::GetChar), diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index 13cb33f8..944e1c9e 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -446,7 +446,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } }, &InlinedClauseType::IsInteger(..) => match terms[0].as_ref() { - &Term::Constant(_, Constant::Integer(_)) => { + &Term::Constant(_, Constant::Integer(_)) | + &Term::Constant(_, Constant::Fixnum(_)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -511,7 +512,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1)))) } } - &Term::Constant(_, ref c @ Constant::Integer(_)) => { + &Term::Constant(_, ref c @ Constant::Integer(_)) | + &Term::Constant(_, ref c @ Constant::Fixnum(_)) => { code.push(Line::Query(put_constant!( Level::Shallow, c.clone(), @@ -708,7 +710,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { match fact_instr { &mut FactInstruction::UnifyValue(r) => { if !safe_vars.contains(&r) { - *fact_instr = FactInstruction::UnifyLocalValue(r); + *fact_instr = FactInstruction::UnifyLocalValue(r); safe_vars.insert(r); } } diff --git a/src/prolog/forms.rs b/src/prolog/forms.rs index f26361de..ece57a04 100644 --- a/src/prolog/forms.rs +++ b/src/prolog/forms.rs @@ -12,6 +12,7 @@ use indexmap::IndexMap; use std::cell::Cell; use std::collections::VecDeque; +use std::convert::TryFrom; use std::path::PathBuf; use std::rc::Rc; @@ -573,11 +574,33 @@ pub struct Module { pub listing_src: ListingSource, } -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone)] pub enum Number { Float(OrderedFloat), Integer(Rc), Rational(Rc), + Fixnum(isize), +} + +impl From for Number { + #[inline] + fn from(n: Integer) -> Self { + Number::Integer(Rc::new(n)) + } +} + +impl From for Number { + #[inline] + fn from(n: Rational) -> Self { + Number::Rational(Rc::new(n)) + } +} + +impl From for Number { + #[inline] + fn from(n: isize) -> Self { + Number::Fixnum(n) + } } impl Default for Number { @@ -586,10 +609,23 @@ impl Default for Number { } } +impl Into for Number { + #[inline] + fn into(self) -> Constant { + match self { + Number::Fixnum(n) => Constant::Fixnum(n), + Number::Integer(n) => Constant::Integer(n), + Number::Float(f) => Constant::Float(f), + Number::Rational(r) => Constant::Rational(r), + } + } +} + impl Into for Number { #[inline] fn into(self) -> HeapCellValue { match self { + Number::Fixnum(n) => HeapCellValue::Addr(Addr::Fixnum(n)), Number::Integer(n) => HeapCellValue::Integer(n), Number::Float(f) => HeapCellValue::Addr(Addr::Float(f)), Number::Rational(r) => HeapCellValue::Rational(r), @@ -597,10 +633,27 @@ impl Into for Number { } } + impl Number { + #[inline] + pub fn to_u32(&self) -> Option { + match self { + &Number::Fixnum(n) => u32::try_from(n).ok(), + &Number::Integer(ref n) => n.to_u32(), + &Number::Float(_) => None, + &Number::Rational(ref r) => + if r.denom() == &1 { + r.numer().to_u32() + } else { + None + } + } + } + #[inline] pub fn is_positive(&self) -> bool { match self { + &Number::Fixnum(n) => n > 0, &Number::Integer(ref n) => &**n > &0, &Number::Float(OrderedFloat(f)) => f.is_sign_positive(), &Number::Rational(ref r) => &**r > &0, @@ -610,6 +663,7 @@ impl Number { #[inline] pub fn is_negative(&self) -> bool { match self { + &Number::Fixnum(n) => n < 0, &Number::Integer(ref n) => &**n < &0, &Number::Float(OrderedFloat(f)) => f.is_sign_negative(), &Number::Rational(ref r) => &**r < &0, @@ -619,6 +673,7 @@ impl Number { #[inline] pub fn is_zero(&self) -> bool { match self { + &Number::Fixnum(n) => n == 0, &Number::Integer(ref n) => &**n == &0, &Number::Float(f) => f == OrderedFloat(0f64), &Number::Rational(ref r) => &**r == &0, @@ -628,9 +683,15 @@ impl Number { #[inline] pub fn abs(self) -> Self { match self { - Number::Integer(n) => Number::Integer(Rc::new(Integer::from(n.abs_ref()))), + Number::Fixnum(n) => + if let Some(n) = n.checked_abs() { + Number::from(n) + } else { + Number::from(Integer::from(n).abs()) + } + Number::Integer(n) => Number::from(Integer::from(n.abs_ref())), Number::Float(f) => Number::Float(OrderedFloat(f.abs())), - Number::Rational(r) => Number::Rational(Rc::new(Rational::from(r.abs_ref()))), + Number::Rational(r) => Number::from(Rational::from(r.abs_ref())), } } } diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 03659752..6d252695 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -12,6 +12,7 @@ use crate::prolog::rug::Integer; use indexmap::{IndexMap, IndexSet}; use std::cell::Cell; +use std::convert::TryFrom; use std::iter::{FromIterator, once}; use std::ops::{Range, RangeFrom}; use std::rc::Rc; @@ -263,30 +264,27 @@ 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(|addr, heap| { - match addr { - Addr::Con(h) => { - match &heap[h] { - HeapCellValue::Integer(ref n) => { - &**n > &0 - } - &HeapCellValue::Rational(ref r) => { - &**r > &0 - } - _ => { - false - } + if let Some(ref op) = op { + op.is_negative_sign() && + iter.leftmost_leaf_has_property(|addr, heap| { + match Number::try_from((addr, heap)) { + Ok(Number::Fixnum(n)) => { + n > 0 + } + Ok(Number::Float(f)) => { + f > OrderedFloat(0f64) + } + Ok(Number::Integer(n)) => { + &*n > &0 + } + Ok(Number::Rational(n)) => { + &*n > &0 + } + _ => { + false } } - Addr::Float(f) => { - f > OrderedFloat(0f64) - } - _ => { - false - } - } - }) + }) } else { false } @@ -311,14 +309,19 @@ fn numbervar(n: Integer) -> Var { impl MachineState { pub fn numbervar(&self, offset: &Integer, addr: Addr) -> Option { - match self.store(self.deref(addr)) { - Addr::Con(h) => { - if let &HeapCellValue::Integer(ref n) = &self.heap[h] { - if &**n >= &0 { - Some(numbervar(Integer::from(offset + &**n))) - } else { - None - } + let addr = self.store(self.deref(addr)); + + match Number::try_from((addr, &self.heap)) { + Ok(Number::Fixnum(n)) => { + if n >= 0 { + Some(numbervar(Integer::from(offset + Integer::from(n)))) + } else { + None + } + } + Ok(Number::Integer(n)) => { + if &*n >= &0 { + Some(numbervar(Integer::from(offset + &*n))) } else { None } @@ -1336,6 +1339,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { &HeapCellValue::Addr(Addr::Float(n)) => { self.print_number(Number::Float(n), &op); } + &HeapCellValue::Addr(Addr::Fixnum(n)) => { + self.print_number(Number::Fixnum(n), &op); + } &HeapCellValue::Addr(Addr::Usize(u)) => { self.append_str(&format!("{}", u)); } diff --git a/src/prolog/indexing.rs b/src/prolog/indexing.rs index 2bcfc6c3..59e83a78 100644 --- a/src/prolog/indexing.rs +++ b/src/prolog/indexing.rs @@ -1,11 +1,13 @@ use prolog_parser::ast::*; use crate::prolog::instructions::*; +use crate::prolog::rug::Integer; use indexmap::IndexMap; use std::collections::VecDeque; use std::hash::Hash; +use std::rc::Rc; #[derive(Clone, Copy)] enum IntIndex { @@ -48,6 +50,41 @@ impl CodeOffsets { } } + fn intercept_constant(&mut self, constant: &Constant, index: usize) { + match constant { + &Constant::Atom(ref name, _) if name.is_char() => { + let c = name.as_str().chars().next().unwrap(); + let code = self.constants + .entry(Constant::Char(c)) + .or_insert(vec![]); + + code.push(Self::add_index(code.is_empty(), index)); + } + &Constant::Fixnum(n) => { + let code = self.constants + .entry(Constant::Integer(Rc::new(Integer::from(n)))) + .or_insert(vec![]); + + code.push(Self::add_index(code.is_empty(), index)); + } + &Constant::Integer(ref n) => { + if let Some(n) = n.to_isize() { + let code = self.constants + .entry(Constant::Fixnum(n)) + .or_insert(vec![]); + + code.push(Self::add_index(code.is_empty(), index)); + } + } + &Constant::String(_) => { + let is_initial_index = self.lists.is_empty(); + self.lists.push(Self::add_index(is_initial_index, index)); + } + _ => { + } + } + } + pub fn index_term(&mut self, first_arg: &Term, index: usize) { match first_arg { &Term::Clause(_, ref name, ref terms, _) => { @@ -63,29 +100,12 @@ impl CodeOffsets { let is_initial_index = self.lists.is_empty(); self.lists.push(Self::add_index(is_initial_index, index)); } - &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(s.clone()); - let code = self.constants.entry(constant).or_insert(Vec::new()); - - let is_initial_index = code.is_empty(); - code.push(Self::add_index(is_initial_index, index)); - } &Term::Constant(_, ref constant) => { - if let Constant::Atom(ref name, _) = constant { - if name.is_char() { - let c = name.as_str().chars().next().unwrap(); - let code = self.constants - .entry(Constant::Char(c)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - } - } - - let code = self.constants.entry(constant.clone()).or_insert(Vec::new()); + self.intercept_constant(constant, index); + + let code = self.constants + .entry(constant.clone()) + .or_insert(vec![]); let is_initial_index = code.is_empty(); code.push(Self::add_index(is_initial_index, index)); diff --git a/src/prolog/lib/assoc.pl b/src/prolog/lib/assoc.pl index b99b1c4b..2ebf1a8e 100644 --- a/src/prolog/lib/assoc.pl +++ b/src/prolog/lib/assoc.pl @@ -63,12 +63,12 @@ Assocs are Key-Value associations implemented as a balanced binary tree @author R.A.O'Keefe, L.Damas, V.S.Costa and Jan Wielemaker */ -/* +/* :- meta_predicate map_assoc(1, ?), map_assoc(2, ?, ?). */ - + %! empty_assoc(?Assoc) is semidet. % % Is true if Assoc is the empty association list. diff --git a/src/prolog/lib/builtins.pl b/src/prolog/lib/builtins.pl index cff33c77..61efae1c 100644 --- a/src/prolog/lib/builtins.pl +++ b/src/prolog/lib/builtins.pl @@ -1024,7 +1024,7 @@ subsumes_term(General, Specific) :- unify_with_occurs_check(X, Y) :- '$unify_with_occurs_check'(X, Y). -current_input(S) :- '$current_input'(S). +current_input(S) :- '$current_input'(S). current_output(S) :- '$current_output'(S). diff --git a/src/prolog/machine/arithmetic_ops.rs b/src/prolog/machine/arithmetic_ops.rs index cf2a3b91..29137604 100644 --- a/src/prolog/machine/arithmetic_ops.rs +++ b/src/prolog/machine/arithmetic_ops.rs @@ -10,6 +10,7 @@ use crate::prolog::ordered_float::*; use crate::prolog::rug::{Integer, Rational}; use std::cmp; +use std::convert::TryFrom; use std::f64; use std::mem; use std::rc::Rc; @@ -24,13 +25,61 @@ macro_rules! try_numeric_result { Err(e) => { let caller_copy = $caller.iter().map(|v| v.context_free_clone()).collect(); - + Err($s.error_form(MachineError::evaluation_error(e), caller_copy)) } } ); } +fn isize_gcd(n1: isize, n2: isize) -> Option { + if n1 == 0 { + return n2.checked_abs().map(|n| n as isize); + } + + if n2 == 0 { + return n1.checked_abs().map(|n| n as isize); + } + + let n1 = n1.checked_abs(); + let n2 = n2.checked_abs(); + + let mut n1 = if let Some(n1) = n1 { n1 } else { return None }; + let mut n2 = if let Some(n2) = n2 { n2 } else { return None }; + + let mut shift = 0; + + while ((n1 | n2) & 1) == 0 { + shift += 1; + n1 >>= 1; + n2 >>= 1; + } + + while (n1 & 1) == 0 { + n1 >>= 1; + } + + loop { + while (n2 & 1) == 0 { + n2 >>= 1; + } + + if n1 > n2 { + let t = n2; + n2 = n1; + n1 = t; + } + + n2 -= n1; + + if n2 == 0 { + break; + } + } + + Some(n1 << shift as isize) +} + impl MachineState { pub(crate) fn get_number(&mut self, at: &ArithmeticTerm) -> Result { @@ -40,7 +89,7 @@ impl MachineState { } &ArithmeticTerm::Interm(i) => Ok(mem::replace( &mut self.interms[i - 1], - Number::Integer(Rc::new(Integer::from(0))), + Number::Fixnum(0), )), &ArithmeticTerm::Number(ref n) => { Ok(n.clone()) @@ -54,6 +103,9 @@ impl MachineState { n: Number, ) -> Result, MachineError> { match n { + Number::Fixnum(n) => { + Ok(Rc::new(Rational::from(n))) + } Number::Rational(r) => { Ok(r) } @@ -80,7 +132,7 @@ impl MachineState { 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)) @@ -114,7 +166,7 @@ impl MachineState { 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)?)); @@ -123,19 +175,19 @@ impl MachineState { 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)?))), + "//" => interms.push(self.idiv(a1, a2)?), + "div" => interms.push(self.int_floor_div(a1, a2)?), + ">>" => interms.push(self.shr(a1, a2)?), + "<<" => interms.push(self.shl(a1, a2)?), + "/\\" => interms.push(self.and(a1, a2)?), + "\\/" => interms.push(self.or(a1, a2)?), + "xor" => interms.push(self.xor(a1, a2)?), + "mod" => interms.push(self.modulus(a1, a2)?), + "rem" => interms.push(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)?))), + "gcd" => interms.push(self.gcd(a1, a2)?), _ => { return Err(self.error_form(MachineError::instantiation_error(), caller)) } @@ -158,27 +210,30 @@ impl MachineState { "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)))), + "truncate" => interms.push(self.truncate(a1)), + "round" => interms.push(self.round(a1)?), + "ceiling" => interms.push(self.ceiling(a1)), + "floor" => interms.push(self.floor(a1)), + "\\" => interms.push(self.bitwise_complement(a1)?), + "sign" => interms.push(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::CharCode(n)) => { + interms.push(Number::Integer(Rc::new(Integer::from(n)))); + } + &HeapCellValue::Addr(Addr::Fixnum(n)) => { + interms.push(Number::Fixnum(n)); } &HeapCellValue::Addr(Addr::Float(n)) => { interms.push(Number::Float(n)) } - &HeapCellValue::Addr(Addr::Usize(n)) => { - interms.push(Number::Integer(Rc::new(Integer::from(n)))); + &HeapCellValue::Integer(ref n) => { + interms.push(Number::Integer(n.clone())) } - &HeapCellValue::Addr(Addr::CharCode(n)) => { + &HeapCellValue::Addr(Addr::Usize(n)) => { interms.push(Number::Integer(Rc::new(Integer::from(n)))); } &HeapCellValue::Rational(ref n) => { @@ -210,9 +265,11 @@ impl MachineState { } pub(crate) - fn int_floor_div(&self, n1: Number, n2: Number) -> Result { + fn int_floor_div(&self, n1: Number, n2: Number) -> Result { match n1 / n2 { - Ok(result) => Ok(rnd_i(&result).to_owned()), + Ok(result) => { + Ok(rnd_i(&result).to_owned()) + } Err(e) => { let stub = MachineError::functor_stub(clause_name!("(div)"), 2); Err(self.error_form( @@ -226,8 +283,57 @@ impl MachineState { } pub(crate) - fn idiv(&self, n1: Number, n2: Number) -> Result { + fn idiv(&self, n1: Number, n2: Number) -> Result { match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if n2 == 0 { + let stub = MachineError::functor_stub(clause_name!("(//)"), 2); + + Err(self.error_form( + MachineError::evaluation_error( + EvalError::ZeroDivisor + ), + stub, + )) + } else { + if let Some(result) = n1.checked_div(n2) { + Ok(Number::from(result)) + } else { + let n1 = Integer::from(n1); + let n2 = Integer::from(n2); + + Ok(Number::from(n1 / n2)) + } + } + } + (Number::Fixnum(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(Number::from(Integer::from(n1) / &*n2)) + } + } + (Number::Integer(n2), Number::Fixnum(n1)) => { + if n1 == 0 { + let stub = MachineError::functor_stub(clause_name!("(//)"), 2); + + Err(self.error_form( + MachineError::evaluation_error( + EvalError::ZeroDivisor + ), + stub, + )) + } else { + Ok(Number::from(&*n2 / Integer::from(n1))) + } + } (Number::Integer(n1), Number::Integer(n2)) => { if &*n2 == &0 { let stub = MachineError::functor_stub(clause_name!("(//)"), 2); @@ -239,10 +345,10 @@ impl MachineState { stub, )) } else { - Ok(<(Integer, Integer)>::from(n1.div_rem_ref(&*n2)).0) + Ok(Number::from(<(Integer, Integer)>::from(n1.div_rem_ref(&*n2)).0)) } } - (Number::Integer(_), n2) => { + (Number::Fixnum(_), n2) | (Number::Integer(_), n2) => { let stub = MachineError::functor_stub(clause_name!("(//)"), 2); Err(self.error_form( @@ -302,6 +408,68 @@ impl MachineState { } match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if n1 != 1 && n2 < 0 { + let n = Number::from(n1); + let stub = MachineError::functor_stub(clause_name!("^"), 2); + + Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Float, + n + ), + stub, + )) + } else { + if let Ok(n2) = u32::try_from(n2) { + if let Some(result) = n1.checked_pow(n2) { + return Ok(Number::from(result)); + } + } + + let n1 = Integer::from(n1); + let n2 = Integer::from(n2); + + Ok(Number::from(binary_pow(n1, &n2))) + } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + if n1 != 1 && &*n2 < &0 { + let n = Number::from(n1); + let stub = MachineError::functor_stub(clause_name!("^"), 2); + + Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Float, + n + ), + stub, + )) + } else { + let n1 = Integer::from(n1); + Ok(Number::from(binary_pow(n1, n2.as_ref()))) + } + } + (Number::Integer(n1), Number::Fixnum(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 { + let n2 = Integer::from(n2); + Ok(Number::from(binary_pow(n1.as_ref().clone(), &n2))) + } + } (Number::Integer(n1), Number::Integer(n2)) => { if &*n1 != &1 && &*n2 < &0 { let n = Number::Integer(n1); @@ -316,7 +484,7 @@ impl MachineState { stub, )) } else { - Ok(Number::Integer(Rc::new(binary_pow(n1.as_ref().clone(), n2.as_ref())))) + Ok(Number::from(binary_pow(n1.as_ref().clone(), n2.as_ref()))) } } (n1, Number::Integer(n2)) => { @@ -344,10 +512,22 @@ impl MachineState { } pub(crate) - fn gcd(&self, n1: Number, n2: Number) -> Result { + fn gcd(&self, n1: Number, n2: Number) -> Result { match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if let Some(result) = isize_gcd(n1, n2) { + Ok(Number::Fixnum(result)) + } else { + Ok(Number::from(Integer::from(n1).gcd(&Integer::from(n2)))) + } + } + (Number::Fixnum(n1), Number::Integer(n2)) | + (Number::Integer(n2), Number::Fixnum(n1)) => { + let n1 = Integer::from(n1); + Ok(Number::from(Integer::from(n2.gcd_ref(&n1)))) + } (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Integer::from(n1.gcd_ref(&n2))) + Ok(Number::from(Integer::from(n1.gcd_ref(&n2)))) } (Number::Float(f), _) | (_, Number::Float(f)) => { let n = Number::Float(f); @@ -403,8 +583,28 @@ impl MachineState { } match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if let Ok(n2) = u32::try_from(n2) { + if let Some(result) = n1.checked_pow(n2) { + return Ok(Number::from(result)); + } + } + + let n1 = Integer::from(n1); + let n2 = Integer::from(n2); + + Ok(Number::from(binary_pow(n1, &n2))) + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1); + Ok(Number::from(binary_pow(n1, n2.as_ref()))) + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + let n2 = Integer::from(n2); + Ok(Number::from(binary_pow(n1.as_ref().clone(), &n2))) + } (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::Integer(Rc::new(binary_pow(n1.as_ref().clone(), &*n2)))) + Ok(Number::from(binary_pow(n1.as_ref().clone(), &*n2))) } (n1, n2) => { self.float_pow(n1, n2) @@ -412,6 +612,7 @@ impl MachineState { } } + #[inline] pub(crate) fn unary_float_fn_template(&self, n1: Number, f: FloatFn) -> Result where @@ -425,46 +626,55 @@ impl MachineState { try_numeric_result!(self, f1, stub) } + #[inline] pub(crate) fn sin(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.sin()) } + #[inline] pub(crate) fn cos(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.cos()) } + #[inline] pub(crate) fn tan(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.tan()) } + #[inline] pub(crate) fn log(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.log(f64::consts::E)) } + #[inline] pub(crate) fn exp(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.exp()) } + #[inline] pub(crate) fn asin(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.asin()) } + #[inline] pub(crate) fn acos(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.acos()) } + #[inline] pub(crate) fn atan(&self, n1: Number) -> Result { self.unary_float_fn_template(n1, |f| f.atan()) } + #[inline] pub(crate) fn sqrt(&self, n1: Number) -> Result { if n1.is_negative() { @@ -475,24 +685,28 @@ impl MachineState { self.unary_float_fn_template(n1, |f| f.sqrt()) } + #[inline] 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) } + #[inline] pub(crate) - fn floor(&self, n1: Number) -> Integer { + fn floor(&self, n1: Number) -> Number { rnd_i(&n1).to_owned() } + #[inline] pub(crate) - fn ceiling(&self, n1: Number) -> Integer { + fn ceiling(&self, n1: Number) -> Number { -self.floor(-n1) } + #[inline] pub(crate) - fn truncate(&self, n: Number) -> Integer { + fn truncate(&self, n: Number) -> Number { if n.is_negative() { -self.floor(n.abs()) } else { @@ -501,7 +715,7 @@ impl MachineState { } pub(crate) - fn round(&self, n: Number) -> Result { + fn round(&self, n: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(is)"), 2); let result = n + Number::Float(OrderedFloat(0.5f64)); @@ -511,14 +725,43 @@ impl MachineState { } pub(crate) - fn shr(&self, n1: Number, n2: Number) -> Result { + fn shr(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(>>)"), 2); match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if let Ok(n2) = u32::try_from(n2) { + if let Some(result) = n1.checked_shr(n2) { + return Ok(Number::from(result)); + } + } + + let n1 = Integer::from(n1); + let n2 = Integer::from(n2); + + match n2.to_u32() { + Some(n2) => Ok(Number::from(n1 >> n2)), + _ => Ok(Number::from(n1 >> u32::max_value())), + } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1); + + match n2.to_u32() { + Some(n2) => Ok(Number::from(n1 >> n2)), + _ => Ok(Number::from(n1 >> u32::max_value())), + } + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + match u32::try_from(n2) { + Ok(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))), + _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))), + } + } (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { - Some(n2) => Ok(Integer::from(&*n1 >> n2)), - _ => Ok(Integer::from(&*n1 >> u32::max_value())), + Some(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))), + _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))), }, (Number::Integer(_), n2) => Err(self.error_form( MachineError::type_error( @@ -540,13 +783,42 @@ impl MachineState { } pub(crate) - fn shl(&self, n1: Number, n2: Number) -> Result { + fn shl(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(<<)"), 2); match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if let Ok(n2) = u32::try_from(n2) { + if let Some(result) = n1.checked_shl(n2) { + return Ok(Number::from(result)); + } + } + + let n1 = Integer::from(n1); + let n2 = Integer::from(n2); + + match n2.to_u32() { + Some(n2) => Ok(Number::from(n1 << n2)), + _ => Ok(Number::from(n1 << u32::max_value())), + } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1); + + match n2.to_u32() { + Some(n2) => Ok(Number::from(n1 << n2)), + _ => Ok(Number::from(n1 << u32::max_value())), + } + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + match u32::try_from(n2) { + Ok(n2) => Ok(Number::from(Integer::from(&*n1 << n2))), + _ => Ok(Number::from(Integer::from(&*n1 << u32::max_value()))), + } + } (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { - Some(n2) => Ok(Integer::from(&*n1 << n2)), - _ => Ok(Integer::from(&*n1 << u32::max_value())), + Some(n2) => Ok(Number::from(Integer::from(&*n1 << n2))), + _ => Ok(Number::from(Integer::from(&*n1 << u32::max_value()))), }, (Number::Integer(_), n2) => Err(self.error_form( MachineError::type_error( @@ -568,11 +840,12 @@ impl MachineState { } pub(crate) - fn bitwise_complement(&self, n1: Number) -> Result { + fn bitwise_complement(&self, n1: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(\\)"), 2); match n1 { - Number::Integer(n1) => Ok(Integer::from(!&*n1)), + Number::Fixnum(n) => Ok(Number::Fixnum(!n)), + Number::Integer(n1) => Ok(Number::from(Integer::from(!&*n1))), _ => Err(self.error_form( MachineError::type_error( self.heap.h(), @@ -585,14 +858,24 @@ impl MachineState { } pub(crate) - fn xor(&self, n1: Number, n2: Number) -> Result { + fn xor(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(xor)"), 2); match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + Ok(Number::from(n1 ^ n2)) + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1); + Ok(Number::from(n1 ^ &*n2)) + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + Ok(Number::from(&*n1 ^ Integer::from(n2))) + } (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Integer::from(&*n1 ^ &*n2)) + Ok(Number::from(Integer::from(&*n1 ^ &*n2))) } - (Number::Integer(_), n2) => { + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { Err(self.error_form( MachineError::type_error( self.heap.h(), @@ -616,19 +899,33 @@ impl MachineState { } pub(crate) - fn and(&self, n1: Number, n2: Number) -> Result { + 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, - )), + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + Ok(Number::from(n1 & n2)) + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1); + Ok(Number::from(n1 & &*n2)) + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + Ok(Number::from(&*n1 & Integer::from(n2))) + } + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::from(Integer::from(&*n1 & &*n2))) + } + (Number::Integer(_), n2) | (Number::Fixnum(_), 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(), @@ -641,10 +938,83 @@ impl MachineState { } pub(crate) - fn modulus(&self, x: Number, y: Number) -> Result { + fn or(&self, n1: Number, n2: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(\\/)"), 2); + + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + Ok(Number::from(n1 | n2)) + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1); + Ok(Number::from(n1 | &*n2)) + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + Ok(Number::from(&*n1 | Integer::from(n2))) + } + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::from(Integer::from(&*n1 | &*n2))) + } + (Number::Integer(_), n2) | (Number::Fixnum(_), 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::Fixnum(n1), Number::Fixnum(n2)) => { + if n2 == 0 { + Err(self.error_form( + MachineError::evaluation_error(EvalError::ZeroDivisor), + stub, + )) + } else { + Ok(Number::from(n1 % n2)) + } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(self.error_form( + MachineError::evaluation_error(EvalError::ZeroDivisor), + stub, + )) + } else { + let n1 = Integer::from(n1); + Ok(Number::from(<(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).1)) + } + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + if n2 == 0 { + Err(self.error_form( + MachineError::evaluation_error(EvalError::ZeroDivisor), + stub, + )) + } else { + let n2 = Integer::from(n2); + Ok(Number::from(<(Integer, Integer)>::from(n1.div_rem_floor_ref(&n2)).1)) + } + } (Number::Integer(x), Number::Integer(y)) => { if &*y == &0 { Err(self.error_form( @@ -652,17 +1022,87 @@ impl MachineState { stub, )) } else { - Ok(<(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1) + Ok(Number::from(<(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1)) } } - (Number::Integer(_), n2) => Err(self.error_form( + (Number::Integer(_), n2) | (Number::Fixnum(_), 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, - n2, + n1, ), stub, )), + } + } + + pub(crate) + fn remainder(&self, n1: Number, n2: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(rem)"), 2); + + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if n2 == 0 { + Err(self.error_form( + MachineError::evaluation_error(EvalError::ZeroDivisor), + stub, + )) + } else { + Ok(Number::from(n1 % n2)) + } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(self.error_form( + MachineError::evaluation_error(EvalError::ZeroDivisor), + stub, + )) + } else { + let n1 = Integer::from(n1); + Ok(Number::from(n1 % &*n2)) + } + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + if n2 == 0 { + Err(self.error_form( + MachineError::evaluation_error(EvalError::ZeroDivisor), + stub, + )) + } else { + let n2 = Integer::from(n2); + Ok(Number::from(&*n1 % n2)) + } + } + (Number::Integer(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(self.error_form( + MachineError::evaluation_error(EvalError::ZeroDivisor), + stub, + )) + } else { + Ok(Number::from(Integer::from(&*n1 % &*n2))) + } + } + (Number::Integer(_), n2) | (Number::Fixnum(_), 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(), @@ -677,6 +1117,27 @@ impl MachineState { pub(crate) fn max(&self, n1: Number, n2: Number) -> Result { match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if n1 > n2 { + Ok(Number::Fixnum(n1)) + } else { + Ok(Number::Fixnum(n2)) + } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 > &n1 { + Ok(Number::Integer(n2)) + } else { + Ok(Number::Fixnum(n1)) + } + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + if &*n1 > &n2 { + Ok(Number::Integer(n1)) + } else { + Ok(Number::Fixnum(n2)) + } + } (Number::Integer(n1), Number::Integer(n2)) => { if n1 > n2 { Ok(Number::Integer(n1)) @@ -698,6 +1159,27 @@ impl MachineState { pub(crate) fn min(&self, n1: Number, n2: Number) -> Result { match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if n1 < n2 { + Ok(Number::Fixnum(n1)) + } else { + Ok(Number::Fixnum(n2)) + } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 < &n1 { + Ok(Number::Integer(n2)) + } else { + Ok(Number::Fixnum(n1)) + } + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + if &*n1 < &n2 { + Ok(Number::Integer(n1)) + } else { + Ok(Number::Fixnum(n2)) + } + } (Number::Integer(n1), Number::Integer(n2)) => { if n1 < n2 { Ok(Number::Integer(n1)) @@ -717,76 +1199,13 @@ impl MachineState { } pub(crate) - fn sign(&self, n: Number) -> Integer { + fn sign(&self, n: Number) -> Number { if n.is_positive() { - Integer::from(1) + Number::from(1) } else if n.is_negative() { - Integer::from(-1) + Number::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, - )) - } + Number::from(0) } } } diff --git a/src/prolog/machine/dynamic_database.rs b/src/prolog/machine/dynamic_database.rs index a4862771..7fd0a8c1 100644 --- a/src/prolog/machine/dynamic_database.rs +++ b/src/prolog/machine/dynamic_database.rs @@ -6,6 +6,8 @@ use crate::prolog::machine::compile::*; use crate::prolog::machine::machine_errors::*; use crate::prolog::machine::streams::*; +use std::convert::TryFrom; + impl Machine { pub(super) fn atom_tbl_of(&self, name: &ClauseName) -> TabledData { match name { @@ -52,10 +54,16 @@ impl Machine { let arity = match self.machine_st.store(self.machine_st.deref(arity)) { Addr::Con(h) => { - if let HeapCellValue::Integer(ref arity) = &self.machine_st.heap[h] { - arity.to_usize().unwrap() - } else { - unreachable!() + match &self.machine_st.heap[h] { + HeapCellValue::Integer(ref arity) => { + arity.to_usize().unwrap() + } + HeapCellValue::Addr(Addr::Fixnum(arity)) => { + usize::try_from(*arity).unwrap() + } + _ => { + unreachable!() + } } } Addr::Usize(n) => { @@ -102,12 +110,12 @@ impl Machine { } } } - + fn abolish_dynamic_clause(&mut self, name: RegType, arity: RegType) { 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); } @@ -155,7 +163,7 @@ impl Machine { name, arity, ); - + self.machine_st = machine_st; if let EvalSession::Error(err) = result { @@ -239,11 +247,17 @@ impl Machine { let index = self.machine_st[temp_v!(3)].clone(); let index = match self.machine_st.store(self.machine_st.deref(index)) { Addr::Con(h) => - if let HeapCellValue::Integer(ref n) = &self.machine_st.heap[h] { - n.to_usize().unwrap() - } else { - unreachable!() - }, + match &self.machine_st.heap[h] { + HeapCellValue::Integer(ref arity) => { + arity.to_usize().unwrap() + } + HeapCellValue::Addr(Addr::Fixnum(arity)) => { + usize::try_from(*arity).unwrap() + } + _ => { + unreachable!() + } + } _ => unreachable!(), }; @@ -260,7 +274,7 @@ impl Machine { if addrs.is_empty() { self.make_undefined(name.clone(), arity); } - + self.print_new_dynamic_clause(addrs, name.clone(), arity) } Err(err) => { @@ -280,12 +294,19 @@ 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(h) => - if let HeapCellValue::Integer(n) = &self.machine_st.heap[h] { - n.to_usize().unwrap() - } else { - unreachable!() - }, + Addr::Con(h) => { + match &self.machine_st.heap[h] { + HeapCellValue::Integer(ref arity) => { + arity.to_usize().unwrap() + } + HeapCellValue::Addr(Addr::Fixnum(arity)) => { + usize::try_from(*arity).unwrap() + } + _ => { + unreachable!() + } + } + } _ => { unreachable!() } @@ -302,7 +323,7 @@ impl Machine { if addrs.is_empty() { self.make_undefined(name.clone(), arity); } - + self.print_new_dynamic_clause(addrs, name.clone(), arity) } Err(err) => { diff --git a/src/prolog/machine/heap.rs b/src/prolog/machine/heap.rs index f979d38a..3eeb4853 100644 --- a/src/prolog/machine/heap.rs +++ b/src/prolog/machine/heap.rs @@ -6,6 +6,7 @@ use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::partial_string::*; use crate::prolog::machine::raw_block::*; +use std::convert::TryFrom; use std::mem; use std::ops::{Index, IndexMut}; use std::ptr; @@ -202,6 +203,9 @@ impl HeapTemplate { Constant::EmptyList => { Addr::EmptyList } + Constant::Fixnum(n) => { + Addr::Fixnum(n) + } Constant::Integer(n) => { Addr::Con(self.push(HeapCellValue::Integer(n))) } @@ -252,26 +256,6 @@ impl HeapTemplate { 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 { @@ -475,6 +459,7 @@ impl HeapTemplate { fn to_local_code_ptr(&self, addr: &Addr) -> Option { let extract_integer = |s: usize| -> Option { match &self[s] { + &HeapCellValue::Addr(Addr::Fixnum(n)) => usize::try_from(n).ok(), &HeapCellValue::Integer(ref n) => n.to_usize(), _ => None } diff --git a/src/prolog/machine/machine_indices.rs b/src/prolog/machine/machine_indices.rs index c5fc505a..5718fddd 100644 --- a/src/prolog/machine/machine_indices.rs +++ b/src/prolog/machine/machine_indices.rs @@ -20,6 +20,7 @@ use indexmap::IndexMap; use std::cell::RefCell; use std::cmp::Ordering; use std::collections::{BTreeMap, VecDeque}; +use std::convert::TryFrom; use std::mem; use std::ops::{Add, AddAssign, Sub, SubAssign}; use std::rc::Rc; @@ -59,6 +60,7 @@ pub enum Addr { Con(usize), CutPoint(usize), EmptyList, + Fixnum(isize), Float(OrderedFloat), Lis(usize), HeapCell(usize), @@ -155,8 +157,9 @@ impl Addr { #[inline] pub fn is_heap_bound(&self) -> bool { match self { - Addr::Char(_) | Addr::CharCode(_) | Addr::EmptyList - | Addr::CutPoint(_) | Addr::Usize(_) | Addr::Float(_) => { + Addr::Char(_) | Addr::CharCode(_) | Addr::EmptyList | + Addr::CutPoint(_) | Addr::Usize(_) | Addr::Fixnum(_) | + Addr::Float(_) => { false } _ => { @@ -189,44 +192,48 @@ impl Addr { pub(super) fn order_category(&self, heap: &Heap) -> Option { - match self { - Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => { - Some(TermOrderCategory::Variable) + match Number::try_from((*self, heap)) { + Ok(Number::Integer(_)) | Ok(Number::Fixnum(_)) | Ok(Number::Rational(_)) => { + Some(TermOrderCategory::Integer) } - Addr::Float(_) => { + Ok(Number::Float(_)) => { Some(TermOrderCategory::FloatingPoint) } - &Addr::Con(h) => { - match &heap[h] { - HeapCellValue::Atom(..) => { + _ => { + 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::DBRef(_) => { + None + } + _ => { + unreachable!() + } + } + } + Addr::Char(_) | Addr::EmptyList => { Some(TermOrderCategory::Atom) } - HeapCellValue::Integer(_) => { + Addr::CharCode(_) | Addr::Fixnum(_) | Addr::Usize(_) => { Some(TermOrderCategory::Integer) } - HeapCellValue::Rational(_) => { - Some(TermOrderCategory::Integer) + Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => { + Some(TermOrderCategory::Compound) } - HeapCellValue::DBRef(_) => { + Addr::CutPoint(_) | Addr::Stream(_) => { None } - _ => { - unreachable!() - } } } - Addr::Char(_) | Addr::EmptyList => { - Some(TermOrderCategory::Atom) - } - Addr::Usize(_) | Addr::CharCode(_) => { - Some(TermOrderCategory::Integer) - } - Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => { - Some(TermOrderCategory::Compound) - } - Addr::CutPoint(_) | Addr::Stream(_) => { - None - } } } @@ -257,13 +264,16 @@ impl Addr { &Addr::EmptyList => { Some(Constant::EmptyList) } + &Addr::Fixnum(n) => { + Some(Constant::Fixnum(n)) + } &Addr::Float(f) => { Some(Constant::Float(f)) } &Addr::PStrLocation(h, n) => { let mut heap_pstr_iter = machine_st.heap_pstr_iter(Addr::PStrLocation(h, n)); - + let mut buf = String::new(); while let Some(Some(c)) = heap_pstr_iter.next() { diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index f5077d9d..9ab9002f 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -56,7 +56,7 @@ impl<'a> Iterator for HeapPStrIter<'a> { } else { return None; } - + match addr { Addr::PStrLocation(h, n) => { if let &HeapCellValue::PartialString(ref pstr, _) = &self.machine_st.heap[h] { @@ -72,7 +72,7 @@ impl<'a> Iterator for HeapPStrIter<'a> { } Addr::Lis(l) => { let addr = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(l))); - + if let Addr::Char(c) = addr { self.focus = Addr::HeapCell(l + 1); return Some(Some(c)); @@ -96,7 +96,7 @@ pub(super) fn compare_pstr<'a>( pstr_iter: HeapPStrIter<'a>, mut c_iter: impl Iterator, -) -> bool { +) -> bool { for opt_c in pstr_iter { match opt_c { Some(_) => { @@ -965,7 +965,7 @@ pub(crate) trait CallPolicy: Any { let a1 = machine_st[r]; let n2 = machine_st.get_number(at)?; - let n2 = Addr::Con(machine_st.heap.push(n2.into())); + let n2 = machine_st.heap.put_constant(n2.into()); machine_st.unify(a1, n2); return_from_clause!(machine_st.last_call, machine_st) diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index b7c56b78..120e39f8 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -21,6 +21,7 @@ use crate::prolog::rug::Integer; use indexmap::{IndexMap, IndexSet}; use std::cmp::Ordering; +use std::convert::TryFrom; use std::rc::Rc; macro_rules! try_or_fail { @@ -261,8 +262,8 @@ impl MachineState { self.fail = true; } - (Addr::PStrLocation(h, n), Addr::Lis(l)) - | (Addr::Lis(l), Addr::PStrLocation(h, n)) => { + (Addr::PStrLocation(h, n), Addr::Lis(l)) | + (Addr::Lis(l), Addr::PStrLocation(h, n)) => { 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())); @@ -369,16 +370,17 @@ impl MachineState { ) if db_ref_1 == db_ref_2 => { } ( - &HeapCellValue::Integer(ref n1), - &HeapCellValue::Integer(ref n2), - ) if &**n1 == &**n2 => { - } - ( - &HeapCellValue::Rational(ref n1), - &HeapCellValue::Rational(ref n2), - ) if &**n1 == &**n2 => { - } - _ => { + v1, + v2, + ) => { + if let Ok(n1) = Number::try_from(v1) { + if let Ok(n2) = Number::try_from(v2) { + if n1 == n2 { + continue; + } + } + } + self.fail = true; } } @@ -397,10 +399,15 @@ impl MachineState { } } } - (Addr::Usize(n1), Addr::Con(n2)) | (Addr::Con(n2), Addr::Usize(n1)) => { - if let HeapCellValue::Integer(ref n2) = &self.heap[n2] { - if let Some(n2) = n2.to_usize() { - if n1 == n2 { + (Addr::Stream(s1), Addr::Stream(s2)) => { + if s1 != s2 { + self.fail = true; + } + } + (v, Addr::Con(h)) | (Addr::Con(h), v) => { + if let Ok(n1) = Number::try_from(&self.heap[h]) { + if let Ok(v) = Number::try_from(&HeapCellValue::Addr(v)) { + if n1 == v { continue; } } @@ -408,23 +415,15 @@ impl MachineState { self.fail = true; } - (Addr::CharCode(n1), Addr::Con(n2)) | (Addr::Con(n2), Addr::CharCode(n1)) => { - if let HeapCellValue::Integer(ref n2) = &self.heap[n2] { - if let Some(n2) = n2.to_u32() { + (a1, a2) => { + if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(a1)) { + if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(a2)) { if n1 == n2 { continue; } } } - self.fail = true; - } - (Addr::Stream(s1), Addr::Stream(s2)) => { - if s1 != s2 { - self.fail = true; - } - } - (a1, a2) => { if a1 != a2 { self.fail = true; } @@ -481,8 +480,8 @@ impl MachineState { self.fail = true; } - (Addr::PStrLocation(h, n), Addr::Lis(l)) - | (Addr::Lis(l), Addr::PStrLocation(h, n)) => { + (Addr::PStrLocation(h, n), Addr::Lis(l)) | + (Addr::Lis(l), Addr::PStrLocation(h, n)) => { 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())); @@ -585,16 +584,17 @@ impl MachineState { ) if db_ref_1 == db_ref_2 => { } ( - &HeapCellValue::Integer(ref n1), - &HeapCellValue::Integer(ref n2), - ) if &**n1 == &**n2 => { - } - ( - &HeapCellValue::Rational(ref n1), - &HeapCellValue::Rational(ref n2), - ) if &**n1 == &**n2 => { - } - _ => { + v1, + v2, + ) => { + if let Ok(n1) = Number::try_from(v1) { + if let Ok(n2) = Number::try_from(v2) { + if n1 == n2 { + continue; + } + } + } + self.fail = true; } } @@ -613,10 +613,15 @@ impl MachineState { } } } - (Addr::Usize(n1), Addr::Con(n2)) | (Addr::Con(n2), Addr::Usize(n1)) => { - if let HeapCellValue::Integer(ref n2) = &self.heap[n2] { - if let Some(n2) = n2.to_usize() { - if n1 == n2 { + (Addr::Stream(s1), Addr::Stream(s2)) => { + if s1 != s2 { + self.fail = true; + } + } + (v, Addr::Con(h)) | (Addr::Con(h), v) => { + if let Ok(n1) = Number::try_from(&self.heap[h]) { + if let Ok(v) = Number::try_from(&HeapCellValue::Addr(v)) { + if n1 == v { continue; } } @@ -624,23 +629,15 @@ impl MachineState { self.fail = true; } - (Addr::CharCode(n1), Addr::Con(n2)) | (Addr::Con(n2), Addr::CharCode(n1)) => { - if let HeapCellValue::Integer(ref n2) = &self.heap[n2] { - if let Some(n2) = n2.to_u32() { + (a1, a2) => { + if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(a1)) { + if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(a2)) { if n1 == n2 { continue; } } } - self.fail = true; - } - (Addr::Stream(s1), Addr::Stream(s2)) => { - if s1 != s2 { - self.fail = true; - } - } - (a1, a2) => { if a1 != a2 { self.fail = true; } @@ -791,6 +788,9 @@ impl MachineState { } HeapCellValue::Integer(ref n1) => { match c { + Constant::Fixnum(n2) => { + n1.to_isize() != Some(*n2) + } Constant::Integer(ref n2) => { n1 != n2 } @@ -919,8 +919,7 @@ 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(Rc::new(try_or_fail!(self, self.gcd(n1, n2)))); + self.interms[t - 1] = try_or_fail!(self, self.gcd(n1, n2)); self.p += 1; } &ArithmeticInstruction::Pow(ref a1, ref a2, t) => { @@ -944,16 +943,14 @@ 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(Rc::new(try_or_fail!(self, self.int_floor_div(n1, n2)))); + self.interms[t - 1] = 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(Rc::new(try_or_fail!(self, self.idiv(n1, n2)))); + self.interms[t - 1] = try_or_fail!(self, self.idiv(n1, n2)); self.p += 1; } &ArithmeticInstruction::Abs(ref a1, t) => { @@ -965,7 +962,7 @@ impl MachineState { &ArithmeticInstruction::Sign(ref a1, t) => { let n = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Integer(Rc::new(self.sign(n))); + self.interms[t - 1] = self.sign(n); self.p += 1; } &ArithmeticInstruction::Neg(ref a1, t) => { @@ -977,8 +974,7 @@ impl MachineState { &ArithmeticInstruction::BitwiseComplement(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = - Number::Integer(Rc::new(try_or_fail!(self, self.bitwise_complement(n1)))); + self.interms[t - 1] = try_or_fail!(self, self.bitwise_complement(n1)); self.p += 1; } &ArithmeticInstruction::Div(ref a1, ref a2, t) => { @@ -992,56 +988,49 @@ 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(Rc::new(try_or_fail!(self, self.shr(n1, n2)))); + self.interms[t - 1] = 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(Rc::new(try_or_fail!(self, self.shl(n1, n2)))); + self.interms[t - 1] = 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(Rc::new(try_or_fail!(self, self.xor(n1, n2)))); + self.interms[t - 1] = 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(Rc::new(try_or_fail!(self, self.and(n1, n2)))); + self.interms[t - 1] = 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(Rc::new(try_or_fail!(self, self.or(n1, n2)))); + self.interms[t - 1] = 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(Rc::new(try_or_fail!(self, self.modulus(n1, n2)))); + self.interms[t - 1] = 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(Rc::new(try_or_fail!(self, self.remainder(n1, n2)))); + self.interms[t - 1] = try_or_fail!(self, self.remainder(n1, n2)); self.p += 1; } &ArithmeticInstruction::Cos(ref a1, t) => { @@ -1120,29 +1109,25 @@ impl MachineState { &ArithmeticInstruction::Truncate(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = - Number::Integer(Rc::new(self.truncate(n1))); + self.interms[t - 1] = 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(Rc::new(try_or_fail!(self, self.round(n1)))); + self.interms[t - 1] = 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(Rc::new(self.ceiling(n1))); + self.interms[t - 1] = 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(Rc::new(self.floor(n1))); + self.interms[t - 1] = self.floor(n1); self.p += 1; } &ArithmeticInstruction::Plus(ref a1, t) => { @@ -1332,7 +1317,7 @@ impl MachineState { } } Addr::Char(_) | Addr::CharCode(_) | Addr::Con(_) | Addr::CutPoint(_) | - Addr::EmptyList | Addr::Float(_) | Addr::Usize(_) => { + Addr::EmptyList | Addr::Fixnum(_) | Addr::Float(_) | Addr::Usize(_) => { c } Addr::Lis(_) => { @@ -1624,19 +1609,35 @@ impl MachineState { Addr::HeapCell(_) | Addr::StackCell(..) => { // 8.5.2.3 a) return Err(self.error_form(MachineError::instantiation_error(), 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, - ); + addr => { + let n = + match Number::try_from((addr, &self.heap)) { + Ok(Number::Fixnum(n)) => Integer::from(n), + Ok(Number::Integer(n)) => Integer::from(n.as_ref()), + _ => { + return Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + addr, + ), + stub, + )); + } + }; - return Err(self.error_form(dom_err, stub)); - } + if n < 0 { // 8.5.2.3 e) + let n = Number::from(n); + let dom_err = MachineError::domain_error( + DomainErrorType::NotLessThanZero, + n, + ); - let n = match n.to_usize() { + return Err(self.error_form(dom_err, stub)); + } + + let n = + match n.to_usize() { Some(n) => n, None => { self.fail = true; @@ -1644,88 +1645,68 @@ impl MachineState { } }; - let term = self.store(self.deref(self[temp_v!(2)])); + let term = self.store(self.deref(self[temp_v!(2)])); - 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.clone(o) { - HeapCellValue::NamedStr(arity, _, _) if 1 <= n && n <= arity => { - let a3 = self[temp_v!(3)]; - let h_a = Addr::HeapCell(o + n); + match term { + Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(_) => { // 8.5.2.3 b) + return Err(self.error_form(MachineError::instantiation_error(), stub)) + } + Addr::Str(o) => match self.heap.clone(o) { + HeapCellValue::NamedStr(arity, _, _) if 1 <= n && n <= arity => { + let a3 = self[temp_v!(3)]; + let h_a = Addr::HeapCell(o + n); - self.unify(a3, h_a); - } - _ => { - self.fail = true; - } - }, - Addr::Lis(l) => { - if n == 1 || n == 2 { - let a3 = self[temp_v!(3)]; - let h_a = Addr::HeapCell(l + n - 1); + self.unify(a3, h_a); + } + _ => { + self.fail = true; + } + }, + Addr::Lis(l) => { + if n == 1 || n == 2 { + let a3 = self[temp_v!(3)]; + let h_a = Addr::HeapCell(l + n - 1); - self.unify(a3, h_a); - } else { - self.fail = true; - } + self.unify(a3, h_a); + } else { + self.fail = true; } - Addr::PStrLocation(h, offset) => { - if n == 1 || n == 2 { - let a3 = self[temp_v!(3)]; - 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()) - } + } + Addr::PStrLocation(h, offset) => { + if n == 1 || n == 2 { + let a3 = self[temp_v!(3)]; + 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 { - unreachable!() + Addr::PStrLocation(h, offset + c.len_utf8()) } } else { unreachable!() - }; + } + } else { + unreachable!() + }; - self.unify(a3, h_a); - } else { - self.fail = true; - } - } - _ => { // 8.5.2.3 d) - return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Compound, - term, - ), - stub, - )) + self.unify(a3, h_a); + } else { + self.fail = true; } } - } else { - return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - Addr::HeapCell(h), - ), - stub, - )) + _ => { // 8.5.2.3 d) + return Err(self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Compound, + term, + ), + stub, + )) + } } } - _ => { // 8.5.2.3 c) - return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - n, - ), - stub, - )) - } } Ok(()) @@ -1747,7 +1728,8 @@ impl MachineState { self.p += 1; } - pub(super) fn compare_term(&mut self, qt: CompareTermQT) { + pub(super) + fn compare_term(&mut self, qt: CompareTermQT) { let a1 = self[temp_v!(1)]; let a2 = self[temp_v!(2)]; @@ -1804,18 +1786,10 @@ impl MachineState { (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), + &HeapCellValue::Atom(ref n1, ref spec_1), + &HeapCellValue::Atom(ref n2, ref spec_2), ) => { - if n1 != n2 { + if n1 != n2 || spec_1 != spec_2 { return true; } } @@ -1828,14 +1802,17 @@ impl MachineState { } } ( - &HeapCellValue::Atom(ref n1, ref spec_1), - &HeapCellValue::Atom(ref n2, ref spec_2), + v1, + v2, ) => { - if n1 != n2 || spec_1 != spec_2 { - return true; + if let Ok(n1) = Number::try_from(v1) { + if let Ok(n2) = Number::try_from(v2) { + if n1 == n2 { + continue; + } + } } - } - _ => { + return true; } } @@ -1852,25 +1829,26 @@ impl MachineState { } } } - (Addr::Usize(n1), Addr::Con(n2)) | (Addr::Con(n2), Addr::Usize(n1)) => { - if let HeapCellValue::Integer(ref n2) = &self.heap[n2] { - if let Some(n2) = n2.to_usize() { + (Addr::CharCode(n1), v2) | (v2, Addr::CharCode(n1)) => { + if let Ok(n2) = Number::try_from((v2, &self.heap)) { + if let Some(n2) = n2.to_u32() { if n1 != n2 { return true; } } } } - (Addr::CharCode(n1), Addr::Con(n2)) | (Addr::Con(n2), Addr::CharCode(n1)) => { - if let HeapCellValue::Integer(ref n2) = &self.heap[n2] { - if let Some(n2) = n2.to_u32() { - if n1 == n2 { + (a1, a2) => { + if let Ok(n1) = Number::try_from((a1, &self.heap)) { + if let Ok(n2) = Number::try_from((a2, &self.heap)) { + if n1 != n2 { return true; + } else { + continue; } } } - } - (a1, a2) => { + if a1 != a2 { return true; } @@ -1919,75 +1897,63 @@ impl MachineState { 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)); + if let Ok(n1) = Number::try_from(&self.heap[h1]) { + if let Ok(n2) = Number::try_from(&self.heap[h2]) { + if n1 != n2 { + return Some(n1.cmp(&n2)); } - } - _ => { + } else { unreachable!() } + } else { + unreachable!() } } - (Addr::Usize(n1), Addr::Usize(n2)) => { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } - (Addr::CharCode(n1), Addr::CharCode(n2)) => { - if n1 != n2 { - return Some(n1.cmp(&n2)); + ( + Addr::Con(h1), + v2, + ) => { + if let Ok(n1) = Number::try_from(&self.heap[h1]) { + if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(v2)) { + if n1 != n2 { + return Some(n1.cmp(&n2)); + } + } else { + unreachable!() + } + } else { + unreachable!() } } - (Addr::Usize(n1), Addr::Con(n2)) | (Addr::Con(n2), Addr::Usize(n1)) => { - if let HeapCellValue::Integer(ref n2) = &self.heap[n2] { - if let Some(n2) = n2.to_usize() { + ( + v1, + Addr::Con(h2), + ) => { + if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(v1)) { + if let Ok(n2) = Number::try_from(&self.heap[h2]) { if n1 != n2 { return Some(n1.cmp(&n2)); } + } else { + unreachable!() } + } else { + unreachable!() } } - (Addr::CharCode(n1), Addr::Con(n2)) | (Addr::Con(n2), Addr::CharCode(n1)) => { - if let HeapCellValue::Integer(ref n2) = &self.heap[n2] { - if let Some(n2) = n2.to_u32() { + (v1, v2) => { + if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(v1)) { + if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(v2)) { if n1 != n2 { return Some(n1.cmp(&n2)); } + } else { + unreachable!() } + } else { + unreachable!() } } - _ => { - unreachable!() - } } } Some(TermOrderCategory::Atom) => { @@ -2330,34 +2296,34 @@ impl MachineState { &InlinedClauseType::IsInteger(r1) => { let d = self.store(self.deref(self[r1])); - match d { - Addr::Con(h) => { - match &self.heap[h] { - HeapCellValue::Integer(_) => { + match Number::try_from((d, &self.heap)) { + Ok(Number::Fixnum(_)) => { + self.p += 1; + } + Ok(Number::Integer(_)) => { + self.p += 1; + } + Ok(Number::Rational(n)) => { + if n.denom() == &1 { + self.p += 1; + } else { + self.fail = true; + } + } + _ => { + match d { + Addr::CharCode(_) => { self.p += 1; } - HeapCellValue::Rational(ref r) => { - if r.denom() == &1 { - self.p += 1; - } else { - self.fail = true; - } + Addr::Char(_) if self.flags.double_quotes.is_codes() => { + self.p += 1; } _ => { self.fail = true; } } } - Addr::CharCode(_) | Addr::Usize(_) => { - 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])); @@ -2484,8 +2450,8 @@ impl MachineState { Addr::Stream(_) => { self.fail = true; } - Addr::Char(_) | Addr::CharCode(_) | Addr::Con(_) | Addr::Float(_) | - Addr::EmptyList | Addr::Usize(_) => { + Addr::Char(_) | Addr::CharCode(_) | Addr::Con(_) | Addr::Fixnum(_) | + Addr::Float(_) | Addr::EmptyList | Addr::Usize(_) => { self.try_functor_unify_components(a1, 0); } Addr::Str(o) => match self.heap.clone(o) { @@ -2510,48 +2476,33 @@ impl MachineState { return Err(self.error_form(MachineError::instantiation_error(), stub)); } - let arity = match arity { - Addr::Con(h) => { - match &self.heap[h] { - &HeapCellValue::Integer(ref n) => { - n.to_isize() - } - &HeapCellValue::Addr(Addr::Usize(n)) => { - Some(n as isize) - } - _ => { - return Err( - self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - arity, - ), - stub, - ) - ); + let arity = + match Number::try_from((arity, &self.heap)) { + Ok(Number::Fixnum(n)) => Some(n), + Ok(Number::Integer(n)) => n.to_isize(), + Ok(Number::Rational(n)) + if n.denom() == &1 => { + n.numer().to_isize() + }, + _ => + match arity { + Addr::CharCode(c) => { + Some(c as isize) + } + arity => { + return Err( + self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + arity, + ), + stub, + ) + ); + } } - } - }, - Addr::Usize(n) => { - Some(n as isize) - } - Addr::CharCode(c) => { - Some(c as isize) - } - arity => { - return Err( - self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - arity, - ), - stub, - ) - ); - } - }; + }; let arity = match arity { Some(arity) => { @@ -2579,7 +2530,7 @@ impl MachineState { } match name { - Addr::Char(_) | Addr::CharCode(_) | Addr::Con(_) | Addr::Float(_) | + Addr::Char(_) | Addr::CharCode(_) | Addr::Con(_) | Addr::Fixnum(_) | Addr::Float(_) | Addr::EmptyList | Addr::PStrLocation(..) | Addr::Usize(_) if arity == 0 => { self.unify(a1, name); } @@ -2925,34 +2876,6 @@ impl MachineState { 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), @@ -2970,15 +2893,34 @@ impl MachineState { } } ( - HeapCellValue::Addr(a1), - HeapCellValue::Addr(a2), + v1, + v2, ) => { - if a1 != a2 { - return true; + if let Ok(n1) = Number::try_from(v1) { + if let Ok(n2) = Number::try_from(v2) { + if n1 != n2 { + return true; + } else { + continue; + } + } else { + return true; + } + } + + match (v1, v2) { + ( + HeapCellValue::Addr(a1), + HeapCellValue::Addr(a2), + ) => { + if a1 != a2 { + return true; + } + } + _ => { + return true; + } } - } - _ => { - return true; } } } @@ -3051,13 +2993,13 @@ impl MachineState { lco: bool, use_default_cp: bool, ) { - let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); + let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); - if INTERRUPT.compare_and_swap(interrupted, false, std::sync::atomic::Ordering::Relaxed) { - self.reset(); - self.fail = true; - return; - } + if INTERRUPT.compare_and_swap(interrupted, false, std::sync::atomic::Ordering::Relaxed) { + self.reset(); + self.fail = true; + return; + } let mut default_call_policy: Box = Box::new(DefaultCallPolicy {}); @@ -3192,8 +3134,12 @@ impl MachineState { self.hb = self.heap.h(); self.p += offset; } - &IndexedChoiceInstruction::Retry(l) => try_or_fail!(self, call_policy.retry(self, l)), - &IndexedChoiceInstruction::Trust(l) => try_or_fail!(self, call_policy.trust(self, l)), + &IndexedChoiceInstruction::Retry(l) => { + try_or_fail!(self, call_policy.retry(self, l)); + } + &IndexedChoiceInstruction::Trust(l) => { + try_or_fail!(self, call_policy.trust(self, l)); + } }; } @@ -3241,7 +3187,9 @@ impl MachineState { &ChoiceInstruction::RetryMeElse(offset) => { try_or_fail!(self, call_policy.retry_me_else(self, offset)) } - &ChoiceInstruction::TrustMe => try_or_fail!(self, call_policy.trust_me(self)), + &ChoiceInstruction::TrustMe => { + try_or_fail!(self, call_policy.trust_me(self)) + } } } diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index 7271c150..4f859c57 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -45,6 +45,7 @@ use crate::prolog::machine::toplevel::*; use indexmap::IndexMap; use std::collections::VecDeque; +use std::convert::TryFrom; use std::fs::File; use std::mem; use std::ops::Index; @@ -205,11 +206,11 @@ impl SubModuleUser for IndexStore { #[inline] fn current_dir() -> std::path::PathBuf { let mut path_buf = std::path::PathBuf::from(PROJECT_DIR); - + // file!() always produces a path relative to PROJECT_DIR. path_buf = path_buf.join(std::path::PathBuf::from(file!())); - path_buf.pop(); + path_buf.pop(); path_buf } @@ -322,34 +323,34 @@ impl Machine { } pub fn run_init_code(&mut self, code: Code) -> bool { - let old_machine_st = self.sink_to_snapshot(); - self.machine_st.reset(); + let old_machine_st = self.sink_to_snapshot(); + self.machine_st.reset(); - self.code_repo.cached_query = code; - self.run_query(); + self.code_repo.cached_query = code; + self.run_query(); let result = self.machine_st.fail; - self.absorb_snapshot(old_machine_st); + self.absorb_snapshot(old_machine_st); !result } pub fn run_top_level(&mut self) { - use std::env; + use std::env; - let mut filename_atoms = vec![]; + let mut filename_atoms = vec![]; - // the first of these is the path to the scryer-prolog executable, so skip - // it. - for filename in env::args().skip(1) { - let atom = clause_name!(filename, self.indices.atom_tbl); - filename_atoms.push(HeapCellValue::Atom(atom, None)); - } + // the first of these is the path to the scryer-prolog executable, so skip + // it. + for filename in env::args().skip(1) { + let atom = clause_name!(filename, self.indices.atom_tbl); + filename_atoms.push(HeapCellValue::Atom(atom, None)); + } - let list_addr = - Addr::HeapCell(self.machine_st.heap.to_list(filename_atoms.into_iter())); + let list_addr = + Addr::HeapCell(self.machine_st.heap.to_list(filename_atoms.into_iter())); - self.machine_st[temp_v!(1)] = list_addr; + self.machine_st[temp_v!(1)] = list_addr; self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(self.toplevel_idx)); self.run_query(); @@ -397,7 +398,7 @@ impl Machine { lib_path.clone(), ) ); - + compile_user_module(&mut wam, Stream::from(LISTS), true, @@ -406,7 +407,7 @@ impl Machine { lib_path.clone(), ), ); - + compile_user_module(&mut wam, Stream::from(ISO_EXT), true, @@ -415,7 +416,7 @@ impl Machine { lib_path.clone(), ) ); - + compile_user_module(&mut wam, Stream::from(SI), true, @@ -539,53 +540,57 @@ impl Machine { fn extract_module_export_list(&mut self) -> Result, ParserError> { - let mut export_list = self.machine_st[temp_v!(2)].clone(); - let mut exports = vec![]; + let mut export_list = self.machine_st[temp_v!(2)].clone(); + let mut exports = vec![]; - while let Addr::Lis(l) = self.machine_st.store(self.machine_st.deref(export_list)) { - match &self.machine_st.heap[l] { - &HeapCellValue::Addr(Addr::Str(s)) => { + while let Addr::Lis(l) = self.machine_st.store(self.machine_st.deref(export_list)) { + match &self.machine_st.heap[l] { + &HeapCellValue::Addr(Addr::Str(s)) => { match &self.machine_st.heap[s] { HeapCellValue::NamedStr(arity, ref name, _) if *arity == 2 && name.as_str() == "/" => { - let name = match &self.machine_st.heap[s+1] { - &HeapCellValue::Atom(ref name, _) => - name.clone(), - _ => - unreachable!() - }; - - let arity = match &self.machine_st.heap[s+2] { - &HeapCellValue::Integer(ref arity) => - arity.to_usize().unwrap(), - _ => - unreachable!() - }; - - exports.push(ModuleExport::PredicateKey((name, arity))); + let name = match &self.machine_st.heap[s+1] { + &HeapCellValue::Atom(ref name, _) => + name.clone(), + _ => + unreachable!() + }; + + let arity = match &self.machine_st.heap[s+2] { + &HeapCellValue::Integer(ref arity) => + arity.to_usize().unwrap(), + &HeapCellValue::Addr(Addr::Fixnum(n)) => + usize::try_from(n).unwrap(), + _ => + unreachable!() + }; + + exports.push(ModuleExport::PredicateKey((name, arity))); } HeapCellValue::NamedStr(arity, ref name, _) if *arity == 3 && name.as_str() == "op" => { let name = match &self.machine_st.heap[s+3] { - &HeapCellValue::Atom(ref name, _) => - name.clone(), - _ => - unreachable!() - }; + &HeapCellValue::Atom(ref name, _) => + name.clone(), + _ => + unreachable!() + }; let spec = match &self.machine_st.heap[s+2] { - &HeapCellValue::Atom(ref name, _) => - name.clone(), - _ => - unreachable!() - }; - - let prec = match &self.machine_st.heap[s+1] { - &HeapCellValue::Integer(ref arity) => - arity.to_usize().unwrap(), - _ => - unreachable!() - }; + &HeapCellValue::Atom(ref name, _) => + name.clone(), + _ => + unreachable!() + }; + + let prec = match &self.machine_st.heap[s+1] { + &HeapCellValue::Integer(ref arity) => + arity.to_usize().unwrap(), + &HeapCellValue::Addr(Addr::Fixnum(n)) => + usize::try_from(n).unwrap(), + _ => + unreachable!() + }; exports.push(ModuleExport::OpDecl(to_op_decl( prec, @@ -595,47 +600,47 @@ impl Machine { } _ => unreachable!() } - } - _ => unreachable!() - } + } + _ => unreachable!() + } - export_list = self.machine_st.heap[l+1].as_addr(l+1); - } + export_list = self.machine_st.heap[l+1].as_addr(l+1); + } - Ok(exports) + Ok(exports) } fn use_module(&mut self, to_src: ToSource) where ToSource: Fn(ClauseName) -> ModuleSource { - // the term expander will overwrite the cached query, so save it here. - let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); + // the term expander will overwrite the cached query, so save it here. + let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); - let module_spec = self.machine_st[temp_v!(1)].clone(); - let name = { + let module_spec = self.machine_st[temp_v!(1)].clone(); + 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!(), + _ => unreachable!(), } - }; + }; - let load_result = match to_src(name) { - ModuleSource::Library(name) => + let load_result = match to_src(name) { + ModuleSource::Library(name) => if let Some(module) = self.indices.take_module(name.clone()) { self.indices.remove_module(clause_name!("user"), &module); self.indices.modules.insert(name.clone(), module); - Ok(name) - } else { - load_library(self, name, false) - }, - ModuleSource::File(name) => + Ok(name) + } else { + load_library(self, name, false) + }, + ModuleSource::File(name) => load_module_from_file(self, PathBuf::from(name.as_str()), false) - }; + }; - let result = load_result.and_then(|name| { + let result = load_result.and_then(|name| { let module = self.indices.take_module(name.clone()).unwrap(); if !module.is_impromptu_module { @@ -645,30 +650,30 @@ impl Machine { Ok(self.indices.insert_module(module)) }); - self.code_repo.cached_query = cached_query; + self.code_repo.cached_query = cached_query; - if let Err(e) = result { - self.throw_session_error(e, (clause_name!("use_module"), 1)); - } + if let Err(e) = result { + self.throw_session_error(e, (clause_name!("use_module"), 1)); + } } fn use_qualified_module(&mut self, to_src: ToSource) where ToSource: Fn(ClauseName) -> ModuleSource { - // the term expander will overwrite the cached query, so save it here. - let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); + // the term expander will overwrite the cached query, so save it here. + let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); - let module_spec = self.machine_st[temp_v!(1)].clone(); - let name = { + let module_spec = self.machine_st[temp_v!(1)].clone(); + 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!(), + _ => unreachable!(), } - }; + }; - let exports = match self.extract_module_export_list() { + let exports = match self.extract_module_export_list() { Ok(exports) => exports, Err(e) => { self.throw_session_error(SessionError::from(e), (clause_name!("use_module"), 2)); @@ -676,38 +681,38 @@ impl Machine { } }; - let load_result = match to_src(name) { - ModuleSource::Library(name) => + let load_result = match to_src(name) { + ModuleSource::Library(name) => if let Some(module) = self.indices.take_module(name.clone()) { self.indices.remove_module(clause_name!("user"), &module); self.indices.modules.insert(name.clone(), module); - Ok(name) - } else { - load_library(self, name, false) - }, - ModuleSource::File(name) => + Ok(name) + } else { + load_library(self, name, false) + }, + ModuleSource::File(name) => load_module_from_file(self, PathBuf::from(name.as_str()), false) - }; + }; - let result = load_result.and_then(|name| { - let module = self.indices.take_module(name.clone()).unwrap(); + let result = load_result.and_then(|name| { + let module = self.indices.take_module(name.clone()).unwrap(); if !module.is_impromptu_module { - self.indices.use_qualified_module(&mut self.code_repo, - self.machine_st.flags, - &module, - &exports)?; + self.indices.use_qualified_module(&mut self.code_repo, + self.machine_st.flags, + &module, + &exports)?; } - Ok(self.indices.insert_module(module)) + Ok(self.indices.insert_module(module)) }); - self.code_repo.cached_query = cached_query; + self.code_repo.cached_query = cached_query; - if let Err(e) = result { - self.throw_session_error(e, (clause_name!("use_module"), 2)); - } + if let Err(e) = result { + self.throw_session_error(e, (clause_name!("use_module"), 2)); + } } fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) { @@ -722,14 +727,14 @@ impl Machine { self.throw_session_error(e, (clause_name!("repl"), 0)); } } - REPLCodePtr::UseModule => - self.use_module(ModuleSource::Library), - REPLCodePtr::UseModuleFromFile => - self.use_module(ModuleSource::File), - REPLCodePtr::UseQualifiedModule => - self.use_qualified_module(ModuleSource::Library), - REPLCodePtr::UseQualifiedModuleFromFile => - self.use_qualified_module(ModuleSource::File) + REPLCodePtr::UseModule => + self.use_module(ModuleSource::Library), + REPLCodePtr::UseModuleFromFile => + self.use_module(ModuleSource::File), + REPLCodePtr::UseQualifiedModule => + self.use_qualified_module(ModuleSource::Library), + REPLCodePtr::UseQualifiedModuleFromFile => + self.use_qualified_module(ModuleSource::File) } self.machine_st.p = CodePtr::Local(p); @@ -786,7 +791,7 @@ impl Machine { } pub(super) fn run_query(&mut self) { - self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query()); + self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query()); let end_ptr = CodePtr::Local(self.machine_st.cp); while self.machine_st.p < end_ptr { diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index dbbc25e5..b6e81a09 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -23,9 +23,9 @@ use crate::ref_thread_local::RefThreadLocal; use indexmap::{IndexMap, IndexSet}; use std::cmp; +use std::convert::TryFrom; use std::io::{stdout, Write}; use std::iter::once; -use std::mem; use std::rc::Rc; use crate::crossterm::event::{read, Event, KeyCode, KeyEvent}; @@ -269,9 +269,9 @@ impl MachineState { } } - fn skip_max_list_result(&mut self, max_steps: &Integer) { + fn skip_max_list_result(&mut self, max_steps: Option) { let search_result = - if let Some(max_steps) = max_steps.to_isize() { + if let Some(max_steps) = max_steps { if max_steps == -1 { self.detect_cycles(self[temp_v!(3)]) } else { @@ -307,59 +307,66 @@ impl MachineState { }; } - pub(super) fn skip_max_list(&mut self) -> CallResult { + pub(super) + fn skip_max_list(&mut self) -> CallResult { let max_steps = self.store(self.deref(self[temp_v!(2)])); 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.skip_max_list_result(max_steps.as_ref()); - } - } else { - unreachable!() - } + Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(_) => { + let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4); + return Err(self.error_form(MachineError::instantiation_error(), stub)); + } + addr => { + let max_steps_n = + match Number::try_from((max_steps, &self.heap)) { + Ok(Number::Integer(n)) => n.to_isize(), + Ok(Number::Fixnum(n)) => Some(n), + _ => None, + }; + + if max_steps_n.map(|i| i >= -1).unwrap_or(false) { + let n = self.store(self.deref(self[temp_v!(1)])); + + match Number::try_from((n, &self.heap)) { + Ok(Number::Integer(n)) => { + if n.as_ref() == &0 { + let xs0 = self[temp_v!(3)]; + let xs = self[temp_v!(4)]; + + self.unify(xs0, xs); + } else { + self.skip_max_list_result(max_steps_n); } - _ => { - self.skip_max_list_result(max_steps.as_ref()); + } + Ok(Number::Fixnum(n)) => { + if n == 0 { + let xs0 = self[temp_v!(3)]; + let xs = self[temp_v!(4)]; + + self.unify(xs0, xs); + } else { + self.skip_max_list_result(max_steps_n); } } - } else { - self.fail = true; + _ => { + self.skip_max_list_result(max_steps_n); + } } } else { - unreachable!() + let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4); + return Err( + self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + addr + ), + stub, + ) + ); } } - Addr::HeapCell(_) | Addr::StackCell(..) => { - let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4); - return Err(self.error_form(MachineError::instantiation_error(), stub)); - } - addr => { - let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4); - return Err( - self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - addr - ), - stub, - ) - ); - } - }; + } Ok(()) } @@ -671,6 +678,10 @@ impl MachineState { let addr = self.heap.put_constant(Constant::Integer(n)); self.unify(nx, addr); } + Ok(Term::Constant(_, Constant::Fixnum(n))) => { + let addr = self.heap.put_constant(Constant::Fixnum(n)); + self.unify(nx, addr); + } Ok(Term::Constant(_, Constant::CharCode(c))) => { self.unify(nx, Addr::CharCode(c)) } @@ -774,17 +785,18 @@ impl MachineState { } &SystemClauseType::BindFromRegister => { let reg = self.store(self.deref(self[temp_v!(2)])); - let n = match reg { - Addr::Con(h) => - if let HeapCellValue::Integer(ref n) = &self.heap[h] { + let n = + match Number::try_from((reg, &self.heap)) { + Ok(Number::Integer(n)) => { n.to_usize() - } else { + } + Ok(Number::Fixnum(n)) => { + usize::try_from(n).ok() + } + _ => { unreachable!() } - _ => { - unreachable!() - } - }; + }; if let Some(n) = n { if n <= MAX_ARITY { @@ -1020,15 +1032,36 @@ impl MachineState { let mut chars = String::new(); for addr in addrs { - match addr { - 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!() + match Number::try_from((addr, &self.heap)) { + Ok(Number::Fixnum(n)) => { + match u32::try_from(n) { + Ok(c) => { + chars.push(std::char::from_u32(c).unwrap()); + } + _ => { + let c = self.int_to_char_code( + &Integer::from(n), + "atom_codes", + 2, + )?; + + chars.push(std::char::from_u32(c).unwrap()); + } } + + continue; + } + Ok(Number::Integer(n)) => { + let c = self.int_to_char_code(&n, "atom_codes", 2)?; + chars.push(std::char::from_u32(c).unwrap()); + + continue; + } + _ => { } + } + + match addr { Addr::CharCode(c) => { chars.push(std::char::from_u32(c).unwrap()); } @@ -1056,7 +1089,9 @@ impl MachineState { } } } - _ => unreachable!(), + _ => { + unreachable!() + } }; } &SystemClauseType::AtomLength => { @@ -1088,17 +1123,6 @@ impl MachineState { self.unify(a2, len); } - &SystemClauseType::CallAttributeGoals => { - let p = self.attr_var_init.project_attrs_loc; - - if self.last_call { - self.execute_at_index(2, dir_entry!(p)); - } else { - self.call_at_index(2, dir_entry!(p)); - } - - return Ok(()); - } &SystemClauseType::CallContinuation => { let stub = MachineError::functor_stub(clause_name!("call_continuation"), 1); @@ -1201,21 +1225,23 @@ impl MachineState { let n = self[temp_v!(1)]; let chs = self[temp_v!(2)]; - let string = match self.store(self.deref(n)) { - 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] { + let n = self.store(self.deref(n)); + + let string = + match Number::try_from((n, &self.heap)) { + Ok(Number::Float(OrderedFloat(n))) => { + format!("{0:<20?}", n) + } + Ok(Number::Fixnum(n)) => { n.to_string() - } else { + } + Ok(Number::Integer(n)) => { + n.to_string() + } + _ => { unreachable!() } - } - _ => { - unreachable!() - } - }; + }; let chars = string.trim().chars().map(|c| Addr::Char(c)); let char_list = Addr::HeapCell(self.heap.to_list(chars)); @@ -1226,21 +1252,21 @@ impl MachineState { let n = self[temp_v!(1)]; let chs = self[temp_v!(2)]; - let string = match self.store(self.deref(n)) { - 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] { + let string = + match Number::try_from((n, &self.heap)) { + Ok(Number::Float(OrderedFloat(n))) => { + format!("{0:<20?}", n) + } + Ok(Number::Fixnum(n)) => { n.to_string() - } else { + } + Ok(Number::Integer(n)) => { + n.to_string() + } + _ => { unreachable!() } - } - _ => { - unreachable!() - } - }; + }; let codes = string .trim() @@ -1322,33 +1348,37 @@ impl MachineState { } addr if addr.is_ref() => { let a2 = self[temp_v!(2)]; + let a2 = self.store(self.deref(a2)); - match self.store(self.deref(a2)) { - Addr::CharCode(code) => { - if let Some(c) = std::char::from_u32(code) { - self.unify(Addr::Char(c), addr); - } else { - self.fail = true; - } + let c = match Number::try_from((a2, &self.heap)) { + Ok(Number::Integer(n)) => { + 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::Char(c), addr); - } else { - self.fail = true; + Ok(Number::Fixnum(n)) => { + self.int_to_char_code(&Integer::from(n), "char_code", 2)? + } + _ => { + match addr { + Addr::CharCode(c) => { + c + } + _ => { + self.fail = true; + return Ok(()); + } } } - _ => self.fail = true, }; + + if let Some(c) = std::char::from_u32(c) { + self.unify(Addr::Char(c), addr); + } else { + self.fail = true; + } + } + _ => { + unreachable!(); } - _ => unreachable!(), }; } &SystemClauseType::CheckCutPoint => { @@ -1967,16 +1997,20 @@ impl MachineState { let specifier = self[temp_v!(2)]; let op = self[temp_v!(3)]; - let priority = match self.store(self.deref(priority)) { - Addr::Con(h) if self.heap.integer_at(h) => - if let HeapCellValue::Integer(ref n) = &self.heap[h] { + let priority = self.store(self.deref(priority)); + + let priority = + match Number::try_from((priority, &self.heap)) { + Ok(Number::Integer(n)) => { n.to_usize().unwrap() - } else { - unreachable!() - }, - _ => - unreachable!(), - }; + } + Ok(Number::Fixnum(n)) => { + usize::try_from(n).unwrap() + } + _ => { + unreachable!(); + } + }; let specifier = match self.store(self.deref(specifier)) { Addr::Con(h) if self.heap.atom_at(h) => @@ -2041,10 +2075,6 @@ impl MachineState { let attr_goals = self.attr_var_init.attribute_goals.clone(); self.fetch_attribute_goals(attr_goals); } - &SystemClauseType::FetchAttributeGoals => { - let attr_goals = mem::replace(&mut self.attr_var_init.attribute_goals, vec![]); - self.fetch_attribute_goals(attr_goals); - } &SystemClauseType::GetAttributedVariableList => { let attr_var = self.store(self.deref(self[temp_v!(1)])); let attr_var_list = @@ -2080,35 +2110,36 @@ impl MachineState { } &SystemClauseType::GetAttrVarQueueBeyond => { let addr = self[temp_v!(1)]; + let addr = self.store(self.deref(addr)); - match self.store(self.deref(addr)) { - 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)]; + let b = + match addr { + Addr::Usize(b) => { + Some(b) + } + _ => { + match Number::try_from((addr, &self.heap)) { + Ok(Number::Integer(n)) => { + n.to_usize() + } + Ok(Number::Fixnum(n)) => { + usize::try_from(n).ok() + } + _ => { + self.fail = true; + return Ok(()); + } + } + } + }; - self.unify(var_list_addr, list_addr); - } - 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); + if let Some(b) = 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)]; + let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); + let list_addr = self[temp_v!(2)]; - self.unify(var_list_addr, list_addr); - } else { - self.fail = true; - } - } else { - unreachable!() - } - } - _ => { - self.fail = true; - } + self.unify(var_list_addr, list_addr); } } &SystemClauseType::GetContinuationChunk => { @@ -2327,51 +2358,58 @@ impl MachineState { CWILCallPolicy::new_in_place(call_policy); } - 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 n = + match Number::try_from((a2, &self.heap)) { + Ok(Number::Integer(n)) => { + Integer::from(&*n.clone()) + } + Ok(Number::Fixnum(n)) => { + Integer::from(n) + } + _ => { + let stub = MachineError::functor_stub( + clause_name!("call_with_inference_limit"), + 3, + ); - let a3 = self[temp_v!(3)]; + let type_error = self.error_form( + MachineError::type_error( + self.heap.h(), + ValidType::Integer, + a2, + ), + stub, + ); - self.unify(a3, count); - } - None => { - panic!( - "install_inference_counter: should have installed \\ - CWILCallPolicy." - ) - } - } - } else { - unreachable!() - } + self.throw_exception(type_error); + return Ok(()); } - _ => { - let stub = MachineError::functor_stub( - clause_name!("call_with_inference_limit"), - 3, - ); + }; - let type_error = self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Integer, - a2, - ), - stub, - ); + match a1 { + Addr::Usize(bp) | Addr::CutPoint(bp) => { + match call_policy.downcast_mut::().ok() { + Some(call_policy) => { + let count = call_policy.add_limit(n, bp).clone(); + let count = self.heap.to_unifiable( + HeapCellValue::Integer(Rc::new(count)) + ); - self.throw_exception(type_error) + let a3 = self[temp_v!(3)]; + self.unify(a3, count); + } + None => { + panic!( + "install_inference_counter: should have installed \\ + CWILCallPolicy." + ) + } + } } - }; + _ => { + unreachable!(); + } + } } &SystemClauseType::ModuleExists => { let module = self.store(self.deref(self[temp_v!(1)])); @@ -2582,9 +2620,9 @@ impl MachineState { match a1 { Addr::Usize(bp) | Addr::CutPoint(bp) => { - let count = call_policy.remove_limit(bp); + let count = call_policy.remove_limit(bp).clone(); let count = self.heap.to_unifiable( - HeapCellValue::Integer(Rc::new(count.clone())), + HeapCellValue::Integer(Rc::new(count)), ); let a2 = self[temp_v!(2)]; @@ -3029,29 +3067,24 @@ impl MachineState { 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 { - 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 { + _ => { + match Number::try_from((seed, &self.heap)) { + Ok(Number::Fixnum(n)) => { + Integer::from(n) + } + Ok(Number::Integer(n)) => { + Integer::from(n.as_ref()) + } + Ok(Number::Rational(n)) + if n.denom() == &1 => { + n.numer().clone() + } + _ => { self.fail = true; return Ok(()); } - } else { - unreachable!() } } - _ => { - self.fail = true; - return Ok(()); - } }; let mut rand = RANDOM_STATE.borrow_mut(); @@ -3195,43 +3228,33 @@ impl MachineState { } }; - let arity = match self.store(self.deref(arity)) { - Addr::Con(h) if self.heap.integer_at(h) => { - if let HeapCellValue::Integer(ref n) = &self.heap[h] { - n.clone() - } else { + let arity = self.store(self.deref(arity)); + + let arity = + match Number::try_from((arity, &self.heap)) { + Ok(Number::Fixnum(n)) => { + Integer::from(n) + } + Ok(Number::Integer(n)) => { + Integer::from(n.as_ref()) + } + _ => { unreachable!() } - } - _ => { - unreachable!() - } - }; + }; let first_idx = match indices .code_dir .get(&(name.clone(), arity.to_usize().unwrap())) { - Some(ref idx) => { + Some(ref idx) if idx.local().is_some() => { if let Some(idx) = idx.local() { idx } else { - let arity = arity.to_usize().unwrap(); - let stub = MachineError::functor_stub(name.clone(), arity); - let h = self.heap.h(); - - let err = MachineError::existence_error( - h, - ExistenceError::Procedure(name, arity), - ); - - let err = self.error_form(err, stub); - - self.throw_exception(err); - return Ok(()); + unreachable!() } } - None => { + _ => { let arity = arity.to_usize().unwrap(); let stub = MachineError::functor_stub(name.clone(), arity); let h = self.heap.h(); @@ -3279,7 +3302,7 @@ impl MachineState { let mut printer = HCPrinter::new(&self, &indices.op_dir, PrinterOutputter::new()); if let &Addr::Con(h) = &ignore_ops { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { printer.ignore_ops = name.as_str() == "true"; } else { unreachable!() @@ -3287,7 +3310,7 @@ impl MachineState { } if let &Addr::Con(h) = &numbervars { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { printer.numbervars = name.as_str() == "true"; } else { unreachable!() @@ -3295,23 +3318,32 @@ impl MachineState { } if let &Addr::Con(h) = "ed { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { printer.quoted = name.as_str() == "true"; } else { unreachable!() } } - if let &Addr::Con(h) = &max_depth { - if let HeapCellValue::Integer(ref n) = &self.heap[h] { + match Number::try_from((max_depth, &self.heap)) { + Ok(Number::Fixnum(n)) => { + if let Ok(n) = usize::try_from(n) { + printer.max_depth = n; + } else { + self.fail = true; + return Ok(()); + } + } + Ok(Number::Integer(n)) => { if let Some(n) = n.to_usize() { printer.max_depth = n; } else { self.fail = true; return Ok(()); } - } else { - unreachable!() + } + _ => { + unreachable!(); } } diff --git a/src/prolog/machine/term_expansion.rs b/src/prolog/machine/term_expansion.rs index 2af0c13f..41331114 100644 --- a/src/prolog/machine/term_expansion.rs +++ b/src/prolog/machine/term_expansion.rs @@ -362,7 +362,7 @@ impl MachineState { wam.code_repo.cached_query = code; self.cp = LocalCodePtr::TopLevel(0, 0); - + self.at_end_of_expansion = false; self.flags.double_quotes = DoubleQuotes::Chars; diff --git a/src/prolog/machine/toplevel.rs b/src/prolog/machine/toplevel.rs index 0d93a394..99990896 100644 --- a/src/prolog/machine/toplevel.rs +++ b/src/prolog/machine/toplevel.rs @@ -13,6 +13,7 @@ use indexmap::{IndexMap, IndexSet}; use std::borrow::BorrowMut; use std::cell::Cell; use std::collections::VecDeque; +use std::convert::TryFrom; use std::mem; use std::ops::DerefMut; use std::rc::Rc; @@ -211,8 +212,8 @@ fn setup_op_decl( }; let prec = match *terms.pop().unwrap() { - Term::Constant(_, Constant::Integer(bi)) => match bi.to_usize() { - Some(n) if n <= 1200 => n, + Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) { + Ok(n) if n <= 1200 => n, _ => return Err(ParserError::InconsistentEntry), }, _ => return Err(ParserError::InconsistentEntry), @@ -232,8 +233,13 @@ fn setup_predicate_indicator(term: &mut Term) -> Result n.to_usize(), + Constant::Fixnum(n) => usize::try_from(n).ok(), + _ => None + } + }) .ok_or(ParserError::InvalidModuleExport)?; let name = name @@ -246,7 +252,7 @@ fn setup_predicate_indicator(term: &mut Term) -> Result Err(ParserError::InvalidModuleExport), } } @@ -344,7 +350,7 @@ fn setup_use_module_decl(mut terms: Vec>) -> Result>) -> Result { let dbl_quotes = *terms.pop().unwrap(); - + match terms[0].as_ref() { Term::Constant(_, Constant::Atom(ref name, _)) if name.as_str() == "double_quotes" => { @@ -629,26 +635,26 @@ fn setup_declaration<'a, 'b, 'c>( match term { Term::Clause(_, name, mut terms, _) => - match (name.as_str(), terms.len()) { - ("dynamic", 1) => { - let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; - Ok(Declaration::Dynamic(name, arity)) - } - ("initialization", 1) => { - let mut rel_worker = RelationWorker::new(flags, line_num, col_num); - let query_terms = rel_worker.setup_query(indices, terms, false)?; - let queue = rel_worker.parse_queue(indices)?; - - Ok(Declaration::ModuleInitialization(query_terms, queue)) - } - ("module", 2) => - Ok(Declaration::Module(setup_module_decl(terms, indices.atom_tbl())?)), - ("op", 3) => - Ok(Declaration::Op(setup_op_decl(terms, indices.atom_tbl())?)), - ("non_counted_backtracking", 1) => { - let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; - Ok(Declaration::NonCountedBacktracking(name, arity)) - } + match (name.as_str(), terms.len()) { + ("dynamic", 1) => { + let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; + Ok(Declaration::Dynamic(name, arity)) + } + ("initialization", 1) => { + let mut rel_worker = RelationWorker::new(flags, line_num, col_num); + let query_terms = rel_worker.setup_query(indices, terms, false)?; + let queue = rel_worker.parse_queue(indices)?; + + Ok(Declaration::ModuleInitialization(query_terms, queue)) + } + ("module", 2) => + Ok(Declaration::Module(setup_module_decl(terms, indices.atom_tbl())?)), + ("op", 3) => + Ok(Declaration::Op(setup_op_decl(terms, indices.atom_tbl())?)), + ("non_counted_backtracking", 1) => { + let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; + Ok(Declaration::NonCountedBacktracking(name, arity)) + } ("set_prolog_flag", 2) => { Ok(Declaration::SetPrologFlag(setup_double_quotes(terms)?)) } @@ -656,27 +662,31 @@ fn setup_declaration<'a, 'b, 'c>( let mut term = *terms.pop().unwrap(); match setup_predicate_indicator(&mut term) { - Ok((name, arity)) => - Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity))), - _ => + Ok((name, arity)) => { + Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity))) + } + _ => { setup_scoped_predicate_indicator(&mut term) .map(|key| { Declaration::MultiFile(MultiFileIndicator::ModuleScoped(key)) }) + } } } - ("use_module", 1) => { - Ok(Declaration::UseModule(setup_use_module_decl(terms)?)) + ("use_module", 1) => { + Ok(Declaration::UseModule(setup_use_module_decl(terms)?)) } - ("use_module", 2) => { - let (name, exports) = setup_qualified_import(terms, indices.atom_tbl())?; - Ok(Declaration::UseQualifiedModule(name, exports)) - } - _ => { - Err(ParserError::InconsistentEntry) + ("use_module", 2) => { + let (name, exports) = setup_qualified_import(terms, indices.atom_tbl())?; + Ok(Declaration::UseQualifiedModule(name, exports)) + } + _ => { + Err(ParserError::InconsistentEntry) } - }, - _ => Err(ParserError::InconsistentEntry), + }, + _ => { + Err(ParserError::InconsistentEntry) + } } } @@ -1249,7 +1259,7 @@ impl<'a> TopLevelBatchWorker<'a> { while !self.term_stream.eof()? { let term = self.term_stream.read_term(&indices.op_dir)?; - + // if is_consistent is false, preds is non-empty. let term = if !term.is_consistent(&preds) { self.process_result(indices, &mut preds)?; diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 1ba6e07a..82ba6230 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -105,7 +105,7 @@ macro_rules! functor_term { ); (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) ); @@ -138,6 +138,9 @@ macro_rules! from_constant { &Constant::CharCode(c) => { HeapCellValue::Addr(Addr::CharCode(c)) } + &Constant::Fixnum(n) => { + HeapCellValue::Addr(Addr::Fixnum(n)) + } &Constant::Integer(ref n) => { HeapCellValue::Integer(n.clone()) } @@ -152,7 +155,7 @@ macro_rules! from_constant { 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) => { diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index d4437fdd..4f037c9a 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -30,16 +30,17 @@ ; Term = [Item] -> !, ( atom(Item) -> - ( Item == user -> - catch('$$compile_batch', E, '$print_exception_with_check'(E)) - ; consult(Item) - ) + ( Item == user -> + catch('$$compile_batch', E, '$print_exception_with_check'(E)) + ; consult(Item) + ) ; - catch(throw(error(type_error(atom, Item), repl/0)), - E, - '$print_exception_with_check'(E)) + catch(throw(error(type_error(atom, Item), repl/0)), + E, + '$print_exception_with_check'(E)) ) - ; '$submit_query_and_print_results'(Term, VarList) + ; + '$submit_query_and_print_results'(Term, VarList) ). '$submit_query_and_print_results'(Term0, VarList) :- @@ -55,10 +56,10 @@ '$needs_bracketing'(Value, Op) :- catch((functor(Value, F, _), - current_op(EqPrec, EqSpec, Op), - current_op(FPrec, _, F)), - _, - false), + current_op(EqPrec, EqSpec, Op), + current_op(FPrec, _, F)), + _, + false), ( EqPrec < FPrec -> true ; '$quoted_token'(F) -> true ; EqPrec == FPrec, @@ -225,10 +226,8 @@ ). '$gather_goals'([], VarList, Goals) :- - '$get_attr_var_queue_beyond'(0, AttrVars), '$gather_query_vars'(VarList, QueryVars), - '$call_attribute_goals'(QueryVars, AttrVars), - '$fetch_attribute_goals'(Goals). + copy_term(QueryVars, QueryVars, Goals). '$gather_goals'([Var = Value | Pairs], VarList, Goals) :- ( ( nonvar(Value) ; '$is_a_different_variable'(Pairs, Value) @@ -253,27 +252,27 @@ '$module_export'(Source, PI) :- ( nonvar(PI) -> ( PI = Name / Arity -> - ( var(Name) -> throw(error(instantiation_error, Source)) - ; integer(Arity) -> - ( \+ atom(Name) -> throw(error(type_error(atom, Name), Source)) - ; Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), Source)) - ; true - ) - ; throw(error(type_error(integer, Arity), Source)) - ) + ( var(Name) -> throw(error(instantiation_error, Source)) + ; integer(Arity) -> + ( \+ atom(Name) -> throw(error(type_error(atom, Name), Source)) + ; Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), Source)) + ; true + ) + ; throw(error(type_error(integer, Arity), Source)) + ) ; PI = op(Prec, Spec, Name) -> - ( integer(Prec) -> - ( \+ atom(Name) -> - throw(error(type_error(atom, Name), Source)) - ; Prec < 0 -> - throw(error(domain_error(not_less_than_zero, Prec), Source)) - ; Prec > 1200 -> - throw(error(domain_error(operator_precision, Prec), Source)) - ; memberchk(Spec, [xfy, yfx, xfx, fx, fy, yf, xf]) - ; throw(error(domain_error(operator_specification, Spec), Source)) - ) - ; throw(error(type_error(integer, Prec), Source)) - ) + ( integer(Prec) -> + ( \+ atom(Name) -> + throw(error(type_error(atom, Name), Source)) + ; Prec < 0 -> + throw(error(domain_error(not_less_than_zero, Prec), Source)) + ; Prec > 1200 -> + throw(error(domain_error(operator_precision, Prec), Source)) + ; memberchk(Spec, [xfy, yfx, xfx, fx, fy, yf, xf]) + ; throw(error(domain_error(operator_specification, Spec), Source)) + ) + ; throw(error(type_error(integer, Prec), Source)) + ) ; throw(error(type_error(module_export, PI), Source)) ) ; throw(error(instantiation_error, Source)) @@ -334,10 +333,10 @@ expand_goals(UnexpandedGoals, ExpandedGoals) :- ), ( Goals = (Goal0, Goals0) -> ( expand_goals(Goal0, Goal1) -> - expand_goals(Goals0, Goals1), - thread_goals(Goal1, ExpandedGoals, Goals1, (',')) + expand_goals(Goals0, Goals1), + thread_goals(Goal1, ExpandedGoals, Goals1, (',')) ; expand_goals(Goals0, Goals1), - ExpandedGoals = (Goal0, Goals1) + ExpandedGoals = (Goal0, Goals1) ) ; Goals = (Goals0 -> Goals1) -> expand_goals(Goals0, ExpandedGoals0), @@ -358,9 +357,9 @@ thread_goals(Goals0, Goals1, Hole, Functor) :- nonvar(Goals0), ( Goals0 = [G | Gs] -> ( Gs == [] -> - Goals1 =.. [Functor, G, Hole] + Goals1 =.. [Functor, G, Hole] ; Goals1 =.. [Functor, G, Goals2], - thread_goals(Gs, Goals2, Hole, Functor) + thread_goals(Gs, Goals2, Hole, Functor) ) ; Goals1 =.. [Functor, Goals0, Hole] ). @@ -369,9 +368,9 @@ thread_goals(Goals0, Goals1, Functor) :- nonvar(Goals0), ( Goals0 = [G | Gs] -> ( Gs = [] -> - Goals1 = G + Goals1 = G ; Goals1 =.. [Functor, G, Goals2], - thread_goals(Gs, Goals2, Functor) + thread_goals(Gs, Goals2, Functor) ) ; Goals1 = Goals0 ). diff --git a/src/prolog/write.rs b/src/prolog/write.rs index a1d8bb97..c44d9232 100644 --- a/src/prolog/write.rs +++ b/src/prolog/write.rs @@ -187,6 +187,7 @@ impl fmt::Display for Addr { &Addr::Char(c) => write!(f, "Addr::Char({})", c), &Addr::CharCode(c) => write!(f, "Addr::CharCode({})", c), &Addr::EmptyList => write!(f, "Addr::EmptyList"), + &Addr::Fixnum(n) => write!(f, "Addr::Fixnum({})", n), &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), @@ -305,13 +306,13 @@ impl fmt::Display for Line { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &Line::Arithmetic(ref arith_instr) => write!(f, "{}", arith_instr), - &Line::Choice(ref choice_instr) => write!(f, "{}", choice_instr), + &Line::Choice(ref choice_instr) => write!(f, "{}", choice_instr), &Line::Control(ref control_instr) => write!(f, "{}", control_instr), - &Line::Cut(ref cut_instr) => write!(f, "{}", cut_instr), + &Line::Cut(ref cut_instr) => write!(f, "{}", cut_instr), &Line::Fact(ref fact_instr) => write!(f, "{}", fact_instr), - &Line::Indexing(ref indexing_instr) => write!(f, "{}", indexing_instr), - &Line::IndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr), - &Line::Query(ref query_instr) => write!(f, "{}", query_instr), + &Line::Indexing(ref indexing_instr) => write!(f, "{}", indexing_instr), + &Line::IndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr), + &Line::Query(ref query_instr) => write!(f, "{}", query_instr), } } } @@ -319,6 +320,7 @@ impl fmt::Display for Line { impl fmt::Display for Number { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + &Number::Fixnum(n) => write!(f, "{}", n), &Number::Float(fl) => write!(f, "{}", fl), &Number::Integer(ref bi) => write!(f, "{}", bi), &Number::Rational(ref r) => write!(f, "{}", r), diff --git a/src/tests/call_with_inference_limit.pl b/src/tests/call_with_inference_limit.pl index 3cafc8b7..a1cf2a4e 100644 --- a/src/tests/call_with_inference_limit.pl +++ b/src/tests/call_with_inference_limit.pl @@ -35,7 +35,7 @@ test_queries_on_call_with_inference_limit :- [true, 2], [inference_limit_exceeded, _]]), findall([X,R1,R2], - (call_with_inference_limit(g(X), 4, R1), + (call_with_inference_limit(g(X), 4, R1), call_with_inference_limit(g(X), 5, R2)), [[1,true,!], [2,true,!], diff --git a/src/tests/facts.pl b/src/tests/facts.pl index 762fca97..98b78726 100644 --- a/src/tests/facts.pl +++ b/src/tests/facts.pl @@ -23,6 +23,6 @@ test_queries_on_facts :- retract(p(_,_,_)), assertz(p(Z, h(Z, W), f(W))), p(f(f(a)), h(f(f(a)), f(a)), f(f(a))), - retract(p(Z, h(Z, W), f(W))).[ + retract(p(Z, h(Z, W), f(W))). -:- initialization(test_queries_on_facts). +:- initialization(test_queries_on_facts). diff --git a/src/tests/rules.pl b/src/tests/rules.pl index 600daaf6..29e72cd8 100644 --- a/src/tests/rules.pl +++ b/src/tests/rules.pl @@ -62,4 +62,3 @@ cleanup :- abolish(p/3), abolish(h/1). :- initialization(test_queries_on_rules). -