aboutsummaryrefslogtreecommitdiffstats
path: root/src/op.rs
blob: e29de52bf50504489ebbd6e934f7a01956f9ea60 (plain) (blame)
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
use crate::eval::Num;
use num::BigInt;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum UnOp {
    Neg,
    Sin,
    Cos,
    Tan,
    Asin,
    Acos,
    Atan,
    Sqrt,
    Log,
    Log10,
    Log2,
    Floor,
    Ceil,
    Round,
    Abs,
}

impl UnOp {
    fn eval(self, x: Num) -> Num {
        use UnOp::*;
        match self {
            Neg => Num::Int(BigInt::from(0)).sub(x),
            Sin => x.sin(),
            Cos => x.cos(),
            Tan => x.tan(),
            Asin => x.asin(),
            Acos => x.acos(),
            Atan => x.atan(),
            Sqrt => x.sqrt(),
            Log => x.log(),
            Log10 => x.log10(),
            Log2 => x.log2(),
            Floor => x.floor(),
            Ceil => x.ceil(),
            Round => x.round(),
            Abs => x.abs(),
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BinOp {
    Pow,
    Mul,
    Div,
    IntDiv,
    Mod,
    Add,
    Sub,
}

impl BinOp {
    fn eval(self, x: Num, y: Num) -> Num {
        match self {
            BinOp::Pow => x.pow(y),
            BinOp::Mul => x.mul(&y),
            BinOp::Div => x.div(y),
            BinOp::IntDiv => x.int_div(y),
            BinOp::Mod => x.modulo(y),
            BinOp::Add => x.add(y),
            BinOp::Sub => x.sub(y),
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Op {
    Num(Num),
    Un(UnOp),
    Bin(BinOp),
}

pub fn eval(ops: impl Iterator<Item = Op>) -> Num {
    let mut stack = Vec::new();
    for op in ops {
        match op {
            Op::Num(n) => stack.push(n),
            Op::Un(op) => {
                let n = stack.pop().unwrap();
                stack.push(op.eval(n));
            }
            Op::Bin(op) => {
                let n2 = stack.pop().unwrap();
                let n1 = stack.pop().unwrap();
                stack.push(op.eval(n1, n2));
            }
        }
    }
    stack.pop().unwrap()
}