darklua_core/nodes/expressions/
binary.rs

1use crate::nodes::{Expression, FunctionReturnType, Token, Type};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4pub enum BinaryOperator {
5    And,
6    Or,
7    Equal,
8    NotEqual,
9    LowerThan,
10    LowerOrEqualThan,
11    GreaterThan,
12    GreaterOrEqualThan,
13    Plus,
14    Minus,
15    Asterisk,
16    Slash,
17    DoubleSlash,
18    Percent,
19    Caret,
20    Concat,
21}
22
23#[inline]
24fn ends_with_if_expression(expression: &Expression) -> bool {
25    let mut current = expression;
26
27    loop {
28        match current {
29            Expression::If(_) => break true,
30            Expression::Binary(binary) => current = binary.right(),
31            Expression::Unary(unary) => current = unary.get_expression(),
32            Expression::Call(_)
33            | Expression::False(_)
34            | Expression::Field(_)
35            | Expression::Function(_)
36            | Expression::Identifier(_)
37            | Expression::Index(_)
38            | Expression::Nil(_)
39            | Expression::Number(_)
40            | Expression::Parenthese(_)
41            | Expression::String(_)
42            | Expression::InterpolatedString(_)
43            | Expression::Table(_)
44            | Expression::True(_)
45            | Expression::VariableArguments(_)
46            | Expression::TypeCast(_) => break false,
47        }
48    }
49}
50
51#[inline]
52fn ends_with_type_cast_to_type_name_without_type_parameters(expression: &Expression) -> bool {
53    let mut current = expression;
54
55    loop {
56        match current {
57            Expression::If(if_statement) => current = if_statement.get_else_result(),
58            Expression::Binary(binary) => current = binary.right(),
59            Expression::Unary(unary) => current = unary.get_expression(),
60            Expression::TypeCast(type_cast) => {
61                let mut current_type = type_cast.get_type();
62
63                break loop {
64                    match current_type {
65                        Type::Name(name) => break !name.has_type_parameters(),
66                        Type::Field(field) => break !field.get_type_name().has_type_parameters(),
67                        Type::Function(function) => {
68                            current_type = match function.get_return_type() {
69                                FunctionReturnType::Type(r#type) => r#type,
70                                FunctionReturnType::TypePack(_)
71                                | FunctionReturnType::GenericTypePack(_) => break false,
72                                FunctionReturnType::VariadicTypePack(variadic_type) => {
73                                    variadic_type.get_type()
74                                }
75                            }
76                        }
77                        Type::Intersection(intersection) => {
78                            current_type = intersection.last_type();
79                        }
80                        Type::Union(union_type) => {
81                            current_type = union_type.last_type();
82                        }
83                        Type::True(_)
84                        | Type::False(_)
85                        | Type::Nil(_)
86                        | Type::String(_)
87                        | Type::Array(_)
88                        | Type::Table(_)
89                        | Type::TypeOf(_)
90                        | Type::Parenthese(_)
91                        | Type::Optional(_) => break false,
92                    }
93                };
94            }
95            Expression::Call(_)
96            | Expression::False(_)
97            | Expression::Field(_)
98            | Expression::Function(_)
99            | Expression::Identifier(_)
100            | Expression::Index(_)
101            | Expression::Nil(_)
102            | Expression::Number(_)
103            | Expression::Parenthese(_)
104            | Expression::String(_)
105            | Expression::InterpolatedString(_)
106            | Expression::Table(_)
107            | Expression::True(_)
108            | Expression::VariableArguments(_) => break false,
109        }
110    }
111}
112
113impl BinaryOperator {
114    #[inline]
115    pub fn precedes(&self, other: Self) -> bool {
116        self.get_precedence() > other.get_precedence()
117    }
118
119    #[inline]
120    pub fn precedes_unary_expression(&self) -> bool {
121        matches!(self, Self::Caret)
122    }
123
124    #[inline]
125    pub fn is_left_associative(&self) -> bool {
126        !matches!(self, Self::Caret | Self::Concat)
127    }
128
129    #[inline]
130    pub fn is_right_associative(&self) -> bool {
131        matches!(self, Self::Caret | Self::Concat)
132    }
133
134    pub fn left_needs_parentheses(&self, left: &Expression) -> bool {
135        let needs_parentheses = match left {
136            Expression::Binary(left) => {
137                if self.is_left_associative() {
138                    self.precedes(left.operator())
139                } else {
140                    !left.operator().precedes(*self)
141                }
142            }
143            Expression::Unary(_) => self.precedes_unary_expression(),
144            Expression::If(_) => true,
145            _ => false,
146        };
147        needs_parentheses
148            || ends_with_if_expression(left)
149            || (matches!(self, BinaryOperator::LowerThan)
150                && ends_with_type_cast_to_type_name_without_type_parameters(left))
151    }
152
153    pub fn right_needs_parentheses(&self, right: &Expression) -> bool {
154        match right {
155            Expression::Binary(right) => {
156                if self.is_right_associative() {
157                    self.precedes(right.operator())
158                } else {
159                    !right.operator().precedes(*self)
160                }
161            }
162            Expression::Unary(_) => false,
163            _ => false,
164        }
165    }
166
167    pub fn to_str(&self) -> &'static str {
168        match self {
169            Self::And => "and",
170            Self::Or => "or",
171            Self::Equal => "==",
172            Self::NotEqual => "~=",
173            Self::LowerThan => "<",
174            Self::LowerOrEqualThan => "<=",
175            Self::GreaterThan => ">",
176            Self::GreaterOrEqualThan => ">=",
177            Self::Plus => "+",
178            Self::Minus => "-",
179            Self::Asterisk => "*",
180            Self::Slash => "/",
181            Self::DoubleSlash => "//",
182            Self::Percent => "%",
183            Self::Caret => "^",
184            Self::Concat => "..",
185        }
186    }
187
188    fn get_precedence(&self) -> u8 {
189        match self {
190            Self::Or => 0,
191            Self::And => 1,
192            Self::Equal
193            | Self::NotEqual
194            | Self::LowerThan
195            | Self::LowerOrEqualThan
196            | Self::GreaterThan
197            | Self::GreaterOrEqualThan => 2,
198            Self::Concat => 3,
199            Self::Plus | Self::Minus => 4,
200            Self::Asterisk | Self::Slash | Self::DoubleSlash | Self::Percent => 5,
201            Self::Caret => 7,
202        }
203    }
204}
205
206#[derive(Clone, Debug, PartialEq, Eq)]
207pub struct BinaryExpression {
208    operator: BinaryOperator,
209    left: Expression,
210    right: Expression,
211    token: Option<Token>,
212}
213
214impl BinaryExpression {
215    pub fn new<T: Into<Expression>, U: Into<Expression>>(
216        operator: BinaryOperator,
217        left: T,
218        right: U,
219    ) -> Self {
220        Self {
221            operator,
222            left: left.into(),
223            right: right.into(),
224            token: None,
225        }
226    }
227
228    pub fn with_token(mut self, token: Token) -> Self {
229        self.token = Some(token);
230        self
231    }
232
233    #[inline]
234    pub fn set_token(&mut self, token: Token) {
235        self.token = Some(token);
236    }
237
238    #[inline]
239    pub fn get_token(&self) -> Option<&Token> {
240        self.token.as_ref()
241    }
242
243    #[inline]
244    pub fn mutate_left(&mut self) -> &mut Expression {
245        &mut self.left
246    }
247
248    #[inline]
249    pub fn mutate_right(&mut self) -> &mut Expression {
250        &mut self.right
251    }
252
253    #[inline]
254    pub fn left(&self) -> &Expression {
255        &self.left
256    }
257
258    #[inline]
259    pub fn right(&self) -> &Expression {
260        &self.right
261    }
262
263    #[inline]
264    pub fn operator(&self) -> BinaryOperator {
265        self.operator
266    }
267
268    super::impl_token_fns!(iter = [token]);
269}
270
271#[cfg(test)]
272mod test {
273    use super::*;
274
275    mod precedence {
276        use super::*;
277
278        use BinaryOperator::*;
279
280        #[test]
281        fn caret() {
282            assert!(Caret.precedes(And));
283            assert!(Caret.precedes(Or));
284            assert!(Caret.precedes(Equal));
285            assert!(Caret.precedes(NotEqual));
286            assert!(Caret.precedes(LowerThan));
287            assert!(Caret.precedes(LowerOrEqualThan));
288            assert!(Caret.precedes(GreaterThan));
289            assert!(Caret.precedes(GreaterOrEqualThan));
290            assert!(Caret.precedes(Plus));
291            assert!(Caret.precedes(Minus));
292            assert!(Caret.precedes(Asterisk));
293            assert!(Caret.precedes(Slash));
294            assert!(Caret.precedes(DoubleSlash));
295            assert!(Caret.precedes(Percent));
296            assert!(Caret.precedes(Concat));
297            assert!(!Caret.precedes(Caret));
298            assert!(Caret.precedes_unary_expression());
299        }
300
301        #[test]
302        fn asterisk() {
303            assert!(Asterisk.precedes(And));
304            assert!(Asterisk.precedes(Or));
305            assert!(Asterisk.precedes(Equal));
306            assert!(Asterisk.precedes(NotEqual));
307            assert!(Asterisk.precedes(LowerThan));
308            assert!(Asterisk.precedes(LowerOrEqualThan));
309            assert!(Asterisk.precedes(GreaterThan));
310            assert!(Asterisk.precedes(GreaterOrEqualThan));
311            assert!(Asterisk.precedes(Plus));
312            assert!(Asterisk.precedes(Minus));
313            assert!(!Asterisk.precedes(Asterisk));
314            assert!(!Asterisk.precedes(Slash));
315            assert!(!Asterisk.precedes(DoubleSlash));
316            assert!(!Asterisk.precedes(Percent));
317            assert!(Asterisk.precedes(Concat));
318            assert!(!Asterisk.precedes(Caret));
319            assert!(!Asterisk.precedes_unary_expression());
320        }
321
322        #[test]
323        fn slash() {
324            assert!(Slash.precedes(And));
325            assert!(Slash.precedes(Or));
326            assert!(Slash.precedes(Equal));
327            assert!(Slash.precedes(NotEqual));
328            assert!(Slash.precedes(LowerThan));
329            assert!(Slash.precedes(LowerOrEqualThan));
330            assert!(Slash.precedes(GreaterThan));
331            assert!(Slash.precedes(GreaterOrEqualThan));
332            assert!(Slash.precedes(Plus));
333            assert!(Slash.precedes(Minus));
334            assert!(!Slash.precedes(Asterisk));
335            assert!(!Slash.precedes(Slash));
336            assert!(!Slash.precedes(DoubleSlash));
337            assert!(!Slash.precedes(Percent));
338            assert!(Slash.precedes(Concat));
339            assert!(!Slash.precedes(Caret));
340            assert!(!Slash.precedes_unary_expression());
341        }
342
343        #[test]
344        fn percent() {
345            assert!(Percent.precedes(And));
346            assert!(Percent.precedes(Or));
347            assert!(Percent.precedes(Equal));
348            assert!(Percent.precedes(NotEqual));
349            assert!(Percent.precedes(LowerThan));
350            assert!(Percent.precedes(LowerOrEqualThan));
351            assert!(Percent.precedes(GreaterThan));
352            assert!(Percent.precedes(GreaterOrEqualThan));
353            assert!(Percent.precedes(Plus));
354            assert!(Percent.precedes(Minus));
355            assert!(!Percent.precedes(Asterisk));
356            assert!(!Percent.precedes(Slash));
357            assert!(!Percent.precedes(DoubleSlash));
358            assert!(!Percent.precedes(Percent));
359            assert!(Percent.precedes(Concat));
360            assert!(!Percent.precedes(Caret));
361            assert!(!Percent.precedes_unary_expression());
362        }
363
364        #[test]
365        fn plus() {
366            assert!(Plus.precedes(And));
367            assert!(Plus.precedes(Or));
368            assert!(Plus.precedes(Equal));
369            assert!(Plus.precedes(NotEqual));
370            assert!(Plus.precedes(LowerThan));
371            assert!(Plus.precedes(LowerOrEqualThan));
372            assert!(Plus.precedes(GreaterThan));
373            assert!(Plus.precedes(GreaterOrEqualThan));
374            assert!(!Plus.precedes(Plus));
375            assert!(!Plus.precedes(Minus));
376            assert!(!Plus.precedes(Asterisk));
377            assert!(!Plus.precedes(Slash));
378            assert!(!Plus.precedes(DoubleSlash));
379            assert!(!Plus.precedes(Percent));
380            assert!(Plus.precedes(Concat));
381            assert!(!Plus.precedes(Caret));
382            assert!(!Plus.precedes_unary_expression());
383        }
384
385        #[test]
386        fn minus() {
387            assert!(Minus.precedes(And));
388            assert!(Minus.precedes(Or));
389            assert!(Minus.precedes(Equal));
390            assert!(Minus.precedes(NotEqual));
391            assert!(Minus.precedes(LowerThan));
392            assert!(Minus.precedes(LowerOrEqualThan));
393            assert!(Minus.precedes(GreaterThan));
394            assert!(Minus.precedes(GreaterOrEqualThan));
395            assert!(!Minus.precedes(Plus));
396            assert!(!Minus.precedes(Minus));
397            assert!(!Minus.precedes(Asterisk));
398            assert!(!Minus.precedes(Slash));
399            assert!(!Minus.precedes(DoubleSlash));
400            assert!(!Minus.precedes(Percent));
401            assert!(Minus.precedes(Concat));
402            assert!(!Minus.precedes(Caret));
403            assert!(!Minus.precedes_unary_expression());
404        }
405
406        #[test]
407        fn concat() {
408            assert!(Concat.precedes(And));
409            assert!(Concat.precedes(Or));
410            assert!(Concat.precedes(Equal));
411            assert!(Concat.precedes(NotEqual));
412            assert!(Concat.precedes(LowerThan));
413            assert!(Concat.precedes(LowerOrEqualThan));
414            assert!(Concat.precedes(GreaterThan));
415            assert!(Concat.precedes(GreaterOrEqualThan));
416            assert!(!Concat.precedes(Plus));
417            assert!(!Concat.precedes(Minus));
418            assert!(!Concat.precedes(Asterisk));
419            assert!(!Concat.precedes(Slash));
420            assert!(!Concat.precedes(DoubleSlash));
421            assert!(!Concat.precedes(Percent));
422            assert!(!Concat.precedes(Concat));
423            assert!(!Concat.precedes(Caret));
424            assert!(!Concat.precedes_unary_expression());
425        }
426
427        #[test]
428        fn and() {
429            assert!(!And.precedes(And));
430            assert!(And.precedes(Or));
431            assert!(!And.precedes(Equal));
432            assert!(!And.precedes(NotEqual));
433            assert!(!And.precedes(LowerThan));
434            assert!(!And.precedes(LowerOrEqualThan));
435            assert!(!And.precedes(GreaterThan));
436            assert!(!And.precedes(GreaterOrEqualThan));
437            assert!(!And.precedes(Plus));
438            assert!(!And.precedes(Minus));
439            assert!(!And.precedes(Asterisk));
440            assert!(!And.precedes(Slash));
441            assert!(!And.precedes(DoubleSlash));
442            assert!(!And.precedes(Percent));
443            assert!(!And.precedes(Concat));
444            assert!(!And.precedes(Caret));
445            assert!(!And.precedes_unary_expression());
446        }
447    }
448}