aboutsummaryrefslogtreecommitdiff
path: root/src/math/expression.rs
blob: 049886dd9a697b7df7857d3a33d23b3a27a9f191 (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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use super::complex::Complex;
use super::context::Context;
use super::function::FunctionArgument;
use super::string::{ContainsAndSkipBrackets, SplitMatchingBracket};
use super::operation::Operation;

enum ExpressionType {
    Value(Complex),
    Variable(String),
    Function(String, FunctionArgument),
    Operation(Operation, Box<Expression>, Box<Expression>),
}

impl Default for ExpressionType {
    fn default() -> Self {
        ExpressionType::Value(Complex::default())
    }
}

#[derive(Default)]
pub struct Expression {
    expr_type: ExpressionType,
    repr: String,
}

impl Expression {
    pub fn from_string(str: &str, operations: &Vec<Operation>) -> Self {
        let mut ex = Self::default();
        ex.repr = str.to_string();
        ex.set_operations(operations);

        ex
    }

    pub fn content(&self) -> &str {
        &self.repr
    }

    pub fn set_operations(&mut self, operations: &Vec<Operation>) {
        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 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, operations);
            let rest_expr = Expression::from_string(rest, operations);
            self.expr_type = ExpressionType::Operation(op.clone(), Box::new(first_expr), Box::new(rest_expr));
        } else if let Ok(r) = repr.parse::<Complex>() {
            self.expr_type = ExpressionType::Value(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, operations));
            }

            self.expr_type = ExpressionType::Function(func.to_string(), FunctionArgument::from_expressions(argv));
        } else {
            self.expr_type = ExpressionType::Variable(repr);
        }
    }

    pub fn evaluate(&self, ctx: &Context) -> Result<Complex, String> {
        match &self.expr_type {
            ExpressionType::Value(v) => Ok(*v),
            ExpressionType::Variable(var) => {
                if let Some(v) = ctx.variable(&var) {
                    Ok(*v)
                } else {
                    Err(format!("variable '{var}' not found"))
                }
            },
            ExpressionType::Function(func, args) => {
                if let Some(f) = ctx.function(&func) {
                    f.eval(args, ctx)
                } else {
                    Err(format!("function '{func}' not found"))
                }
            }
            ExpressionType::Operation(op, a, b) => {
                Ok(op.evaluate(a.evaluate(ctx)?, b.evaluate(ctx)?))
            }
        }
    }
}