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 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;

View file

@ -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<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)
}
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<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)]
mod tests {
use super::Integer;
use super::Int;
use number::*;
use value::*;

View file

@ -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<Real>,
exact: Exact,
}
//#[derive(Debug, PartialEq)]
//pub struct Number {
// real: Real,
// imag: Option<Real>,
// exact: Exact,
//}
impl Number {
fn new(real: Real, imag: Option<Real>, 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<Real>, 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));
// }
//}

View file

@ -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)