aboutsummaryrefslogtreecommitdiff
path: root/src/expression.rs
blob: c7574a961db59a0aa493fee4d8ccd64772800113 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use crate::complex::Complex;
use crate::context::Context;
use crate::function::FunctionArgument;
use crate::string::{ContainsAndSkipBrackets, SplitMatchingBracket};

pub struct Expression {
    repr: String,
}

impl Expression {
    pub fn from_string(str: &str) -> Self {
        Self {
            repr: str.replace(' ', ""),
        }
    }

    pub fn evaluate(&self, context: &Context) -> Result<Complex, String> {
        let (repr, oprepr) = {
            if self.repr.starts_with('(') {
                let (oprepr, r) = self.repr.split_on_matching_bracket();
                if r.is_empty() {
                    let repr = oprepr[1..oprepr.len() - 1].to_string();
                    (repr.clone(), repr)
                } else {
                    (self.repr.to_string(), r.to_string())
                }
            } else {
                (self.repr.to_string(), self.repr.to_string())
            }
        };

        let curop: Option<_> = {
            let mut o = None;
            for op in context.operations() {
                if oprepr.contains_and_skip_brackets(op.sign().to_string().as_str()) {
                    o = Some(op);
                    break;
                }
            }
            o
        };

        if let Some(op) = curop {
            let (first, rest) = repr.split_once_and_skipt_brackets(op.sign()).unwrap();
            let first_expr = Expression::from_string(first);
            let rest_expr = Expression::from_string(rest);
            Ok(op.evaluate(first_expr.evaluate(context)?, rest_expr.evaluate(context)?))
        } else if let Ok(r) = repr.parse::<Complex>() {
            Ok(r)
        } else if let Some((func, args)) = repr.split_once('(') {
            let mut argv = Vec::new();

            for arg in args[..args.len() - 1].split(',') {
                argv.push(Expression::from_string(arg).evaluate(context)?);
            }

            if let Some(func) = context.function(func) {
                Ok(func.eval(FunctionArgument::new(argv), context)?)
            } else {
                Err(format!("function '{func}' not found"))
            }
        } else if let Some(res) = context.variable(&repr) {
            Ok(*res)
        } else {
            Err(format!("variable '{repr}' not found"))
        }
    }
}