diff --git a/types/src/lib.rs b/types/src/lib.rs index 95037dc..7632128 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -1,4 +1,5 @@ mod bool; +mod number; mod object; mod pair; mod sym; @@ -7,3 +8,5 @@ pub use bool::Bool; pub use object::Obj; pub use pair::Pair; pub use sym::Sym; + +pub use self::number::Int; diff --git a/types/src/number/integer.rs b/types/src/number/integer.rs index cad3893..a11024b 100644 --- a/types/src/number/integer.rs +++ b/types/src/number/integer.rs @@ -3,40 +3,40 @@ */ use std::any::Any; -use value::*; -use super::*; +use number::Number; +use object::{Obj, Object}; -#[derive(Debug, Eq, PartialEq)] -pub struct Integer(pub Int); - -impl Number for Integer { - fn convert_down(&self) -> Option> { None } - - fn is_exact(&self) -> bool { true } -} - -impl Value for Integer { - fn as_value(&self) -> &Value { self } -} - -impl IsBool for Integer { } -impl IsChar for Integer { } - -impl IsNumber for Integer { - fn is_integer(&self) -> bool { true } -} - -impl ValueEq for Integer { - fn eq(&self, other: &Value) -> bool { - other.as_any().downcast_ref::().map_or(false, |x| x == self) - } +pub type Int = i64; +impl Object for Int { fn as_any(&self) -> &Any { self } } +impl Number for Int { + fn as_int(&self) -> Option<&Int> { Some(self) } +} + +impl PartialEq for Int { + fn eq(&self, rhs: &Obj) -> bool { + match rhs.obj().and_then(Object::as_num) { + Some(num) => self == num, + None => false + } + } +} + +impl PartialEq for Int { + fn eq(&self, rhs: &Number) -> bool { + match rhs.as_int() { + Some(rhs) => *self == *rhs, + None => false + } + } +} + #[cfg(test)] mod tests { - use super::Integer; + use super::Int; use number::*; use value::*; diff --git a/types/src/number/mod.rs b/types/src/number/mod.rs index f79ad46..122214e 100644 --- a/types/src/number/mod.rs +++ b/types/src/number/mod.rs @@ -6,16 +6,18 @@ /// /// Scheme numbers are complex, literally. +mod integer; + use std::fmt; +use object::Object; -pub mod real; -mod add; -mod math; +pub use self::integer::Int; -pub use self::real::Real; - -type Int = i64; -type Flt = f64; +pub trait Number: + Object +{ + fn as_int(&self) -> Option<&Int> { None } +} #[derive(Debug, Eq, PartialEq)] pub enum Exact { Yes, No } @@ -30,79 +32,79 @@ impl fmt::Display for Exact { } // TODO: Implement PartialEq myself cause there are some weird nuances to comparing numbers. -#[derive(Debug, PartialEq)] -pub struct Number { - real: Real, - imag: Option, - exact: Exact, -} +//#[derive(Debug, PartialEq)] +//pub struct Number { +// real: Real, +// imag: Option, +// exact: Exact, +//} -impl Number { - fn new(real: Real, imag: Option, exact: Exact) -> Number { - Number { - real: real.reduce(), - imag: imag.map(|n| n.reduce()), - exact: exact, - } - } - - pub fn from_int(value: Int, exact: Exact) -> Number { - Number::new(Real::Integer(value), None, exact) - } - - pub fn from_quotient(p: Int, q: Int, exact: Exact) -> Number { - let real = if exact == Exact::Yes { - // Make an exact rational an integer if possible. - Real::Rational(p, q).demote() - } - else { - // Make an inexact rational an irrational. - Real::Rational(p, q).promote_once() - }; - Number::new(real, None, exact) - } - - pub fn from_float(value: Flt, exact: Exact) -> Number { - let real = if exact == Exact::Yes { - // Attempt to demote irrationals. - Real::Irrational(value).demote() - } - else { - Real::Irrational(value) - }; - Number::new(real, None, exact) - } - - pub fn is_exact(&self) -> bool { - match self.exact { - Exact::Yes => true, - Exact::No => false, - } - } -} - -impl fmt::Display for Number { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.real).and_then( - |r| self.imag.map(|i| write!(f, "{:+}i", i)).unwrap_or(Ok(r))) - } -} - -#[cfg(test)] -mod tests { - use super::Exact; - use super::Number; - use super::real::Real; - - #[test] - fn exact_numbers_are_exact() { - assert!(Number::from_int(3, Exact::Yes).is_exact()); - assert!(!Number::from_int(3, Exact::No).is_exact()); - } - - #[test] - fn exact_irrationals_are_reduced() { - let real = Real::Rational(3, 2); - assert_eq!(Number::from_float(1.5, Exact::Yes), Number::new(real, None, Exact::Yes)); - } -} +//impl Number { +// fn new(real: Real, imag: Option, exact: Exact) -> Number { +// Number { +// real: real.reduce(), +// imag: imag.map(|n| n.reduce()), +// exact: exact, +// } +// } +// +// pub fn from_int(value: Int, exact: Exact) -> Number { +// Number::new(Real::Integer(value), None, exact) +// } +// +// pub fn from_quotient(p: Int, q: Int, exact: Exact) -> Number { +// let real = if exact == Exact::Yes { +// // Make an exact rational an integer if possible. +// Real::Rational(p, q).demote() +// } +// else { +// // Make an inexact rational an irrational. +// Real::Rational(p, q).promote_once() +// }; +// Number::new(real, None, exact) +// } +// +// pub fn from_float(value: Flt, exact: Exact) -> Number { +// let real = if exact == Exact::Yes { +// // Attempt to demote irrationals. +// Real::Irrational(value).demote() +// } +// else { +// Real::Irrational(value) +// }; +// Number::new(real, None, exact) +// } +// +// pub fn is_exact(&self) -> bool { +// match self.exact { +// Exact::Yes => true, +// Exact::No => false, +// } +// } +//} +// +//impl fmt::Display for Number { +// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +// write!(f, "{}", self.real).and_then( +// |r| self.imag.map(|i| write!(f, "{:+}i", i)).unwrap_or(Ok(r))) +// } +//} +// +//#[cfg(test)] +//mod tests { +// use super::Exact; +// use super::Number; +// use super::real::Real; +// +// #[test] +// fn exact_numbers_are_exact() { +// assert!(Number::from_int(3, Exact::Yes).is_exact()); +// assert!(!Number::from_int(3, Exact::No).is_exact()); +// } +// +// #[test] +// fn exact_irrationals_are_reduced() { +// let real = Real::Rational(3, 2); +// assert_eq!(Number::from_float(1.5, Exact::Yes), Number::new(real, None, Exact::Yes)); +// } +//} diff --git a/types/src/object.rs b/types/src/object.rs index 0b988ba..3eb2201 100644 --- a/types/src/object.rs +++ b/types/src/object.rs @@ -18,6 +18,7 @@ use std::mem; use std::any::Any; use std::fmt; use super::*; +use number::Number; #[derive(Debug)] pub enum Obj { @@ -38,6 +39,8 @@ pub trait Object: fn as_pair(&self) -> Option<&Pair> { None } /// Cast this Object to a Sym if possible. fn as_sym(&self) -> Option<&Sym> { None } + /// Cast this Object to a Number if possible. + fn as_num(&self) -> Option<&Number> { None } } impl Obj { @@ -45,6 +48,13 @@ impl Obj { Obj::Ptr(Box::new(obj)) } + pub fn obj<'a>(&'a self) -> Option<&'a Object> { + match self { + Obj::Ptr(obj) => Some(obj.deref()), + Obj::Null => None + } + } + pub fn take(&mut self) -> Obj { // Stole Option's implementation of this. Handy. :D mem::replace(self, Obj::Null)