calculatex/
expr.rs

1pub mod val;
2
3use crate::{function::eval_fn_call, parser::fn_call::FnCall};
4use std::convert::TryFrom;
5
6use val::*;
7
8pub mod unit;
9use unit::*;
10
11pub mod unit_expr;
12
13use crate::{error::CalcError, statement::Scope};
14
15#[derive(Debug, Clone)]
16pub enum Expr {
17    Atom(Val),
18    ParenExpr(Box<Expr>),
19    Ident(String),
20    FnCall(FnCall),
21    Cons(Op, Vec<Expr>),
22}
23
24impl std::fmt::Display for Expr {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        match self {
27            Expr::Atom(v) => write!(f, "{}", v),
28            Expr::ParenExpr(e) => write!(f, "({:?})", e),
29            Expr::Ident(n) => write!(f, "{}", n),
30            Expr::FnCall(fc) => write!(f, "{:?}", fc),
31            Expr::Cons(op, e) => write!(f, "({:?}, {:?})", op, e),
32        }
33    }
34}
35
36impl Expr {
37    pub fn eval(&self, scope: &Scope) -> Result<Val, CalcError> {
38        let e = |a: &Expr| a.eval(scope);
39        Ok(match self {
40            Expr::Atom(v) => v.clamp_num(),
41            Expr::ParenExpr(ex) => e(ex)?,
42            Expr::Ident(n) => {
43                if let Some(v) = scope.variables.get(n) {
44                    v.clone()
45                } else {
46                    (1.0, Unit::try_from(n)?).into()
47                }
48            }
49            Expr::FnCall(fc) => eval_fn_call(fc, scope)?,
50            Expr::Cons(op, xs) => match (op, xs.as_slice()) {
51                (Op::Plus, [a, b]) => (e(a)? + e(b)?)?,
52                (Op::Minus, [a, b]) => (e(a)? - e(b)?)?,
53                (Op::Mul, [a, b]) => e(a)? * e(b)?,
54                (Op::Div, [a, b]) => e(a)? / e(b)?,
55                (Op::Exp, [a, b]) => e(a)?.pow(&e(b)?),
56                (Op::AddUnit(u, _), [v]) => e(v)?.with_unit(&u),
57                _ => return Err(CalcError::MathError),
58            },
59        })
60    }
61
62    pub fn remove_parens(&self) -> Self {
63        if let Expr::ParenExpr(b) = self {
64            *b.clone()
65        } else {
66            self.clone()
67        }
68    }
69}
70
71#[derive(Debug, Clone)]
72pub enum Op {
73    Plus,
74    Minus,
75    Mul,
76    Div,
77    Exp,
78    AddUnit(Unit, String),
79}