use std::{ops::{Add, Sub, Mul, Div, Shl, Shr, BitOr, BitAnd, BitXor, Neg, Not}, cmp::Ordering}; use crate::prelude::*; fn ratio_to_f64(r: Rational64) -> f64 { *r.numer() as f64 / *r.denom() as f64 } macro_rules! error { ($($arg:tt)*) => { exception!(VALUE_EXCEPTION, $($arg)*) }; } /// /// MATH OPERATIONS /// fn ipow(n: i64, d: i64, p: i64) -> Result<(i64, i64)> { Ok(match (n, d, p) { (0, _, 0) => Err(error!("cannot exponent 0 ** 0"))?, (0, _, _) => (0, 1), (_, _, 0) => (1, 1), (1, 1, _) => (1, 1), (n, d, p) if p < 0 => (d.pow((-p) as u32), n.pow((-p) as u32)), (n, d, p) => (n.pow(p as u32), d.pow(p as u32)), }) } fn promote(a: Value, b: Value) -> (Value, Value) { use Value as V; match (&a, &b) { (V::Int(x), V::Ratio(..)) => (V::Ratio((*x).into()), b), (V::Int(x), V::Float(..)) => (V::Float(*x as f64), b), (V::Int(x), V::Complex(..)) => (V::Complex((*x as f64).into()), b), (V::Ratio(x), V::Float(..)) => (V::Float(ratio_to_f64(*x)), b), (V::Ratio(x), V::Complex(..)) => (V::Complex(ratio_to_f64(*x).into()), b), (V::Float(x), V::Complex(..)) => (V::Complex((*x).into()), b), (V::Ratio(..), V::Int(y)) => (a, V::Ratio((*y).into())), (V::Float(..), V::Int(y)) => (a, V::Float(*y as f64)), (V::Complex(..), V::Int(y)) => (a, V::Complex((*y as f64).into())), (V::Float(..), V::Ratio(y)) => (a, V::Float(ratio_to_f64(*y))), (V::Complex(..), V::Ratio(y)) => (a, V::Complex(ratio_to_f64(*y).into())), (V::Complex(..), V::Float(y)) => (a, V::Complex((*y).into())), (V::List(l1), V::List(l2)) if l1.len() > 0 && l2.len() > 0 => (V::Matrix(Matrix::from_list(l1.to_vec()).into()), V::Matrix(Matrix::from_list(l2.to_vec()).into())), (_, V::List(l)) if l.len() > 0 => (a, V::Matrix(Matrix::from_list(l.to_vec()).into())), (V::List(l), _) if l.len() > 0 => (V::Matrix(Matrix::from_list(l.to_vec()).into()), b), _ => (a, b), } } impl Add for Value { type Output = Result; fn add(self, rhs: Self) -> Self::Output { use Value::*; match promote(self, rhs) { (Int(x), Int(y)) => Ok(Int(x + y)), (Float(x), Float(y)) => Ok(Float(x + y)), (Ratio(x), Ratio(y)) => Ok(Ratio(x + y)), (Complex(x), Complex(y)) => Ok(Complex(x + y)), (Matrix(x), Matrix(y)) => Ok(Matrix((x + y)?.into())), (Matrix(x), r) => Ok(Matrix(x.increment(r)?.into())), (l, Matrix(y)) => Ok(Matrix(y.increment(l)?.into())), (String(str), value) => Ok(String(Rc::from( format!("{str}{value}") ))), (value, String(str)) => Ok(String(Rc::from( format!("{value}{str}") ))), (List(mut l1), List(l2)) => { l1.extend_from_slice(&l2); Ok(List(l1)) }, (l, r) => Err(error!("cannot add {l:?} + {r:?}")) } } } impl Sub for Value { type Output = Result; fn sub(self, rhs: Self) -> Self::Output { use Value::*; match promote(self, rhs) { (Int(x), Int(y)) => Ok(Int(x - y)), (Float(x), Float(y)) => Ok(Float(x - y)), (Ratio(x), Ratio(y)) => Ok(Ratio(x - y)), (Complex(x), Complex(y)) => Ok(Complex(x - y)), (Matrix(x), Matrix(y)) => Ok(Matrix((x - y)?.into())), (Matrix(x), r) => Ok(Matrix(x.decrement(r)?.into())), (l, r) => Err(error!("cannot subtract {l:?} - {r:?}")) } } } impl Mul for Value { type Output = Result; fn mul(self, rhs: Value) -> Self::Output { use Value::*; match promote(self, rhs) { (Int(x), Int(y)) => Ok(Int(x * y)), (Float(x), Float(y)) => Ok(Float(x * y)), (Ratio(x), Ratio(y)) => Ok(Ratio(x * y)), (Complex(x), Complex(y)) => Ok(Complex(x * y)), (Matrix(x), Matrix(y)) => Ok(Matrix((x * y)?.into())), (Matrix(x), r) => Ok(Matrix(x.scale(r)?.into())), (l, Matrix(y)) => Ok(Matrix(y.scale(l)?.into())), (l, r) => Err(error!("cannot multiply {l:?} * {r:?}")) } } } impl Div for Value { type Output = Result; fn div(self, rhs: Value) -> Self::Output { use Value::*; match promote(self, rhs) { (Int(_), Int(0)) => Err(error!("cannot divide by zero")), (Int(x), Int(y)) => Ok(Ratio(Rational64::new(x, y))), (Float(x), Float(y)) => Ok(Float(x / y)), (Ratio(x), Ratio(y)) => Ok(Ratio(x / y)), (Complex(x), Complex(y)) => Ok(Complex(x / y)), (l, r) => Err(error!("cannot divide {l:?} / {r:?}")) } } } impl BitOr for Value { type Output = Result; fn bitor(self, rhs: Value) -> Self::Output { use Value::*; match promote(self, rhs) { (Int(x), Int(y)) => Ok(Int(x | y)), (l, r) => Err(error!("cannot bitwise or {l:?} | {r:?}")) } } } impl BitAnd for Value { type Output = Result; fn bitand(self, rhs: Value) -> Self::Output { use Value::*; match promote(self, rhs) { (Int(x), Int(y)) => Ok(Int(x & y)), (l, r) => Err(error!("cannot bitwise and {l:?} & {r:?}")) } } } impl BitXor for Value { type Output = Result; fn bitxor(self, rhs: Value) -> Self::Output { use Value::*; match promote(self, rhs) { (Int(x), Int(y)) => Ok(Int(x ^ y)), (l, r) => Err(error!("cannot bitwise xor {l:?} ^ {r:?}")) } } } impl Shl for Value { type Output = Result; fn shl(self, rhs: Value) -> Self::Output { use Value::*; match promote(self, rhs) { (Int(x), Int(y)) => Ok(Int(x << y)), (l, r) => Err(error!("cannot bitwise shift left {l:?} << {r:?}")) } } } impl Shr for Value { type Output = Result; fn shr(self, rhs: Value) -> Self::Output { use Value::*; match promote(self, rhs) { (Int(x), Int(y)) => Ok(Int(x >> y)), (l, r) => Err(error!("cannot bitwise shift right {l:?} >> {r:?}")) } } } impl PartialEq for Value { fn eq(&self, other: &Self) -> bool { use Value::*; match (self, other) { (Nil, Nil) => true, (Bool(a), Bool(b)) => a == b, (Int(a), Int(b)) => *a == *b, (Ratio(a), Ratio(b)) => *a == *b, (Float(a), Float(b)) => *a == *b, (Complex(a), Complex(b)) => *a == *b, (Int(a), Ratio(b)) => Rational64::from(*a) == *b, (Ratio(a), Int(b)) => *a == Rational64::from(*b), (Int(a), Float(b)) => *a as f64 == *b, (Float(a), Int(b)) => *a == *b as f64, (Int(a), Complex(b)) => Complex64::from(*a as f64) == *b, (Complex(a), Int(b)) => *a == Complex64::from(*b as f64), (Ratio(a), Float(b)) => ratio_to_f64(*a) == *b, (Float(a), Ratio(b)) => *a == ratio_to_f64(*b), (Ratio(a), Complex(b)) => Complex64::from(ratio_to_f64(*a)) == *b, (Complex(a), Ratio(b)) => *a == Complex64::from(ratio_to_f64(*b)), (Float(a), Complex(b)) => Complex64::from(*a) == *b, (Complex(a), Float(b)) => *a == Complex64::from(*b), (String(a), String(b)) => *a == *b, (List(a), List(b)) => *a == *b, (Matrix(a), Matrix(b)) => a == b, _ => false, } } } impl PartialOrd for Value { fn partial_cmp(&self, other: &Self) -> Option { use Value::*; match (self, other) { (Nil, Nil) => Some(Ordering::Equal), (Bool(a), Bool(b)) => a.partial_cmp(b), (Int(a), Int(b)) => a.partial_cmp(b), (Ratio(a), Ratio(b)) => a.partial_cmp(b), (Float(a), Float(b)) => a.partial_cmp(b), (Int(a), Ratio(b)) => Rational64::from(*a).partial_cmp(b), (Ratio(a), Int(b)) => a.partial_cmp(&Rational64::from(*b)), (Int(a), Float(b)) => (*a as f64).partial_cmp(b), (Float(a), Int(b)) => a.partial_cmp(&(*b as f64)), (Ratio(a), Float(b)) => ratio_to_f64(*a).partial_cmp(b), (Float(a), Ratio(b)) => a.partial_cmp(&ratio_to_f64(*b)), (String(a), String(b)) => a.partial_cmp(b), (List(a), List(b)) => a.partial_cmp(b), (Matrix(a), Matrix(b)) => a.values.partial_cmp(&b.values), _ => None, } } } impl Neg for Value { type Output = Value; fn neg(self) -> Self::Output { use Value::*; match self { Bool(b) => Bool(!b), Int(i) => Int(-i), Float(f) => Float(-f), Ratio(r) => Ratio(-r), Complex(c) => Complex(-c), _ => return Float(f64::NAN) } } } impl Not for Value { type Output = bool; fn not(self) -> Self::Output { use Value as V; match self { V::Nil => true, V::Bool(b) => !b, V::Int(i) => i == 0, V::Float(f) => f == 0.0, V::Ratio(r) => *(r.numer()) == 0 || *(r.denom()) == 0, V::Complex(c) => !c.is_normal(), V::Regex(_) => false, V::List(_) => false, V::Matrix(_) => false, V::Table(_) => false, V::String(s) => s.as_ref() == "", V::Function(_) => false, V::Iter(_) => false, V::Range(_) => false, V::File(_) => false, V::Exception(_) => false, } } } impl Value { pub fn modulo(self, rhs: Value) -> Result { use Value::*; match promote(self, rhs) { (Int(x), Int(y)) => Ok(Int(x % y)), (Float(x), Float(y)) => Ok(Float(x % y)), (Ratio(x), Ratio(y)) => Ok(Ratio(x % y)), (Complex(x), Complex(y)) => Ok(Complex(x % y)), (l, r) => Err(error!("cannot modulo: {l:?} % {r:?}")) } } pub fn pow(self, rhs: Value) -> Result { use Value::*; if let (Ratio(x), Int(y)) = (&self, &rhs) { return Ok(Ratio(ipow(*(*x).numer(), *(*x).denom(), *y)?.into())); } match promote(self, rhs) { (Int(x), Int(y)) => Ok(Ratio(ipow(x, 1, y)?.into())), (Float(x), Float(y)) => Ok(Float(x.powf(y))), (Ratio(x), Ratio(y)) => Ok(Float(ratio_to_f64(x).powf(ratio_to_f64(y)))), (Complex(x), Complex(y)) => Ok(Complex(x.powc(y))), (l, r) => Err(error!("cannot exponent: {l:?} ** {r:?}")) } } pub fn floaty(self) -> Self { use Value as V; match self { V::Int(i) => V::Float(i as f64), V::Ratio(r) => V::Float(ratio_to_f64(r)), a => a } } pub fn is_zero(&self) -> bool { use Value as V; match self { V::Int(i) => *i == 0, V::Float(f) => *f == 0.0 || *f == -0.0, V::Ratio(r) => *r.numer() == 0, _ => false, } } pub fn binary_op(op: BinaryOp, lhs: Value, rhs: Value) -> Result { use BinaryOp::*; match op { Add => lhs + rhs, Subtract => lhs - rhs, Multiply => lhs * rhs, Divide => lhs / rhs, Modulo => lhs.modulo(rhs), Power => lhs.pow(rhs), BitwiseAnd => lhs & rhs, BitwiseOr => lhs | rhs, BitwiseXor => lhs ^ rhs, BitwiseShiftLeft => lhs << rhs, BitwiseShiftRight => lhs >> rhs, Equals => Ok(Self::Bool(lhs == rhs)), NotEquals => Ok(Self::Bool(lhs != rhs)), GreaterEquals => Ok(Self::Bool(lhs >= rhs)), LessEquals => Ok(Self::Bool(lhs <= rhs)), GreaterThan => Ok(Self::Bool(lhs > rhs)), LessThan => Ok(Self::Bool(lhs < rhs)), Range | RangeEq => { let Value::Int(lhs) = lhs else { return Err(error!("range can only take [Int]'s")) }; let Value::Int(rhs) = rhs else { return Err(error!("range can only take [Int]'s")) }; Ok(Self::Range(Rc::new((lhs, rhs, op == RangeEq)))) }, } } pub fn unary_op(op: UnaryOp, val: Value) -> Value { use UnaryOp::*; match op { Negate => -val, Not => Self::Bool(!val), } } pub fn to_regex(value: &str) -> Result { match Regex::new(value) { Ok(r) => Ok(Self::Regex(r.into())), Err(e) => Err(error!("{e}")), } } }