From: Mark Thom Date: Mon, 13 May 2019 00:14:00 +0000 (-0400) Subject: revamp evaluable functors, add missing evaluable functors X-Git-Tag: v0.8.110~62 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=f34415032253e167283ff1812cce001e0e9d62b4;p=scryer-prolog.git revamp evaluable functors, add missing evaluable functors --- diff --git a/Cargo.toml b/Cargo.toml index 493c2f02..4fe658dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scryer-prolog" -version = "0.8.81" +version = "0.8.82" authors = ["Mark Thom "] repository = "https://github.com/mthom/scryer-prolog" description = "A modern Prolog implementation written mostly in Rust." @@ -13,11 +13,11 @@ default = ["readline_rs_compat"] cfg-if = "0.1.7" downcast = "0.10.0" indexmap = "1.0.2" -num = "0.2" ordered-float = "0.5.0" -prolog_parser = "0.8.26" +prolog_parser = "0.8.27" readline_rs_compat = { version = "0.1.9", optional = true } ref_thread_local = "0.0.0" +rug = "1.4.0" [dependencies.termion] version = "1.4.0" diff --git a/README.md b/README.md index 448836d3..e0a009ee 100644 --- a/README.md +++ b/README.md @@ -133,8 +133,12 @@ to my knowledge is not currently the case. The following predicates are built-in to Scryer. * Arithmetic support: - * `is/2` works for `(+)/2`, `(-)/{1,2}`, `(*)/2`, `(//)/2`, `(**)/2`, `(div)/2`, `(/)/2`, `(rdiv)/2`, - `(xor)/2`, `(rem)/2`, `(mod)/2`, `(/\)/2`, `(\/)/2`, `(>>)/2`, `(<<)/2`, `abs/1`. + * `is/2` works for `(+)/2`, `(-)/{1,2}`, `(*)/2`, `(//)/2`, + `(**)/2`, `(^)/2`, `(div)/2`, `(/)/2`, `(rdiv)/2`, `(xor)/2`, + `(rem)/2`, `(mod)/2`, `(/\)/2`, `(\/)/2`, `(>>)/2`,`(<<)/2`, + `(\)/1`, `abs/1`, `sin/1`, `cos/1`, `tan/1`, `asin/1`, `acos/1`, + `atan/1`, `atan2/2`, `log/1`, `exp/1`, `sqrt/1`, `float/1`, + `truncate/1`, `round/1`, `floor/1`, `ceiling/1` * Comparison operators: `>`, `<`, `=<`, `>=`, `=:=`, `=\=`. * `(:)/2` * `(@>)/2` diff --git a/src/prolog/arithmetic.rs b/src/prolog/arithmetic.rs index 09a3042d..f3b67778 100644 --- a/src/prolog/arithmetic.rs +++ b/src/prolog/arithmetic.rs @@ -6,10 +6,18 @@ use prolog::forms::*; use prolog::instructions::*; use prolog::iterators::*; +use prolog::machine::machine_errors::*; use prolog::machine::machine_indices::*; +use prolog::ordered_float::*; +use prolog::rug::{Integer, Rational}; +use prolog::rug::ops::PowAssign; + use std::cell::Cell; -use std::cmp::{min, max}; +use std::cmp::{Ordering, min, max}; +use std::f64; +use std::num::FpCategory; +use std::ops::{Add, Sub, Div, Mul, Neg}; use std::rc::Rc; use std::vec::Vec; @@ -27,17 +35,19 @@ impl<'a> ArithInstructionIterator<'a> { fn new(term: &'a Term) -> Result { let state = match term { &Term::AnonVar => - return Err(ArithmeticError::InvalidTerm), + return Err(ArithmeticError::UninstantiatedVar), &Term::Clause(ref cell, ref name, ref terms, ref fixity) => match ClauseType::from(name.clone(), terms.len(), fixity.clone()) { ct @ ClauseType::Named(..) | ct @ ClauseType::Op(..) => Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)), - _ => Err(ArithmeticError::InvalidOp) + _ => Err(ArithmeticError::NonEvaluableFunctor(Constant::Atom(name.clone(), + fixity.clone()), + terms.len())) }?, &Term::Constant(ref cell, ref cons) => TermIterState::Constant(Level::Shallow, cell, cons), &Term::Cons(_, _, _) => - return Err(ArithmeticError::InvalidTerm), + return Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2)), &Term::Var(ref cell, ref var) => TermIterState::Var(Level::Shallow, cell, var.clone()) }; @@ -61,7 +71,7 @@ impl<'a> Iterator for ArithInstructionIterator<'a> { TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)), TermIterState::Clause(lvl, child_num, cell, ct, subterms) => { - let arity = subterms.len(); + let arity = subterms.len(); if child_num == arity { return Some(Ok(ArithTermRef::Op(ct.name(), arity))); @@ -75,7 +85,7 @@ impl<'a> Iterator for ArithInstructionIterator<'a> { TermIterState::Var(_, cell, var) => return Some(Ok(ArithTermRef::Var(cell, var.clone()))), _ => - return Some(Err(ArithmeticError::InvalidTerm)) + return Some(Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))) }; } @@ -115,7 +125,23 @@ impl<'a> ArithmeticEvaluator<'a> match name.as_str() { "abs" => Ok(ArithmeticInstruction::Abs(a1, t)), "-" => Ok(ArithmeticInstruction::Neg(a1, t)), - _ => Err(ArithmeticError::InvalidOp) + "+" => Ok(ArithmeticInstruction::Plus(a1, t)), + "cos" => Ok(ArithmeticInstruction::Cos(a1, t)), + "sin" => Ok(ArithmeticInstruction::Sin(a1, t)), + "tan" => Ok(ArithmeticInstruction::Tan(a1, t)), + "log" => Ok(ArithmeticInstruction::Log(a1, t)), + "exp" => Ok(ArithmeticInstruction::Exp(a1, t)), + "sqrt" => Ok(ArithmeticInstruction::Sqrt(a1, t)), + "acos" => Ok(ArithmeticInstruction::ACos(a1, t)), + "asin" => Ok(ArithmeticInstruction::ASin(a1, t)), + "atan" => Ok(ArithmeticInstruction::ATan(a1, t)), + "float" => Ok(ArithmeticInstruction::Float(a1, t)), + "truncate" => Ok(ArithmeticInstruction::Truncate(a1, t)), + "round" => Ok(ArithmeticInstruction::Round(a1, t)), + "ceiling" => Ok(ArithmeticInstruction::Ceiling(a1, t)), + "floor" => Ok(ArithmeticInstruction::Floor(a1, t)), + "\\" => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)), + _ => Err(ArithmeticError::NonEvaluableFunctor(Constant::Atom(name, None), 1)) } } @@ -128,7 +154,8 @@ impl<'a> ArithmeticEvaluator<'a> "/" => Ok(ArithmeticInstruction::Div(a1, a2, t)), "//" => Ok(ArithmeticInstruction::IDiv(a1, a2, t)), "max" => Ok(ArithmeticInstruction::Max(a1, a2, t)), - "div" => Ok(ArithmeticInstruction::FIDiv(a1, a2, t)), + "min" => Ok(ArithmeticInstruction::Min(a1, a2, t)), + "div" => Ok(ArithmeticInstruction::IntFloorDiv(a1, a2, t)), "rdiv" => Ok(ArithmeticInstruction::RDiv(a1, a2, t)), "*" => Ok(ArithmeticInstruction::Mul(a1, a2, t)), "**" => Ok(ArithmeticInstruction::Pow(a1, a2, t)), @@ -140,7 +167,8 @@ impl<'a> ArithmeticEvaluator<'a> "xor" => Ok(ArithmeticInstruction::Xor(a1, a2, t)), "mod" => Ok(ArithmeticInstruction::Mod(a1, a2, t)), "rem" => Ok(ArithmeticInstruction::Rem(a1, a2, t)), - _ => Err(ArithmeticError::InvalidOp) + "atan2" => Ok(ArithmeticInstruction::ATan2(a1, a2, t)), + _ => Err(ArithmeticError::NonEvaluableFunctor(Constant::Atom(name, None), 2)) } } @@ -193,16 +221,20 @@ impl<'a> ArithmeticEvaluator<'a> Self::get_binary_instr(name, a1, a2, ninterm) }, - _ => Err(ArithmeticError::InvalidOp) + _ => Err(ArithmeticError::NonEvaluableFunctor(Constant::Atom(name, None), arity)) } } fn push_constant(&mut self, c: &Constant) -> Result<(), ArithmeticError> { match c { - &Constant::Number(ref n) => - self.interm.push(ArithmeticTerm::Number(n.clone())), + &Constant::Integer(ref n) => + self.interm.push(ArithmeticTerm::Number(Number::Integer(n.clone()))), + &Constant::Float(ref n) => + self.interm.push(ArithmeticTerm::Number(Number::Float(n.clone()))), + &Constant::Rational(ref n) => + self.interm.push(ArithmeticTerm::Number(Number::Rational(n.clone()))), _ => - return Err(ArithmeticError::InvalidAtom), + return Err(ArithmeticError::NonEvaluableFunctor(c.clone(), 0)) } Ok(()) @@ -240,3 +272,238 @@ impl<'a> ArithmeticEvaluator<'a> } } +// integer division rounding function -- 9.1.3.1. +pub fn rnd_i(n: Number) -> Integer { + match n { + Number::Integer(n) => n, + Number::Float(OrderedFloat(f)) => + Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0)), + Number::Rational(r) => r.fract_floor(Integer::new()).1 + } +} + +// floating point rounding function -- 9.1.4.1. +pub fn rnd_f(n: Number) -> f64 { + match n { + Number::Integer(n) => n.to_f64(), + Number::Float(OrderedFloat(f)) => f, + Number::Rational(r) => r.to_f64() + } +} + +// floating point result function -- 9.1.4.2. +pub fn result_f(n: Number, round: Round) -> Result + where Round: Fn(Number) -> f64 +{ + let f = rnd_f(n); + + match f.classify() { + FpCategory::Normal | FpCategory::Zero => + Ok(round(Number::Float(OrderedFloat(f)))), + FpCategory::Infinite => { + let f = round(Number::Float(OrderedFloat(f))); + + if OrderedFloat(f) == OrderedFloat(f64::MAX) { + Ok(f) + } else { + Err(EvalError::FloatOverflow) + } + }, + FpCategory::Nan => Err(EvalError::Undefined), + _ => Ok(round(Number::Float(OrderedFloat(f)))) + } +} + +fn float_i_to_f(n: Integer) -> Result { + result_f(Number::Integer(n), rnd_f) +} + +fn float_r_to_f(r: Rational) -> Result { + result_f(Number::Rational(r), rnd_f) +} + +fn add_f(f1: f64, f2: f64) -> Result, EvalError> { + Ok(OrderedFloat(result_f(Number::Float(OrderedFloat(f1 + f2)), rnd_f)?)) +} + +fn mul_f(f1: f64, f2: f64) -> Result, EvalError> { + Ok(OrderedFloat(result_f(Number::Float(OrderedFloat(f1 * f2)), rnd_f)?)) +} + +fn div_f(f1: f64, f2: f64) -> Result, EvalError> { + if FpCategory::Zero == f2.classify() { + Err(EvalError::ZeroDivisor) + } else { + Ok(OrderedFloat(result_f(Number::Float(OrderedFloat(f1 / f2)), rnd_f)?)) + } +} + +impl Add for Number { + type Output = Result; + + fn add(self, rhs: Number) -> Self::Output { + match (self, rhs) { + (Number::Integer(n1), Number::Integer(n2)) => + Ok(Number::Integer(n1 + n2)), // add_i + (Number::Integer(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => + Ok(Number::Float(add_f(float_i_to_f(n1)?, n2)?)), + (Number::Integer(n1), Number::Rational(n2)) + | (Number::Rational(n2), Number::Integer(n1)) => + Ok(Number::Rational(Rational::from(n1) + n2)), + (Number::Rational(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => + Ok(Number::Float(add_f(float_r_to_f(n1)?, n2)?)), + (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => + Ok(Number::Float(add_f(f1, f2)?)), + (Number::Rational(r1), Number::Rational(r2)) => + Ok(Number::Rational(r1 + r2)) + } + } +} + +impl Neg for Number { + type Output = Number; + + fn neg(self) -> Self::Output { + match self { + Number::Integer(n) => Number::Integer(-n), + Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)), + Number::Rational(r) => Number::Rational(-r) + } + } +} + +impl Sub for Number { + type Output = Result; + + fn sub(self, rhs: Number) -> Self::Output { + self.add(-rhs) + } +} + +impl Mul for Number { + type Output = Result; + + fn mul(self, rhs: Number) -> Self::Output { + match (self, rhs) { + (Number::Integer(n1), Number::Integer(n2)) => + Ok(Number::Integer(n1 * n2)), // mul_i + (Number::Integer(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => + Ok(Number::Float(mul_f(float_i_to_f(n1)?, n2)?)), + (Number::Integer(n1), Number::Rational(n2)) + | (Number::Rational(n2), Number::Integer(n1)) => + Ok(Number::Rational(Rational::from(n1) * n2)), + (Number::Rational(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => + Ok(Number::Float(mul_f(float_r_to_f(n1)?, n2)?)), + (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => + Ok(Number::Float(mul_f(f1, f2)?)), + (Number::Rational(r1), Number::Rational(r2)) => + Ok(Number::Rational(r1 * r2)) + } + } +} + +impl Div for Number { + type Output = Result; + + 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::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::Rational(n1), Number::Float(OrderedFloat(n2))) => + Ok(Number::Float(div_f(float_r_to_f(n1)?, n2)?)), + (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => + Ok(Number::Float(div_f(n2, float_r_to_f(n1)?)?)), + (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => + Ok(Number::Float(div_f(f1, f2)?)), + (Number::Rational(r1), Number::Rational(r2)) => + Ok(Number::Float(div_f(float_r_to_f(r1)?, float_r_to_f(r2)?)?)) + } + } +} + +impl PartialOrd for Number { + fn partial_cmp(&self, rhs: &Number) -> Option { + 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)) + } + } +} + +impl Ord for Number { + fn cmp(&self, rhs: &Number) -> Ordering { + match (self, rhs) { + (&Number::Integer(ref n1), &Number::Integer(ref n2)) => + n1.cmp(n2), + (&Number::Integer(_), Number::Float(_)) => + Ordering::Greater, + (&Number::Float(_), &Number::Integer(_)) => + Ordering::Less, + (&Number::Integer(_), &Number::Rational(_)) => + Ordering::Greater, + (&Number::Rational(_), &Number::Integer(_)) => + Ordering::Less, + (&Number::Rational(_), Number::Float(_)) => + Ordering::Greater, + (&Number::Float(_), &Number::Rational(_)) => + Ordering::Less, + (&Number::Float(f1), &Number::Float(f2)) => + f1.cmp(&f2), + (&Number::Rational(ref r1), &Number::Rational(ref r2)) => + r1.cmp(&r2) + } + } +} + +// Computes n ^ power. Ignores the sign of power. +pub fn binary_pow(mut n: Integer, power: Integer) -> Integer +{ + let one = Integer::from(1); + + let mut power = power.abs(); + + if power == Integer::from(0) { + return Integer::from(1); + } + + let mut oddand = Integer::from(1); + + while power > one { + if power.is_odd() { + oddand *= &n; + } + + n.pow_assign(2); + power >>= 1; + } + + n * oddand +} diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index 5a5c67b2..773dc5e0 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -1,12 +1,13 @@ use prolog_parser::ast::*; +use prolog::forms::Number; use prolog::machine::machine_indices::*; use ref_thread_local::RefThreadLocal; use std::collections::BTreeMap; -#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Clone, Copy, Eq, PartialEq)] pub enum CompareNumberQT { GreaterThan, LessThan, @@ -29,7 +30,7 @@ impl CompareNumberQT { } } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum CompareTermQT { LessThan, LessThanOrEqual, @@ -48,7 +49,7 @@ impl CompareTermQT { } } -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, PartialEq, Eq)] pub enum ArithmeticTerm { Reg(RegType), Interm(usize), @@ -65,7 +66,7 @@ impl ArithmeticTerm { } } -#[derive(Clone, Eq, Ord, PartialOrd, PartialEq)] +#[derive(Clone, Eq, PartialEq)] pub enum InlinedClauseType { CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm), IsAtom(RegType), @@ -147,7 +148,7 @@ impl InlinedClauseType { } } -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Copy, Clone, Eq, PartialEq)] pub enum SystemClauseType { AbolishClause, AbolishModuleClause, @@ -416,7 +417,7 @@ impl SystemClauseType { } } -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Clone, Eq, PartialEq)] pub enum BuiltInClauseType { AcyclicTerm, Arg, @@ -436,7 +437,7 @@ pub enum BuiltInClauseType { Sort, } -#[derive(Clone, PartialEq, Eq, Ord, PartialOrd)] +#[derive(Clone, PartialEq, Eq)] pub enum ClauseType { BuiltIn(BuiltInClauseType), CallN, diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index ad2d8f7b..851f46a9 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -305,13 +305,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator match ct { &InlinedClauseType::CompareNumber(cmp, ..) => { if let &Term::Var(ref vr, ref name) = terms[0].as_ref() { - self.mark_non_callable(name.clone(), 2, term_loc, vr, code); + self.mark_non_callable(name.clone(), 2, term_loc, vr, code); } if let &Term::Var(ref vr, ref name) = terms[1].as_ref() { - self.mark_non_callable(name.clone(), 2, term_loc, vr, code); + self.mark_non_callable(name.clone(), 2, term_loc, vr, code); } - + let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?; let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?; @@ -365,7 +365,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator }, &InlinedClauseType::IsRational(..) => match terms[0].as_ref() { - &Term::Constant(_, Constant::Number(Number::Rational(_))) => { + &Term::Constant(_, Constant::Rational(_)) => { code.push(succeed!()); }, &Term::Var(ref vr, ref name) => { @@ -378,7 +378,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator }, &InlinedClauseType::IsFloat(..) => match terms[0].as_ref() { - &Term::Constant(_, Constant::Number(Number::Float(_))) => { + &Term::Constant(_, Constant::Float(_)) => { code.push(succeed!()); }, &Term::Var(ref vr, ref name) => { @@ -418,7 +418,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator &InlinedClauseType::IsInteger(..) => match terms[0].as_ref() { &Term::Constant(_, Constant::CharCode(_)) - | &Term::Constant(_, Constant::Number(Number::Integer(_))) => { + | &Term::Constant(_, Constant::Integer(_)) => { code.push(succeed!()); }, &Term::Var(ref vr, ref name) => { @@ -486,7 +486,25 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1)))) } }, - &Term::Constant(_, ref c @ Constant::Number(_)) => { + &Term::Constant(_, ref c @ Constant::Integer(_)) => { + code.push(Line::Query(put_constant!(Level::Shallow, c.clone(), temp_v!(1)))); + + if use_default_call_policy { + code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1)))) + } else { + code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1)))) + } + }, + &Term::Constant(_, ref c @ Constant::Float(_)) => { + code.push(Line::Query(put_constant!(Level::Shallow, c.clone(), temp_v!(1)))); + + if use_default_call_policy { + code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1)))) + } else { + code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1)))) + } + }, + &Term::Constant(_, ref c @ Constant::Rational(_)) => { code.push(Line::Query(put_constant!(Level::Shallow, c.clone(), temp_v!(1)))); if use_default_call_policy { diff --git a/src/prolog/forms.rs b/src/prolog/forms.rs index e6168f36..cb2c7a87 100644 --- a/src/prolog/forms.rs +++ b/src/prolog/forms.rs @@ -5,6 +5,8 @@ use prolog_parser::tabled_rc::*; use prolog::clause_types::*; use prolog::machine::machine_errors::*; use prolog::machine::machine_indices::*; +use prolog::ordered_float::OrderedFloat; +use prolog::rug::{Integer, Rational}; use std::cell::Cell; use std::collections::{HashMap, VecDeque}; @@ -288,3 +290,62 @@ pub struct Module { pub user_goal_expansions: (Predicate, VecDeque), // same for goal_expansions. pub inserted_expansions: bool // has the module been successfully inserted into toplevel?? } + +#[derive(Clone, PartialEq, Eq)] +pub enum Number { + Float(OrderedFloat), + Integer(Integer), + Rational(Rational) +} + +impl Default for Number { + fn default() -> Self { + Number::Float(OrderedFloat(0f64)) + } +} + +impl Number { + pub fn to_constant(self) -> Constant { + match self { + Number::Integer(n) => Constant::Integer(n), + Number::Float(f) => Constant::Float(f), + Number::Rational(r) => Constant::Rational(r) + } + } + + #[inline] + pub fn is_positive(&self) -> bool { + match self { + &Number::Integer(ref n) => n > &0, + &Number::Float(OrderedFloat(f)) => f.is_sign_positive(), + &Number::Rational(ref r) => r > &0 + } + } + + #[inline] + pub fn is_negative(&self) -> bool { + match self { + &Number::Integer(ref n) => n < &0, + &Number::Float(OrderedFloat(f)) => f.is_sign_negative(), + &Number::Rational(ref r) => r < &0 + } + } + + #[inline] + pub fn is_zero(&self) -> bool { + match self { + &Number::Integer(ref n) => n == &0, + &Number::Float(f) => f == OrderedFloat(0f64), + &Number::Rational(ref r) => r == &0 + } + } + + #[inline] + pub fn abs(self) -> Self { + match self { + Number::Integer(n) => Number::Integer(n.abs()), + Number::Float(f) => Number::Float(OrderedFloat(f.abs())), + Number::Rational(r) => Number::Rational(r.abs()) + } + } +} diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 83c4887d..8136c75f 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -2,12 +2,12 @@ use prolog_parser::ast::*; use prolog_parser::string_list::*; use prolog::clause_types::*; -use prolog::forms::{fetch_atom_op_spec, fetch_op_spec}; +use prolog::forms::*; use prolog::heap_iter::*; use prolog::machine::machine_indices::*; use prolog::machine::machine_state::*; -use prolog::num::*; use prolog::ordered_float::OrderedFloat; +use prolog::rug::{Integer}; use std::cell::Cell; use std::collections::{HashMap, HashSet}; @@ -112,8 +112,12 @@ impl<'a> HCPreOrderIterator<'a> { _ => return false }, - Addr::Con(Constant::Number(n)) => - return property_check(Constant::Number(n)), + Addr::Con(Constant::Integer(n)) => + return property_check(Constant::Integer(n)), + Addr::Con(Constant::Float(n)) => + return property_check(Constant::Float(n)), + Addr::Con(Constant::Rational(n)) => + return property_check(Constant::Rational(n)), _ => return false } @@ -253,7 +257,9 @@ fn negated_op_needs_bracketing(iter: &HCPreOrderIterator, op: &Option n.is_positive(), + Constant::Integer(n) => n > 0, + Constant::Float(f) => f > OrderedFloat(0f64), + Constant::Rational(r) => r > 0, _ => false } }) @@ -263,20 +269,21 @@ fn negated_op_needs_bracketing(iter: &HCPreOrderIterator, op: &Option Option { + pub fn numbervar(&self, offset: &Integer, addr: Addr) -> Option { static CHAR_CODES: [char; 26] = ['A','B','C','D','E','F','G','H','I','J', 'K','L','M','N','O','P','Q','R','S','T', 'U','V','W','X','Y','Z']; match self.store(self.deref(addr)) { - Addr::Con(Constant::Number(Number::Integer(ref n))) - if !n.is_negative() => { - let n = offset + n.as_ref(); - - let i = n.mod_floor(&BigInt::from(26)).to_usize().unwrap(); - let j = n.div_floor(&BigInt::from(26)); - - Some(if j.is_zero() { + Addr::Con(Constant::Integer(ref n)) + if n >= &0 => { + let n = Integer::from(offset + n); + + let i = n.mod_u(26) as usize; + let j = n.div_rem_floor(Integer::from(26)); + let j = <(Integer, Integer)>::from(j).1; + + Some(if j == 0 { CHAR_CODES[i].to_string() } else { format!("{}{}", CHAR_CODES[i], j) @@ -300,7 +307,7 @@ pub struct HCPrinter<'a, Outputter> { last_item_idx: usize, cyclic_terms: HashMap, pub(crate) var_names: HashMap, - pub(crate) numbervars_offset: BigInt, + pub(crate) numbervars_offset: Integer, pub(crate) numbervars: bool, pub(crate) quoted: bool, pub(crate) ignore_ops: bool @@ -389,7 +396,7 @@ fn non_quoted_token>(mut iter: Iter) -> bool { } else if c == '{' { (iter.next() == Some('}') && iter.next().is_none()) } else if solo_char!(c) { - false + !(c == ')' || c == '}' || c == ']' || c == ',' || c == '%' || c == '|') } else { false } @@ -411,7 +418,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> printed_vars: HashSet::new(), last_item_idx: 0, numbervars: false, - numbervars_offset: BigInt::zero(), + numbervars_offset: Integer::from(0), quoted: false, ignore_ops: false, cyclic_terms: HashMap::new(), @@ -577,7 +584,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> self.last_item_idx = self.outputter.len(); self.outputter.append(s); } - + fn offset_as_string(&self, iter: &mut HCPreOrderIterator, addr: Addr) -> Option { if let Some(var) = self.var_names.get(&addr) { @@ -781,8 +788,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> self.append_str(&format!("{}", c)), Constant::EmptyList => self.append_str("[]"), - Constant::Number(n) => - self.print_number(n, op), + Constant::Integer(n) => + self.print_number(Number::Integer(n), op), + Constant::Float(n) => + self.print_number(Number::Float(n), op), + Constant::Rational(n) => + self.print_number(Number::Rational(n), op), Constant::String(s) => self.print_string(s), Constant::Usize(i) => @@ -837,7 +848,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> if self.numbervars && arity == 1 && name.as_str() == "$VAR" { !iter.immediate_leaf_has_property(|c| { match c { - Constant::Number(n) => n.is_zero() || n.is_positive(), + Constant::Integer(n) => n >= 0, + Constant::Float(f) => f >= OrderedFloat(0f64), + Constant::Rational(r) => r >= 0, _ => false } }) && needs_bracketing(&spec, op) diff --git a/src/prolog/instructions.rs b/src/prolog/instructions.rs index 6b613d3c..3b639ce5 100644 --- a/src/prolog/instructions.rs +++ b/src/prolog/instructions.rs @@ -73,7 +73,8 @@ pub enum ArithmeticInstruction { IntPow(ArithmeticTerm, ArithmeticTerm, usize), IDiv(ArithmeticTerm, ArithmeticTerm, usize), Max(ArithmeticTerm, ArithmeticTerm, usize), - FIDiv(ArithmeticTerm, ArithmeticTerm, usize), + Min(ArithmeticTerm, ArithmeticTerm, usize), + IntFloorDiv(ArithmeticTerm, ArithmeticTerm, usize), RDiv(ArithmeticTerm, ArithmeticTerm, usize), Div(ArithmeticTerm, ArithmeticTerm, usize), Shl(ArithmeticTerm, ArithmeticTerm, usize), @@ -83,8 +84,25 @@ pub enum ArithmeticInstruction { Or(ArithmeticTerm, ArithmeticTerm, usize), Mod(ArithmeticTerm, ArithmeticTerm, usize), Rem(ArithmeticTerm, ArithmeticTerm, usize), + Cos(ArithmeticTerm, usize), + Sin(ArithmeticTerm, usize), + Tan(ArithmeticTerm, usize), + Log(ArithmeticTerm, usize), + Exp(ArithmeticTerm, usize), + ACos(ArithmeticTerm, usize), + ASin(ArithmeticTerm, usize), + ATan(ArithmeticTerm, usize), + ATan2(ArithmeticTerm, ArithmeticTerm, usize), + Sqrt(ArithmeticTerm, usize), Abs(ArithmeticTerm, usize), + Float(ArithmeticTerm, usize), + Truncate(ArithmeticTerm, usize), + Round(ArithmeticTerm, usize), + Ceiling(ArithmeticTerm, usize), + Floor(ArithmeticTerm, usize), Neg(ArithmeticTerm, usize), + Plus(ArithmeticTerm, usize), + BitwiseComplement(ArithmeticTerm, usize) } pub enum ControlInstruction { diff --git a/src/prolog/machine/dynamic_database.rs b/src/prolog/machine/dynamic_database.rs index ac6ba36a..d2dff3ba 100644 --- a/src/prolog/machine/dynamic_database.rs +++ b/src/prolog/machine/dynamic_database.rs @@ -4,7 +4,6 @@ use prolog::heap_print::*; use prolog::machine::*; use prolog::machine::compile::*; use prolog::machine::machine_errors::*; -use prolog::num::ToPrimitive; use std::io::Read; @@ -47,7 +46,7 @@ impl Machine { }; let arity = match self.machine_st.store(self.machine_st.deref(arity)) { - Addr::Con(Constant::Number(Number::Integer(arity))) => + Addr::Con(Constant::Integer(arity)) => arity.to_usize().unwrap(), _ => unreachable!() }; @@ -192,7 +191,7 @@ 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(Constant::Number(Number::Integer(n))) => n.to_usize().unwrap(), + Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(), _ => unreachable!() }; @@ -227,7 +226,7 @@ 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(Constant::Number(Number::Integer(n))) => n.to_usize().unwrap(), + Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(), _ => unreachable!() }; diff --git a/src/prolog/machine/machine_errors.rs b/src/prolog/machine/machine_errors.rs index c2a7e336..34011f69 100644 --- a/src/prolog/machine/machine_errors.rs +++ b/src/prolog/machine/machine_errors.rs @@ -3,9 +3,7 @@ use prolog_parser::string_list::*; use prolog::machine::machine_indices::*; use prolog::machine::machine_state::*; -use prolog::num::bigint::BigInt; - -use std::rc::Rc; +use prolog::rug::Integer; pub(super) type MachineStub = Vec; @@ -23,7 +21,7 @@ pub(super) struct MachineError { impl MachineError { pub(super) fn functor_stub(name: ClauseName, arity: usize) -> MachineStub { let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name, None))); - functor!("/", 2, [name, heap_integer!(arity)], SharedOpDesc::new(400, YFX)) + functor!("/", 2, [name, heap_integer!(Integer::from(arity))], SharedOpDesc::new(400, YFX)) } pub(super) fn evaluation_error(eval_error: EvalError) -> Self { @@ -47,7 +45,7 @@ impl MachineError { let mut stub = functor!("evaluation_error", 1, [HeapCellValue::Addr(Addr::HeapCell(h + 2))]); stub.append(&mut functor!("/", 2, [HeapCellValue::Addr(Addr::HeapCell(h + 2 + 3)), - heap_integer!(arity)], + heap_integer!(Integer::from(arity))], SharedOpDesc::new(400, YFX))); stub.append(&mut functor!(":", 2, [mod_name, name], SharedOpDesc::new(600, XFY))); @@ -99,7 +97,28 @@ impl MachineError { MachineError { stub, from: ErrorProvenance::Constructed } } + fn arithmetic_error(h: usize, err: ArithmeticError) -> Self { + match err { + ArithmeticError::UninstantiatedVar => + Self::instantiation_error(), + ArithmeticError::NonEvaluableFunctor(name, arity) => { + let name = HeapCellValue::Addr(Addr::Con(name)); + let culprit = functor!("/", 2, [name, heap_integer!(Integer::from(arity))], + SharedOpDesc::new(400, YFX)); + + let mut stub = Self::type_error(ValidType::Evaluable, Addr::HeapCell(3+h)).stub; + stub.extend(culprit.into_iter()); + + MachineError { stub, from: ErrorProvenance::Constructed } + } + } + } + pub(super) fn syntax_error(h: usize, err: ParserError) -> Self { + if let ParserError::Arithmetic(err) = err { + return Self::arithmetic_error(h, err); + } + let err = vec![heap_atom!(err.as_str())]; let mut stub = if err.len() == 1 { @@ -175,7 +194,8 @@ pub enum ValidType { Callable, Character, Compound, -// Evaluable, + Evaluable, + Float, // InByte, // InCharacter, Integer, @@ -196,7 +216,8 @@ impl ValidType { ValidType::Callable => "callable", ValidType::Character => "character", ValidType::Compound => "compound", -// ValidType::Evaluable => "evaluable", + ValidType::Evaluable => "evaluable", + ValidType::Float => "float", // ValidType::InByte => "in_byte", // ValidType::InCharacter => "in_character", ValidType::Integer => "integer", @@ -249,21 +270,19 @@ impl RepFlag { // from 7.12.2 g) of 13211-1:1995 #[derive(Clone, Copy)] pub enum EvalError { -// FloatOverflow, -// Undefined, -// FloatUnderflow, + FloatOverflow, + Undefined, +// Underflow, ZeroDivisor, - NoRoots } impl EvalError { pub fn as_str(self) -> &'static str { match self { -// EvalError::FloatOverflow => "float_overflow", -// EvalError::Undefined => "undefined", + EvalError::FloatOverflow => "float_overflow", + EvalError::Undefined => "undefined", // EvalError::FloatUnderflow => "underflow", EvalError::ZeroDivisor => "zero_divisor", - EvalError::NoRoots => "no_roots" } } } diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index c9e32951..cafd9136 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -11,8 +11,8 @@ use prolog::machine::machine_errors::*; use prolog::machine::machine_indices::*; use prolog::machine::modules::*; use prolog::machine::or_stack::*; -use prolog::num::{BigInt, BigUint, One, ToPrimitive, Zero}; use prolog::read::PrologStream; +use prolog::rug::Integer; use downcast::Any; @@ -20,7 +20,6 @@ use std::cmp::Ordering; use std::io::{Write, stdout}; use std::mem; use std::ops::{Index, IndexMut}; -use std::rc::Rc; pub(super) struct Ball { pub(super) boundary: usize, // ball.0 @@ -288,7 +287,7 @@ impl MachineState { }, &Addr::Con(Constant::CharCode(c)) => codes.push(c), - &Addr::Con(Constant::Number(Number::Integer(ref n))) => + &Addr::Con(Constant::Integer(ref n)) => if let Some(c) = n.to_u8() { codes.push(c); } else { @@ -741,7 +740,7 @@ pub(crate) trait CallPolicy: Any { let a1 = machine_st[r].clone(); let a2 = machine_st.get_number(at)?; - machine_st.unify(a1, Addr::Con(Constant::Number(a2))); + machine_st.unify(a1, Addr::Con(a2.to_constant())); return_from_clause!(machine_st.last_call, machine_st) }, } @@ -875,8 +874,8 @@ impl CallPolicy for DefaultCallPolicy {} pub(crate) struct CWILCallPolicy { pub(crate) prev_policy: Box, - count: BigUint, - limits: Vec<(BigUint, usize)>, + count: Integer, + limits: Vec<(Integer, usize)>, inference_limit_exceeded: bool } @@ -887,7 +886,7 @@ impl CWILCallPolicy { mem::swap(&mut prev_policy, policy); let new_policy = CWILCallPolicy { prev_policy, - count: BigUint::zero(), + count: Integer::from(0), limits: vec![], inference_limit_exceeded: false }; *policy = Box::new(new_policy); @@ -904,35 +903,32 @@ impl CWILCallPolicy { return Err(functor!("inference_limit_exceeded", 1, [HeapCellValue::Addr(Addr::Con(Constant::Usize(bp)))])); } else { - self.count += BigUint::one(); + self.count += 1; } } Ok(()) } - pub(crate) fn add_limit(&mut self, limit: Rc, b: usize) -> Rc { - let limit = match limit.to_biguint() { - Some(limit) => limit + &self.count, - None => panic!("install_inference_counter: limit must be positive") - }; + pub(crate) fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer { + limit += &self.count; match self.limits.last().cloned() { Some((ref inner_limit, _)) if *inner_limit <= limit => {}, _ => self.limits.push((limit, b)) }; - Rc::new(BigInt::from(self.count.clone())) + &self.count } - pub(crate) fn remove_limit(&mut self, b: usize) -> Rc { + pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer { if let Some((_, bp)) = self.limits.last().cloned() { if bp == b { self.limits.pop(); } } - Rc::new(BigInt::from(self.count.clone())) + &self.count } pub(crate) fn is_empty(&self) -> bool { diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index f790b980..cd2c9214 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -2,6 +2,7 @@ use prolog_parser::ast::*; use prolog_parser::string_list::StringList; use prolog_parser::tabled_rc::*; +use prolog::arithmetic::*; use prolog::clause_types::*; use prolog::forms::*; use prolog::heap_iter::*; @@ -15,16 +16,27 @@ use prolog::machine::or_stack::*; use prolog::machine::machine_errors::*; use prolog::machine::machine_indices::*; use prolog::machine::machine_state::*; -use prolog::num::{Integer, Signed, ToPrimitive, One, Zero}; -use prolog::num::bigint::{BigInt, BigUint}; -use prolog::num::rational::Ratio; +use prolog::ordered_float::*; +use prolog::rug::{Integer, Rational}; use prolog::read::PrologStream; -use std::cmp::{max, Ordering}; +use std::cmp::{min, max, Ordering}; use std::collections::{HashMap, HashSet}; +use std::f64; use std::mem; use std::rc::Rc; +macro_rules! try_numeric_result { + ($s: ident, $e: expr, $caller: expr) => {{ + match $e { + Ok(val) => + Ok(val), + Err(e) => + Err($s.error_form(MachineError::evaluation_error(e), $caller)) + } + }} +} + macro_rules! try_or_fail { ($s:ident, $e:expr) => {{ match $e { @@ -328,7 +340,7 @@ impl MachineState { stepper(c as char); return true; }, - HeapCellValue::Addr(Addr::Con(Constant::Number(Number::Integer(n)))) => + HeapCellValue::Addr(Addr::Con(Constant::Integer(n))) => if let Some(c) = n.to_u8() { self.pstr_trail(prev_s); stepper(c as char); @@ -343,7 +355,7 @@ impl MachineState { fn bind_with_occurs_check(&mut self, r: Ref, addr: Addr) { let mut fail = false; - + for value in self.acyclic_pre_order_iter(addr.clone()) { if let HeapCellValue::Addr(addr) = value { if let Some(inner_r) = addr.as_var() { @@ -355,14 +367,14 @@ impl MachineState { } } - self.fail = fail; + self.fail = fail; self.bind(r, addr); } pub(super) fn unify_with_occurs_check(&mut self, a1: Addr, a2: Addr) { let mut pdl = vec![a1, a2]; let mut tabu_list: HashSet<(Addr, Addr)> = HashSet::new(); - + self.fail = false; while !(pdl.is_empty() || self.fail) { @@ -378,7 +390,7 @@ impl MachineState { } else { tabu_list.insert((d1.clone(), d2.clone())); } - + match (d1.clone(), d2.clone()) { (Addr::AttrVar(h), addr) | (addr, Addr::AttrVar(h)) => self.bind_with_occurs_check(Ref::AttrVar(h), addr), @@ -463,11 +475,11 @@ impl MachineState { } } } - + pub(super) fn unify(&mut self, a1: Addr, a2: Addr) { let mut pdl = vec![a1, a2]; let mut tabu_list: HashSet<(Addr, Addr)> = HashSet::new(); - + self.fail = false; while !(pdl.is_empty() || self.fail) { @@ -483,7 +495,7 @@ impl MachineState { } else { tabu_list.insert((d1.clone(), d2.clone())); } - + match (d1.clone(), d2.clone()) { (Addr::AttrVar(h), addr) | (addr, Addr::AttrVar(h)) => self.bind(Ref::AttrVar(h), addr), @@ -816,48 +828,34 @@ impl MachineState { &ArithmeticTerm::Reg(r) => self.arith_eval_by_metacall(r), &ArithmeticTerm::Interm(i) => - Ok(mem::replace(&mut self.interms[i-1], Number::Integer(Rc::new(BigInt::zero())))), + Ok(mem::replace(&mut self.interms[i-1], Number::Integer(Integer::from(0)))), &ArithmeticTerm::Number(ref n) => Ok(n.clone()), } } - fn rational_from_number(&self, n: Number, caller: &MachineStub) - -> Result>, MachineStub> + fn rational_from_number(&self, n: Number, caller: &MachineStub) -> Result { match n { Number::Rational(r) => Ok(r), - Number::Float(fl) => - if let Some(r) = Ratio::from_float(fl.into_inner()) { - Ok(Rc::new(r)) - } else { - Err(self.error_form(MachineError::instantiation_error(), caller.clone())) - }, - Number::Integer(bi) => - Ok(Rc::new(Ratio::from_integer((*bi).clone()))) + Number::Float(OrderedFloat(f)) => + Rational::from_f64(f).ok_or_else(|| { + self.error_form(MachineError::instantiation_error(), caller.clone()) + }), + Number::Integer(n) => + Ok(Rational::from(n)) } } fn get_rational(&mut self, at: &ArithmeticTerm, caller: &MachineStub) - -> Result>, MachineStub> + -> Result { let n = self.get_number(at)?; self.rational_from_number(n, caller) } - fn signed_bitwise_op(&self, n1: &BigInt, n2: &BigInt, f: Op) -> Rc - where Op: FnOnce(&BigUint, &BigUint) -> BigUint - { - let n1_b = n1.to_signed_bytes_le(); - let n2_b = n2.to_signed_bytes_le(); - - let u_n1 = BigUint::from_bytes_le(&n1_b); - let u_n2 = BigUint::from_bytes_le(&n2_b); - - Rc::new(BigInt::from_signed_bytes_le(&f(&u_n1, &u_n2).to_bytes_le())) - } - - pub(super) fn arith_eval_by_metacall(&self, r: RegType) -> Result + pub(super) + fn arith_eval_by_metacall(&self, r: RegType) -> Result { let a = self[r].clone(); @@ -871,13 +869,14 @@ impl MachineState { let a1 = interms.pop().unwrap(); match name.as_str() { - "+" => interms.push(a1 + a2), - "-" => interms.push(a1 - a2), - "*" => interms.push(a1 * a2), + "+" => interms.push(try_numeric_result!(self, a1 + a2, caller.clone())?), + "-" => interms.push(try_numeric_result!(self, a1 - a2, caller.clone())?), + "*" => interms.push(try_numeric_result!(self, a1 * a2, caller.clone())?), "/" => interms.push(self.div(a1, a2)?), - "**" => interms.push(self.pow(a1, a2)?), - "^" => interms.push(self.binary_pow(a1, a2)?), + "**" => interms.push(self.pow(a1, a2, "(is)")?), + "^" => interms.push(self.int_pow(a1, a2)?), "max" => interms.push(self.max(a1, a2)?), + "min" => interms.push(self.min(a1, a2)?), "rdiv" => { let r1 = self.rational_from_number(a1, &caller)?; let r2 = self.rational_from_number(a2, &caller)?; @@ -886,7 +885,7 @@ impl MachineState { interms.push(result) }, "//" => interms.push(Number::Integer(self.idiv(a1, a2)?)), - "div" => interms.push(Number::Integer(self.fidiv(a1, a2)?)), + "div" => interms.push(Number::Integer(self.int_floor_div(a1, a2)?)), ">>" => interms.push(Number::Integer(self.shr(a1, a2)?)), "<<" => interms.push(Number::Integer(self.shl(a1, a2)?)), "/\\" => interms.push(Number::Integer(self.and(a1, a2)?)), @@ -894,6 +893,7 @@ impl MachineState { "xor" => interms.push(Number::Integer(self.xor(a1, a2)?)), "mod" => interms.push(Number::Integer(self.modulus(a1, a2)?)), "rem" => interms.push(Number::Integer(self.remainder(a1, a2)?)), + "atan2" => interms.push(Number::Float(OrderedFloat(self.atan2(a1, a2)?))), _ => return Err(self.error_form(MachineError::instantiation_error(), caller)) } @@ -902,13 +902,34 @@ impl MachineState { let a1 = interms.pop().unwrap(); match name.as_str() { - "-" => interms.push(- a1), - _ => return Err(self.error_form(MachineError::instantiation_error(), - caller)) + "-" => interms.push(- a1), + "+" => interms.push(a1), + "cos" => interms.push(Number::Float(OrderedFloat(self.cos(a1)?))), + "sin" => interms.push(Number::Float(OrderedFloat(self.sin(a1)?))), + "tan" => interms.push(Number::Float(OrderedFloat(self.tan(a1)?))), + "sqrt" => interms.push(Number::Float(OrderedFloat(self.sqrt(a1)?))), + "log" => interms.push(Number::Float(OrderedFloat(self.log(a1)?))), + "exp" => interms.push(Number::Float(OrderedFloat(self.exp(a1)?))), + "acos" => interms.push(Number::Float(OrderedFloat(self.acos(a1)?))), + "asin" => interms.push(Number::Float(OrderedFloat(self.asin(a1)?))), + "atan" => interms.push(Number::Float(OrderedFloat(self.atan(a1)?))), + "abs" => interms.push(a1.abs()), + "float" => interms.push(Number::Float(OrderedFloat(self.float(a1)?))), + "truncate" => interms.push(Number::Integer(self.truncate(a1))), + "round" => interms.push(Number::Integer(self.round(a1)?)), + "ceiling" => interms.push(Number::Integer(self.ceiling(a1))), + "floor" => interms.push(Number::Integer(self.floor(a1))), + "\\" => interms.push(Number::Integer(self.bitwise_complement(a1)?)), + _ => return Err(self.error_form(MachineError::instantiation_error(), + caller)) } }, - HeapCellValue::Addr(Addr::Con(Constant::Number(n))) => - interms.push(n), + HeapCellValue::Addr(Addr::Con(Constant::Integer(n))) => + interms.push(Number::Integer(n)), + HeapCellValue::Addr(Addr::Con(Constant::Float(n))) => + interms.push(Number::Float(n)), + HeapCellValue::Addr(Addr::Con(Constant::Rational(n))) => + interms.push(Number::Rational(n)), _ => return Err(self.error_form(MachineError::instantiation_error(), caller)) } @@ -917,58 +938,46 @@ impl MachineState { Ok(interms.pop().unwrap()) } - fn rdiv(&self, r1: Rc>, r2: Rc>) - -> Result>, MachineStub> + fn rdiv(&self, r1: Rational, r2: Rational) -> Result { let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2); - if *r2 == Ratio::zero() { + if r2 == 0 { Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { - Ok(Rc::new(&*r1 / &*r2)) + Ok(r1 / r2) } } - fn fidiv(&self, n1: Number, n2: Number) -> Result, MachineStub> + fn int_floor_div(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(div)"), 2); - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => - if *n2 == BigInt::zero() { - Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Rc::new(n1.div_floor(&n2))) - }, - (Number::Integer(_), n2) => - Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n2))), - stub)), - (n1, _) => - Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n1))), - stub)) + match n1 / n2 { + Ok(result) => Ok(rnd_i(result)), + Err(e) => Err(self.error_form(MachineError::evaluation_error(e), stub)) } } - fn idiv(&self, n1: Number, n2: Number) -> Result, MachineStub> + fn idiv(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(//)"), 2); match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => - if *n2 == BigInt::zero() { - Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) + if n2 == 0 { + Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), + stub)) } else { - Ok(Rc::new(&*n1 / &*n2)) + Ok(n1.div_rem(n2).0) }, (Number::Integer(_), n2) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n2))), + Addr::Con(n2.to_constant())), stub)), (n1, _) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n1))), + Addr::Con(n1.to_constant())), stub)) } } @@ -980,133 +989,299 @@ impl MachineState { if n2.is_zero() { Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { - Ok(n1 / n2) + try_numeric_result!(self, n1 / n2, stub) } } - fn binary_pow(&self, n1: Number, n2: Number) -> Result + fn atan2(&self, n1: Number, n2: Number) -> Result { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + + if n1.is_zero() && n2.is_zero() { + Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)) + } else { + let f1 = self.float(n1)?; + let f2 = self.float(n2)?; + + self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.atan2(f2)) + } + } + + fn int_pow(&self, n1: Number, n2: Number) -> Result + { + if n1.is_zero() && n2.is_negative() { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); + } + match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => - self.pow(Number::Integer(n1), Number::Integer(n2)), - (Number::Integer(_), n) | (n, _) => { - let n = Addr::Con(Constant::Number(n)); - let stub = MachineError::functor_stub(clause_name!("^"), 2); + if n1 != 1 && n2 < 0 { + let n = Addr::Con(Constant::Integer(n1)); + let stub = MachineError::functor_stub(clause_name!("^"), 2); + + Err(self.error_form(MachineError::type_error(ValidType::Float, n), stub)) + } else { + Ok(Number::Integer(binary_pow(n1, n2))) + }, + (n1, Number::Integer(n2)) => { + let f1 = self.float(n1)?; + let f2 = self.float(Number::Integer(n2))?; + + self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) + .map(|f| Number::Float(OrderedFloat(f))) + }, + (n1, n2) => { + let f2 = self.float(n2)?; - Err(self.error_form(MachineError::type_error(ValidType::Integer, n), stub)) + if n1.is_negative() && f2 != f2.floor() { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); + } + + let f1 = self.float(n1)?; + self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) + .map(|f| Number::Float(OrderedFloat(f))) } } } - fn pow(&self, n1: Number, n2: Number) -> Result + fn float_pow(&self, n1: Number, n2: Number) -> Result { - match n1.pow(n2) { - Ok(result) => Ok(result), - Err(_) => { - let stub = MachineError::functor_stub(clause_name!("**"), 2); - Err(self.error_form(MachineError::evaluation_error(EvalError::NoRoots), - stub)) - } + let f1 = result_f(n1, rnd_f); + let f2 = result_f(n2, rnd_f); + + let stub = MachineError::functor_stub(clause_name!("(**)"), 2); + + let f1 = try_numeric_result!(self, f1, stub.clone())?; + let f2 = try_numeric_result!(self, f2, stub.clone())?; + + let result = result_f(Number::Float(OrderedFloat(f1.powf(f2))), rnd_f); + + Ok(Number::Float(OrderedFloat(try_numeric_result!(self, result, stub)?))) + } + + fn pow(&self, n1: Number, n2: Number, culprit: &'static str) -> Result + { + if n2.is_negative() { + let stub = MachineError::functor_stub(clause_name!(culprit), 2); + return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); } + + match (n1, n2) { + (Number::Integer(n1), Number::Integer(n2)) => + Ok(Number::Integer(binary_pow(n1, n2))), + (n1, n2) => + self.float_pow(n1, n2) + } + } + + fn unary_float_fn_template(&self, n1: Number, f: FloatFn) -> Result + where FloatFn: Fn(f64) -> f64 + { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + + let f1 = try_numeric_result!(self, result_f(n1, rnd_f), stub.clone())?; + let f1 = result_f(Number::Float(OrderedFloat(f(f1))), rnd_f); + + try_numeric_result!(self, f1, stub) + } + + fn sin(&self, n1: Number) -> Result + { + self.unary_float_fn_template(n1, |f| f.sin()) + } + + fn cos(&self, n1: Number) -> Result + { + self.unary_float_fn_template(n1, |f| f.cos()) + } + + fn tan(&self, n1: Number) -> Result + { + self.unary_float_fn_template(n1, |f| f.tan()) + } + + fn log(&self, n1: Number) -> Result + { + self.unary_float_fn_template(n1, |f| f.log(f64::consts::E)) + } + + fn exp(&self, n1: Number) -> Result + { + self.unary_float_fn_template(n1, |f| f.exp()) + } + + fn asin(&self, n1: Number) -> Result + { + self.unary_float_fn_template(n1, |f| f.asin()) + } + + fn acos(&self, n1: Number) -> Result + { + self.unary_float_fn_template(n1, |f| f.acos()) } - fn shr(&self, n1: Number, n2: Number) -> Result, MachineStub> + fn atan(&self, n1: Number) -> Result + { + self.unary_float_fn_template(n1, |f| f.atan()) + } + + fn sqrt(&self, n1: Number) -> Result + { + if n1.is_negative() { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); + } + + self.unary_float_fn_template(n1, |f| f.sqrt()) + } + + fn float(&self, n: Number) -> Result + { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + try_numeric_result!(self, result_f(n, rnd_f), stub) + } + + fn floor(&self, n1: Number) -> Integer + { + rnd_i(n1) + } + + fn ceiling(&self, n1: Number) -> Integer + { + -self.floor(-n1) + } + + fn truncate(&self, n: Number) -> Integer + { + if n.is_negative() { + -self.floor(n.abs()) + } else { + self.floor(n) + } + } + + fn round(&self, n: Number) -> Result + { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + + let result = n + Number::Float(OrderedFloat(0.5f64)); + let result = try_numeric_result!(self, result, stub)?; + + Ok(self.floor(result)) + } + + fn shr(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(>>)"), 2); match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => - match n2.to_usize() { - Some(n2) => Ok(Rc::new(&*n1 >> n2)), - _ => Ok(Rc::new(&*n1 >> usize::max_value())) + match n2.to_u32() { + Some(n2) => Ok(n1 >> n2), + _ => Ok(n1 >> u32::max_value()) }, (Number::Integer(_), n2) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n2))), + Addr::Con(n2.to_constant())), stub)), (n1, _) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n1))), + Addr::Con(n1.to_constant())), stub)) } } - fn shl(&self, n1: Number, n2: Number) -> Result, MachineStub> + fn shl(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(<<)"), 2); match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => - match n2.to_usize() { - Some(n2) => Ok(Rc::new(&*n1 << n2)), - _ => Ok(Rc::new(&*n1 << usize::max_value())) + match n2.to_u32() { + Some(n2) => Ok(n1 << n2), + _ => Ok(n1 << u32::max_value()) }, (Number::Integer(_), n2) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n2))), + Addr::Con(n2.to_constant())), stub)), (n1, _) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n1))), + Addr::Con(n1.to_constant())), stub)) } } - fn xor(&self, n1: Number, n2: Number) -> Result, MachineStub> + fn bitwise_complement(&self, n1: Number) -> Result + { + let stub = MachineError::functor_stub(clause_name!("(\\)"), 2); + + match n1 { + Number::Integer(n1) => + Ok(!n1), + _ => + Err(self.error_form(MachineError::type_error(ValidType::Integer, + Addr::Con(n1.to_constant())), + stub)) + } + } + + fn xor(&self, n1: Number, n2: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(xor)"), 2); match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => - Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 ^ u_n2)), + Ok(n1 ^ n2), (Number::Integer(_), n2) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n2))), + Addr::Con(n2.to_constant())), stub)), (n1, _) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n1))), + Addr::Con(n1.to_constant())), stub)) } } - fn and(&self, n1: Number, n2: Number) -> Result, MachineStub> + 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(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 & u_n2)), + Ok(n1 & n2), (Number::Integer(_), n2) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n2))), + Addr::Con(n2.to_constant())), stub)), (n1, _) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n1))), + Addr::Con(n1.to_constant())), stub)) } } - fn modulus(&self, n1: Number, n2: Number) -> Result, MachineStub> + fn modulus(&self, x: Number, y: Number) -> Result { let stub = MachineError::functor_stub(clause_name!("(mod)"), 2); - match (n1, n2) { - (Number::Integer(n1), Number::Integer(n2)) => - if *n2 == BigInt::zero() { - Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), - stub)) + match (x, y) { + (Number::Integer(x), Number::Integer(y)) => + if y == 0 { + Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { - Ok(Rc::new(n1.mod_floor(&n2))) + Ok(x.div_rem_floor(y).1) }, (Number::Integer(_), n2) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n2))), + Addr::Con(n2.to_constant())), stub)), (n1, _) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n1))), + Addr::Con(n1.to_constant())), stub)) } } @@ -1115,68 +1290,76 @@ impl MachineState { Ok(max(n1, n2)) } - fn remainder(&self, n1: Number, n2: Number) -> Result, MachineStub> + fn min(&self, n1: Number, n2: Number) -> Result { + Ok(min(n1, n2)) + } + + 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 == BigInt::zero() { + if n2 == 0 { Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) } else { - Ok(Rc::new(&*n1 % &*n2)) + Ok(n1 % n2) }, (Number::Integer(_), n2) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n2))), + Addr::Con(n2.to_constant())), stub)), (n1, _) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n1))), + Addr::Con(n1.to_constant())), stub)) } } - fn or(&self, n1: Number, n2: Number) -> Result, MachineStub> + 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(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 & u_n2)), + Ok(n1 | n2), (Number::Integer(_), n2) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n2))), + Addr::Con(n2.to_constant())), stub)), (n1, _) => Err(self.error_form(MachineError::type_error(ValidType::Integer, - Addr::Con(Constant::Number(n1))), + Addr::Con(n1.to_constant())), stub)) } } - pub(super) fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) { + pub(super) + fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) + { + let stub = MachineError::functor_stub(clause_name!("(is)"), 2); + match instr { &ArithmeticInstruction::Add(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = n1 + n2; + self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 + n2, stub)); self.p += 1; }, &ArithmeticInstruction::Sub(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = n1 - n2; + self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 - n2, stub)); self.p += 1; }, &ArithmeticInstruction::Mul(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = n1 * n2; + self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 * n2, stub)); self.p += 1; }, &ArithmeticInstruction::Max(ref a1, ref a2, t) => { @@ -1186,18 +1369,25 @@ impl MachineState { self.interms[t - 1] = try_or_fail!(self, self.max(n1, n2)); self.p += 1; }, + &ArithmeticInstruction::Min(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + let n2 = try_or_fail!(self, self.get_number(a2)); + + self.interms[t - 1] = try_or_fail!(self, self.min(n1, n2)); + self.p += 1; + }, &ArithmeticInstruction::IntPow(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.binary_pow(n1, n2)); + self.interms[t - 1] = try_or_fail!(self, self.int_pow(n1, n2)); self.p += 1; }, &ArithmeticInstruction::Pow(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.pow(n1, n2)); + self.interms[t - 1] = try_or_fail!(self, self.pow(n1, n2, "(**)")); self.p += 1; }, &ArithmeticInstruction::RDiv(ref a1, ref a2, t) => { @@ -1209,11 +1399,11 @@ impl MachineState { self.interms[t - 1] = Number::Rational(try_or_fail!(self, self.rdiv(r1, r2))); self.p += 1; }, - &ArithmeticInstruction::FIDiv(ref a1, ref a2, t) => { + &ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.fidiv(n1, n2))); + self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.int_floor_div(n1, n2))); self.p += 1; }, &ArithmeticInstruction::IDiv(ref a1, ref a2, t) => { @@ -1235,6 +1425,12 @@ impl MachineState { self.interms[t - 1] = - n1; self.p += 1; }, + &ArithmeticInstruction::BitwiseComplement(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.bitwise_complement(n1))); + self.p += 1; + }, &ArithmeticInstruction::Div(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)); @@ -1290,7 +1486,104 @@ impl MachineState { self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.remainder(n1, n2))); self.p += 1; - } + }, + &ArithmeticInstruction::Cos(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.cos(n1)))); + self.p += 1; + }, + &ArithmeticInstruction::Sin(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.sin(n1)))); + self.p += 1; + }, + &ArithmeticInstruction::Tan(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.tan(n1)))); + self.p += 1; + }, + &ArithmeticInstruction::Sqrt(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.sqrt(n1)))); + self.p += 1; + }, + &ArithmeticInstruction::Log(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.log(n1)))); + self.p += 1; + }, + &ArithmeticInstruction::Exp(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.exp(n1)))); + self.p += 1; + }, + &ArithmeticInstruction::ACos(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.acos(n1)))); + self.p += 1; + }, + &ArithmeticInstruction::ASin(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.asin(n1)))); + self.p += 1; + }, + &ArithmeticInstruction::ATan(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.atan(n1)))); + self.p += 1; + }, + &ArithmeticInstruction::ATan2(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::Float(OrderedFloat(try_or_fail!(self, self.atan2(n1, n2)))); + self.p += 1; + }, + &ArithmeticInstruction::Float(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.float(n1)))); + self.p += 1; + }, + &ArithmeticInstruction::Truncate(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Integer(self.truncate(n1)); + self.p += 1; + }, + &ArithmeticInstruction::Round(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.round(n1))); + self.p += 1; + }, + &ArithmeticInstruction::Ceiling(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Integer(self.ceiling(n1)); + self.p += 1; + }, + &ArithmeticInstruction::Floor(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = Number::Integer(self.floor(n1)); + self.p += 1; + }, + &ArithmeticInstruction::Plus(ref a1, t) => { + let n1 = try_or_fail!(self, self.get_number(a1)); + + self.interms[t - 1] = n1; + self.p += 1; + }, }; } @@ -1775,10 +2068,10 @@ impl MachineState { match n { Addr::HeapCell(_) | Addr::StackCell(..) => // 8.5.2.3 a) return Err(self.error_form(MachineError::instantiation_error(), stub)), - Addr::Con(Constant::Number(Number::Integer(n))) => { - if n.is_negative() { + Addr::Con(Constant::Integer(n)) => { + if n < 0 { // 8.5.2.3 e) - let n = Addr::Con(Constant::Number(Number::Integer(n))); + let n = Addr::Con(Constant::Integer(n)); let dom_err = MachineError::domain_error(DomainError::NotLessThanZero, n); return Err(self.error_form(dom_err, stub)); @@ -1829,7 +2122,7 @@ impl MachineState { } else { Addr::Con(Constant::String(s.tail())) }; - + self.unify(a3, h_a); } else { self.fail = true; @@ -1982,20 +2275,50 @@ impl MachineState { return Ordering::Greater, (HeapCellValue::Addr(Addr::StackCell(..)), _) => return Ordering::Less, - (HeapCellValue::Addr(Addr::Con(Constant::Number(..))), + (HeapCellValue::Addr(Addr::Con(Constant::Integer(..))), HeapCellValue::Addr(Addr::HeapCell(_))) - | (HeapCellValue::Addr(Addr::Con(Constant::Number(..))), + | (HeapCellValue::Addr(Addr::Con(Constant::Integer(..))), HeapCellValue::Addr(Addr::AttrVar(_))) => return Ordering::Greater, - (HeapCellValue::Addr(Addr::Con(Constant::Number(..))), + (HeapCellValue::Addr(Addr::Con(Constant::Integer(..))), HeapCellValue::Addr(Addr::StackCell(..))) => return Ordering::Greater, - (HeapCellValue::Addr(Addr::Con(Constant::Number(n1))), - HeapCellValue::Addr(Addr::Con(Constant::Number(n2)))) => + (HeapCellValue::Addr(Addr::Con(Constant::Integer(n1))), + HeapCellValue::Addr(Addr::Con(Constant::Integer(n2)))) => if n1 != n2 { return n1.cmp(&n2); }, - (HeapCellValue::Addr(Addr::Con(Constant::Number(_))), _) => + (HeapCellValue::Addr(Addr::Con(Constant::Integer(_))), _) => + return Ordering::Less, + (HeapCellValue::Addr(Addr::Con(Constant::Float(..))), + HeapCellValue::Addr(Addr::HeapCell(_))) + | (HeapCellValue::Addr(Addr::Con(Constant::Float(..))), + HeapCellValue::Addr(Addr::AttrVar(_))) => + return Ordering::Greater, + (HeapCellValue::Addr(Addr::Con(Constant::Float(..))), + HeapCellValue::Addr(Addr::StackCell(..))) => + return Ordering::Greater, + (HeapCellValue::Addr(Addr::Con(Constant::Float(n1))), + HeapCellValue::Addr(Addr::Con(Constant::Float(n2)))) => + if n1 != n2 { + return n1.cmp(&n2); + }, + (HeapCellValue::Addr(Addr::Con(Constant::Float(_))), _) => + return Ordering::Less, + (HeapCellValue::Addr(Addr::Con(Constant::Rational(..))), + HeapCellValue::Addr(Addr::HeapCell(_))) + | (HeapCellValue::Addr(Addr::Con(Constant::Rational(..))), + HeapCellValue::Addr(Addr::AttrVar(_))) => + return Ordering::Greater, + (HeapCellValue::Addr(Addr::Con(Constant::Rational(..))), + HeapCellValue::Addr(Addr::StackCell(..))) => + return Ordering::Greater, + (HeapCellValue::Addr(Addr::Con(Constant::Rational(n1))), + HeapCellValue::Addr(Addr::Con(Constant::Rational(n2)))) => + if n1 != n2 { + return n1.cmp(&n2); + }, + (HeapCellValue::Addr(Addr::Con(Constant::Rational(_))), _) => return Ordering::Less, (HeapCellValue::Addr(Addr::Con(Constant::String(..))), HeapCellValue::Addr(Addr::HeapCell(_))) @@ -2006,7 +2329,13 @@ impl MachineState { HeapCellValue::Addr(Addr::StackCell(..))) => return Ordering::Greater, (HeapCellValue::Addr(Addr::Con(Constant::String(_))), - HeapCellValue::Addr(Addr::Con(Constant::Number(_)))) => + HeapCellValue::Addr(Addr::Con(Constant::Integer(_)))) => + return Ordering::Greater, + (HeapCellValue::Addr(Addr::Con(Constant::String(_))), + HeapCellValue::Addr(Addr::Con(Constant::Rational(_)))) => + return Ordering::Greater, + (HeapCellValue::Addr(Addr::Con(Constant::String(_))), + HeapCellValue::Addr(Addr::Con(Constant::Float(_)))) => return Ordering::Greater, (HeapCellValue::Addr(Addr::Con(Constant::String(s1))), HeapCellValue::Addr(Addr::Con(Constant::String(s2)))) => @@ -2034,7 +2363,13 @@ impl MachineState { HeapCellValue::Addr(Addr::StackCell(..))) => return Ordering::Greater, (HeapCellValue::Addr(Addr::Con(Constant::Atom(..))), - HeapCellValue::Addr(Addr::Con(Constant::Number(_)))) => + HeapCellValue::Addr(Addr::Con(Constant::Float(_)))) => + return Ordering::Greater, + (HeapCellValue::Addr(Addr::Con(Constant::Atom(..))), + HeapCellValue::Addr(Addr::Con(Constant::Integer(_)))) => + return Ordering::Greater, + (HeapCellValue::Addr(Addr::Con(Constant::Atom(..))), + HeapCellValue::Addr(Addr::Con(Constant::Rational(_)))) => return Ordering::Greater, (HeapCellValue::Addr(Addr::Con(Constant::Atom(..))), HeapCellValue::Addr(Addr::Con(Constant::String(_)))) => @@ -2114,10 +2449,10 @@ impl MachineState { let d = self.store(self.deref(self[r1].clone())); match d { - Addr::Con(Constant::Number(Number::Integer(_))) => self.p += 1, + Addr::Con(Constant::Integer(_)) => self.p += 1, Addr::Con(Constant::CharCode(_)) => self.p += 1, - Addr::Con(Constant::Number(Number::Rational(r))) => - if r.denom() == &BigInt::one() { + Addr::Con(Constant::Rational(r)) => + if r.denom() == &1 { self.p += 1; } else { self.fail = true; @@ -2137,7 +2472,7 @@ impl MachineState { let d = self.store(self.deref(self[r1].clone())); match d { - Addr::Con(Constant::Number(Number::Float(_))) => self.p += 1, + Addr::Con(Constant::Float(_)) => self.p += 1, _ => self.fail = true }; }, @@ -2145,7 +2480,7 @@ impl MachineState { let d = self.store(self.deref(self[r1].clone())); match d { - Addr::Con(Constant::Number(Number::Rational(_))) => self.p += 1, + Addr::Con(Constant::Rational(_)) => self.p += 1, _ => self.fail = true }; }, @@ -2195,11 +2530,10 @@ impl MachineState { } } - fn try_functor_compound_case(&mut self, name: ClauseName, arity: usize, - spec: Option) + fn try_functor_compound_case(&mut self, name: ClauseName, arity: usize, spec: Option) { let name = Addr::Con(Constant::Atom(name, spec)); - let arity = Addr::Con(integer!(arity)); + let arity = Addr::Con(Constant::Integer(Integer::from(arity))); self.try_functor_unify_components(name, arity); } @@ -2239,7 +2573,7 @@ impl MachineState { self.try_functor_compound_case(clause_name!("."), 2, shared_op_desc) }, Addr::Con(_) => - self.try_functor_unify_components(a1, Addr::Con(integer!(0))), + self.try_functor_unify_components(a1, Addr::Con(Constant::Integer(Integer::from(0)))), Addr::Str(o) => match self.heap[o].clone() { HeapCellValue::NamedStr(arity, name, spec) => { @@ -2260,7 +2594,7 @@ impl MachineState { return Err(self.error_form(MachineError::instantiation_error(), stub)); } - if let Addr::Con(Constant::Number(Number::Integer(arity))) = arity { + if let Addr::Con(Constant::Integer(arity)) = arity { let arity = match arity.to_isize() { Some(arity) => arity, None => { @@ -2275,8 +2609,9 @@ impl MachineState { return Err(self.error_form(rep_err, stub)); } else if arity < 0 { // 8.5.1.3 g) + let arity = Integer::from(arity); let dom_err = MachineError::domain_error(DomainError::NotLessThanZero, - Addr::Con(integer!(arity))); + Addr::Con(Constant::Integer(arity))); return Err(self.error_form(dom_err, stub)); } @@ -2333,12 +2668,12 @@ impl MachineState { return Ok(s); } else { let stub = MachineError::functor_stub(clause_name!("partial_string"), 2); - + match self.try_from_list(r, stub.clone()) { Ok(addrs) => Ok(StringList::new(match self.try_char_list(addrs) { Ok(string) => string, - Err(err) => { + Err(err) => { return Err(self.error_form(err, stub)); } }, false)), diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index bbd1efe9..96a24c97 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -11,10 +11,9 @@ use prolog::machine::machine_errors::*; use prolog::machine::machine_indices::*; use prolog::machine::machine_state::*; use prolog::machine::toplevel::{to_op_decl}; -use prolog::num::{FromPrimitive, ToPrimitive, Zero}; -use prolog::num::bigint::{BigInt}; use prolog::ordered_float::OrderedFloat; use prolog::read::{PrologStream, readline}; +use prolog::rug::Integer; use ref_thread_local::RefThreadLocal; @@ -121,7 +120,7 @@ impl MachineState { fn finalize_skip_max_list(&mut self, n: usize, addr: Addr) { let target_n = self[temp_v!(1)].clone(); - self.unify(Addr::Con(integer!(n)), target_n); + self.unify(Addr::Con(Constant::Integer(Integer::from(n))), target_n); if !self.fail { let xs = self[temp_v!(4)].clone(); @@ -133,12 +132,12 @@ impl MachineState { let max_steps = self.store(self.deref(self[temp_v!(2)].clone())); match max_steps { - Addr::Con(Constant::Number(Number::Integer(ref max_steps))) => + Addr::Con(Constant::Integer(ref max_steps)) => if max_steps.to_isize().map(|i| i >= -1).unwrap_or(false) { let n = self.store(self.deref(self[temp_v!(1)].clone())); match n { - Addr::Con(Constant::Number(Number::Integer(ref n))) if n.is_zero() => { + Addr::Con(Constant::Integer(ref n)) if n == &0 => { let xs0 = self[temp_v!(3)].clone(); let xs = self[temp_v!(4)].clone(); @@ -163,7 +162,7 @@ impl MachineState { self.finalize_skip_max_list(n + s.len(), Addr::Con(Constant::EmptyList)) } else { - let i = max_steps.to_usize().unwrap() - n; + let i = (max_steps as usize) - n; if s.len() < i { self.finalize_skip_max_list(n + s.len(), @@ -338,7 +337,7 @@ impl MachineState { } } - fn int_to_char_code(&mut self, n: Rc, stub: &'static str, arity: usize) + fn int_to_char_code(&mut self, n: &Integer, stub: &'static str, arity: usize) -> Result { if let Some(c) = n.to_u8() { @@ -381,8 +380,12 @@ impl MachineState { return Err(self.error_form(err, stub)); }, - Ok(Term::Constant(_, Constant::Number(n))) => - self.unify(nx, Addr::Con(Constant::Number(n))), + Ok(Term::Constant(_, Constant::Rational(n))) => + self.unify(nx, Addr::Con(Constant::Rational(n))), + Ok(Term::Constant(_, Constant::Float(n))) => + self.unify(nx, Addr::Con(Constant::Float(n))), + Ok(Term::Constant(_, Constant::Integer(n))) => + self.unify(nx, Addr::Con(Constant::Integer(n))), Ok(Term::Constant(_, Constant::CharCode(c))) => self.unify(nx, Addr::Con(Constant::CharCode(c))), _ => { @@ -519,8 +522,8 @@ impl MachineState { for addr in addrs.iter() { match addr { - &Addr::Con(Constant::Number(Number::Integer(ref n))) => { - let c = self.int_to_char_code(n.clone(), "atom_codes", 2)?; + &Addr::Con(Constant::Integer(ref n)) => { + let c = self.int_to_char_code(&n, "atom_codes", 2)?; chars.push(c as char); }, &Addr::Con(Constant::CharCode(c)) => @@ -550,10 +553,10 @@ impl MachineState { _ => unreachable!() }; - let len = Number::Integer(Rc::new(BigInt::from_usize(atom.as_str().len()).unwrap())); + let len = Integer::from(atom.as_str().len()); let a2 = self[temp_v!(2)].clone(); - self.unify(a2, Addr::Con(Constant::Number(len))); + self.unify(a2, Addr::Con(Constant::Integer(len))); }, &SystemClauseType::CharsToNumber => { let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); @@ -574,9 +577,9 @@ impl MachineState { let chs = self[temp_v!(2)].clone(); let string = match self.store(self.deref(n)) { - Addr::Con(Constant::Number(Number::Float(OrderedFloat(n)))) => + Addr::Con(Constant::Float(OrderedFloat(n))) => format!("{0:<20?}", n), - Addr::Con(Constant::Number(Number::Integer(n))) => + Addr::Con(Constant::Integer(n)) => n.to_string(), _ => unreachable!() }; @@ -591,9 +594,9 @@ impl MachineState { let chs = self[temp_v!(2)].clone(); let string = match self.store(self.deref(n)) { - Addr::Con(Constant::Number(Number::Float(OrderedFloat(n)))) => + Addr::Con(Constant::Float(OrderedFloat(n))) => format!("{0:<20?}", n), - Addr::Con(Constant::Number(Number::Integer(n))) => + Addr::Con(Constant::Integer(n)) => n.to_string(), _ => unreachable!() }; @@ -659,8 +662,8 @@ impl MachineState { match self.store(self.deref(a2)) { Addr::Con(Constant::CharCode(code)) => self.unify(Addr::Con(Constant::Char(code as char)), addr.clone()), - Addr::Con(Constant::Number(Number::Integer(n))) => { - let c = self.int_to_char_code(n, "char_code", 2)?; + Addr::Con(Constant::Integer(n)) => { + let c = self.int_to_char_code(&n, "char_code", 2)?; self.unify(Addr::Con(Constant::Char(c as char)), addr.clone()); }, _ => self.fail = true @@ -967,12 +970,12 @@ impl MachineState { let a2 = self[temp_v!(2)].clone(); let a3 = self[temp_v!(3)].clone(); - let arity = Number::Integer(Rc::new(BigInt::from_usize(arity).unwrap())); + let arity = Integer::from(arity); self.unify(a2, Addr::Con(Constant::Atom(name, spec))); if !self.fail { - self.unify(a3, Addr::Con(Constant::Number(arity))); + self.unify(a3, Addr::Con(Constant::Integer(arity))); } }, _ => self.fail = true @@ -1007,11 +1010,11 @@ impl MachineState { } }; - let a2 = Number::Integer(Rc::new(BigInt::from_usize(priority).unwrap())); + let a2 = Integer::from(priority); let a3 = Addr::Con(Constant::Atom(clause_name!(spec), None)); let a4 = Addr::Con(Constant::Atom(name, Some(shared_op_desc))); - self.unify(Addr::Con(Constant::Number(a2)), prec); + self.unify(Addr::Con(Constant::Integer(a2)), prec); if !self.fail { self.unify(a3, specifier); @@ -1032,7 +1035,7 @@ impl MachineState { let op = self[temp_v!(3)].clone(); let priority = match self.store(self.deref(priority)) { - Addr::Con(Constant::Number(Number::Integer(n))) => n.to_usize().unwrap(), + Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(), _ => unreachable!() }; @@ -1251,11 +1254,11 @@ impl MachineState { match (a1, a2.clone()) { (Addr::Con(Constant::Usize(bp)), - Addr::Con(Constant::Number(Number::Integer(n)))) => + Addr::Con(Constant::Integer(n))) => match call_policy.downcast_mut::().ok() { Some(call_policy) => { let count = call_policy.add_limit(n, bp); - let count = Addr::Con(Constant::Number(Number::Integer(count))); + let count = Addr::Con(Constant::Integer(count.clone())); let a3 = self[temp_v!(3)].clone(); @@ -1369,7 +1372,7 @@ impl MachineState { if let Addr::Con(Constant::Usize(bp)) = a1 { let count = call_policy.remove_limit(bp); - let count = Addr::Con(Constant::Number(Number::Integer(count))); + let count = Addr::Con(Constant::Integer(count.clone())); let a2 = self[temp_v!(2)].clone(); @@ -1692,7 +1695,7 @@ impl MachineState { if var_names.contains_key(&var) { continue; } - + var_names.insert(var, atom); }, _ => unreachable!() diff --git a/src/prolog/machine/term_expansion.rs b/src/prolog/machine/term_expansion.rs index fdd28c57..2797399c 100644 --- a/src/prolog/machine/term_expansion.rs +++ b/src/prolog/machine/term_expansion.rs @@ -3,7 +3,8 @@ use prolog_parser::parser::*; use prolog::machine::*; use prolog::machine::machine_indices::HeapCellValue; -use prolog::num::*; +use prolog::rug::Integer; +use prolog::rug::ops::Pow; use std::cell::Cell; use std::collections::VecDeque; @@ -306,7 +307,7 @@ impl MachineState { // names in the pre-expansion term. This formula ensures that all generated "numbervars"- // style variable names will be longer than the keys of the var_dict, and therefore // not equal to any of them. - printer.numbervars_offset = pow(BigInt::from(10), max_var_length) * 26; + printer.numbervars_offset = Integer::from(10).pow(max_var_length as u32) * 26; printer.drop_toplevel_spec(); printer.see_all_locs(); diff --git a/src/prolog/machine/toplevel.rs b/src/prolog/machine/toplevel.rs index 6e8be1cd..93335a54 100644 --- a/src/prolog/machine/toplevel.rs +++ b/src/prolog/machine/toplevel.rs @@ -9,7 +9,6 @@ use prolog::machine::machine_errors::*; use prolog::machine::machine_indices::*; use prolog::machine::machine_state::MachineState; use prolog::machine::term_expansion::*; -use prolog::num::*; use std::borrow::BorrowMut; use std::collections::{HashMap, HashSet, VecDeque}; @@ -142,7 +141,7 @@ fn setup_op_decl(mut terms: Vec>) -> Result }; let prec = match *terms.pop().unwrap() { - Term::Constant(_, Constant::Number(Number::Integer(bi))) => + Term::Constant(_, Constant::Integer(bi)) => match bi.to_usize() { Some(n) if n <= 1200 => n, _ => return Err(ParserError::InconsistentEntry) @@ -162,7 +161,7 @@ fn setup_predicate_indicator(mut term: Term) -> Result ( - HeapCellValue::Addr(Addr::Con(integer!($i))) + HeapCellValue::Addr(Addr::Con(Constant::Integer($i))) ) } diff --git a/src/prolog/mod.rs b/src/prolog/mod.rs index 4d41801c..d7747718 100644 --- a/src/prolog/mod.rs +++ b/src/prolog/mod.rs @@ -1,6 +1,6 @@ -extern crate num; extern crate ordered_float; extern crate prolog_parser; +extern crate rug; pub mod instructions; #[macro_use] mod macros; diff --git a/src/prolog/write.rs b/src/prolog/write.rs index 6a357ea3..df259884 100644 --- a/src/prolog/write.rs +++ b/src/prolog/write.rs @@ -276,6 +276,16 @@ impl fmt::Display for SessionError { } } +impl fmt::Display for Number { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &Number::Float(fl) => write!(f, "{}", fl), + &Number::Integer(ref bi) => write!(f, "{}", bi), + &Number::Rational(ref r) => write!(f, "{}", r) + } + } +} + impl fmt::Display for ArithmeticTerm { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -307,8 +317,10 @@ impl fmt::Display for ArithmeticInstruction { write!(f, "idiv {}, {}, @{}", a1, a2, t), &ArithmeticInstruction::Max(ref a1, ref a2, ref t) => write!(f, "max {}, {}, @{}", a1, a2, t), - &ArithmeticInstruction::FIDiv(ref a1, ref a2, ref t) => - write!(f, "floored_idiv {}, {}, @{}", a1, a2, t), + &ArithmeticInstruction::Min(ref a1, ref a2, ref t) => + write!(f, "min {}, {}, @{}", a1, a2, t), + &ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, ref t) => + write!(f, "int_floor_div {}, {}, @{}", a1, a2, t), &ArithmeticInstruction::RDiv(ref a1, ref a2, ref t) => write!(f, "rdiv {}, {}, @{}", a1, a2, t), &ArithmeticInstruction::Shl(ref a1, ref a2, ref t) => @@ -325,8 +337,42 @@ impl fmt::Display for ArithmeticInstruction { write!(f, "mod {}, {}, @{}", a1, a2, t), &ArithmeticInstruction::Rem(ref a1, ref a2, ref t) => write!(f, "rem {}, {}, @{}", a1, a2, t), + &ArithmeticInstruction::ATan2(ref a1, ref a2, ref t) => + write!(f, "atan2 {}, {}, @{}", a1, a2, t), + &ArithmeticInstruction::Plus(ref a, ref t) => + write!(f, "plus {}, @{}", a, t), &ArithmeticInstruction::Neg(ref a, ref t) => - write!(f, "neg {}, @{}", a, t) + write!(f, "neg {}, @{}", a, t), + &ArithmeticInstruction::Cos(ref a, ref t) => + write!(f, "cos {}, @{}", a, t), + &ArithmeticInstruction::Sin(ref a, ref t) => + write!(f, "sin {}, @{}", a, t), + &ArithmeticInstruction::Tan(ref a, ref t) => + write!(f, "tan {}, @{}", a, t), + &ArithmeticInstruction::ATan(ref a, ref t) => + write!(f, "atan {}, @{}", a, t), + &ArithmeticInstruction::ASin(ref a, ref t) => + write!(f, "asin {}, @{}", a, t), + &ArithmeticInstruction::ACos(ref a, ref t) => + write!(f, "acos {}, @{}", a, t), + &ArithmeticInstruction::Log(ref a, ref t) => + write!(f, "log {}, @{}", a, t), + &ArithmeticInstruction::Exp(ref a, ref t) => + write!(f, "exp {}, @{}", a, t), + &ArithmeticInstruction::Sqrt(ref a, ref t) => + write!(f, "sqrt {}, @{}", a, t), + &ArithmeticInstruction::BitwiseComplement(ref a, ref t) => + write!(f, "bitwise_complement {}, @{}", a, t), + &ArithmeticInstruction::Truncate(ref a, ref t) => + write!(f, "truncate {}, @{}", a, t), + &ArithmeticInstruction::Round(ref a, ref t) => + write!(f, "round {}, @{}", a, t), + &ArithmeticInstruction::Ceiling(ref a, ref t) => + write!(f, "ceiling {}, @{}", a, t), + &ArithmeticInstruction::Floor(ref a, ref t) => + write!(f, "floor {}, @{}", a, t), + &ArithmeticInstruction::Float(ref a, ref t) => + write!(f, "float {}, @{}", a, t), } } } diff --git a/src/tests.rs b/src/tests.rs index 2df7406b..c4f8e0e1 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1016,8 +1016,8 @@ fn test_queries_on_arithmetic() assert_prolog_success!(&mut wam, "X is ((3 + 4) // 2) + 2 - 1 // 1, Y is 2+2, Z = 8, Y is 4.", [["Y = 4", "X = 4", "Z = 8"]]); - assert_prolog_success!(&mut wam, "X is (3 rdiv 4) / 2, Y is 3 rdiv 8, X = Y.", - [["X = 3/8", "Y = 3/8"]]); + assert_prolog_success!(&mut wam, "X is (3 rdiv 4) / 2, Y is 3 rdiv 8.", + [["X = 0.375", "Y = 3/8"]]); assert_prolog_success!(&mut wam, "X is 10 xor -4, X is -10.", [["X = -10"]]); assert_prolog_success!(&mut wam, "X is 4 xor -7, X is -3.", [["X = -3"]]); @@ -1066,8 +1066,6 @@ fn test_queries_on_arithmetic() [["X = 1"]]); assert_prolog_success!(&mut wam, "X is 3 ** 1.", [["X = 3"]]); - assert_prolog_success!(&mut wam, "X is 3 ** -3.", - [["X = 1/27"]]); assert_prolog_success!(&mut wam, "X is (-3) ** 3.", [["X = -27"]]); assert_prolog_success!(&mut wam, "X is (-3) ** 3.", @@ -1078,38 +1076,35 @@ fn test_queries_on_arithmetic() [["X = 1"]]); assert_prolog_success!(&mut wam, "X is (-3) ** 1.", [["X = -3"]]); - assert_prolog_success!(&mut wam, "X is (-3) ** -3.", - [["X = -1/27"]]); - assert_prolog_success!(&mut wam, "X is (1 rdiv 27) ** -3, X ~ 19683."); - assert_prolog_success!(&mut wam, "X is (-1 rdiv 27) ** -3, X ~ -19683."); +// assert_prolog_success!(&mut wam, "X is (1 rdiv 27) ** -3, X ~ 19683."); +// assert_prolog_success!(&mut wam, "X is (-1 rdiv 27) ** -3, X ~ -19683."); assert_prolog_success!(&mut wam, "X is 0.0 ** 0.", [["X = 1.0"]]); assert_prolog_success!(&mut wam, "catch(_ is 0.0 ** -2342, error(E, _), true).", - [["E = evaluation_error(no_roots)"]]); + [["E = evaluation_error(undefined)"]]); assert_prolog_success!(&mut wam, "X is 0.0 ** 2342.", [["X = 0"]]); assert_prolog_success!(&mut wam, "catch(_ is (-3) ** (1 rdiv 2), error(E, _), true).", - [["E = evaluation_error(no_roots)"]]); + [["E = evaluation_error(undefined)"]]); assert_prolog_success!(&mut wam, "catch(_ is (-3/2) ** (1 rdiv 2), error(E, _), true).", - [["E = evaluation_error(no_roots)"]]); + [["E = evaluation_error(undefined)"]]); assert_prolog_success!(&mut wam, "catch(_ is (-3 rdiv 2) ** (1 rdiv 4), error(E, _), true).", - [["E = evaluation_error(no_roots)"]]); + [["E = evaluation_error(undefined)"]]); assert_prolog_success!(&mut wam, "catch(_ is (-3 rdiv 2) ** (-1 rdiv 4), error(E, _), true).", - [["E = evaluation_error(no_roots)"]]); + [["E = evaluation_error(undefined)"]]); assert_prolog_success!(&mut wam, "catch(_ is 0 ** (-5 rdiv 4), error(E, _), true).", - [["E = evaluation_error(no_roots)"]]); + [["E = evaluation_error(undefined)"]]); assert_prolog_success!(&mut wam, "X is 3 ** (1 rdiv 3), Y is X ** 3, Y ~ 3."); - assert_prolog_success!(&mut wam, "X is (-3) ** (1 rdiv 3), Y is X ** 3, Y ~ -3."); - assert_prolog_failure!(&mut wam, "X is (-5) ** (1 rdiv 3), Y is X ** 3, Y ~ -3."); - assert_prolog_failure!(&mut wam, "X is 5 ** (1 rdiv 3), Y is X ** 3, Y ~ 3."); - assert_prolog_failure!(&mut wam, "X is (1 rdiv 3) ** 0.5, Y is X ** 2, X ~ Y."); +// assert_prolog_success!(&mut wam, "X is (-3) ** (1 rdiv 3), Y is X ** 3, Y ~ -3."); +// assert_prolog_failure!(&mut wam, "X is (-5) ** (1 rdiv 3), Y is X ** 3, Y ~ -3."); + assert_prolog_success!(&mut wam, "X is 5 ** (1 rdiv 3), Y is X ** 3, Y ~ 5."); assert_prolog_success!(&mut wam, "X is (1 rdiv 3) ** 0.5, Y is X ** 2, 1 rdiv 3 ~ Y."); - assert_prolog_success!(&mut wam, "X is (-5) ** (-1 rdiv 3), Y is X ** 3, Y ~ -1 rdiv 5."); - assert_prolog_failure!(&mut wam, "X is (-5) ** (-1 rdiv 3), Y is X ** 3, Y ~ 1 rdiv 5."); +// assert_prolog_success!(&mut wam, "X is (-5) ** (-1 rdiv 3), Y is X ** 3, Y ~ -1 rdiv 5."); +// assert_prolog_failure!(&mut wam, "X is (-5) ** (-1 rdiv 3), Y is X ** 3, Y ~ 1 rdiv 5."); assert_prolog_success!(&mut wam, "X is (0 rdiv 5) ** 5.", [["X = 0"]]); @@ -1612,9 +1607,9 @@ fn test_queries_on_builtins() assert_prolog_failure!(&mut wam, "[] @< \"string\"."); assert_prolog_failure!(&mut wam, "[] @< atom."); assert_prolog_success!(&mut wam, "atom @< []."); - assert_prolog_failure!(&mut wam, "1.1 @< 1."); + assert_prolog_success!(&mut wam, "1.1 @< 1."); assert_prolog_success!(&mut wam, "1.0 @=< 1."); - assert_prolog_success!(&mut wam, "1 @=< 1.0."); //TODO: currently this succeeds. make it fail. + assert_prolog_success!(&mut wam, "1 @=< 1.0."); submit(&mut wam, ":- use_module(library(non_iso)).");