This commit is contained in:
Eryn Wells 2018-08-31 19:10:54 -07:00
parent e61dc0b6a4
commit 683e2504b9
4 changed files with 124 additions and 109 deletions

View file

@ -1,4 +1,5 @@
mod bool; mod bool;
mod number;
mod object; mod object;
mod pair; mod pair;
mod sym; mod sym;
@ -7,3 +8,5 @@ pub use bool::Bool;
pub use object::Obj; pub use object::Obj;
pub use pair::Pair; pub use pair::Pair;
pub use sym::Sym; pub use sym::Sym;
pub use self::number::Int;

View file

@ -3,40 +3,40 @@
*/ */
use std::any::Any; use std::any::Any;
use value::*; use number::Number;
use super::*; use object::{Obj, Object};
#[derive(Debug, Eq, PartialEq)] pub type Int = i64;
pub struct Integer(pub Int);
impl Number for Integer {
fn convert_down(&self) -> Option<Box<Number>> { 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::<Self>().map_or(false, |x| x == self)
}
impl Object for Int {
fn as_any(&self) -> &Any { self } fn as_any(&self) -> &Any { self }
} }
impl Number for Int {
fn as_int(&self) -> Option<&Int> { Some(self) }
}
impl PartialEq<Obj> for Int {
fn eq(&self, rhs: &Obj) -> bool {
match rhs.obj().and_then(Object::as_num) {
Some(num) => self == num,
None => false
}
}
}
impl PartialEq<Number> for Int {
fn eq(&self, rhs: &Number) -> bool {
match rhs.as_int() {
Some(rhs) => *self == *rhs,
None => false
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Integer; use super::Int;
use number::*; use number::*;
use value::*; use value::*;

View file

@ -6,16 +6,18 @@
/// ///
/// Scheme numbers are complex, literally. /// Scheme numbers are complex, literally.
mod integer;
use std::fmt; use std::fmt;
use object::Object;
pub mod real; pub use self::integer::Int;
mod add;
mod math;
pub use self::real::Real; pub trait Number:
Object
type Int = i64; {
type Flt = f64; fn as_int(&self) -> Option<&Int> { None }
}
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub enum Exact { Yes, No } 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. // TODO: Implement PartialEq myself cause there are some weird nuances to comparing numbers.
#[derive(Debug, PartialEq)] //#[derive(Debug, PartialEq)]
pub struct Number { //pub struct Number {
real: Real, // real: Real,
imag: Option<Real>, // imag: Option<Real>,
exact: Exact, // exact: Exact,
} //}
impl Number { //impl Number {
fn new(real: Real, imag: Option<Real>, exact: Exact) -> Number { // fn new(real: Real, imag: Option<Real>, exact: Exact) -> Number {
Number { // Number {
real: real.reduce(), // real: real.reduce(),
imag: imag.map(|n| n.reduce()), // imag: imag.map(|n| n.reduce()),
exact: exact, // exact: exact,
} // }
} // }
//
pub fn from_int(value: Int, exact: Exact) -> Number { // pub fn from_int(value: Int, exact: Exact) -> Number {
Number::new(Real::Integer(value), None, exact) // Number::new(Real::Integer(value), None, exact)
} // }
//
pub fn from_quotient(p: Int, q: Int, exact: Exact) -> Number { // pub fn from_quotient(p: Int, q: Int, exact: Exact) -> Number {
let real = if exact == Exact::Yes { // let real = if exact == Exact::Yes {
// Make an exact rational an integer if possible. // // Make an exact rational an integer if possible.
Real::Rational(p, q).demote() // Real::Rational(p, q).demote()
} // }
else { // else {
// Make an inexact rational an irrational. // // Make an inexact rational an irrational.
Real::Rational(p, q).promote_once() // Real::Rational(p, q).promote_once()
}; // };
Number::new(real, None, exact) // Number::new(real, None, exact)
} // }
//
pub fn from_float(value: Flt, exact: Exact) -> Number { // pub fn from_float(value: Flt, exact: Exact) -> Number {
let real = if exact == Exact::Yes { // let real = if exact == Exact::Yes {
// Attempt to demote irrationals. // // Attempt to demote irrationals.
Real::Irrational(value).demote() // Real::Irrational(value).demote()
} // }
else { // else {
Real::Irrational(value) // Real::Irrational(value)
}; // };
Number::new(real, None, exact) // Number::new(real, None, exact)
} // }
//
pub fn is_exact(&self) -> bool { // pub fn is_exact(&self) -> bool {
match self.exact { // match self.exact {
Exact::Yes => true, // Exact::Yes => true,
Exact::No => false, // Exact::No => false,
} // }
} // }
} //}
//
impl fmt::Display for Number { //impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.real).and_then( // write!(f, "{}", self.real).and_then(
|r| self.imag.map(|i| write!(f, "{:+}i", i)).unwrap_or(Ok(r))) // |r| self.imag.map(|i| write!(f, "{:+}i", i)).unwrap_or(Ok(r)))
} // }
} //}
//
#[cfg(test)] //#[cfg(test)]
mod tests { //mod tests {
use super::Exact; // use super::Exact;
use super::Number; // use super::Number;
use super::real::Real; // use super::real::Real;
//
#[test] // #[test]
fn exact_numbers_are_exact() { // fn exact_numbers_are_exact() {
assert!(Number::from_int(3, Exact::Yes).is_exact()); // assert!(Number::from_int(3, Exact::Yes).is_exact());
assert!(!Number::from_int(3, Exact::No).is_exact()); // assert!(!Number::from_int(3, Exact::No).is_exact());
} // }
//
#[test] // #[test]
fn exact_irrationals_are_reduced() { // fn exact_irrationals_are_reduced() {
let real = Real::Rational(3, 2); // let real = Real::Rational(3, 2);
assert_eq!(Number::from_float(1.5, Exact::Yes), Number::new(real, None, Exact::Yes)); // assert_eq!(Number::from_float(1.5, Exact::Yes), Number::new(real, None, Exact::Yes));
} // }
} //}

View file

@ -18,6 +18,7 @@ use std::mem;
use std::any::Any; use std::any::Any;
use std::fmt; use std::fmt;
use super::*; use super::*;
use number::Number;
#[derive(Debug)] #[derive(Debug)]
pub enum Obj { pub enum Obj {
@ -38,6 +39,8 @@ pub trait Object:
fn as_pair(&self) -> Option<&Pair> { None } fn as_pair(&self) -> Option<&Pair> { None }
/// Cast this Object to a Sym if possible. /// Cast this Object to a Sym if possible.
fn as_sym(&self) -> Option<&Sym> { None } fn as_sym(&self) -> Option<&Sym> { None }
/// Cast this Object to a Number if possible.
fn as_num(&self) -> Option<&Number> { None }
} }
impl Obj { impl Obj {
@ -45,6 +48,13 @@ impl Obj {
Obj::Ptr(Box::new(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 { pub fn take(&mut self) -> Obj {
// Stole Option's implementation of this. Handy. :D // Stole Option's implementation of this. Handy. :D
mem::replace(self, Obj::Null) mem::replace(self, Obj::Null)