fee/expr/
lrpn.rs

1use crate::{
2    Error, EvalError, LContext, Ptr,
3    expr::{Op, ParseableToken},
4    prelude::*,
5    resolver::LockedResolver,
6};
7
8#[derive(Debug, PartialEq, Copy, Clone)]
9pub enum LRpn<'a>
10{
11    Num(f64),
12    Var(Ptr<'a, f64>),
13    Fn(Ptr<'a, ExprFn>, usize),
14    Op(Op),
15}
16
17impl<'a, 'c, V, F> ParseableToken<'a, 'c, Locked, V, F, V, F> for LRpn<'c>
18where
19    V: LockedResolver<f64>,
20    F: LockedResolver<ExprFn>,
21{
22    #[inline]
23    fn f64(num: f64) -> Self
24    {
25        LRpn::Num(num)
26    }
27
28    #[inline]
29    fn i64(num: i64) -> Self
30    {
31        LRpn::Num(num as f64)
32    }
33
34    #[inline]
35    fn bool(val: bool) -> Self
36    {
37        LRpn::Num(if val { 1.0 } else { 0.0 })
38    }
39
40    #[inline]
41    fn op(op: Op) -> Self
42    {
43        LRpn::Op(op)
44    }
45
46    // TODO: Return an error manin
47    #[inline]
48    fn var(name: &'a str, ctx: &'c LContext<V, F>) -> Self
49    {
50        LRpn::Var(ctx.get_var_ptr(name).unwrap())
51    }
52
53    #[inline]
54    fn fun(name: &'a str, argc: usize, ctx: &'c LContext<V, F>) -> Self
55    {
56        LRpn::Fn(ctx.get_fn_ptr(name).unwrap(), argc)
57    }
58}
59
60impl<'e, 'c, V, F> ExprCompiler<'e, 'c, Locked, V, F, V, F, LRpn<'c>> for Expr<LRpn<'c>>
61where
62    V: LockedResolver<f64>,
63    F: LockedResolver<ExprFn>,
64{
65    fn compile(expr: &'e str, ctx: &'c LContext<V, F>) -> Result<Expr<LRpn<'c>>, Error<'e>>
66    {
67        Expr::try_from((expr, ctx))
68    }
69}
70
71impl<'a, V, F> ExprEvaluator<'a, Locked, V, F, V, F> for Expr<LRpn<'a>>
72where
73    V: LockedResolver<f64>,
74    F: LockedResolver<ExprFn>,
75{
76    fn eval(&self, _ctx: &LContext<V, F>, stack: &mut Vec<f64>) -> Result<f64, Error<'a>>
77    {
78        if self.tokens.len() == 1 {
79            if let LRpn::Num(num) = &self.tokens[0] {
80                return Ok(*num);
81            }
82        }
83
84        for tok in self.tokens.iter() {
85            match tok {
86                LRpn::Num(num) => stack.push(*num),
87                LRpn::Var(ptr) => stack.push(ptr.get()),
88                LRpn::Fn(ptr, argc) => {
89                    if *argc > stack.len() {
90                        return Err(Error::EvalError(EvalError::RPNStackUnderflow));
91                    }
92
93                    let start = stack.len() - argc;
94                    let args = unsafe { stack.get_unchecked(start..) };
95                    let val = (ptr.get())(args);
96
97                    stack.truncate(start);
98                    stack.push(val);
99                }
100                LRpn::Op(op) => {
101                    if op.num_operands() > stack.len() {
102                        return Err(Error::EvalError(EvalError::RPNStackUnderflow));
103                    }
104
105                    let start = stack.len() - op.num_operands();
106                    let args = unsafe { stack.get_unchecked(start..) };
107                    let res = op.apply(args);
108                    stack.truncate(start);
109                    stack.push(res);
110                }
111            }
112        }
113
114        match stack.pop() {
115            Some(result) if stack.is_empty() => Ok(result),
116            _ => Err(Error::EvalError(EvalError::MalformedExpression)),
117        }
118    }
119}