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