Skip to main content

darklua_core/process/evaluator/
mod.rs

1mod lua_value;
2
3pub use lua_value::*;
4
5use crate::nodes::*;
6
7/// A struct to convert an Expression node into a LuaValue object.
8#[derive(Debug, Clone, Default, PartialEq, Eq)]
9pub struct Evaluator {
10    pure_metamethods: bool,
11}
12
13impl Evaluator {
14    /// When evaluating expressions related to tables, this value tells the evaluator if
15    /// metamethods can have side effects. For example, indexing a normal table in Lua does not
16    /// have any side effects, but if the table is a metatable, it's `__index` metamethod can
17    /// possibly have side effects (since it can be a function call).
18    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        // when the evaluator will be able to manage tuples, keep only the first element
84        // of the tuple here (or coerce the tuple to `nil` if it is empty)
85        self.evaluate_prefix(type_instantiation.get_prefix())
86    }
87
88    fn evaluate_parenthese_expression(&self, parenthese: &ParentheseExpression) -> LuaValue {
89        // when the evaluator will be able to manage tuples, keep only the first element
90        // of the tuple here (or coerce the tuple to `nil` if it is empty)
91        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}