use std::rc::Rc; use rug::Float; use super::{ Environment, Node, NodeEnum, Precedence, constant::Constant, set::Set, string_node::StringNode, }; #[derive(Clone, Debug, PartialEq, PartialOrd)] pub struct Add { left: Rc, right: Rc, } impl Node for Add { fn evaluate(&self, env: &mut Environment) -> Result, String> { let evaluated_left = self.left.evaluate(env)?; let evaluated_right = self.right.evaluate(env)?; match (evaluated_left.as_ref(), evaluated_right.as_ref()) { // Zero rule (NodeEnum::Constant(zero), _) if zero.get_value() == &0.0 => Ok(evaluated_right), (_, NodeEnum::Constant(zero)) if zero.get_value() == &0.0 => Ok(evaluated_left), // Constant + Constant = Constant (NodeEnum::Constant(a), NodeEnum::Constant(b)) => Ok(Rc::new( Constant::new(Float::with_val_64( env.get_float_precision(), a.get_value() + b.get_value(), )) .into(), )), // Move constants after symbols in add (NodeEnum::Constant(_), NodeEnum::Symbol(_)) => { Ok(Rc::new(Add::new(evaluated_right, evaluated_left).into())) } // Concatenate sets (NodeEnum::Set(s1), NodeEnum::Set(s2)) => { let values = { let mut v = s1.get_values().clone(); v.append(&mut s2.get_values().clone()); v }; Ok(Set::new(values)) } // Concatenate strings (NodeEnum::StringNode(s1), NodeEnum::StringNode(s2)) => { Ok(StringNode::new(s1.get_value().clone() + s2.get_value())) } _ => Ok(Rc::new(Add::new(evaluated_left, evaluated_right).into())), } } fn as_string(&self, env: Option<&Environment>) -> String { let left_string = if self.left.precedence() <= self.precedence() { format!("({})", self.left.as_string(env)) } else { self.left.as_string(env) }; let right_string = if self.right.precedence() <= self.precedence() { format!("({})", self.right.as_string(env)) } else { self.right.as_string(env) }; format!("{}+{}", left_string, right_string) } fn precedence(&self) -> Precedence { Precedence::Term } } impl Add { pub fn new(left: Rc, right: Rc) -> Self { Self { left, right } } pub fn new_rc(left: Rc, right: Rc) -> Rc { Rc::new(Self { left, right }.into()) } pub fn get_left(&self) -> Rc { self.left.clone() } pub fn get_right(&self) -> Rc { self.right.clone() } }