darklua_core/nodes/expressions/
mod.rs

1mod binary;
2mod field;
3mod function;
4mod if_expression;
5mod index;
6mod interpolated_string;
7mod number;
8mod parenthese;
9mod prefix;
10mod string;
11pub(crate) mod string_utils;
12mod table;
13mod type_cast;
14mod unary;
15
16pub use binary::*;
17pub use field::*;
18pub use function::*;
19pub use if_expression::*;
20pub use index::*;
21pub use interpolated_string::*;
22pub use number::*;
23pub use parenthese::*;
24pub use prefix::*;
25pub use string::*;
26pub use string_utils::StringError;
27pub use table::*;
28pub use type_cast::*;
29pub use unary::*;
30
31use crate::nodes::{FunctionCall, Identifier, Token, Variable};
32
33use super::impl_token_fns;
34
35use std::num::FpCategory;
36
37/// Represents all possible expressions.
38#[derive(Clone, Debug, PartialEq, Eq)]
39pub enum Expression {
40    /// A binary operation (e.g., `a + b`, `x == y`)
41    Binary(Box<BinaryExpression>),
42    /// A function call (e.g., `print("Hello")`)
43    Call(Box<FunctionCall>),
44    /// The `false` keyword
45    False(Option<Token>),
46    /// A field access (e.g., `object.field`)
47    Field(Box<FieldExpression>),
48    /// A function definition (e.g., `function(...) ... end`)
49    Function(Box<FunctionExpression>),
50    /// An identifier (e.g., variable name)
51    Identifier(Identifier),
52    /// An if expression (e.g., `if a then b else c`)
53    If(Box<IfExpression>),
54    /// A table index access (e.g., `table[key]`)
55    Index(Box<IndexExpression>),
56    /// The `nil` keyword
57    Nil(Option<Token>),
58    /// A numeric literal (e.g., `42`, `3.14`)
59    Number(NumberExpression),
60    /// An expression in parentheses (e.g., `(1 + 2)`)
61    Parenthese(Box<ParentheseExpression>),
62    /// A string literal (e.g., `"hello"`)
63    String(StringExpression),
64    /// An interpolated string (e.g., `` `Hello ${name}` ``)
65    InterpolatedString(InterpolatedStringExpression),
66    /// A table constructor (e.g., `{key = value, [expr] = value}`)
67    Table(TableExpression),
68    /// The `true` keyword
69    True(Option<Token>),
70    /// A unary operation (e.g., `-x`, `not condition`)
71    Unary(Box<UnaryExpression>),
72    /// The variable arguments symbol (`...`)
73    VariableArguments(Option<Token>),
74    /// A type cast expression (e.g., `value :: Type`)
75    TypeCast(TypeCastExpression),
76}
77
78impl Expression {
79    /// Creates a new nil expression.
80    #[inline]
81    pub fn nil() -> Self {
82        Self::Nil(None)
83    }
84
85    /// Creates a new variable arguments expression.
86    #[inline]
87    pub fn variable_arguments() -> Self {
88        Self::VariableArguments(None)
89    }
90
91    /// Creates a new identifier expression.
92    pub fn identifier<S: Into<Identifier>>(identifier: S) -> Self {
93        Self::Identifier(identifier.into())
94    }
95
96    /// Wraps this expression in parentheses.
97    pub fn in_parentheses(self) -> Self {
98        Self::Parenthese(ParentheseExpression::new(self).into())
99    }
100
101    /// Returns a mutable reference to the last token for this expression,
102    /// creating it if missing.
103    pub fn mutate_last_token(&mut self) -> &mut Token {
104        let mut current = self;
105        loop {
106            match current {
107                Self::Binary(binary) => {
108                    current = binary.mutate_right();
109                }
110                Self::Call(call) => break call.mutate_last_token(),
111                Self::Field(field) => break field.mutate_last_token(),
112                Self::Function(function) => break function.mutate_last_token(),
113                Self::Identifier(identifier) => break identifier.mutate_or_insert_token(),
114                Self::If(if_expr) => {
115                    current = if_expr.mutate_else_result();
116                }
117                Self::Index(index) => break index.mutate_last_token(),
118                Self::Number(number) => break number.mutate_or_insert_token(),
119                Self::String(string) => break string.mutate_or_insert_token(),
120                Self::InterpolatedString(interpolated) => break interpolated.mutate_last_token(),
121                Self::Table(table) => break table.mutate_last_token(),
122                Self::Parenthese(parenthese) => break parenthese.mutate_last_token(),
123                Self::TypeCast(type_cast) => break type_cast.mutate_last_token(),
124                Self::Unary(unary) => {
125                    current = unary.mutate_expression();
126                }
127                Self::True(token) => {
128                    if token.is_none() {
129                        *token = Some(Token::from_content("true"));
130                    }
131                    break token.as_mut().unwrap();
132                }
133                Self::False(token) => {
134                    if token.is_none() {
135                        *token = Some(Token::from_content("false"));
136                    }
137                    break token.as_mut().unwrap();
138                }
139                Self::Nil(token) => {
140                    if token.is_none() {
141                        *token = Some(Token::from_content("nil"));
142                    }
143                    break token.as_mut().unwrap();
144                }
145                Self::VariableArguments(ref mut token) => {
146                    if token.is_none() {
147                        *token = Some(Token::from_content("..."));
148                    }
149                    break token.as_mut().unwrap();
150                }
151            }
152        }
153    }
154}
155
156impl From<bool> for Expression {
157    fn from(boolean: bool) -> Expression {
158        if boolean {
159            Expression::True(None)
160        } else {
161            Expression::False(None)
162        }
163    }
164}
165
166impl From<f64> for Expression {
167    fn from(value: f64) -> Expression {
168        match value.classify() {
169            FpCategory::Nan => BinaryExpression::new(
170                BinaryOperator::Slash,
171                DecimalNumber::new(0.0),
172                DecimalNumber::new(0.0),
173            )
174            .into(),
175            FpCategory::Infinite => BinaryExpression::new(
176                BinaryOperator::Slash,
177                Expression::from(if value.is_sign_positive() { 1.0 } else { -1.0 }),
178                DecimalNumber::new(0.0),
179            )
180            .into(),
181            FpCategory::Zero => {
182                DecimalNumber::new(if value.is_sign_positive() { 0.0 } else { -0.0 }).into()
183            }
184            FpCategory::Subnormal | FpCategory::Normal => {
185                if value < 0.0 {
186                    UnaryExpression::new(UnaryOperator::Minus, Expression::from(value.abs())).into()
187                } else if value < 0.1 {
188                    let exponent = value.log10().floor();
189
190                    DecimalNumber::new(value)
191                        .with_exponent(exponent as i64, true)
192                        .into()
193                } else if value > 999.0 && (value / 100.0).fract() == 0.0 {
194                    let mut exponent = value.log10().floor();
195                    let mut power = 10_f64.powf(exponent);
196
197                    while exponent > 2.0 && (value / power).fract() != 0.0 {
198                        exponent -= 1.0;
199                        power /= 10.0;
200                    }
201
202                    DecimalNumber::new(value)
203                        .with_exponent(exponent as i64, true)
204                        .into()
205                } else {
206                    DecimalNumber::new(value).into()
207                }
208            }
209        }
210    }
211}
212
213impl From<f32> for Expression {
214    fn from(value: f32) -> Self {
215        (value as f64).into()
216    }
217}
218
219impl From<usize> for Expression {
220    fn from(value: usize) -> Self {
221        (value as f64).into()
222    }
223}
224
225impl From<u64> for Expression {
226    fn from(value: u64) -> Self {
227        (value as f64).into()
228    }
229}
230
231impl From<u32> for Expression {
232    fn from(value: u32) -> Self {
233        (value as f64).into()
234    }
235}
236
237impl From<u16> for Expression {
238    fn from(value: u16) -> Self {
239        (value as f64).into()
240    }
241}
242
243impl From<u8> for Expression {
244    fn from(value: u8) -> Self {
245        (value as f64).into()
246    }
247}
248
249impl From<i64> for Expression {
250    fn from(value: i64) -> Self {
251        (value as f64).into()
252    }
253}
254
255impl From<i32> for Expression {
256    fn from(value: i32) -> Self {
257        (value as f64).into()
258    }
259}
260
261impl From<i16> for Expression {
262    fn from(value: i16) -> Self {
263        (value as f64).into()
264    }
265}
266
267impl From<i8> for Expression {
268    fn from(value: i8) -> Self {
269        (value as f64).into()
270    }
271}
272
273impl From<BinaryExpression> for Expression {
274    fn from(binary: BinaryExpression) -> Expression {
275        Expression::Binary(Box::new(binary))
276    }
277}
278
279impl From<FunctionCall> for Expression {
280    fn from(call: FunctionCall) -> Expression {
281        Expression::Call(Box::new(call))
282    }
283}
284
285impl From<FieldExpression> for Expression {
286    fn from(field: FieldExpression) -> Expression {
287        Expression::Field(Box::new(field))
288    }
289}
290
291impl From<FunctionExpression> for Expression {
292    fn from(function: FunctionExpression) -> Self {
293        Expression::Function(Box::new(function))
294    }
295}
296
297impl From<Identifier> for Expression {
298    fn from(identifier: Identifier) -> Self {
299        Expression::Identifier(identifier)
300    }
301}
302
303impl From<IfExpression> for Expression {
304    fn from(if_expression: IfExpression) -> Expression {
305        Expression::If(Box::new(if_expression))
306    }
307}
308
309impl From<IndexExpression> for Expression {
310    fn from(index: IndexExpression) -> Self {
311        Self::Index(Box::new(index))
312    }
313}
314
315impl From<NumberExpression> for Expression {
316    fn from(number: NumberExpression) -> Self {
317        Self::Number(number)
318    }
319}
320
321impl From<DecimalNumber> for Expression {
322    fn from(number: DecimalNumber) -> Self {
323        Self::Number(NumberExpression::Decimal(number))
324    }
325}
326
327impl From<HexNumber> for Expression {
328    fn from(number: HexNumber) -> Self {
329        Self::Number(NumberExpression::Hex(number))
330    }
331}
332
333impl From<BinaryNumber> for Expression {
334    fn from(number: BinaryNumber) -> Self {
335        Self::Number(NumberExpression::Binary(number))
336    }
337}
338
339impl From<Prefix> for Expression {
340    fn from(prefix: Prefix) -> Self {
341        match prefix {
342            Prefix::Call(call) => Self::Call(call),
343            Prefix::Field(field) => Self::Field(field),
344            Prefix::Identifier(name) => Self::Identifier(name),
345            Prefix::Index(index) => Self::Index(index),
346            Prefix::Parenthese(expression) => (*expression).into(),
347        }
348    }
349}
350
351impl From<ParentheseExpression> for Expression {
352    fn from(expression: ParentheseExpression) -> Self {
353        Self::Parenthese(expression.into())
354    }
355}
356
357impl From<StringExpression> for Expression {
358    fn from(string: StringExpression) -> Self {
359        Self::String(string)
360    }
361}
362
363impl From<InterpolatedStringExpression> for Expression {
364    fn from(interpolated_string: InterpolatedStringExpression) -> Self {
365        Self::InterpolatedString(interpolated_string)
366    }
367}
368
369impl From<TableExpression> for Expression {
370    fn from(table: TableExpression) -> Self {
371        Self::Table(table)
372    }
373}
374
375impl From<UnaryExpression> for Expression {
376    fn from(unary: UnaryExpression) -> Self {
377        Self::Unary(Box::new(unary))
378    }
379}
380
381impl From<TypeCastExpression> for Expression {
382    fn from(type_cast: TypeCastExpression) -> Self {
383        Self::TypeCast(type_cast)
384    }
385}
386
387impl From<Variable> for Expression {
388    fn from(variable: Variable) -> Self {
389        match variable {
390            Variable::Identifier(identifier) => Self::Identifier(identifier),
391            Variable::Field(field) => Self::Field(field),
392            Variable::Index(index) => Self::Index(index),
393        }
394    }
395}
396
397impl<T: Into<Expression>> From<Option<T>> for Expression {
398    fn from(value: Option<T>) -> Self {
399        match value {
400            None => Self::nil(),
401            Some(value) => value.into(),
402        }
403    }
404}
405
406#[cfg(test)]
407mod test {
408    macro_rules! snapshot_from_expression {
409        ($($name:ident => $input:expr),+ $(,)?) => {
410            $(
411                #[test]
412                fn $name() {
413                    let result = crate::nodes::Expression::from($input);
414
415                    insta::assert_debug_snapshot!(stringify!($name), result);
416                }
417            )+
418        };
419    }
420
421    mod expression_from_floats {
422        snapshot_from_expression!(
423            f64_0 => 0_f64,
424            f64_1e42 => 1e42_f64,
425            f64_1_2345e50 => 1.2345e50_f64,
426            f64_infinity => f64::INFINITY,
427            i64_minus_one => -1_i64,
428            f64_minus_zero => -0.0,
429            f32_0_5 => 0.5_f32,
430            f32_infinity => f32::INFINITY,
431            f32_nan => f32::NAN,
432            f64_nan => f64::NAN,
433        );
434    }
435
436    mod expression_from_integers {
437        snapshot_from_expression!(
438            u8_max => u8::MAX,
439            u16_max => u16::MAX,
440            u32_max => u32::MAX,
441            u64_max => u64::MAX,
442            i8_max => i8::MIN,
443            i16_max => i16::MIN,
444            i32_max => i32::MIN,
445            i64_max => i64::MIN,
446        );
447    }
448}