openbirch-rs/src/lib/node/add.rs
2025-02-24 15:26:49 +01:00

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()
}
}