blanket_script/parser/
expression.rs

1use nom::{
2    branch::alt,
3    bytes::complete::tag,
4    character::complete::{none_of, one_of},
5    combinator::{cut, map, opt},
6    multi::{count, many0, many1, many_m_n},
7    sequence::{delimited, pair, preceded, terminated},
8    IResult, Parser,
9};
10use std::fmt;
11
12use super::{ws0, ParseResult, SyntaxError, SyntaxErrorKind};
13
14#[derive(Debug, Eq, PartialEq, Clone)]
15pub enum Expression {
16    Number(String),
17    BigInt(String),
18    String(StringLiteral),
19    Identifier(String),
20    UnaryOperation {
21        operator: UnaryOperator,
22        operand: Box<Expression>,
23    },
24    BinaryOperation {
25        operator: BinaryOperator,
26        left: Box<Expression>,
27        right: Box<Expression>,
28    },
29}
30
31impl fmt::Display for Expression {
32    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33        match self {
34            Self::Number(number) => write!(f, "{}", number),
35            Self::BigInt(bigint) => write!(f, "{}n", bigint),
36            Self::String(string) => write!(f, "\"{}\"", string.value),
37            Self::Identifier(name) => write!(f, "{}", name),
38            Self::UnaryOperation { operator, operand } => match operator {
39                UnaryOperator::Try => write!(f, "({}?)", operand),
40                _ => write!(f, "({}{})", operator, operand),
41            },
42            Self::BinaryOperation {
43                operator,
44                left,
45                right,
46            } => write!(f, "({} {} {})", left, operator, right),
47        }
48    }
49}
50
51/// String literals can contain interpolations, which are expressions that are
52/// evaluated and inserted into the string at the location of the interpolation.
53/// For example, the string `"Hello, {name}!"` contains a single interpolation
54/// at index 7.
55#[derive(Debug, Eq, PartialEq, Clone)]
56pub struct StringLiteral {
57    /// The string value with interpolations removed.
58    pub value: String,
59    /// The list of interpolations and their indices in the string.
60    pub interpolations: Vec<(usize, Box<Expression>)>,
61}
62
63#[derive(Debug, PartialEq, Clone)]
64enum StringPart {
65    Literal(String),
66    Interpolation(Box<Expression>),
67}
68
69#[derive(Debug, Eq, PartialEq, Clone, Copy)]
70pub enum UnaryOperator {
71    Negate,
72    LogicalNot,
73    BitwiseNot,
74    UnaryPlus,
75    UnaryMinus,
76    Try,
77}
78
79impl fmt::Display for UnaryOperator {
80    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81        match self {
82            Self::Negate => write!(f, "!"),
83            Self::LogicalNot => write!(f, "!"),
84            Self::BitwiseNot => write!(f, "~"),
85            Self::UnaryPlus => write!(f, "+"),
86            Self::UnaryMinus => write!(f, "-"),
87            Self::Try => write!(f, "?"),
88        }
89    }
90}
91
92impl std::str::FromStr for UnaryOperator {
93    type Err = ();
94
95    fn from_str(s: &str) -> Result<Self, Self::Err> {
96        match s {
97            "!" => Ok(Self::Negate),
98            "~" => Ok(Self::BitwiseNot),
99            "+" => Ok(Self::UnaryPlus),
100            "-" => Ok(Self::UnaryMinus),
101            "?" => Ok(Self::Try),
102            _ => Err(()),
103        }
104    }
105}
106
107#[derive(Debug, Eq, PartialEq, Clone, Copy)]
108pub enum Associativity {
109    LeftToRight,
110    RightToLeft,
111}
112
113#[derive(Debug, Eq, PartialEq, Clone, Copy)]
114pub enum BinaryOperator {
115    /// Exponentiation operator `**`
116    Exponent,
117    /// Multiplication operator `*`
118    Multiply,
119    /// Division operator `/`
120    Divide,
121    /// Modulus operator `%`
122    Modulo,
123    /// Add operator `+`
124    Add,
125    /// Subtract operator `-`
126    Subtract,
127    /// Left shift operator `<<`
128    LeftShift,
129    /// Right shift operator `>>`
130    RightShift,
131    /// Less than operator `<`
132    LessThan,
133    /// Less than or equal operator `<=`
134    LessThanOrEqual,
135    /// Greater than operator `>`
136    GreaterThan,
137    /// Greater than or equal operator `>=`
138    GreaterThanOrEqual,
139    /// Equality operator `==`
140    Equal,
141    /// Not equal operator `!=`
142    NotEqual,
143    /// Bitwise AND operator `&`
144    BitwiseAnd,
145    /// Bitwise XOR operator `^`
146    BitwiseXor,
147    /// Bitwise OR operator `|`
148    BitwiseOr,
149    /// Logical AND operator `&&`
150    LogicalAnd,
151    /// Logical OR operator `||`
152    LogicalOr,
153    /// Pipe operator `|>`
154    Pipe,
155}
156
157impl BinaryOperator {
158    pub fn precedence(&self) -> u8 {
159        match self {
160            Self::Exponent => 13,
161            Self::Multiply | Self::Divide | Self::Modulo => 12,
162            Self::Add | Self::Subtract => 11,
163            Self::LeftShift | Self::RightShift => 10,
164            Self::LessThan
165            | Self::LessThanOrEqual
166            | Self::GreaterThan
167            | Self::GreaterThanOrEqual => 9,
168            Self::Equal | Self::NotEqual => 8,
169            Self::BitwiseAnd => 7,
170            Self::BitwiseXor => 6,
171            Self::BitwiseOr => 5,
172            Self::LogicalAnd => 4,
173            Self::LogicalOr => 3,
174            Self::Pipe => 2,
175        }
176    }
177
178    pub fn associativity(&self) -> Associativity {
179        match self {
180            Self::Exponent => Associativity::RightToLeft,
181            Self::Multiply
182            | Self::Divide
183            | Self::Modulo
184            | Self::Add
185            | Self::Subtract
186            | Self::LeftShift
187            | Self::RightShift
188            | Self::LessThan
189            | Self::LessThanOrEqual
190            | Self::GreaterThan
191            | Self::GreaterThanOrEqual
192            | Self::Equal
193            | Self::NotEqual
194            | Self::BitwiseAnd
195            | Self::BitwiseXor
196            | Self::BitwiseOr
197            | Self::LogicalAnd
198            | Self::LogicalOr
199            | Self::Pipe => Associativity::LeftToRight,
200        }
201    }
202}
203
204impl std::str::FromStr for BinaryOperator {
205    type Err = ();
206
207    fn from_str(s: &str) -> Result<Self, Self::Err> {
208        match s {
209            "**" => Ok(Self::Exponent),
210            "*" => Ok(Self::Multiply),
211            "/" => Ok(Self::Divide),
212            "%" => Ok(Self::Modulo),
213            "+" => Ok(Self::Add),
214            "-" => Ok(Self::Subtract),
215            "<<" => Ok(Self::LeftShift),
216            ">>" => Ok(Self::RightShift),
217            "<" => Ok(Self::LessThan),
218            "<=" => Ok(Self::LessThanOrEqual),
219            ">" => Ok(Self::GreaterThan),
220            ">=" => Ok(Self::GreaterThanOrEqual),
221            "==" => Ok(Self::Equal),
222            "!=" => Ok(Self::NotEqual),
223            "&" => Ok(Self::BitwiseAnd),
224            "^" => Ok(Self::BitwiseXor),
225            "|" => Ok(Self::BitwiseOr),
226            "&&" => Ok(Self::LogicalAnd),
227            "||" => Ok(Self::LogicalOr),
228            "|>" => Ok(Self::Pipe),
229            _ => Err(()),
230        }
231    }
232}
233
234impl fmt::Display for BinaryOperator {
235    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236        match self {
237            Self::Exponent => write!(f, "**"),
238            Self::Multiply => write!(f, "*"),
239            Self::Divide => write!(f, "/"),
240            Self::Modulo => write!(f, "%"),
241            Self::Add => write!(f, "+"),
242            Self::Subtract => write!(f, "-"),
243            Self::LeftShift => write!(f, "<<"),
244            Self::RightShift => write!(f, ">>"),
245            Self::LessThan => write!(f, "<"),
246            Self::LessThanOrEqual => write!(f, "<="),
247            Self::GreaterThan => write!(f, ">"),
248            Self::GreaterThanOrEqual => write!(f, ">="),
249            Self::Equal => write!(f, "=="),
250            Self::NotEqual => write!(f, "!="),
251            Self::BitwiseAnd => write!(f, "&"),
252            Self::BitwiseXor => write!(f, "^"),
253            Self::BitwiseOr => write!(f, "|"),
254            Self::LogicalAnd => write!(f, "&&"),
255            Self::LogicalOr => write!(f, "||"),
256            Self::Pipe => write!(f, "|>"),
257        }
258    }
259}
260
261fn non_zero_digit(input: &str) -> ParseResult<char> {
262    one_of("123456789")(input)
263}
264
265fn digit(input: &str) -> ParseResult<char> {
266    one_of("0123456789")(input)
267}
268
269fn hex_digit(input: &str) -> ParseResult<char> {
270    let result: IResult<&str, char> = one_of("0123456789abcdefABCDEF").parse(input);
271    match result {
272        Ok((input, c)) => Ok((input, c)),
273        Err(_) => Err(nom::Err::Error(SyntaxError {
274            input,
275            error: SyntaxErrorKind::InvalidHexDigit,
276        })),
277    }
278}
279
280fn delimited_digit(input: &str) -> ParseResult<char> {
281    if input.starts_with("__") {
282        return Err(nom::Err::Failure(SyntaxError {
283            input,
284            error: SyntaxErrorKind::ConsecutiveUnderscoreInNumericLiteral,
285        }));
286    }
287    alt((digit, preceded(tag("_"), digit))).parse(input)
288}
289
290fn whole_number(input: &str) -> ParseResult<String> {
291    if input.starts_with('_') {
292        return Err(nom::Err::Failure(SyntaxError {
293            input,
294            error: SyntaxErrorKind::NumericLiteralStartsWithUnderscore,
295        }));
296    } else if input.is_empty() {
297        return Err(nom::Err::Failure(SyntaxError {
298            input,
299            error: SyntaxErrorKind::EmptyInput,
300        }));
301    }
302    // Must start with a non-zero digit
303    let (input, start) = non_zero_digit(input)?;
304    // Followed by zero or more digits
305    // Underscores are allowed between digits but not at the start or end
306    let (input, digits) = many0(delimited_digit).parse(input)?;
307    // Concatenate the digits into a single string
308    let number = std::iter::once(start).chain(digits).collect::<String>();
309    Ok((input, number))
310}
311
312fn decimal_number(input: &str) -> ParseResult<String> {
313    let (input, mut number) = whole_number(input)?;
314    // Optionally followed by a decimal point and fractional part
315    let (input, decimal) = opt(preceded(tag("."), many1(delimited_digit))).parse(input)?;
316    if input.starts_with('_') {
317        return Err(nom::Err::Failure(SyntaxError {
318            input,
319            error: SyntaxErrorKind::NumericLiteralEndsWithUnderscore,
320        }));
321    }
322    // Add the decimal point and fractional part if present
323    if let Some(decimal) = decimal {
324        number.extend(std::iter::once('.').chain(decimal));
325    }
326    Ok((input, number))
327}
328
329fn scientific_notation(input: &str) -> ParseResult<String> {
330    let (input, mut number) = decimal_number(input)?;
331    let (input, sign) = preceded(alt((tag("e"), tag("E"))), opt(one_of("+-"))).parse(input)?;
332    let (input, exponent) = many1(delimited_digit).parse(input)?;
333    if input.starts_with('_') {
334        return Err(nom::Err::Failure(SyntaxError {
335            input,
336            error: SyntaxErrorKind::NumericLiteralEndsWithUnderscore,
337        }));
338    }
339    match sign {
340        Some('-') => number.push_str("e-"),
341        Some('+') => number.push('e'),
342        None => number.push('e'),
343        _ => unreachable!(),
344    };
345    number.extend(exponent);
346
347    Ok((input, number))
348}
349
350fn parse_number(input: &str) -> ParseResult<Expression> {
351    map(alt((scientific_notation, decimal_number)), |number| {
352        Expression::Number(number)
353    })
354    .parse(input)
355}
356
357fn parse_bigint(input: &str) -> ParseResult<Expression> {
358    if input.starts_with('n') {
359        return Err(nom::Err::Failure(SyntaxError {
360            input,
361            error: SyntaxErrorKind::EmptyBigIntLiteral,
362        }));
363    }
364    map(
365        terminated(alt((scientific_notation, whole_number)), tag("n")),
366        Expression::BigInt,
367    )
368    .parse(input)
369}
370
371fn parse_escaped_char(input: &str) -> ParseResult<char> {
372    let (input, result) = alt((
373        tag("\\\\"), // Double backslash
374        tag("\\\""), // Double quote
375        tag("\\n"),  // Newline
376        tag("\\r"),  // Carriage return
377        tag("\\t"),  // Tab
378        tag("\\0"),  // Null character
379        tag("{{"),   // Open curly brace
380        tag("}}"),   // Close curly brace
381    ))
382    .parse(input)?;
383    match result {
384        "\\\\" => Ok((input, '\\')),
385        "\\\"" => Ok((input, '"')),
386        "\\n" => Ok((input, '\n')),
387        "\\r" => Ok((input, '\r')),
388        "\\t" => Ok((input, '\t')),
389        "\\0" => Ok((input, '\0')),
390        "{{" => Ok((input, '{')),
391        "}}" => Ok((input, '}')),
392        _ => unreachable!(),
393    }
394}
395
396/// Parses a Unicode code point escape sequence which can be either `\xHHHH` or `\u{HHHH}`.
397/// The code point is converted to a `char` if it is valid or `SyntaxErrorKind::InvalidUnicodeCodePoint`
398/// is returned if the code point is not a valid Unicode code point.
399///
400/// ## Grammar
401///
402/// ```text
403/// EscapedCodePoint ::=
404///     | '\u' '{' HexDigit{2,6} '}'
405///     | '\x' HexDigit HexDigit
406/// ```
407fn parse_escaped_code_point(input: &str) -> ParseResult<char> {
408    let (input, value) = alt((
409        preceded(
410            tag("\\u"),
411            cut(delimited(tag("{"), many_m_n(2, 6, hex_digit), tag("}"))),
412        ),
413        preceded(tag("\\x"), cut(count(hex_digit, 2))),
414    ))
415    .parse(input)?;
416    let value = value.iter().collect::<String>();
417    let code_point = u32::from_str_radix(&value, 16).unwrap();
418    match std::char::from_u32(code_point) {
419        Some(c) => Ok((input, c)),
420        None => Err(nom::Err::Failure(SyntaxError {
421            input,
422            error: SyntaxErrorKind::InvalidUnicodeCodePoint(code_point),
423        })),
424    }
425}
426
427fn parse_regular_char(input: &str) -> ParseResult<char> {
428    none_of("\\\"{}").parse(input)
429}
430
431fn parse_interpolation(input: &str) -> ParseResult<StringPart> {
432    map(
433        delimited(tag("{"), alt((parse_number, parse_bigint)), tag("}")),
434        |inter| StringPart::Interpolation(inter.into()),
435    )
436    .parse(input)
437}
438
439fn parse_string(input: &str) -> ParseResult<Expression> {
440    let (input, parsed) = delimited(
441        tag("\""),
442        many0(alt((
443            map(
444                many1(alt((
445                    parse_regular_char,
446                    parse_escaped_char,
447                    parse_escaped_code_point,
448                ))),
449                |f| StringPart::Literal(f.iter().collect()),
450            ),
451            parse_interpolation,
452        ))),
453        tag("\""),
454    )
455    .parse(input)?;
456    let mut string = StringLiteral {
457        value: String::new(),
458        interpolations: vec![],
459    };
460    for part in parsed {
461        match part {
462            StringPart::Literal(literal) => string.value.push_str(&literal),
463            StringPart::Interpolation(interpolation) => {
464                string
465                    .interpolations
466                    .push((string.value.len(), interpolation));
467            }
468        }
469    }
470    Ok((input, Expression::String(string)))
471}
472
473const ALPHA_WITH_UNDERSCORE: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
474const ALPHANUMERIC_WITH_UNDERSCORE: &str =
475    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789";
476
477pub(crate) fn parse_identifier(input: &str) -> ParseResult<String> {
478    map(
479        pair(
480            one_of(ALPHA_WITH_UNDERSCORE),
481            many0(one_of(ALPHANUMERIC_WITH_UNDERSCORE)),
482        ),
483        |(first, rest)| std::iter::once(first).chain(rest).collect(),
484    )
485    .parse(input)
486}
487
488pub(crate) fn parse_binary_operator(input: &str) -> ParseResult<BinaryOperator> {
489    map(
490        ws0(alt((
491            tag("|>"),
492            tag("**"),
493            tag("*"),
494            tag("/"),
495            tag("%"),
496            tag("+"),
497            tag("-"),
498            tag("<<"),
499            tag(">>"),
500            tag("<="),
501            tag("<"),
502            tag(">="),
503            tag(">"),
504            tag("=="),
505            tag("!="),
506            tag("&&"),
507            tag("||"),
508            tag("&"),
509            tag("^"),
510            tag("|"),
511        ))),
512        |op| op.parse().unwrap(),
513    )
514    .parse(input)
515}
516
517pub(crate) fn parse_unary_operator(input: &str) -> ParseResult<UnaryOperator> {
518    map(ws0(alt((tag("!"), tag("~"), tag("+"), tag("-")))), |op| {
519        op.parse().unwrap()
520    })
521    .parse(input)
522}
523
524pub(crate) fn parse_term(input: &str) -> ParseResult<Expression> {
525    map(
526        (
527            opt(parse_unary_operator),
528            alt((
529                map(parse_identifier, Expression::Identifier),
530                parse_string,
531                parse_bigint,
532                parse_number,
533            )),
534            opt(tag("?")),
535        ),
536        |(prefix, expr, postfix)| {
537            let mut expression = expr;
538            if postfix.is_some() {
539                expression = Expression::UnaryOperation {
540                    operator: UnaryOperator::Try,
541                    operand: Box::new(expression),
542                };
543            }
544            if let Some(op) = prefix {
545                expression = Expression::UnaryOperation {
546                    operator: op,
547                    operand: Box::new(expression),
548                };
549            }
550            expression
551        },
552    )
553    .parse(input)
554}
555
556/// Shunting-yard algorithm to parse an expression with binary operators.
557/// The algorithm uses two stacks: one for the output and one for operators.
558/// The output stack is used to store the operands and intermediate results
559/// while the operator stack is used to store the operators.
560///
561/// The algorithm works as follows:
562/// 1. Parse the left-hand side of the expression as a term.
563/// 2. While there are more tokens to read, (`opt` is used to handle the case)
564///     1. Read the next operator and right-hand side term.
565///     2. While there is an operator at the top of the operator stack with
566///        higher precedence or the same precedence with left-to-right
567///        associativity, pop the operator and apply it to the top two elements
568///        on the output stack.
569///     3. Push the operator onto the operator stack.
570///     4. Push the right-hand side term onto the output stack.
571/// 3. While there are operators on the operator stack, pop the operator and
572///    apply it to the top two elements on the output stack.
573/// 4. The final result is the last element on the output stack.
574/// 5. Return the result.
575pub(crate) fn parse_expression(input: &str) -> ParseResult<Expression> {
576    let (input, left) = parse_term(input)?;
577    let mut output: Vec<Expression> = vec![left];
578    let mut operators = Vec::<BinaryOperator>::new();
579    let mut remaining = input;
580    loop {
581        let (input, opt_right) =
582            opt(pair(ws0(parse_binary_operator), ws0(parse_term))).parse(remaining)?;
583        remaining = input;
584        let (op, right) = match opt_right {
585            // Found an operator and a right-hand side term
586            Some((op, right)) => (op, right),
587            // No more operators, so we're done
588            None => break,
589        };
590        while let Some(&top) = operators.last() {
591            // If the operator at the top of the stack has higher precedence
592            // or the same precedence with left-to-right associativity, pop
593            // the operator and apply it to the top two elements on the output
594            // stack.
595            if top.precedence() > op.precedence()
596                || (top.precedence() == op.precedence()
597                    && op.associativity() == Associativity::LeftToRight)
598            {
599                let right = output.pop().unwrap();
600                let left = output.pop().unwrap();
601                output.push(Expression::BinaryOperation {
602                    operator: operators.pop().unwrap(),
603                    left: Box::new(left),
604                    right: Box::new(right),
605                });
606            } else {
607                break;
608            }
609        }
610        output.push(right);
611        operators.push(op);
612    }
613    while let Some(op) = operators.pop() {
614        let right = output.pop().unwrap();
615        let left = output.pop().unwrap();
616        output.push(Expression::BinaryOperation {
617            operator: op,
618            left: Box::new(left),
619            right: Box::new(right),
620        });
621    }
622    Ok((remaining, output.pop().unwrap()))
623}
624
625#[cfg(test)]
626mod tests {
627    use super::*;
628
629    macro_rules! test_expression {
630        ($name:ident, $input:expr, $expected:expr) => {
631            #[test]
632            fn $name() {
633                let (rest, result) = parse_expression($input).unwrap();
634                assert_eq!(rest, "");
635                assert_eq!(result, $expected);
636            }
637        };
638    }
639
640    macro_rules! test_error_kind {
641        ($parser:ident, $name:ident, $input:expr, $kind:pat) => {
642            #[test]
643            fn $name() {
644                let result = $parser($input);
645                assert!(result.is_err());
646                let err = result.unwrap_err();
647                match err {
648                    nom::Err::Failure(SyntaxError { error, .. }) => assert!(matches!(error, $kind)),
649                    _ => panic!("Unexpected error: {:?}", err),
650                }
651            }
652        };
653        ($name:ident, $input:expr, $kind:pat) => {
654            test_error_kind!(parse_expression, $name, $input, $kind);
655        };
656    }
657
658    test_expression!(number_simple, "42", Expression::Number("42".into()));
659    test_expression!(number_pi, "3.14159", Expression::Number("3.14159".into()));
660    test_expression!(
661        number_pi_underscore,
662        "3.141_59",
663        Expression::Number("3.14159".into())
664    );
665    test_expression!(
666        number_billion,
667        "1000000000",
668        Expression::Number("1000000000".into())
669    );
670    test_expression!(
671        number_billion_with_underline,
672        "1_000_000_000",
673        Expression::Number("1000000000".into())
674    );
675    test_error_kind!(parse_number, number_empty, "", SyntaxErrorKind::EmptyInput);
676    test_error_kind!(
677        parse_number,
678        number_underscore_at_start,
679        "_42",
680        SyntaxErrorKind::NumericLiteralStartsWithUnderscore
681    );
682    test_error_kind!(
683        parse_number,
684        number_underscore_at_end,
685        "42_",
686        SyntaxErrorKind::NumericLiteralEndsWithUnderscore
687    );
688    test_error_kind!(
689        parse_number,
690        number_decimal_underscore_at_end,
691        "42.0_",
692        SyntaxErrorKind::NumericLiteralEndsWithUnderscore
693    );
694    test_error_kind!(
695        parse_number,
696        number_exponent_underscore_at_end,
697        "42e10_",
698        SyntaxErrorKind::NumericLiteralEndsWithUnderscore
699    );
700    test_error_kind!(
701        parse_number,
702        number_consecutive_underscores,
703        "1__000",
704        SyntaxErrorKind::ConsecutiveUnderscoreInNumericLiteral
705    );
706    test_expression!(
707        number_scientific_notation,
708        "1e6",
709        Expression::Number("1e6".into())
710    );
711    test_expression!(
712        number_scientific_notation_uppercase,
713        "1E6",
714        Expression::Number("1e6".into())
715    );
716    test_expression!(
717        number_scientific_notation_positive,
718        "1e+6",
719        Expression::Number("1e6".into())
720    );
721    test_expression!(
722        number_scientific_notation_negative,
723        "1e-6",
724        Expression::Number("1e-6".into())
725    );
726    test_expression!(
727        number_scientific_notation_decimal,
728        "1.23e4",
729        Expression::Number("1.23e4".into())
730    );
731    test_expression!(
732        number_scientific_notation_decimal_positive,
733        "1.23e+4",
734        Expression::Number("1.23e4".into())
735    );
736    test_expression!(
737        number_scientific_notation_decimal_negative,
738        "1.23e-4",
739        Expression::Number("1.23e-4".into())
740    );
741
742    test_expression!(bigint_simple, "42n", Expression::BigInt("42".into()));
743    test_expression!(
744        bigint_billion,
745        "1000000000n",
746        Expression::BigInt("1000000000".into())
747    );
748    test_expression!(
749        bigint_billion_with_underline,
750        "1_000_000_000n",
751        Expression::BigInt("1000000000".into())
752    );
753    test_expression!(
754        bigint_scientific_notation,
755        "1e6n",
756        Expression::BigInt("1e6".into())
757    );
758    test_expression!(
759        bigint_scientific_notation_uppercase,
760        "1E6n",
761        Expression::BigInt("1e6".into())
762    );
763    test_expression!(
764        bigint_scientific_notation_positive,
765        "1e+6n",
766        Expression::BigInt("1e6".into())
767    );
768    test_expression!(
769        bigint_scientific_notation_negative,
770        "100e-2n",
771        Expression::BigInt("100e-2".into())
772    );
773    test_expression!(
774        bigint_scientific_notation_decimal,
775        "1.23e4n",
776        Expression::BigInt("1.23e4".into())
777    );
778    test_error_kind!(
779        parse_bigint,
780        bigint_empty,
781        "n",
782        SyntaxErrorKind::EmptyBigIntLiteral
783    );
784    test_error_kind!(
785        parse_bigint,
786        bigint_underscore_at_end,
787        "42_n",
788        SyntaxErrorKind::NumericLiteralEndsWithUnderscore
789    );
790    test_error_kind!(
791        parse_bigint,
792        bigint_consecutive_underscores,
793        "1__000n",
794        SyntaxErrorKind::ConsecutiveUnderscoreInNumericLiteral
795    );
796
797    test_expression!(
798        string_empty,
799        r#""""#,
800        Expression::String(StringLiteral {
801            value: "".into(),
802            interpolations: vec![]
803        })
804    );
805    test_expression!(
806        string_simple,
807        r#""Hello, World!""#,
808        Expression::String(StringLiteral {
809            value: "Hello, World!".into(),
810            interpolations: vec![]
811        })
812    );
813    test_expression!(
814        string_escaped_chars,
815        r#""\\\"\n\r\t{{}}""#,
816        Expression::String(StringLiteral {
817            value: "\\\"\n\r\t{}".into(),
818            interpolations: vec![]
819        })
820    );
821    test_expression!(
822        string_unicode_code,
823        r#""\x41\u{41}\u{0041}\u{000041}""#,
824        Expression::String(StringLiteral {
825            value: "AAAA".into(),
826            interpolations: vec![]
827        })
828    );
829    test_expression!(
830        string_unicode_code_emoji,
831        r#""\u{2603}\u{1F600}""#,
832        Expression::String(StringLiteral {
833            value: "☃😀".into(),
834            interpolations: vec![]
835        })
836    );
837    test_error_kind!(
838        string_invalid_unicode_code_point,
839        r#""\u{110000}""#,
840        SyntaxErrorKind::InvalidUnicodeCodePoint(0x110000)
841    );
842    test_error_kind!(
843        string_missing_unicode_code_point_opening_brace,
844        r#""\u41}""#,
845        SyntaxErrorKind::NomError(nom::error::ErrorKind::Tag)
846    );
847    test_error_kind!(
848        string_missing_unicode_code_point_closing_brace,
849        r#""\u{41""#,
850        SyntaxErrorKind::NomError(nom::error::ErrorKind::Tag)
851    );
852    test_error_kind!(
853        string_invalid_hex_digit,
854        r#""\xGG""#,
855        SyntaxErrorKind::InvalidHexDigit
856    );
857    test_error_kind!(
858        string_invalid_unicode_code_point_hex,
859        r#""\u{GG}""#,
860        SyntaxErrorKind::InvalidHexDigit
861    );
862    test_expression!(
863        string_interpolation,
864        r#""{42}""#,
865        Expression::String(StringLiteral {
866            value: "".into(),
867            interpolations: vec![(0, Box::new(Expression::Number("42".into())))]
868        })
869    );
870    test_expression!(
871        string_interpolation_with_text,
872        r#""Hello, {42}!""#,
873        Expression::String(StringLiteral {
874            value: "Hello, !".into(),
875            interpolations: vec![(7, Box::new(Expression::Number("42".into())))]
876        })
877    );
878    test_expression!(
879        string_newline,
880        r#""
881""#,
882        Expression::String(StringLiteral {
883            value: "\n".into(),
884            interpolations: vec![]
885        })
886    );
887    test_expression!(
888        identifier_simple,
889        "foo",
890        Expression::Identifier("foo".into())
891    );
892    test_expression!(
893        identifier_with_underscore,
894        "_foo",
895        Expression::Identifier("_foo".into())
896    );
897    test_expression!(
898        identifier_with_numbers,
899        "foo123",
900        Expression::Identifier("foo123".into())
901    );
902    test_expression!(
903        identifier_with_underscore_and_numbers,
904        "_foo_123",
905        Expression::Identifier("_foo_123".into())
906    );
907    test_expression!(
908        identifier_all_uppercase,
909        "FOO",
910        Expression::Identifier("FOO".into())
911    );
912    test_expression!(
913        identifier_mixed_case,
914        "FooBar",
915        Expression::Identifier("FooBar".into())
916    );
917    test_expression!(
918        identifier_single_character,
919        "f",
920        Expression::Identifier("f".into())
921    );
922    test_expression!(
923        identifier_with_multiple_underscores,
924        "foo_bar_baz",
925        Expression::Identifier("foo_bar_baz".into())
926    );
927    test_expression!(
928        identifier_with_leading_underscore_and_numbers,
929        "_123foo",
930        Expression::Identifier("_123foo".into())
931    );
932    test_expression!(
933        identifier_underscore_number,
934        "_42",
935        Expression::Identifier("_42".into())
936    );
937    test_expression!(
938        bigint_underscore_number_n,
939        "_42n",
940        Expression::Identifier("_42n".into())
941    );
942
943    macro_rules! test_binary_expression {
944        ($input:expr, $expected:expr) => {
945            let (input, result) = parse_expression($input).unwrap();
946            assert_eq!(input, "");
947            assert_eq!(dbg!(result).to_string(), $expected);
948        };
949    }
950
951    #[test]
952    fn test_binary_expression() {
953        test_binary_expression!("1 + 2 * 3", "(1 + (2 * 3))");
954        test_binary_expression!("2 * 3 + 4", "((2 * 3) + 4)");
955        test_binary_expression!("2 ** 3 * 4", "((2 ** 3) * 4)");
956        test_binary_expression!("2 * 3 ** 4", "(2 * (3 ** 4))");
957
958        // Associativity tests
959        test_binary_expression!("1 + 2 + 3", "((1 + 2) + 3)"); // Left-to-right
960        test_binary_expression!("2 ** 3 ** 2", "(2 ** (3 ** 2))"); // Right-to-left
961        test_binary_expression!("10 / 5 / 2", "((10 / 5) / 2)"); // Left-to-right
962
963        // Unary operators
964        test_binary_expression!("-2 * 3", "((-2) * 3)");
965        test_binary_expression!("!1 && 2", "((!1) && 2)");
966        test_binary_expression!("~1 & 2", "((~1) & 2)");
967
968        // Bitwise operations
969        test_binary_expression!("1 | 2 & 3", "(1 | (2 & 3))");
970        test_binary_expression!("1 & 2 ^ 3", "((1 & 2) ^ 3)");
971        test_binary_expression!("1 | 2 | 3", "((1 | 2) | 3)");
972
973        // Logical operations
974        test_binary_expression!("1 || 2 && 3", "(1 || (2 && 3))");
975        test_binary_expression!("1 && 2 || 3 && 4", "((1 && 2) || (3 && 4))");
976
977        // Comparison operations
978        test_binary_expression!("1 < 2 == 3 > 4", "((1 < 2) == (3 > 4))");
979        test_binary_expression!("1 == 2 != 3 == 4", "(((1 == 2) != 3) == 4)");
980
981        // Shift operations
982        test_binary_expression!("1 << 2 + 3", "(1 << (2 + 3))");
983        test_binary_expression!("1 + 2 >> 3", "((1 + 2) >> 3)");
984
985        // Pipe operator
986        test_binary_expression!("1 |> 2 |> 3", "((1 |> 2) |> 3)");
987
988        // Complex combinations
989        test_binary_expression!("1 + 2 * 3 ** 4", "(1 + (2 * (3 ** 4)))");
990        test_binary_expression!(
991            "1 || 2 && 3 | 4 ^ 5 & 6",
992            "(1 || (2 && (3 | (4 ^ (5 & 6)))))"
993        );
994        test_binary_expression!(
995            "1 + 2 * 3 < 4 && 5 == 6",
996            "(((1 + (2 * 3)) < 4) && (5 == 6))"
997        );
998    }
999}