use prolog::num::bigint::BigInt;
-use prolog::num::ToPrimitive;
+use prolog::num::{Float, ToPrimitive, Zero};
+use prolog::num::rational::Ratio;
use prolog::ordered_float::*;
use std::fmt;
use std::io::Error as IOError;
use std::num::{ParseFloatError};
-use std::ops::{Add, AddAssign, Sub, Mul, Neg};
+use std::ops::{Add, AddAssign, Div, Sub, Mul, Neg};
use std::str::Utf8Error;
use std::vec::Vec;
Atom(Atom),
Float(OrderedFloat<f64>),
Integer(BigInt),
+ Rational(Ratio<BigInt>),
String(String),
Usize(usize),
EmptyList
write!(f, "{}", fl),
&Constant::Integer(ref i) =>
write!(f, "{}", i),
+ &Constant::Rational(ref r) =>
+ write!(f, "{}", r),
&Constant::String(ref s) =>
write!(f, "{}", s),
&Constant::Usize(integer) =>
impl From<Number> for Constant {
fn from(n: Number) -> Self {
match n {
+ Number::Rational(r) => Constant::Rational(r),
Number::Integer(n) => Constant::Integer(n),
Number::Float(f) => Constant::Float(f)
}
Var(Cell<VarReg>, Var)
}
-pub enum InlinedQueryTerm {
+pub enum InlinedQueryTerm {
IsAtomic(Vec<Box<Term>>),
IsVar(Vec<Box<Term>>)
-}
+}
impl InlinedQueryTerm {
pub fn arity(&self) -> usize {
#[derive(Clone)]
pub enum Number {
Float(OrderedFloat<f64>),
- Integer(BigInt)
+ Integer(BigInt),
+ Rational(Ratio<BigInt>)
+}
+
+impl Number {
+ pub fn is_zero(&self) -> bool {
+ match self {
+ &Number::Float(fl) => fl.into_inner().is_zero(),
+ &Number::Integer(ref bi) => bi.is_zero(),
+ &Number::Rational(ref r) => r.is_zero()
+ }
+ }
+}
+
+enum NumberPair {
+ Float(OrderedFloat<f64>, OrderedFloat<f64>),
+ Integer(BigInt, BigInt),
+ Rational(Ratio<BigInt>, Ratio<BigInt>)
+}
+
+impl NumberPair {
+ fn flip(self) -> NumberPair {
+ match self {
+ NumberPair::Float(f1, f2) => NumberPair::Float(f2, f1),
+ NumberPair::Integer(n1, n2) => NumberPair::Integer(n2, n1),
+ NumberPair::Rational(r1, r2) => NumberPair::Rational(r2, r1)
+ }
+ }
+
+ fn integer_float_pair(n1: BigInt, n2: OrderedFloat<f64>) -> NumberPair {
+ match n1.to_f64() {
+ Some(f1) => NumberPair::Float(OrderedFloat(f1), n2),
+ None => if let Some(r) = Ratio::from_float(n2.into_inner()) {
+ NumberPair::Rational(Ratio::from_integer(n1), r)
+ } else if n2.into_inner().is_sign_positive() {
+ NumberPair::Float(OrderedFloat(f64::infinity()),
+ OrderedFloat(f64::infinity()))
+ } else {
+ NumberPair::Float(OrderedFloat(f64::neg_infinity()),
+ OrderedFloat(f64::neg_infinity()))
+ }
+ }
+ }
+
+ fn float_rational_pair(n1: OrderedFloat<f64>, n2: Ratio<BigInt>) -> NumberPair {
+ if let Some(r) = Ratio::from_float(n1.into_inner()) {
+ NumberPair::Rational(r, n2)
+ } else if n1.into_inner().is_sign_positive() {
+ NumberPair::Float(OrderedFloat(f64::infinity()),
+ OrderedFloat(f64::infinity()))
+ } else {
+ NumberPair::Float(OrderedFloat(f64::neg_infinity()),
+ OrderedFloat(f64::neg_infinity()))
+ }
+ }
+
+ fn from(n1: Number, n2: Number) -> NumberPair
+ {
+ match (n1, n2) {
+ (Number::Integer(n1), Number::Integer(n2)) =>
+ NumberPair::Integer(n1, n2),
+ (Number::Float(n1), Number::Float(n2)) =>
+ NumberPair::Float(n1, n2),
+ (Number::Rational(n1), Number::Rational(n2)) =>
+ NumberPair::Rational(n1, n2),
+ (Number::Integer(n1), Number::Float(n2)) =>
+ Self::integer_float_pair(n1, n2),
+ (Number::Float(n1), Number::Integer(n2)) =>
+ Self::integer_float_pair(n2, n1).flip(),
+ (Number::Float(n1), Number::Rational(n2)) =>
+ Self::float_rational_pair(n1, n2),
+ (Number::Rational(n1), Number::Float(n2)) =>
+ Self::float_rational_pair(n2, n1).flip(),
+ (Number::Rational(n1), Number::Integer(n2)) =>
+ NumberPair::Rational(n1, Ratio::from_integer(n2)),
+ (Number::Integer(n1), Number::Rational(n2)) =>
+ NumberPair::Rational(Ratio::from_integer(n1), n2)
+ }
+ }
}
impl Add<Number> for Number {
type Output = Number;
fn add(self, rhs: Number) -> Self::Output {
- match (self, rhs) {
- (Number::Integer(n1), Number::Integer(n2)) =>
+ match NumberPair::from(self, rhs) {
+ NumberPair::Float(f1, f2) =>
+ Number::Float(OrderedFloat(f1.into_inner() + f2.into_inner())),
+ NumberPair::Integer(n1, n2) =>
Number::Integer(n1 + n2),
- (Number::Float(n1), Number::Float(n2)) =>
- Number::Float(OrderedFloat(n1.into_inner() + n2.into_inner())),
- (Number::Integer(n1), Number::Float(n2))
- | (Number::Float(n2), Number::Integer(n1)) =>
- match n1.to_f64() {
- Some(n1) => Number::Float(OrderedFloat(n1 + n2.into_inner())),
- None => Number::Integer(n1)
- }
+ NumberPair::Rational(r1, r2) =>
+ Number::Rational(r1 + r2)
}
}
}
type Output = Number;
fn sub(self, rhs: Number) -> Self::Output {
- match (self, rhs) {
- (Number::Integer(n1), Number::Integer(n2)) =>
+ match NumberPair::from(self, rhs) {
+ NumberPair::Float(f1, f2) =>
+ Number::Float(OrderedFloat(f1.into_inner() - f2.into_inner())),
+ NumberPair::Integer(n1, n2) =>
Number::Integer(n1 - n2),
- (Number::Float(n1), Number::Float(n2)) =>
- Number::Float(OrderedFloat(n1.into_inner() - n2.into_inner())),
- (Number::Integer(n1), Number::Float(n2))
- | (Number::Float(n2), Number::Integer(n1)) =>
- match n1.to_f64() {
- Some(n1) => Number::Float(OrderedFloat(n1 - n2.into_inner())),
- None => Number::Integer(n1)
- }
+ NumberPair::Rational(r1, r2) =>
+ Number::Rational(r1 - r2)
}
}
}
type Output = Number;
fn mul(self, rhs: Number) -> Self::Output {
- match (self, rhs) {
- (Number::Integer(n1), Number::Integer(n2)) =>
+ match NumberPair::from(self, rhs) {
+ NumberPair::Float(f1, f2) =>
+ Number::Float(OrderedFloat(f1.into_inner() * f2.into_inner())),
+ NumberPair::Integer(n1, n2) =>
Number::Integer(n1 * n2),
- (Number::Float(n1), Number::Float(n2)) =>
- Number::Float(OrderedFloat(n1.into_inner() * n2.into_inner())),
- (Number::Integer(n1), Number::Float(n2))
- | (Number::Float(n2), Number::Integer(n1)) =>
- match n1.to_f64() {
- Some(n1) => Number::Float(OrderedFloat(n1 * n2.into_inner())),
- None => Number::Integer(n1)
- }
- }
+ NumberPair::Rational(r1, r2) =>
+ Number::Rational(r1 * r2)
+ }
}
}
-
-/*TODO: reserved for proper division.
+
impl Div<Number> for Number {
type Output = Number;
fn div(self, rhs: Number) -> Self::Output {
- match (self, rhs) {
- (Number::Integer(n1), Number::Integer(n2)) =>
- Number::Integer(n1 / n2),
- (Number::Float(n1), Number::Float(n2)) =>
- Number::Float(OrderedFloat(n1.into_inner() / n2.into_inner())),
- (Number::Integer(n1), Number::Float(n2))
- | (Number::Float(n2), Number::Integer(n1)) =>
+ match NumberPair::from(self, rhs) {
+ NumberPair::Float(f1, f2) =>
+ Number::Float(OrderedFloat(f1.into_inner() / f2.into_inner())),
+ NumberPair::Integer(n1, n2) =>
match n1.to_f64() {
- Some(n1) => Number::Float(OrderedFloat(n1 / n2.into_inner())),
- None => Number::Integer(n1)
- }
+ Some(f1) => if let Some(f2) = n2.to_f64() {
+ Number::Float(OrderedFloat(f1 / f2))
+ } else {
+ let r1 = Ratio::from_integer(n1);
+ let r2 = Ratio::from_integer(n2);
+
+ Number::Rational(r1 / r2)
+ },
+ None => {
+ let r1 = Ratio::from_integer(n1);
+ let r2 = Ratio::from_integer(n2);
+
+ Number::Rational(r1 / r2)
+ },
+ },
+ NumberPair::Rational(r1, r2) =>
+ 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(f) => Number::Float(OrderedFloat(-1.0 * f.into_inner()))
+ Number::Float(f) => Number::Float(OrderedFloat(-1.0 * f.into_inner())),
+ Number::Rational(r) => Number::Rational(- r)
}
}
}
Sub(ArithmeticTerm, ArithmeticTerm, usize),
Mul(ArithmeticTerm, ArithmeticTerm, usize),
IDiv(ArithmeticTerm, ArithmeticTerm, usize),
+ RDiv(ArithmeticTerm, ArithmeticTerm, usize),
+ Div(ArithmeticTerm, ArithmeticTerm, usize),
Neg(ArithmeticTerm, usize)
}
IsExecute(RegType),
Proceed,
ThrowCall,
- ThrowExecute,
+ ThrowExecute,
}
impl ControlInstruction {
&ControlInstruction::Goto(_, _) => true,
&ControlInstruction::Proceed => true,
&ControlInstruction::IsCall(_) => true,
- &ControlInstruction::IsExecute(_) => true,
+ &ControlInstruction::IsExecute(_) => true,
_ => false
}
}
use prolog::and_stack::*;
use prolog::num::Zero;
use prolog::num::bigint::BigInt;
+use prolog::num::rational::Ratio;
use prolog::or_stack::*;
use prolog::ordered_float::OrderedFloat;
use prolog::fixtures::*;
match $e {
Ok(val) => val,
Err(msg) => {
- $s.throw_exception(string!(msg));
+ $s.throw_exception(msg);
return;
}
}
};
}
- fn get_number(&self, at: &ArithmeticTerm) -> Result<Number, &'static str> {
+ fn get_rational(&self, at: &ArithmeticTerm) -> Result<Ratio<BigInt>, Vec<HeapCellValue>> {
+ let n = self.get_number(at)?;
+
+ match n {
+ Number::Rational(r) => Ok(r),
+ Number::Float(fl) =>
+ if let Some(r) = Ratio::from_float(fl.into_inner()) {
+ Ok(r)
+ } else {
+ Err(functor!("instantiation_error", 1, [atom!("(is)/2")]))
+ },
+ Number::Integer(bi) =>
+ Ok(Ratio::from_integer(bi))
+ }
+ }
+
+ fn get_number(&self, at: &ArithmeticTerm) -> Result<Number, Vec<HeapCellValue>> {
match at {
&ArithmeticTerm::Reg(r) => {
let addr = self[r].clone();
Ok(Number::Integer(bi)),
Addr::Con(Constant::Float(fl)) =>
Ok(Number::Float(fl)),
+ Addr::Con(Constant::Rational(r)) =>
+ Ok(Number::Rational(r)),
_ =>
- Err("is/2: variable not instantiated to number.")
+ Err(functor!("instantiation_error", 1, [atom!("(is)/2")]))
}
},
&ArithmeticTerm::Interm(i) => Ok(self.interms[i-1].clone()),
self.interms[t - 1] = n1 * n2;
self.p += 1;
},
+ &ArithmeticInstruction::RDiv(ref a1, ref a2, t) => {
+ let r1 = try_or_fail!(self, self.get_rational(a1));
+ let r2 = try_or_fail!(self, self.get_rational(a2));
+
+ if r2 == Ratio::zero() {
+ self.throw_exception(functor!("evaluation_error",
+ 1,
+ [atom!("zero_divisor")]));
+ return;
+ }
+
+ self.interms[t - 1] = Number::Rational(r1 / r2);
+ 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] = - 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));
+
+ if n2.is_zero() {
+ self.throw_exception(functor!("evaluation_error",
+ 1,
+ [atom!("zero_divisor")]));
+ return;
+ }
+
+ self.interms[t - 1] = n1 / n2;
+ self.p += 1;
}
};
}