use std::{ cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}, convert::From, fmt, ops::{Add, Mul, Sub}, }; use crate::lisp::error::{EvalError, LispError}; #[derive(Debug, Copy, Clone)] pub enum LispNumber { Integer(i64), Float(f64), } impl LispNumber { pub fn div(self, rhs: Self) -> Result { use LispNumber::*; if rhs == Integer(0) || rhs == Float(0.) { Err(EvalError::DivByZero.into()) } else { Ok(match (self, rhs) { (Integer(a), Integer(b)) => Float(a as f64 / b as f64), (Float(a), Integer(b)) => Float(a / b as f64), (Integer(a), Float(b)) => Float(a as f64 / b), (Float(a), Float(b)) => Float(a / b), }) } } pub fn unwrap_integer(self) -> i64 { match self { Self::Integer(x) => x, Self::Float(x) => x.floor() as i64, // lossy } } } impl Add for LispNumber { type Output = Self; fn add(self, rhs: Self) -> Self::Output { use LispNumber::*; match (self, rhs) { (Integer(a), Integer(b)) => Integer(a + b), (Float(a), Integer(b)) => Float(a + b as f64), (Integer(a), Float(b)) => Float(a as f64 + b), (Float(a), Float(b)) => Float(a + b), } } } impl Sub for LispNumber { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { use LispNumber::*; match (self, rhs) { (Integer(a), Integer(b)) => Integer(a - b), (Float(a), Integer(b)) => Float(a - b as f64), (Integer(a), Float(b)) => Float(a as f64 - b), (Float(a), Float(b)) => Float(a - b), } } } impl Mul for LispNumber { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { use LispNumber::*; match (self, rhs) { (Integer(a), Integer(b)) => Integer(a * b), (Float(a), Integer(b)) => Float(a * b as f64), (Integer(a), Float(b)) => Float(a as f64 * b), (Float(a), Float(b)) => Float(a * b), } } } impl PartialEq for LispNumber { fn eq(&self, other: &Self) -> bool { use LispNumber::*; match (self, other) { (Integer(a), Integer(b)) => *a == *b, (Float(a), Integer(b)) => *a == *b as f64, (Integer(a), Float(b)) => *a as f64 == *b, (Float(a), Float(b)) => *a == *b, } } } impl Eq for LispNumber {} impl Ord for LispNumber { fn cmp(&self, other: &Self) -> Ordering { use LispNumber::*; match (*self, *other) { (Integer(a), Integer(b)) => a.cmp(&b), (Float(a), Integer(b)) => (a as i64).cmp(&b), (Integer(a), Float(b)) => a.cmp(&(b as i64)), (Float(a), Float(b)) => (a as i64).cmp(&(b as i64)), } } } impl PartialOrd for LispNumber { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl fmt::Display for LispNumber { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { LispNumber::Integer(v) => write!(f, "{}", v), LispNumber::Float(v) => write!(f, "{}", v), } } } impl From for LispNumber { fn from(target: i64) -> Self { LispNumber::Integer(target) } }