94 lines
2.8 KiB
Rust
94 lines
2.8 KiB
Rust
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<NodeEnum>,
|
|
right: Rc<NodeEnum>,
|
|
}
|
|
|
|
impl Node for Add {
|
|
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, 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<NodeEnum>, right: Rc<NodeEnum>) -> Self {
|
|
Self { left, right }
|
|
}
|
|
|
|
pub fn new_rc(left: Rc<NodeEnum>, right: Rc<NodeEnum>) -> Rc<NodeEnum> {
|
|
Rc::new(Self { left, right }.into())
|
|
}
|
|
|
|
pub fn get_left(&self) -> Rc<NodeEnum> {
|
|
self.left.clone()
|
|
}
|
|
|
|
pub fn get_right(&self) -> Rc<NodeEnum> {
|
|
self.right.clone()
|
|
}
|
|
}
|