1use crate::Event;
8use crate::compiler::grammar::expr::parser::ID_EXTERNAL;
9use crate::compiler::grammar::expr::{BinaryOperator, Expression, UnaryOperator};
10use crate::{Context, compiler::Number, runtime::Variable};
11use std::sync::Arc;
12use std::{cmp::Ordering, fmt::Display};
13
14impl Context<'_> {
15 pub(crate) fn eval_expression(&mut self, expr: &[Expression]) -> Result<Variable, Event> {
16 while let Some(item) = expr.get(self.expr_pos) {
17 self.expr_pos += 1;
18 match item {
19 Expression::VariableLocal(id) => {
20 let value = self
21 .vars_local
22 .get(*id as usize)
23 .cloned()
24 .unwrap_or_default();
25 self.expr_stack.push(value);
26 }
27 Expression::VariableMatch(id) => {
28 let value = self
29 .vars_match
30 .get(*id as usize)
31 .cloned()
32 .unwrap_or_default();
33 self.expr_stack.push(value);
34 }
35 Expression::VariableOther(v) => {
36 self.expr_stack.push(self.variable(v).unwrap_or_default());
37 }
38 Expression::ConstantInteger(i) => {
39 self.expr_stack.push(Variable::Integer(*i));
40 }
41 Expression::ConstantFloat(f) => {
42 self.expr_stack.push(Variable::Float(*f));
43 }
44 Expression::ConstantString(id) => {
45 let value = self.constant(*id);
46 self.expr_stack.push(Variable::String(value));
47 }
48 Expression::UnaryOperator(op) => {
49 let value = self.expr_stack.pop().unwrap_or_default();
50 self.expr_stack.push(match op {
51 UnaryOperator::Not => value.op_not(),
52 UnaryOperator::Minus => value.op_minus(),
53 });
54 }
55 Expression::BinaryOperator(op) => {
56 let right = self.expr_stack.pop().unwrap_or_default();
57 let left = self.expr_stack.pop().unwrap_or_default();
58 self.expr_stack.push(match op {
59 BinaryOperator::Add => left.op_add(right),
60 BinaryOperator::Subtract => left.op_subtract(right),
61 BinaryOperator::Multiply => left.op_multiply(right),
62 BinaryOperator::Divide => left.op_divide(right),
63 BinaryOperator::And => left.op_and(right),
64 BinaryOperator::Or => left.op_or(right),
65 BinaryOperator::Xor => left.op_xor(right),
66 BinaryOperator::Eq => left.op_eq(right),
67 BinaryOperator::Ne => left.op_ne(right),
68 BinaryOperator::Lt => left.op_lt(right),
69 BinaryOperator::Le => left.op_le(right),
70 BinaryOperator::Gt => left.op_gt(right),
71 BinaryOperator::Ge => left.op_ge(right),
72 });
73 }
74 Expression::Function { id, num_args } => {
75 let num_args = *num_args as usize;
76
77 if let Some(fnc) = self.runtime.functions.get(*id as usize) {
78 let start = self.expr_stack.len().saturating_sub(num_args);
79 let arguments = self.expr_stack.split_off(start);
80 let result = (fnc)(self, arguments);
81 self.expr_stack.push(result);
82 } else {
83 let start = self.expr_stack.len().saturating_sub(num_args);
84 let arguments = self.expr_stack.split_off(start);
85 self.pos -= 1; return Err(Event::Function {
87 id: ID_EXTERNAL - *id,
88 arguments,
89 });
90 }
91 }
92 Expression::JmpIf { val, pos } => {
93 if self.expr_stack.last().is_some_and(|v| v.to_bool()) == *val {
94 self.expr_pos += *pos as usize;
95 }
96 }
97 Expression::ArrayAccess => {
98 let index = self.expr_stack.pop().unwrap_or_default().to_usize();
99 let array = self.expr_stack.pop().unwrap_or_default().into_array();
100 self.expr_stack
101 .push(array.get(index).cloned().unwrap_or_default());
102 }
103 Expression::ArrayBuild(num_items) => {
104 let start = self.expr_stack.len().saturating_sub(*num_items as usize);
105 let items = Arc::from(&self.expr_stack[start..]);
106 self.expr_stack.truncate(start);
107 self.expr_stack.push(Variable::Array(items));
108 }
109 }
110 }
111
112 let result = self.expr_stack.pop().unwrap_or_default();
113 self.expr_stack.clear();
114 self.expr_pos = 0;
115 Ok(result)
116 }
117}
118
119impl Variable {
120 pub fn op_add(self, other: Variable) -> Variable {
121 match (self, other) {
122 (Variable::Integer(a), Variable::Integer(b)) => Variable::Integer(a.saturating_add(b)),
123 (Variable::Float(a), Variable::Float(b)) => Variable::Float(a + b),
124 (Variable::Integer(i), Variable::Float(f))
125 | (Variable::Float(f), Variable::Integer(i)) => Variable::Float(i as f64 + f),
126 (Variable::Array(a), Variable::Array(b)) => {
127 Variable::Array(a.iter().chain(b.iter()).cloned().collect())
128 }
129 (Variable::Array(a), b) => Variable::Array(a.iter().cloned().chain([b]).collect()),
130 (a, Variable::Array(b)) => {
131 Variable::Array([a].into_iter().chain(b.iter().cloned()).collect())
132 }
133 (Variable::String(a), b) => {
134 if !a.is_empty() {
135 Variable::String(format!("{}{}", a, b).into())
136 } else {
137 b
138 }
139 }
140 (a, Variable::String(b)) => {
141 if !b.is_empty() {
142 Variable::String(format!("{}{}", a, b).into())
143 } else {
144 a
145 }
146 }
147 }
148 }
149
150 pub fn op_subtract(self, other: Variable) -> Variable {
151 match (self, other) {
152 (Variable::Integer(a), Variable::Integer(b)) => Variable::Integer(a.saturating_sub(b)),
153 (Variable::Float(a), Variable::Float(b)) => Variable::Float(a - b),
154 (Variable::Integer(a), Variable::Float(b)) => Variable::Float(a as f64 - b),
155 (Variable::Float(a), Variable::Integer(b)) => Variable::Float(a - b as f64),
156 (Variable::Array(a), b) | (b, Variable::Array(a)) => {
157 Variable::Array(a.iter().filter(|v| *v != &b).cloned().collect())
158 }
159 (a, b) => a.parse_number().op_subtract(b.parse_number()),
160 }
161 }
162
163 pub fn op_multiply(self, other: Variable) -> Variable {
164 match (self, other) {
165 (Variable::Integer(a), Variable::Integer(b)) => Variable::Integer(a.saturating_mul(b)),
166 (Variable::Float(a), Variable::Float(b)) => Variable::Float(a * b),
167 (Variable::Integer(i), Variable::Float(f))
168 | (Variable::Float(f), Variable::Integer(i)) => Variable::Float(i as f64 * f),
169 (a, b) => a.parse_number().op_multiply(b.parse_number()),
170 }
171 }
172
173 pub fn op_divide(self, other: Variable) -> Variable {
174 match (self, other) {
175 (Variable::Integer(a), Variable::Integer(b)) => {
176 Variable::Float(if b != 0 { a as f64 / b as f64 } else { 0.0 })
177 }
178 (Variable::Float(a), Variable::Float(b)) => {
179 Variable::Float(if b != 0.0 { a / b } else { 0.0 })
180 }
181 (Variable::Integer(a), Variable::Float(b)) => {
182 Variable::Float(if b != 0.0 { a as f64 / b } else { 0.0 })
183 }
184 (Variable::Float(a), Variable::Integer(b)) => {
185 Variable::Float(if b != 0 { a / b as f64 } else { 0.0 })
186 }
187 (a, b) => a.parse_number().op_divide(b.parse_number()),
188 }
189 }
190
191 pub fn op_and(self, other: Variable) -> Variable {
192 Variable::Integer(i64::from(self.to_bool() & other.to_bool()))
193 }
194
195 pub fn op_or(self, other: Variable) -> Variable {
196 Variable::Integer(i64::from(self.to_bool() | other.to_bool()))
197 }
198
199 pub fn op_xor(self, other: Variable) -> Variable {
200 Variable::Integer(i64::from(self.to_bool() ^ other.to_bool()))
201 }
202
203 pub fn op_eq(self, other: Variable) -> Variable {
204 Variable::Integer(i64::from(self == other))
205 }
206
207 pub fn op_ne(self, other: Variable) -> Variable {
208 Variable::Integer(i64::from(self != other))
209 }
210
211 pub fn op_lt(self, other: Variable) -> Variable {
212 Variable::Integer(i64::from(self < other))
213 }
214
215 pub fn op_le(self, other: Variable) -> Variable {
216 Variable::Integer(i64::from(self <= other))
217 }
218
219 pub fn op_gt(self, other: Variable) -> Variable {
220 Variable::Integer(i64::from(self > other))
221 }
222
223 pub fn op_ge(self, other: Variable) -> Variable {
224 Variable::Integer(i64::from(self >= other))
225 }
226
227 pub fn op_not(self) -> Variable {
228 Variable::Integer(i64::from(!self.to_bool()))
229 }
230
231 pub fn op_minus(self) -> Variable {
232 match self {
233 Variable::Integer(n) => Variable::Integer(-n),
234 Variable::Float(n) => Variable::Float(-n),
235 _ => self.parse_number().op_minus(),
236 }
237 }
238
239 pub fn parse_number(&self) -> Variable {
240 match self {
241 Variable::String(s) if !s.is_empty() => {
242 if let Ok(n) = s.parse::<i64>() {
243 Variable::Integer(n)
244 } else if let Ok(n) = s.parse::<f64>() {
245 Variable::Float(n)
246 } else {
247 Variable::Integer(0)
248 }
249 }
250 Variable::Integer(n) => Variable::Integer(*n),
251 Variable::Float(n) => Variable::Float(*n),
252 Variable::Array(l) => Variable::Integer(l.is_empty() as i64),
253 _ => Variable::Integer(0),
254 }
255 }
256
257 pub fn to_bool(&self) -> bool {
258 match self {
259 Variable::Float(f) => *f != 0.0,
260 Variable::Integer(n) => *n != 0,
261 Variable::String(s) => !s.is_empty(),
262 Variable::Array(a) => !a.is_empty(),
263 }
264 }
265}
266
267impl PartialEq for Variable {
268 fn eq(&self, other: &Self) -> bool {
269 match (self, other) {
270 (Self::Integer(a), Self::Integer(b)) => a == b,
271 (Self::Float(a), Self::Float(b)) => a == b,
272 (Self::Integer(a), Self::Float(b)) | (Self::Float(b), Self::Integer(a)) => {
273 *a as f64 == *b
274 }
275 (Self::String(a), Self::String(b)) => a == b,
276 (Self::String(_), Self::Integer(_) | Self::Float(_)) => &self.parse_number() == other,
277 (Self::Integer(_) | Self::Float(_), Self::String(_)) => self == &other.parse_number(),
278 (Self::Array(a), Self::Array(b)) => a == b,
279 _ => false,
280 }
281 }
282}
283
284impl Eq for Variable {}
285
286#[allow(clippy::non_canonical_partial_ord_impl)]
287impl PartialOrd for Variable {
288 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
289 match (self, other) {
290 (Self::Integer(a), Self::Integer(b)) => a.partial_cmp(b),
291 (Self::Float(a), Self::Float(b)) => a.partial_cmp(b),
292 (Self::Integer(a), Self::Float(b)) => (*a as f64).partial_cmp(b),
293 (Self::Float(a), Self::Integer(b)) => a.partial_cmp(&(*b as f64)),
294 (Self::String(a), Self::String(b)) => a.partial_cmp(b),
295 (Self::String(_), Self::Integer(_) | Self::Float(_)) => {
296 self.parse_number().partial_cmp(other)
297 }
298 (Self::Integer(_) | Self::Float(_), Self::String(_)) => {
299 self.partial_cmp(&other.parse_number())
300 }
301 (Self::Array(a), Self::Array(b)) => a.partial_cmp(b),
302 (Self::Array(_) | Self::String(_), _) => Ordering::Greater.into(),
303 (_, Self::Array(_)) => Ordering::Less.into(),
304 }
305 }
306}
307
308impl Ord for Variable {
309 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
310 self.partial_cmp(other).unwrap_or(Ordering::Greater)
311 }
312}
313
314impl Display for Variable {
315 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
316 match self {
317 Variable::String(v) => v.fmt(f),
318 Variable::Integer(v) => v.fmt(f),
319 Variable::Float(v) => v.fmt(f),
320 Variable::Array(v) => {
321 for (i, v) in v.iter().enumerate() {
322 if i > 0 {
323 f.write_str("\n")?;
324 }
325 v.fmt(f)?;
326 }
327 Ok(())
328 }
329 }
330 }
331}
332
333impl Number {
334 pub fn is_non_zero(&self) -> bool {
335 match self {
336 Number::Integer(n) => *n != 0,
337 Number::Float(n) => *n != 0.0,
338 }
339 }
340}
341
342impl Default for Number {
343 fn default() -> Self {
344 Number::Integer(0)
345 }
346}
347
348impl From<bool> for Number {
349 #[inline(always)]
350 fn from(b: bool) -> Self {
351 Number::Integer(i64::from(b))
352 }
353}
354
355impl From<i64> for Number {
356 #[inline(always)]
357 fn from(n: i64) -> Self {
358 Number::Integer(n)
359 }
360}
361
362impl From<f64> for Number {
363 #[inline(always)]
364 fn from(n: f64) -> Self {
365 Number::Float(n)
366 }
367}
368
369impl From<i32> for Number {
370 #[inline(always)]
371 fn from(n: i32) -> Self {
372 Number::Integer(n as i64)
373 }
374}
375
376#[cfg(test)]
377mod test {
378 use ahash::{HashMap, HashMapExt};
379
380 use crate::{
381 compiler::{
382 VariableType,
383 grammar::expr::{
384 BinaryOperator, Expression, Token, UnaryOperator, parser::ExpressionParser,
385 tokenizer::Tokenizer,
386 },
387 },
388 runtime::Variable,
389 };
390
391 use evalexpr::*;
392
393 pub trait EvalExpression {
394 fn eval(&self, variables: &HashMap<String, Variable>) -> Option<Variable>;
395 }
396
397 impl EvalExpression for Vec<Expression> {
398 fn eval(&self, variables: &HashMap<String, Variable>) -> Option<Variable> {
399 let mut stack = Vec::with_capacity(self.len());
400 let mut exprs = self.iter();
401
402 while let Some(expr) = exprs.next() {
403 match expr {
404 Expression::VariableOther(v) => {
405 if let VariableType::Global(v) = v.as_ref() {
406 stack.push(variables.get(v)?.clone());
407 } else {
408 unreachable!("Invalid expression")
409 }
410 }
411 Expression::ConstantInteger(i) => stack.push(Variable::Integer(*i)),
412 Expression::ConstantFloat(f) => stack.push(Variable::Float(*f)),
413 Expression::UnaryOperator(op) => {
414 let value = stack.pop()?;
415 stack.push(match op {
416 UnaryOperator::Not => value.op_not(),
417 UnaryOperator::Minus => value.op_minus(),
418 });
419 }
420 Expression::BinaryOperator(op) => {
421 let right = stack.pop()?;
422 let left = stack.pop()?;
423 stack.push(match op {
424 BinaryOperator::Add => left.op_add(right),
425 BinaryOperator::Subtract => left.op_subtract(right),
426 BinaryOperator::Multiply => left.op_multiply(right),
427 BinaryOperator::Divide => left.op_divide(right),
428 BinaryOperator::And => left.op_and(right),
429 BinaryOperator::Or => left.op_or(right),
430 BinaryOperator::Xor => left.op_xor(right),
431 BinaryOperator::Eq => left.op_eq(right),
432 BinaryOperator::Ne => left.op_ne(right),
433 BinaryOperator::Lt => left.op_lt(right),
434 BinaryOperator::Le => left.op_le(right),
435 BinaryOperator::Gt => left.op_gt(right),
436 BinaryOperator::Ge => left.op_ge(right),
437 });
438 }
439 Expression::JmpIf { val, pos } => {
440 if stack.last()?.to_bool() == *val {
441 for _ in 0..*pos {
442 exprs.next();
443 }
444 }
445 }
446 _ => unreachable!("Invalid expression"),
447 }
448 }
449 stack.pop()
450 }
451 }
452
453 #[test]
454 fn eval_expression() {
455 let mut variables = HashMap::from_iter([
456 ("A".to_string(), Variable::Integer(0)),
457 ("B".to_string(), Variable::Integer(0)),
458 ("C".to_string(), Variable::Integer(0)),
459 ("D".to_string(), Variable::Integer(0)),
460 ("E".to_string(), Variable::Integer(0)),
461 ("F".to_string(), Variable::Integer(0)),
462 ("G".to_string(), Variable::Integer(0)),
463 ("H".to_string(), Variable::Integer(0)),
464 ("I".to_string(), Variable::Integer(0)),
465 ("J".to_string(), Variable::Integer(0)),
466 ]);
467 let num_vars = variables.len();
468
469 for expr in [
470 "A + B",
471 "A * B",
472 "A / B",
473 "A - B",
474 "-A",
475 "A == B",
476 "A != B",
477 "A > B",
478 "A < B",
479 "A >= B",
480 "A <= B",
481 "A + B * C - D / E",
482 "A + B + C - D - E",
483 "(A + B) * (C - D) / E",
484 "A - B + C * D / E * F - G",
485 "A + B * C - D / E",
486 "(A + B) * (C - D) / E",
487 "A - B + C / D * E",
488 "(A + B) / (C - D) + E",
489 "A * (B + C) - D / E",
490 "A / (B - C + D) * E",
491 "(A + B) * C - D / (E + F)",
492 "A * B - C + D / E",
493 "A + B - C * D / E",
494 "(A * B + C) / D - E",
495 "A - B / C + D * E",
496 "A + B * (C - D) / E",
497 "A * B / C + (D - E)",
498 "(A - B) * C / D + E",
499 "A * (B / C) - D + E",
500 "(A + B) / (C + D) * E",
501 "A - B * C / D + E",
502 "A + (B - C) * D / E",
503 "(A + B) * (C / D) - E",
504 "A - B / (C * D) + E",
505 "(A + B) > (C - D) && E <= F",
506 "A * B == C / D || E - F != G + H",
507 "A / B >= C * D && E + F < G - H",
508 "(A * B - C) != (D / E + F) && G > H",
509 "A - B < C && D + E >= F * G",
510 "(A * B) > C && (D / E) < F || G == H",
511 "(A + B) <= (C - D) || E > F && G != H",
512 "A * B != C + D || E - F == G / H",
513 "A >= B * C && D < E - F || G != H + I",
514 "(A / B + C) > D && E * F <= G - H",
515 "A * (B - C) == D && E / F > G + H",
516 "(A - B + C) != D || E * F >= G && H < I",
517 "A < B / C && D + E * F == G - H",
518 "(A + B * C) <= D && E > F / G",
519 "(A * B - C) > D || E <= F + G && H != I",
520 "A != B / C && D == E * F - G",
521 "A <= B + C - D && E / F > G * H",
522 "(A - B * C) < D || E >= F + G && H != I",
523 "(A + B) / C == D && E - F < G * H",
524 "A * B != C && D >= E + F / G || H < I",
525 "!(A * B != C) && !(D >= E + F / G) || !(H < I)",
526 "-A - B - (- C - D) - E - (-F)",
527 ] {
528 println!("Testing {}", expr);
529 for (pos, v) in variables.values_mut().enumerate() {
530 *v = Variable::Integer(pos as i64 + 1);
531 }
532
533 assert_expr(expr, &variables);
534
535 for (pos, v) in variables.values_mut().enumerate() {
536 *v = Variable::Integer((num_vars - pos) as i64);
537 }
538
539 assert_expr(expr, &variables);
540 }
541
542 for expr in [
543 "true && false",
544 "!true || false",
545 "true && !false",
546 "!(true && false)",
547 "true || true && false",
548 "!false && (true || false)",
549 "!(true || !false) && true",
550 "!(!true && !false)",
551 "true || false && !true",
552 "!(true && true) || !false",
553 "!(!true || !false) && (!false) && !(!true)",
554 ] {
555 let pexp = parse_expression(expr.replace("true", "1").replace("false", "0").as_str());
556 let result = pexp.eval(&HashMap::new()).unwrap();
557
558 match (eval(expr).expect(expr), result) {
561 (Value::Float(a), Variable::Float(b)) if a == b => (),
562 (Value::Float(a), Variable::Integer(b)) if a == b as f64 => (),
563 (Value::Boolean(a), Variable::Integer(b)) if a == (b != 0) => (),
564 (a, b) => {
565 panic!("{} => {:?} != {:?}", expr, a, b)
566 }
567 }
568 }
569 }
570
571 fn assert_expr(expr: &str, variables: &HashMap<String, Variable>) {
572 let e = parse_expression(expr);
573
574 let result = e.eval(variables).unwrap();
575
576 let mut str_expr = expr.to_string();
577 let mut str_expr_float = expr.to_string();
578 for (k, v) in variables {
579 let v = v.to_string();
580
581 if v.contains('.') {
582 str_expr_float = str_expr_float.replace(k, &v);
583 } else {
584 str_expr_float = str_expr_float.replace(k, &format!("{}.0", v));
585 }
586 str_expr = str_expr.replace(k, &v);
587 }
588
589 assert_eq!(
590 parse_expression(&str_expr)
591 .eval(&HashMap::new())
592 .unwrap()
593 .to_number()
594 .to_float(),
595 result.to_number().to_float()
596 );
597
598 assert_eq!(
599 parse_expression(&str_expr_float)
600 .eval(&HashMap::new())
601 .unwrap()
602 .to_number()
603 .to_float(),
604 result.to_number().to_float()
605 );
606
607 match (
610 eval(&str_expr_float)
611 .map(|v| {
612 if matches!(&v, Value::Float(f) if f64::is_infinite(*f)) {
614 Value::Float(0.0)
615 } else {
616 v
617 }
618 })
619 .expect(&str_expr),
620 result,
621 ) {
622 (Value::Float(a), Variable::Float(b)) if a == b => (),
623 (Value::Float(a), Variable::Integer(b)) if a == b as f64 => (),
624 (Value::Boolean(a), Variable::Integer(b)) if a == (b != 0) => (),
625 (a, b) => {
626 panic!("{} => {:?} != {:?}", str_expr, a, b)
627 }
628 }
629 }
630
631 fn parse_expression(expr: &str) -> Vec<Expression> {
632 ExpressionParser::from_tokenizer(Tokenizer::new(expr, |var_name: &str, _: bool| {
633 Ok::<_, String>(Token::Variable(VariableType::Global(var_name.to_string())))
634 }))
635 .parse()
636 .unwrap()
637 .output
638 }
639}