1#![no_std]
2
3use micromath::F32Ext;
4
5const MAX_STACK_SIZE: usize = 64;
6
7pub enum ParseError {
8 TooManyValuesInStack,
9 NoValuesInStack,
10 NumberNotParsed,
11}
12
13struct Stack<T> {
14 stack: [Option<T>; MAX_STACK_SIZE],
15 stack_top: usize,
16}
17impl<T: Copy> Stack<T> {
18 fn new() -> Stack<T> {
19 Stack {
20 stack: [Option::None; MAX_STACK_SIZE],
21 stack_top: 0,
22 }
23 }
24
25 fn push(&mut self, val: T) -> Result<(), ParseError> {
26 if self.stack_top >= MAX_STACK_SIZE {
27 return Err(ParseError::TooManyValuesInStack);
28 }
29
30 self.stack[self.stack_top] = Some(val);
31 self.stack_top += 1;
32 Ok(())
33 }
34
35 fn pop(&mut self) -> Option<T> {
36 if self.stack_top == 0 {
37 return None;
38 }
39
40 self.stack_top -= 1;
42 let result = self.stack[self.stack_top].take();
43
44 result
45 }
46
47 fn iter<'a>(&'a self) -> StackIter<'a, T> {
48 StackIter {
49 curr_loc: 0,
50 end_loc: self.stack_top,
51 data: self,
52 }
53 }
54}
55
56struct StackIter<'a, T> {
57 curr_loc: usize,
58 end_loc: usize,
59 data: &'a Stack<T>,
60}
61
62impl<'a, T> StackIter<'a, T> {
63 fn is_empty(&self) -> bool {
64 self.curr_loc == self.end_loc
65 }
66}
67
68impl<'a, T: Copy> Iterator for StackIter<'a, T> {
69 type Item = T;
70
71 fn next(&mut self) -> Option<Self::Item> {
72 if self.is_empty() {
73 None
74 } else {
75 let result = self.data.stack[self.curr_loc]; self.curr_loc += 1;
77 result
78 }
79 }
80}
81
82pub struct TinyExpr {
83 stack: Stack<ExprNode>,
84}
85
86impl TinyExpr {
87 pub fn from_str(s: &str) -> ParseResult<TinyExpr> {
88 let tokens = s.split_whitespace();
89
90 let mut stack = Stack::new();
91
92 for token in tokens {
93 let val = ExprNode::parse_token(token)?;
94 stack.push(val)?;
95 }
96
97 Ok(Self { stack })
98 }
99
100 pub fn eval(&self, x: f32, y: f32) -> ParseResult<f32> {
101 let mut eval_stack = Stack::new();
102
103 let mut stack_iterator = self.stack.iter();
104
105 while let Some(curr_val) = stack_iterator.next() {
106 match curr_val {
109 ExprNode::Lerp => {
110 let z: f32 = eval_stack
111 .pop()
112 .ok_or_else(|| ParseError::NoValuesInStack)?;
113 let y: f32 = eval_stack
114 .pop()
115 .ok_or_else(|| ParseError::NoValuesInStack)?;
116 let x = eval_stack
117 .pop()
118 .ok_or_else(|| ParseError::NoValuesInStack)?;
119 eval_stack.push((1.0 - z) * x + z * y)?;
120 }
121 ExprNode::Add => {
123 let y: f32 = eval_stack
124 .pop()
125 .ok_or_else(|| ParseError::NoValuesInStack)?;
126 let x = eval_stack
127 .pop()
128 .ok_or_else(|| ParseError::NoValuesInStack)?;
129
130 eval_stack.push(x + y)?;
131 }
132 ExprNode::Mul => {
133 let y: f32 = eval_stack
134 .pop()
135 .ok_or_else(|| ParseError::NoValuesInStack)?;
136 let x = eval_stack
137 .pop()
138 .ok_or_else(|| ParseError::NoValuesInStack)?;
139 eval_stack.push(x * y)?;
140 }
141 ExprNode::Div => {
142 let y: f32 = eval_stack
143 .pop()
144 .ok_or_else(|| ParseError::NoValuesInStack)?;
145 let x = eval_stack
146 .pop()
147 .ok_or_else(|| ParseError::NoValuesInStack)?;
148 eval_stack.push(x / y)?;
149 }
150 ExprNode::Sub => {
151 let y: f32 = eval_stack
152 .pop()
153 .ok_or_else(|| ParseError::NoValuesInStack)?;
154 let x = eval_stack
155 .pop()
156 .ok_or_else(|| ParseError::NoValuesInStack)?;
157 eval_stack.push(x - y)?;
158 }
159 ExprNode::Pow => {
160 let y: f32 = eval_stack
161 .pop()
162 .ok_or_else(|| ParseError::NoValuesInStack)?;
163 let x = eval_stack
164 .pop()
165 .ok_or_else(|| ParseError::NoValuesInStack)?;
166 eval_stack.push(x.powf(y))?;
167 }
168 ExprNode::Atan2 => {
169 let y: f32 = eval_stack
170 .pop()
171 .ok_or_else(|| ParseError::NoValuesInStack)?;
172 let x: f32 = eval_stack
173 .pop()
174 .ok_or_else(|| ParseError::NoValuesInStack)?;
175 eval_stack.push(x.atan2(y))?;
176 }
177
178 ExprNode::Sin => {
180 let x = eval_stack
181 .pop()
182 .ok_or_else(|| ParseError::NoValuesInStack)?;
183 eval_stack.push(x.sin())?;
184 }
185 ExprNode::Cos => {
186 let x = eval_stack
187 .pop()
188 .ok_or_else(|| ParseError::NoValuesInStack)?;
189 eval_stack.push(x.cos())?;
190 }
191 ExprNode::Fract => {
192 let x = eval_stack
193 .pop()
194 .ok_or_else(|| ParseError::NoValuesInStack)?;
195 eval_stack.push(x.fract())?;
196 }
197 ExprNode::Sqrt => {
198 let x = eval_stack
199 .pop()
200 .ok_or_else(|| ParseError::NoValuesInStack)?;
201 eval_stack.push(x.fract())?;
202 }
203 ExprNode::Floor => {
204 let x = eval_stack
205 .pop()
206 .ok_or_else(|| ParseError::NoValuesInStack)?;
207 eval_stack.push(x.floor())?;
208 }
209 ExprNode::Abs => {
210 let x = eval_stack
211 .pop()
212 .ok_or_else(|| ParseError::NoValuesInStack)?;
213 eval_stack.push(x.abs())?;
214 }
215 ExprNode::Number(r) => eval_stack.push(r)?,
217 ExprNode::X => eval_stack.push(x)?,
218 ExprNode::Y => eval_stack.push(y)?,
219 };
220 }
221
222 if let Some(x) = eval_stack.pop() {
223 Ok(x)
224 } else {
225 Err(ParseError::NoValuesInStack)
226 }
227 }
228}
229
230pub type ParseResult<T> = Result<T, ParseError>;
231
232#[derive(Copy, Clone, Debug)]
233enum ExprNode {
234 Number(f32),
235 X,
236 Y,
237 Sin,
239 Cos,
240 Fract,
241 Sqrt,
242 Floor,
243 Abs,
244 Atan2,
246 Pow,
247 Add,
248 Mul,
249 Div,
250 Sub,
251 Lerp,
253}
254
255impl ExprNode {
256 fn parse_token(token: &str) -> ParseResult<ExprNode> {
257 match token {
258 "x" => Ok(ExprNode::X),
259 "y" => Ok(ExprNode::Y),
260 "sin" => Ok(ExprNode::Sin),
261 "cos" => Ok(ExprNode::Cos),
262 "atan2" => Ok(ExprNode::Atan2),
263 "fract" => Ok(ExprNode::Fract),
264 "pow" => Ok(ExprNode::Pow),
265 "sqrt" => Ok(ExprNode::Sqrt),
266 "floor" => Ok(ExprNode::Floor),
267 "abs" => Ok(ExprNode::Abs),
268 "add" => Ok(ExprNode::Add),
269 "mul" => Ok(ExprNode::Mul),
270 "div" => Ok(ExprNode::Div),
271 "sub" => Ok(ExprNode::Sub),
272 "lerp" => Ok(ExprNode::Lerp),
273 _ => {
274 let float = token
275 .parse::<f32>()
276 .map_err(|_| ParseError::NumberNotParsed)?;
277 Ok(ExprNode::Number(float))
278 }
279 }
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use super::*;
286
287 enum TestEvalResult {
288 Ok(f32),
289 ErrFromStr(ParseError),
290 ErrEval(ParseError),
291 }
292
293 impl TestEvalResult {
294 #[must_use]
298 fn is_ok(&self) -> bool {
299 matches!(self, Self::Ok(..))
300 }
301
302 #[must_use]
306 fn is_err_from_str(&self) -> bool {
307 matches!(self, Self::ErrFromStr(..))
308 }
309
310 #[must_use]
314 fn is_err_eval(&self) -> bool {
315 matches!(self, Self::ErrEval(..))
316 }
317 }
318
319 fn evaluate(s: &str, x: f32, y: f32) -> TestEvalResult {
320 let e = match TinyExpr::from_str(s) {
321 Ok(r) => match r.eval(x, y) {
322 Ok(a) => TestEvalResult::Ok(a),
323 Err(err) => TestEvalResult::ErrEval(err),
324 },
325 Err(err) => TestEvalResult::ErrFromStr(err),
326 };
327
328 e
336 }
337
338 #[test]
339 fn it_works() {
340 match evaluate("2.3", 0.0, 0.0) {
341 TestEvalResult::Ok(r) => assert_eq!(r, 2.3),
342 _ => assert!(false),
343 }
344
345 match evaluate("2", 0.0, 0.0) {
346 TestEvalResult::Ok(r) => assert_eq!(r, 2.0),
347 _ => assert!(false),
348 }
349
350 match evaluate("x", 5.0, 0.0) {
351 TestEvalResult::Ok(r) => assert_eq!(r, 5.0),
352 _ => assert!(false),
353 }
354
355 match evaluate("y", 0.0, 6.0) {
356 TestEvalResult::Ok(r) => assert_eq!(r, 6.0),
357 _ => assert!(false),
358 }
359
360 match evaluate("x y add", 2.0, 5.0) {
361 TestEvalResult::Ok(r) => {
362 assert_eq!(r, 7.0)
363 }
364 _ => {
365 assert!(false)
366 }
367 }
368
369 match evaluate("x y 0.0 lerp", 2.0, 5.0) {
370 TestEvalResult::Ok(r) => {
371 assert_eq!(r, 2.0)
372 }
373 _ => {
374 assert!(false)
375 }
376 }
377
378 match evaluate("x y 1.0 lerp", 2.0, 5.0) {
379 TestEvalResult::Ok(r) => {
380 assert_eq!(r, 5.0)
381 }
382 _ => {
383 assert!(false)
384 }
385 }
386
387 match evaluate("x y mul 4.0 add", 2.0, 5.0) {
388 TestEvalResult::Ok(r) => {
389 assert_eq!(r, 14.0)
390 }
391 _ => {
392 assert!(false)
393 }
394 }
395 }
396
397 #[test]
398 fn it_does_not_work_empty() {
399 let empty_result = evaluate("", 0.0, 0.0);
400 assert!(empty_result.is_err_eval());
401 }
402
403 #[test]
404 fn it_does_not_work_gobbligook() {
405 let empty_result = evaluate("gobbligook", 0.0, 0.0);
406 assert!(empty_result.is_err_from_str());
407 }
408}