aboutsummaryrefslogtreecommitdiff
path: root/src/parse/mod.rs
blob: 4238e3b49de98ae3d806f4a30c869b845c0088d4 (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 crate::lex::Token;
use crate::error::CalcError;

pub fn to_postfix(tokens: Vec<Token>) -> Result<Vec<Token>, CalcError> {
    let mut postfixed: Vec<Token> = vec![];
    let mut op_stack: Vec<Token> = vec![];
    for token in tokens {
        match token {
            Token::Num(_) => {
                postfixed.push(token);
            },
            Token::Function(_) => {
                op_stack.push(token);
            }
            Token::Operator(current_op) => {
                while let Some(top_op) = op_stack.last() {
                    match top_op {
                        Token::LParen => {
                            break;
                        }
                        Token::Operator(x) => {
                            let tp = x.precedence;
                            let cp = current_op.precedence;
                            if tp > cp || (tp == cp && x.is_left_associative) {
                                postfixed.push(op_stack.pop().unwrap());
                            } else {
                                break;
                            }
                        }
                        Token::Function(_) => {
                            postfixed.push(op_stack.pop().unwrap());
                        }
                        _ => { unreachable!(); }
                    }
                }
                op_stack.push(token);
            },
            Token::LParen => {
                op_stack.push(token);
            },
            Token::RParen => {
                let mut push_until_paren: bool = false;
                while let Some(token) = op_stack.pop() {
                    if token == Token::LParen {
                        push_until_paren = true;
                        break;
                    }
                    postfixed.push(token)
                }
                if !push_until_paren {
                    return Err(CalcError::Syntax("Mismatched parentheses!".into()));
                }
            }
        }
    }
    while let Some(op) = op_stack.pop() {
        postfixed.push(op);
    }
    Ok(postfixed)
}

pub fn eval_postfix(postfixed: Vec<Token>) -> Result<f64, CalcError> {
    let mut num_stack: Vec<f64> = vec![];
    for token in postfixed {
        match token {
            Token::Num(n) => {
                num_stack.push(n);
            },
            Token::Operator(op) => {
                if let Some(n2) = num_stack.pop() {
                    if let Some(n1) = num_stack.pop() {
                        num_stack.push(op.operate(n1, n2)?);
                    } else {
                        return Err(
                            CalcError::Parser(
                                format!("Too many operators, Too little operands")
                            )
                        )
                    }
                } else {
                    return Err(
                        CalcError::Parser(
                            format!("Too many operators, Too little operands")
                        )
                    )
                }
            },
            Token::Function(funct) => {
                if let Some(arg) = num_stack.pop() {
                    num_stack.push(funct.apply(arg)?)
                }
            }
            _ => {
                unreachable!("nah nigga")
            }
        }
    }
    if num_stack.len() == 1 {
        Ok(num_stack.pop().unwrap())
    } else {
        return Err(
            CalcError::Parser(
                format!("Too many operators, Too little operands")
            )
        )
    }
}