mathengine_evaluator/
lib.rs1use mathengine_lexer::Operation;
2use mathengine_parser::{
3 Expression,
4 types::{Number, UnitValue, Value},
5};
6
7pub mod error;
8pub use error::EvalError;
9
10pub fn evaluate(expr: &Expression) -> Result<Value, EvalError> {
11 match expr {
12 Expression::Number(n) => Ok(Value::Number(Number::from(*n))),
13 Expression::UnitValue { value, unit } => {
14 Ok(Value::UnitValue(UnitValue::new(*value, unit.clone())))
15 }
16 Expression::Unit(_unit) => Err(EvalError::InvalidUnitExpression {
17 message: "Cannot evaluate a unit without a value".to_string(),
18 }),
19 Expression::Binary { op, left, right } => match op {
20 Operation::Convert => {
21 let left_val = evaluate(left)?;
22 let (value, from_unit) = match left_val {
23 Value::UnitValue(uv) => (uv.value(), uv.unit().to_string()),
24 _ => {
25 return Err(EvalError::InvalidUnitExpression {
26 message: "Left side of conversion must be a unit value".to_string(),
27 });
28 }
29 };
30
31 let to_unit = match right.as_ref() {
32 Expression::Unit(u) => u,
33 _ => {
34 return Err(EvalError::InvalidUnitExpression {
35 message: "Right side of conversion must be a unit".to_string(),
36 });
37 }
38 };
39
40 let unit_value = UnitValue::new(value, from_unit.clone());
42 let converted = unit_value.convert_to(to_unit)?;
43
44 Ok(Value::UnitValue(converted))
45 }
46 _ => {
47 let left_val = evaluate(left)?;
48 let right_val = evaluate(right)?;
49
50 if let Operation::Divide = op {
52 match &right_val {
53 Value::Number(n) if n.0 == 0.0 => return Err(EvalError::DivisionByZero),
54 _ => {}
55 }
56 }
57
58 let result = match op {
59 Operation::Add => left_val + right_val,
60 Operation::Subtract => left_val - right_val,
61 Operation::Multiply => left_val * right_val,
62 Operation::Divide => left_val / right_val,
63 Operation::Power => {
64 match (left_val, right_val) {
66 (Value::Number(l), Value::Number(r)) => {
67 Value::Number(Number::from(l.0.powf(r.0)))
68 }
69 _ => {
70 return Err(EvalError::UnsupportedOperation {
71 operation: "power".to_string(),
72 operand_type: "non-numeric values".to_string(),
73 });
74 }
75 }
76 }
77 Operation::Convert => {
78 return Err(EvalError::UnsupportedOperation {
79 operation: "convert".to_string(),
80 operand_type: "binary operation".to_string(),
81 });
82 }
83 };
84
85 Ok(result)
86 }
87 },
88 Expression::Unary { op, operand } => {
89 let val = evaluate(operand)?;
90 match op {
91 Operation::Subtract => match val {
92 Value::Number(n) => Ok(Value::Number(-n)),
93 Value::UnitValue(_) => Err(EvalError::UnsupportedOperation {
94 operation: "negate".to_string(),
95 operand_type: "unit value".to_string(),
96 }),
97 },
98 _ => Err(EvalError::UnsupportedOperation {
99 operation: format!("{:?}", op),
100 operand_type: "unary operand".to_string(),
101 }),
102 }
103 }
104 }
105}
106