1mod lua_value;
2
3pub use lua_value::*;
4
5use crate::nodes::*;
6
7#[derive(Debug, Clone, Default, PartialEq, Eq)]
9pub struct Evaluator {
10 pure_metamethods: bool,
11}
12
13impl Evaluator {
14 pub fn assume_pure_metamethods(mut self) -> Self {
19 self.pure_metamethods = true;
20 self
21 }
22
23 pub fn evaluate(&self, expression: &Expression) -> LuaValue {
24 match expression {
25 Expression::False(_) => LuaValue::False,
26 Expression::Function(_) => LuaValue::Function,
27 Expression::Nil(_) => LuaValue::Nil,
28 Expression::Number(number) => LuaValue::from(number.compute_value()),
29 Expression::String(string) => LuaValue::from(string.get_value()),
30 Expression::Table(_) => LuaValue::Table,
31 Expression::True(_) => LuaValue::True,
32 Expression::Binary(binary) => self.evaluate_binary(binary),
33 Expression::Unary(unary) => self.evaluate_unary(unary),
34 Expression::Parenthese(parenthese) => {
35 self.evaluate(parenthese.inner_expression())
38 }
39 Expression::If(if_expression) => self.evaluate_if(if_expression),
40 Expression::InterpolatedString(interpolated_string) => {
41 let mut result = String::new();
42 for segment in interpolated_string.iter_segments() {
43 match segment {
44 InterpolationSegment::String(string) => {
45 result.push_str(string.get_value());
46 }
47 InterpolationSegment::Value(value) => {
48 match self.evaluate(value.get_expression()) {
49 LuaValue::False => {
50 result.push_str("false");
51 }
52 LuaValue::True => {
53 result.push_str("true");
54 }
55 LuaValue::Nil => {
56 result.push_str("nil");
57 }
58 LuaValue::String(string) => {
59 result.push_str(&string);
60 }
61 LuaValue::Function
62 | LuaValue::Number(_)
63 | LuaValue::Table
64 | LuaValue::Unknown => return LuaValue::Unknown,
65 }
66 }
67 }
68 }
69 LuaValue::String(result)
70 }
71 Expression::TypeCast(type_cast) => self.evaluate(type_cast.get_expression()),
72 Expression::Call(_)
73 | Expression::Field(_)
74 | Expression::Identifier(_)
75 | Expression::Index(_)
76 | Expression::VariableArguments(_) => LuaValue::Unknown,
77 }
78 }
79
80 #[allow(clippy::only_used_in_recursion)]
81 pub fn can_return_multiple_values(&self, expression: &Expression) -> bool {
82 match expression {
83 Expression::Call(_)
84 | Expression::Field(_)
85 | Expression::Index(_)
86 | Expression::Unary(_)
87 | Expression::VariableArguments(_) => true,
88 Expression::Binary(binary) => {
89 !matches!(binary.operator(), BinaryOperator::And | BinaryOperator::Or)
90 }
91 Expression::False(_)
92 | Expression::Function(_)
93 | Expression::Identifier(_)
94 | Expression::If(_)
95 | Expression::Nil(_)
96 | Expression::Number(_)
97 | Expression::Parenthese(_)
98 | Expression::String(_)
99 | Expression::InterpolatedString(_)
100 | Expression::Table(_)
101 | Expression::True(_) => false,
102 Expression::TypeCast(type_cast) => {
103 self.can_return_multiple_values(type_cast.get_expression())
104 }
105 }
106 }
107
108 pub fn has_side_effects(&self, expression: &Expression) -> bool {
109 match expression {
110 Expression::False(_)
111 | Expression::Function(_)
112 | Expression::Identifier(_)
113 | Expression::Nil(_)
114 | Expression::Number(_)
115 | Expression::String(_)
116 | Expression::True(_)
117 | Expression::VariableArguments(_) => false,
118 Expression::If(if_expression) => self.if_expression_has_side_effects(if_expression),
119 Expression::Binary(binary) => {
120 let left = binary.left();
121 let right = binary.right();
122
123 let left_value = self.evaluate(left);
124 let left_side_effect = self.has_side_effects(binary.left());
125
126 match binary.operator() {
127 BinaryOperator::And => {
128 if left_value.is_truthy().unwrap_or(true) {
129 left_side_effect || self.has_side_effects(binary.right())
130 } else {
131 left_side_effect
132 }
133 }
134 BinaryOperator::Or => {
135 if left_value.is_truthy().unwrap_or(false) {
136 left_side_effect
137 } else {
138 left_side_effect || self.has_side_effects(binary.right())
139 }
140 }
141 _ => {
142 if self.pure_metamethods {
143 left_side_effect || self.has_side_effects(binary.right())
144 } else {
145 self.maybe_metatable(&left_value)
146 || self.maybe_metatable(&self.evaluate(right))
147 || self.has_side_effects(left)
148 || self.has_side_effects(right)
149 }
150 }
151 }
152 }
153 Expression::Unary(unary) => {
154 if self.pure_metamethods || matches!(unary.operator(), UnaryOperator::Not) {
155 self.has_side_effects(unary.get_expression())
156 } else {
157 let sub_expression = unary.get_expression();
158
159 self.maybe_metatable(&self.evaluate(sub_expression))
160 || self.has_side_effects(sub_expression)
161 }
162 }
163 Expression::Field(field) => self.field_has_side_effects(field),
164 Expression::Index(index) => self.index_has_side_effects(index),
165 Expression::Parenthese(parenthese) => {
166 self.has_side_effects(parenthese.inner_expression())
167 }
168 Expression::Table(table) => table
169 .get_entries()
170 .iter()
171 .any(|entry| self.table_entry_has_side_effects(entry)),
172 Expression::Call(call) => self.call_has_side_effects(call),
173 Expression::InterpolatedString(interpolated_string) => interpolated_string
174 .iter_segments()
175 .any(|segment| match segment {
176 InterpolationSegment::String(_) => false,
177 InterpolationSegment::Value(value) => {
178 self.has_side_effects(value.get_expression())
179 }
180 }),
181 Expression::TypeCast(type_cast) => self.has_side_effects(type_cast.get_expression()),
182 }
183 }
184
185 fn if_expression_has_side_effects(&self, if_expression: &IfExpression) -> bool {
186 if self.has_side_effects(if_expression.get_condition()) {
187 return true;
188 }
189
190 let condition = self.evaluate(if_expression.get_condition());
191
192 if let Some(truthy) = condition.is_truthy() {
193 if truthy {
194 self.has_side_effects(if_expression.get_result())
195 } else {
196 for branch in if_expression.iter_branches() {
197 if self.has_side_effects(branch.get_condition()) {
198 return true;
199 }
200
201 let branch_condition = self.evaluate(branch.get_condition());
202
203 if let Some(truthy) = branch_condition.is_truthy() {
204 if truthy {
205 return self.has_side_effects(branch.get_result());
206 }
207 } else if self.has_side_effects(branch.get_result()) {
208 return true;
209 }
210 }
211
212 self.has_side_effects(if_expression.get_else_result())
213 }
214 } else {
215 if self.has_side_effects(if_expression.get_result()) {
216 return true;
217 }
218
219 for branch in if_expression.iter_branches() {
220 if self.has_side_effects(branch.get_condition())
221 || self.has_side_effects(branch.get_result())
222 {
223 return true;
224 }
225 }
226
227 self.has_side_effects(if_expression.get_else_result())
228 }
229 }
230
231 #[inline]
232 fn call_has_side_effects(&self, _call: &FunctionCall) -> bool {
233 true
234 }
235
236 #[inline]
237 fn table_entry_has_side_effects(&self, entry: &TableEntry) -> bool {
238 match entry {
239 TableEntry::Field(entry) => self.has_side_effects(entry.get_value()),
240 TableEntry::Index(entry) => {
241 self.has_side_effects(entry.get_key()) || self.has_side_effects(entry.get_value())
242 }
243 TableEntry::Value(value) => self.has_side_effects(value),
244 }
245 }
246
247 #[inline]
248 fn field_has_side_effects(&self, field: &FieldExpression) -> bool {
249 !self.pure_metamethods || self.prefix_has_side_effects(field.get_prefix())
250 }
251
252 #[inline]
253 fn index_has_side_effects(&self, index: &IndexExpression) -> bool {
254 !self.pure_metamethods
255 || self.has_side_effects(index.get_index())
256 || self.prefix_has_side_effects(index.get_prefix())
257 }
258
259 fn prefix_has_side_effects(&self, prefix: &Prefix) -> bool {
260 match prefix {
261 Prefix::Call(call) => self.call_has_side_effects(call),
262 Prefix::Field(field) => self.field_has_side_effects(field),
263 Prefix::Identifier(_) => false,
264 Prefix::Index(index) => self.index_has_side_effects(index),
265 Prefix::Parenthese(sub_expression) => {
266 self.has_side_effects(sub_expression.inner_expression())
267 }
268 }
269 }
270
271 #[inline]
272 fn maybe_metatable(&self, value: &LuaValue) -> bool {
273 match value {
274 LuaValue::False
275 | LuaValue::Function
276 | LuaValue::Nil
277 | LuaValue::Number(_)
278 | LuaValue::String(_)
279 | LuaValue::Table
280 | LuaValue::True => false,
281 LuaValue::Unknown => true,
282 }
283 }
284
285 fn evaluate_binary(&self, expression: &BinaryExpression) -> LuaValue {
286 match expression.operator() {
287 BinaryOperator::And => self
288 .evaluate(expression.left())
289 .map_if_truthy(|_| self.evaluate(expression.right())),
290 BinaryOperator::Or => self
291 .evaluate(expression.left())
292 .map_if_truthy_else(|left| left, || self.evaluate(expression.right())),
293 BinaryOperator::Equal => self.evaluate_equal(
294 &self.evaluate(expression.left()),
295 &self.evaluate(expression.right()),
296 ),
297 BinaryOperator::NotEqual => {
298 let result = self.evaluate_equal(
299 &self.evaluate(expression.left()),
300 &self.evaluate(expression.right()),
301 );
302
303 match result {
304 LuaValue::True => LuaValue::False,
305 LuaValue::False => LuaValue::True,
306 _ => LuaValue::Unknown,
307 }
308 }
309 BinaryOperator::Plus => self.evaluate_math(expression, |a, b| a + b),
310 BinaryOperator::Minus => self.evaluate_math(expression, |a, b| a - b),
311 BinaryOperator::Asterisk => self.evaluate_math(expression, |a, b| a * b),
312 BinaryOperator::Slash => self.evaluate_math(expression, |a, b| a / b),
313 BinaryOperator::DoubleSlash => self.evaluate_math(expression, |a, b| (a / b).floor()),
314 BinaryOperator::Caret => self.evaluate_math(expression, |a, b| a.powf(b)),
315 BinaryOperator::Percent => {
316 self.evaluate_math(expression, |a, b| a - b * (a / b).floor())
317 }
318 BinaryOperator::Concat => {
319 match (
320 self.evaluate(expression.left()).string_coercion(),
321 self.evaluate(expression.right()).string_coercion(),
322 ) {
323 (LuaValue::String(mut left), LuaValue::String(right)) => {
324 left.push_str(&right);
325 LuaValue::String(left)
326 }
327 _ => LuaValue::Unknown,
328 }
329 }
330 BinaryOperator::LowerThan => self.evaluate_relational(expression, |a, b| a < b),
331 BinaryOperator::LowerOrEqualThan => self.evaluate_relational(expression, |a, b| a <= b),
332 BinaryOperator::GreaterThan => self.evaluate_relational(expression, |a, b| a > b),
333 BinaryOperator::GreaterOrEqualThan => {
334 self.evaluate_relational(expression, |a, b| a >= b)
335 }
336 }
337 }
338
339 fn evaluate_equal(&self, left: &LuaValue, right: &LuaValue) -> LuaValue {
340 match (left, right) {
341 (LuaValue::Unknown, _) | (_, LuaValue::Unknown) => LuaValue::Unknown,
342 (LuaValue::True, LuaValue::True)
343 | (LuaValue::False, LuaValue::False)
344 | (LuaValue::Nil, LuaValue::Nil) => LuaValue::True,
345 (LuaValue::Number(a), LuaValue::Number(b)) => {
346 LuaValue::from((a - b).abs() < f64::EPSILON)
347 }
348 (LuaValue::String(a), LuaValue::String(b)) => LuaValue::from(a == b),
349 _ => LuaValue::False,
350 }
351 }
352
353 fn evaluate_math<F>(&self, expression: &BinaryExpression, operation: F) -> LuaValue
354 where
355 F: Fn(f64, f64) -> f64,
356 {
357 let left = self.evaluate(expression.left()).number_coercion();
358
359 if let LuaValue::Number(left) = left {
360 let right = self.evaluate(expression.right()).number_coercion();
361
362 if let LuaValue::Number(right) = right {
363 LuaValue::Number(operation(left, right))
364 } else {
365 LuaValue::Unknown
366 }
367 } else {
368 LuaValue::Unknown
369 }
370 }
371
372 fn evaluate_relational<F>(&self, expression: &BinaryExpression, operation: F) -> LuaValue
373 where
374 F: Fn(f64, f64) -> bool,
375 {
376 let left = self.evaluate(expression.left());
377
378 match left {
379 LuaValue::Number(left) => {
380 let right = self.evaluate(expression.right());
381
382 if let LuaValue::Number(right) = right {
383 if operation(left, right) {
384 LuaValue::True
385 } else {
386 LuaValue::False
387 }
388 } else {
389 LuaValue::Unknown
390 }
391 }
392 LuaValue::String(left) => {
393 let right = self.evaluate(expression.right());
394
395 if let LuaValue::String(right) = right {
396 self.compare_strings(&left, &right, expression.operator())
397 } else {
398 LuaValue::Unknown
399 }
400 }
401 _ => LuaValue::Unknown,
402 }
403 }
404
405 fn compare_strings(&self, left: &str, right: &str, operator: BinaryOperator) -> LuaValue {
406 LuaValue::from(match operator {
407 BinaryOperator::Equal => left == right,
408 BinaryOperator::NotEqual => left != right,
409 BinaryOperator::LowerThan => left < right,
410 BinaryOperator::LowerOrEqualThan => left <= right,
411 BinaryOperator::GreaterThan => left > right,
412 BinaryOperator::GreaterOrEqualThan => left >= right,
413 _ => return LuaValue::Unknown,
414 })
415 }
416
417 fn evaluate_unary(&self, expression: &UnaryExpression) -> LuaValue {
418 match expression.operator() {
419 UnaryOperator::Not => self
420 .evaluate(expression.get_expression())
421 .is_truthy()
422 .map(|value| LuaValue::from(!value))
423 .unwrap_or(LuaValue::Unknown),
424 UnaryOperator::Minus => {
425 match self.evaluate(expression.get_expression()).number_coercion() {
426 LuaValue::Number(value) => LuaValue::from(-value),
427 _ => LuaValue::Unknown,
428 }
429 }
430 _ => LuaValue::Unknown,
431 }
432 }
433
434 fn evaluate_if(&self, expression: &IfExpression) -> LuaValue {
435 let condition = self.evaluate(expression.get_condition());
436
437 if let Some(truthy) = condition.is_truthy() {
438 if truthy {
439 self.evaluate(expression.get_result())
440 } else {
441 for branch in expression.iter_branches() {
442 let branch_condition = self.evaluate(branch.get_condition());
443 if let Some(truthy) = branch_condition.is_truthy() {
444 if truthy {
445 return self.evaluate(branch.get_result());
446 }
447 } else {
448 return LuaValue::Unknown;
449 }
450 }
451
452 self.evaluate(expression.get_else_result())
453 }
454 } else {
455 LuaValue::Unknown
456 }
457 }
458}
459
460#[cfg(test)]
461mod test {
462 use super::*;
463
464 macro_rules! evaluate_expressions {
465 ($($name:ident ($expression:expr) => $value:expr),* $(,)?) => {
466 $(
467 #[test]
468 fn $name() {
469 assert_eq!($value, Evaluator::default().evaluate(&$expression.into()));
470 }
471 )*
472 };
473 }
474
475 evaluate_expressions!(
476 true_expression(Expression::from(true)) => LuaValue::True,
477 false_expression(Expression::from(false)) => LuaValue::False,
478 nil_expression(Expression::nil()) => LuaValue::Nil,
479 number_expression(DecimalNumber::new(0.0)) => LuaValue::Number(0.0),
480 number_expression_negative_zero(DecimalNumber::new(-0.0)) => LuaValue::Number(-0.0),
481 string_expression(StringExpression::from_value("foo")) => LuaValue::String("foo".to_owned()),
482 empty_interpolated_string_expression(InterpolatedStringExpression::empty()) => LuaValue::String("".to_owned()),
483 interpolated_string_expression_with_one_string(InterpolatedStringExpression::empty().with_segment("hello"))
484 => LuaValue::String("hello".to_owned()),
485 interpolated_string_expression_with_multiple_string_segments(
486 InterpolatedStringExpression::empty()
487 .with_segment("hello")
488 .with_segment("-")
489 .with_segment("bye")
490 ) => LuaValue::String("hello-bye".to_owned()),
491 interpolated_string_expression_with_true_segment(
492 InterpolatedStringExpression::empty().with_segment(Expression::from(true))
493 ) => LuaValue::String("true".to_owned()),
494 interpolated_string_expression_with_false_segment(
495 InterpolatedStringExpression::empty().with_segment(Expression::from(false))
496 ) => LuaValue::String("false".to_owned()),
497 interpolated_string_expression_with_nil_segment(
498 InterpolatedStringExpression::empty().with_segment(Expression::nil())
499 ) => LuaValue::String("nil".to_owned()),
500 interpolated_string_expression_with_mixed_segments(
501 InterpolatedStringExpression::empty()
502 .with_segment("variable = ")
503 .with_segment(Expression::from(true))
504 .with_segment("?")
505 ) => LuaValue::String("variable = true?".to_owned()),
506 interpolated_string_expression_with_mixed_segments_unknown(
507 InterpolatedStringExpression::empty()
508 .with_segment("variable = ")
509 .with_segment(Expression::identifier("test"))
510 .with_segment("!")
511 ) => LuaValue::Unknown,
512 true_wrapped_in_parens(ParentheseExpression::new(true)) => LuaValue::True,
513 false_wrapped_in_parens(ParentheseExpression::new(false)) => LuaValue::False,
514 nil_wrapped_in_parens(ParentheseExpression::new(Expression::nil())) => LuaValue::Nil,
515 number_wrapped_in_parens(ParentheseExpression::new(DecimalNumber::new(0.0)))
516 => LuaValue::Number(0.0),
517 string_wrapped_in_parens(ParentheseExpression::new(StringExpression::from_value("foo")))
518 => LuaValue::from("foo"),
519 table_expression(TableExpression::default()) => LuaValue::Table,
520 if_expression_always_true(IfExpression::new(true, 1.0, 0.0)) => LuaValue::from(1.0),
521 if_expression_always_false(IfExpression::new(false, 1.0, 0.0)) => LuaValue::from(0.0),
522 if_expression_unknown_condition(IfExpression::new(Expression::identifier("test"), 1.0, 0.0))
523 => LuaValue::Unknown,
524 if_expression_elseif_always_true(IfExpression::new(false, 1.0, 0.0).with_branch(true, 2.0))
525 => LuaValue::from(2.0),
526 if_expression_elseif_always_false(IfExpression::new(false, 1.0, 0.0).with_branch(false, 2.0))
527 => LuaValue::from(0.0),
528 );
529
530 mod binary_expressions {
531 use super::*;
532
533 macro_rules! evaluate_binary_expressions {
534 ($($name:ident ($operator:expr, $left:expr, $right:expr) => $expect:expr),* $(,)?) => {
535 $(
536 #[test]
537 fn $name() {
538 let binary = BinaryExpression::new($operator, $left, $right);
539
540 let result = Evaluator::default().evaluate(&binary.into());
541
542 match (&$expect, &result) {
543 (LuaValue::Number(expect_float), LuaValue::Number(result))=> {
544 if expect_float.is_nan() {
545 assert!(result.is_nan(), "{} should be NaN", result);
546 } else if expect_float.is_infinite() {
547 assert!(result.is_infinite(), "{} should be infinite", result);
548 assert_eq!(expect_float.is_sign_positive(), result.is_sign_positive());
549 } else {
550 assert!(
551 (expect_float - result).abs() < f64::EPSILON,
552 "{} does not approximate {}", result, expect_float
553 );
554 assert!(
555 expect_float.is_sign_positive() == result.is_sign_positive(),
556 "{} should be of the same sign as {}", result, expect_float
557 );
558 }
559 }
560 _ => {
561 assert_eq!($expect, result);
562 }
563 }
564 }
565 )*
566 };
567 }
568
569 evaluate_binary_expressions!(
570 true_and_number(
571 BinaryOperator::And,
572 true,
573 Expression::Number(DecimalNumber::new(0.0).into())
574 ) => LuaValue::Number(0.0),
575 true_and_true(
576 BinaryOperator::And,
577 true,
578 true
579 ) => LuaValue::True,
580 true_and_false(
581 BinaryOperator::And,
582 true,
583 false
584 ) => LuaValue::False,
585 true_and_nil(
586 BinaryOperator::And,
587 true,
588 Expression::nil()
589 ) => LuaValue::Nil,
590 true_and_string(
591 BinaryOperator::And,
592 true,
593 Expression::String(StringExpression::from_value("foo"))
594 ) => LuaValue::String("foo".to_owned()),
595 true_and_table(
596 BinaryOperator::And,
597 true,
598 TableExpression::default()
599 ) => LuaValue::Table,
600 nil_and_true(
601 BinaryOperator::And,
602 Expression::nil(),
603 true
604 ) => LuaValue::Nil,
605 false_and_true(
606 BinaryOperator::And,
607 false,
608 true
609 ) => LuaValue::False,
610 true_or_number(
611 BinaryOperator::Or,
612 true,
613 Expression::Number(DecimalNumber::new(0.0).into())
614 ) => LuaValue::True,
615 true_or_true(
616 BinaryOperator::Or,
617 true,
618 true
619 ) => LuaValue::True,
620 true_or_false(
621 BinaryOperator::Or,
622 true,
623 false
624 ) => LuaValue::True,
625 true_or_nil(
626 BinaryOperator::Or,
627 true,
628 Expression::nil()
629 ) => LuaValue::True,
630 true_or_string(
631 BinaryOperator::Or,
632 true,
633 Expression::String(StringExpression::from_value("foo"))
634 ) => LuaValue::True,
635 nil_or_true(
636 BinaryOperator::Or,
637 Expression::nil(),
638 true
639 ) => LuaValue::True,
640 nil_or_false(
641 BinaryOperator::Or,
642 Expression::nil(),
643 false
644 ) => LuaValue::False,
645 nil_or_nil(
646 BinaryOperator::Or,
647 Expression::nil(),
648 Expression::nil()
649 ) => LuaValue::Nil,
650 one_plus_two(
651 BinaryOperator::Plus,
652 Expression::from(1.0),
653 Expression::from(2.0)
654 ) => LuaValue::Number(3.0),
655 one_minus_two(
656 BinaryOperator::Minus,
657 Expression::from(1.0),
658 Expression::from(2.0)
659 ) => LuaValue::Number(-1.0),
660 three_times_four(
661 BinaryOperator::Asterisk,
662 Expression::from(3.0),
663 Expression::from(4.0)
664 ) => LuaValue::Number(12.0),
665 twelve_divided_by_four(
666 BinaryOperator::Slash,
667 Expression::from(12.0),
668 Expression::from(4.0)
669 ) => LuaValue::Number(3.0),
670 one_divided_by_zero(
671 BinaryOperator::Slash,
672 Expression::from(1.0),
673 Expression::from(0.0)
674 ) => LuaValue::Number(f64::INFINITY),
675 negative_zero_plus_negative_zero(
676 BinaryOperator::Plus,
677 Expression::from(-0.0),
678 Expression::from(-0.0)
679 ) => LuaValue::Number(-0.0),
680 negative_zero_minus_zero(
681 BinaryOperator::Minus,
682 Expression::from(-0.0),
683 Expression::from(0.0)
684 ) => LuaValue::Number(-0.0),
685 zero_divided_by_zero(
686 BinaryOperator::Slash,
687 Expression::from(0.0),
688 Expression::from(0.0)
689 ) => LuaValue::Number(f64::NAN),
690 twelve_floor_division_by_four(
691 BinaryOperator::DoubleSlash,
692 Expression::from(12.0),
693 Expression::from(4.0)
694 ) => LuaValue::Number(3.0),
695 eleven_floor_division_by_three(
696 BinaryOperator::DoubleSlash,
697 Expression::from(11.0),
698 Expression::from(3.0)
699 ) => LuaValue::Number(3.0),
700 one_floor_division_by_zero(
701 BinaryOperator::DoubleSlash,
702 Expression::from(1.0),
703 Expression::from(0.0)
704 ) => LuaValue::Number(f64::INFINITY),
705 minus_one_floor_division_by_zero(
706 BinaryOperator::DoubleSlash,
707 Expression::from(-1.0),
708 Expression::from(0.0)
709 ) => LuaValue::Number(f64::NEG_INFINITY),
710 zero_floor_division_by_zero(
711 BinaryOperator::DoubleSlash,
712 Expression::from(0.0),
713 Expression::from(0.0)
714 ) => LuaValue::Number(f64::NAN),
715 five_mod_two(
716 BinaryOperator::Percent,
717 Expression::from(5.0),
718 Expression::from(2.0)
719 ) => LuaValue::Number(1.0),
720 minus_five_mod_two(
721 BinaryOperator::Percent,
722 Expression::from(-5.0),
723 Expression::from(2.0)
724 ) => LuaValue::Number(1.0),
725 minus_five_mod_minus_two(
726 BinaryOperator::Percent,
727 Expression::from(-5.0),
728 Expression::from(-2.0)
729 ) => LuaValue::Number(-1.0),
730 five_point_two_mod_two(
731 BinaryOperator::Percent,
732 Expression::from(5.5),
733 Expression::from(2.0)
734 ) => LuaValue::Number(1.5),
735 five_pow_two(
736 BinaryOperator::Caret,
737 Expression::from(5.0),
738 Expression::from(2.0)
739 ) => LuaValue::Number(25.0),
740 string_number_plus_string_number(
741 BinaryOperator::Plus,
742 StringExpression::from_value("2"),
743 StringExpression::from_value("3")
744 ) => LuaValue::Number(5.0),
745 concat_strings(
746 BinaryOperator::Concat,
747 StringExpression::from_value("2"),
748 StringExpression::from_value("3")
749 ) => LuaValue::from("23"),
750 concat_string_with_number(
751 BinaryOperator::Concat,
752 StringExpression::from_value("foo"),
753 11.0
754 ) => LuaValue::from("foo11"),
755 concat_number_with_string(
756 BinaryOperator::Concat,
757 11.0,
758 StringExpression::from_value("foo")
759 ) => LuaValue::from("11foo"),
760 concat_number_with_number(
761 BinaryOperator::Concat,
762 11.0,
763 33.0
764 ) => LuaValue::from("1133"),
765 concat_number_with_negative_number(
766 BinaryOperator::Concat,
767 11.0,
768 -33.0
769 ) => LuaValue::from("11-33"),
770 concat_empty_strings(
771 BinaryOperator::Concat,
772 StringExpression::empty(),
773 StringExpression::empty()
774 ) => LuaValue::from(""),
775 number_lower_than_string(
776 BinaryOperator::LowerThan,
777 1.0,
778 StringExpression::empty()
779 ) => LuaValue::Unknown,
780 number_string_greater_than_number(
781 BinaryOperator::GreaterThan,
782 StringExpression::from_value("100"),
783 1.0
784 ) => LuaValue::Unknown,
785 number_string_greater_or_equal_than_number(
786 BinaryOperator::GreaterOrEqualThan,
787 StringExpression::from_value("100"),
788 100.0
789 ) => LuaValue::Unknown,
790 number_lower_or_equal_than_number_string(
791 BinaryOperator::GreaterOrEqualThan,
792 100.0,
793 StringExpression::from_value("100")
794 ) => LuaValue::Unknown,
795 );
796
797 macro_rules! evaluate_equality {
798 ($($name:ident ($left:expr, $right:expr) => $value:expr),* $(,)?) => {
799 $(
800 mod $name {
801 use super::*;
802
803 #[test]
804 fn equal() {
805 let binary = BinaryExpression::new(
806 BinaryOperator::Equal,
807 $left,
808 $right,
809 );
810
811 assert_eq!($value, Evaluator::default().evaluate(&binary.into()));
812
813 let binary = BinaryExpression::new(
814 BinaryOperator::Equal,
815 $right,
816 $left,
817 );
818
819 assert_eq!($value, Evaluator::default().evaluate(&binary.into()));
820 }
821
822 #[test]
823 fn not_equal() {
824 let value = match $value {
825 LuaValue::True => LuaValue::False,
826 LuaValue::False => LuaValue::True,
827 _ => LuaValue::Unknown
828 };
829 let binary = BinaryExpression::new(
830 BinaryOperator::NotEqual,
831 $left,
832 $right,
833 );
834
835 assert_eq!(value, Evaluator::default().evaluate(&binary.into()));
836
837 let binary = BinaryExpression::new(
838 BinaryOperator::NotEqual,
839 $right,
840 $left,
841 );
842
843 assert_eq!(value, Evaluator::default().evaluate(&binary.into()));
844 }
845 }
846 )*
847 };
848 }
849
850 evaluate_equality!(
851 true_true(Expression::from(true), Expression::from(true)) => LuaValue::True,
852 false_false(Expression::from(false), Expression::from(false)) => LuaValue::True,
853 nil_nil(Expression::nil(), Expression::nil()) => LuaValue::True,
854 same_strings(
855 StringExpression::from_value("foo"),
856 StringExpression::from_value("foo")
857 ) => LuaValue::True,
858 same_numbers(
859 Expression::Number(DecimalNumber::new(0.0).into()),
860 Expression::Number(DecimalNumber::new(0.0).into())
861 ) => LuaValue::True,
862 true_false(Expression::from(true), Expression::from(false)) => LuaValue::False,
863 true_nil(Expression::from(true), Expression::from(false)) => LuaValue::False,
864 different_numbers(
865 Expression::Number(DecimalNumber::new(1.0).into()),
866 Expression::Number(DecimalNumber::new(10.0).into())
867 ) => LuaValue::False,
868 different_strings(
869 StringExpression::from_value("foo"),
870 StringExpression::from_value("bar")
871 ) => LuaValue::False,
872 );
873
874 macro_rules! evaluate_equality_with_relational_operators {
875 ($($name:ident => $value:expr),* $(,)?) => {
876 $(
877 mod $name {
878 use super::*;
879
880 #[test]
881 fn lower() {
882 let value: Expression = $value.into();
883 let binary = BinaryExpression::new(BinaryOperator::LowerThan, value.clone(), value);
884 assert_eq!(LuaValue::False, Evaluator::default().evaluate(&binary.into()));
885 }
886
887 #[test]
888 fn lower_or_equal() {
889 let value: Expression = $value.into();
890 let binary = BinaryExpression::new(BinaryOperator::LowerOrEqualThan, value.clone(), value);
891 assert_eq!(LuaValue::True, Evaluator::default().evaluate(&binary.into()));
892 }
893
894 #[test]
895 fn greater() {
896 let value: Expression = $value.into();
897 let binary = BinaryExpression::new(BinaryOperator::GreaterThan, value.clone(), value);
898 assert_eq!(LuaValue::False, Evaluator::default().evaluate(&binary.into()));
899 }
900
901 #[test]
902 fn greater_or_equal() {
903 let value: Expression = $value.into();
904 let binary = BinaryExpression::new(BinaryOperator::GreaterOrEqualThan, value.clone(), value);
905 assert_eq!(LuaValue::True, Evaluator::default().evaluate(&binary.into()));
906 }
907 }
908 )*
909 };
910 }
911
912 evaluate_equality_with_relational_operators!(
913 zero => 1.0,
914 one => 1.0,
915 hundred => 100.0,
916 string => StringExpression::from_value("var"),
917 );
918
919 macro_rules! evaluate_strict_relational_operators {
920 ($($name_lower:ident($lower:expr) < $name_greater:ident($greater:expr)),* $(,)?) => {
921 mod lower_or_greater_than {
922 use super::*;
923 paste::paste! {
924
925 $(
926 #[test]
927 fn [<$name_lower _lower_than_ $name_greater>]() {
928 let binary = BinaryExpression::new(
929 BinaryOperator::LowerThan,
930 $lower,
931 $greater,
932 );
933 assert_eq!(LuaValue::True, Evaluator::default().evaluate(&binary.into()));
934 }
935
936 #[test]
937 fn [<$name_lower _lower_or_equal_than_ $name_greater>]() {
938 let binary = BinaryExpression::new(
939 BinaryOperator::LowerOrEqualThan,
940 $lower,
941 $greater,
942 );
943 assert_eq!(LuaValue::True, Evaluator::default().evaluate(&binary.into()));
944 }
945
946 #[test]
947 fn [<$name_lower _greater_than_ $name_greater>]() {
948 let binary = BinaryExpression::new(
949 BinaryOperator::GreaterThan,
950 $lower,
951 $greater,
952 );
953 assert_eq!(LuaValue::False, Evaluator::default().evaluate(&binary.into()));
954 }
955
956 #[test]
957 fn [<$name_lower _greater_or_equal_than_ $name_greater>]() {
958 let binary = BinaryExpression::new(
959 BinaryOperator::GreaterOrEqualThan,
960 $lower,
961 $greater,
962 );
963 assert_eq!(LuaValue::False, Evaluator::default().evaluate(&binary.into()));
964 }
965
966 #[test]
967 fn [<$name_greater _lower_than_ $name_lower>]() {
968 let binary = BinaryExpression::new(
969 BinaryOperator::LowerThan,
970 $greater,
971 $lower,
972 );
973 assert_eq!(LuaValue::False, Evaluator::default().evaluate(&binary.into()));
974 }
975
976 #[test]
977 fn [<$name_greater _lower_or_equal_than_ $name_lower>]() {
978 let binary = BinaryExpression::new(
979 BinaryOperator::LowerOrEqualThan,
980 $greater,
981 $lower,
982 );
983 assert_eq!(LuaValue::False, Evaluator::default().evaluate(&binary.into()));
984 }
985
986 #[test]
987 fn [<$name_greater _greater_than_ $name_lower>]() {
988 let binary = BinaryExpression::new(
989 BinaryOperator::GreaterThan,
990 $greater,
991 $lower,
992 );
993 assert_eq!(LuaValue::True, Evaluator::default().evaluate(&binary.into()));
994 }
995
996 #[test]
997 fn [<$name_greater _greater_or_equal_than_ $name_lower>]() {
998 let binary = BinaryExpression::new(
999 BinaryOperator::GreaterOrEqualThan,
1000 $greater,
1001 $lower,
1002 );
1003 assert_eq!(LuaValue::True, Evaluator::default().evaluate(&binary.into()));
1004 }
1005 )*
1006
1007 }
1008 }
1009 };
1010 }
1011
1012 evaluate_strict_relational_operators!(
1013 one(1.0) < hundred(100.0),
1014 minus_15(-15.0) < minus_2_5(-2.5),
1015 string_a(StringExpression::from_value("a"))
1016 < string_b(StringExpression::from_value("b")),
1017 string_a(StringExpression::from_value("a"))
1018 < string_aa(StringExpression::from_value("aa")),
1019 string_1(StringExpression::from_value("1"))
1020 < string_a(StringExpression::from_value("a")),
1021 string_111(StringExpression::from_value("111"))
1022 < string_a(StringExpression::from_value("a")),
1023 empty_string(StringExpression::from_value(""))
1024 < string_colon(StringExpression::from_value(":")),
1025 );
1026 }
1027
1028 mod unary_expressions {
1029 use super::*;
1030 use UnaryOperator::*;
1031
1032 macro_rules! evaluate_unary_expressions {
1033 ($($name:ident ($operator:expr, $input:expr) => $value:expr),*) => {
1034 $(
1035 #[test]
1036 fn $name() {
1037 let unary = UnaryExpression::new($operator, $input);
1038 assert_eq!($value, Evaluator::default().evaluate(&unary.into()));
1039 }
1040 )*
1041 };
1042 }
1043
1044 evaluate_unary_expressions!(
1045 not_true(Not, Expression::from(true)) => LuaValue::False,
1046 not_false(Not, Expression::from(false)) => LuaValue::True,
1047 not_nil(Not, Expression::nil()) => LuaValue::True,
1048 not_table(Not, TableExpression::default()) => LuaValue::False,
1049 not_string(Not, StringExpression::from_value("foo")) => LuaValue::False,
1050 not_number(
1051 Not,
1052 Expression::Number(DecimalNumber::new(10.0).into())
1053 ) => LuaValue::False,
1054 not_identifier(Not, Expression::identifier("foo")) => LuaValue::Unknown,
1055 minus_one(Minus, DecimalNumber::new(1.0)) => LuaValue::from(-1.0),
1056 minus_zero(Minus, DecimalNumber::new(-0.0)) => LuaValue::from(-0.0),
1057 minus_negative_number(Minus, DecimalNumber::new(-5.0)) => LuaValue::from(5.0),
1058 minus_string_converted_to_number(Minus, StringExpression::from_value("1")) => LuaValue::from(-1.0)
1059 );
1060 }
1061
1062 macro_rules! has_side_effects {
1063 ($($name:ident => $expression:expr),* $(,)?) => {
1064 $(
1065 #[test]
1066 fn $name() {
1067 assert!(Evaluator::default().has_side_effects(&$expression.into()));
1068 }
1069 )*
1070 };
1071 }
1072
1073 macro_rules! has_no_side_effects {
1074 ($($name:ident => $expression:expr),* $(,)?) => {
1075 $(
1076 #[test]
1077 fn $name() {
1078 assert!(!Evaluator::default().has_side_effects(&$expression.into()));
1079 }
1080 )*
1081 };
1082 }
1083
1084 has_side_effects!(
1085 call_to_unknown_function => FunctionCall::from_name("foo"),
1086 binary_true_and_call => BinaryExpression::new(
1087 BinaryOperator::And,
1088 Expression::from(true),
1089 FunctionCall::from_name("foo"),
1090 ),
1091 binary_false_or_call => BinaryExpression::new(
1092 BinaryOperator::Or,
1093 Expression::from(false),
1094 FunctionCall::from_name("var"),
1095 ),
1096 addition_unknown_variable_and_number => BinaryExpression::new(
1097 BinaryOperator::Plus,
1098 Expression::identifier("var"),
1099 1.0,
1100 ),
1101 addition_number_with_unknown_variable => BinaryExpression::new(
1102 BinaryOperator::Plus,
1103 1.0,
1104 Expression::identifier("var"),
1105 ),
1106 unary_minus_on_variable => UnaryExpression::new(UnaryOperator::Minus, Identifier::new("var")),
1107 length_on_variable => UnaryExpression::new(UnaryOperator::Length, Identifier::new("var")),
1108 field_index => FieldExpression::new(Identifier::new("var"), "field"),
1109 table_value_with_call_in_entry => TableExpression::default()
1110 .append_array_value(FunctionCall::from_name("call")),
1111
1112 interpolated_string_with_function_call => InterpolatedStringExpression::empty()
1113 .with_segment(Expression::from(FunctionCall::from_name("foo"))),
1114 );
1115
1116 has_no_side_effects!(
1117 true_value => Expression::from(true),
1118 false_value => Expression::from(false),
1119 nil_value => Expression::nil(),
1120 table_value => TableExpression::default(),
1121 number_value => Expression::Number(DecimalNumber::new(0.0).into()),
1122 string_value => StringExpression::from_value(""),
1123 empty_interpolated_string_value => InterpolatedStringExpression::empty(),
1124 interpolated_string_with_true_value => InterpolatedStringExpression::empty()
1125 .with_segment(Expression::from(true)),
1126 identifier => Expression::identifier("foo"),
1127 identifier_in_parentheses => Expression::identifier("foo").in_parentheses(),
1128 binary_false_and_call => BinaryExpression::new(
1129 BinaryOperator::And,
1130 Expression::from(false),
1131 FunctionCall::from_name("foo"),
1132 ),
1133 binary_true_or_call => BinaryExpression::new(
1134 BinaryOperator::Or,
1135 Expression::from(true),
1136 FunctionCall::from_name("foo"),
1137 ),
1138 not_variable => UnaryExpression::new(UnaryOperator::Not, Identifier::new("var")),
1139 );
1140
1141 mod assume_pure_metamethods {
1142 use super::*;
1143
1144 macro_rules! has_no_side_effects {
1145 ($($name:ident => $expression:expr),* $(,)?) => {
1146 $(
1147 #[test]
1148 fn $name() {
1149 let evaluator = Evaluator::default().assume_pure_metamethods();
1150 assert!(!evaluator.has_side_effects(&$expression.into()));
1151 }
1152 )*
1153 };
1154 }
1155
1156 has_no_side_effects!(
1157 addition_unknown_variable_and_number => BinaryExpression::new(
1158 BinaryOperator::Plus,
1159 Expression::identifier("foo"),
1160 1.0,
1161 ),
1162 addition_number_with_unknown_variable => BinaryExpression::new(
1163 BinaryOperator::Plus,
1164 1.0,
1165 Expression::identifier("foo"),
1166 ),
1167 unary_minus_on_variable => UnaryExpression::new(UnaryOperator::Minus, Identifier::new("var")),
1168 length_on_variable => UnaryExpression::new(UnaryOperator::Length, Identifier::new("var")),
1169 not_on_variable => UnaryExpression::new(UnaryOperator::Not, Identifier::new("var")),
1170 field_index => FieldExpression::new(Identifier::new("var"), "field"),
1171 );
1172 }
1173}