Skip to main content

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