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 #[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}