darklua_core/nodes/expressions/
binary.rs1use 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}