Skip to main content

mq_lang/ast/
parser.rs

1use crate::arena::Arena;
2use crate::ast::node::{IdentWithToken, MatchArm, Pattern};
3use crate::error::syntax::SyntaxError;
4use crate::lexer::Lexer;
5use crate::lexer::token::{Token, TokenKind};
6use crate::module::ModuleId;
7use crate::selector::Selector;
8use crate::{Ident, Shared, lexer};
9use smallvec::{SmallVec, smallvec};
10use smol_str::SmolStr;
11use std::iter::Peekable;
12use std::sync::LazyLock;
13
14use super::constants;
15use super::node::{AccessTarget, Args, Branches, Expr, Literal, Node, Param, Params};
16use super::{Program, TokenId};
17
18type IfExpr = (Option<Shared<Node>>, Shared<Node>);
19
20static GET_IDENT: LazyLock<Ident> = LazyLock::new(|| Ident::from(constants::builtins::GET));
21
22pub struct Parser<'a, 'alloc> {
23    tokens: Peekable<core::slice::Iter<'a, Shared<Token>>>,
24    token_arena: &'alloc mut Arena<Shared<Token>>,
25    module_id: ModuleId,
26}
27
28impl<'a, 'alloc> Parser<'a, 'alloc> {
29    pub fn new(
30        tokens: core::slice::Iter<'a, Shared<Token>>,
31        token_arena: &'alloc mut Arena<Shared<Token>>,
32        module_id: ModuleId,
33    ) -> Self {
34        Self {
35            tokens: tokens.peekable(),
36            token_arena,
37            module_id,
38        }
39    }
40
41    pub fn parse(&mut self) -> Result<Program, SyntaxError> {
42        self.parse_program(true)
43    }
44
45    fn parse_program(&mut self, root: bool) -> Result<Program, SyntaxError> {
46        let mut asts = Vec::with_capacity(64);
47
48        // Initial check for invalid starting tokens in a program.
49        match self.tokens.peek() {
50            Some(token) => match &token.kind {
51                TokenKind::Pipe | TokenKind::SemiColon => {
52                    return Err(SyntaxError::UnexpectedToken((***token).clone()));
53                }
54                TokenKind::End => {
55                    return Err(SyntaxError::UnmatchedEnd((***token).clone()));
56                }
57                _ => {}
58            },
59            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
60        };
61
62        while let Some(token) = self.tokens.next() {
63            match &token.kind {
64                TokenKind::Pipe => continue, // Skip pipes.
65                TokenKind::Eof => break,     // End of file terminates the program.
66                TokenKind::SemiColon | TokenKind::End => {
67                    // Semicolons and 'end' keyword terminate sub-programs (e.g., in 'def', 'fn').
68                    // In the root program, after a semicolon or 'end', the parser checks if the next token is EOF.
69                    // If the next token is not EOF, it returns an error for the unexpected token.
70                    if root {
71                        match self.tokens.peek() {
72                            Some(next_token) if !matches!(next_token.kind, TokenKind::Eof) => {
73                                if matches!(token.kind, TokenKind::End) {
74                                    return Err(SyntaxError::UnmatchedEnd((**token).clone()));
75                                } else {
76                                    return Err(SyntaxError::UnexpectedToken((***next_token).clone()));
77                                }
78                            }
79                            _ => break,
80                        }
81                    }
82                    // For non-root programs (e.g. function bodies), a semicolon/end explicitly ends the program.
83                    break;
84                }
85                TokenKind::Nodes if root => {
86                    let ast = self.parse_all_nodes(token)?;
87                    asts.push(ast);
88                }
89                TokenKind::Nodes => {
90                    return Err(SyntaxError::UnexpectedToken((**token).clone()));
91                }
92                TokenKind::NewLine | TokenKind::Tab(_) | TokenKind::Whitespace(_) => {
93                    unreachable!("parse_program should have filtered out whitespace tokens")
94                }
95                _ => {
96                    let ast = self.parse_expr(token)?;
97                    asts.push(ast);
98                }
99            }
100        }
101
102        if asts.is_empty() {
103            return Err(SyntaxError::UnexpectedEOFDetected(self.module_id));
104        }
105
106        Ok(asts)
107    }
108
109    #[inline(always)]
110    fn parse_expr(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
111        self.parse_equality_expr(token)
112    }
113
114    #[inline(always)]
115    fn binary_op_precedence(kind: &TokenKind) -> u8 {
116        match kind {
117            TokenKind::Equal
118            | TokenKind::PlusEqual
119            | TokenKind::MinusEqual
120            | TokenKind::StarEqual
121            | TokenKind::SlashEqual
122            | TokenKind::PercentEqual
123            | TokenKind::DoubleSlashEqual => 0,
124            TokenKind::Or => 1,
125            TokenKind::And => 2,
126            TokenKind::EqEq
127            | TokenKind::NeEq
128            | TokenKind::Gt
129            | TokenKind::Gte
130            | TokenKind::Lt
131            | TokenKind::Lte
132            | TokenKind::TildeEqual
133            | TokenKind::NotTildeEqual => 3,
134            TokenKind::Plus | TokenKind::Minus | TokenKind::RightShift | TokenKind::LeftShift => 4,
135            TokenKind::Asterisk | TokenKind::Slash | TokenKind::Percent | TokenKind::Convert => 5,
136            TokenKind::DoubleDot | TokenKind::Coalesce => 6,
137            _ => 0,
138        }
139    }
140
141    fn binary_op_function_name(kind: &TokenKind) -> &'static str {
142        match kind {
143            TokenKind::Asterisk => constants::builtins::MUL,
144            TokenKind::Coalesce => constants::builtins::COALESCE,
145            TokenKind::EqEq => constants::builtins::EQ,
146            TokenKind::Gte => constants::builtins::GTE,
147            TokenKind::Gt => constants::builtins::GT,
148            TokenKind::Lte => constants::builtins::LTE,
149            TokenKind::Lt => constants::builtins::LT,
150            TokenKind::Minus => constants::builtins::SUB,
151            TokenKind::NeEq => constants::builtins::NE,
152            TokenKind::Percent => constants::builtins::MOD,
153            TokenKind::Plus => constants::builtins::ADD,
154            TokenKind::DoubleDot => constants::builtins::RANGE,
155            TokenKind::Slash => constants::builtins::DIV,
156            TokenKind::TildeEqual => constants::builtins::IS_REGEX_MATCH,
157            TokenKind::NotTildeEqual => constants::builtins::IS_NOT_REGEX_MATCH,
158            TokenKind::LeftShift => constants::builtins::SHIFT_LEFT,
159            TokenKind::RightShift => constants::builtins::SHIFT_RIGHT,
160            TokenKind::Convert => constants::builtins::CONVERT,
161            _ => unreachable!("binary_op_function_name called with non-binary operator"),
162        }
163    }
164
165    fn create_compound_assign(
166        &self,
167        lhs: &Shared<Node>,
168        rhs: Shared<Node>,
169        operator_token_id: TokenId,
170        operator_token: &Shared<Token>,
171        function_name: &'static str,
172    ) -> Result<Shared<Node>, SyntaxError> {
173        let compound_rhs = Shared::new(Node {
174            token_id: operator_token_id,
175            expr: Shared::new(Expr::Call(
176                IdentWithToken::new_with_token(function_name, Some(Shared::clone(operator_token))),
177                smallvec![Shared::clone(lhs), rhs],
178            )),
179        });
180        self.create_assign(lhs, compound_rhs, operator_token_id, operator_token)
181    }
182
183    /// Creates an assignment node, handling both simple identifiers and indexed targets.
184    ///
185    /// - `x = rhs` → `Assign(x, rhs)`
186    /// - `arr[idx] = rhs` (lhs is `Call("get", [arr, idx])`) → `Assign(arr, set(arr, idx, rhs))`
187    fn create_assign(
188        &self,
189        lhs: &Shared<Node>,
190        rhs: Shared<Node>,
191        operator_token_id: TokenId,
192        operator_token: &Shared<Token>,
193    ) -> Result<Shared<Node>, SyntaxError> {
194        match &*lhs.expr {
195            Expr::Ident(ident) => Ok(Shared::new(Node {
196                token_id: operator_token_id,
197                expr: Shared::new(Expr::Assign(ident.clone(), rhs)),
198            })),
199            Expr::Call(func_ident, args) if func_ident.name == *GET_IDENT && args.len() == 2 => match &*args[0].expr {
200                Expr::Ident(var_ident) => Ok(Shared::new(Node {
201                    token_id: operator_token_id,
202                    expr: Shared::new(Expr::Assign(
203                        var_ident.clone(),
204                        Shared::new(Node {
205                            token_id: operator_token_id,
206                            expr: Shared::new(Expr::Call(
207                                IdentWithToken::new_with_token(
208                                    constants::builtins::SET,
209                                    Some(Shared::clone(operator_token)),
210                                ),
211                                smallvec![Shared::clone(&args[0]), Shared::clone(&args[1]), rhs,],
212                            )),
213                        }),
214                    )),
215                })),
216                _ => Err(SyntaxError::InvalidAssignmentTarget(
217                    (*self.token_arena[args[0].token_id]).clone(),
218                )),
219            },
220            _ => Err(SyntaxError::InvalidAssignmentTarget(
221                (*self.token_arena[lhs.token_id]).clone(),
222            )),
223        }
224    }
225
226    fn parse_binary_op(parser: &mut Parser, min_prec: u8, mut lhs: Shared<Node>) -> Result<Shared<Node>, SyntaxError> {
227        while let Some(peeked_token_rc) = parser.tokens.peek() {
228            let kind = &peeked_token_rc.kind;
229            if !Self::is_binary_op(kind) {
230                break;
231            }
232
233            let prec = Self::binary_op_precedence(kind);
234
235            if prec < min_prec {
236                break;
237            }
238
239            let operator_token = parser.tokens.next().unwrap();
240            let operator_token_id = parser.token_arena.alloc(Shared::clone(operator_token));
241
242            let rhs_token = match parser.tokens.next() {
243                Some(t) if t.kind == TokenKind::Eof => {
244                    return Err(SyntaxError::UnexpectedEOFAfterToken((**operator_token).clone()));
245                }
246                Some(t) => t,
247                None => return Err(SyntaxError::UnexpectedEOFAfterToken((**operator_token).clone())),
248            };
249            let mut rhs = parser.parse_primary_expr(rhs_token)?;
250
251            loop {
252                let next_prec = if let Some(next_token) = parser.tokens.peek() {
253                    if Self::is_binary_op(&next_token.kind) {
254                        Self::binary_op_precedence(&next_token.kind)
255                    } else {
256                        0
257                    }
258                } else {
259                    0
260                };
261                if next_prec > prec {
262                    rhs = Self::parse_binary_op(parser, next_prec, rhs)?;
263                } else {
264                    break;
265                }
266            }
267
268            lhs = match kind {
269                TokenKind::Equal => parser.create_assign(&lhs, rhs, operator_token_id, operator_token)?,
270                TokenKind::And => {
271                    let operands = match &*lhs.expr {
272                        Expr::And(existing) => {
273                            let mut ops = existing.clone();
274                            ops.push(rhs);
275                            ops
276                        }
277                        _ => vec![lhs, rhs],
278                    };
279                    Shared::new(Node {
280                        token_id: operator_token_id,
281                        expr: Shared::new(Expr::And(operands)),
282                    })
283                }
284                TokenKind::Or => {
285                    let operands = match &*lhs.expr {
286                        Expr::Or(existing) => {
287                            let mut ops = existing.clone();
288                            ops.push(rhs);
289                            ops
290                        }
291                        _ => vec![lhs, rhs],
292                    };
293                    Shared::new(Node {
294                        token_id: operator_token_id,
295                        expr: Shared::new(Expr::Or(operands)),
296                    })
297                }
298                TokenKind::PlusEqual => parser.create_compound_assign(
299                    &lhs,
300                    rhs,
301                    operator_token_id,
302                    operator_token,
303                    constants::builtins::ADD,
304                )?,
305                TokenKind::MinusEqual => parser.create_compound_assign(
306                    &lhs,
307                    rhs,
308                    operator_token_id,
309                    operator_token,
310                    constants::builtins::SUB,
311                )?,
312                TokenKind::StarEqual => parser.create_compound_assign(
313                    &lhs,
314                    rhs,
315                    operator_token_id,
316                    operator_token,
317                    constants::builtins::MUL,
318                )?,
319                TokenKind::SlashEqual => parser.create_compound_assign(
320                    &lhs,
321                    rhs,
322                    operator_token_id,
323                    operator_token,
324                    constants::builtins::DIV,
325                )?,
326                TokenKind::PercentEqual => parser.create_compound_assign(
327                    &lhs,
328                    rhs,
329                    operator_token_id,
330                    operator_token,
331                    constants::builtins::MOD,
332                )?,
333                TokenKind::DoubleSlashEqual => {
334                    let floor_div_rhs = Shared::new(Node {
335                        token_id: operator_token_id,
336                        expr: Shared::new(Expr::Call(
337                            IdentWithToken::new_with_token(
338                                constants::builtins::FLOOR,
339                                Some(Shared::clone(operator_token)),
340                            ),
341                            smallvec![Shared::new(Node {
342                                token_id: operator_token_id,
343                                expr: Shared::new(Expr::Call(
344                                    IdentWithToken::new_with_token(
345                                        constants::builtins::DIV,
346                                        Some(Shared::clone(operator_token)),
347                                    ),
348                                    smallvec![Shared::clone(&lhs), rhs],
349                                )),
350                            })],
351                        )),
352                    });
353                    parser.create_assign(&lhs, floor_div_rhs, operator_token_id, operator_token)?
354                }
355                _ => Shared::new(Node {
356                    token_id: operator_token_id,
357                    expr: Shared::new(Expr::Call(
358                        IdentWithToken::new_with_token(
359                            Self::binary_op_function_name(kind),
360                            Some(Shared::clone(operator_token)),
361                        ),
362                        smallvec![lhs, rhs],
363                    )),
364                }),
365            };
366        }
367
368        Ok(lhs)
369    }
370
371    fn parse_equality_expr(&mut self, initial_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
372        let lhs = self.parse_primary_expr(initial_token)?;
373        let lhs = Self::parse_binary_op(self, 0, lhs)?;
374
375        if let Some(token) = self.tokens.peek()
376            && matches!(token.kind, TokenKind::As)
377        {
378            return self.parse_as_binding(lhs);
379        }
380
381        Ok(lhs)
382    }
383
384    fn parse_as_binding(&mut self, expr: Shared<Node>) -> Result<Shared<Node>, SyntaxError> {
385        let as_token = self.tokens.next().unwrap();
386        let as_token_id = self.token_arena.alloc(Shared::clone(as_token));
387
388        let name_token = match self.tokens.next() {
389            Some(token) => token,
390            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
391        };
392
393        match &name_token.kind {
394            TokenKind::Ident(name) => {
395                let ident = IdentWithToken::new_with_token(name, Some(Shared::clone(name_token)));
396                Ok(Shared::new(Node {
397                    token_id: as_token_id,
398                    expr: Shared::new(Expr::As(ident, expr)),
399                }))
400            }
401            _ => Err(SyntaxError::UnexpectedToken((**name_token).clone())),
402        }
403    }
404
405    fn parse_primary_expr(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
406        match &token.kind {
407            TokenKind::Selector(_) | TokenKind::DoubleDot => self.parse_selector(token),
408            TokenKind::Let => self.parse_let(token),
409            TokenKind::Var => self.parse_var(token),
410            TokenKind::Def => self.parse_def(token),
411            TokenKind::Macro => self.parse_macro(token),
412            TokenKind::Do => self.parse_block(token),
413            TokenKind::Fn | TokenKind::Arrow => self.parse_fn(token),
414            TokenKind::While => self.parse_while(token),
415            TokenKind::Loop => self.parse_loop(token),
416            TokenKind::Foreach => self.parse_foreach(token),
417            TokenKind::Module => self.parse_module(token),
418            TokenKind::Try => self.parse_try(token),
419            TokenKind::Quote => self.parse_quote(token),
420            TokenKind::Unquote => self.parse_unquote(token),
421            TokenKind::If => self.parse_if(token),
422            TokenKind::Match => self.parse_match(token),
423            TokenKind::InterpolatedString(_) => self.parse_interpolated_string(token),
424            TokenKind::Include => self.parse_include(token),
425            TokenKind::Import => self.parse_import(token),
426            TokenKind::Self_ => self.parse_self(token),
427            TokenKind::Break => self.parse_break(token),
428            TokenKind::Continue => self.parse_continue(token),
429            TokenKind::Ident(name) => self.parse_ident(name, token),
430            TokenKind::BoolLiteral(_) => self.parse_literal(token),
431            TokenKind::StringLiteral(_) => self.parse_literal(token),
432            TokenKind::BytesLiteral(_) => self.parse_literal(token),
433            TokenKind::NumberLiteral(_) => self.parse_literal(token),
434            TokenKind::LBracket => self.parse_array(token),
435            TokenKind::LBrace => self.parse_dict(token),
436            TokenKind::LParen => self.parse_paren(token),
437            TokenKind::Not => self.parse_not(token),
438            TokenKind::Minus => self.parse_negate(token),
439            TokenKind::Env(_) => self.parse_env(token),
440            TokenKind::None => self.parse_literal(token),
441            TokenKind::Colon => self.parse_symbol(token),
442            TokenKind::Eof => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
443            _ => Err(SyntaxError::UnexpectedToken((**token).clone())),
444        }
445    }
446
447    fn parse_module(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
448        match &token.kind {
449            TokenKind::Module => match self.tokens.peek() {
450                Some(_) => {
451                    let ident_token = self
452                        .tokens
453                        .next()
454                        .ok_or(SyntaxError::UnexpectedEOFDetected(self.module_id))?;
455
456                    self.consume_colon_or_do();
457
458                    let program = self.parse_program(false)?;
459
460                    // Only allow 'let', 'def', or 'module' at the top-level of a module block
461                    for node in &program {
462                        match &*node.expr {
463                            Expr::Let(_, _) | Expr::Def(_, _, _) | Expr::Module(_, _) | Expr::Import(_) => {}
464                            _ => {
465                                return Err(SyntaxError::UnexpectedToken((*self.token_arena[node.token_id]).clone()));
466                            }
467                        }
468                    }
469
470                    Ok(Shared::new(Node {
471                        token_id: self.token_arena.alloc(Shared::clone(token)),
472                        expr: Shared::new(Expr::Module(
473                            IdentWithToken::new_with_token(
474                                match &ident_token.kind {
475                                    TokenKind::Ident(name) => name,
476                                    _ => {
477                                        return Err(SyntaxError::UnexpectedToken((**ident_token).clone()));
478                                    }
479                                },
480                                Some(Shared::clone(ident_token)),
481                            ),
482                            program.iter().map(Shared::clone).collect(),
483                        )),
484                    }))
485                }
486                None => Err(SyntaxError::UnexpectedToken((**token).clone())),
487            },
488            _ => Err(SyntaxError::UnexpectedToken((**token).clone())),
489        }
490    }
491
492    fn parse_symbol(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
493        match &token.kind {
494            TokenKind::Colon => {
495                let next_token = match self.tokens.next() {
496                    Some(t) => t,
497                    None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
498                };
499                match &next_token.kind {
500                    TokenKind::Ident(name) => Ok(Shared::new(Node {
501                        token_id: self.token_arena.alloc(Shared::clone(token)),
502                        expr: Shared::new(Expr::Literal(Literal::Symbol(Ident::new(name)))),
503                    })),
504                    TokenKind::StringLiteral(s) => Ok(Shared::new(Node {
505                        token_id: self.token_arena.alloc(Shared::clone(token)),
506                        expr: Shared::new(Expr::Literal(Literal::Symbol(Ident::new(s)))),
507                    })),
508                    _ => Err(SyntaxError::UnexpectedToken((**next_token).clone())),
509                }
510            }
511            _ => Err(SyntaxError::UnexpectedToken((**token).clone())),
512        }
513    }
514
515    fn parse_paren(&mut self, lparen_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
516        let opening = (**lparen_token).clone();
517        let token_id = self.token_arena.alloc(Shared::clone(lparen_token));
518        let expr_token = match self.tokens.next() {
519            Some(t) => t,
520            None => {
521                return Err(SyntaxError::ExpectedClosingParen(
522                    Token {
523                        range: opening.range,
524                        kind: TokenKind::Eof,
525                        module_id: self.module_id,
526                    },
527                    Some(Box::new(opening)),
528                ));
529            }
530        };
531
532        let expr_node = self.parse_expr(expr_token)?;
533
534        match self.tokens.next() {
535            Some(t) if t.kind == TokenKind::RParen => {}
536            Some(t) if t.kind == TokenKind::Eof => {
537                return Err(SyntaxError::ExpectedClosingParen(
538                    (**t).clone(),
539                    Some(Box::new(opening)),
540                ));
541            }
542            Some(t) => return Err(SyntaxError::UnexpectedToken((**t).clone())),
543            None => {
544                return Err(SyntaxError::ExpectedClosingParen(
545                    Token {
546                        range: opening.range,
547                        kind: TokenKind::Eof,
548                        module_id: self.module_id,
549                    },
550                    Some(Box::new(opening)),
551                ));
552            }
553        }
554
555        let paren_node = Shared::new(Node {
556            token_id,
557            expr: Shared::new(Expr::Paren(expr_node)),
558        });
559
560        // Handle postfix operations: (expr)(args), (expr)[N], (expr)(args)[N], etc.
561        self.parse_postfix_ops(paren_node, lparen_token)
562    }
563
564    fn parse_not(&mut self, not_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
565        let token_id = self.token_arena.alloc(Shared::clone(not_token));
566
567        let expr_token = match self.tokens.next() {
568            Some(t) if t.kind == TokenKind::Eof => {
569                return Err(SyntaxError::UnexpectedEOFAfterToken((**not_token).clone()));
570            }
571            Some(t) => t,
572            None => return Err(SyntaxError::UnexpectedEOFAfterToken((**not_token).clone())),
573        };
574
575        if !matches!(
576            expr_token.kind,
577            TokenKind::BoolLiteral(_)
578                | TokenKind::StringLiteral(_)
579                | TokenKind::BytesLiteral(_)
580                | TokenKind::NumberLiteral(_)
581                | TokenKind::If
582                | TokenKind::Foreach
583                | TokenKind::LBrace
584                | TokenKind::LBracket
585                | TokenKind::LParen
586                | TokenKind::While
587                | TokenKind::Loop
588                | TokenKind::Match
589                | TokenKind::Self_
590                | TokenKind::Selector(_)
591                | TokenKind::Env(_)
592                | TokenKind::Not
593                | TokenKind::Ident(_)
594        ) {
595            return Err(SyntaxError::UnexpectedToken((**expr_token).clone()));
596        }
597
598        let expr_node = self.parse_primary_expr(expr_token)?;
599
600        // Convert ! to not() function call
601        let not_ident = IdentWithToken::new_with_token(constants::builtins::NOT, Some(Shared::clone(not_token)));
602        let args = smallvec![expr_node];
603
604        Ok(Shared::new(Node {
605            token_id,
606            expr: Shared::new(Expr::Call(not_ident, args)),
607        }))
608    }
609
610    fn parse_negate(&mut self, minus_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
611        let token_id = self.token_arena.alloc(Shared::clone(minus_token));
612
613        let expr_token = match self.tokens.next() {
614            Some(t) if t.kind == TokenKind::Eof => {
615                return Err(SyntaxError::UnexpectedEOFAfterToken((**minus_token).clone()));
616            }
617            Some(t) => t,
618            None => return Err(SyntaxError::UnexpectedEOFAfterToken((**minus_token).clone())),
619        };
620
621        if !matches!(
622            expr_token.kind,
623            TokenKind::NumberLiteral(_)
624                | TokenKind::If
625                | TokenKind::Foreach
626                | TokenKind::LBrace
627                | TokenKind::LBracket
628                | TokenKind::While
629                | TokenKind::Loop
630                | TokenKind::Match
631                | TokenKind::Self_
632                | TokenKind::Env(_)
633                | TokenKind::Ident(_)
634        ) {
635            return Err(SyntaxError::UnexpectedToken((**expr_token).clone()));
636        }
637
638        let expr_node = self.parse_primary_expr(expr_token)?;
639        let negate_ident =
640            IdentWithToken::new_with_token(constants::builtins::NEGATE, Some(Shared::clone(minus_token)));
641        let args = smallvec![expr_node];
642
643        Ok(Shared::new(Node {
644            token_id,
645            expr: Shared::new(Expr::Call(negate_ident, args)),
646        }))
647    }
648
649    fn parse_dict(&mut self, lbrace_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
650        let opening = (**lbrace_token).clone();
651        let token_id = self.token_arena.alloc(Shared::clone(lbrace_token));
652        let mut pairs = SmallVec::new();
653
654        let eof_closing_err = |opening: &Token, module_id: ModuleId| {
655            SyntaxError::ExpectedClosingBrace(
656                Token {
657                    range: opening.range,
658                    kind: TokenKind::Eof,
659                    module_id,
660                },
661                Some(Box::new(opening.clone())),
662            )
663        };
664
665        loop {
666            match self.tokens.peek() {
667                Some(token) if token.kind == TokenKind::RBrace => {
668                    self.tokens.next();
669                    break;
670                }
671                Some(token) if token.kind == TokenKind::Eof => {
672                    return Err(SyntaxError::ExpectedClosingBrace(
673                        (***token).clone(),
674                        Some(Box::new(opening.clone())),
675                    ));
676                }
677                None => {
678                    return Err(eof_closing_err(&opening, self.module_id));
679                }
680                _ => {}
681            }
682
683            // Parse key
684            let key_token = match self.tokens.next() {
685                Some(t) => t,
686                None => return Err(eof_closing_err(&opening, self.module_id)),
687            };
688
689            let key_node = match &key_token.kind {
690                TokenKind::Ident(name) => Shared::new(Node {
691                    token_id: self.token_arena.alloc(Shared::clone(key_token)),
692                    expr: Shared::new(Expr::Literal(Literal::Symbol(Ident::new(name)))),
693                }),
694                TokenKind::StringLiteral(s) => Shared::new(Node {
695                    token_id: self.token_arena.alloc(Shared::clone(key_token)),
696                    expr: Shared::new(Expr::Literal(Literal::String(s.clone()))),
697                }),
698                _ => {
699                    return Err(SyntaxError::UnexpectedToken((**key_token).clone()));
700                }
701            };
702
703            // Expect Colon
704            match self.tokens.next() {
705                Some(token) if token.kind == TokenKind::Colon => {}
706                Some(token) => return Err(SyntaxError::UnexpectedToken((**token).clone())),
707                None => return Err(eof_closing_err(&opening, self.module_id)),
708            }
709
710            // Parse value
711            let value_token = match self.tokens.next() {
712                Some(t) => t,
713                None => return Err(eof_closing_err(&opening, self.module_id)),
714            };
715            let value_node = self.parse_expr(value_token)?;
716
717            pairs.push(Shared::new(Node {
718                token_id,
719                expr: Shared::new(Expr::Call(
720                    IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::clone(key_token))),
721                    smallvec![key_node, value_node],
722                )),
723            }));
724
725            // Peek for Comma or RBrace
726            match self.tokens.peek() {
727                Some(token) if token.kind == TokenKind::Comma => {
728                    self.tokens.next(); // Consume Comma
729                    // Check for trailing comma followed by RBrace
730                    if let Some(next_token) = self.tokens.peek()
731                        && next_token.kind == TokenKind::RBrace
732                    {
733                        self.tokens.next(); // Consume RBrace
734                        break;
735                    }
736                }
737                Some(token) if token.kind == TokenKind::RBrace => {
738                    self.tokens.next(); // Consume RBrace
739                    break;
740                }
741                Some(token) => {
742                    return Err(SyntaxError::ExpectedClosingBrace(
743                        (***token).clone(),
744                        Some(Box::new(opening.clone())),
745                    ));
746                }
747                None => return Err(eof_closing_err(&opening, self.module_id)),
748            }
749        }
750
751        Ok(Shared::new(Node {
752            token_id,
753            expr: Shared::new(Expr::Call(
754                IdentWithToken::new_with_token(constants::builtins::DICT, Some(Shared::clone(lbrace_token))),
755                pairs,
756            )),
757        }))
758    }
759
760    fn parse_env(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
761        match &token.kind {
762            TokenKind::Env(s) => Ok(Shared::new(Node {
763                token_id: self.token_arena.alloc(Shared::clone(token)),
764                expr: std::env::var(s)
765                    .map_err(|_| SyntaxError::EnvNotFound((**token).clone(), SmolStr::new(s)))
766                    .map(|s| Shared::new(Expr::Literal(Literal::String(s.to_owned()))))?,
767            })),
768            TokenKind::Eof => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
769            _ => Err(SyntaxError::UnexpectedToken((**token).clone())),
770        }
771    }
772
773    fn parse_attribute_access(
774        &mut self,
775        base_node: Shared<Node>,
776        token_id: TokenId,
777    ) -> Result<Shared<Node>, SyntaxError> {
778        let selector_token = match self.tokens.peek() {
779            Some(t) => Shared::clone(t),
780            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
781        };
782
783        if let TokenKind::Selector(selector) = &selector_token.kind
784            && selector.len() > 1
785        {
786            if !Selector::try_from(&*selector_token)
787                .map_err(SyntaxError::UnknownSelector)?
788                .is_attribute_selector()
789            {
790                return Err(SyntaxError::UnexpectedToken((*selector_token).clone()));
791            }
792
793            let attribute_name = &selector[1..]; // Skip the leading '.'
794            let attr_literal_token_id = self.token_arena.alloc(Shared::clone(&selector_token));
795            let attr_literal = Shared::new(Node {
796                token_id: attr_literal_token_id,
797                expr: Shared::new(Expr::Literal(Literal::String(attribute_name.to_string()))),
798            });
799
800            self.tokens.next(); // Consume selector token
801
802            if self.is_next_token(|kind| matches!(kind, TokenKind::PipeEqual)) {
803                self.tokens.next(); // consume '|='
804                return self.parse_set_attr_call_with_selector(base_node, attr_literal);
805            }
806
807            Ok(Shared::new(Node {
808                token_id: attr_literal_token_id,
809                expr: Shared::new(Expr::Call(
810                    IdentWithToken::new_with_token(
811                        constants::builtins::ATTR,
812                        Some(Shared::clone(&self.token_arena[token_id])),
813                    ),
814                    smallvec![base_node, attr_literal],
815                )),
816            }))
817        } else {
818            Ok(base_node)
819        }
820    }
821
822    fn parse_self(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
823        let token_id = self.token_arena.alloc(Shared::clone(token));
824        let self_node = Shared::new(Node {
825            token_id,
826            expr: Shared::new(Expr::Self_),
827        });
828        let node = self.parse_attribute_access(self_node, token_id)?;
829
830        match self.tokens.peek().map(|t| &t.kind) {
831            Some(TokenKind::LBracket) => self.parse_bracket_access(node, token),
832            _ => Ok(node),
833        }
834    }
835
836    fn parse_break(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
837        let token_id = self.token_arena.alloc(Shared::clone(token));
838
839        // Check for colon and expression (break: expr)
840        let value = if self.tokens.peek().map(|t| &t.kind) == Some(&TokenKind::Colon) {
841            self.tokens.next(); // consume colon
842            let expr_token = self
843                .tokens
844                .next()
845                .ok_or(SyntaxError::UnexpectedEOFDetected(self.module_id))?;
846            Some(self.parse_expr(expr_token)?)
847        } else {
848            None
849        };
850
851        Ok(Shared::new(Node {
852            token_id,
853            expr: Shared::new(Expr::Break(value)),
854        }))
855    }
856
857    fn parse_continue(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
858        Ok(Shared::new(Node {
859            token_id: self.token_arena.alloc(Shared::clone(token)),
860            expr: Shared::new(Expr::Continue),
861        }))
862    }
863
864    fn parse_array(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
865        let opening = (**token).clone();
866        let token_id = self.token_arena.alloc(Shared::clone(token));
867        let mut elements: SmallVec<[Shared<Node>; 4]> = SmallVec::new();
868        let mut closed = false;
869
870        while let Some(elem_token) = self.tokens.next() {
871            match &elem_token.kind {
872                TokenKind::RBracket => {
873                    closed = true;
874                    break;
875                }
876                TokenKind::Eof => {
877                    return Err(SyntaxError::ExpectedClosingBracket(
878                        (**elem_token).clone(),
879                        Some(Box::new(opening)),
880                    ));
881                }
882                TokenKind::Comma => continue,
883                _ => {
884                    let expr = self.parse_expr(elem_token)?;
885                    elements.push(expr);
886                }
887            }
888        }
889
890        if !closed {
891            return Err(SyntaxError::ExpectedClosingBracket(
892                Token {
893                    range: opening.range,
894                    kind: TokenKind::Eof,
895                    module_id: self.module_id,
896                },
897                Some(Box::new(opening)),
898            ));
899        }
900
901        let array_node = Shared::new(Node {
902            token_id,
903            expr: Shared::new(Expr::Call(
904                IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::clone(token))),
905                elements,
906            )),
907        });
908
909        // Handle postfix bracket access: [1,2,3][0], [1,2,3][0:2], etc.
910        self.parse_postfix_ops(array_node, token)
911    }
912
913    fn parse_all_nodes(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
914        Ok(Shared::new(Node {
915            token_id: self.token_arena.alloc(Shared::clone(token)),
916            expr: Shared::new(Expr::Nodes),
917        }))
918    }
919
920    fn is_binary_op(token_kind: &TokenKind) -> bool {
921        matches!(
922            token_kind,
923            TokenKind::And
924                | TokenKind::Asterisk
925                | TokenKind::Equal
926                | TokenKind::EqEq
927                | TokenKind::Coalesce
928                | TokenKind::Gte
929                | TokenKind::Gt
930                | TokenKind::Lte
931                | TokenKind::Lt
932                | TokenKind::Minus
933                | TokenKind::NeEq
934                | TokenKind::Or
935                | TokenKind::Percent
936                | TokenKind::Plus
937                | TokenKind::DoubleDot
938                | TokenKind::Slash
939                | TokenKind::PlusEqual
940                | TokenKind::MinusEqual
941                | TokenKind::SlashEqual
942                | TokenKind::PercentEqual
943                | TokenKind::DoubleSlashEqual
944                | TokenKind::StarEqual
945                | TokenKind::TildeEqual
946                | TokenKind::NotTildeEqual
947                | TokenKind::LeftShift
948                | TokenKind::RightShift
949                | TokenKind::Convert
950        )
951    }
952
953    fn is_next_token(&mut self, expected: impl Fn(&TokenKind) -> bool) -> bool {
954        self.tokens.peek().as_ref().map(|t| &t.kind).is_some_and(expected)
955    }
956
957    fn is_next_token_allowed(token_kind: Option<&TokenKind>) -> bool {
958        matches!(
959            token_kind,
960            Some(TokenKind::And)
961                | Some(TokenKind::As)
962                | Some(TokenKind::Asterisk)
963                | Some(TokenKind::Catch)
964                | Some(TokenKind::Colon)
965                | Some(TokenKind::Comma)
966                | Some(TokenKind::Eof)
967                | Some(TokenKind::Elif)
968                | Some(TokenKind::Else)
969                | Some(TokenKind::EqEq)
970                | Some(TokenKind::Equal)
971                | Some(TokenKind::Gte)
972                | Some(TokenKind::Gt)
973                | Some(TokenKind::Lte)
974                | Some(TokenKind::Lt)
975                | Some(TokenKind::Minus)
976                | Some(TokenKind::NeEq)
977                | Some(TokenKind::Or)
978                | Some(TokenKind::Percent)
979                | Some(TokenKind::Pipe)
980                | Some(TokenKind::Plus)
981                | Some(TokenKind::DoubleDot)
982                | Some(TokenKind::RBrace)
983                | Some(TokenKind::RBracket)
984                | Some(TokenKind::RParen)
985                | Some(TokenKind::SemiColon)
986                | Some(TokenKind::End)
987                | Some(TokenKind::Slash)
988                | Some(TokenKind::Coalesce)
989                | Some(TokenKind::PlusEqual)
990                | Some(TokenKind::MinusEqual)
991                | Some(TokenKind::SlashEqual)
992                | Some(TokenKind::StarEqual)
993                | Some(TokenKind::DoubleSlashEqual)
994                | Some(TokenKind::PercentEqual)
995                | Some(TokenKind::TildeEqual)
996                | Some(TokenKind::NotTildeEqual)
997                | Some(TokenKind::LeftShift)
998                | Some(TokenKind::RightShift)
999                | Some(TokenKind::Convert)
1000                | None
1001        )
1002    }
1003
1004    fn parse_literal(&mut self, literal_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1005        let literal_node = match &literal_token.kind {
1006            TokenKind::BoolLiteral(b) => Ok(Shared::new(Node {
1007                token_id: self.token_arena.alloc(Shared::clone(literal_token)),
1008                expr: Shared::new(Expr::Literal(Literal::Bool(*b))),
1009            })),
1010            TokenKind::StringLiteral(s) => Ok(Shared::new(Node {
1011                token_id: self.token_arena.alloc(Shared::clone(literal_token)),
1012                expr: Shared::new(Expr::Literal(Literal::String(s.to_owned()))),
1013            })),
1014            TokenKind::BytesLiteral(b) => Ok(Shared::new(Node {
1015                token_id: self.token_arena.alloc(Shared::clone(literal_token)),
1016                expr: Shared::new(Expr::Literal(Literal::Bytes(b.clone()))),
1017            })),
1018            TokenKind::NumberLiteral(n) => Ok(Shared::new(Node {
1019                token_id: self.token_arena.alloc(Shared::clone(literal_token)),
1020                expr: Shared::new(Expr::Literal(Literal::Number(*n))),
1021            })),
1022            TokenKind::None => Ok(Shared::new(Node {
1023                token_id: self.token_arena.alloc(Shared::clone(literal_token)),
1024                expr: Shared::new(Expr::Literal(Literal::None)),
1025            })),
1026            TokenKind::Eof => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1027            _ => Err(SyntaxError::UnexpectedToken((**literal_token).clone())),
1028        }?;
1029
1030        let token = self.tokens.peek();
1031
1032        if Self::is_next_token_allowed(token.as_ref().map(|t| &t.kind)) {
1033            Ok(literal_node)
1034        } else {
1035            Err(SyntaxError::UnexpectedToken((***token.unwrap()).clone()))
1036        }
1037    }
1038
1039    fn parse_ident(&mut self, ident: &str, ident_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1040        match self.tokens.peek().map(|t| &t.kind) {
1041            Some(TokenKind::Selector(selector)) if selector.len() > 1 => {
1042                let token_id = self.token_arena.alloc(Shared::clone(ident_token));
1043                let base_node = Shared::new(Node {
1044                    token_id,
1045                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
1046                        ident,
1047                        Some(Shared::clone(ident_token)),
1048                    ))),
1049                });
1050
1051                self.parse_attribute_access(base_node, token_id)
1052            }
1053            Some(TokenKind::DoubleColon) => {
1054                // Parse qualified access: module::function(), module::ident, or module::module2::method
1055                // Build the module path by collecting all identifiers separated by '::'
1056                let mut module_path = vec![IdentWithToken::new_with_token(ident, Some(Shared::clone(ident_token)))];
1057
1058                // Collect all module path segments
1059                while matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::DoubleColon)) {
1060                    self.tokens.next(); // consume '::'
1061
1062                    let next_token = self
1063                        .tokens
1064                        .next()
1065                        .ok_or(SyntaxError::UnexpectedEOFDetected(self.module_id))?;
1066
1067                    let next_ident = match &next_token.kind {
1068                        TokenKind::Ident(name) => name.clone(),
1069                        _ => return Err(SyntaxError::UnexpectedToken((**next_token).clone())),
1070                    };
1071
1072                    // Check if this is the last segment (followed by '(' or not '::')
1073                    match self.tokens.peek().map(|t| &t.kind) {
1074                        Some(TokenKind::DoubleColon) => {
1075                            // More segments to come, add to module path
1076                            module_path.push(IdentWithToken::new_with_token(
1077                                &next_ident,
1078                                Some(Shared::clone(next_token)),
1079                            ));
1080                        }
1081                        Some(TokenKind::LParen) => {
1082                            // This is a function call: module::...::function(args)
1083                            let args = self.parse_args()?;
1084                            let access_target = AccessTarget::Call(
1085                                IdentWithToken::new_with_token(&next_ident, Some(Shared::clone(next_token))),
1086                                args,
1087                            );
1088
1089                            let token_id = self.token_arena.alloc(Shared::clone(ident_token));
1090                            let qualified_node = Shared::new(Node {
1091                                token_id,
1092                                expr: Shared::new(Expr::QualifiedAccess(module_path, access_target)),
1093                            });
1094                            // Check for bracket access after qualified function call (e.g., module::func()[:1])
1095                            if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LBracket)) {
1096                                return self.parse_bracket_access(qualified_node, ident_token);
1097                            }
1098                            return Ok(qualified_node);
1099                        }
1100                        _ => {
1101                            // This is an identifier: module::...::ident
1102                            let access_target = AccessTarget::Ident(IdentWithToken::new_with_token(
1103                                &next_ident,
1104                                Some(Shared::clone(next_token)),
1105                            ));
1106
1107                            let token_id = self.token_arena.alloc(Shared::clone(ident_token));
1108                            return Ok(Shared::new(Node {
1109                                token_id,
1110                                expr: Shared::new(Expr::QualifiedAccess(module_path, access_target)),
1111                            }));
1112                        }
1113                    }
1114                }
1115
1116                // This should not be reached, but handle it gracefully
1117                Err(SyntaxError::UnexpectedToken((**ident_token).clone()))
1118            }
1119            Some(TokenKind::LParen) => {
1120                let mut args = self.parse_args()?;
1121                let token_id = self.token_arena.alloc(Shared::clone(ident_token));
1122
1123                // Check for macro call (e.g., foo(args) do ...)
1124                if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::Do)) {
1125                    let do_token = self.tokens.next().unwrap(); // consume 'do'
1126                    let block = self.parse_block(do_token)?;
1127                    args.push(block);
1128
1129                    return Ok(Shared::new(Node {
1130                        token_id: self.token_arena.alloc(Shared::clone(ident_token)),
1131                        expr: Shared::new(Expr::Call(
1132                            IdentWithToken::new_with_token(ident, Some(Shared::clone(ident_token))),
1133                            args,
1134                        )),
1135                    }));
1136                }
1137
1138                let call_node = Shared::new(Node {
1139                    token_id,
1140                    expr: Shared::new(Expr::Call(
1141                        IdentWithToken::new_with_token(ident, Some(Shared::clone(ident_token))),
1142                        args,
1143                    )),
1144                });
1145
1146                if self.is_next_token(|token_kind| matches!(token_kind, TokenKind::Question)) {
1147                    let question_token = self.tokens.next().unwrap();
1148                    let question_token_id = self.token_arena.alloc(Shared::clone(question_token));
1149
1150                    return Ok(Shared::new(Node {
1151                        token_id: question_token_id,
1152                        expr: Shared::new(Expr::Try(
1153                            call_node,
1154                            Shared::new(Node {
1155                                token_id,
1156                                expr: Shared::new(Expr::Literal(Literal::None)),
1157                            }),
1158                        )),
1159                    }));
1160                }
1161
1162                // Check for bracket access after function call (e.g., foo()[0])
1163                if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LBracket)) {
1164                    let result = self.parse_bracket_access(call_node, ident_token)?;
1165                    self.parse_postfix_ops(result, ident_token)
1166                } else if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::Selector(_))) {
1167                    self.parse_attribute_access(call_node, token_id)
1168                } else if Self::is_next_token_allowed(self.tokens.peek().map(|t| &t.kind)) {
1169                    Ok(call_node)
1170                } else {
1171                    Err(SyntaxError::UnexpectedToken((***self.tokens.peek().unwrap()).clone()))
1172                }
1173            }
1174            Some(TokenKind::LBracket) => {
1175                let ident_node = Shared::new(Node {
1176                    token_id: self.token_arena.alloc(Shared::clone(ident_token)),
1177                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
1178                        ident,
1179                        Some(Shared::clone(ident_token)),
1180                    ))),
1181                });
1182
1183                let result = self.parse_bracket_access(ident_node, ident_token)?;
1184                self.parse_postfix_ops(result, ident_token)
1185            }
1186            token if Self::is_next_token_allowed(token) => Ok(Shared::new(Node {
1187                token_id: self.token_arena.alloc(Shared::clone(ident_token)),
1188                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
1189                    ident,
1190                    Some(Shared::clone(ident_token)),
1191                ))),
1192            })),
1193            _ => Err(SyntaxError::UnexpectedToken((**ident_token).clone())),
1194        }
1195    }
1196
1197    // Parses bracket access operations recursively to handle nested access like arr[0][1][2]
1198    fn parse_bracket_access(
1199        &mut self,
1200        target_node: Shared<Node>,
1201        original_token: &Shared<Token>,
1202    ) -> Result<Shared<Node>, SyntaxError> {
1203        let lbracket = self.tokens.next().map(|t| (**t).clone()); // consume '['
1204
1205        // Check for [:N] or [:]  style slice (empty start index).
1206        // [:ident] and [:string] are dict key accesses using a symbol, not slices.
1207        let is_slice_from_start = matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::Colon))
1208            && !matches!(
1209                self.tokens.clone().nth(1).map(|t| &t.kind),
1210                Some(TokenKind::Ident(_)) | Some(TokenKind::StringLiteral(_))
1211            );
1212
1213        if is_slice_from_start {
1214            let _ = self.tokens.next(); // consume ':'
1215            let start_node = Shared::new(Node {
1216                token_id: self.token_arena.alloc(Shared::clone(original_token)),
1217                expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
1218            });
1219
1220            let result_node = match self.tokens.next() {
1221                Some(t) if t.kind == TokenKind::RBracket => {
1222                    // [:] = slice(arr, 0, len(arr))
1223                    Shared::new(Node {
1224                        token_id: self.token_arena.alloc(Shared::clone(original_token)),
1225                        expr: Shared::new(Expr::Call(
1226                            IdentWithToken::new_with_token(
1227                                constants::builtins::SLICE,
1228                                Some(Shared::clone(original_token)),
1229                            ),
1230                            smallvec![
1231                                Shared::clone(&target_node),
1232                                start_node,
1233                                Shared::new(Node {
1234                                    token_id: self.token_arena.alloc(Shared::clone(original_token)),
1235                                    expr: Shared::new(Expr::Call(
1236                                        IdentWithToken::new_with_token(constants::builtins::LEN, None,),
1237                                        smallvec![target_node],
1238                                    )),
1239                                })
1240                            ],
1241                        )),
1242                    })
1243                }
1244                Some(t) => {
1245                    let end_node = self.parse_expr(t)?;
1246                    match self.tokens.peek() {
1247                        Some(token) if matches!(token.kind, TokenKind::RBracket) => {
1248                            let _ = self.tokens.next();
1249                        }
1250                        Some(token) => {
1251                            return Err(SyntaxError::ExpectedClosingBracket(
1252                                (***token).clone(),
1253                                lbracket.clone().map(Box::new),
1254                            ));
1255                        }
1256                        None => {
1257                            return Err(SyntaxError::ExpectedClosingBracket(
1258                                Token {
1259                                    range: original_token.range,
1260                                    kind: TokenKind::Eof,
1261                                    module_id: self.module_id,
1262                                },
1263                                lbracket.clone().map(Box::new),
1264                            ));
1265                        }
1266                    }
1267                    Shared::new(Node {
1268                        token_id: self.token_arena.alloc(Shared::clone(original_token)),
1269                        expr: Shared::new(Expr::Call(
1270                            IdentWithToken::new_with_token(
1271                                constants::builtins::SLICE,
1272                                Some(Shared::clone(original_token)),
1273                            ),
1274                            smallvec![target_node, start_node, end_node],
1275                        )),
1276                    })
1277                }
1278                None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1279            };
1280
1281            let final_result = if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LBracket)) {
1282                self.parse_bracket_access(result_node, original_token)?
1283            } else {
1284                result_node
1285            };
1286            return Ok(final_result);
1287        }
1288
1289        // Parse the first expression
1290        let first_token = match self.tokens.next() {
1291            Some(t) => t,
1292            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1293        };
1294
1295        let first_node = self.parse_expr(first_token)?;
1296
1297        // Check if this is a slice operation (contains ':')
1298        let is_slice = matches!(self.tokens.peek(), Some(token) if matches!(token.kind, TokenKind::Colon));
1299
1300        let result_node = if is_slice {
1301            // Consume the colon
1302            let _ = self.tokens.next();
1303
1304            match self.tokens.next() {
1305                Some(t) if t.kind == TokenKind::RBracket => Shared::new(Node {
1306                    token_id: self.token_arena.alloc(Shared::clone(original_token)),
1307                    expr: Shared::new(Expr::Call(
1308                        IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::clone(original_token))),
1309                        smallvec![
1310                            Shared::clone(&target_node),
1311                            first_node,
1312                            Shared::new(Node {
1313                                token_id: self.token_arena.alloc(Shared::clone(original_token)),
1314                                expr: Shared::new(Expr::Call(
1315                                    IdentWithToken::new_with_token(constants::builtins::LEN, None),
1316                                    smallvec![target_node],
1317                                )),
1318                            })
1319                        ],
1320                    )),
1321                }),
1322                Some(t) => {
1323                    let second_node = self.parse_expr(t)?;
1324
1325                    // Expect closing bracket
1326                    match self.tokens.peek() {
1327                        Some(token) if matches!(token.kind, TokenKind::RBracket) => {
1328                            let _ = self.tokens.next(); // consume ']'
1329                        }
1330                        Some(token) => {
1331                            return Err(SyntaxError::ExpectedClosingBracket(
1332                                (***token).clone(),
1333                                lbracket.clone().map(Box::new),
1334                            ));
1335                        }
1336                        None => {
1337                            return Err(SyntaxError::ExpectedClosingBracket(
1338                                Token {
1339                                    range: original_token.range,
1340                                    kind: TokenKind::Eof,
1341                                    module_id: self.module_id,
1342                                },
1343                                lbracket.clone().map(Box::new),
1344                            ));
1345                        }
1346                    }
1347
1348                    Shared::new(Node {
1349                        token_id: self.token_arena.alloc(Shared::clone(original_token)),
1350                        expr: Shared::new(Expr::Call(
1351                            IdentWithToken::new_with_token(
1352                                constants::builtins::SLICE,
1353                                Some(Shared::clone(original_token)),
1354                            ),
1355                            smallvec![target_node, first_node, second_node],
1356                        )),
1357                    })
1358                }
1359                None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1360            }
1361        } else {
1362            // Expect closing bracket
1363            match self.tokens.peek() {
1364                Some(token) if matches!(token.kind, TokenKind::RBracket) => {
1365                    let _ = self.tokens.next(); // consume ']'
1366                }
1367                Some(token) => {
1368                    return Err(SyntaxError::ExpectedClosingBracket(
1369                        (***token).clone(),
1370                        lbracket.clone().map(Box::new),
1371                    ));
1372                }
1373                None => {
1374                    return Err(SyntaxError::ExpectedClosingBracket(
1375                        Token {
1376                            range: original_token.range,
1377                            kind: TokenKind::Eof,
1378                            module_id: self.module_id,
1379                        },
1380                        lbracket.map(Box::new),
1381                    ));
1382                }
1383            }
1384
1385            Shared::new(Node {
1386                token_id: self.token_arena.alloc(Shared::clone(original_token)),
1387                expr: Shared::new(Expr::Call(
1388                    IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::clone(original_token))),
1389                    smallvec![target_node, first_node],
1390                )),
1391            })
1392        };
1393
1394        // Check for additional bracket access (nested indexing)
1395        let final_result = if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LBracket)) {
1396            self.parse_bracket_access(result_node, original_token)?
1397        } else {
1398            result_node
1399        };
1400
1401        // Check for function call after bracket access (e.g., arr[0]() or arr[0][1]())
1402        // and handle further postfix operations (e.g., arr[0]()[1])
1403        if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LParen)) {
1404            let args = self.parse_args()?;
1405            let call_dynamic = Shared::new(Node {
1406                token_id: self.token_arena.alloc(Shared::clone(original_token)),
1407                expr: Shared::new(Expr::CallDynamic(final_result, args)),
1408            });
1409            self.parse_postfix_ops(call_dynamic, original_token)
1410        } else {
1411            Ok(final_result)
1412        }
1413    }
1414
1415    /// Parses postfix operations (dynamic calls and bracket access) after a primary expression.
1416    /// Handles chains like `(expr)(args)[N]`, `expr[N](args)[M]`, etc.
1417    fn parse_postfix_ops(
1418        &mut self,
1419        mut current: Shared<Node>,
1420        original_token: &Shared<Token>,
1421    ) -> Result<Shared<Node>, SyntaxError> {
1422        loop {
1423            if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LParen)) {
1424                let args = self.parse_args()?;
1425                current = Shared::new(Node {
1426                    token_id: self.token_arena.alloc(Shared::clone(original_token)),
1427                    expr: Shared::new(Expr::CallDynamic(current, args)),
1428                });
1429            } else if matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::LBracket)) {
1430                current = self.parse_bracket_access(current, original_token)?;
1431            } else {
1432                break;
1433            }
1434        }
1435        Ok(current)
1436    }
1437
1438    fn parse_def(&mut self, def_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1439        let ident_token = self.tokens.next();
1440        let ident = match &ident_token {
1441            Some(token) => match &token.kind {
1442                TokenKind::Ident(ident) => Ok(ident),
1443                _ => Err(SyntaxError::UnexpectedToken((***token).clone())),
1444            },
1445            None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1446        }?;
1447        let def_token_id = self.token_arena.alloc(Shared::clone(def_token));
1448        let params = if self.is_next_token(|token| matches!(token, TokenKind::Colon | TokenKind::Do)) {
1449            SmallVec::new()
1450        } else {
1451            self.parse_params()?
1452        };
1453
1454        self.consume_colon_or_do();
1455
1456        let program = self.parse_program(false)?;
1457
1458        Ok(Shared::new(Node {
1459            token_id: def_token_id,
1460            expr: Shared::new(Expr::Def(
1461                IdentWithToken::new_with_token(ident, ident_token.map(Shared::clone)),
1462                params,
1463                program,
1464            )),
1465        }))
1466    }
1467
1468    fn parse_macro(&mut self, macro_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1469        let ident_token = self.tokens.next();
1470        let ident = match &ident_token {
1471            Some(token) => match &token.kind {
1472                TokenKind::Ident(ident) => Ok(ident),
1473                _ => Err(SyntaxError::UnexpectedToken((***token).clone())),
1474            },
1475            None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1476        }?;
1477        let macro_token_id = self.token_arena.alloc(Shared::clone(macro_token));
1478        let params = self.parse_params()?;
1479
1480        // Macros should not support default parameters
1481        if params.iter().any(|p| p.default.is_some()) {
1482            return Err(SyntaxError::MacroParametersCannotHaveDefaults(
1483                (*self.token_arena[macro_token_id]).clone(),
1484            ));
1485        }
1486
1487        // Macros should not support variadic parameters
1488        if params.iter().any(|p| p.is_variadic) {
1489            return Err(SyntaxError::MacroParametersCannotBeVariadic(
1490                (*self.token_arena[macro_token_id]).clone(),
1491            ));
1492        }
1493
1494        self.consume_colon();
1495
1496        let expr = match self.tokens.next() {
1497            Some(token) => self.parse_expr(token)?,
1498            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1499        };
1500
1501        Ok(Shared::new(Node {
1502            token_id: macro_token_id,
1503            expr: Shared::new(Expr::Macro(
1504                IdentWithToken::new_with_token(ident, ident_token.map(Shared::clone)),
1505                params,
1506                expr,
1507            )),
1508        }))
1509    }
1510
1511    fn parse_block(&mut self, do_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1512        let do_token_id = self.token_arena.alloc(Shared::clone(do_token));
1513        let program = self.parse_program(false)?;
1514
1515        // The End token is already consumed by parse_program when it encounters it
1516        // No need to expect another End token here
1517
1518        Ok(Shared::new(Node {
1519            token_id: do_token_id,
1520            expr: Shared::new(Expr::Block(program)),
1521        }))
1522    }
1523
1524    fn parse_fn(&mut self, fn_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1525        let fn_token_id = self.token_arena.alloc(Shared::clone(fn_token));
1526        let params = self.parse_params()?;
1527
1528        self.consume_colon_or_do();
1529
1530        let program = self.parse_program(false)?;
1531
1532        let fn_node = Shared::new(Node {
1533            token_id: fn_token_id,
1534            expr: Shared::new(Expr::Fn(params, program)),
1535        });
1536
1537        // Handle postfix operations: fn(...): ... end(args), fn(...): ... end(args)[N], etc.
1538        self.parse_postfix_ops(fn_node, fn_token)
1539    }
1540
1541    fn parse_while(&mut self, while_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1542        let token_id = self.token_arena.alloc(Shared::clone(while_token));
1543        let args = self.parse_args()?;
1544
1545        if args.len() != 1 {
1546            return Err(SyntaxError::UnexpectedToken((**while_token).clone()));
1547        }
1548
1549        self.consume_colon_or_do();
1550
1551        match self.tokens.peek() {
1552            Some(_) => {
1553                let cond = args.first().unwrap();
1554                let body_program = self.parse_program(false)?;
1555
1556                Ok(Shared::new(Node {
1557                    token_id,
1558                    expr: Shared::new(Expr::While(
1559                        Shared::clone(cond),
1560                        body_program.iter().map(Shared::clone).collect(),
1561                    )),
1562                }))
1563            }
1564            None => Err(SyntaxError::UnexpectedToken((**while_token).clone())),
1565        }
1566    }
1567
1568    fn parse_loop(&mut self, loop_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1569        let token_id = self.token_arena.alloc(Shared::clone(loop_token));
1570
1571        self.consume_colon_or_do();
1572
1573        match self.tokens.peek() {
1574            Some(_) => {
1575                let body_program = self.parse_program(false)?;
1576
1577                Ok(Shared::new(Node {
1578                    token_id,
1579                    expr: Shared::new(Expr::Loop(body_program.iter().map(Shared::clone).collect())),
1580                }))
1581            }
1582            None => Err(SyntaxError::UnexpectedToken((**loop_token).clone())),
1583        }
1584    }
1585
1586    fn parse_try(&mut self, try_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1587        let token_id = self.token_arena.alloc(Shared::clone(try_token));
1588
1589        self.consume_colon_or_do();
1590
1591        // Parse try expression
1592        let try_expr = match self.tokens.next() {
1593            Some(token) => self.parse_expr(token)?,
1594            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1595        };
1596
1597        if !self.is_next_token(|token_kind| matches!(token_kind, TokenKind::Catch)) {
1598            return Ok(Shared::new(Node {
1599                token_id,
1600                expr: Shared::new(Expr::Try(
1601                    try_expr,
1602                    Shared::new(Node {
1603                        token_id,
1604                        expr: Shared::new(Expr::Literal(Literal::None)),
1605                    }),
1606                )),
1607            }));
1608        }
1609
1610        // Expect 'catch' keyword
1611        self.next_token(|token_kind| matches!(token_kind, TokenKind::Catch))?;
1612        self.consume_colon_or_do();
1613
1614        // Parse catch expression
1615        let catch_expr = match self.tokens.next() {
1616            Some(token) => self.parse_expr(token)?,
1617            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1618        };
1619
1620        Ok(Shared::new(Node {
1621            token_id,
1622            expr: Shared::new(Expr::Try(try_expr, catch_expr)),
1623        }))
1624    }
1625
1626    fn parse_quote(&mut self, quote_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1627        let token_id = self.token_arena.alloc(Shared::clone(quote_token));
1628
1629        self.consume_colon();
1630
1631        let expr = match self.tokens.next() {
1632            Some(token) => self.parse_expr(token)?,
1633            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1634        };
1635
1636        Ok(Shared::new(Node {
1637            token_id,
1638            expr: Shared::new(Expr::Quote(expr)),
1639        }))
1640    }
1641
1642    fn parse_unquote(&mut self, unquote_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1643        let token_id = self.token_arena.alloc(Shared::clone(unquote_token));
1644
1645        let args = self.parse_args()?;
1646
1647        if args.len() != 1 {
1648            return Err(SyntaxError::UnexpectedToken((*self.token_arena[token_id]).clone()));
1649        }
1650
1651        let expr = Shared::clone(args.first().unwrap());
1652
1653        Ok(Shared::new(Node {
1654            token_id,
1655            expr: Shared::new(Expr::Unquote(expr)),
1656        }))
1657    }
1658
1659    fn parse_foreach(&mut self, foreach_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1660        let args = self.parse_args()?;
1661
1662        if args.len() != 2 {
1663            return Err(SyntaxError::UnexpectedToken((**foreach_token).clone()));
1664        }
1665
1666        let first_arg = &*args.first().unwrap().expr;
1667
1668        match first_arg {
1669            Expr::Ident(IdentWithToken {
1670                name: ident,
1671                token: ident_token,
1672            }) => {
1673                self.consume_colon_or_do();
1674
1675                let each_values = Shared::clone(&args[1]);
1676                let body_program = self.parse_program(false)?;
1677
1678                Ok(Shared::new(Node {
1679                    token_id: self.token_arena.alloc(Shared::clone(foreach_token)),
1680                    expr: Shared::new(Expr::Foreach(
1681                        IdentWithToken {
1682                            name: *ident,
1683                            token: ident_token.clone(),
1684                        },
1685                        Shared::clone(&each_values),
1686                        body_program.iter().map(Shared::clone).collect(),
1687                    )),
1688                }))
1689            }
1690            _ => Err(SyntaxError::UnexpectedToken((**foreach_token).clone())),
1691        }
1692    }
1693
1694    fn parse_if(&mut self, if_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1695        let token_id = self.token_arena.alloc(Shared::clone(if_token));
1696        let args = self.parse_args()?;
1697
1698        if args.len() != 1 {
1699            return Err(SyntaxError::UnexpectedToken((*self.token_arena[token_id]).clone()));
1700        }
1701        let cond = args.first().unwrap();
1702
1703        self.consume_colon();
1704
1705        let then_expr = self.parse_next_expr(token_id)?;
1706
1707        let mut branches: Branches = SmallVec::new();
1708        branches.push((Some(Shared::clone(cond)), then_expr));
1709
1710        let elif_branches = self.parse_elif()?;
1711        branches.extend(elif_branches);
1712
1713        if let Some(token) = self.tokens.peek()
1714            && matches!(token.kind, TokenKind::Else)
1715        {
1716            let token_id = self.next_token(|token_kind| matches!(token_kind, TokenKind::Else))?;
1717
1718            self.consume_colon();
1719
1720            let else_expr = self.parse_next_expr(token_id)?;
1721            branches.push((None, else_expr));
1722        }
1723
1724        Ok(Shared::new(Node {
1725            token_id: self.token_arena.alloc(Shared::clone(if_token)),
1726            expr: Shared::new(Expr::If(branches)),
1727        }))
1728    }
1729
1730    fn parse_match(&mut self, match_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
1731        let token_id = self.token_arena.alloc(Shared::clone(match_token));
1732
1733        // Parse the value expression: match (value):
1734        let args = self.parse_args()?;
1735        if args.len() != 1 {
1736            return Err(SyntaxError::UnexpectedToken((*self.token_arena[token_id]).clone()));
1737        }
1738        let value = Shared::clone(args.first().unwrap());
1739
1740        self.consume_colon_or_do();
1741
1742        // Parse match arms
1743        let mut arms: super::node::MatchArms = SmallVec::new();
1744
1745        while let Some(token) = self.tokens.peek() {
1746            // Check for end of match
1747            if matches!(token.kind, TokenKind::End | TokenKind::Eof) {
1748                break;
1749            }
1750
1751            // Consume pipe '|' before each arm
1752            let token_id = self.next_token(|token_kind| matches!(token_kind, TokenKind::Pipe))?;
1753            // Parse pattern
1754            let pattern = self.parse_pattern()?;
1755            // Check for guard (if condition)
1756            let guard = if let Some(token) = self.tokens.peek() {
1757                if matches!(token.kind, TokenKind::If) {
1758                    let if_token = Shared::clone(token);
1759                    self.tokens.next(); // consume 'if'
1760                    let guard_args = self.parse_args()?;
1761                    if guard_args.len() != 1 {
1762                        return Err(SyntaxError::UnexpectedToken((*if_token).clone()));
1763                    }
1764                    Some(Shared::clone(guard_args.first().unwrap()))
1765                } else {
1766                    None
1767                }
1768            } else {
1769                None
1770            };
1771
1772            self.consume_colon();
1773
1774            // Parse body expression
1775            let body = self.parse_next_expr(token_id)?;
1776
1777            arms.push(MatchArm { pattern, guard, body });
1778        }
1779
1780        // Consume 'end' keyword
1781        if let Some(token) = self.tokens.peek()
1782            && matches!(token.kind, TokenKind::End)
1783        {
1784            self.tokens.next();
1785        }
1786
1787        Ok(Shared::new(Node {
1788            token_id,
1789            expr: Shared::new(Expr::Match(value, arms)),
1790        }))
1791    }
1792
1793    fn parse_pattern(&mut self) -> Result<Pattern, SyntaxError> {
1794        let first = self.parse_single_pattern()?;
1795        if !matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::Or)) {
1796            return Ok(first);
1797        }
1798        let mut patterns = vec![first];
1799        while matches!(self.tokens.peek().map(|t| &t.kind), Some(TokenKind::Or)) {
1800            self.tokens.next(); // consume ||
1801            patterns.push(self.parse_single_pattern()?);
1802        }
1803        Ok(Pattern::Or(patterns))
1804    }
1805
1806    fn parse_single_pattern(&mut self) -> Result<Pattern, SyntaxError> {
1807        let token = match self.tokens.next() {
1808            Some(t) => t,
1809            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1810        };
1811
1812        match &token.kind {
1813            // Wildcard pattern: _
1814            TokenKind::Ident(name) if name == constants::identifiers::PATTERN_MATCH_WILDCARD => Ok(Pattern::Wildcard),
1815            // Type pattern: :string, :number, etc.
1816            TokenKind::Colon => {
1817                let type_token = match self.tokens.next() {
1818                    Some(t) => t,
1819                    None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1820                };
1821                match &type_token.kind {
1822                    TokenKind::Ident(type_name) => Ok(Pattern::Type(Ident::new(type_name))),
1823                    _ => Err(SyntaxError::UnexpectedToken((**type_token).clone())),
1824                }
1825            }
1826            // Literal patterns
1827            TokenKind::StringLiteral(s) => Ok(Pattern::Literal(Literal::String(s.clone()))),
1828            TokenKind::BytesLiteral(b) => Ok(Pattern::Literal(Literal::Bytes(b.clone()))),
1829            TokenKind::NumberLiteral(n) => Ok(Pattern::Literal(Literal::Number(*n))),
1830            TokenKind::BoolLiteral(b) => Ok(Pattern::Literal(Literal::Bool(*b))),
1831            TokenKind::None => Ok(Pattern::Literal(Literal::None)),
1832            // Array pattern: [pattern, pattern, ...]
1833            TokenKind::LBracket => self.parse_array_pattern(),
1834            // Dict pattern: {key, key: pattern}
1835            TokenKind::LBrace => self.parse_dict_pattern(),
1836            // Identifier pattern (binding)
1837            TokenKind::Ident(name) => Ok(Pattern::Ident(IdentWithToken::new(name))),
1838            _ => Err(SyntaxError::UnexpectedToken((**token).clone())),
1839        }
1840    }
1841
1842    fn parse_array_pattern(&mut self) -> Result<super::node::Pattern, SyntaxError> {
1843        let mut patterns = Vec::new();
1844        let mut has_rest = false;
1845        let mut rest_binding: Option<IdentWithToken> = None;
1846
1847        loop {
1848            // Check for closing bracket
1849            if let Some(token) = self.tokens.peek() {
1850                if matches!(token.kind, TokenKind::RBracket) {
1851                    self.tokens.next(); // consume ]
1852                    break;
1853                }
1854
1855                // Check for rest pattern: ...rest
1856                if matches!(token.kind, TokenKind::DoubleDot) {
1857                    self.tokens.next();
1858                    if let Some(ident_token) = self.tokens.next() {
1859                        if let TokenKind::Ident(name) = &ident_token.kind {
1860                            rest_binding = Some(IdentWithToken::new(name));
1861                            has_rest = true;
1862                        } else {
1863                            return Err(SyntaxError::UnexpectedToken((**ident_token).clone()));
1864                        }
1865                    }
1866                    // Expect closing bracket after rest
1867                    if let Some(token) = self.tokens.next()
1868                        && !matches!(token.kind, TokenKind::RBracket)
1869                    {
1870                        return Err(SyntaxError::UnexpectedToken((**token).clone()));
1871                    }
1872                    break;
1873                }
1874            }
1875
1876            let pattern = self.parse_pattern()?;
1877            patterns.push(pattern);
1878
1879            // Check for comma or closing bracket
1880            if let Some(token) = self.tokens.peek() {
1881                if matches!(token.kind, TokenKind::Comma) {
1882                    self.tokens.next(); // consume comma
1883                } else if matches!(token.kind, TokenKind::RBracket) {
1884                    // Will be consumed in next iteration
1885                    continue;
1886                } else {
1887                    return Err(SyntaxError::UnexpectedToken((***token).clone()));
1888                }
1889            }
1890        }
1891
1892        if has_rest {
1893            Ok(Pattern::ArrayRest(patterns, rest_binding.unwrap()))
1894        } else {
1895            Ok(Pattern::Array(patterns))
1896        }
1897    }
1898
1899    fn parse_dict_pattern(&mut self) -> Result<super::node::Pattern, SyntaxError> {
1900        let mut fields = Vec::new();
1901
1902        loop {
1903            // Check for closing brace
1904            if let Some(token) = self.tokens.peek()
1905                && matches!(token.kind, TokenKind::RBrace)
1906            {
1907                self.tokens.next(); // consume }
1908                break;
1909            }
1910
1911            // Parse key (must be identifier)
1912            let key_token = match self.tokens.next() {
1913                Some(t) => t,
1914                None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1915            };
1916
1917            let key = match &key_token.kind {
1918                TokenKind::Ident(name) => IdentWithToken::new(name),
1919                _ => return Err(SyntaxError::UnexpectedToken((**key_token).clone())),
1920            };
1921
1922            // Check if there's a colon (key: pattern) or just key shorthand
1923            let pattern = if let Some(token) = self.tokens.peek() {
1924                if matches!(token.kind, TokenKind::Colon) {
1925                    self.tokens.next(); // consume colon
1926                    self.parse_pattern()?
1927                } else {
1928                    // Shorthand: {key} means {key: key}
1929                    super::node::Pattern::Ident(key.clone())
1930                }
1931            } else {
1932                super::node::Pattern::Ident(key.clone())
1933            };
1934
1935            fields.push((key, pattern));
1936
1937            // Check for comma or closing brace
1938            if let Some(token) = self.tokens.peek() {
1939                if matches!(token.kind, TokenKind::Comma) {
1940                    self.tokens.next(); // consume comma
1941                } else if matches!(token.kind, TokenKind::RBrace) {
1942                    // Will be consumed in next iteration
1943                    continue;
1944                } else {
1945                    return Err(SyntaxError::UnexpectedToken((***token).clone()));
1946                }
1947            }
1948        }
1949
1950        Ok(super::node::Pattern::Dict(fields))
1951    }
1952
1953    #[inline(always)]
1954    fn parse_next_expr(&mut self, token_id: TokenId) -> Result<Shared<Node>, SyntaxError> {
1955        let expr_token = match self.tokens.next() {
1956            Some(token) => Ok(token),
1957            None => Err(SyntaxError::UnexpectedToken((*self.token_arena[token_id]).clone())),
1958        }?;
1959
1960        self.parse_expr(expr_token)
1961    }
1962
1963    fn parse_elif(&mut self) -> Result<Vec<IfExpr>, SyntaxError> {
1964        let mut nodes = Vec::with_capacity(8);
1965
1966        while let Some(token) = self.tokens.peek() {
1967            if !matches!(token.kind, TokenKind::Elif) {
1968                break;
1969            }
1970
1971            let token_id = self.next_token(|token_kind| matches!(token_kind, TokenKind::Elif))?;
1972            let args = self.parse_args()?;
1973
1974            if args.len() != 1 {
1975                return Err(SyntaxError::UnexpectedToken((*self.token_arena[token_id]).clone()));
1976            }
1977
1978            self.consume_colon();
1979
1980            let expr_token = match self.tokens.next() {
1981                Some(token) => Ok(token),
1982                None => Err(SyntaxError::UnexpectedToken((*self.token_arena[token_id]).clone())),
1983            }?;
1984
1985            let cond = args.first().unwrap();
1986            let then_expr = self.parse_expr(expr_token)?;
1987
1988            nodes.push((Some(Shared::clone(cond)), then_expr));
1989        }
1990
1991        Ok(nodes)
1992    }
1993
1994    fn parse_let_or_var_pattern(&mut self) -> Result<Pattern, SyntaxError> {
1995        // Clone kind to release the peek borrow before calling next()
1996        let token_kind = match self.tokens.peek() {
1997            Some(t) => t.kind.clone(),
1998            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
1999        };
2000        match token_kind {
2001            TokenKind::LBracket => {
2002                self.tokens.next(); // consume [
2003                self.parse_array_pattern()
2004            }
2005            TokenKind::LBrace => {
2006                self.tokens.next(); // consume {
2007                self.parse_dict_pattern()
2008            }
2009            TokenKind::Ident(ref name) => {
2010                let ident_token = self.tokens.next().unwrap();
2011                Ok(Pattern::Ident(IdentWithToken::new_with_token(
2012                    name,
2013                    Some(Shared::clone(ident_token)),
2014                )))
2015            }
2016            _ => {
2017                let bad_token = self.tokens.next().unwrap();
2018                Err(SyntaxError::UnexpectedToken((**bad_token).clone()))
2019            }
2020        }
2021    }
2022
2023    fn parse_let(&mut self, let_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2024        let let_token_id = self.token_arena.alloc(Shared::clone(let_token));
2025        let pattern = self.parse_let_or_var_pattern()?;
2026
2027        self.next_token(|token_kind| matches!(token_kind, TokenKind::Equal))?;
2028        let expr_token = match self.tokens.next() {
2029            Some(token) => Ok(token),
2030            None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2031        }?;
2032
2033        if matches!(expr_token.kind, TokenKind::Let | TokenKind::Var) {
2034            return Err(SyntaxError::UnexpectedToken((**expr_token).clone()));
2035        }
2036
2037        let ast = self.parse_expr(expr_token)?;
2038
2039        if let Some(token) = self.tokens.peek()
2040            && !matches!(
2041                token.kind,
2042                TokenKind::Pipe | TokenKind::Eof | TokenKind::SemiColon | TokenKind::End
2043            )
2044        {
2045            return Err(SyntaxError::UnexpectedToken((***token).clone()));
2046        }
2047
2048        Ok(Shared::new(Node {
2049            token_id: let_token_id,
2050            expr: Shared::new(Expr::Let(pattern, ast)),
2051        }))
2052    }
2053
2054    fn parse_var(&mut self, var_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2055        let var_token_id = self.token_arena.alloc(Shared::clone(var_token));
2056        let pattern = self.parse_let_or_var_pattern()?;
2057
2058        self.next_token(|token_kind| matches!(token_kind, TokenKind::Equal))?;
2059        let expr_token = match self.tokens.next() {
2060            Some(token) => Ok(token),
2061            None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2062        }?;
2063
2064        if matches!(expr_token.kind, TokenKind::Let | TokenKind::Var) {
2065            return Err(SyntaxError::UnexpectedToken((**expr_token).clone()));
2066        }
2067
2068        let ast = self.parse_expr(expr_token)?;
2069
2070        if let Some(token) = self.tokens.peek()
2071            && !matches!(
2072                token.kind,
2073                TokenKind::Pipe | TokenKind::Eof | TokenKind::SemiColon | TokenKind::End
2074            )
2075        {
2076            return Err(SyntaxError::UnexpectedToken((***token).clone()));
2077        }
2078
2079        Ok(Shared::new(Node {
2080            token_id: var_token_id,
2081            expr: Shared::new(Expr::Var(pattern, ast)),
2082        }))
2083    }
2084
2085    #[inline(always)]
2086    fn parse_include(&mut self, include_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2087        match self.tokens.peek() {
2088            Some(token) => match &token.kind {
2089                TokenKind::StringLiteral(module) => {
2090                    self.tokens.next();
2091                    Ok(Shared::new(Node {
2092                        token_id: self.token_arena.alloc(Shared::clone(include_token)),
2093                        expr: Shared::new(Expr::Include(Literal::String(module.to_owned()))),
2094                    }))
2095                }
2096                _ => Err(SyntaxError::InsufficientTokens((***token).clone())),
2097            },
2098            None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2099        }
2100    }
2101
2102    #[inline(always)]
2103    fn parse_import(&mut self, import_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2104        let token_id = self.token_arena.alloc(Shared::clone(import_token));
2105        let token = match self.tokens.next() {
2106            Some(token) => Ok(Shared::clone(token)),
2107            None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2108        }?;
2109
2110        match &token.kind {
2111            TokenKind::StringLiteral(module) => {
2112                let module_name = module.to_owned();
2113                Ok(Shared::new(Node {
2114                    token_id,
2115                    expr: Shared::new(Expr::Import(Literal::String(module_name))),
2116                }))
2117            }
2118            _ => Err(SyntaxError::InsufficientTokens((*token).clone())),
2119        }
2120    }
2121
2122    fn parse_interpolated_string(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2123        if let TokenKind::InterpolatedString(segments) = &token.kind {
2124            let mut parsed_segments = Vec::new();
2125
2126            for segment in segments {
2127                match segment {
2128                    lexer::token::StringSegment::Text(text, _) => {
2129                        parsed_segments.push(super::node::StringSegment::Text(text.clone()));
2130                    }
2131                    lexer::token::StringSegment::Expr(expr_str, range) => {
2132                        // Parse the expression string
2133                        let expr_str = expr_str.trim();
2134
2135                        // Handle special cases first
2136                        if expr_str == constants::identifiers::SELF {
2137                            parsed_segments.push(super::node::StringSegment::Self_);
2138                        } else if let Some(stripped) = expr_str.strip_prefix("$") {
2139                            // Environment variable
2140                            parsed_segments.push(super::node::StringSegment::Env(SmolStr::from(stripped)));
2141                        } else {
2142                            // Parse as a full expression
2143                            let lexer = Lexer::new(crate::lexer::Options::default());
2144                            let tokens = lexer.tokenize(expr_str, token.module_id).map_err(|_| {
2145                                SyntaxError::UnexpectedToken(Token {
2146                                    range: *range,
2147                                    kind: TokenKind::InterpolatedString(vec![]),
2148                                    module_id: token.module_id,
2149                                })
2150                            })?;
2151
2152                            let shared_tokens: Vec<Shared<Token>> = tokens.into_iter().map(Shared::new).collect();
2153                            let mut parser = Parser::new(shared_tokens.iter(), self.token_arena, token.module_id);
2154                            let expr_node = parser.parse_expr_from_tokens().map_err(|_| {
2155                                SyntaxError::UnexpectedToken(Token {
2156                                    range: *range,
2157                                    kind: TokenKind::InterpolatedString(vec![]),
2158                                    module_id: token.module_id,
2159                                })
2160                            })?;
2161
2162                            parsed_segments.push(super::node::StringSegment::Expr(expr_node));
2163                        }
2164                    }
2165                }
2166            }
2167
2168            Ok(Shared::new(Node {
2169                token_id: self.token_arena.alloc(Shared::clone(token)),
2170                expr: Shared::new(Expr::InterpolatedString(parsed_segments)),
2171            }))
2172        } else {
2173            Err(SyntaxError::UnexpectedToken((**token).clone()))
2174        }
2175    }
2176
2177    #[inline(always)]
2178    fn parse_expr_from_tokens(&mut self) -> Result<Shared<Node>, SyntaxError> {
2179        if let Some(token) = self.tokens.next() {
2180            self.parse_expr(token)
2181        } else {
2182            Err(SyntaxError::UnexpectedEOFDetected(self.module_id))
2183        }
2184    }
2185
2186    /// Parse function parameters (supports default values)
2187    fn parse_params(&mut self) -> Result<Params, SyntaxError> {
2188        let opening_paren = match self.tokens.peek() {
2189            Some(token) => match &token.kind {
2190                TokenKind::LParen => {
2191                    let t = (***token).clone();
2192                    self.tokens.next();
2193                    Some(t)
2194                }
2195                _ => return Err(SyntaxError::UnexpectedToken((***token).clone())),
2196            },
2197            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2198        };
2199
2200        let mut params: Params = SmallVec::new();
2201        let mut prev_token: Option<&TokenKind> = None;
2202        let mut seen_default = false;
2203        let mut seen_variadic = false;
2204
2205        while let Some(token) = self.tokens.next() {
2206            match &token.kind {
2207                TokenKind::RParen => match prev_token {
2208                    Some(TokenKind::Comma) => {
2209                        return Err(SyntaxError::UnexpectedToken((**token).clone()));
2210                    }
2211                    _ => break,
2212                },
2213                TokenKind::Eof => match prev_token {
2214                    Some(TokenKind::RParen) => break,
2215                    Some(_) | None => {
2216                        return Err(SyntaxError::ExpectedClosingParen(
2217                            (**token).clone(),
2218                            opening_paren.clone().map(Box::new),
2219                        ));
2220                    }
2221                },
2222                TokenKind::Comma => match prev_token {
2223                    Some(_) => {
2224                        let token = match self.tokens.peek() {
2225                            Some(token) => Ok(Shared::clone(token)),
2226                            None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2227                        }?;
2228                        match &token.kind {
2229                            TokenKind::Comma => {
2230                                return Err(SyntaxError::UnexpectedToken((*token).clone()));
2231                            }
2232                            _ => continue,
2233                        }
2234                    }
2235                    None => return Err(SyntaxError::UnexpectedToken((**token).clone())),
2236                },
2237                TokenKind::SemiColon => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2238                TokenKind::Asterisk => {
2239                    // Variadic parameter: *name
2240                    if seen_variadic {
2241                        return Err(SyntaxError::MultipleVariadicParameters((**token).clone()));
2242                    }
2243                    let ident_token = match self.tokens.next() {
2244                        Some(t) => t,
2245                        None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2246                    };
2247                    match &ident_token.kind {
2248                        TokenKind::Ident(name) => {
2249                            let ident = IdentWithToken::new_with_token(name, Some(Shared::clone(ident_token)));
2250                            params.push(Param::variadic(ident));
2251                            seen_variadic = true;
2252                        }
2253                        _ => {
2254                            return Err(SyntaxError::UnexpectedToken((**ident_token).clone()));
2255                        }
2256                    }
2257                }
2258                TokenKind::Ident(name) => {
2259                    // Non-variadic param after variadic is an error
2260                    if seen_variadic {
2261                        return Err(SyntaxError::VariadicParameterMustBeLast((**token).clone()));
2262                    }
2263
2264                    // Parse parameter name
2265                    let ident = IdentWithToken::new_with_token(name, Some(Shared::clone(token)));
2266
2267                    // Check for '=' indicating a default value
2268                    let default = if let Some(next_token) = self.tokens.peek()
2269                        && matches!(next_token.kind, TokenKind::Equal)
2270                    {
2271                        self.tokens.next(); // consume '='
2272                        seen_default = true;
2273
2274                        // Parse default value expression
2275                        let default_token = match self.tokens.next() {
2276                            Some(t) => t,
2277                            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2278                        };
2279
2280                        Some(self.parse_expr(default_token)?)
2281                    } else {
2282                        if seen_default {
2283                            return Err(SyntaxError::ParameterWithoutDefaultAfterDefault((**token).clone()));
2284                        }
2285                        None
2286                    };
2287
2288                    params.push(Param::with_default(ident, default));
2289                }
2290                _ => {
2291                    return Err(SyntaxError::UnexpectedToken((**token).clone()));
2292                }
2293            }
2294
2295            prev_token = Some(&token.kind);
2296
2297            if let Some(token) = self.tokens.peek()
2298                && !matches!(token.kind, TokenKind::RParen | TokenKind::Comma)
2299            {
2300                return Err(SyntaxError::ExpectedClosingParen(
2301                    (***token).clone(),
2302                    opening_paren.clone().map(Box::new),
2303                ));
2304            }
2305        }
2306
2307        Ok(params)
2308    }
2309
2310    fn parse_args(&mut self) -> Result<Args, SyntaxError> {
2311        let opening_paren = match self.tokens.peek() {
2312            Some(token) => match &token.kind {
2313                TokenKind::LParen => {
2314                    let t = (***token).clone();
2315                    self.tokens.next();
2316                    Some(t)
2317                }
2318                _ => return Err(SyntaxError::UnexpectedToken((***token).clone())),
2319            },
2320            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2321        };
2322
2323        let mut args: Args = SmallVec::new();
2324        let mut prev_token: Option<&TokenKind> = None;
2325
2326        while let Some(token) = self.tokens.next() {
2327            match &token.kind {
2328                TokenKind::RParen => match prev_token {
2329                    Some(TokenKind::Comma) => {
2330                        return Err(SyntaxError::UnexpectedToken((**token).clone()));
2331                    }
2332                    _ => break,
2333                },
2334                TokenKind::Eof => match prev_token {
2335                    Some(TokenKind::RParen) => break,
2336                    Some(_) | None => {
2337                        return Err(SyntaxError::ExpectedClosingParen(
2338                            (**token).clone(),
2339                            opening_paren.clone().map(Box::new),
2340                        ));
2341                    }
2342                },
2343                TokenKind::Comma => match prev_token {
2344                    Some(_) => {
2345                        let token = match self.tokens.peek() {
2346                            Some(token) => Ok(Shared::clone(token)),
2347                            None => Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2348                        }?;
2349                        match &token.kind {
2350                            TokenKind::Comma => {
2351                                return Err(SyntaxError::UnexpectedToken((*token).clone()));
2352                            }
2353                            _ => continue,
2354                        }
2355                    }
2356                    None => return Err(SyntaxError::UnexpectedToken((**token).clone())),
2357                },
2358                TokenKind::SemiColon => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2359                _ => {
2360                    // Arguments that are complex expressions (idents, selectors, if, fn)
2361                    args.push(self.parse_arg_expr(token)?);
2362                }
2363            }
2364
2365            prev_token = Some(&token.kind);
2366
2367            if let Some(token) = self.tokens.peek()
2368                && !matches!(token.kind, TokenKind::RParen | TokenKind::Comma)
2369            {
2370                return Err(SyntaxError::ExpectedClosingParen(
2371                    (***token).clone(),
2372                    opening_paren.clone().map(Box::new),
2373                ));
2374            }
2375        }
2376
2377        Ok(args)
2378    }
2379
2380    // Helper to parse an argument that is expected to be a general expression.
2381    // This typically involves a recursive call to `parse_expr`.
2382    #[inline(always)]
2383    fn parse_arg_expr(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2384        self.parse_expr(token)
2385    }
2386
2387    fn parse_set_attr_call_with_selector(
2388        &mut self,
2389        selector_node: Shared<Node>,
2390        attr_literal: Shared<Node>,
2391    ) -> Result<Shared<Node>, SyntaxError> {
2392        let token = match self.tokens.next() {
2393            Some(token) => token,
2394            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2395        };
2396        let value = self.parse_expr(token)?;
2397
2398        // Create the set_attr() function call
2399        Ok(Shared::new(Node {
2400            token_id: self.token_arena.alloc(Shared::clone(token)),
2401            expr: Shared::new(Expr::Call(
2402                IdentWithToken::new_with_token(constants::builtins::SET_ATTR, Some(Shared::clone(token))),
2403                smallvec![selector_node, attr_literal, value],
2404            )),
2405        }))
2406    }
2407
2408    /// Build an attr() call given a pre-built base node and an attribute selector token.
2409    fn build_attr_call_for_node(
2410        &mut self,
2411        base_node: Shared<Node>,
2412        attr_token: Shared<Token>,
2413        token: &Shared<Token>,
2414    ) -> Result<Shared<Node>, SyntaxError> {
2415        if let TokenKind::Selector(attr_selector) = &attr_token.kind {
2416            if !Selector::try_from(&*attr_token)
2417                .map_err(SyntaxError::UnknownSelector)?
2418                .is_attribute_selector()
2419            {
2420                return Err(SyntaxError::UnexpectedToken((*attr_token).clone()));
2421            }
2422
2423            let attribute = &attr_selector[1..]; // Skip the dot
2424            let attr_literal = Shared::new(Node {
2425                token_id: self.token_arena.alloc(Shared::clone(token)),
2426                expr: Shared::new(Expr::Literal(Literal::String(attribute.to_string()))),
2427            });
2428
2429            if self.is_next_token(|kind| matches!(kind, TokenKind::PipeEqual)) {
2430                self.tokens.next(); // consume '|=' token
2431                return self.parse_set_attr_call_with_selector(base_node, attr_literal);
2432            }
2433
2434            Ok(Shared::new(Node {
2435                token_id: self.token_arena.alloc(Shared::clone(token)),
2436                expr: Shared::new(Expr::Call(
2437                    IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::clone(token))),
2438                    smallvec![base_node, attr_literal],
2439                )),
2440            }))
2441        } else {
2442            Err(SyntaxError::UnexpectedToken((**token).clone()))
2443        }
2444    }
2445
2446    /// Parse a selector with an attribute suffix and convert it to an attr() function call
2447    fn parse_selector_with_attribute(
2448        &mut self,
2449        token: &Shared<Token>,
2450        attr_token: Shared<Token>,
2451    ) -> Result<Shared<Node>, SyntaxError> {
2452        let base_node = self.parse_selector_direct(token)?;
2453        self.build_attr_call_for_node(base_node, attr_token, token)
2454    }
2455
2456    /// Parse a selector without checking for attributes (to avoid infinite recursion)
2457    fn parse_selector_direct(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2458        match &token.kind {
2459            TokenKind::Selector(selector) => {
2460                if selector == "." {
2461                    if self.is_next_token(|token_kind| matches!(token_kind, TokenKind::LBracket)) {
2462                        self.parse_selector_table_args(Shared::clone(token))
2463                    } else {
2464                        Ok(Shared::new(Node {
2465                            token_id: self.token_arena.alloc(Shared::clone(token)),
2466                            expr: Shared::new(Expr::Self_),
2467                        }))
2468                    }
2469                } else {
2470                    let selector = Selector::try_from(&**token).map_err(SyntaxError::UnknownSelector)?;
2471
2472                    if selector.is_attribute_selector() {
2473                        let token_id = self.token_arena.alloc(Shared::clone(token));
2474                        let self_node = Shared::new(Node {
2475                            token_id,
2476                            expr: Shared::new(Expr::Self_),
2477                        });
2478                        let attr_literal = Shared::new(Node {
2479                            token_id,
2480                            expr: Shared::new(Expr::Literal(Literal::String(selector.name()))),
2481                        });
2482                        if self.is_next_token(|kind| matches!(kind, TokenKind::PipeEqual)) {
2483                            self.tokens.next();
2484                            return self.parse_set_attr_call_with_selector(self_node, attr_literal);
2485                        }
2486                        return Ok(Shared::new(Node {
2487                            token_id,
2488                            expr: Shared::new(Expr::Call(
2489                                IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::clone(token))),
2490                                smallvec![self_node, attr_literal],
2491                            )),
2492                        }));
2493                    }
2494
2495                    // ."key"[] or ."key"[n]: array iteration/indexing on the property value
2496                    if matches!(selector, Selector::Property(_))
2497                        && self.is_next_token(|kind| matches!(kind, TokenKind::LBracket))
2498                    {
2499                        let prop_node = Shared::new(Node {
2500                            token_id: self.token_arena.alloc(Shared::clone(token)),
2501                            expr: Shared::new(Expr::Selector(selector)),
2502                        });
2503                        return self.parse_property_iterator(token, vec![prop_node]);
2504                    }
2505
2506                    Ok(Shared::new(Node {
2507                        token_id: self.token_arena.alloc(Shared::clone(token)),
2508                        expr: Shared::new(Expr::Selector(selector)),
2509                    }))
2510                }
2511            }
2512            TokenKind::DoubleDot => {
2513                let recursive_node = Shared::new(Node {
2514                    token_id: self.token_arena.alloc(Shared::clone(token)),
2515                    expr: Shared::new(Expr::Selector(Selector::Recursive)),
2516                });
2517                if let Some(next) = self.tokens.peek() {
2518                    match &next.kind {
2519                        // .."key" → recursive descent + Dict key access
2520                        TokenKind::StringLiteral(key) => {
2521                            let key = key.clone();
2522                            let next = self.tokens.next().unwrap();
2523                            let prop_node = Shared::new(Node {
2524                                token_id: self.token_arena.alloc(Shared::clone(next)),
2525                                expr: Shared::new(Expr::Selector(Selector::Property(Ident::new(key.as_str())))),
2526                            });
2527                            return Ok(Shared::new(Node {
2528                                token_id: self.token_arena.alloc(Shared::clone(token)),
2529                                expr: Shared::new(Expr::Block(vec![recursive_node, prop_node])),
2530                            }));
2531                        }
2532                        // ..text, ..h, ..code, etc. → recursive descent + Markdown node-type selector
2533                        // Attribute selectors (.value, .url, .level, etc.) are excluded here;
2534                        // use `.. | .value` instead, which routes through the proper attr() call.
2535                        TokenKind::Ident(name) => {
2536                            let selector_str = format!(".{}", name);
2537                            if let Some(selector) = Selector::from_selector_str(&selector_str)
2538                                && !selector.is_attribute_selector()
2539                            {
2540                                let next = self.tokens.next().unwrap();
2541                                let sel_node = Shared::new(Node {
2542                                    token_id: self.token_arena.alloc(Shared::clone(next)),
2543                                    expr: Shared::new(Expr::Selector(selector)),
2544                                });
2545
2546                                return Ok(Shared::new(Node {
2547                                    token_id: self.token_arena.alloc(Shared::clone(token)),
2548                                    expr: Shared::new(Expr::Block(vec![recursive_node, sel_node])),
2549                                }));
2550                            }
2551                        }
2552                        _ => {}
2553                    }
2554                }
2555                Ok(recursive_node)
2556            }
2557            _ => Err(SyntaxError::InsufficientTokens((**token).clone())),
2558        }
2559    }
2560
2561    fn parse_selector(&mut self, token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2562        // Handle chained property access: .a.b.c → Block([Selector(Property("a")), ...])
2563        if let TokenKind::Selector(_) = &token.kind
2564            && matches!(Selector::try_from(&**token), Ok(Selector::Property(_)))
2565        {
2566            let next_is_property = self
2567                .tokens
2568                .peek()
2569                .is_some_and(|t| matches!(Selector::try_from(&***t), Ok(Selector::Property(_))));
2570            if next_is_property {
2571                return self.parse_chained_property_selectors(token);
2572            }
2573        }
2574
2575        if self.is_next_token(|kind| matches!(kind, TokenKind::Selector(_)))
2576            && let Some(attr_token) = self.tokens.next()
2577        {
2578            return self.parse_selector_with_attribute(token, Shared::clone(attr_token));
2579        }
2580
2581        // Check for selector call: `.h(...)`, `.code(...)`
2582        if self.is_next_token(|kind| matches!(kind, TokenKind::LParen))
2583            && let TokenKind::Selector(s) = &token.kind
2584            && s != "."
2585        {
2586            let selector = Selector::try_from(&**token).map_err(SyntaxError::UnknownSelector)?;
2587            if !selector.is_attribute_selector() {
2588                let args = self.parse_args()?;
2589                let base_node = Shared::new(Node {
2590                    token_id: self.token_arena.alloc(Shared::clone(token)),
2591                    expr: Shared::new(Expr::SelectorCall(selector, args)),
2592                });
2593                // Check for attribute access on SelectorCall: `.h(1).level`
2594                if self.is_next_token(|kind| matches!(kind, TokenKind::Selector(_)))
2595                    && let Some(attr_token) = self.tokens.next()
2596                {
2597                    return self.build_attr_call_for_node(base_node, Shared::clone(attr_token), token);
2598                }
2599                return Ok(base_node);
2600            }
2601        }
2602
2603        self.parse_selector_direct(token)
2604    }
2605
2606    fn parse_chained_property_selectors(&mut self, first_token: &Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2607        let first_sel = Selector::try_from(&**first_token).map_err(SyntaxError::UnknownSelector)?;
2608        let mut nodes: Program = vec![Shared::new(Node {
2609            token_id: self.token_arena.alloc(Shared::clone(first_token)),
2610            expr: Shared::new(Expr::Selector(first_sel)),
2611        })];
2612
2613        while self.is_next_token(|kind| matches!(kind, TokenKind::Selector(_))) {
2614            let next_is_property = self
2615                .tokens
2616                .peek()
2617                .is_some_and(|t| matches!(Selector::try_from(&***t), Ok(Selector::Property(_))));
2618            if !next_is_property {
2619                break;
2620            }
2621            let next_token = self.tokens.next().unwrap();
2622            let sel = Selector::try_from(&**next_token).map_err(SyntaxError::UnknownSelector)?;
2623            nodes.push(Shared::new(Node {
2624                token_id: self.token_arena.alloc(Shared::clone(next_token)),
2625                expr: Shared::new(Expr::Selector(sel)),
2626            }));
2627        }
2628
2629        // ."a"."b"[] or ."a"."b"[n]: array iteration/indexing after a chained property access
2630        if self.is_next_token(|kind| matches!(kind, TokenKind::LBracket)) {
2631            return self.parse_property_iterator(first_token, nodes);
2632        }
2633
2634        Ok(Shared::new(Node {
2635            token_id: self.token_arena.alloc(Shared::clone(first_token)),
2636            expr: Shared::new(Expr::Block(nodes)),
2637        }))
2638    }
2639
2640    fn parse_property_iterator(
2641        &mut self,
2642        token: &Shared<Token>,
2643        mut nodes: Program,
2644    ) -> Result<Shared<Node>, SyntaxError> {
2645        let index = self.parse_bracket_expr()?;
2646
2647        let list_selector = match &index {
2648            None => Selector::List(None, None),
2649            Some(node) => {
2650                if let Expr::Literal(Literal::Number(num)) = &*node.expr {
2651                    Selector::List(Some(num.value() as usize), None)
2652                } else {
2653                    // Dynamic index expression: emit a SelectorCall so the index is evaluated at runtime
2654                    let token_id = self.token_arena.alloc(Shared::clone(token));
2655                    nodes.push(Shared::new(Node {
2656                        token_id,
2657                        expr: Shared::new(Expr::SelectorCall(
2658                            Selector::List(None, None),
2659                            smallvec![Shared::clone(node)],
2660                        )),
2661                    }));
2662                    return Ok(Shared::new(Node {
2663                        token_id: self.token_arena.alloc(Shared::clone(token)),
2664                        expr: Shared::new(Expr::Block(nodes)),
2665                    }));
2666                }
2667            }
2668        };
2669
2670        nodes.push(Shared::new(Node {
2671            token_id: self.token_arena.alloc(Shared::clone(token)),
2672            expr: Shared::new(Expr::Selector(list_selector)),
2673        }));
2674
2675        Ok(Shared::new(Node {
2676            token_id: self.token_arena.alloc(Shared::clone(token)),
2677            expr: Shared::new(Expr::Block(nodes)),
2678        }))
2679    }
2680
2681    // Parses arguments for table or list item selectors like `.[index1][index2]` (for tables) or `.[index1]` (for lists).
2682    fn parse_selector_table_args(&mut self, token: Shared<Token>) -> Result<Shared<Node>, SyntaxError> {
2683        let first = self.parse_bracket_expr()?;
2684        let has_second = self.is_next_token(|kind| matches!(kind, TokenKind::LBracket));
2685        let second = if has_second {
2686            Some(self.parse_bracket_expr()?)
2687        } else {
2688            None
2689        };
2690
2691        let is_dynamic_node = |opt: &Option<Shared<Node>>| {
2692            opt.as_ref()
2693                .is_some_and(|n| !matches!(&*n.expr, Expr::Literal(Literal::Number(_))))
2694        };
2695        let has_dynamic = is_dynamic_node(&first) || second.as_ref().is_some_and(is_dynamic_node);
2696        let has_explicit_args = self.is_next_token(|kind| matches!(kind, TokenKind::LParen));
2697
2698        if has_dynamic || has_explicit_args {
2699            let is_table = second.is_some();
2700            let selector = if is_table {
2701                Selector::Table(None, None)
2702            } else {
2703                Selector::List(None, None)
2704            };
2705
2706            let mut args: Args = SmallVec::new();
2707
2708            // .[][v]: insert None as row placeholder so args[0]=row, args[1]=col positional encoding holds.
2709            if is_table && first.is_none() && second.as_ref().is_some_and(|s| s.is_some()) {
2710                let placeholder_token_id = self.token_arena.alloc(Shared::clone(&token));
2711                args.push(Shared::new(Node {
2712                    token_id: placeholder_token_id,
2713                    expr: Shared::new(Expr::Literal(Literal::None)),
2714                }));
2715            } else if let Some(node) = first {
2716                args.push(node);
2717            }
2718
2719            if let Some(Some(node)) = second {
2720                args.push(node);
2721            }
2722            if has_explicit_args {
2723                args.extend(self.parse_args()?);
2724            }
2725
2726            let token_id = self.token_arena.alloc(Shared::clone(&token));
2727            return Ok(Shared::new(Node {
2728                token_id,
2729                expr: Shared::new(Expr::SelectorCall(selector, args)),
2730            }));
2731        }
2732
2733        let static_index = |opt: Option<Shared<Node>>| -> Option<usize> {
2734            opt.and_then(|n| {
2735                if let Expr::Literal(Literal::Number(num)) = &*n.expr {
2736                    Some(num.value() as usize)
2737                } else {
2738                    None
2739                }
2740            })
2741        };
2742        let i1 = static_index(first);
2743        let selector = match second {
2744            None => Selector::List(i1, None),
2745            Some(opt) => Selector::Table(i1, static_index(opt)),
2746        };
2747
2748        let token_id = self.token_arena.alloc(Shared::clone(&token));
2749        Ok(Shared::new(Node {
2750            token_id,
2751            expr: Shared::new(Expr::Selector(selector)),
2752        }))
2753    }
2754
2755    fn parse_bracket_expr(&mut self) -> Result<Option<Shared<Node>>, SyntaxError> {
2756        let bracket_token = match self.tokens.peek() {
2757            Some(t) => Shared::clone(t),
2758            None => return Err(SyntaxError::UnexpectedEOFDetected(self.module_id)),
2759        };
2760        self.next_token(|kind| matches!(kind, TokenKind::LBracket))?;
2761
2762        if self.is_next_token(|kind| matches!(kind, TokenKind::RBracket)) {
2763            self.tokens.next();
2764            return Ok(None);
2765        }
2766
2767        let expr_token = match self.tokens.next() {
2768            Some(t) => Shared::clone(t),
2769            None => return Err(SyntaxError::InsufficientTokens((*bracket_token).clone())),
2770        };
2771        let node = self.parse_expr(&expr_token)?;
2772        self.next_token(|kind| matches!(kind, TokenKind::RBracket))?;
2773        Ok(Some(node))
2774    }
2775
2776    fn next_token(&mut self, expected_kinds: fn(&TokenKind) -> bool) -> Result<TokenId, SyntaxError> {
2777        match self.tokens.peek() {
2778            // Token found and matches one of the expected kinds.
2779            Some(token) if expected_kinds(&token.kind) => {
2780                let token = self.tokens.next().unwrap();
2781                Ok(self.token_arena.alloc(Shared::clone(token)))
2782            } // Consume and return.
2783            // Token found but does not match expected kinds.
2784            Some(token) => Err(SyntaxError::UnexpectedToken(Token {
2785                range: token.range,
2786                kind: token.kind.clone(),
2787                module_id: token.module_id,
2788            })),
2789            // No token found (EOF).
2790            None =>
2791            // If EOF is not expected here, it's an error.
2792            {
2793                Err(SyntaxError::UnexpectedEOFDetected(self.module_id))
2794            }
2795        }
2796    }
2797
2798    #[inline(always)]
2799    fn consume_colon(&mut self) {
2800        if self.is_next_token(|token_kind| matches!(token_kind, TokenKind::Colon)) {
2801            let _ = self.next_token(|token_kind| matches!(token_kind, TokenKind::Colon));
2802        }
2803    }
2804
2805    #[inline(always)]
2806    fn consume_colon_or_do(&mut self) {
2807        // Check for 'do' keyword
2808        if self.is_next_token(|kind| matches!(kind, TokenKind::Do)) {
2809            let _ = self.next_token(|kind| matches!(kind, TokenKind::Do));
2810        } else {
2811            self.consume_colon();
2812        }
2813    }
2814}
2815
2816#[cfg(test)]
2817mod tests {
2818    use crate::ast::node::StringSegment;
2819    use crate::{Module, ast::node::MatchArm, range::Range, selector};
2820
2821    use super::*;
2822    use rstest::rstest;
2823    use smallvec::smallvec;
2824
2825    fn token(token_kind: TokenKind) -> Token {
2826        Token {
2827            range: Range::default(),
2828            kind: token_kind,
2829            module_id: 1.into(),
2830        }
2831    }
2832
2833    #[rstest]
2834    #[case::ident1(
2835        vec![
2836            token(TokenKind::Ident(SmolStr::new("and"))),
2837            token(TokenKind::LParen),
2838            token(TokenKind::Ident(SmolStr::new("contains"))),
2839            token(TokenKind::LParen),
2840            token(TokenKind::StringLiteral("test".to_owned())),
2841            token(TokenKind::RParen),
2842            token(TokenKind::Comma),
2843            token(TokenKind::Ident(SmolStr::new("startswith"))),
2844            token(TokenKind::LParen),
2845            token(TokenKind::StringLiteral("test2".to_owned())),
2846            token(TokenKind::RParen),
2847            token(TokenKind::RParen),
2848            token(TokenKind::Eof)
2849        ],
2850        Ok(vec![
2851            Shared::new(Node {
2852                token_id: 4.into(),
2853                expr: Shared::new(Expr::Call(
2854                    IdentWithToken::new_with_token("and", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("and")))))),
2855                    smallvec![
2856                        Shared::new(Node {
2857                            token_id: 1.into(),
2858                            expr: Shared::new(Expr::Call(
2859                                IdentWithToken::new_with_token("contains", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("contains")))))),
2860                                smallvec![Shared::new(Node {
2861                                    token_id: 0.into(),
2862                                    expr: Shared::new(Expr::Literal(Literal::String("test".to_owned())))
2863                                })],
2864                            ))
2865                        }),
2866                        Shared::new(Node {
2867                            token_id: 3.into(),
2868                            expr: Shared::new(Expr::Call(
2869                                IdentWithToken::new_with_token("startswith", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("startswith")))))),
2870                                smallvec![Shared::new(Node {
2871                                    token_id: 2.into(),
2872                                    expr: Shared::new(Expr::Literal(Literal::String("test2".to_owned())))
2873                                })],
2874                            ))
2875                        })
2876                    ],
2877                ))
2878            })
2879        ]))]
2880    #[case::ident2(
2881        vec![
2882            token(TokenKind::Ident(SmolStr::new("and"))),
2883            token(TokenKind::LParen),
2884            token(TokenKind::Selector(SmolStr::new(".h1"))),
2885            token(TokenKind::Comma),
2886            token(TokenKind::Selector(SmolStr::new("."))),
2887            token(TokenKind::LBracket),
2888            token(TokenKind::NumberLiteral(2.into())),
2889            token(TokenKind::RBracket),
2890            token(TokenKind::LBracket),
2891            token(TokenKind::RBracket),
2892            token(TokenKind::RParen),
2893            token(TokenKind::Eof)
2894        ],
2895        Ok(vec![
2896            Shared::new(Node {
2897                token_id: 8.into(),
2898                expr: Shared::new(Expr::Call(
2899                    IdentWithToken::new_with_token("and", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("and")))))),
2900                    smallvec![
2901                        Shared::new(Node {
2902                            token_id: 0.into(),
2903                            expr: Shared::new(Expr::Selector(Selector::Heading(Some(1)))),
2904                        }),
2905                        Shared::new(Node {
2906                            token_id: 5.into(),
2907                            expr: Shared::new(Expr::Selector(Selector::Table(Some(2), None))),
2908                        }),
2909                    ],
2910                ))
2911            })
2912        ]))]
2913    #[case::ident3(
2914        vec![
2915            token(TokenKind::Def),
2916            token(TokenKind::Ident(SmolStr::new("filter"))),
2917            token(TokenKind::LParen),
2918            token(TokenKind::Ident(SmolStr::new("arg1"))),
2919            token(TokenKind::Comma),
2920            token(TokenKind::Ident(SmolStr::new("arg2"))),
2921            token(TokenKind::RParen),
2922            token(TokenKind::Colon),
2923            token(TokenKind::Ident(SmolStr::new("contains"))),
2924            token(TokenKind::LParen),
2925            token(TokenKind::StringLiteral("arg1".to_owned())),
2926            token(TokenKind::Comma),
2927            token(TokenKind::StringLiteral("arg2".to_owned())),
2928            token(TokenKind::RParen),
2929        ],
2930        Ok(vec![
2931            Shared::new(Node {
2932                token_id: 0.into(),
2933                expr: Shared::new(Expr::Def(
2934                    IdentWithToken::new_with_token("filter", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("filter")))))),
2935                    smallvec![
2936                        Param::new(IdentWithToken::new_with_token("arg1", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arg1"))))))),
2937                        Param::new(IdentWithToken::new_with_token("arg2", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arg2"))))))),
2938                    ],
2939                    vec![Shared::new(Node {
2940                        token_id: 4.into(),
2941                        expr: Shared::new(Expr::Call(
2942                            IdentWithToken::new_with_token("contains", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("contains")))))),
2943                            smallvec![
2944                                Shared::new(Node {
2945                                    token_id: 2.into(),
2946                                    expr: Shared::new(Expr::Literal(Literal::String("arg1".to_owned()))),
2947                                }),
2948                                Shared::new(Node {
2949                                    token_id: 3.into(),
2950                                    expr: Shared::new(Expr::Literal(Literal::String("arg2".to_owned()))),
2951                                }),
2952                            ],
2953                        )),
2954                    })],
2955                )),
2956            }),
2957        ]))]
2958    #[case::ident4(
2959        vec![
2960            token(TokenKind::Ident(SmolStr::new("and"))),
2961            token(TokenKind::LParen),
2962            token(TokenKind::None),
2963            token(TokenKind::Comma),
2964            token(TokenKind::Self_),
2965            token(TokenKind::RParen),
2966            token(TokenKind::Eof)
2967        ],
2968        Ok(vec![
2969            Shared::new(Node {
2970                token_id: 2.into(),
2971                expr: Shared::new(Expr::Call(
2972                    IdentWithToken::new_with_token("and", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("and")))))),
2973                    smallvec![
2974                        Shared::new(Node {
2975                            token_id: 0.into(),
2976                            expr: Shared::new(Expr::Literal(Literal::None)),
2977                        }),
2978                        Shared::new(Node {
2979                            token_id: 1.into(),
2980                            expr: Shared::new(Expr::Self_),
2981                        }),
2982                    ],
2983                ))
2984            })
2985        ]))]
2986    #[case::ident5(
2987        vec![
2988            token(TokenKind::Ident(SmolStr::new("and"))),
2989            token(TokenKind::LParen),
2990            token(TokenKind::None),
2991            token(TokenKind::Comma),
2992            token(TokenKind::Self_),
2993            token(TokenKind::RParen),
2994            token(TokenKind::Ident(SmolStr::new("and"))),
2995        ],
2996        Err(SyntaxError::UnexpectedToken(token(TokenKind::Ident(SmolStr::new("and"))))))]
2997    #[case::ident5(
2998        vec![
2999            token(TokenKind::Ident(SmolStr::new("and"))),
3000            token(TokenKind::LParen),
3001            token(TokenKind::None),
3002            token(TokenKind::Comma),
3003            token(TokenKind::Self_),
3004            token(TokenKind::RParen),
3005            token(TokenKind::Def),
3006        ],
3007        Err(SyntaxError::UnexpectedToken(token(TokenKind::Def))))]
3008    #[case::ident6(
3009        vec![
3010            token(TokenKind::Ident(SmolStr::new("and"))),
3011            token(TokenKind::Def),
3012        ],
3013        Err(SyntaxError::UnexpectedToken(token(TokenKind::Ident(SmolStr::new("and"))))))]
3014    #[case::ident_attribute_access(
3015        vec![
3016            token(TokenKind::Ident(SmolStr::new("c"))),
3017            token(TokenKind::Selector(SmolStr::new(".lang"))),
3018            token(TokenKind::Eof),
3019        ],
3020        Ok(vec![
3021            Shared::new(Node {
3022                token_id: 2.into(),
3023                expr: Shared::new(Expr::Call(
3024                    IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))),
3025                    smallvec![
3026                        Shared::new(Node {
3027                            token_id: 0.into(),
3028                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
3029                        }),
3030                        Shared::new(Node {
3031                            token_id: 1.into(),
3032                            expr: Shared::new(Expr::Literal(Literal::String("lang".to_owned()))),
3033                        }),
3034                    ],
3035                )),
3036            })
3037        ]))]
3038    #[case::error(
3039        vec![
3040            token(TokenKind::Ident(SmolStr::new("contains"))),
3041            token(TokenKind::LParen),
3042            token(TokenKind::Selector(SmolStr::new("inline_code"))),
3043            token(TokenKind::Eof)
3044        ],
3045        Err(SyntaxError::UnknownSelector(selector::UnknownSelector::new(token(TokenKind::Selector(SmolStr::new("inline_code")))))))]
3046    #[case::def1(
3047        vec![
3048            token(TokenKind::Def),
3049            token(TokenKind::Ident(SmolStr::new("name"))),
3050            token(TokenKind::LParen),
3051            token(TokenKind::RParen),
3052            token(TokenKind::Colon),
3053            token(TokenKind::StringLiteral("value".to_owned())),
3054            token(TokenKind::SemiColon)
3055        ],
3056        Ok(vec![
3057            Shared::new(Node {
3058                token_id: 0.into(),
3059                expr: Shared::new(Expr::Def(
3060                        IdentWithToken::new_with_token("name", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("name")))))),
3061                        SmallVec::new(),
3062                        vec![Shared::new(Node {
3063                            token_id: 2.into(),
3064                            expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
3065                        })],
3066                )),
3067            }),
3068        ]))]
3069    #[case::def_with_end(
3070        vec![
3071            token(TokenKind::Def),
3072            token(TokenKind::Ident(SmolStr::new("name"))),
3073            token(TokenKind::LParen),
3074            token(TokenKind::RParen),
3075            token(TokenKind::Colon),
3076            token(TokenKind::StringLiteral("value".to_owned())),
3077            token(TokenKind::End)
3078        ],
3079        Ok(vec![
3080            Shared::new(Node {
3081                token_id: 0.into(),
3082                expr: Shared::new(Expr::Def(
3083                        IdentWithToken::new_with_token("name", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("name")))))),
3084                        SmallVec::new(),
3085                        vec![Shared::new(Node {
3086                            token_id: 2.into(),
3087                            expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
3088                        })],
3089                )),
3090            }),
3091        ]))]
3092    #[case::def2(
3093        vec![
3094            token(TokenKind::Def),
3095            token(TokenKind::Ident(SmolStr::new("name"))),
3096            token(TokenKind::LParen),
3097            token(TokenKind::Comma),
3098            token(TokenKind::RParen),
3099        ],
3100        Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::Comma, module_id: 1.into()})))]
3101    #[case::def3(
3102        vec![
3103            token(TokenKind::Def),
3104            token(TokenKind::Ident(SmolStr::new("name"))),
3105            token(TokenKind::LParen),
3106            token(TokenKind::StringLiteral("value".to_owned())),
3107            token(TokenKind::Comma),
3108            token(TokenKind::RParen),
3109        ],
3110        Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::StringLiteral("value".to_string()), module_id: 1.into()})))]
3111    #[case::def4(
3112        vec![
3113            token(TokenKind::Def),
3114            token(TokenKind::Ident(SmolStr::new("name"))),
3115            token(TokenKind::LParen),
3116            token(TokenKind::StringLiteral("value".to_owned())),
3117            token(TokenKind::RParen),
3118            token(TokenKind::Colon),
3119        ],
3120        Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::StringLiteral("value".to_string()), module_id: 1.into()})))]
3121    #[case::def5(
3122        vec![
3123            token(TokenKind::Def),
3124            token(TokenKind::Ident(SmolStr::new("name"))),
3125            token(TokenKind::LParen),
3126            token(TokenKind::StringLiteral("value".to_owned())),
3127            token(TokenKind::RParen),
3128            token(TokenKind::Colon),
3129            token(TokenKind::Pipe),
3130        ],
3131        Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::StringLiteral("value".to_string()), module_id: 1.into()})))]
3132    #[case::def6(
3133        vec![
3134            token(TokenKind::Def),
3135            token(TokenKind::Ident(SmolStr::new("name"))),
3136            token(TokenKind::LParen),
3137            token(TokenKind::StringLiteral("value".to_owned())),
3138            token(TokenKind::RParen),
3139            token(TokenKind::Colon),
3140            token(TokenKind::SemiColon),
3141        ],
3142        Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::StringLiteral("value".to_string()), module_id: 1.into()})))]
3143    #[case::def7(
3144        vec![
3145            token(TokenKind::Def),
3146            token(TokenKind::Ident(SmolStr::new("name"))),
3147            token(TokenKind::LParen),
3148            token(TokenKind::StringLiteral("value".to_owned())),
3149            token(TokenKind::RParen),
3150            token(TokenKind::Colon),
3151        ],
3152        Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::StringLiteral("value".to_string()), module_id: 1.into()})))]
3153    #[case::def7(
3154        vec![
3155            token(TokenKind::Def),
3156            token(TokenKind::LParen),
3157            token(TokenKind::StringLiteral("value".to_owned())),
3158            token(TokenKind::RParen),
3159            token(TokenKind::Colon),
3160        ],
3161        Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::LParen, module_id: 1.into()})))]
3162    #[case::def_without_colon1(
3163        vec![
3164            token(TokenKind::Def),
3165            token(TokenKind::Ident(SmolStr::new("name"))),
3166            token(TokenKind::LParen),
3167            token(TokenKind::RParen),
3168            token(TokenKind::StringLiteral("value".to_owned())),
3169            token(TokenKind::SemiColon)
3170        ],
3171        Ok(vec![
3172            Shared::new(Node {
3173                token_id: 0.into(),
3174                expr: Shared::new(Expr::Def(
3175                        IdentWithToken::new_with_token("name", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("name")))))),
3176                        SmallVec::new(),
3177                        vec![Shared::new(Node {
3178                            token_id: 1.into(),
3179                            expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
3180                        })],
3181                )),
3182            }),
3183        ]))]
3184    #[case::def_without_colon2(
3185        vec![
3186            token(TokenKind::Def),
3187            token(TokenKind::Ident(SmolStr::new("name"))),
3188            token(TokenKind::LParen),
3189            token(TokenKind::RParen),
3190            token(TokenKind::StringLiteral("value".to_owned())),
3191            token(TokenKind::End)
3192        ],
3193        Ok(vec![
3194            Shared::new(Node {
3195                token_id: 0.into(),
3196                expr: Shared::new(Expr::Def(
3197                        IdentWithToken::new_with_token("name", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("name")))))),
3198                        SmallVec::new(),
3199                        vec![Shared::new(Node {
3200                            token_id: 1.into(),
3201                            expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
3202                        })],
3203                )),
3204            }),
3205        ]))]
3206    #[case::def_without_colon_with_args(
3207        vec![
3208            token(TokenKind::Def),
3209            token(TokenKind::Ident(SmolStr::new("name"))),
3210            token(TokenKind::LParen),
3211            token(TokenKind::Ident(SmolStr::new("x"))),
3212            token(TokenKind::RParen),
3213            token(TokenKind::Ident(SmolStr::new("x"))),
3214            token(TokenKind::SemiColon)
3215        ],
3216        Ok(vec![
3217            Shared::new(Node {
3218                token_id: 0.into(),
3219                expr: Shared::new(Expr::Def(
3220                        IdentWithToken::new_with_token("name", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("name")))))),
3221                        smallvec![
3222                          Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
3223                        ],
3224                        vec![Shared::new(Node {
3225                            token_id: 1.into(),
3226                            expr: Shared::new(Expr::Ident(
3227                                IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))),
3228                            )),
3229                        })],
3230                )),
3231            }),
3232        ]))]
3233    #[case::unmatched_end_at_root(
3234        // `end` at root level followed by non-EOF: def foo: if (.): . end end | foo
3235        vec![
3236            token(TokenKind::Def),
3237            token(TokenKind::Ident(SmolStr::new("foo"))),
3238            token(TokenKind::Colon),
3239            token(TokenKind::If),
3240            token(TokenKind::LParen),
3241            token(TokenKind::Selector(SmolStr::new("."))),
3242            token(TokenKind::RParen),
3243            token(TokenKind::Colon),
3244            token(TokenKind::Selector(SmolStr::new("."))),
3245            token(TokenKind::End),    // closes def body
3246            token(TokenKind::End),    // unmatched – no open block
3247            token(TokenKind::Pipe),   // something after (like `| foo`)
3248            token(TokenKind::Ident(SmolStr::new("foo"))),
3249            token(TokenKind::Eof),
3250        ],
3251        Err(SyntaxError::UnmatchedEnd(token(TokenKind::End))))]
3252    #[case::unmatched_end_standalone_if(
3253        // `end` after a standalone single-line if (no open block): if (.): . end end
3254        vec![
3255            token(TokenKind::If),
3256            token(TokenKind::LParen),
3257            token(TokenKind::Selector(SmolStr::new("."))),
3258            token(TokenKind::RParen),
3259            token(TokenKind::Colon),
3260            token(TokenKind::Selector(SmolStr::new("."))),
3261            token(TokenKind::End),    // unmatched
3262            token(TokenKind::End),
3263            token(TokenKind::Eof),
3264        ],
3265        Err(SyntaxError::UnmatchedEnd(token(TokenKind::End))))]
3266    #[case::unmatched_end_at_start(
3267        // `end` as the very first token at root level
3268        vec![
3269            token(TokenKind::End),
3270            token(TokenKind::Eof),
3271        ],
3272        Err(SyntaxError::UnmatchedEnd(token(TokenKind::End))))]
3273    #[case::let_1(
3274            vec![
3275                token(TokenKind::Let),
3276                token(TokenKind::Ident(SmolStr::new("x"))),
3277                token(TokenKind::Equal),
3278                token(TokenKind::NumberLiteral(42.into())),
3279                token(TokenKind::Eof)
3280            ],
3281            Ok(vec![
3282                Shared::new(Node {
3283                    token_id: 0.into(),
3284                    expr: Shared::new(Expr::Let(
3285                        Pattern::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
3286                        Shared::new(Node {
3287                            token_id: 2.into(),
3288                            expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
3289                        }),
3290                    )),
3291                })
3292            ]))]
3293    #[case::let_2(
3294            vec![
3295                token(TokenKind::Let),
3296                token(TokenKind::Ident(SmolStr::new("y"))),
3297                token(TokenKind::Equal),
3298                token(TokenKind::StringLiteral("hello".to_owned())),
3299                token(TokenKind::Eof)
3300            ],
3301            Ok(vec![
3302                Shared::new(Node {
3303                    token_id: 0.into(),
3304                    expr: Shared::new(Expr::Let(
3305                        Pattern::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y"))))))),
3306                        Shared::new(Node {
3307                            token_id: 2.into(),
3308                            expr: Shared::new(Expr::Literal(Literal::String("hello".to_owned()))),
3309                        }),
3310                    )),
3311                })
3312            ]))]
3313    #[case::let_3(
3314            vec![
3315                token(TokenKind::Let),
3316                token(TokenKind::Ident(SmolStr::new("flag"))),
3317                token(TokenKind::Equal),
3318                token(TokenKind::BoolLiteral(true)),
3319                token(TokenKind::Eof)
3320            ],
3321            Ok(vec![
3322                Shared::new(Node {
3323                    token_id: 0.into(),
3324                    expr: Shared::new(Expr::Let(
3325                        Pattern::Ident(IdentWithToken::new_with_token("flag", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("flag"))))))),
3326                        Shared::new(Node {
3327                            token_id: 2.into(),
3328                            expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3329                        }),
3330                    )),
3331                })
3332            ]))]
3333    #[case::let_4(
3334            vec![
3335                token(TokenKind::Let),
3336                token(TokenKind::Ident(SmolStr::new("z"))),
3337                token(TokenKind::Equal),
3338                token(TokenKind::Ident(SmolStr::new("some_var"))),
3339                token(TokenKind::Eof)
3340            ],
3341            Ok(vec![
3342                Shared::new(Node {
3343                    token_id: 0.into(),
3344                    expr: Shared::new(Expr::Let(
3345                        Pattern::Ident(IdentWithToken::new_with_token("z", Some(Shared::new(token(TokenKind::Ident("z".into())))))),
3346                        Shared::new(Node {
3347                            token_id: 2.into(),
3348                            expr: Shared::new(
3349                                Expr::Ident(IdentWithToken::new_with_token("some_var",
3350                                                 Some(Shared::new(token(TokenKind::Ident(SmolStr::new("some_var"))))))))
3351                        }),
3352                    )),
3353                })
3354            ]))]
3355    #[case::let_5(
3356            vec![
3357                token(TokenKind::Let),
3358                token(TokenKind::Ident(SmolStr::new("z"))),
3359                token(TokenKind::Equal),
3360                token(TokenKind::Ident(SmolStr::new("some_var"))),
3361                token(TokenKind::Pipe),
3362            ],
3363            Ok(vec![
3364                Shared::new(Node {
3365                    token_id: 0.into(),
3366                    expr: Shared::new(Expr::Let(
3367                        Pattern::Ident(IdentWithToken::new_with_token("z", Some(Shared::new(token(TokenKind::Ident("z".into())))))),
3368                        Shared::new(Node {
3369                            token_id: 2.into(),
3370                            expr: Shared::new(
3371                                Expr::Ident(IdentWithToken::new_with_token("some_var", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("some_var")))))))),
3372                        }),
3373                    )),
3374                })
3375            ]))]
3376    #[case::let_6(
3377            vec![
3378                token(TokenKind::Let),
3379                token(TokenKind::Ident(SmolStr::new("z"))),
3380                token(TokenKind::Equal),
3381                token(TokenKind::Ident(SmolStr::new("some_var"))),
3382            ],
3383            Ok(vec![
3384                Shared::new(Node {
3385                    token_id: 0.into(),
3386                    expr: Shared::new(Expr::Let(
3387                        Pattern::Ident(IdentWithToken::new_with_token("z", Some(Shared::new(token(TokenKind::Ident("z".into())))))),
3388                        Shared::new(Node {
3389                            token_id: 2.into(),
3390                            expr: Shared::new(
3391                                Expr::Ident(IdentWithToken::new_with_token("some_var", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("some_var")))))))),
3392                        }),
3393                    )),
3394                })
3395            ]))]
3396    #[case::var_1(
3397            vec![
3398                token(TokenKind::Var),
3399                token(TokenKind::Ident(SmolStr::new("x"))),
3400                token(TokenKind::Equal),
3401                token(TokenKind::NumberLiteral(42.into())),
3402                token(TokenKind::Eof)
3403            ],
3404            Ok(vec![
3405                Shared::new(Node {
3406                    token_id: 0.into(),
3407                    expr: Shared::new(Expr::Var(
3408                        Pattern::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
3409                        Shared::new(Node {
3410                            token_id: 2.into(),
3411                            expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
3412                        }),
3413                    )),
3414                })
3415            ]))]
3416    #[case::var_2(
3417            vec![
3418                token(TokenKind::Var),
3419                token(TokenKind::Ident(SmolStr::new("count"))),
3420                token(TokenKind::Equal),
3421                token(TokenKind::NumberLiteral(0.into())),
3422                token(TokenKind::Eof)
3423            ],
3424            Ok(vec![
3425                Shared::new(Node {
3426                    token_id: 0.into(),
3427                    expr: Shared::new(Expr::Var(
3428                        Pattern::Ident(IdentWithToken::new_with_token("count", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("count"))))))),
3429                        Shared::new(Node {
3430                            token_id: 2.into(),
3431                            expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
3432                        }),
3433                    )),
3434                })
3435            ]))]
3436    #[case::assign_1(
3437            vec![
3438                token(TokenKind::Ident(SmolStr::new("x"))),
3439                token(TokenKind::Equal),
3440                token(TokenKind::NumberLiteral(100.into())),
3441                token(TokenKind::Eof)
3442            ],
3443            Ok(vec![
3444                Shared::new(Node {
3445                    token_id: 1.into(),
3446                    expr: Shared::new(Expr::Assign(
3447                        IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))),
3448                        Shared::new(Node {
3449                            token_id: 2.into(),
3450                            expr: Shared::new(Expr::Literal(Literal::Number(100.into()))),
3451                        }),
3452                    )),
3453                })
3454            ]))]
3455    #[case::assign_2(
3456            vec![
3457                token(TokenKind::Ident(SmolStr::new("name"))),
3458                token(TokenKind::Equal),
3459                token(TokenKind::StringLiteral("Alice".to_owned())),
3460                token(TokenKind::Eof)
3461            ],
3462            Ok(vec![
3463                Shared::new(Node {
3464                    token_id: 1.into(),
3465                    expr: Shared::new(Expr::Assign(
3466                        IdentWithToken::new_with_token("name", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("name")))))),
3467                        Shared::new(Node {
3468                            token_id: 2.into(),
3469                            expr: Shared::new(Expr::Literal(Literal::String("Alice".to_owned()))),
3470                        }),
3471                    )),
3472                })
3473            ]))]
3474    #[case::index_assign(
3475            vec![
3476                token(TokenKind::Ident(SmolStr::new("arr"))),
3477                token(TokenKind::LBracket),
3478                token(TokenKind::NumberLiteral(0.into())),
3479                token(TokenKind::RBracket),
3480                token(TokenKind::Equal),
3481                token(TokenKind::NumberLiteral(10.into())),
3482                token(TokenKind::Eof)
3483            ],
3484            Ok(vec![
3485                Shared::new(Node {
3486                    token_id: 3.into(),
3487                    expr: Shared::new(Expr::Assign(
3488                        IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
3489                        Shared::new(Node {
3490                            token_id: 3.into(),
3491                            expr: Shared::new(Expr::Call(
3492                                IdentWithToken::new_with_token(constants::builtins::SET, Some(Shared::new(token(TokenKind::Equal)))),
3493                                smallvec![
3494                                    Shared::new(Node {
3495                                        token_id: 0.into(),
3496                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
3497                                    }),
3498                                    Shared::new(Node {
3499                                        token_id: 1.into(),
3500                                        expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
3501                                    }),
3502                                    Shared::new(Node {
3503                                        token_id: 4.into(),
3504                                        expr: Shared::new(Expr::Literal(Literal::Number(10.into()))),
3505                                    }),
3506                                ],
3507                            )),
3508                        }),
3509                    )),
3510                })
3511            ]))]
3512    #[case::index_compound_assign(
3513            vec![
3514                token(TokenKind::Ident(SmolStr::new("arr"))),
3515                token(TokenKind::LBracket),
3516                token(TokenKind::NumberLiteral(0.into())),
3517                token(TokenKind::RBracket),
3518                token(TokenKind::PlusEqual),
3519                token(TokenKind::NumberLiteral(1.into())),
3520                token(TokenKind::Eof)
3521            ],
3522            Ok(vec![
3523                Shared::new(Node {
3524                    token_id: 3.into(),
3525                    expr: Shared::new(Expr::Assign(
3526                        IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
3527                        Shared::new(Node {
3528                            token_id: 3.into(),
3529                            expr: Shared::new(Expr::Call(
3530                                IdentWithToken::new_with_token(constants::builtins::SET, Some(Shared::new(token(TokenKind::PlusEqual)))),
3531                                smallvec![
3532                                    Shared::new(Node {
3533                                        token_id: 0.into(),
3534                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
3535                                    }),
3536                                    Shared::new(Node {
3537                                        token_id: 1.into(),
3538                                        expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
3539                                    }),
3540                                    Shared::new(Node {
3541                                        token_id: 3.into(),
3542                                        expr: Shared::new(Expr::Call(
3543                                            IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::PlusEqual)))),
3544                                            smallvec![
3545                                                Shared::new(Node {
3546                                                    token_id: 2.into(),
3547                                                    expr: Shared::new(Expr::Call(
3548                                                        IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
3549                                                        smallvec![
3550                                                            Shared::new(Node {
3551                                                                token_id: 0.into(),
3552                                                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
3553                                                            }),
3554                                                            Shared::new(Node {
3555                                                                token_id: 1.into(),
3556                                                                expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
3557                                                            }),
3558                                                        ],
3559                                                    )),
3560                                                }),
3561                                                Shared::new(Node {
3562                                                    token_id: 4.into(),
3563                                                    expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
3564                                                }),
3565                                            ],
3566                                        )),
3567                                    }),
3568                                ],
3569                            )),
3570                        }),
3571                    )),
3572                })
3573            ]))]
3574    #[case::index_double_slash_equal(
3575            vec![
3576                token(TokenKind::Ident(SmolStr::new("arr"))),
3577                token(TokenKind::LBracket),
3578                token(TokenKind::NumberLiteral(0.into())),
3579                token(TokenKind::RBracket),
3580                token(TokenKind::DoubleSlashEqual),
3581                token(TokenKind::NumberLiteral(2.into())),
3582                token(TokenKind::Eof)
3583            ],
3584            // arr[0] //= 2  →  arr = set(arr, 0, floor(div(get(arr, 0), 2)))
3585            Ok(vec![
3586                Shared::new(Node {
3587                    token_id: 3.into(),
3588                    expr: Shared::new(Expr::Assign(
3589                        IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
3590                        Shared::new(Node {
3591                            token_id: 3.into(),
3592                            expr: Shared::new(Expr::Call(
3593                                IdentWithToken::new_with_token(constants::builtins::SET, Some(Shared::new(token(TokenKind::DoubleSlashEqual)))),
3594                                smallvec![
3595                                    Shared::new(Node {
3596                                        token_id: 0.into(),
3597                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
3598                                    }),
3599                                    Shared::new(Node {
3600                                        token_id: 1.into(),
3601                                        expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
3602                                    }),
3603                                    Shared::new(Node {
3604                                        token_id: 3.into(),
3605                                        expr: Shared::new(Expr::Call(
3606                                            IdentWithToken::new_with_token(constants::builtins::FLOOR, Some(Shared::new(token(TokenKind::DoubleSlashEqual)))),
3607                                            smallvec![Shared::new(Node {
3608                                                token_id: 3.into(),
3609                                                expr: Shared::new(Expr::Call(
3610                                                    IdentWithToken::new_with_token(constants::builtins::DIV, Some(Shared::new(token(TokenKind::DoubleSlashEqual)))),
3611                                                    smallvec![
3612                                                        Shared::new(Node {
3613                                                            token_id: 2.into(),
3614                                                            expr: Shared::new(Expr::Call(
3615                                                                IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
3616                                                                smallvec![
3617                                                                    Shared::new(Node {
3618                                                                        token_id: 0.into(),
3619                                                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
3620                                                                    }),
3621                                                                    Shared::new(Node {
3622                                                                        token_id: 1.into(),
3623                                                                        expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
3624                                                                    }),
3625                                                                ],
3626                                                            )),
3627                                                        }),
3628                                                        Shared::new(Node {
3629                                                            token_id: 4.into(),
3630                                                            expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
3631                                                        }),
3632                                                    ],
3633                                                )),
3634                                            })],
3635                                        )),
3636                                    }),
3637                                ],
3638                            )),
3639                        }),
3640                    )),
3641                })
3642            ]))]
3643    #[case::root_semicolon_error(
3644            vec![
3645                token(TokenKind::Ident(SmolStr::new("x"))),
3646                token(TokenKind::SemiColon),
3647                token(TokenKind::Ident(SmolStr::new("y"))),
3648                token(TokenKind::Eof)
3649            ],
3650            Err(SyntaxError::UnexpectedToken(token(TokenKind::Ident(SmolStr::new("y"))))))]
3651    #[case::if_1(
3652            vec![
3653                token(TokenKind::If),
3654                token(TokenKind::LParen),
3655                token(TokenKind::BoolLiteral(true)),
3656                token(TokenKind::RParen),
3657                token(TokenKind::Colon),
3658                token(TokenKind::StringLiteral("true branch".to_owned())),
3659                token(TokenKind::Else),
3660                token(TokenKind::Colon),
3661                token(TokenKind::StringLiteral("false branch".to_owned())),
3662                token(TokenKind::Eof)
3663            ],
3664            Ok(vec![
3665                Shared::new(Node {
3666                    token_id: 7.into(),
3667                    expr: Shared::new(Expr::If(smallvec![
3668                        (
3669                            Some(Shared::new(Node {
3670                                token_id: 1.into(),
3671                                expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3672                            })),
3673                            Shared::new(Node {
3674                                token_id: 3.into(),
3675                                expr: Shared::new(Expr::Literal(Literal::String("true branch".to_owned()))),
3676                            })
3677                        ),
3678                        (
3679                            None,
3680                            Shared::new(Node {
3681                                token_id: 6.into(),
3682                                expr: Shared::new(Expr::Literal(Literal::String("false branch".to_owned()))),
3683                            })
3684                        )
3685                    ])),
3686                })
3687            ]))]
3688    #[case::if_elif_else(
3689            vec![
3690                token(TokenKind::If),
3691                token(TokenKind::LParen),
3692                token(TokenKind::BoolLiteral(true)),
3693                token(TokenKind::RParen),
3694                token(TokenKind::Colon),
3695                token(TokenKind::StringLiteral("true branch".to_owned())),
3696                token(TokenKind::Elif),
3697                token(TokenKind::LParen),
3698                token(TokenKind::BoolLiteral(false)),
3699                token(TokenKind::RParen),
3700                token(TokenKind::Colon),
3701                token(TokenKind::StringLiteral("elif branch".to_owned())),
3702                token(TokenKind::Else),
3703                token(TokenKind::Colon),
3704                token(TokenKind::StringLiteral("else branch".to_owned())),
3705                token(TokenKind::Eof)
3706            ],
3707            Ok(vec![
3708                Shared::new(Node {
3709                    token_id: 11.into(),
3710                    expr: Shared::new(Expr::If(smallvec![
3711                        (
3712                            Some(Shared::new(Node {
3713                                token_id: 1.into(),
3714                                expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3715                            })),
3716                            Shared::new(Node {
3717                                token_id: 3.into(),
3718                                expr: Shared::new(Expr::Literal(Literal::String("true branch".to_owned()))),
3719                            })
3720                        ),
3721                        (
3722                            Some(Shared::new(Node {
3723                                token_id: 5.into(),
3724                                expr: Shared::new(Expr::Literal(Literal::Bool(false))),
3725                            })),
3726                            Shared::new(Node {
3727                                token_id: 7.into(),
3728                                expr: Shared::new(Expr::Literal(Literal::String("elif branch".to_owned()))),
3729                            })
3730                        ),
3731                        (
3732                            None,
3733                            Shared::new(Node {
3734                                token_id: 10.into(),
3735                                expr: Shared::new(Expr::Literal(Literal::String("else branch".to_owned()))),
3736                            })
3737                        )
3738                    ])),
3739                })
3740            ]))]
3741    #[case::if_only(
3742            vec![
3743                token(TokenKind::If),
3744                token(TokenKind::LParen),
3745                token(TokenKind::BoolLiteral(true)),
3746                token(TokenKind::RParen),
3747                token(TokenKind::Colon),
3748                token(TokenKind::StringLiteral("true branch".to_owned())),
3749                token(TokenKind::Eof)
3750            ],
3751            Ok(vec![
3752                Shared::new(Node {
3753                    token_id: 4.into(),
3754                    expr: Shared::new(Expr::If(smallvec![
3755                        (
3756                            Some(Shared::new(Node {
3757                                token_id: 1.into(),
3758                                expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3759                            })),
3760                            Shared::new(Node {
3761                                token_id: 3.into(),
3762                                expr: Shared::new(Expr::Literal(Literal::String("true branch".to_owned()))),
3763                            })
3764                        ),
3765                    ])),
3766                })
3767            ]))]
3768    #[case::if_elif(
3769            vec![
3770                token(TokenKind::If),
3771                token(TokenKind::LParen),
3772                token(TokenKind::BoolLiteral(true)),
3773                token(TokenKind::RParen),
3774                token(TokenKind::Colon),
3775                token(TokenKind::StringLiteral("true branch".to_owned())),
3776                token(TokenKind::Elif),
3777                token(TokenKind::LParen),
3778                token(TokenKind::BoolLiteral(true)),
3779                token(TokenKind::RParen),
3780                token(TokenKind::Colon),
3781                token(TokenKind::StringLiteral("true branch".to_owned())),
3782                token(TokenKind::Eof)
3783            ],
3784            Ok(vec![
3785                Shared::new(Node {
3786                    token_id: 8.into(),
3787                    expr: Shared::new(Expr::If(smallvec![
3788                        (
3789                            Some(Shared::new(Node {
3790                                token_id: 1.into(),
3791                                expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3792                            })),
3793                            Shared::new(Node {
3794                                token_id: 3.into(),
3795                                expr: Shared::new(Expr::Literal(Literal::String("true branch".to_owned()))),
3796                            })
3797                        ),
3798                        (
3799                            Some(Shared::new(Node {
3800                                token_id: 5.into(),
3801                                expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3802                            })),
3803                            Shared::new(Node {
3804                                token_id: 7.into(),
3805                                expr: Shared::new(Expr::Literal(Literal::String("true branch".to_owned()))),
3806                            })
3807                        ),
3808                    ])),
3809                })
3810            ]))]
3811    #[case::if_error(
3812            vec![
3813                token(TokenKind::If),
3814                token(TokenKind::LParen),
3815                token(TokenKind::BoolLiteral(true)),
3816                token(TokenKind::RParen),
3817                token(TokenKind::Colon),
3818                token(TokenKind::StringLiteral("true branch".to_owned())),
3819                token(TokenKind::Elif),
3820                token(TokenKind::LParen),
3821                token(TokenKind::BoolLiteral(false)),
3822                token(TokenKind::RParen),
3823                token(TokenKind::Colon),
3824                token(TokenKind::StringLiteral("elif branch".to_owned())),
3825                token(TokenKind::Else),
3826                token(TokenKind::Colon),
3827                token(TokenKind::Eof)
3828            ],
3829            Err(SyntaxError::UnexpectedEOFDetected(0.into())))]
3830    #[case::if_error(
3831            vec![
3832                token(TokenKind::If),
3833                token(TokenKind::LParen),
3834                token(TokenKind::RParen),
3835                token(TokenKind::Colon),
3836                token(TokenKind::StringLiteral("true branch".to_owned())),
3837                token(TokenKind::Elif),
3838                token(TokenKind::LParen),
3839                token(TokenKind::BoolLiteral(false)),
3840                token(TokenKind::RParen),
3841                token(TokenKind::Colon),
3842                token(TokenKind::StringLiteral("elif branch".to_owned())),
3843                token(TokenKind::Else),
3844                token(TokenKind::Colon),
3845                token(TokenKind::Eof)
3846            ],
3847            Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::If, module_id: 1.into()})))]
3848    #[case::elif_error(
3849            vec![
3850                token(TokenKind::If),
3851                token(TokenKind::LParen),
3852                token(TokenKind::BoolLiteral(true)),
3853                token(TokenKind::RParen),
3854                token(TokenKind::Colon),
3855                token(TokenKind::StringLiteral("true branch".to_owned())),
3856                token(TokenKind::Elif),
3857                token(TokenKind::LParen),
3858                token(TokenKind::RParen),
3859                token(TokenKind::Colon),
3860                token(TokenKind::StringLiteral("elif branch".to_owned())),
3861                token(TokenKind::Else),
3862                token(TokenKind::Colon),
3863                token(TokenKind::Eof)
3864            ],
3865            Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::Elif, module_id: 1.into()})))]
3866    #[case::h_selector(
3867        vec![
3868            token(TokenKind::Selector(SmolStr::new(".h"))),
3869            token(TokenKind::Eof)
3870        ],
3871        Ok(vec![
3872            Shared::new(Node {
3873                token_id: 2.into(),
3874                expr: Shared::new(Expr::Selector(Selector::Heading(None))),
3875            })
3876        ]))]
3877    #[case::h_selector_without_number(
3878        vec![
3879            token(TokenKind::Selector(SmolStr::new(".h"))),
3880            token(TokenKind::Eof)
3881        ],
3882        Ok(vec![
3883            Shared::new(Node {
3884                token_id: 1.into(),
3885                expr: Shared::new(Expr::Selector(Selector::Heading(None))),
3886            })
3887        ]))]
3888    #[case::while_(
3889        vec![
3890            token(TokenKind::While),
3891            token(TokenKind::LParen),
3892            token(TokenKind::BoolLiteral(true)),
3893            token(TokenKind::RParen),
3894            token(TokenKind::Colon),
3895            token(TokenKind::StringLiteral("loop body".to_owned())),
3896            token(TokenKind::SemiColon),
3897        ],
3898        Ok(vec![Shared::new(Node {
3899            token_id: 0.into(),
3900            expr: Shared::new(Expr::While(
3901                Shared::new(Node {
3902                    token_id: 1.into(),
3903                    expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3904                }),
3905                vec![Shared::new(Node {
3906                    token_id: 3.into(),
3907                    expr: Shared::new(Expr::Literal(Literal::String("loop body".to_owned()))),
3908                })],
3909            )),
3910        })]))]
3911    #[case::while_error(
3912        vec![
3913            token(TokenKind::While),
3914            token(TokenKind::LParen),
3915            token(TokenKind::RParen),
3916            token(TokenKind::Colon),
3917            token(TokenKind::StringLiteral("loop body".to_owned())),
3918            token(TokenKind::SemiColon),
3919        ],
3920        Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::While, module_id: 1.into()})))]
3921    #[case::while_error(
3922        vec![
3923            token(TokenKind::While),
3924            token(TokenKind::LParen),
3925            token(TokenKind::BoolLiteral(true)),
3926            token(TokenKind::RParen),
3927            token(TokenKind::Colon),
3928        ],
3929        Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::While, module_id: 1.into()})))]
3930    #[case::while_do_end(
3931        vec![
3932            token(TokenKind::While),
3933            token(TokenKind::LParen),
3934            token(TokenKind::BoolLiteral(true)),
3935            token(TokenKind::RParen),
3936            token(TokenKind::Do),
3937            token(TokenKind::StringLiteral("loop body".to_owned())),
3938            token(TokenKind::End),
3939        ],
3940        Ok(vec![Shared::new(Node {
3941            token_id: 0.into(),
3942            expr: Shared::new(Expr::While(
3943                Shared::new(Node {
3944                    token_id: 1.into(),
3945                    expr: Shared::new(Expr::Literal(Literal::Bool(true))),
3946                }),
3947                vec![Shared::new(Node {
3948                    token_id: 3.into(),
3949                    expr: Shared::new(Expr::Literal(Literal::String("loop body".to_owned()))),
3950                })],
3951            )),
3952        })]))]
3953    #[case::loop_(
3954        vec![
3955            token(TokenKind::Loop),
3956            token(TokenKind::Colon),
3957            token(TokenKind::StringLiteral("loop body".to_owned())),
3958            token(TokenKind::SemiColon),
3959        ],
3960        Ok(vec![Shared::new(Node {
3961            token_id: 1.into(),
3962            expr: Shared::new(Expr::Loop(
3963                vec![Shared::new(Node {
3964                    token_id: 2.into(),
3965                    expr: Shared::new(Expr::Literal(Literal::String("loop body".to_owned()))),
3966                })],
3967            )),
3968        })]))]
3969    #[case::loop_error_no_body(
3970        vec![
3971            token(TokenKind::Loop),
3972            token(TokenKind::Colon),
3973        ],
3974        Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::Loop, module_id: 1.into()})))]
3975    #[case::try_catch(
3976        vec![
3977            token(TokenKind::Try),
3978            token(TokenKind::Colon),
3979            token(TokenKind::Ident(SmolStr::new("error_expr"))),
3980            token(TokenKind::Catch),
3981            token(TokenKind::Colon),
3982            token(TokenKind::StringLiteral("fallback".to_owned())),
3983            token(TokenKind::Eof),
3984        ],
3985        Ok(vec![Shared::new(Node {
3986            token_id: 2.into(),
3987            expr: Shared::new(Expr::Try(
3988                Shared::new(Node {
3989                    token_id: 2.into(),
3990                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("error_expr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("error_expr")))))))),
3991                }),
3992                Shared::new(Node {
3993                    token_id: 5.into(),
3994                    expr: Shared::new(Expr::Literal(Literal::String("fallback".to_owned()))),
3995                }),
3996            )),
3997        })]))]
3998    #[case::foreach(
3999        vec![
4000            token(TokenKind::Foreach),
4001            token(TokenKind::LParen),
4002            token(TokenKind::Ident(SmolStr::new("item"))),
4003            token(TokenKind::Comma),
4004            token(TokenKind::StringLiteral("array".to_owned())),
4005            token(TokenKind::RParen),
4006            token(TokenKind::Colon),
4007            token(TokenKind::Ident(SmolStr::new("print"))),
4008            token(TokenKind::LParen),
4009            token(TokenKind::Ident(SmolStr::new("item"))),
4010            token(TokenKind::RParen),
4011            token(TokenKind::SemiColon),
4012        ],
4013        Ok(vec![Shared::new(Node {
4014            token_id: 6.into(),
4015            expr: Shared::new(Expr::Foreach(
4016                IdentWithToken::new_with_token(
4017                    "item",
4018                    Some(Shared::new(token(TokenKind::Ident(SmolStr::new("item"))))),
4019                ),
4020                Shared::new(Node {
4021                    token_id: 1.into(),
4022                    expr: Shared::new(Expr::Literal(Literal::String("array".to_owned()))),
4023                }),
4024                vec![Shared::new(Node {
4025                    token_id: 4.into(),
4026                    expr: Shared::new(Expr::Call(
4027                        IdentWithToken::new_with_token(
4028                            "print",
4029                            Some(Shared::new(token(TokenKind::Ident(SmolStr::new(
4030                                "print",
4031                            ))))),
4032                        ),
4033                        smallvec![Shared::new(Node {
4034                            token_id: 3.into(),
4035                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
4036                                "item",
4037                                Some(Shared::new(token(TokenKind::Ident(SmolStr::new("item"))))),
4038                            ))),
4039                        })],
4040                    )),
4041                })],
4042            )),
4043        })]))]
4044    #[case::foreach(
4045        vec![
4046            token(TokenKind::Foreach),
4047            token(TokenKind::LParen),
4048            token(TokenKind::RParen),
4049            token(TokenKind::Colon),
4050            token(TokenKind::Ident(SmolStr::new("print"))),
4051            token(TokenKind::LParen),
4052            token(TokenKind::Ident(SmolStr::new("item"))),
4053            token(TokenKind::RParen),
4054            token(TokenKind::SemiColon),
4055        ],
4056        Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind:TokenKind::Foreach, module_id: 1.into()})))]
4057    #[case::foreach_do_end(
4058        vec![
4059            token(TokenKind::Foreach),
4060            token(TokenKind::LParen),
4061            token(TokenKind::Ident(SmolStr::new("item"))),
4062            token(TokenKind::Comma),
4063            token(TokenKind::StringLiteral("array".to_owned())),
4064            token(TokenKind::RParen),
4065            token(TokenKind::Do),
4066            token(TokenKind::Ident(SmolStr::new("print"))),
4067            token(TokenKind::LParen),
4068            token(TokenKind::Ident(SmolStr::new("item"))),
4069            token(TokenKind::RParen),
4070            token(TokenKind::End),
4071        ],
4072        Ok(vec![Shared::new(Node {
4073            token_id: 6.into(),
4074            expr: Shared::new(Expr::Foreach(
4075                IdentWithToken::new_with_token(
4076                    "item",
4077                    Some(Shared::new(token(TokenKind::Ident(SmolStr::new("item"))))),
4078                ),
4079                Shared::new(Node {
4080                    token_id: 1.into(),
4081                    expr: Shared::new(Expr::Literal(Literal::String("array".to_owned()))),
4082                }),
4083                vec![Shared::new(Node {
4084                    token_id: 4.into(),
4085                    expr: Shared::new(Expr::Call(
4086                        IdentWithToken::new_with_token(
4087                            "print",
4088                            Some(Shared::new(token(TokenKind::Ident(SmolStr::new(
4089                                "print",
4090                            ))))),
4091                        ),
4092                        smallvec![Shared::new(Node {
4093                            token_id: 3.into(),
4094                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
4095                                "item",
4096                                Some(Shared::new(token(TokenKind::Ident(SmolStr::new("item"))))),
4097                            ))),
4098                        })],
4099                    )),
4100                })],
4101            )),
4102        })]))]
4103    #[case::self_(
4104        vec![token(TokenKind::Self_), token(TokenKind::Eof)],
4105        Ok(vec![Shared::new(Node {
4106            token_id: 0.into(),
4107            expr: Shared::new(Expr::Self_),
4108        })]))]
4109    #[case::include(
4110        vec![
4111            token(TokenKind::Include),
4112            token(TokenKind::StringLiteral("module_name".to_owned())),
4113            token(TokenKind::Eof),
4114        ],
4115        Ok(vec![Shared::new(Node {
4116            token_id: 0.into(),
4117            expr: Shared::new(Expr::Include(Literal::String("module_name".to_owned()))),
4118        })]))]
4119    #[case::code_selector_with_language(
4120        vec![
4121            token(TokenKind::Selector(SmolStr::new(".code"))),
4122            token(TokenKind::Eof),
4123        ],
4124        Ok(vec![Shared::new(Node {
4125            token_id: 2.into(),
4126            expr: Shared::new(Expr::Selector(Selector::Code)),
4127        })]))]
4128    #[case::selector_call_heading_single_arg(
4129        vec![
4130            token(TokenKind::Selector(SmolStr::new(".h"))),
4131            token(TokenKind::LParen),
4132            token(TokenKind::NumberLiteral(1.into())),
4133            token(TokenKind::RParen),
4134            token(TokenKind::Eof),
4135        ],
4136        Ok(vec![Shared::new(Node {
4137            token_id: 1.into(),
4138            expr: Shared::new(Expr::SelectorCall(
4139                Selector::Heading(None),
4140                // arg literal is allocated first (id=0), then the selector token (id=1)
4141                smallvec![Shared::new(Node {
4142                    token_id: 0.into(),
4143                    expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
4144                })],
4145            )),
4146        })]))]
4147    #[case::selector_call_heading_multi_arg(
4148        vec![
4149            token(TokenKind::Selector(SmolStr::new(".h"))),
4150            token(TokenKind::LParen),
4151            token(TokenKind::NumberLiteral(1.into())),
4152            token(TokenKind::Comma),
4153            token(TokenKind::NumberLiteral(2.into())),
4154            token(TokenKind::RParen),
4155            token(TokenKind::Eof),
4156        ],
4157        Ok(vec![Shared::new(Node {
4158            token_id: 2.into(),
4159            expr: Shared::new(Expr::SelectorCall(
4160                Selector::Heading(None),
4161                // args are allocated first (id=0, id=1), then the selector token (id=2)
4162                smallvec![
4163                    Shared::new(Node {
4164                        token_id: 0.into(),
4165                        expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
4166                    }),
4167                    Shared::new(Node {
4168                        token_id: 1.into(),
4169                        expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
4170                    }),
4171                ],
4172            )),
4173        })]))]
4174    #[case::selector_call_code_lang(
4175        vec![
4176            token(TokenKind::Selector(SmolStr::new(".code"))),
4177            token(TokenKind::LParen),
4178            token(TokenKind::StringLiteral("rust".to_owned())),
4179            token(TokenKind::RParen),
4180            token(TokenKind::Eof),
4181        ],
4182        Ok(vec![Shared::new(Node {
4183            token_id: 1.into(),
4184            expr: Shared::new(Expr::SelectorCall(
4185                Selector::Code,
4186                // arg literal is allocated first (id=0), then the selector token (id=1)
4187                smallvec![Shared::new(Node {
4188                    token_id: 0.into(),
4189                    expr: Shared::new(Expr::Literal(Literal::String("rust".to_owned()))),
4190                })],
4191            )),
4192        })]))]
4193    #[case::selector_call_with_attribute(
4194        vec![
4195            token(TokenKind::Selector(SmolStr::new(".h"))),
4196            token(TokenKind::LParen),
4197            token(TokenKind::NumberLiteral(1.into())),
4198            token(TokenKind::RParen),
4199            token(TokenKind::Selector(SmolStr::new(".level"))),
4200            token(TokenKind::Eof),
4201        ],
4202        Ok(vec![Shared::new(Node {
4203            // attr() Call: arg literal id=0, SelectorCall id=1, attr_literal id=2, Call id=3
4204            token_id: 3.into(),
4205            expr: Shared::new(Expr::Call(
4206                IdentWithToken::new_with_token(
4207                    constants::builtins::ATTR,
4208                    Some(Shared::new(token(TokenKind::Selector(SmolStr::new(".h"))))),
4209                ),
4210                smallvec![
4211                    Shared::new(Node {
4212                        token_id: 1.into(),
4213                        expr: Shared::new(Expr::SelectorCall(
4214                            Selector::Heading(None),
4215                            smallvec![Shared::new(Node {
4216                                token_id: 0.into(),
4217                                expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
4218                            })],
4219                        )),
4220                    }),
4221                    Shared::new(Node {
4222                        token_id: 2.into(),
4223                        expr: Shared::new(Expr::Literal(Literal::String("level".to_owned()))),
4224                    }),
4225                ],
4226            )),
4227        })]))]
4228    #[case::selector_call_code_with_lang_attribute(
4229        vec![
4230            token(TokenKind::Selector(SmolStr::new(".code"))),
4231            token(TokenKind::LParen),
4232            token(TokenKind::StringLiteral("rust".to_owned())),
4233            token(TokenKind::RParen),
4234            token(TokenKind::Selector(SmolStr::new(".lang"))),
4235            token(TokenKind::Eof),
4236        ],
4237        Ok(vec![Shared::new(Node {
4238            // attr() Call: arg literal id=0, SelectorCall id=1, attr_literal id=2, Call id=3
4239            token_id: 3.into(),
4240            expr: Shared::new(Expr::Call(
4241                IdentWithToken::new_with_token(
4242                    constants::builtins::ATTR,
4243                    Some(Shared::new(token(TokenKind::Selector(SmolStr::new(".code"))))),
4244                ),
4245                smallvec![
4246                    Shared::new(Node {
4247                        token_id: 1.into(),
4248                        expr: Shared::new(Expr::SelectorCall(
4249                            Selector::Code,
4250                            smallvec![Shared::new(Node {
4251                                token_id: 0.into(),
4252                                expr: Shared::new(Expr::Literal(Literal::String("rust".to_owned()))),
4253                            })],
4254                        )),
4255                    }),
4256                    Shared::new(Node {
4257                        token_id: 2.into(),
4258                        expr: Shared::new(Expr::Literal(Literal::String("lang".to_owned()))),
4259                    }),
4260                ],
4261            )),
4262        })]))]
4263    #[case::table_selector(
4264        vec![
4265            token(TokenKind::Selector(SmolStr::new("."))),
4266            token(TokenKind::LBracket),
4267            token(TokenKind::NumberLiteral(1.into())),
4268            token(TokenKind::RBracket),
4269            token(TokenKind::LBracket),
4270            token(TokenKind::NumberLiteral(2.into())),
4271            token(TokenKind::RBracket),
4272            token(TokenKind::Eof),
4273        ],
4274        Ok(vec![Shared::new(Node {
4275            token_id: 8.into(),
4276            expr: Shared::new(Expr::Selector(Selector::Table(Some(1), Some(2)))),
4277        })]))]
4278    #[case::selector_call_list_bracket_single_arg(
4279        vec![
4280            token(TokenKind::Selector(SmolStr::new("."))),
4281            token(TokenKind::LBracket),
4282            token(TokenKind::RBracket),
4283            token(TokenKind::LParen),
4284            token(TokenKind::NumberLiteral(2.into())),
4285            token(TokenKind::RParen),
4286            token(TokenKind::Eof),
4287        ],
4288        Ok(vec![Shared::new(Node {
4289            token_id: 2.into(),
4290            expr: Shared::new(Expr::SelectorCall(
4291                Selector::List(None, None),
4292                smallvec![Shared::new(Node {
4293                    token_id: 1.into(),
4294                    expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
4295                })],
4296            )),
4297        })]))]
4298    #[case::selector_call_table_bracket_single_arg(
4299        vec![
4300            token(TokenKind::Selector(SmolStr::new("."))),
4301            token(TokenKind::LBracket),
4302            token(TokenKind::RBracket),
4303            token(TokenKind::LBracket),
4304            token(TokenKind::RBracket),
4305            token(TokenKind::LParen),
4306            token(TokenKind::NumberLiteral(1.into())),
4307            token(TokenKind::RParen),
4308            token(TokenKind::Eof),
4309        ],
4310        Ok(vec![Shared::new(Node {
4311            token_id: 3.into(),
4312            expr: Shared::new(Expr::SelectorCall(
4313                Selector::Table(None, None),
4314                smallvec![Shared::new(Node {
4315                    token_id: 2.into(),
4316                    expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
4317                })],
4318            )),
4319        })]))]
4320    #[case::selector_call_list_bracket_variable(
4321        vec![
4322            token(TokenKind::Selector(SmolStr::new("."))),
4323            token(TokenKind::LBracket),
4324            token(TokenKind::Ident(SmolStr::new("v"))),
4325            token(TokenKind::RBracket),
4326            token(TokenKind::Eof),
4327        ],
4328        Ok(vec![Shared::new(Node {
4329            token_id: 3.into(),
4330            expr: Shared::new(Expr::SelectorCall(
4331                Selector::List(None, None),
4332                smallvec![Shared::new(Node {
4333                    token_id: 1.into(),
4334                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
4335                        "v",
4336                        Some(Shared::new(token(TokenKind::Ident(SmolStr::new("v"))))),
4337                    ))),
4338                })],
4339            )),
4340        })]))]
4341    #[case::selector_call_table_bracket_column_variable(
4342        vec![
4343            token(TokenKind::Selector(SmolStr::new("."))),
4344            token(TokenKind::LBracket),
4345            token(TokenKind::RBracket),
4346            token(TokenKind::LBracket),
4347            token(TokenKind::Ident(SmolStr::new("v"))),
4348            token(TokenKind::RBracket),
4349            token(TokenKind::Eof),
4350        ],
4351        Ok(vec![Shared::new(Node {
4352            token_id: 5.into(),
4353            expr: Shared::new(Expr::SelectorCall(
4354                Selector::Table(None, None),
4355                smallvec![
4356                    Shared::new(Node {
4357                        token_id: 4.into(),
4358                        expr: Shared::new(Expr::Literal(Literal::None)),
4359                    }),
4360                    Shared::new(Node {
4361                        token_id: 2.into(),
4362                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
4363                            "v",
4364                            Some(Shared::new(token(TokenKind::Ident(SmolStr::new("v"))))),
4365                        ))),
4366                    }),
4367                ],
4368            )),
4369        })]))]
4370    #[case::selector_call_table_bracket_variable(
4371        vec![
4372            token(TokenKind::Selector(SmolStr::new("."))),
4373            token(TokenKind::LBracket),
4374            token(TokenKind::Ident(SmolStr::new("v"))),
4375            token(TokenKind::RBracket),
4376            token(TokenKind::LBracket),
4377            token(TokenKind::RBracket),
4378            token(TokenKind::Eof),
4379        ],
4380        Ok(vec![Shared::new(Node {
4381            token_id: 4.into(),
4382            expr: Shared::new(Expr::SelectorCall(
4383                Selector::Table(None, None),
4384                smallvec![Shared::new(Node {
4385                    token_id: 1.into(),
4386                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(
4387                        "v",
4388                        Some(Shared::new(token(TokenKind::Ident(SmolStr::new("v"))))),
4389                    ))),
4390                })],
4391            )),
4392        })]))]
4393    #[case::selector_call_table_bracket_row_col_args(
4394        vec![
4395            token(TokenKind::Selector(SmolStr::new("."))),
4396            token(TokenKind::LBracket),
4397            token(TokenKind::RBracket),
4398            token(TokenKind::LBracket),
4399            token(TokenKind::RBracket),
4400            token(TokenKind::LParen),
4401            token(TokenKind::NumberLiteral(1.into())),
4402            token(TokenKind::Comma),
4403            token(TokenKind::NumberLiteral(2.into())),
4404            token(TokenKind::RParen),
4405            token(TokenKind::Eof),
4406        ],
4407        Ok(vec![Shared::new(Node {
4408            token_id: 4.into(),
4409            expr: Shared::new(Expr::SelectorCall(
4410                Selector::Table(None, None),
4411                smallvec![
4412                    Shared::new(Node {
4413                        token_id: 2.into(),
4414                        expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
4415                    }),
4416                    Shared::new(Node {
4417                        token_id: 3.into(),
4418                        expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
4419                    }),
4420                ],
4421            )),
4422        })]))]
4423    #[case::foreach_error(
4424        vec![
4425            token(TokenKind::Foreach),
4426            token(TokenKind::LParen),
4427            token(TokenKind::Ident(SmolStr::new("item"))),
4428            token(TokenKind::Comma),
4429            token(TokenKind::StringLiteral("array".to_owned())),
4430            token(TokenKind::RParen),
4431            token(TokenKind::Colon),
4432            token(TokenKind::Eof),
4433        ],
4434        Err(SyntaxError::UnexpectedEOFDetected(Module::TOP_LEVEL_MODULE_ID)))]
4435    #[case::while_error(
4436        vec![
4437            token(TokenKind::While),
4438            token(TokenKind::LParen),
4439            token(TokenKind::BoolLiteral(true)),
4440            token(TokenKind::RParen),
4441            token(TokenKind::Colon),
4442            token(TokenKind::Eof),
4443        ],
4444        Err(SyntaxError::UnexpectedEOFDetected(Module::TOP_LEVEL_MODULE_ID)))]
4445    #[case::using_reserved_keyword_let(
4446            vec![
4447                token(TokenKind::Let),
4448                token(TokenKind::If),  // Using "if" as a variable name (should error)
4449                token(TokenKind::Equal),
4450                token(TokenKind::NumberLiteral(42.into())),
4451                token(TokenKind::Eof)
4452            ],
4453            Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::If, module_id: 1.into()})))]
4454    #[case::using_reserved_keyword_while(
4455            vec![
4456                token(TokenKind::Let),
4457                token(TokenKind::While),  // Using "while" as a variable name (should error)
4458                token(TokenKind::Equal),
4459                token(TokenKind::NumberLiteral(42.into())),
4460                token(TokenKind::Eof)
4461            ],
4462            Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::While, module_id: 1.into()})))]
4463    #[case::using_reserved_keyword_def(
4464            vec![
4465                token(TokenKind::Let),
4466                token(TokenKind::Def),  // Using "def" as a variable name (should error)
4467                token(TokenKind::Equal),
4468                token(TokenKind::NumberLiteral(42.into())),
4469                token(TokenKind::Eof)
4470            ],
4471            Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::Def, module_id: 1.into()})))]
4472    #[case::using_reserved_keyword_include(
4473            vec![
4474                token(TokenKind::Let),
4475                token(TokenKind::Include),  // Using "include" as a variable name (should error)
4476                token(TokenKind::Equal),
4477                token(TokenKind::NumberLiteral(42.into())),
4478                token(TokenKind::Eof)
4479            ],
4480            Err(SyntaxError::UnexpectedToken(Token{range: Range::default(), kind: TokenKind::Include, module_id: 1.into()})))]
4481    #[case::nodes(
4482        vec![
4483            token(TokenKind::Nodes),
4484            token(TokenKind::Eof)
4485        ],
4486        Ok(vec![
4487            Shared::new(Node {
4488                token_id: 0.into(),
4489                expr: Shared::new(Expr::Nodes),
4490            })
4491        ]))]
4492    #[case::nodes_error_in_subprogram(
4493        vec![
4494            token(TokenKind::Def),
4495            token(TokenKind::Ident(SmolStr::new("test"))),
4496            token(TokenKind::LParen),
4497            token(TokenKind::RParen),
4498            token(TokenKind::Colon),
4499            token(TokenKind::Nodes),
4500            token(TokenKind::SemiColon)
4501        ],
4502        Err(SyntaxError::UnexpectedToken(token(TokenKind::Nodes))))]
4503    #[case::nodes_then_selector(
4504        vec![
4505            token(TokenKind::Nodes),
4506            token(TokenKind::Pipe),
4507            token(TokenKind::Selector(SmolStr::new(".h1"))),
4508            token(TokenKind::Eof)
4509        ],
4510        Ok(vec![
4511            Shared::new(Node {
4512                token_id: 0.into(),
4513                expr: Shared::new(Expr::Nodes),
4514            }),
4515            Shared::new(Node {
4516                token_id: 1.into(),
4517                expr: Shared::new(Expr::Selector(Selector::Heading(Some(1)))),
4518            })
4519        ]))]
4520    #[case::root_level_with_multiple_pipes(
4521        vec![
4522            token(TokenKind::Nodes),
4523            token(TokenKind::Pipe),
4524            token(TokenKind::Nodes),
4525            token(TokenKind::Pipe),
4526            token(TokenKind::Selector(SmolStr::new(".h1"))),
4527            token(TokenKind::Pipe),
4528            token(TokenKind::Selector(SmolStr::new(".text"))),
4529            token(TokenKind::Eof)
4530        ],
4531        Ok(vec![
4532            Shared::new(Node {
4533                token_id: 0.into(),
4534                expr: Shared::new(Expr::Nodes),
4535            }),
4536            Shared::new(Node {
4537                token_id: 1.into(),
4538                expr: Shared::new(Expr::Nodes),
4539            }),
4540            Shared::new(Node {
4541                token_id: 2.into(),
4542                expr: Shared::new(Expr::Selector(Selector::Heading(Some(1)))),
4543            }),
4544            Shared::new(Node {
4545                token_id: 3.into(),
4546                expr: Shared::new(Expr::Selector(Selector::Text)),
4547            })
4548        ]))]
4549    #[case::fn_simple(
4550        vec![
4551            token(TokenKind::Fn),
4552            token(TokenKind::LParen),
4553            token(TokenKind::RParen),
4554            token(TokenKind::Colon),
4555            token(TokenKind::StringLiteral("result".to_owned())),
4556            token(TokenKind::SemiColon),
4557        ],
4558        Ok(vec![
4559            Shared::new(Node {
4560                token_id: 0.into(),
4561                expr: Shared::new(Expr::Fn(
4562                    SmallVec::new(),
4563                    vec![
4564                        Shared::new(Node {
4565                            token_id: 2.into(),
4566                            expr: Shared::new(Expr::Literal(Literal::String("result".to_owned()))),
4567                        })
4568                    ],
4569                )),
4570            })
4571        ]))]
4572    #[case::fn_with_args(
4573        vec![
4574            token(TokenKind::Fn),
4575            token(TokenKind::LParen),
4576            token(TokenKind::Ident(SmolStr::new("x"))),
4577            token(TokenKind::Comma),
4578            token(TokenKind::Ident(SmolStr::new("y"))),
4579            token(TokenKind::RParen),
4580            token(TokenKind::Colon),
4581            token(TokenKind::Ident(SmolStr::new("contains"))),
4582            token(TokenKind::LParen),
4583            token(TokenKind::Ident(SmolStr::new("x"))),
4584            token(TokenKind::Comma),
4585            token(TokenKind::Ident(SmolStr::new("y"))),
4586            token(TokenKind::RParen),
4587            token(TokenKind::SemiColon),
4588        ],
4589        Ok(vec![
4590            Shared::new(Node {
4591                token_id: 0.into(),
4592                expr: Shared::new(Expr::Fn(
4593                    smallvec![
4594                        Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
4595                        Param::new(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y"))))))),
4596                    ],
4597                    vec![
4598                        Shared::new(Node {
4599                            token_id: 4.into(),
4600                            expr: Shared::new(Expr::Call(
4601                                IdentWithToken::new_with_token("contains", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("contains")))))),
4602                                smallvec![
4603                                    Shared::new(Node {
4604                                        token_id: 2.into(),
4605                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
4606                                    }),
4607                                    Shared::new(Node {
4608                                        token_id: 3.into(),
4609                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
4610                                    }),
4611                                ],
4612                            )),
4613                        })
4614                    ],
4615                )),
4616            })
4617        ]))]
4618    #[case::fn_with_multiple_statements(
4619        vec![
4620            token(TokenKind::Fn),
4621            token(TokenKind::LParen),
4622            token(TokenKind::Ident(SmolStr::new("x"))),
4623            token(TokenKind::RParen),
4624            token(TokenKind::Colon),
4625            token(TokenKind::StringLiteral("first".to_owned())),
4626            token(TokenKind::Pipe),
4627            token(TokenKind::StringLiteral("second".to_owned())),
4628            token(TokenKind::SemiColon),
4629        ],
4630        Ok(vec![
4631            Shared::new(Node {
4632                token_id: 0.into(),
4633                expr: Shared::new(Expr::Fn(
4634                    smallvec![
4635                        Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
4636                    ],
4637                    vec![
4638                        Shared::new(Node {
4639                            token_id: 2.into(),
4640                            expr: Shared::new(Expr::Literal(Literal::String("first".to_owned()))),
4641                        }),
4642                        Shared::new(Node {
4643                            token_id: 3.into(),
4644                            expr: Shared::new(Expr::Literal(Literal::String("second".to_owned()))),
4645                        })
4646                    ],
4647                )),
4648            })
4649        ]))]
4650    #[case::fn_with_invalid_args(
4651        vec![
4652            token(TokenKind::Fn),
4653            token(TokenKind::LParen),
4654            token(TokenKind::StringLiteral("invalid".to_owned())),
4655            token(TokenKind::RParen),
4656            token(TokenKind::Colon),
4657            token(TokenKind::StringLiteral("result".to_owned())),
4658            token(TokenKind::SemiColon),
4659        ],
4660        Err(SyntaxError::UnexpectedToken(token(TokenKind::StringLiteral("invalid".to_owned())))))]
4661    #[case::fn_without_body(
4662        vec![
4663            token(TokenKind::Fn),
4664            token(TokenKind::LParen),
4665            token(TokenKind::RParen),
4666            token(TokenKind::Colon),
4667            token(TokenKind::SemiColon),
4668        ],
4669        Err(SyntaxError::UnexpectedToken(token(TokenKind::SemiColon))))]
4670    #[case::fn_nested_in_call(
4671        vec![
4672            token(TokenKind::Ident(SmolStr::new("apply"))),
4673            token(TokenKind::LParen),
4674            token(TokenKind::Fn),
4675            token(TokenKind::LParen),
4676            token(TokenKind::Ident(SmolStr::new("x"))),
4677            token(TokenKind::RParen),
4678            token(TokenKind::Colon),
4679            token(TokenKind::StringLiteral("processed".to_owned())),
4680            token(TokenKind::SemiColon),
4681            token(TokenKind::RParen),
4682            token(TokenKind::Eof),
4683        ],
4684        Ok(vec![
4685            Shared::new(Node {
4686                token_id: 4.into(),
4687                expr: Shared::new(Expr::Call(
4688                    IdentWithToken::new_with_token("apply", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("apply")))))),
4689                    smallvec![
4690                        Shared::new(Node {
4691                            token_id: 0.into(),
4692                            expr: Shared::new(Expr::Fn(
4693                                smallvec![
4694                                  Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
4695                                ],
4696                                vec![
4697                                    Shared::new(Node {
4698                                        token_id: 2.into(),
4699                                        expr: Shared::new(Expr::Literal(Literal::String("processed".to_owned()))),
4700                                    })
4701                                ],
4702                            )),
4703                        })
4704                    ],
4705                )),
4706            })
4707        ]))]
4708    #[case::empty_array(
4709                vec![
4710                    token(TokenKind::LBracket),
4711                    token(TokenKind::RBracket),
4712                    token(TokenKind::Eof)
4713                ],
4714                Ok(vec![
4715                    Shared::new(Node {
4716                        token_id: 0.into(),
4717                        expr: Shared::new(Expr::Call(
4718                            IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4719                            SmallVec::new(),
4720                        )),
4721                    })
4722                ]))]
4723    #[case::array_with_elements(
4724                vec![
4725                    token(TokenKind::LBracket),
4726                    token(TokenKind::StringLiteral("first".to_owned())),
4727                    token(TokenKind::Comma),
4728                    token(TokenKind::NumberLiteral(42.into())),
4729                    token(TokenKind::RBracket),
4730                    token(TokenKind::Eof)
4731                ],
4732                Ok(vec![
4733                    Shared::new(Node {
4734                        token_id: 0.into(),
4735                        expr: Shared::new(Expr::Call(
4736                            IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4737                            smallvec![
4738                                Shared::new(Node {
4739                                    token_id: 1.into(),
4740                                    expr: Shared::new(Expr::Literal(Literal::String("first".to_owned()))),
4741                                }),
4742                                Shared::new(Node {
4743                                    token_id: 2.into(),
4744                                    expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
4745                                }),
4746                            ],
4747                        )),
4748                    })
4749                ]))]
4750    #[case::array_with_mixed_elements(
4751                vec![
4752                    token(TokenKind::LBracket),
4753                    token(TokenKind::StringLiteral("text".to_owned())),
4754                    token(TokenKind::Comma),
4755                    token(TokenKind::BoolLiteral(true)),
4756                    token(TokenKind::Comma),
4757                    token(TokenKind::None),
4758                    token(TokenKind::RBracket),
4759                    token(TokenKind::Eof)
4760                ],
4761                Ok(vec![
4762                    Shared::new(Node {
4763                        token_id: 0.into(),
4764                        expr: Shared::new(Expr::Call(
4765                            IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4766                            smallvec![
4767                                Shared::new(Node {
4768                                    token_id: 1.into(),
4769                                    expr: Shared::new(Expr::Literal(Literal::String("text".to_owned()))),
4770                                }),
4771                                Shared::new(Node {
4772                                    token_id: 2.into(),
4773                                    expr: Shared::new(Expr::Literal(Literal::Bool(true))),
4774                                }),
4775                                Shared::new(Node {
4776                                    token_id: 3.into(),
4777                                    expr: Shared::new(Expr::Literal(Literal::None)),
4778                                }),
4779                            ],
4780                        )),
4781                    })
4782                ]))]
4783    #[case::array_with_nested_array(
4784                vec![
4785                    token(TokenKind::LBracket),
4786                    token(TokenKind::LBracket),
4787                    token(TokenKind::NumberLiteral(1.into())),
4788                    token(TokenKind::RBracket),
4789                    token(TokenKind::Comma),
4790                    token(TokenKind::LBracket),
4791                    token(TokenKind::NumberLiteral(2.into())),
4792                    token(TokenKind::RBracket),
4793                    token(TokenKind::RBracket),
4794                    token(TokenKind::Eof)
4795                ],
4796                Ok(vec![
4797                    Shared::new(Node {
4798                        token_id: 0.into(),
4799                        expr: Shared::new(Expr::Call(
4800                            IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4801                            smallvec![
4802                                Shared::new(Node {
4803                                    token_id: 1.into(),
4804                                    expr: Shared::new(Expr::Call(
4805                                        IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4806                                        smallvec![
4807                                            Shared::new(Node {
4808                                                token_id: 2.into(),
4809                                                expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
4810                                            }),
4811                                        ],
4812                                    )),
4813                                }),
4814                                Shared::new(Node {
4815                                    token_id: 3.into(),
4816                                    expr: Shared::new(Expr::Call(
4817                                        IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4818                                        smallvec![
4819                                            Shared::new(Node {
4820                                                token_id: 4.into(),
4821                                                expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
4822                                            }),
4823                                        ],
4824                                    )),
4825                                }),
4826                            ],
4827                        )),
4828                    })
4829                ]))]
4830    #[case::array_with_trailing_comma(
4831                vec![
4832                    token(TokenKind::LBracket),
4833                    token(TokenKind::StringLiteral("value".to_owned())),
4834                    token(TokenKind::Comma),
4835                    token(TokenKind::RBracket),
4836                    token(TokenKind::Eof)
4837                ],
4838                Ok(vec![
4839                    Shared::new(Node {
4840                        token_id: 0.into(),
4841                        expr: Shared::new(Expr::Call(
4842                            IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4843                            smallvec![
4844                                Shared::new(Node {
4845                                    token_id: 1.into(),
4846                                    expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
4847                                }),
4848                            ],
4849                        )),
4850                    })
4851                ]))]
4852    #[case::array_unclosed(
4853                    vec![
4854                        token(TokenKind::LBracket),
4855                        token(TokenKind::StringLiteral("value".to_owned())),
4856                        token(TokenKind::Eof)
4857                    ],
4858                    Err(SyntaxError::ExpectedClosingBracket(token(TokenKind::Eof), Some(Box::new(token(TokenKind::LBracket))))))]
4859    #[case::array_invalid_token(
4860                    vec![
4861                        token(TokenKind::LBracket),
4862                        token(TokenKind::Pipe),
4863                        token(TokenKind::RBracket),
4864                        token(TokenKind::Eof)
4865                    ],
4866                    Err(SyntaxError::UnexpectedToken(token(TokenKind::Pipe))))]
4867    #[case::array_nested_unclosed(
4868                    vec![
4869                        token(TokenKind::LBracket),
4870                        token(TokenKind::LBracket),
4871                        token(TokenKind::StringLiteral("inner".to_owned())),
4872                        token(TokenKind::RBracket),
4873                        token(TokenKind::Eof)
4874                    ],
4875                    Err(SyntaxError::ExpectedClosingBracket(token(TokenKind::Eof), Some(Box::new(token(TokenKind::LBracket))))))]
4876    #[case::array_with_ident(
4877                    vec![
4878                        token(TokenKind::LBracket),
4879                        token(TokenKind::Ident(SmolStr::new("foo"))),
4880                        token(TokenKind::Comma),
4881                        token(TokenKind::Ident(SmolStr::new("bar"))),
4882                        token(TokenKind::RBracket),
4883                        token(TokenKind::Eof)
4884                    ],
4885                    Ok(vec![
4886                        Shared::new(Node {
4887                            token_id: 0.into(),
4888                            expr: Shared::new(Expr::Call(
4889                                IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
4890                                smallvec![
4891                                    Shared::new(Node {
4892                                        token_id: 1.into(),
4893                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))))),
4894                                    }),
4895                                    Shared::new(Node {
4896                                        token_id: 2.into(),
4897                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("bar", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("bar")))))))),
4898                                    }),
4899                                ],
4900                            )),
4901                        })
4902                    ]))]
4903    #[case::equality_simple(
4904                    vec![
4905                        token(TokenKind::StringLiteral("hello".to_owned())),
4906                        token(TokenKind::EqEq),
4907                        token(TokenKind::StringLiteral("world".to_owned())),
4908                        token(TokenKind::Eof)
4909                    ],
4910                    Ok(vec![
4911                        Shared::new(Node {
4912                            token_id: 1.into(),
4913                            expr: Shared::new(Expr::Call(
4914                                IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
4915                                smallvec![
4916                                    Shared::new(Node {
4917                                        token_id: 0.into(),
4918                                        expr: Shared::new(Expr::Literal(Literal::String("hello".to_owned()))),
4919                                    }),
4920                                    Shared::new(Node {
4921                                        token_id: 2.into(),
4922                                        expr: Shared::new(Expr::Literal(Literal::String("world".to_owned()))),
4923                                    }),
4924                                ],
4925                            )),
4926                        })
4927                    ]))]
4928    #[case::equality_numbers(
4929                    vec![
4930                        token(TokenKind::NumberLiteral(42.into())),
4931                        token(TokenKind::EqEq),
4932                        token(TokenKind::NumberLiteral(42.into())),
4933                        token(TokenKind::Eof)
4934                    ],
4935                    Ok(vec![
4936                        Shared::new(Node {
4937                            token_id: 1.into(),
4938                            expr: Shared::new(Expr::Call(
4939                                IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
4940                                smallvec![
4941                                    Shared::new(Node {
4942                                        token_id: 0.into(),
4943                                        expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
4944                                    }),
4945                                    Shared::new(Node {
4946                                        token_id: 2.into(),
4947                                        expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
4948                                    }),
4949                                ],
4950                            )),
4951                        })
4952                    ]))]
4953    #[case::equality_booleans(
4954                    vec![
4955                        token(TokenKind::BoolLiteral(true)),
4956                        token(TokenKind::EqEq),
4957                        token(TokenKind::BoolLiteral(false)),
4958                        token(TokenKind::Eof)
4959                    ],
4960                    Ok(vec![
4961                        Shared::new(Node {
4962                            token_id: 1.into(),
4963                            expr: Shared::new(Expr::Call(
4964                                IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
4965                                smallvec![
4966                                    Shared::new(Node {
4967                                        token_id: 0.into(),
4968                                        expr: Shared::new(Expr::Literal(Literal::Bool(true))),
4969                                    }),
4970                                    Shared::new(Node {
4971                                        token_id: 2.into(),
4972                                        expr: Shared::new(Expr::Literal(Literal::Bool(false))),
4973                                    }),
4974                                ],
4975                            )),
4976                        })
4977                    ]))]
4978    #[case::equality_with_identifiers(
4979                    vec![
4980                        token(TokenKind::Ident(SmolStr::new("x"))),
4981                        token(TokenKind::EqEq),
4982                        token(TokenKind::Ident(SmolStr::new("y"))),
4983                        token(TokenKind::Eof)
4984                    ],
4985                    Ok(vec![
4986                        Shared::new(Node {
4987                            token_id: 1.into(),
4988                            expr: Shared::new(Expr::Call(
4989                                IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
4990                                smallvec![
4991                                    Shared::new(Node {
4992                                        token_id: 0.into(),
4993                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
4994                                    }),
4995                                    Shared::new(Node {
4996                                        token_id: 2.into(),
4997                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
4998                                    }),
4999                                ],
5000                            )),
5001                        })
5002                    ]))]
5003    #[case::equality_with_function_call(
5004                    vec![
5005                        token(TokenKind::Ident(SmolStr::new("foo"))),
5006                        token(TokenKind::LParen),
5007                        token(TokenKind::StringLiteral("arg".to_owned())),
5008                        token(TokenKind::RParen),
5009                        token(TokenKind::EqEq),
5010                        token(TokenKind::StringLiteral("result".to_owned())),
5011                        token(TokenKind::Eof)
5012                    ],
5013                    Ok(vec![
5014                        Shared::new(Node {
5015                            token_id: 2.into(),
5016                            expr: Shared::new(Expr::Call(
5017                                IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
5018                                smallvec![
5019                                    Shared::new(Node {
5020                                        token_id: 1.into(),
5021                                        expr: Shared::new(Expr::Call(
5022                                            IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
5023                                            smallvec![
5024                                                Shared::new(Node {
5025                                                    token_id: 0.into(),
5026                                                    expr: Shared::new(Expr::Literal(Literal::String("arg".to_owned()))),
5027                                                }),
5028                                            ],
5029                                        )),
5030                                    }),
5031                                    Shared::new(Node {
5032                                        token_id: 3.into(),
5033                                        expr: Shared::new(Expr::Literal(Literal::String("result".to_owned()))),
5034                                    }),
5035                                ],
5036                            )),
5037                        })
5038                    ]))]
5039    #[case::equality_with_selectors(
5040                    vec![
5041                        token(TokenKind::Selector(SmolStr::new(".h1"))),
5042                        token(TokenKind::EqEq),
5043                        token(TokenKind::Selector(SmolStr::new(".text"))),
5044                        token(TokenKind::Eof)
5045                    ],
5046                    Ok(vec![
5047                        Shared::new(Node {
5048                            token_id: 1.into(),
5049                            expr: Shared::new(Expr::Call(
5050                                IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
5051                                smallvec![
5052                                    Shared::new(Node {
5053                                        token_id: 0.into(),
5054                                        expr: Shared::new(Expr::Selector(Selector::Heading(Some(1)))),
5055                                    }),
5056                                    Shared::new(Node {
5057                                        token_id: 2.into(),
5058                                        expr: Shared::new(Expr::Selector(Selector::Text)),
5059                                    }),
5060                                ],
5061                            )),
5062                        })
5063                    ]))]
5064    #[case::equality_with_none(
5065                    vec![
5066                        token(TokenKind::None),
5067                        token(TokenKind::EqEq),
5068                        token(TokenKind::None),
5069                        token(TokenKind::Eof)
5070                    ],
5071                    Ok(vec![
5072                        Shared::new(Node {
5073                            token_id: 1.into(),
5074                            expr: Shared::new(Expr::Call(
5075                                IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
5076                                smallvec![
5077                                    Shared::new(Node {
5078                                        token_id: 0.into(),
5079                                        expr: Shared::new(Expr::Literal(Literal::None)),
5080                                    }),
5081                                    Shared::new(Node {
5082                                        token_id: 2.into(),
5083                                        expr: Shared::new(Expr::Literal(Literal::None)),
5084                                    }),
5085                                ],
5086                            )),
5087                        })
5088                    ]))]
5089    #[case::equality_error_missing_rhs(
5090                    vec![
5091                        token(TokenKind::StringLiteral("hello".to_owned())),
5092                        token(TokenKind::EqEq),
5093                        token(TokenKind::Eof)
5094                    ],
5095                    Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::EqEq))))]
5096    #[case::equality_in_if_condition(
5097                    vec![
5098                        token(TokenKind::If),
5099                        token(TokenKind::LParen),
5100                        token(TokenKind::Ident(SmolStr::new("x"))),
5101                        token(TokenKind::EqEq),
5102                        token(TokenKind::NumberLiteral(5.into())),
5103                        token(TokenKind::RParen),
5104                        token(TokenKind::Colon),
5105                        token(TokenKind::StringLiteral("equal".to_owned())),
5106                        token(TokenKind::Eof)
5107                    ],
5108                    Ok(vec![
5109                        Shared::new(Node {
5110                            token_id: 6.into(),
5111                            expr: Shared::new(Expr::If(smallvec![
5112                                (
5113                                    Some(Shared::new(Node {
5114                                        token_id: 2.into(),
5115                                        expr: Shared::new(Expr::Call(
5116                                            IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
5117                                            smallvec![
5118                                                Shared::new(Node {
5119                                                    token_id: 1.into(),
5120                                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
5121                                                }),
5122                                                Shared::new(Node {
5123                                                    token_id: 3.into(),
5124                                                    expr: Shared::new(Expr::Literal(Literal::Number(5.into()))),
5125                                                }),
5126                                            ],
5127                                        )),
5128                                    })),
5129                                    Shared::new(Node {
5130                                        token_id: 5.into(),
5131                                        expr: Shared::new(Expr::Literal(Literal::String("equal".to_owned()))),
5132                                    })
5133                                ),
5134                            ])),
5135                        })
5136                    ]))]
5137    #[case::not_equality_simple(
5138                    vec![
5139                        token(TokenKind::StringLiteral("hello".to_owned())),
5140                        token(TokenKind::NeEq),
5141                        token(TokenKind::StringLiteral("world".to_owned())),
5142                        token(TokenKind::Eof)
5143                    ],
5144                    Ok(vec![
5145                        Shared::new(Node {
5146                            token_id: 1.into(),
5147                            expr: Shared::new(Expr::Call(
5148                                IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5149                                smallvec![
5150                                    Shared::new(Node {
5151                                        token_id: 0.into(),
5152                                        expr: Shared::new(Expr::Literal(Literal::String("hello".to_owned()))),
5153                                    }),
5154                                    Shared::new(Node {
5155                                        token_id: 2.into(),
5156                                        expr: Shared::new(Expr::Literal(Literal::String("world".to_owned()))),
5157                                    }),
5158                                ],
5159                            )),
5160                        })
5161                    ]))]
5162    #[case::not_equality_numbers(
5163                    vec![
5164                        token(TokenKind::NumberLiteral(42.into())),
5165                        token(TokenKind::NeEq),
5166                        token(TokenKind::NumberLiteral(24.into())),
5167                        token(TokenKind::Eof)
5168                    ],
5169                    Ok(vec![
5170                        Shared::new(Node {
5171                            token_id: 1.into(),
5172                            expr: Shared::new(Expr::Call(
5173                                IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5174                                smallvec![
5175                                    Shared::new(Node {
5176                                        token_id: 0.into(),
5177                                        expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
5178                                    }),
5179                                    Shared::new(Node {
5180                                        token_id: 2.into(),
5181                                        expr: Shared::new(Expr::Literal(Literal::Number(24.into()))),
5182                                    }),
5183                                ],
5184                            )),
5185                        })
5186                    ]))]
5187    #[case::not_equality_booleans(
5188                    vec![
5189                        token(TokenKind::BoolLiteral(true)),
5190                        token(TokenKind::NeEq),
5191                        token(TokenKind::BoolLiteral(false)),
5192                        token(TokenKind::Eof)
5193                    ],
5194                    Ok(vec![
5195                        Shared::new(Node {
5196                            token_id: 1.into(),
5197                            expr: Shared::new(Expr::Call(
5198                                IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5199                                smallvec![
5200                                    Shared::new(Node {
5201                                        token_id: 0.into(),
5202                                        expr: Shared::new(Expr::Literal(Literal::Bool(true))),
5203                                    }),
5204                                    Shared::new(Node {
5205                                        token_id: 2.into(),
5206                                        expr: Shared::new(Expr::Literal(Literal::Bool(false))),
5207                                    }),
5208                                ],
5209                            )),
5210                        })
5211                    ]))]
5212    #[case::not_equality_with_identifiers(
5213                    vec![
5214                        token(TokenKind::Ident(SmolStr::new("x"))),
5215                        token(TokenKind::NeEq),
5216                        token(TokenKind::Ident(SmolStr::new("y"))),
5217                        token(TokenKind::Eof)
5218                    ],
5219                    Ok(vec![
5220                        Shared::new(Node {
5221                            token_id: 1.into(),
5222                            expr: Shared::new(Expr::Call(
5223                                IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5224                                smallvec![
5225                                    Shared::new(Node {
5226                                        token_id: 0.into(),
5227                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
5228                                    }),
5229                                    Shared::new(Node {
5230                                        token_id: 2.into(),
5231                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
5232                                    }),
5233                                ],
5234                            )),
5235                        })
5236                    ]))]
5237    #[case::not_equality_with_function_call(
5238                    vec![
5239                        token(TokenKind::Ident(SmolStr::new("foo"))),
5240                        token(TokenKind::LParen),
5241                        token(TokenKind::StringLiteral("arg".to_owned())),
5242                        token(TokenKind::RParen),
5243                        token(TokenKind::NeEq),
5244                        token(TokenKind::StringLiteral("result".to_owned())),
5245                        token(TokenKind::Eof)
5246                    ],
5247                    Ok(vec![
5248                        Shared::new(Node {
5249                            token_id: 2.into(),
5250                            expr: Shared::new(Expr::Call(
5251                                IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5252                                smallvec![
5253                                    Shared::new(Node {
5254                                        token_id: 1.into(),
5255                                        expr: Shared::new(Expr::Call(
5256                                            IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
5257                                            smallvec![
5258                                                Shared::new(Node {
5259                                                    token_id: 0.into(),
5260                                                    expr: Shared::new(Expr::Literal(Literal::String("arg".to_owned()))),
5261                                                }),
5262                                            ],
5263                                        )),
5264                                    }),
5265                                    Shared::new(Node {
5266                                        token_id: 3.into(),
5267                                        expr: Shared::new(Expr::Literal(Literal::String("result".to_owned()))),
5268                                    }),
5269                                ],
5270                            )),
5271                        })
5272                    ]))]
5273    #[case::not_equality_with_selectors(
5274                    vec![
5275                        token(TokenKind::Selector(SmolStr::new(".h1"))),
5276                        token(TokenKind::NeEq),
5277                        token(TokenKind::Selector(SmolStr::new(".text"))),
5278                        token(TokenKind::Eof)
5279                    ],
5280                    Ok(vec![
5281                        Shared::new(Node {
5282                            token_id: 1.into(),
5283                            expr: Shared::new(Expr::Call(
5284                                IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5285                                smallvec![
5286                                    Shared::new(Node {
5287                                        token_id: 0.into(),
5288                                        expr: Shared::new(Expr::Selector(Selector::Heading(Some(1)))),
5289                                    }),
5290                                    Shared::new(Node {
5291                                        token_id: 2.into(),
5292                                        expr: Shared::new(Expr::Selector(Selector::Text)),
5293                                    }),
5294                                ],
5295                            )),
5296                        })
5297                    ]))]
5298    #[case::not_equality_with_none(
5299                    vec![
5300                        token(TokenKind::None),
5301                        token(TokenKind::NeEq),
5302                        token(TokenKind::StringLiteral("something".to_owned())),
5303                        token(TokenKind::Eof)
5304                    ],
5305                    Ok(vec![
5306                        Shared::new(Node {
5307                            token_id: 1.into(),
5308                            expr: Shared::new(Expr::Call(
5309                                IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5310                                smallvec![
5311                                    Shared::new(Node {
5312                                        token_id: 0.into(),
5313                                        expr: Shared::new(Expr::Literal(Literal::None)),
5314                                    }),
5315                                    Shared::new(Node {
5316                                        token_id: 2.into(),
5317                                        expr: Shared::new(Expr::Literal(Literal::String("something".to_owned()))),
5318                                    }),
5319                                ],
5320                            )),
5321                        })
5322                    ]))]
5323    #[case::not_equality_error_missing_rhs(
5324                    vec![
5325                        token(TokenKind::StringLiteral("hello".to_owned())),
5326                        token(TokenKind::NeEq),
5327                        token(TokenKind::Eof)
5328                    ],
5329                    Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::NeEq))))]
5330    #[case::not_equality_in_if_condition(
5331                    vec![
5332                        token(TokenKind::If),
5333                        token(TokenKind::LParen),
5334                        token(TokenKind::Ident(SmolStr::new("x"))),
5335                        token(TokenKind::NeEq),
5336                        token(TokenKind::NumberLiteral(5.into())),
5337                        token(TokenKind::RParen),
5338                        token(TokenKind::Colon),
5339                        token(TokenKind::StringLiteral("not equal".to_owned())),
5340                        token(TokenKind::Eof)
5341                    ],
5342                    Ok(vec![
5343                        Shared::new(Node {
5344                            token_id: 6.into(),
5345                            expr: Shared::new(Expr::If(smallvec![
5346                                (
5347                                    Some(Shared::new(Node {
5348                                        token_id: 2.into(),
5349                                        expr: Shared::new(Expr::Call(
5350                                            IdentWithToken::new_with_token(constants::builtins::NE, Some(Shared::new(token(TokenKind::NeEq)))),
5351                                            smallvec![
5352                                                Shared::new(Node {
5353                                                    token_id: 1.into(),
5354                                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
5355                                                }),
5356                                                Shared::new(Node {
5357                                                    token_id: 3.into(),
5358                                                    expr: Shared::new(Expr::Literal(Literal::Number(5.into()))),
5359                                                }),
5360                                            ],
5361                                        )),
5362                                    })),
5363                                    Shared::new(Node {
5364                                        token_id: 5.into(),
5365                                        expr: Shared::new(Expr::Literal(Literal::String("not equal".to_owned()))),
5366                                    })
5367                                ),
5368                            ])),
5369                        })
5370                    ]))]
5371    #[case::plus_simple(
5372                    vec![
5373                        token(TokenKind::NumberLiteral(1.into())),
5374                        token(TokenKind::Plus),
5375                        token(TokenKind::NumberLiteral(2.into())),
5376                        token(TokenKind::Eof)
5377                    ],
5378                    Ok(vec![
5379                        Shared::new(Node {
5380                            token_id: 1.into(),
5381                            expr: Shared::new(Expr::Call(
5382                                IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
5383                                smallvec![
5384                                    Shared::new(Node {
5385                                        token_id: 0.into(),
5386                                        expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
5387                                    }),
5388                                    Shared::new(Node {
5389                                        token_id: 2.into(),
5390                                        expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5391                                    }),
5392                                ],
5393                            )),
5394                        })
5395                    ]))]
5396    #[case::plus_with_identifiers(
5397                    vec![
5398                        token(TokenKind::Ident(SmolStr::new("x"))),
5399                        token(TokenKind::Plus),
5400                        token(TokenKind::Ident(SmolStr::new("y"))),
5401                        token(TokenKind::Eof)
5402                    ],
5403                    Ok(vec![
5404                        Shared::new(Node {
5405                            token_id: 1.into(),
5406                            expr: Shared::new(Expr::Call(
5407                                IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
5408                                smallvec![
5409                                    Shared::new(Node {
5410                                        token_id: 0.into(),
5411                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
5412                                    }),
5413                                    Shared::new(Node {
5414                                        token_id: 2.into(),
5415                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
5416                                    }),
5417                                ],
5418                            )),
5419                        })
5420                    ]))]
5421    #[case::plus_error_missing_rhs(
5422                    vec![
5423                        token(TokenKind::NumberLiteral(1.into())),
5424                        token(TokenKind::Plus),
5425                        token(TokenKind::Eof)
5426                    ],
5427                    Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Plus))))]
5428    #[case::lt_simple(
5429                    vec![
5430                        token(TokenKind::NumberLiteral(1.into())),
5431                        token(TokenKind::Lt),
5432                        token(TokenKind::NumberLiteral(2.into())),
5433                        token(TokenKind::Eof)
5434                    ],
5435                    Ok(vec![
5436                        Shared::new(Node {
5437                            token_id: 1.into(),
5438                            expr: Shared::new(Expr::Call(
5439                                IdentWithToken::new_with_token(constants::builtins::LT, Some(Shared::new(token(TokenKind::Lt)))),
5440                                smallvec![
5441                                    Shared::new(Node {
5442                                        token_id: 0.into(),
5443                                        expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
5444                                    }),
5445                                    Shared::new(Node {
5446                                        token_id: 2.into(),
5447                                        expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5448                                    }),
5449                                ],
5450                            )),
5451                        })
5452                    ]))]
5453    #[case::lte_simple(
5454                    vec![
5455                        token(TokenKind::NumberLiteral(1.into())),
5456                        token(TokenKind::Lte),
5457                        token(TokenKind::NumberLiteral(2.into())),
5458                        token(TokenKind::Eof)
5459                    ],
5460                    Ok(vec![
5461                        Shared::new(Node {
5462                            token_id: 1.into(),
5463                            expr: Shared::new(Expr::Call(
5464                                IdentWithToken::new_with_token(constants::builtins::LTE, Some(Shared::new(token(TokenKind::Lte)))),
5465                                smallvec![
5466                                    Shared::new(Node {
5467                                        token_id: 0.into(),
5468                                        expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
5469                                    }),
5470                                    Shared::new(Node {
5471                                        token_id: 2.into(),
5472                                        expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5473                                    }),
5474                                ],
5475                            )),
5476                        })
5477                    ]))]
5478    #[case::gt_simple(
5479                    vec![
5480                        token(TokenKind::NumberLiteral(3.into())),
5481                        token(TokenKind::Gt),
5482                        token(TokenKind::NumberLiteral(2.into())),
5483                        token(TokenKind::Eof)
5484                    ],
5485                    Ok(vec![
5486                        Shared::new(Node {
5487                            token_id: 1.into(),
5488                            expr: Shared::new(Expr::Call(
5489                                IdentWithToken::new_with_token(constants::builtins::GT, Some(Shared::new(token(TokenKind::Gt)))),
5490                                smallvec![
5491                                    Shared::new(Node {
5492                                        token_id: 0.into(),
5493                                        expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
5494                                    }),
5495                                    Shared::new(Node {
5496                                        token_id: 2.into(),
5497                                        expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5498                                    }),
5499                                ],
5500                            )),
5501                        })
5502                    ]))]
5503    #[case::gte_simple(
5504                    vec![
5505                        token(TokenKind::NumberLiteral(3.into())),
5506                        token(TokenKind::Gte),
5507                        token(TokenKind::NumberLiteral(2.into())),
5508                        token(TokenKind::Eof)
5509                    ],
5510                    Ok(vec![
5511                        Shared::new(Node {
5512                            token_id: 1.into(),
5513                            expr: Shared::new(Expr::Call(
5514                                IdentWithToken::new_with_token(constants::builtins::GTE, Some(Shared::new(token(TokenKind::Gte)))),
5515                                smallvec![
5516                                    Shared::new(Node {
5517                                        token_id: 0.into(),
5518                                        expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
5519                                    }),
5520                                    Shared::new(Node {
5521                                        token_id: 2.into(),
5522                                        expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5523                                    }),
5524                                ],
5525                            )),
5526                        })
5527                    ]))]
5528    #[case::dict_empty(
5529                        vec![
5530                            token(TokenKind::LBrace),
5531                            token(TokenKind::RBrace),
5532                            token(TokenKind::Eof)
5533                        ],
5534                        Ok(vec![
5535                            Shared::new(Node {
5536                                token_id: 0.into(),
5537                                expr: Shared::new(Expr::Call(
5538                                    IdentWithToken::new_with_token(constants::builtins::DICT, Some(Shared::new(token(TokenKind::LBrace)))),
5539                                    SmallVec::new(),
5540                                )),
5541                            })
5542                        ]))]
5543    #[case::dict_single_pair(
5544                        vec![
5545                            token(TokenKind::LBrace),
5546                            token(TokenKind::Ident(SmolStr::new("key"))),
5547                            token(TokenKind::Colon),
5548                            token(TokenKind::StringLiteral("value".to_owned())),
5549                            token(TokenKind::RBrace),
5550                            token(TokenKind::Eof)
5551                        ],
5552                        Ok(vec![
5553                            Shared::new(Node {
5554                                token_id: 0.into(),
5555                                expr: Shared::new(Expr::Call(
5556                                    IdentWithToken::new_with_token(constants::builtins::DICT, Some(Shared::new(token(TokenKind::LBrace)))),
5557                                    smallvec![
5558                                        Shared::new(Node {
5559                                            token_id: 0.into(),
5560                                            expr: Shared::new(Expr::Call(
5561                                                IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("key")))))),
5562                                                smallvec![
5563                                                    Shared::new(Node {
5564                                                        token_id: 1.into(),
5565                                                        expr: Shared::new(Expr::Literal(Literal::Symbol(Ident::new("key")))),
5566                                                    }),
5567                                                    Shared::new(Node {
5568                                                        token_id: 2.into(),
5569                                                        expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
5570                                                    }),
5571                                                ],
5572                                            )),
5573                                        }),
5574                                    ],
5575                                )),
5576                            })
5577                        ]))]
5578    #[case::dict_multiple_pairs(
5579                        vec![
5580                            token(TokenKind::LBrace),
5581                            token(TokenKind::Ident(SmolStr::new("a"))),
5582                            token(TokenKind::Colon),
5583                            token(TokenKind::NumberLiteral(1.into())),
5584                            token(TokenKind::Comma),
5585                            token(TokenKind::StringLiteral("b".to_owned())),
5586                            token(TokenKind::Colon),
5587                            token(TokenKind::BoolLiteral(true)),
5588                            token(TokenKind::RBrace),
5589                            token(TokenKind::Eof)
5590                        ],
5591                        Ok(vec![
5592                            Shared::new(Node {
5593                                token_id: 0.into(),
5594                                expr: Shared::new(Expr::Call(
5595                                    IdentWithToken::new_with_token(constants::builtins::DICT, Some(Shared::new(token(TokenKind::LBrace)))),
5596                                    smallvec![
5597                                        Shared::new(Node {
5598                                            token_id: 0.into(),
5599                                            expr: Shared::new(Expr::Call(
5600                                                IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))),
5601                                                smallvec![
5602                                                    Shared::new(Node {
5603                                                        token_id: 1.into(),
5604                                                        expr: Shared::new(Expr::Literal(Literal::Symbol(Ident::new("a")))),
5605                                                    }),
5606                                                    Shared::new(Node {
5607                                                        token_id: 2.into(),
5608                                                        expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
5609                                                    }),
5610                                                ],
5611                                            )),
5612                                        }),
5613                                        Shared::new(Node {
5614                                            token_id: 0.into(),
5615                                            expr: Shared::new(Expr::Call(
5616                                                IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::StringLiteral("b".to_owned()))))),
5617                                                smallvec![
5618                                                    Shared::new(Node {
5619                                                        token_id: 3.into(),
5620                                                        expr: Shared::new(Expr::Literal(Literal::String("b".to_owned()))),
5621                                                    }),
5622                                                    Shared::new(Node {
5623                                                        token_id: 4.into(),
5624                                                        expr: Shared::new(Expr::Literal(Literal::Bool(true))),
5625                                                    }),
5626                                                ],
5627                                            )),
5628                                        }),
5629                                    ],
5630                                )),
5631                            })
5632                        ]))]
5633    #[case::dict_trailing_comma(
5634                        vec![
5635                            token(TokenKind::LBrace),
5636                            token(TokenKind::Ident(SmolStr::new("x"))),
5637                            token(TokenKind::Colon),
5638                            token(TokenKind::NumberLiteral(10.into())),
5639                            token(TokenKind::Comma),
5640                            token(TokenKind::RBrace),
5641                            token(TokenKind::Eof)
5642                        ],
5643                        Ok(vec![
5644                            Shared::new(Node {
5645                                token_id: 0.into(),
5646                                expr: Shared::new(Expr::Call(
5647                                    IdentWithToken::new_with_token(constants::builtins::DICT, Some(Shared::new(token(TokenKind::LBrace)))),
5648                                    smallvec![
5649                                        Shared::new(Node {
5650                                            token_id: 0.into(),
5651                                            expr: Shared::new(Expr::Call(
5652                                                IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))),
5653                                                smallvec![
5654                                                    Shared::new(Node {
5655                                                        token_id: 1.into(),
5656                                                        expr: Shared::new(Expr::Literal(Literal::Symbol(Ident::new("x")))),
5657                                                    }),
5658                                                    Shared::new(Node {
5659                                                        token_id: 2.into(),
5660                                                        expr: Shared::new(Expr::Literal(Literal::Number(10.into()))),
5661                                                    }),
5662                                                ],
5663                                            )),
5664                                        }),
5665                                    ],
5666                                )),
5667                            })
5668                        ]))]
5669    #[case::dict_unclosed(
5670                        vec![
5671                            token(TokenKind::LBrace),
5672                            token(TokenKind::Ident(SmolStr::new("k"))),
5673                            token(TokenKind::Colon),
5674                            token(TokenKind::NumberLiteral(1.into())),
5675                            token(TokenKind::Eof)
5676                        ],
5677                        Err(SyntaxError::ExpectedClosingBrace(token(TokenKind::Eof), Some(Box::new(token(TokenKind::LBrace))))))]
5678    #[case::dict_missing_colon(
5679                        vec![
5680                            token(TokenKind::LBrace),
5681                            token(TokenKind::Ident(SmolStr::new("k"))),
5682                            token(TokenKind::NumberLiteral(1.into())),
5683                            token(TokenKind::RBrace),
5684                            token(TokenKind::Eof)
5685                        ],
5686                        Err(SyntaxError::UnexpectedToken(token(TokenKind::NumberLiteral(1.into())))))]
5687    #[case::dict_invalid_key(
5688                        vec![
5689                            token(TokenKind::LBrace),
5690                            token(TokenKind::NumberLiteral(1.into())),
5691                            token(TokenKind::Colon),
5692                            token(TokenKind::StringLiteral("v".to_owned())),
5693                            token(TokenKind::RBrace),
5694                            token(TokenKind::Eof)
5695                        ],
5696                        Err(SyntaxError::UnexpectedToken(token(TokenKind::NumberLiteral(1.into())))))]
5697    #[case::attr_h_value(
5698        vec![
5699            token(TokenKind::Selector(".h".into())),
5700            token(TokenKind::Selector(".value".into())),
5701        ],
5702        Ok(vec![
5703            Shared::new(Node {
5704                token_id: 2.into(),
5705                expr: Shared::new(Expr::Call(IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Selector(".h".into()))))),
5706                    smallvec![
5707                        Shared::new(Node {
5708                            token_id: 0.into(),
5709                            expr: Shared::new(Expr::Selector(Selector::Heading(None))),
5710                        }),
5711                        Shared::new(Node {
5712                            token_id: 1.into(),
5713                            expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
5714                        }),
5715
5716                    ],
5717                ))})]))]
5718    #[case::attr(
5719        vec![
5720            token(TokenKind::Selector(".list".into())),
5721            token(TokenKind::Selector(".checked".into())),
5722        ],
5723        Ok(vec![
5724            Shared::new(Node {
5725                token_id: 2.into(),
5726                expr: Shared::new(Expr::Call(IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Selector(".list".into()))))),
5727                    smallvec![
5728                        Shared::new(Node {
5729                            token_id: 0.into(),
5730                            expr: Shared::new(Expr::Selector(Selector::List(None, None))),
5731                        }),
5732                        Shared::new(Node {
5733                            token_id: 1.into(),
5734                            expr: Shared::new(Expr::Literal(Literal::String("checked".to_owned()))),
5735                        }),
5736
5737                    ],
5738                ))})]))]
5739    #[case::paren(
5740        vec![
5741            token(TokenKind::LParen),
5742            token(TokenKind::NumberLiteral(1.into())),
5743            token(TokenKind::Plus),
5744            token(TokenKind::NumberLiteral(2.into())),
5745            token(TokenKind::RParen),
5746        ],
5747        Ok(vec![
5748            Shared::new(Node {
5749                token_id: 0.into(),
5750                expr: Shared::new(Expr::Paren(
5751                    Shared::new(Node {
5752                        token_id: 2.into(),
5753                        expr: Shared::new(Expr::Call(
5754                            IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
5755                            smallvec![
5756                                Shared::new(Node {
5757                                    token_id: 1.into(),
5758                                    expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
5759                                }),
5760                                Shared::new(Node {
5761                                    token_id: 3.into(),
5762                                    expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5763                                }),
5764                            ],
5765                        )),
5766                    })
5767                )),
5768            })
5769        ]))]
5770    #[case::minus_simple(
5771        vec![
5772            token(TokenKind::NumberLiteral(5.into())),
5773            token(TokenKind::Minus),
5774            token(TokenKind::NumberLiteral(3.into())),
5775            token(TokenKind::Eof)
5776        ],
5777        Ok(vec![
5778            Shared::new(Node {
5779                token_id: 1.into(),
5780                expr: Shared::new(Expr::Call(
5781                    IdentWithToken::new_with_token(constants::builtins::SUB, Some(Shared::new(token(TokenKind::Minus)))),
5782                    smallvec![
5783                        Shared::new(Node {
5784                            token_id: 0.into(),
5785                            expr: Shared::new(Expr::Literal(Literal::Number(5.into()))),
5786                        }),
5787                        Shared::new(Node {
5788                            token_id: 2.into(),
5789                            expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
5790                        }),
5791                    ],
5792                )),
5793            })
5794        ]))]
5795    #[case::minus_with_identifiers(
5796        vec![
5797            token(TokenKind::Ident(SmolStr::new("a"))),
5798            token(TokenKind::Minus),
5799            token(TokenKind::Ident(SmolStr::new("b"))),
5800            token(TokenKind::Eof)
5801        ],
5802        Ok(vec![
5803            Shared::new(Node {
5804                token_id: 1.into(),
5805                expr: Shared::new(Expr::Call(
5806                    IdentWithToken::new_with_token(constants::builtins::SUB, Some(Shared::new(token(TokenKind::Minus)))),
5807                    smallvec![
5808                        Shared::new(Node {
5809                            token_id: 0.into(),
5810                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
5811                        }),
5812                        Shared::new(Node {
5813                            token_id: 2.into(),
5814                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
5815                        }),
5816                    ],
5817                )),
5818            })
5819        ]))]
5820    #[case::slash_simple(
5821        vec![
5822            token(TokenKind::NumberLiteral(6.into())),
5823            token(TokenKind::Slash),
5824            token(TokenKind::NumberLiteral(2.into())),
5825            token(TokenKind::Eof)
5826        ],
5827        Ok(vec![
5828            Shared::new(Node {
5829                token_id: 1.into(),
5830                expr: Shared::new(Expr::Call(
5831                    IdentWithToken::new_with_token(constants::builtins::DIV, Some(Shared::new(token(TokenKind::Slash)))),
5832                    smallvec![
5833                        Shared::new(Node {
5834                            token_id: 0.into(),
5835                            expr: Shared::new(Expr::Literal(Literal::Number(6.into()))),
5836                        }),
5837                        Shared::new(Node {
5838                            token_id: 2.into(),
5839                            expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
5840                        }),
5841                    ],
5842                )),
5843            })
5844        ]))]
5845    #[case::percent_simple(
5846            vec![
5847                token(TokenKind::NumberLiteral(10.into())),
5848                token(TokenKind::Percent),
5849                token(TokenKind::NumberLiteral(3.into())),
5850                token(TokenKind::Eof)
5851            ],
5852            Ok(vec![
5853                Shared::new(Node {
5854                    token_id: 1.into(),
5855                    expr: Shared::new(Expr::Call(
5856                        IdentWithToken::new_with_token(constants::builtins::MOD, Some(Shared::new(token(TokenKind::Percent)))),
5857                        smallvec![
5858                            Shared::new(Node {
5859                                token_id: 0.into(),
5860                                expr: Shared::new(Expr::Literal(Literal::Number(10.into()))),
5861                            }),
5862                            Shared::new(Node {
5863                                token_id: 2.into(),
5864                                expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
5865                            }),
5866                        ],
5867                    )),
5868                })
5869            ]))]
5870    #[case::percent_with_identifiers(
5871            vec![
5872                token(TokenKind::Ident(SmolStr::new("a"))),
5873                token(TokenKind::Percent),
5874                token(TokenKind::Ident(SmolStr::new("b"))),
5875                token(TokenKind::Eof)
5876            ],
5877            Ok(vec![
5878                Shared::new(Node {
5879                    token_id: 1.into(),
5880                    expr: Shared::new(Expr::Call(
5881                        IdentWithToken::new_with_token(constants::builtins::MOD, Some(Shared::new(token(TokenKind::Percent)))),
5882                        smallvec![
5883                            Shared::new(Node {
5884                                token_id: 0.into(),
5885                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
5886                            }),
5887                            Shared::new(Node {
5888                                token_id: 2.into(),
5889                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
5890                            }),
5891                        ],
5892                    )),
5893                })
5894            ]))]
5895    #[case::percent_error_missing_rhs(
5896            vec![
5897                token(TokenKind::NumberLiteral(10.into())),
5898                token(TokenKind::Percent),
5899                token(TokenKind::Eof)
5900            ],
5901            Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Percent))))]
5902    #[case::mul_simple(
5903            vec![
5904                token(TokenKind::NumberLiteral(3.into())),
5905                token(TokenKind::Asterisk),
5906                token(TokenKind::NumberLiteral(4.into())),
5907                token(TokenKind::Eof)
5908            ],
5909            Ok(vec![
5910                Shared::new(Node {
5911                    token_id: 1.into(),
5912                    expr: Shared::new(Expr::Call(
5913                        IdentWithToken::new_with_token(constants::builtins::MUL, Some(Shared::new(token(TokenKind::Asterisk)))),
5914                        smallvec![
5915                            Shared::new(Node {
5916                                token_id: 0.into(),
5917                                expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
5918                            }),
5919                            Shared::new(Node {
5920                                token_id: 2.into(),
5921                                expr: Shared::new(Expr::Literal(Literal::Number(4.into()))),
5922                            }),
5923                        ],
5924                    )),
5925                })
5926            ]))]
5927    #[case::mul_with_identifiers(
5928            vec![
5929                token(TokenKind::Ident(SmolStr::new("a"))),
5930                token(TokenKind::Asterisk),
5931                token(TokenKind::Ident(SmolStr::new("b"))),
5932                token(TokenKind::Eof)
5933            ],
5934            Ok(vec![
5935                Shared::new(Node {
5936                    token_id: 1.into(),
5937                    expr: Shared::new(Expr::Call(
5938                        IdentWithToken::new_with_token(constants::builtins::MUL, Some(Shared::new(token(TokenKind::Asterisk)))),
5939                        smallvec![
5940                            Shared::new(Node {
5941                                token_id: 0.into(),
5942                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
5943                            }),
5944                            Shared::new(Node {
5945                                token_id: 2.into(),
5946                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
5947                            }),
5948                        ],
5949                    )),
5950                })
5951            ]))]
5952    #[case::mul_error_missing_rhs(
5953            vec![
5954                token(TokenKind::NumberLiteral(5.into())),
5955                token(TokenKind::Asterisk),
5956                token(TokenKind::Eof)
5957            ],
5958            Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Asterisk))))]
5959    #[case::convert_simple(
5960            vec![
5961                token(TokenKind::Ident(SmolStr::new("a"))),
5962                token(TokenKind::Convert),
5963                token(TokenKind::Ident(SmolStr::new("b"))),
5964                token(TokenKind::Eof)
5965            ],
5966            Ok(vec![
5967                Shared::new(Node {
5968                    token_id: 1.into(),
5969                    expr: Shared::new(Expr::Call(
5970                        IdentWithToken::new_with_token(constants::builtins::CONVERT, Some(Shared::new(token(TokenKind::Convert)))),
5971                        smallvec![
5972                            Shared::new(Node {
5973                                token_id: 0.into(),
5974                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
5975                            }),
5976                            Shared::new(Node {
5977                                token_id: 2.into(),
5978                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
5979                            }),
5980                        ],
5981                    )),
5982                })
5983            ]))]
5984    #[case::convert_error_missing_rhs(
5985            vec![
5986                token(TokenKind::Ident(SmolStr::new("a"))),
5987                token(TokenKind::Convert),
5988                token(TokenKind::Eof)
5989            ],
5990            Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Convert))))]
5991    #[case::multiple_binary_operators(
5992            vec![
5993                token(TokenKind::NumberLiteral(1.into())),
5994                token(TokenKind::Asterisk),
5995                token(TokenKind::NumberLiteral(2.into())),
5996                token(TokenKind::Asterisk),
5997                token(TokenKind::NumberLiteral(3.into())),
5998                token(TokenKind::Eof)
5999            ],
6000            Ok(vec![
6001                Shared::new(Node {
6002                    token_id: 3.into(),
6003                    expr: Shared::new(Expr::Call(
6004                        IdentWithToken::new_with_token(constants::builtins::MUL, Some(Shared::new(token(TokenKind::Asterisk)))),
6005                        smallvec![
6006                            Shared::new(Node {
6007                                token_id: 1.into(),
6008                                expr: Shared::new(Expr::Call(
6009                                    IdentWithToken::new_with_token(constants::builtins::MUL, Some(Shared::new(token(TokenKind::Asterisk)))),
6010                                    smallvec![
6011                                        Shared::new(Node {
6012                                            token_id: 0.into(),
6013                                            expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6014                                        }),
6015                                        Shared::new(Node {
6016                                            token_id: 2.into(),
6017                                            expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
6018                                        }),
6019                                    ],
6020                                )),
6021                            }),
6022                            Shared::new(Node {
6023                                token_id: 4.into(),
6024                                expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
6025                            }),
6026                        ],
6027                    )),
6028                })
6029            ]))]
6030    #[case::multiple_binary_operators_eq(
6031            vec![
6032                token(TokenKind::NumberLiteral(1.into())),
6033                token(TokenKind::Plus),
6034                token(TokenKind::NumberLiteral(2.into())),
6035                token(TokenKind::EqEq),
6036                token(TokenKind::NumberLiteral(3.into())),
6037                token(TokenKind::Eof)
6038            ],
6039            Ok(vec![
6040                Shared::new(Node {
6041                    token_id: 3.into(),
6042                    expr: Shared::new(Expr::Call(
6043                        IdentWithToken::new_with_token(constants::builtins::EQ, Some(Shared::new(token(TokenKind::EqEq)))),
6044                        smallvec![
6045                            Shared::new(Node {
6046                                token_id: 1.into(),
6047                                expr: Shared::new(Expr::Call(
6048                                    IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
6049                                    smallvec![
6050                                        Shared::new(Node {
6051                                            token_id: 0.into(),
6052                                            expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6053                                        }),
6054                                        Shared::new(Node {
6055                                            token_id: 2.into(),
6056                                            expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
6057                                        }),
6058                                    ],
6059                                )),
6060                            }),
6061                            Shared::new(Node {
6062                                token_id: 4.into(),
6063                                expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
6064                            }),
6065                        ],
6066                    )),
6067                })
6068            ]))]
6069    #[case::multiple_and_operators(
6070            vec![
6071                token(TokenKind::Ident(SmolStr::new("a"))),
6072                token(TokenKind::And),
6073                token(TokenKind::Ident(SmolStr::new("b"))),
6074                token(TokenKind::And),
6075                token(TokenKind::Ident(SmolStr::new("c"))),
6076                token(TokenKind::Eof)
6077            ],
6078            Ok(vec![
6079                Shared::new(Node {
6080                    token_id: 3.into(),
6081                    expr: Shared::new(Expr::And(vec![
6082                        Shared::new(Node {
6083                            token_id: 0.into(),
6084                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6085                        }),
6086                        Shared::new(Node {
6087                            token_id: 2.into(),
6088                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6089                        }),
6090                        Shared::new(Node {
6091                            token_id: 4.into(),
6092                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6093                        }),
6094                    ])),
6095                })
6096            ]))]
6097    #[case::multiple_or_operators(
6098            vec![
6099                token(TokenKind::Ident(SmolStr::new("x"))),
6100                token(TokenKind::Or),
6101                token(TokenKind::Ident(SmolStr::new("y"))),
6102                token(TokenKind::Or),
6103                token(TokenKind::Ident(SmolStr::new("z"))),
6104                token(TokenKind::Eof)
6105            ],
6106            Ok(vec![
6107                Shared::new(Node {
6108                    token_id: 3.into(),
6109                    expr: Shared::new(Expr::Or(vec![
6110                        Shared::new(Node {
6111                            token_id: 0.into(),
6112                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
6113                        }),
6114                        Shared::new(Node {
6115                            token_id: 2.into(),
6116                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
6117                        }),
6118                        Shared::new(Node {
6119                            token_id: 4.into(),
6120                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("z", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("z")))))))),
6121                        }),
6122                    ])),
6123                })
6124            ]))]
6125    #[case::and_or_mixed(
6126            vec![
6127                token(TokenKind::Ident(SmolStr::new("a"))),
6128                token(TokenKind::And),
6129                token(TokenKind::Ident(SmolStr::new("b"))),
6130                token(TokenKind::Or),
6131                token(TokenKind::Ident(SmolStr::new("c"))),
6132                token(TokenKind::Eof)
6133            ],
6134            Ok(vec![
6135                Shared::new(Node {
6136                    token_id: 3.into(),
6137                    expr: Shared::new(Expr::Or(vec![
6138                        Shared::new(Node {
6139                            token_id: 1.into(),
6140                            expr: Shared::new(Expr::And(vec![
6141                                Shared::new(Node {
6142                                    token_id: 0.into(),
6143                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6144                                }),
6145                                Shared::new(Node {
6146                                    token_id: 2.into(),
6147                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6148                                }),
6149                            ])),
6150                        }),
6151                        Shared::new(Node {
6152                            token_id: 4.into(),
6153                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6154                        }),
6155                    ])),
6156                })
6157            ]))]
6158    #[case::four_and_operators(
6159            vec![
6160                token(TokenKind::Ident(SmolStr::new("a"))),
6161                token(TokenKind::And),
6162                token(TokenKind::Ident(SmolStr::new("b"))),
6163                token(TokenKind::And),
6164                token(TokenKind::Ident(SmolStr::new("c"))),
6165                token(TokenKind::And),
6166                token(TokenKind::Ident(SmolStr::new("d"))),
6167                token(TokenKind::Eof)
6168            ],
6169            Ok(vec![
6170                Shared::new(Node {
6171                    token_id: 5.into(),
6172                    expr: Shared::new(Expr::And(vec![
6173                        Shared::new(Node {
6174                            token_id: 0.into(),
6175                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6176                        }),
6177                        Shared::new(Node {
6178                            token_id: 2.into(),
6179                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6180                        }),
6181                        Shared::new(Node {
6182                            token_id: 4.into(),
6183                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6184                        }),
6185                        Shared::new(Node {
6186                            token_id: 6.into(),
6187                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("d", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("d")))))))),
6188                        }),
6189                    ])),
6190                })
6191            ]))]
6192    #[case::four_or_operators(
6193            vec![
6194                token(TokenKind::Ident(SmolStr::new("a"))),
6195                token(TokenKind::Or),
6196                token(TokenKind::Ident(SmolStr::new("b"))),
6197                token(TokenKind::Or),
6198                token(TokenKind::Ident(SmolStr::new("c"))),
6199                token(TokenKind::Or),
6200                token(TokenKind::Ident(SmolStr::new("d"))),
6201                token(TokenKind::Eof)
6202            ],
6203            Ok(vec![
6204                Shared::new(Node {
6205                    token_id: 5.into(),
6206                    expr: Shared::new(Expr::Or(vec![
6207                        Shared::new(Node {
6208                            token_id: 0.into(),
6209                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6210                        }),
6211                        Shared::new(Node {
6212                            token_id: 2.into(),
6213                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6214                        }),
6215                        Shared::new(Node {
6216                            token_id: 4.into(),
6217                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6218                        }),
6219                        Shared::new(Node {
6220                            token_id: 6.into(),
6221                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("d", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("d")))))))),
6222                        }),
6223                    ])),
6224                })
6225            ]))]
6226    #[case::or_with_and_in_middle(
6227            vec![
6228                token(TokenKind::Ident(SmolStr::new("a"))),
6229                token(TokenKind::Or),
6230                token(TokenKind::Ident(SmolStr::new("b"))),
6231                token(TokenKind::And),
6232                token(TokenKind::Ident(SmolStr::new("c"))),
6233                token(TokenKind::Or),
6234                token(TokenKind::Ident(SmolStr::new("d"))),
6235                token(TokenKind::Eof)
6236            ],
6237            Ok(vec![
6238                Shared::new(Node {
6239                    token_id: 5.into(),
6240                    expr: Shared::new(Expr::Or(vec![
6241                        Shared::new(Node {
6242                            token_id: 0.into(),
6243                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6244                        }),
6245                        Shared::new(Node {
6246                            token_id: 3.into(),
6247                            expr: Shared::new(Expr::And(vec![
6248                                Shared::new(Node {
6249                                    token_id: 2.into(),
6250                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6251                                }),
6252                                Shared::new(Node {
6253                                    token_id: 4.into(),
6254                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6255                                }),
6256                            ])),
6257                        }),
6258                        Shared::new(Node {
6259                            token_id: 6.into(),
6260                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("d", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("d")))))))),
6261                        }),
6262                    ])),
6263                })
6264            ]))]
6265    #[case::and_or_and_mixed(
6266            // a && b || c && d  =>  Or([And([a, b]), And([c, d])])
6267            vec![
6268                token(TokenKind::Ident(SmolStr::new("a"))),
6269                token(TokenKind::And),
6270                token(TokenKind::Ident(SmolStr::new("b"))),
6271                token(TokenKind::Or),
6272                token(TokenKind::Ident(SmolStr::new("c"))),
6273                token(TokenKind::And),
6274                token(TokenKind::Ident(SmolStr::new("d"))),
6275                token(TokenKind::Eof)
6276            ],
6277            Ok(vec![
6278                Shared::new(Node {
6279                    token_id: 3.into(),
6280                    expr: Shared::new(Expr::Or(vec![
6281                        Shared::new(Node {
6282                            token_id: 1.into(),
6283                            expr: Shared::new(Expr::And(vec![
6284                                Shared::new(Node {
6285                                    token_id: 0.into(),
6286                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6287                                }),
6288                                Shared::new(Node {
6289                                    token_id: 2.into(),
6290                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6291                                }),
6292                            ])),
6293                        }),
6294                        Shared::new(Node {
6295                            token_id: 5.into(),
6296                            expr: Shared::new(Expr::And(vec![
6297                                Shared::new(Node {
6298                                    token_id: 4.into(),
6299                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6300                                }),
6301                                Shared::new(Node {
6302                                    token_id: 6.into(),
6303                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("d", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("d")))))))),
6304                                }),
6305                            ])),
6306                        }),
6307                    ])),
6308                })
6309            ]))]
6310    #[case::or_and_or_mixed(
6311            // a || b && c || d  =>  Or([a, And([b, c]), d])
6312            vec![
6313                token(TokenKind::Ident(SmolStr::new("a"))),
6314                token(TokenKind::Or),
6315                token(TokenKind::Ident(SmolStr::new("b"))),
6316                token(TokenKind::And),
6317                token(TokenKind::Ident(SmolStr::new("c"))),
6318                token(TokenKind::Or),
6319                token(TokenKind::Ident(SmolStr::new("d"))),
6320                token(TokenKind::Eof)
6321            ],
6322            Ok(vec![
6323                Shared::new(Node {
6324                    token_id: 5.into(),
6325                    expr: Shared::new(Expr::Or(vec![
6326                        Shared::new(Node {
6327                            token_id: 0.into(),
6328                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6329                        }),
6330                        Shared::new(Node {
6331                            token_id: 3.into(),
6332                            expr: Shared::new(Expr::And(vec![
6333                                Shared::new(Node {
6334                                    token_id: 2.into(),
6335                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6336                                }),
6337                                Shared::new(Node {
6338                                    token_id: 4.into(),
6339                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6340                                }),
6341                            ])),
6342                        }),
6343                        Shared::new(Node {
6344                            token_id: 6.into(),
6345                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("d", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("d")))))))),
6346                        }),
6347                    ])),
6348                })
6349            ]))]
6350    #[case::and_and_or_and_and_mixed(
6351            // a && b && c || d && e && f  =>  Or([And([a,b,c]), And([d,e,f])])
6352            vec![
6353                token(TokenKind::Ident(SmolStr::new("a"))),
6354                token(TokenKind::And),
6355                token(TokenKind::Ident(SmolStr::new("b"))),
6356                token(TokenKind::And),
6357                token(TokenKind::Ident(SmolStr::new("c"))),
6358                token(TokenKind::Or),
6359                token(TokenKind::Ident(SmolStr::new("d"))),
6360                token(TokenKind::And),
6361                token(TokenKind::Ident(SmolStr::new("e"))),
6362                token(TokenKind::And),
6363                token(TokenKind::Ident(SmolStr::new("f"))),
6364                token(TokenKind::Eof)
6365            ],
6366            Ok(vec![
6367                Shared::new(Node {
6368                    token_id: 5.into(),
6369                    expr: Shared::new(Expr::Or(vec![
6370                        Shared::new(Node {
6371                            token_id: 3.into(),
6372                            expr: Shared::new(Expr::And(vec![
6373                                Shared::new(Node {
6374                                    token_id: 0.into(),
6375                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
6376                                }),
6377                                Shared::new(Node {
6378                                    token_id: 2.into(),
6379                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
6380                                }),
6381                                Shared::new(Node {
6382                                    token_id: 4.into(),
6383                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("c", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("c")))))))),
6384                                }),
6385                            ])),
6386                        }),
6387                        Shared::new(Node {
6388                            token_id: 9.into(),
6389                            expr: Shared::new(Expr::And(vec![
6390                                Shared::new(Node {
6391                                    token_id: 6.into(),
6392                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("d", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("d")))))))),
6393                                }),
6394                                Shared::new(Node {
6395                                    token_id: 8.into(),
6396                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("e", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("e")))))))),
6397                                }),
6398                                Shared::new(Node {
6399                                    token_id: 10.into(),
6400                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("f", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("f")))))))),
6401                                }),
6402                            ])),
6403                        }),
6404                    ])),
6405                })
6406            ]))]
6407    #[case::range_simple(
6408                vec![
6409                    token(TokenKind::NumberLiteral(1.into())),
6410                    token(TokenKind::DoubleDot),
6411                    token(TokenKind::NumberLiteral(5.into())),
6412                    token(TokenKind::Eof)
6413                ],
6414                Ok(vec![
6415                    Shared::new(Node {
6416                        token_id: 1.into(),
6417                        expr: Shared::new(Expr::Call(
6418                            IdentWithToken::new_with_token(constants::builtins::RANGE, Some(Shared::new(token(TokenKind::DoubleDot)))),
6419                            smallvec![
6420                                Shared::new(Node {
6421                                    token_id: 0.into(),
6422                                    expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6423                                }),
6424                                Shared::new(Node {
6425                                    token_id: 2.into(),
6426                                    expr: Shared::new(Expr::Literal(Literal::Number(5.into()))),
6427                                }),
6428                            ],
6429                        )),
6430                    })
6431                ]))]
6432    #[case::range_with_identifiers(
6433                vec![
6434                    token(TokenKind::Ident(SmolStr::new("start"))),
6435                    token(TokenKind::DoubleDot),
6436                    token(TokenKind::Ident(SmolStr::new("end"))),
6437                    token(TokenKind::Eof)
6438                ],
6439                Ok(vec![
6440                    Shared::new(Node {
6441                        token_id: 1.into(),
6442                        expr: Shared::new(Expr::Call(
6443                            IdentWithToken::new_with_token(constants::builtins::RANGE, Some(Shared::new(token(TokenKind::DoubleDot)))),
6444                            smallvec![
6445                                Shared::new(Node {
6446                                    token_id: 0.into(),
6447                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("start", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("start")))))))),
6448                                }),
6449                                Shared::new(Node {
6450                                    token_id: 2.into(),
6451                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("end", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("end")))))))),
6452                                }),
6453                            ],
6454                        )),
6455                    })
6456                ]))]
6457    #[case::range_error_missing_rhs(
6458                vec![
6459                    token(TokenKind::NumberLiteral(1.into())),
6460                    token(TokenKind::DoubleDot),
6461                    token(TokenKind::Eof)
6462                ],
6463                Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::DoubleDot))))]
6464    #[case::args_missing_rparen(
6465                vec![
6466                    token(TokenKind::Ident(SmolStr::new("foo"))),
6467                    token(TokenKind::LParen),
6468                    token(TokenKind::StringLiteral("bar".to_owned())),
6469                    // Missing RParen
6470                    token(TokenKind::Eof)
6471                ],
6472                Err(SyntaxError::ExpectedClosingParen(
6473                    token(TokenKind::Eof),
6474                    Some(Box::new(token(TokenKind::LParen))),
6475                ))
6476            )]
6477    #[case::args_unexpected_token(
6478                vec![
6479                    token(TokenKind::Ident(SmolStr::new("foo"))),
6480                    token(TokenKind::LParen),
6481                    token(TokenKind::NumberLiteral(1.into())),
6482                    token(TokenKind::Colon), // Invalid token in args
6483                    token(TokenKind::RParen),
6484                    token(TokenKind::Eof)
6485                ],
6486                Err(SyntaxError::ExpectedClosingParen(
6487                    token(TokenKind::Colon),
6488                    Some(Box::new(token(TokenKind::LParen))),
6489                ))
6490            )]
6491    #[case::args_leading_comma(
6492                vec![
6493                    token(TokenKind::Ident(SmolStr::new("foo"))),
6494                    token(TokenKind::LParen),
6495                    token(TokenKind::Comma),
6496                    token(TokenKind::Ident(SmolStr::new("bar"))),
6497                    token(TokenKind::RParen),
6498                    token(TokenKind::Eof)
6499                ],
6500                Err(SyntaxError::UnexpectedToken(token(TokenKind::Comma)))
6501            )]
6502    #[case::args_double_comma(
6503                vec![
6504                    token(TokenKind::Ident(SmolStr::new("foo"))),
6505                    token(TokenKind::LParen),
6506                    token(TokenKind::Ident(SmolStr::new("bar"))),
6507                    token(TokenKind::Comma),
6508                    token(TokenKind::Comma),
6509                    token(TokenKind::Ident(SmolStr::new("baz"))),
6510                    token(TokenKind::RParen),
6511                    token(TokenKind::Eof)
6512                ],
6513                Err(SyntaxError::UnexpectedToken(token(TokenKind::Comma)))
6514            )]
6515    #[case::binary_operator_chaining(
6516                vec![
6517                    token(TokenKind::NumberLiteral(2.into())),
6518                    token(TokenKind::Gt),
6519                    token(TokenKind::NumberLiteral(1.into())),
6520                    token(TokenKind::Or),
6521                    token(TokenKind::NumberLiteral(2.into())),
6522                    token(TokenKind::Gt),
6523                    token(TokenKind::NumberLiteral(1.into())),
6524                    token(TokenKind::Eof)
6525                ],
6526                Ok(vec![
6527                    Shared::new(Node {
6528                        token_id: 3.into(),
6529                        expr: Shared::new(Expr::Or(vec![
6530                            Shared::new(Node {
6531                                token_id: 1.into(),
6532                                expr: Shared::new(Expr::Call(
6533                                    IdentWithToken::new_with_token(constants::builtins::GT, Some(Shared::new(token(TokenKind::Gt)))),
6534                                    smallvec![
6535                                        Shared::new(Node {
6536                                            token_id: 0.into(),
6537                                            expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
6538                                        }),
6539                                        Shared::new(Node {
6540                                            token_id: 2.into(),
6541                                            expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6542                                        }),
6543                                    ],
6544                                )),
6545                            }),
6546                            Shared::new(Node {
6547                                token_id: 5.into(),
6548                                expr: Shared::new(Expr::Call(
6549                                    IdentWithToken::new_with_token(constants::builtins::GT, Some(Shared::new(token(TokenKind::Gt)))),
6550                                    smallvec![
6551                                        Shared::new(Node {
6552                                            token_id: 4.into(),
6553                                            expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
6554                                        }),
6555                                        Shared::new(Node {
6556                                            token_id: 6.into(),
6557                                            expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6558                                        }),
6559                                    ],
6560                                )),
6561                            }),
6562                        ])),
6563                    })
6564                ]))]
6565    #[case::not_simple(
6566                vec![
6567                    token(TokenKind::Not),
6568                    token(TokenKind::BoolLiteral(false)),
6569                    token(TokenKind::Eof)
6570                ],
6571                Ok(vec![
6572                    Shared::new(Node {
6573                        token_id: 0.into(),
6574                        expr: Shared::new(Expr::Call(
6575                            IdentWithToken::new_with_token(constants::builtins::NOT, Some(Shared::new(token(TokenKind::Not)))),
6576                            smallvec![
6577                                Shared::new(Node {
6578                                    token_id: 1.into(),
6579                                    expr: Shared::new(Expr::Literal(Literal::Bool(false))),
6580                                }),
6581                            ],
6582                        )),
6583                    })
6584                ]))]
6585    #[case::not_with_expr(
6586                vec![
6587                    token(TokenKind::Not),
6588                    token(TokenKind::Ident(SmolStr::new("x"))),
6589                    token(TokenKind::Eof)
6590                ],
6591                Ok(vec![
6592                    Shared::new(Node {
6593                        token_id: 0.into(),
6594                        expr: Shared::new(Expr::Call(
6595                            IdentWithToken::new_with_token(constants::builtins::NOT, Some(Shared::new(token(TokenKind::Not)))),
6596                            smallvec![
6597                                Shared::new(Node {
6598                                    token_id: 1.into(),
6599                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
6600                                }),
6601                            ],
6602                        )),
6603                    })
6604                ]))]
6605    #[case::bracket_access_with_number(
6606                vec![
6607                    token(TokenKind::Ident(SmolStr::new("arr"))),
6608                    token(TokenKind::LBracket),
6609                    token(TokenKind::NumberLiteral(5.into())),
6610                    token(TokenKind::RBracket),
6611                    token(TokenKind::Eof)
6612                ],
6613                Ok(vec![
6614                    Shared::new(Node {
6615                        token_id: 2.into(),
6616                        expr: Shared::new(Expr::Call(
6617                            IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
6618                            smallvec![
6619                                Shared::new(Node {
6620                                    token_id: 0.into(),
6621                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
6622                                }),
6623                                Shared::new(Node {
6624                                    token_id: 1.into(),
6625                                    expr: Shared::new(Expr::Literal(Literal::Number(5.into()))),
6626                                }),
6627                            ],
6628                        )),
6629                    })
6630                ]))]
6631    #[case::bracket_access_with_string(
6632                vec![
6633                    token(TokenKind::Ident(SmolStr::new("dict"))),
6634                    token(TokenKind::LBracket),
6635                    token(TokenKind::StringLiteral("key".to_owned())),
6636                    token(TokenKind::RBracket),
6637                    token(TokenKind::Eof)
6638                ],
6639                Ok(vec![
6640                    Shared::new(Node {
6641                        token_id: 2.into(),
6642                        expr: Shared::new(Expr::Call(
6643                            IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("dict")))))),
6644                            smallvec![
6645                                Shared::new(Node {
6646                                    token_id: 0.into(),
6647                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token(constants::builtins::DICT, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("dict")))))))),
6648                                }),
6649                                Shared::new(Node {
6650                                    token_id: 1.into(),
6651                                    expr: Shared::new(Expr::Literal(Literal::String("key".to_owned()))),
6652                                }),
6653                            ],
6654                        )),
6655                    })
6656                ]))]
6657    #[case::bracket_access_error_missing_rbracket(
6658                vec![
6659                    token(TokenKind::Ident(SmolStr::new("arr"))),
6660                    token(TokenKind::LBracket),
6661                    token(TokenKind::NumberLiteral(5.into())),
6662                    token(TokenKind::Eof)
6663                ],
6664                Err(SyntaxError::ExpectedClosingBracket(
6665                    token(TokenKind::Eof),
6666                    Some(Box::new(token(TokenKind::LBracket))),
6667                )))]
6668    #[case::slice_access_with_numbers(
6669                vec![
6670                    token(TokenKind::Ident(SmolStr::new("arr"))),
6671                    token(TokenKind::LBracket),
6672                    token(TokenKind::NumberLiteral(1.into())),
6673                    token(TokenKind::Colon),
6674                    token(TokenKind::NumberLiteral(3.into())),
6675                    token(TokenKind::RBracket),
6676                    token(TokenKind::Eof)
6677                ],
6678                Ok(vec![
6679                    Shared::new(Node {
6680                        token_id: 5.into(),
6681                        expr: Shared::new(Expr::Call(
6682                            IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
6683                            smallvec![
6684                                Shared::new(Node {
6685                                    token_id: 0.into(),
6686                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
6687                                }),
6688                                Shared::new(Node {
6689                                    token_id: 1.into(),
6690                                    expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6691                                }),
6692                                Shared::new(Node {
6693                                    token_id: 2.into(),
6694                                    expr: Shared::new(Expr::Literal(Literal::Number(3.into()))),
6695                                }),
6696                            ],
6697                        )),
6698                    })
6699                ]))]
6700    #[case::slice_access_with_variables(
6701                vec![
6702                    token(TokenKind::Ident(SmolStr::new("items"))),
6703                    token(TokenKind::LBracket),
6704                    token(TokenKind::Ident(SmolStr::new("start"))),
6705                    token(TokenKind::Colon),
6706                    token(TokenKind::Ident(SmolStr::new("end"))),
6707                    token(TokenKind::RBracket),
6708                    token(TokenKind::Eof)
6709                ],
6710                Ok(vec![
6711                    Shared::new(Node {
6712                        token_id: 5.into(),
6713                        expr: Shared::new(Expr::Call(
6714                            IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("items")))))),
6715                            smallvec![
6716                                Shared::new(Node {
6717                                    token_id: 0.into(),
6718                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("items", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("items")))))))),
6719                                }),
6720                                Shared::new(Node {
6721                                    token_id: 1.into(),
6722                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("start", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("start")))))))),
6723                                }),
6724                                Shared::new(Node {
6725                                    token_id: 2.into(),
6726                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("end", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("end")))))))),
6727                                }),
6728                            ],
6729                        )),
6730                    })
6731                ]))]
6732    #[case::not_with_paren_expr(
6733                vec![
6734                    token(TokenKind::Not),
6735                    token(TokenKind::LParen),
6736                    token(TokenKind::BoolLiteral(false)),
6737                    token(TokenKind::RParen),
6738                    token(TokenKind::Eof)
6739                ],
6740                Ok(vec![
6741                    Shared::new(Node {
6742                        token_id: 0.into(),
6743                        expr: Shared::new(Expr::Call(
6744                            IdentWithToken::new_with_token(constants::builtins::NOT, Some(Shared::new(token(TokenKind::Not)))),
6745                            smallvec![
6746                                Shared::new(Node {
6747                                    token_id: 1.into(),
6748                                    expr: Shared::new(Expr::Paren(
6749                                        Shared::new(Node {
6750                                            token_id: 2.into(),
6751                                            expr: Shared::new(Expr::Literal(Literal::Bool(false))),
6752                                        })
6753                                    )),
6754                                }),
6755                            ],
6756                        )),
6757                    })
6758                ]))]
6759    #[case::not_error_missing_rhs(
6760                vec![
6761                    token(TokenKind::Not),
6762                    token(TokenKind::Eof)
6763                ],
6764                Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Not))))]
6765    #[case::break_(
6766                    vec![
6767                        token(TokenKind::Break),
6768                        token(TokenKind::Eof)
6769                    ],
6770                    Ok(vec![
6771                        Shared::new(Node {
6772                            token_id: 0.into(),
6773                            expr: Shared::new(Expr::Break(None)),
6774                        })
6775                    ]))]
6776    #[case::continue_(
6777                    vec![
6778                        token(TokenKind::Continue),
6779                        token(TokenKind::Eof)
6780                    ],
6781                    Ok(vec![
6782                        Shared::new(Node {
6783                            token_id: 0.into(),
6784                            expr: Shared::new(Expr::Continue),
6785                        })
6786                    ]))]
6787    #[case::self_bracket_access_with_number(
6788                vec![
6789                    token(TokenKind::Self_),
6790                    token(TokenKind::LBracket),
6791                    token(TokenKind::NumberLiteral(5.into())),
6792                    token(TokenKind::RBracket),
6793                    token(TokenKind::Eof)
6794                ],
6795                Ok(vec![
6796                    Shared::new(Node {
6797                        token_id: 2.into(),
6798                        expr: Shared::new(Expr::Call(
6799                            IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Self_)))),
6800                            smallvec![
6801                                Shared::new(Node {
6802                                    token_id: 0.into(),
6803                                    expr: Shared::new(Expr::Self_),
6804                                }),
6805                                Shared::new(Node {
6806                                    token_id: 1.into(),
6807                                    expr: Shared::new(Expr::Literal(Literal::Number(5.into()))),
6808                                }),
6809                            ],
6810                        )),
6811                    })
6812                ]))]
6813    #[case::self_bracket_access_with_string(
6814                vec![
6815                    token(TokenKind::Self_),
6816                    token(TokenKind::LBracket),
6817                    token(TokenKind::StringLiteral("key".to_owned())),
6818                    token(TokenKind::RBracket),
6819                    token(TokenKind::Eof)
6820                ],
6821                Ok(vec![
6822                    Shared::new(Node {
6823                        token_id: 2.into(),
6824                        expr: Shared::new(Expr::Call(
6825                            IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Self_)))),
6826                            smallvec![
6827                                Shared::new(Node {
6828                                    token_id: 0.into(),
6829                                    expr: Shared::new(Expr::Self_),
6830                                }),
6831                                Shared::new(Node {
6832                                    token_id: 1.into(),
6833                                    expr: Shared::new(Expr::Literal(Literal::String("key".to_owned()))),
6834                                }),
6835                            ],
6836                        )),
6837                    })
6838                ]))]
6839    // Test function call followed by index access (e.g., foo()[0])
6840    #[case::function_call_with_index_access(
6841        vec![
6842            token(TokenKind::Ident(SmolStr::new("foo"))),
6843            token(TokenKind::LParen),
6844            token(TokenKind::RParen),
6845            token(TokenKind::LBracket),
6846            token(TokenKind::NumberLiteral(0.into())),
6847            token(TokenKind::RBracket),
6848            token(TokenKind::Eof)
6849        ],
6850        Ok(vec![
6851            Shared::new(Node {
6852                token_id: 2.into(),
6853                expr: Shared::new(Expr::Call(
6854                    IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
6855                    smallvec![
6856                        Shared::new(Node {
6857                            token_id: 0.into(),
6858                            expr: Shared::new(Expr::Call(
6859                                IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
6860                                SmallVec::new(),
6861                            )),
6862                        }),
6863                        Shared::new(Node {
6864                            token_id: 1.into(),
6865                            expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
6866                        }),
6867                    ],
6868                )),
6869            })
6870        ]))]
6871    // Test function call with arguments followed by index access
6872    #[case::function_call_with_args_and_index_access(
6873        vec![
6874            token(TokenKind::Ident(SmolStr::new("bar"))),
6875            token(TokenKind::LParen),
6876            token(TokenKind::StringLiteral("arg".to_owned())),
6877            token(TokenKind::RParen),
6878            token(TokenKind::LBracket),
6879            token(TokenKind::StringLiteral("key".to_owned())),
6880            token(TokenKind::RBracket),
6881            token(TokenKind::Eof)
6882        ],
6883        Ok(vec![
6884            Shared::new(Node {
6885                token_id: 1.into(),
6886                expr: Shared::new(Expr::Call(
6887                    IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("bar")))))),
6888                    smallvec![
6889                        Shared::new(Node {
6890                            token_id: 1.into(),
6891                            expr: Shared::new(Expr::Call(
6892                                IdentWithToken::new_with_token("bar", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("bar")))))),
6893                                smallvec![
6894                                    Shared::new(Node {
6895                                        token_id: 0.into(),
6896                                        expr: Shared::new(Expr::Literal(Literal::String("arg".to_owned()))),
6897                                    })
6898                                ],
6899                            )),
6900                        }),
6901                        Shared::new(Node {
6902                            token_id: 2.into(),
6903                            expr: Shared::new(Expr::Literal(Literal::String("key".to_owned()))),
6904                        }),
6905                    ],
6906                )),
6907            })
6908        ]))]
6909    // Test chained index access on function call result
6910    #[case::function_call_with_chained_index_access(
6911        vec![
6912            token(TokenKind::Ident(SmolStr::new("baz"))),
6913            token(TokenKind::LParen),
6914            token(TokenKind::RParen),
6915            token(TokenKind::LBracket),
6916            token(TokenKind::NumberLiteral(0.into())),
6917            token(TokenKind::RBracket),
6918            token(TokenKind::LBracket),
6919            token(TokenKind::NumberLiteral(1.into())),
6920            token(TokenKind::RBracket),
6921            token(TokenKind::Eof)
6922        ],
6923        Ok(vec![
6924            Shared::new(Node {
6925                token_id: 2.into(),
6926                expr: Shared::new(Expr::Call(
6927                    IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("baz")))))),
6928                    smallvec![
6929                        Shared::new(Node {
6930                            token_id: 2.into(),
6931                            expr: Shared::new(Expr::Call(
6932                                IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("baz")))))),
6933                                smallvec![
6934                                    Shared::new(Node {
6935                                        token_id: 0.into(),
6936                                        expr: Shared::new(Expr::Call(
6937                                            IdentWithToken::new_with_token("baz", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("baz")))))),
6938                                            SmallVec::new(),
6939                                        )),
6940                                    }),
6941                                    Shared::new(Node {
6942                                        token_id: 1.into(),
6943                                        expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
6944                                    }),
6945                                ],
6946                            )),
6947                        }),
6948                        Shared::new(Node {
6949                            token_id: 3.into(),
6950                            expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
6951                        }),
6952                    ],
6953                )),
6954            })
6955        ]))]
6956    #[case::try_without_catch(
6957            vec![
6958                token(TokenKind::Try),
6959                token(TokenKind::Colon),
6960                token(TokenKind::Ident(SmolStr::new("error_expr"))),
6961                token(TokenKind::Eof),
6962            ],
6963            Ok(vec![Shared::new(Node {
6964                token_id: 2.into(),
6965                expr: Shared::new(Expr::Try(
6966                    Shared::new(Node {
6967                        token_id: 2.into(),
6968                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("error_expr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("error_expr")))))))),
6969                    }),
6970                    Shared::new(Node {
6971                        token_id: 0.into(),
6972                        expr: Shared::new(Expr::Literal(Literal::None)),
6973                    }),
6974                )),
6975            })])
6976        )]
6977    // Test index access followed by function call (e.g., arr[0]())
6978    #[case::index_access_with_function_call(
6979        vec![
6980            token(TokenKind::Ident(SmolStr::new("arr"))),
6981            token(TokenKind::LBracket),
6982            token(TokenKind::NumberLiteral(0.into())),
6983            token(TokenKind::RBracket),
6984            token(TokenKind::LParen),
6985            token(TokenKind::RParen),
6986            token(TokenKind::Eof)
6987        ],
6988        Ok(vec![
6989            Shared::new(Node {
6990                token_id: 2.into(),
6991                expr: Shared::new(Expr::CallDynamic(
6992                    Shared::new(Node {
6993                        token_id: 2.into(),
6994                        expr: Shared::new(Expr::Call(
6995                            IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
6996                            smallvec![
6997                                Shared::new(Node {
6998                                    token_id: 0.into(),
6999                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
7000                                }),
7001                                Shared::new(Node {
7002                                    token_id: 1.into(),
7003                                    expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7004                                }),
7005                            ],
7006                        )),
7007                    }),
7008                    SmallVec::new(),
7009                )),
7010            })
7011        ]))]
7012    // Test index access with args followed by function call (e.g., arr[0](arg))
7013    #[case::index_access_with_function_call_and_args(
7014        vec![
7015            token(TokenKind::Ident(SmolStr::new("arr"))),
7016            token(TokenKind::LBracket),
7017            token(TokenKind::NumberLiteral(0.into())),
7018            token(TokenKind::RBracket),
7019            token(TokenKind::LParen),
7020            token(TokenKind::StringLiteral("test".to_owned())),
7021            token(TokenKind::RParen),
7022            token(TokenKind::Eof)
7023        ],
7024        Ok(vec![
7025            Shared::new(Node {
7026                token_id: 2.into(),
7027                expr: Shared::new(Expr::CallDynamic(
7028                    Shared::new(Node {
7029                        token_id: 2.into(),
7030                        expr: Shared::new(Expr::Call(
7031                            IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
7032                            smallvec![
7033                                Shared::new(Node {
7034                                    token_id: 0.into(),
7035                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
7036                                }),
7037                                Shared::new(Node {
7038                                    token_id: 1.into(),
7039                                    expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7040                                }),
7041                            ],
7042                        )),
7043                    }),
7044                    smallvec![
7045                        Shared::new(Node {
7046                            token_id: 3.into(),
7047                            expr: Shared::new(Expr::Literal(Literal::String("test".to_owned()))),
7048                        })
7049                    ],
7050                )),
7051            })
7052        ]))]
7053    // Test group expr with index access: (x)[0] → get(Paren(x), 0)
7054    #[case::group_expr_with_index_access(
7055        vec![
7056            token(TokenKind::LParen),
7057            token(TokenKind::Ident(SmolStr::new("x"))),
7058            token(TokenKind::RParen),
7059            token(TokenKind::LBracket),
7060            token(TokenKind::NumberLiteral(0.into())),
7061            token(TokenKind::RBracket),
7062            token(TokenKind::Eof),
7063        ],
7064        Ok(vec![
7065            Shared::new(Node {
7066                token_id: 0.into(),
7067                expr: Shared::new(Expr::Call(
7068                    IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::LParen)))),
7069                    smallvec![
7070                        Shared::new(Node {
7071                            token_id: 0.into(),
7072                            expr: Shared::new(Expr::Paren(
7073                                Shared::new(Node {
7074                                    token_id: 1.into(),
7075                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
7076                                }),
7077                            )),
7078                        }),
7079                        Shared::new(Node {
7080                            token_id: 2.into(),
7081                            expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7082                        }),
7083                    ],
7084                )),
7085            })
7086        ]))]
7087    // Test group expr with dynamic call: (x)("test") → CallDynamic(Paren(x), ["test"])
7088    #[case::group_expr_with_dynamic_call(
7089        vec![
7090            token(TokenKind::LParen),
7091            token(TokenKind::Ident(SmolStr::new("x"))),
7092            token(TokenKind::RParen),
7093            token(TokenKind::LParen),
7094            token(TokenKind::StringLiteral("test".to_owned())),
7095            token(TokenKind::RParen),
7096            token(TokenKind::Eof),
7097        ],
7098        Ok(vec![
7099            Shared::new(Node {
7100                token_id: 0.into(),
7101                expr: Shared::new(Expr::CallDynamic(
7102                    Shared::new(Node {
7103                        token_id: 0.into(),
7104                        expr: Shared::new(Expr::Paren(
7105                            Shared::new(Node {
7106                                token_id: 1.into(),
7107                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
7108                            }),
7109                        )),
7110                    }),
7111                    smallvec![
7112                        Shared::new(Node {
7113                            token_id: 2.into(),
7114                            expr: Shared::new(Expr::Literal(Literal::String("test".to_owned()))),
7115                        }),
7116                    ],
7117                )),
7118            })
7119        ]))]
7120    // Test group expr with chained call then index: (f)("a")[0] → get(CallDynamic(Paren(f), ["a"]), 0)
7121    #[case::group_expr_with_chained_call_and_index(
7122        vec![
7123            token(TokenKind::LParen),
7124            token(TokenKind::Ident(SmolStr::new("f"))),
7125            token(TokenKind::RParen),
7126            token(TokenKind::LParen),
7127            token(TokenKind::StringLiteral("a".to_owned())),
7128            token(TokenKind::RParen),
7129            token(TokenKind::LBracket),
7130            token(TokenKind::NumberLiteral(0.into())),
7131            token(TokenKind::RBracket),
7132            token(TokenKind::Eof),
7133        ],
7134        Ok(vec![
7135            Shared::new(Node {
7136                token_id: 0.into(),
7137                expr: Shared::new(Expr::Call(
7138                    IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::LParen)))),
7139                    smallvec![
7140                        Shared::new(Node {
7141                            token_id: 3.into(),
7142                            expr: Shared::new(Expr::CallDynamic(
7143                                Shared::new(Node {
7144                                    token_id: 0.into(),
7145                                    expr: Shared::new(Expr::Paren(
7146                                        Shared::new(Node {
7147                                            token_id: 1.into(),
7148                                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("f", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("f")))))))),
7149                                        }),
7150                                    )),
7151                                }),
7152                                smallvec![
7153                                    Shared::new(Node {
7154                                        token_id: 2.into(),
7155                                        expr: Shared::new(Expr::Literal(Literal::String("a".to_owned()))),
7156                                    }),
7157                                ],
7158                            )),
7159                        }),
7160                        Shared::new(Node {
7161                            token_id: 4.into(),
7162                            expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7163                        }),
7164                    ],
7165                )),
7166            })
7167        ]))]
7168    // Test array literal with index access: [1,2][0] → get(array([1,2]), 0)
7169    #[case::array_literal_with_index_access(
7170        vec![
7171            token(TokenKind::LBracket),
7172            token(TokenKind::NumberLiteral(1.into())),
7173            token(TokenKind::Comma),
7174            token(TokenKind::NumberLiteral(2.into())),
7175            token(TokenKind::RBracket),
7176            token(TokenKind::LBracket),
7177            token(TokenKind::NumberLiteral(0.into())),
7178            token(TokenKind::RBracket),
7179            token(TokenKind::Eof),
7180        ],
7181        Ok(vec![
7182            Shared::new(Node {
7183                token_id: 0.into(),
7184                expr: Shared::new(Expr::Call(
7185                    IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::LBracket)))),
7186                    smallvec![
7187                        Shared::new(Node {
7188                            token_id: 0.into(),
7189                            expr: Shared::new(Expr::Call(
7190                                IdentWithToken::new_with_token(constants::builtins::ARRAY, Some(Shared::new(token(TokenKind::LBracket)))),
7191                                smallvec![
7192                                    Shared::new(Node {
7193                                        token_id: 1.into(),
7194                                        expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
7195                                    }),
7196                                    Shared::new(Node {
7197                                        token_id: 2.into(),
7198                                        expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
7199                                    }),
7200                                ],
7201                            )),
7202                        }),
7203                        Shared::new(Node {
7204                            token_id: 3.into(),
7205                            expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7206                        }),
7207                    ],
7208                )),
7209            })
7210        ]))]
7211    // Test chained index access followed by function call (e.g., arr[0][1]())
7212    #[case::chained_index_access_with_function_call(
7213        vec![
7214            token(TokenKind::Ident(SmolStr::new("arr"))),
7215            token(TokenKind::LBracket),
7216            token(TokenKind::NumberLiteral(0.into())),
7217            token(TokenKind::RBracket),
7218            token(TokenKind::LBracket),
7219            token(TokenKind::NumberLiteral(1.into())),
7220            token(TokenKind::RBracket),
7221            token(TokenKind::LParen),
7222            token(TokenKind::RParen),
7223            token(TokenKind::Eof)
7224        ],
7225        Ok(vec![
7226            Shared::new(Node {
7227                token_id: 4.into(),
7228                expr: Shared::new(Expr::CallDynamic(
7229                    Shared::new(Node {
7230                        token_id: 4.into(),
7231                        expr: Shared::new(Expr::Call(
7232                            IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
7233                            smallvec![
7234                                Shared::new(Node {
7235                                    token_id: 2.into(),
7236                                    expr: Shared::new(Expr::Call(
7237                                        IdentWithToken::new_with_token(constants::builtins::GET, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
7238                                        smallvec![
7239                                            Shared::new(Node {
7240                                                token_id: 0.into(),
7241                                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
7242                                            }),
7243                                            Shared::new(Node {
7244                                                token_id: 1.into(),
7245                                                expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7246                                            }),
7247                                        ],
7248                                    )),
7249                                }),
7250                                Shared::new(Node {
7251                                    token_id: 3.into(),
7252                                    expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
7253                                }),
7254                            ],
7255                        )),
7256                    }),
7257                    SmallVec::new(),
7258                )),
7259            })
7260        ]))]
7261    #[case::function_call_with_question_mark(
7262            vec![
7263                token(TokenKind::Ident(SmolStr::new("foo"))),
7264                token(TokenKind::LParen),
7265                token(TokenKind::StringLiteral("arg".to_owned())),
7266                token(TokenKind::RParen),
7267                token(TokenKind::Question),
7268                token(TokenKind::Eof),
7269            ],
7270            Ok(vec![Shared::new(Node {
7271                token_id: 1.into(),
7272                expr: Shared::new(Expr::Try(
7273                    Shared::new(Node {
7274                        token_id: 1.into(),
7275                        expr: Shared::new(Expr::Call(
7276                            IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
7277                            smallvec![
7278                                Shared::new(Node {
7279                                    token_id: 0.into(),
7280                                    expr: Shared::new(Expr::Literal(Literal::String("arg".to_owned()))),
7281                                }),
7282                            ],
7283                        )),
7284                    }),
7285                    Shared::new(Node {
7286                        token_id: 1.into(),
7287                        expr: Shared::new(Expr::Literal(Literal::None)),
7288                    }),
7289                )),
7290            })])
7291        )]
7292    #[case::question_mark_after_call(
7293                vec![
7294                    token(TokenKind::Ident(SmolStr::new("foo"))),
7295                    token(TokenKind::LParen),
7296                    token(TokenKind::RParen),
7297                    token(TokenKind::Question),
7298                    token(TokenKind::Eof),
7299                ],
7300                Ok(vec![
7301                    Shared::new(Node {
7302                        token_id: 1.into(),
7303                        expr: Shared::new(Expr::Try(
7304                            Shared::new(Node {
7305                                token_id: 0.into(),
7306                                expr: Shared::new(Expr::Call(
7307                                    IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
7308                                    SmallVec::new(),
7309                                )),
7310                            }),
7311                            Shared::new(Node {
7312                                token_id: 0.into(),
7313                                expr: Shared::new(Expr::Literal(Literal::None)),
7314                            }),
7315                        )),
7316                    })
7317                ]))]
7318    #[case::question_mark_after_call_with_args(
7319                vec![
7320                    token(TokenKind::Ident(SmolStr::new("bar"))),
7321                    token(TokenKind::LParen),
7322                    token(TokenKind::StringLiteral("arg".to_owned())),
7323                    token(TokenKind::RParen),
7324                    token(TokenKind::Question),
7325                    token(TokenKind::Eof),
7326                ],
7327                Ok(vec![
7328                    Shared::new(Node {
7329                        token_id: 1.into(),
7330                        expr: Shared::new(Expr::Try(
7331                            Shared::new(Node {
7332                                token_id: 1.into(),
7333                                expr: Shared::new(Expr::Call(
7334                                    IdentWithToken::new_with_token("bar", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("bar")))))),
7335                                    smallvec![
7336                                        Shared::new(Node {
7337                                            token_id: 0.into(),
7338                                            expr: Shared::new(Expr::Literal(Literal::String("arg".to_owned()))),
7339                                        }),
7340                                    ],
7341                                )),
7342                            }),
7343                            Shared::new(Node {
7344                                token_id: 1.into(),
7345                                expr: Shared::new(Expr::Literal(Literal::None)),
7346                            }),
7347                        )),
7348                    })
7349                ]))]
7350    #[case::question_mark_after_call_error(
7351                vec![
7352                    token(TokenKind::Ident(SmolStr::new("foo"))),
7353                    token(TokenKind::Question),
7354                    token(TokenKind::Eof),
7355                ],
7356                Err(SyntaxError::UnexpectedToken(token(TokenKind::Ident("foo".into())))))]
7357    #[case::coalesce_simple(
7358                    vec![
7359                        token(TokenKind::StringLiteral("foo".to_owned())),
7360                        token(TokenKind::Coalesce),
7361                        token(TokenKind::StringLiteral("bar".to_owned())),
7362                        token(TokenKind::Eof)
7363                    ],
7364                    Ok(vec![
7365                        Shared::new(Node {
7366                            token_id: 1.into(),
7367                            expr: Shared::new(Expr::Call(
7368                                IdentWithToken::new_with_token(constants::builtins::COALESCE, Some(Shared::new(token(TokenKind::Coalesce)))),
7369                                smallvec![
7370                                    Shared::new(Node {
7371                                        token_id: 0.into(),
7372                                        expr: Shared::new(Expr::Literal(Literal::String("foo".to_owned()))),
7373                                    }),
7374                                    Shared::new(Node {
7375                                        token_id: 2.into(),
7376                                        expr: Shared::new(Expr::Literal(Literal::String("bar".to_owned()))),
7377                                    }),
7378                                ],
7379                            )),
7380                        })
7381                    ]))]
7382    #[case::coalesce_with_none(
7383                    vec![
7384                        token(TokenKind::None),
7385                        token(TokenKind::Coalesce),
7386                        token(TokenKind::StringLiteral("default".to_owned())),
7387                        token(TokenKind::Eof)
7388                    ],
7389                    Ok(vec![
7390                        Shared::new(Node {
7391                            token_id: 1.into(),
7392                            expr: Shared::new(Expr::Call(
7393                                IdentWithToken::new_with_token(constants::builtins::COALESCE, Some(Shared::new(token(TokenKind::Coalesce)))),
7394                                smallvec![
7395                                    Shared::new(Node {
7396                                        token_id: 0.into(),
7397                                        expr: Shared::new(Expr::Literal(Literal::None)),
7398                                    }),
7399                                    Shared::new(Node {
7400                                        token_id: 2.into(),
7401                                        expr: Shared::new(Expr::Literal(Literal::String("default".to_owned()))),
7402                                    }),
7403                                ],
7404                            )),
7405                        })
7406                    ]))]
7407    #[case::coalesce_with_identifiers(
7408                    vec![
7409                        token(TokenKind::Ident(SmolStr::new("x"))),
7410                        token(TokenKind::Coalesce),
7411                        token(TokenKind::Ident(SmolStr::new("y"))),
7412                        token(TokenKind::Eof)
7413                    ],
7414                    Ok(vec![
7415                        Shared::new(Node {
7416                            token_id: 1.into(),
7417                            expr: Shared::new(Expr::Call(
7418                                IdentWithToken::new_with_token(constants::builtins::COALESCE, Some(Shared::new(token(TokenKind::Coalesce)))),
7419                                smallvec![
7420                                    Shared::new(Node {
7421                                        token_id: 0.into(),
7422                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
7423                                    }),
7424                                    Shared::new(Node {
7425                                        token_id: 2.into(),
7426                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
7427                                    }),
7428                                ],
7429                            )),
7430                        })
7431                    ]))]
7432    #[case::coalesce_error_missing_rhs(
7433                    vec![
7434                        token(TokenKind::StringLiteral("foo".to_owned())),
7435                        token(TokenKind::Coalesce),
7436                        token(TokenKind::Eof)
7437                    ],
7438                    Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Coalesce))))]
7439    #[case::negate_simple(
7440        vec![
7441            token(TokenKind::Minus),
7442            token(TokenKind::NumberLiteral(42.into())),
7443            token(TokenKind::Eof)
7444        ],
7445        Ok(vec![
7446            Shared::new(Node {
7447                token_id: 0.into(),
7448                expr: Shared::new(Expr::Call(
7449                    IdentWithToken::new_with_token(constants::builtins::NEGATE, Some(Shared::new(token(TokenKind::Minus)))),
7450                    smallvec![
7451                        Shared::new(Node {
7452                            token_id: 1.into(),
7453                            expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
7454                        }),
7455                    ],
7456                )),
7457            })
7458        ]))]
7459    #[case::negate_with_identifier(
7460        vec![
7461            token(TokenKind::Minus),
7462            token(TokenKind::Ident(SmolStr::new("x"))),
7463            token(TokenKind::Eof)
7464        ],
7465        Ok(vec![
7466            Shared::new(Node {
7467                token_id: 0.into(),
7468                expr: Shared::new(Expr::Call(
7469                    IdentWithToken::new_with_token(constants::builtins::NEGATE, Some(Shared::new(token(TokenKind::Minus)))),
7470                    smallvec![
7471                        Shared::new(Node {
7472                            token_id: 1.into(),
7473                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
7474                        }),
7475                    ],
7476                )),
7477            })
7478        ]))]
7479    #[case::negate_error_missing_rhs(
7480        vec![
7481            token(TokenKind::Minus),
7482            token(TokenKind::Eof)
7483        ],
7484        Err(SyntaxError::UnexpectedEOFAfterToken(token(TokenKind::Minus))))]
7485    #[case::import_simple(
7486            vec![
7487            token(TokenKind::Import),
7488            token(TokenKind::StringLiteral("name".to_owned())),
7489            token(TokenKind::Eof),
7490            ],
7491            Ok(vec![
7492            Shared::new(Node {
7493                token_id: 0.into(),
7494                expr: Shared::new(Expr::Import(
7495                    Literal::String("name".to_owned()),
7496                )),
7497            })
7498            ]))]
7499    #[case::import_as(
7500            vec![
7501            token(TokenKind::Import),
7502            token(TokenKind::StringLiteral("name".to_owned())),
7503            token(TokenKind::Eof),
7504            ],
7505            Ok(vec![
7506            Shared::new(Node {
7507                token_id: 0.into(),
7508                expr: Shared::new(Expr::Import(
7509                    Literal::String("name".to_owned()),
7510                )),
7511            })
7512            ]))]
7513    #[case::qualified_access(
7514            vec![
7515            token(TokenKind::Ident(SmolStr::new("test"))),
7516            token(TokenKind::DoubleColon),
7517            token(TokenKind::Ident(SmolStr::new("foo"))),
7518            token(TokenKind::Eof),
7519            ],
7520            Ok(vec![
7521                Shared::new(Node {
7522                    token_id: 1.into(),
7523                    expr: Shared::new(Expr::QualifiedAccess(
7524                        vec![IdentWithToken::new_with_token("test", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("test"))))))],
7525                        AccessTarget::Ident(IdentWithToken::new_with_token("foo", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("foo")))))),
7526                    ))),
7527                })
7528            ]))]
7529    #[case::qualified_access_with_call(
7530        vec![
7531            token(TokenKind::Ident(SmolStr::new("mod"))),
7532            token(TokenKind::DoubleColon),
7533            token(TokenKind::Ident(SmolStr::new("func"))),
7534            token(TokenKind::LParen),
7535            token(TokenKind::StringLiteral("arg".to_owned())),
7536            token(TokenKind::RParen),
7537            token(TokenKind::Eof),
7538        ],
7539        Ok(vec![
7540            Shared::new(Node {
7541                token_id: 4.into(),
7542                expr: Shared::new(Expr::QualifiedAccess(
7543                    vec![IdentWithToken::new_with_token("mod", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod"))))))],
7544                    AccessTarget::Call(
7545                        IdentWithToken::new_with_token("func", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("func")))))),
7546                        smallvec![
7547                            Shared::new(Node {
7548                                token_id: 0.into(),
7549                                expr: Shared::new(Expr::Literal(Literal::String("arg".to_owned()))),
7550                            }),
7551                        ],
7552                    ),
7553                )),
7554            })
7555        ]))]
7556    #[case::qualified_access_multi_level(
7557        vec![
7558            token(TokenKind::Ident(SmolStr::new("mod1"))),
7559            token(TokenKind::DoubleColon),
7560            token(TokenKind::Ident(SmolStr::new("mod2"))),
7561            token(TokenKind::DoubleColon),
7562            token(TokenKind::Ident(SmolStr::new("func"))),
7563            token(TokenKind::LParen),
7564            token(TokenKind::RParen),
7565            token(TokenKind::Eof),
7566        ],
7567        Ok(vec![
7568            Shared::new(Node {
7569                token_id: 4.into(),
7570                expr: Shared::new(Expr::QualifiedAccess(
7571                    vec![
7572                        IdentWithToken::new_with_token("mod1", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod1")))))),
7573                        IdentWithToken::new_with_token("mod2", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod2")))))),
7574                    ],
7575                    AccessTarget::Call(
7576                        IdentWithToken::new_with_token("func", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("func")))))),
7577                        smallvec![],
7578                    ),
7579                )),
7580            })
7581        ]))]
7582    #[case::slice_access_with_start_only(
7583            vec![
7584                token(TokenKind::Ident(SmolStr::new("arr"))),
7585                token(TokenKind::LBracket),
7586                token(TokenKind::NumberLiteral(1.into())),
7587                token(TokenKind::Colon),
7588                token(TokenKind::RBracket),
7589                token(TokenKind::Eof)
7590            ],
7591            Ok(vec![
7592                Shared::new(Node {
7593                    token_id: 4.into(),
7594                    expr: Shared::new(Expr::Call(
7595                        IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
7596                        smallvec![
7597                            Shared::new(Node {
7598                                token_id: 0.into(),
7599                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
7600                            }),
7601                            Shared::new(Node {
7602                                token_id: 1.into(),
7603                                expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
7604                            }),
7605                            Shared::new(Node {
7606                                token_id: 3.into(),
7607                                expr: Shared::new(Expr::Call(
7608                                    IdentWithToken::new_with_token("len", None),
7609                                    smallvec![
7610                                        Shared::new(Node {
7611                                            token_id: 0.into(),
7612                                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
7613                                        }),
7614                                    ],
7615                                )),
7616                            }),
7617                        ],
7618                    )),
7619                })
7620            ]))]
7621    #[case::slice_access_with_end_only(
7622        vec![
7623            token(TokenKind::Ident(SmolStr::new("arr"))),
7624            token(TokenKind::LBracket),
7625            token(TokenKind::Colon),
7626            token(TokenKind::NumberLiteral(2.into())),
7627            token(TokenKind::RBracket),
7628            token(TokenKind::Eof),
7629        ],
7630        Ok(vec![
7631            Shared::new(Node {
7632                token_id: 3.into(),
7633                expr: Shared::new(Expr::Call(
7634                    IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))),
7635                    smallvec![
7636                        Shared::new(Node {
7637                            token_id: 0.into(),
7638                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("arr")))))))),
7639                        }),
7640                        Shared::new(Node {
7641                            token_id: 1.into(),
7642                            expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7643                        }),
7644                        Shared::new(Node {
7645                            token_id: 2.into(),
7646                            expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
7647                        }),
7648                    ],
7649                )),
7650            })
7651        ]))]
7652    #[case::qualified_access_with_call_and_slice(
7653        vec![
7654            token(TokenKind::Ident(SmolStr::new("mod"))),
7655            token(TokenKind::DoubleColon),
7656            token(TokenKind::Ident(SmolStr::new("func"))),
7657            token(TokenKind::LParen),
7658            token(TokenKind::RParen),
7659            token(TokenKind::LBracket),
7660            token(TokenKind::NumberLiteral(0.into())),
7661            token(TokenKind::Colon),
7662            token(TokenKind::NumberLiteral(2.into())),
7663            token(TokenKind::RBracket),
7664            token(TokenKind::Eof),
7665        ],
7666        Ok(vec![
7667            Shared::new(Node {
7668                token_id: 3.into(),
7669                expr: Shared::new(Expr::Call(
7670                    IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod")))))),
7671                    smallvec![
7672                        Shared::new(Node {
7673                            token_id: 0.into(),
7674                            expr: Shared::new(Expr::QualifiedAccess(
7675                                vec![IdentWithToken::new_with_token("mod", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod"))))))],
7676                                AccessTarget::Call(
7677                                    IdentWithToken::new_with_token("func", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("func")))))),
7678                                    smallvec![],
7679                                ),
7680                            )),
7681                        }),
7682                        Shared::new(Node {
7683                            token_id: 1.into(),
7684                            expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7685                        }),
7686                        Shared::new(Node {
7687                            token_id: 2.into(),
7688                            expr: Shared::new(Expr::Literal(Literal::Number(2.into()))),
7689                        }),
7690                    ],
7691                )),
7692            })
7693        ]))]
7694    #[case::qualified_access_with_call_and_end_only_slice(
7695        vec![
7696            token(TokenKind::Ident(SmolStr::new("mod"))),
7697            token(TokenKind::DoubleColon),
7698            token(TokenKind::Ident(SmolStr::new("func"))),
7699            token(TokenKind::LParen),
7700            token(TokenKind::RParen),
7701            token(TokenKind::LBracket),
7702            token(TokenKind::Colon),
7703            token(TokenKind::NumberLiteral(1.into())),
7704            token(TokenKind::RBracket),
7705            token(TokenKind::Eof),
7706        ],
7707        Ok(vec![
7708            Shared::new(Node {
7709                token_id: 3.into(),
7710                expr: Shared::new(Expr::Call(
7711                    IdentWithToken::new_with_token(constants::builtins::SLICE, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod")))))),
7712                    smallvec![
7713                        Shared::new(Node {
7714                            token_id: 0.into(),
7715                            expr: Shared::new(Expr::QualifiedAccess(
7716                                vec![IdentWithToken::new_with_token("mod", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("mod"))))))],
7717                                AccessTarget::Call(
7718                                    IdentWithToken::new_with_token("func", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("func")))))),
7719                                    smallvec![],
7720                                ),
7721                            )),
7722                        }),
7723                        Shared::new(Node {
7724                            token_id: 1.into(),
7725                            expr: Shared::new(Expr::Literal(Literal::Number(0.into()))),
7726                        }),
7727                        Shared::new(Node {
7728                            token_id: 2.into(),
7729                            expr: Shared::new(Expr::Literal(Literal::Number(1.into()))),
7730                        }),
7731                    ],
7732                )),
7733            })
7734        ]))]
7735    #[case::selector_dot_is_self(
7736                vec![
7737                    token(TokenKind::Selector(SmolStr::new("."))),
7738                    token(TokenKind::Eof)
7739                ],
7740                Ok(vec![
7741                    Shared::new(Node {
7742                        token_id: 0.into(),
7743                        expr: Shared::new(Expr::Self_),
7744                    })
7745                ]))]
7746    #[case::ident_with_single_attr(
7747                    vec![
7748                        token(TokenKind::Ident(SmolStr::new("obj"))),
7749                        token(TokenKind::Selector(SmolStr::new(".name"))),
7750                        token(TokenKind::Eof)
7751                    ],
7752                    Ok(vec![
7753                        Shared::new(Node {
7754                            token_id: 1.into(),
7755                            expr: Shared::new(Expr::Call(
7756                                IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("obj")))))),
7757                                smallvec![
7758                                    Shared::new(Node {
7759                                        token_id: 0.into(),
7760                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("obj", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("obj")))))))),
7761                                    }),
7762                                    Shared::new(Node {
7763                                        token_id: 1.into(),
7764                                        expr: Shared::new(Expr::Literal(Literal::String("name".to_owned()))),
7765                                    }),
7766                                ],
7767                            )),
7768                        })
7769                    ]))]
7770    #[case::function_call_result_with_attr(
7771                    vec![
7772                        token(TokenKind::Ident(SmolStr::new("get_user"))),
7773                        token(TokenKind::LParen),
7774                        token(TokenKind::RParen),
7775                        token(TokenKind::Selector(SmolStr::new(".name"))),
7776                        token(TokenKind::Eof)
7777                    ],
7778                    Ok(vec![
7779                        Shared::new(Node {
7780                            token_id: 3.into(),
7781                            expr: Shared::new(Expr::Call(
7782                                IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("get_user")))))),
7783                                smallvec![
7784                                    Shared::new(Node {
7785                                        token_id: 0.into(),
7786                                        expr: Shared::new(Expr::Call(
7787                                            IdentWithToken::new_with_token("get_user", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("get_user")))))),
7788                                            SmallVec::new(),
7789                                        )),
7790                                    }),
7791                                    Shared::new(Node {
7792                                        token_id: 1.into(),
7793                                        expr: Shared::new(Expr::Literal(Literal::String("name".to_owned()))),
7794                                    }),
7795                                ],
7796                            )),
7797                        })
7798                    ]))]
7799    #[case::ident_with_attr_in_pipe(
7800                    vec![
7801                        token(TokenKind::Ident(SmolStr::new("data"))),
7802                        token(TokenKind::Pipe),
7803                        token(TokenKind::Ident(SmolStr::new("obj"))),
7804                        token(TokenKind::Selector(SmolStr::new(".value"))),
7805                        token(TokenKind::Eof)
7806                    ],
7807                    Ok(vec![
7808                        Shared::new(Node {
7809                            token_id: 0.into(),
7810                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("data", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("data")))))))),
7811                        }),
7812                        Shared::new(Node {
7813                            token_id: 3.into(),
7814                            expr: Shared::new(Expr::Call(
7815                                IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Ident(SmolStr::new("obj")))))),
7816                                smallvec![
7817                                    Shared::new(Node {
7818                                        token_id: 1.into(),
7819                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("obj", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("obj")))))))),
7820                                    }),
7821                                    Shared::new(Node {
7822                                        token_id: 2.into(),
7823                                        expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
7824                                    }),
7825                                ],
7826                            )),
7827                        })
7828                    ]))]
7829    #[case::self_with_attr(
7830                    vec![
7831                        token(TokenKind::Self_),
7832                        token(TokenKind::Selector(SmolStr::new(".value"))),
7833                        token(TokenKind::Eof)
7834                    ],
7835                    Ok(vec![
7836                        Shared::new(Node {
7837                            token_id: 1.into(),
7838                            expr: Shared::new(Expr::Call(
7839                                IdentWithToken::new_with_token(constants::builtins::ATTR, Some(Shared::new(token(TokenKind::Self_)))),
7840                                smallvec![
7841                                    Shared::new(Node {
7842                                        token_id: 0.into(),
7843                                        expr: Shared::new(Expr::Self_),
7844                                    }),
7845                                    Shared::new(Node {
7846                                        token_id: 1.into(),
7847                                        expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
7848                                    }),
7849                                ],
7850                            )),
7851                        })
7852                    ]))]
7853    #[case::pipe_equal_with_selector(
7854                    vec![
7855                        token(TokenKind::Selector(SmolStr::new(".h1"))),
7856                        token(TokenKind::Selector(SmolStr::new(".value"))),
7857                        token(TokenKind::PipeEqual),
7858                        token(TokenKind::StringLiteral("new_id".to_owned())),
7859                        token(TokenKind::Eof)
7860                    ],
7861                    Ok(vec![
7862                        Shared::new(Node {
7863                            token_id: 3.into(),
7864                            expr: Shared::new(Expr::Call(
7865                                IdentWithToken::new_with_token(constants::builtins::SET_ATTR, Some(Shared::new(token(TokenKind::StringLiteral("new_id".to_owned()))))),
7866                                smallvec![
7867                                    Shared::new(Node {
7868                                        token_id: 0.into(),
7869                                        expr: Shared::new(Expr::Selector(selector::Selector::Heading(Some(1)))),
7870                                    }),
7871                                    Shared::new(Node {
7872                                        token_id: 1.into(),
7873                                        expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
7874                                    }),
7875                                    Shared::new(Node {
7876                                        token_id: 2.into(),
7877                                        expr: Shared::new(Expr::Literal(Literal::String("new_id".to_owned()))),
7878                                    }),
7879                                ],
7880                            )),
7881                        })
7882                    ]))]
7883    #[case::pipe_equal_with_ident_and_attr(
7884                    vec![
7885                        token(TokenKind::Ident(SmolStr::new("obj"))),
7886                        token(TokenKind::Selector(SmolStr::new(".value"))),
7887                        token(TokenKind::PipeEqual),
7888                        token(TokenKind::StringLiteral("John".to_owned())),
7889                        token(TokenKind::Eof)
7890                    ],
7891                    Ok(vec![
7892                        Shared::new(Node {
7893                            token_id: 3.into(),
7894                            expr: Shared::new(Expr::Call(
7895                                IdentWithToken::new_with_token(constants::builtins::SET_ATTR, Some(Shared::new(token(TokenKind::StringLiteral("John".to_owned()))))),
7896                                smallvec![
7897                                    Shared::new(Node {
7898                                        token_id: 0.into(),
7899                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("obj", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("obj")))))))),
7900                                    }),
7901                                    Shared::new(Node {
7902                                        token_id: 1.into(),
7903                                        expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
7904                                    }),
7905                                    Shared::new(Node {
7906                                        token_id: 2.into(),
7907                                        expr: Shared::new(Expr::Literal(Literal::String("John".to_owned()))),
7908                                    }),
7909                                ],
7910                            )),
7911                        })
7912                    ]))]
7913    #[case::pipe_equal_with_self_and_attr(
7914                    vec![
7915                        token(TokenKind::Self_),
7916                        token(TokenKind::Selector(SmolStr::new(".value"))),
7917                        token(TokenKind::PipeEqual),
7918                        token(TokenKind::NumberLiteral(42.into())),
7919                        token(TokenKind::Eof)
7920                    ],
7921                    Ok(vec![
7922                        Shared::new(Node {
7923                            token_id: 2.into(),
7924                            expr: Shared::new(Expr::Call(
7925                                IdentWithToken::new_with_token(constants::builtins::SET_ATTR, Some(Shared::new(token(TokenKind::NumberLiteral(42.into()))))),
7926                                smallvec![
7927                                    Shared::new(Node {
7928                                        token_id: 0.into(),
7929                                        expr: Shared::new(Expr::Self_),
7930                                    }),
7931                                    Shared::new(Node {
7932                                        token_id: 1.into(),
7933                                        expr: Shared::new(Expr::Literal(Literal::String("value".to_owned()))),
7934                                    }),
7935                                    Shared::new(Node {
7936                                        token_id: 2.into(),
7937                                        expr: Shared::new(Expr::Literal(Literal::Number(42.into()))),
7938                                    }),
7939                                ],
7940                            )),
7941                        })
7942                    ]))]
7943    #[case::let_with_reserved_keyword_as_value(
7944                        vec![
7945                            token(TokenKind::Let),
7946                            token(TokenKind::Ident(SmolStr::new("aaa"))),
7947                            token(TokenKind::Equal),
7948                            token(TokenKind::Let), // Using "let" as a value (should error)
7949                            token(TokenKind::Eof)
7950                        ],
7951                        Err(SyntaxError::UnexpectedToken(Token {
7952                            range: Range::default(),
7953                            kind: TokenKind::Let,
7954                            module_id: 1.into(),
7955                        }))
7956                    )]
7957    #[case::let_with_reserved_keyword_as_variable_and_value(
7958                        vec![
7959                            token(TokenKind::Let),
7960                            token(TokenKind::Let), // Using "let" as a variable name (should error)
7961                            token(TokenKind::Equal),
7962                            token(TokenKind::Ident(SmolStr::new("vvv"))),
7963                            token(TokenKind::Eof)
7964                        ],
7965                        Err(SyntaxError::UnexpectedToken(Token {
7966                            range: Range::default(),
7967                            kind: TokenKind::Let,
7968                            module_id: 1.into(),
7969                        }))
7970                    )]
7971    #[case::let_with_reserved_keyword_as_variable_and_value2(
7972                        vec![
7973                            token(TokenKind::Let),
7974                            token(TokenKind::Let), // Using "let" as a variable name (should error)
7975                            token(TokenKind::Equal),
7976                            token(TokenKind::Let), // Using "let" as a value (should error)
7977                            token(TokenKind::Eof)
7978                        ],
7979                        Err(SyntaxError::UnexpectedToken(Token {
7980                            range: Range::default(),
7981                            kind: TokenKind::Let,
7982                            module_id: 1.into(),
7983                        }))
7984                    )]
7985    #[case::macro_basic(
7986        vec![
7987            token(TokenKind::Macro),
7988            token(TokenKind::Ident(SmolStr::new("double"))),
7989            token(TokenKind::LParen),
7990            token(TokenKind::Ident(SmolStr::new("x"))),
7991            token(TokenKind::RParen),
7992            token(TokenKind::Colon),
7993            token(TokenKind::Ident(SmolStr::new("x"))),
7994            token(TokenKind::Plus),
7995            token(TokenKind::Ident(SmolStr::new("x"))),
7996        ],
7997        Ok(vec![
7998            Shared::new(Node {
7999                token_id: 0.into(),
8000                expr: Shared::new(Expr::Macro(
8001                    IdentWithToken::new_with_token("double", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("double")))))),
8002                    smallvec![
8003                        Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))
8004                    ],
8005                    Shared::new(Node {
8006                        token_id: 3.into(),
8007                        expr: Shared::new(Expr::Call(
8008                            IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
8009                            smallvec![
8010                                Shared::new(Node {
8011                                    token_id: 2.into(),
8012                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
8013                                }),
8014                                Shared::new(Node {
8015                                    token_id: 4.into(),
8016                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
8017                                })
8018                            ]
8019                        ))
8020                    }),
8021                )),
8022            }),
8023        ]))]
8024    #[case::macro_with_end(
8025        vec![
8026            token(TokenKind::Macro),
8027            token(TokenKind::Ident(SmolStr::new("triple"))),
8028            token(TokenKind::LParen),
8029            token(TokenKind::Ident(SmolStr::new("x"))),
8030            token(TokenKind::RParen),
8031            token(TokenKind::Colon),
8032            token(TokenKind::Ident(SmolStr::new("x"))),
8033            token(TokenKind::Plus),
8034            token(TokenKind::Ident(SmolStr::new("x"))),
8035            token(TokenKind::Plus),
8036            token(TokenKind::Ident(SmolStr::new("x"))),
8037        ],
8038        Ok(vec![
8039            Shared::new(Node {
8040                token_id: 0.into(),
8041                expr: Shared::new(Expr::Macro(
8042                    IdentWithToken::new_with_token("triple", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("triple")))))),
8043                    smallvec![
8044                        Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))
8045                    ],
8046                    Shared::new(Node {
8047                        token_id: 5.into(),
8048                        expr: Shared::new(Expr::Call(
8049                            IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
8050                            smallvec![
8051                                Shared::new(Node {
8052                                    token_id: 3.into(),
8053                                    expr: Shared::new(Expr::Call(
8054                                        IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
8055                                        smallvec![
8056                                            Shared::new(Node {
8057                                                token_id: 2.into(),
8058                                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
8059                                            }),
8060                                            Shared::new(Node {
8061                                                token_id: 4.into(),
8062                                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
8063                                            })
8064                                        ]
8065                                    ))
8066                                }),
8067                                Shared::new(Node {
8068                                    token_id: 6.into(),
8069                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
8070                                })
8071                            ]
8072                        ))
8073                    }),
8074                )),
8075            }),
8076        ]))]
8077    #[case::macro_multiple_params(
8078        vec![
8079            token(TokenKind::Macro),
8080            token(TokenKind::Ident(SmolStr::new("add_two"))),
8081            token(TokenKind::LParen),
8082            token(TokenKind::Ident(SmolStr::new("a"))),
8083            token(TokenKind::Comma),
8084            token(TokenKind::Ident(SmolStr::new("b"))),
8085            token(TokenKind::RParen),
8086            token(TokenKind::Colon),
8087            token(TokenKind::Ident(SmolStr::new("a"))),
8088            token(TokenKind::Plus),
8089            token(TokenKind::Ident(SmolStr::new("b"))),
8090        ],
8091        Ok(vec![
8092            Shared::new(Node {
8093                token_id: 0.into(),
8094                expr: Shared::new(Expr::Macro(
8095                    IdentWithToken::new_with_token("add_two", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("add_two")))))),
8096                    smallvec![
8097                        Param::new(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a"))))))),
8098                        Param::new(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b"))))))),
8099                    ],
8100                    Shared::new(Node {
8101                        token_id: 3.into(),
8102                        expr: Shared::new(Expr::Call(
8103                            IdentWithToken::new_with_token(constants::builtins::ADD, Some(Shared::new(token(TokenKind::Plus)))),
8104                            smallvec![
8105                                Shared::new(Node {
8106                                    token_id: 2.into(),
8107                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a")))))))),
8108                                }),
8109                                Shared::new(Node {
8110                                    token_id: 4.into(),
8111                                    expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("b", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("b")))))))),
8112                                })
8113                            ]
8114                        ))
8115                    }),
8116                )),
8117            }),
8118        ]))]
8119    #[case::def_with_variadic_param(
8120        vec![
8121            token(TokenKind::Def),
8122            token(TokenKind::Ident(SmolStr::new("f"))),
8123            token(TokenKind::LParen),
8124            token(TokenKind::Asterisk),
8125            token(TokenKind::Ident(SmolStr::new("args"))),
8126            token(TokenKind::RParen),
8127            token(TokenKind::Colon),
8128            token(TokenKind::Ident(SmolStr::new("args"))),
8129            token(TokenKind::SemiColon)
8130        ],
8131        Ok(vec![
8132            Shared::new(Node {
8133                token_id: 0.into(),
8134                expr: Shared::new(Expr::Def(
8135                        IdentWithToken::new_with_token("f", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("f")))))),
8136                        smallvec![
8137                            Param::variadic(IdentWithToken::new_with_token("args", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("args"))))))),
8138                        ],
8139                        vec![Shared::new(Node {
8140                            token_id: 2.into(),
8141                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("args", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("args")))))))),
8142                        })],
8143                )),
8144            }),
8145        ]))]
8146    #[case::def_with_regular_and_variadic_param(
8147        vec![
8148            token(TokenKind::Def),
8149            token(TokenKind::Ident(SmolStr::new("f"))),
8150            token(TokenKind::LParen),
8151            token(TokenKind::Ident(SmolStr::new("a"))),
8152            token(TokenKind::Comma),
8153            token(TokenKind::Asterisk),
8154            token(TokenKind::Ident(SmolStr::new("rest"))),
8155            token(TokenKind::RParen),
8156            token(TokenKind::Colon),
8157            token(TokenKind::Ident(SmolStr::new("rest"))),
8158            token(TokenKind::SemiColon)
8159        ],
8160        Ok(vec![
8161            Shared::new(Node {
8162                token_id: 0.into(),
8163                expr: Shared::new(Expr::Def(
8164                        IdentWithToken::new_with_token("f", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("f")))))),
8165                        smallvec![
8166                            Param::new(IdentWithToken::new_with_token("a", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("a"))))))),
8167                            Param::variadic(IdentWithToken::new_with_token("rest", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("rest"))))))),
8168                        ],
8169                        vec![Shared::new(Node {
8170                            token_id: 2.into(),
8171                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("rest", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("rest")))))))),
8172                        })],
8173                )),
8174            }),
8175        ]))]
8176    #[case::def_variadic_param_not_last(
8177        vec![
8178            token(TokenKind::Def),
8179            token(TokenKind::Ident(SmolStr::new("f"))),
8180            token(TokenKind::LParen),
8181            token(TokenKind::Asterisk),
8182            token(TokenKind::Ident(SmolStr::new("a"))),
8183            token(TokenKind::Comma),
8184            token(TokenKind::Ident(SmolStr::new("b"))),
8185            token(TokenKind::RParen),
8186        ],
8187        Err(SyntaxError::VariadicParameterMustBeLast(Token{range: Range::default(), kind: TokenKind::Ident(SmolStr::new("b")), module_id: 1.into()})))]
8188    #[case::def_multiple_variadic_params(
8189        vec![
8190            token(TokenKind::Def),
8191            token(TokenKind::Ident(SmolStr::new("f"))),
8192            token(TokenKind::LParen),
8193            token(TokenKind::Asterisk),
8194            token(TokenKind::Ident(SmolStr::new("a"))),
8195            token(TokenKind::Comma),
8196            token(TokenKind::Asterisk),
8197            token(TokenKind::Ident(SmolStr::new("b"))),
8198            token(TokenKind::RParen),
8199        ],
8200        Err(SyntaxError::MultipleVariadicParameters(Token{range: Range::default(), kind: TokenKind::Asterisk, module_id: 1.into()})))]
8201    #[case::def_without_params(
8202        vec![
8203            token(TokenKind::Def),
8204            token(TokenKind::Ident(SmolStr::new("f"))),
8205            token(TokenKind::Colon),
8206            token(TokenKind::Ident(SmolStr::new("args"))),
8207            token(TokenKind::SemiColon)
8208        ],
8209        Ok(vec![
8210            Shared::new(Node {
8211                token_id: 0.into(),
8212                expr: Shared::new(Expr::Def(
8213                        IdentWithToken::new_with_token("f", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("f")))))),
8214                        smallvec![],
8215                        vec![Shared::new(Node {
8216                            token_id: 2.into(),
8217                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("args", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("args")))))))),
8218                        })],
8219                )),
8220            }),
8221        ]))]
8222    #[case::def_without_params_with_do(
8223        vec![
8224            token(TokenKind::Def),
8225            token(TokenKind::Ident(SmolStr::new("f"))),
8226            token(TokenKind::Do),
8227            token(TokenKind::Ident(SmolStr::new("args"))),
8228            token(TokenKind::SemiColon)
8229        ],
8230        Ok(vec![
8231            Shared::new(Node {
8232                token_id: 0.into(),
8233                expr: Shared::new(Expr::Def(
8234                        IdentWithToken::new_with_token("f", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("f")))))),
8235                        smallvec![],
8236                        vec![Shared::new(Node {
8237                            token_id: 2.into(),
8238                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("args", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("args")))))))),
8239                        })],
8240                )),
8241            }),
8242        ]))]
8243    #[case::macro_variadic_param(
8244        vec![
8245            token(TokenKind::Macro),
8246            token(TokenKind::Ident(SmolStr::new("m"))),
8247            token(TokenKind::LParen),
8248            token(TokenKind::Asterisk),
8249            token(TokenKind::Ident(SmolStr::new("args"))),
8250            token(TokenKind::RParen),
8251            token(TokenKind::Colon),
8252            token(TokenKind::Ident(SmolStr::new("args"))),
8253        ],
8254        Err(SyntaxError::MacroParametersCannotBeVariadic(Token{range: Range::default(), kind: TokenKind::Macro, module_id: 1.into()})))]
8255    #[case::arrow_simple(
8256        vec![
8257            token(TokenKind::Arrow),
8258            token(TokenKind::LParen),
8259            token(TokenKind::RParen),
8260            token(TokenKind::Colon),
8261            token(TokenKind::StringLiteral("result".to_owned())),
8262            token(TokenKind::SemiColon),
8263        ],
8264        Ok(vec![
8265            Shared::new(Node {
8266                token_id: 0.into(),
8267                expr: Shared::new(Expr::Fn(
8268                    SmallVec::new(),
8269                    vec![
8270                        Shared::new(Node {
8271                            token_id: 2.into(),
8272                            expr: Shared::new(Expr::Literal(Literal::String("result".to_owned()))),
8273                        })
8274                    ],
8275                )),
8276            })
8277        ]))]
8278    #[case::arrow_with_args(
8279        vec![
8280            token(TokenKind::Arrow),
8281            token(TokenKind::LParen),
8282            token(TokenKind::Ident(SmolStr::new("x"))),
8283            token(TokenKind::Comma),
8284            token(TokenKind::Ident(SmolStr::new("y"))),
8285            token(TokenKind::RParen),
8286            token(TokenKind::Colon),
8287            token(TokenKind::Ident(SmolStr::new("contains"))),
8288            token(TokenKind::LParen),
8289            token(TokenKind::Ident(SmolStr::new("x"))),
8290            token(TokenKind::Comma),
8291            token(TokenKind::Ident(SmolStr::new("y"))),
8292            token(TokenKind::RParen),
8293            token(TokenKind::SemiColon),
8294        ],
8295        Ok(vec![
8296            Shared::new(Node {
8297                token_id: 0.into(),
8298                expr: Shared::new(Expr::Fn(
8299                    smallvec![
8300                        Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
8301                        Param::new(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y"))))))),
8302                    ],
8303                    vec![
8304                        Shared::new(Node {
8305                            token_id: 4.into(),
8306                            expr: Shared::new(Expr::Call(
8307                                IdentWithToken::new_with_token("contains", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("contains")))))),
8308                                smallvec![
8309                                    Shared::new(Node {
8310                                        token_id: 2.into(),
8311                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x")))))))),
8312                                    }),
8313                                    Shared::new(Node {
8314                                        token_id: 3.into(),
8315                                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("y", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("y")))))))),
8316                                    }),
8317                                ],
8318                            )),
8319                        })
8320                    ],
8321                )),
8322            })
8323        ]))]
8324    #[case::arrow_nested_in_call(
8325        vec![
8326            token(TokenKind::Ident(SmolStr::new("apply"))),
8327            token(TokenKind::LParen),
8328            token(TokenKind::Arrow),
8329            token(TokenKind::LParen),
8330            token(TokenKind::Ident(SmolStr::new("x"))),
8331            token(TokenKind::RParen),
8332            token(TokenKind::Colon),
8333            token(TokenKind::StringLiteral("processed".to_owned())),
8334            token(TokenKind::SemiColon),
8335            token(TokenKind::RParen),
8336            token(TokenKind::Eof),
8337        ],
8338        Ok(vec![
8339            Shared::new(Node {
8340                token_id: 4.into(),
8341                expr: Shared::new(Expr::Call(
8342                    IdentWithToken::new_with_token("apply", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("apply")))))),
8343                    smallvec![
8344                        Shared::new(Node {
8345                            token_id: 0.into(),
8346                            expr: Shared::new(Expr::Fn(
8347                                smallvec![
8348                                  Param::new(IdentWithToken::new_with_token("x", Some(Shared::new(token(TokenKind::Ident(SmolStr::new("x"))))))),
8349                                ],
8350                                vec![
8351                                    Shared::new(Node {
8352                                        token_id: 2.into(),
8353                                        expr: Shared::new(Expr::Literal(Literal::String("processed".to_owned()))),
8354                                    })
8355                                ],
8356                            )),
8357                        })
8358                    ],
8359                )),
8360            })
8361        ]))]
8362    fn test_parse(#[case] input: Vec<Token>, #[case] expected: Result<Program, SyntaxError>) {
8363        let mut arena = Arena::new(10);
8364        let tokens: Vec<Shared<Token>> = input.into_iter().map(Shared::new).collect();
8365        let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8366
8367        match (&result, &expected) {
8368            (Ok(actual), Ok(expected)) => {
8369                assert_eq!(actual.len(), expected.len());
8370                let actual_exprs: Vec<_> = actual.iter().map(|a| &*a.expr).collect();
8371                let expected_exprs: Vec<_> = expected.iter().map(|e| &*e.expr).collect();
8372                assert_eq!(actual_exprs, expected_exprs);
8373            }
8374            (Err(actual), Err(expected)) => {
8375                assert_eq!(actual, expected);
8376            }
8377            _ => {
8378                panic!("Mismatch: actual = {:?}, expected = {:?}", result, expected)
8379            }
8380        }
8381    }
8382
8383    #[rstest]
8384    #[case::heading(".h1", Selector::Heading(Some(1)))]
8385    #[case::heading_h3(".h3", Selector::Heading(Some(3)))]
8386    #[case::blockquote(".>", Selector::Blockquote)]
8387    #[case::blockquote_full(".blockquote", Selector::Blockquote)]
8388    #[case::footnote(".^", Selector::Footnote)]
8389    #[case::footnote_full(".footnote", Selector::Footnote)]
8390    #[case::mdx_jsx_flow(".mdx_jsx_flow_element", Selector::MdxJsxFlowElement)]
8391    #[case::mdx_jsx_flow_short(".<", Selector::MdxJsxFlowElement)]
8392    #[case::emphasis(".**", Selector::Emphasis)]
8393    #[case::emphasis_full(".emphasis", Selector::Emphasis)]
8394    #[case::math(".$$", Selector::Math)]
8395    #[case::math_full(".math", Selector::Math)]
8396    #[case::horizontal_rule(".---", Selector::HorizontalRule)]
8397    #[case::horizontal_rule_alt(".***", Selector::HorizontalRule)]
8398    #[case::horizontal_rule_full(".horizontal_rule", Selector::HorizontalRule)]
8399    #[case::mdx_text_expression(".{}", Selector::MdxTextExpression)]
8400    #[case::mdx_text_expression_full(".mdx_text_expression", Selector::MdxTextExpression)]
8401    #[case::footnote_ref(".[^]", Selector::FootnoteRef)]
8402    #[case::footnote_ref_full(".footnote_ref", Selector::FootnoteRef)]
8403    #[case::definition(".definition", Selector::Definition)]
8404    #[case::break_selector(".break", Selector::Break)]
8405    #[case::delete(".delete", Selector::Delete)]
8406    #[case::html(".<>", Selector::Html)]
8407    #[case::html_full(".html", Selector::Html)]
8408    #[case::image(".image", Selector::Image)]
8409    #[case::image_ref(".image_ref", Selector::ImageRef)]
8410    #[case::code(".code", Selector::Code)]
8411    #[case::code_inline(".code_inline", Selector::InlineCode)]
8412    #[case::math_inline(".math_inline", Selector::InlineMath)]
8413    #[case::link(".link", Selector::Link)]
8414    #[case::link_ref(".link_ref", Selector::LinkRef)]
8415    #[case::list(".list", Selector::List(None, None))]
8416    #[case::toml(".toml", Selector::Toml)]
8417    #[case::strong(".strong", Selector::Strong)]
8418    #[case::yaml(".yaml", Selector::Yaml)]
8419    #[case::text(".text", Selector::Text)]
8420    #[case::mdx_js_esm(".mdx_js_esm", Selector::MdxJsEsm)]
8421    #[case::mdx_jsx_text_element(".mdx_jsx_text_element", Selector::MdxJsxTextElement)]
8422    #[case::mdx_flow_expression(".mdx_flow_expression", Selector::MdxFlowExpression)]
8423    fn test_parse_selector(#[case] selector_str: &str, #[case] expected_selector: Selector) {
8424        let mut arena = Arena::new(10);
8425        let token = Shared::new(Token {
8426            range: Range::default(),
8427            kind: TokenKind::Selector(SmolStr::new(selector_str)),
8428            module_id: 1.into(),
8429        });
8430
8431        let tokens = [
8432            Shared::clone(&token),
8433            Shared::new(Token {
8434                range: Range::default(),
8435                kind: TokenKind::Eof,
8436                module_id: 1.into(),
8437            }),
8438        ];
8439
8440        let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8441
8442        match result {
8443            Ok(program) => {
8444                assert_eq!(program.len(), 1);
8445                if let Expr::Selector(selector) = &*program[0].expr {
8446                    assert_eq!(*selector, expected_selector);
8447                } else {
8448                    panic!("Expected Selector expression, got {:?}", program[0].expr);
8449                }
8450            }
8451            Err(err) => panic!("Parse error: {:?}", err),
8452        }
8453    }
8454
8455    #[rstest]
8456    #[case(".", Some(1), None, Selector::List(Some(1), None))]
8457    #[case(".", Some(2), Some(3), Selector::Table(Some(2), Some(3)))]
8458    fn test_parse_array_selector(
8459        #[case] selector_str: &str,
8460        #[case] first_idx: Option<usize>,
8461        #[case] second_idx: Option<usize>,
8462        #[case] expected_selector: Selector,
8463    ) {
8464        let mut arena = Arena::new(10);
8465        let mut tokens = vec![
8466            Shared::new(Token {
8467                range: Range::default(),
8468                kind: TokenKind::Selector(SmolStr::new(selector_str)),
8469                module_id: 1.into(),
8470            }),
8471            Shared::new(Token {
8472                range: Range::default(),
8473                kind: TokenKind::LBracket,
8474                module_id: 1.into(),
8475            }),
8476        ];
8477
8478        if let Some(idx) = first_idx {
8479            tokens.push(Shared::new(Token {
8480                range: Range::default(),
8481                kind: TokenKind::NumberLiteral(idx.into()),
8482                module_id: 1.into(),
8483            }));
8484        }
8485
8486        tokens.push(Shared::new(Token {
8487            range: Range::default(),
8488            kind: TokenKind::RBracket,
8489            module_id: 1.into(),
8490        }));
8491
8492        if second_idx.is_some() {
8493            tokens.push(Shared::new(Token {
8494                range: Range::default(),
8495                kind: TokenKind::LBracket,
8496                module_id: 1.into(),
8497            }));
8498
8499            if let Some(idx) = second_idx {
8500                tokens.push(Shared::new(Token {
8501                    range: Range::default(),
8502                    kind: TokenKind::NumberLiteral(idx.into()),
8503                    module_id: 1.into(),
8504                }));
8505            }
8506
8507            tokens.push(Shared::new(Token {
8508                range: Range::default(),
8509                kind: TokenKind::RBracket,
8510                module_id: 1.into(),
8511            }));
8512        }
8513
8514        tokens.push(Shared::new(Token {
8515            range: Range::default(),
8516            kind: TokenKind::Eof,
8517            module_id: 1.into(),
8518        }));
8519
8520        let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8521
8522        match result {
8523            Ok(program) => {
8524                assert_eq!(program.len(), 1);
8525                if let Expr::Selector(selector) = &*program[0].expr {
8526                    assert_eq!(*selector, expected_selector);
8527                } else {
8528                    panic!("Expected Selector expression, got {:?}", program[0].expr);
8529                }
8530            }
8531            Err(err) => panic!("Parse error: {:?}", err),
8532        }
8533    }
8534
8535    // ."key"[] or ."key"[n] — single property selector followed by array iterator/index
8536    #[rstest]
8537    #[case::all_elements(".\"items\"", None, vec![Selector::Property("items".into()), Selector::List(None, None)])]
8538    #[case::index_0(".\"items\"", Some(0usize), vec![Selector::Property("items".into()), Selector::List(Some(0), None)])]
8539    #[case::index_2(".\"items\"", Some(2usize), vec![Selector::Property("items".into()), Selector::List(Some(2), None)])]
8540    fn test_parse_property_selector_iterator(
8541        #[case] selector_str: &str,
8542        #[case] index: Option<usize>,
8543        #[case] expected: Vec<Selector>,
8544    ) {
8545        let mut arena = Arena::new(10);
8546        let mut tokens = vec![
8547            Shared::new(Token {
8548                range: Range::default(),
8549                kind: TokenKind::Selector(SmolStr::new(selector_str)),
8550                module_id: 1.into(),
8551            }),
8552            Shared::new(Token {
8553                range: Range::default(),
8554                kind: TokenKind::LBracket,
8555                module_id: 1.into(),
8556            }),
8557        ];
8558        if let Some(idx) = index {
8559            tokens.push(Shared::new(Token {
8560                range: Range::default(),
8561                kind: TokenKind::NumberLiteral(idx.into()),
8562                module_id: 1.into(),
8563            }));
8564        }
8565        tokens.push(Shared::new(Token {
8566            range: Range::default(),
8567            kind: TokenKind::RBracket,
8568            module_id: 1.into(),
8569        }));
8570        tokens.push(Shared::new(Token {
8571            range: Range::default(),
8572            kind: TokenKind::Eof,
8573            module_id: 1.into(),
8574        }));
8575
8576        let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID)
8577            .parse()
8578            .expect("parse error");
8579
8580        assert_eq!(result.len(), 1);
8581        let Expr::Block(nodes) = &*result[0].expr else {
8582            panic!("expected Block, got {:?}", result[0].expr);
8583        };
8584        assert_eq!(nodes.len(), expected.len());
8585        for (node, sel) in nodes.iter().zip(expected.iter()) {
8586            let Expr::Selector(actual) = &*node.expr else {
8587                panic!("expected Selector, got {:?}", node.expr);
8588            };
8589            assert_eq!(actual, sel);
8590        }
8591    }
8592
8593    // ."a"."b"[] or ."a"."b"[n] — chained property selectors followed by array iterator/index
8594    #[rstest]
8595    #[case::all_elements(".\"a\"", ".\"b\"", None, vec![Selector::Property("a".into()), Selector::Property("b".into()), Selector::List(None, None)])]
8596    #[case::index_0(".\"a\"", ".\"b\"", Some(0usize), vec![Selector::Property("a".into()), Selector::Property("b".into()), Selector::List(Some(0), None)])]
8597    #[case::index_1(".\"a\"", ".\"b\"", Some(1usize), vec![Selector::Property("a".into()), Selector::Property("b".into()), Selector::List(Some(1), None)])]
8598    fn test_parse_chained_property_selector_iterator(
8599        #[case] first: &str,
8600        #[case] second: &str,
8601        #[case] index: Option<usize>,
8602        #[case] expected: Vec<Selector>,
8603    ) {
8604        let mut arena = Arena::new(10);
8605        let mut tokens = vec![
8606            Shared::new(Token {
8607                range: Range::default(),
8608                kind: TokenKind::Selector(SmolStr::new(first)),
8609                module_id: 1.into(),
8610            }),
8611            Shared::new(Token {
8612                range: Range::default(),
8613                kind: TokenKind::Selector(SmolStr::new(second)),
8614                module_id: 1.into(),
8615            }),
8616            Shared::new(Token {
8617                range: Range::default(),
8618                kind: TokenKind::LBracket,
8619                module_id: 1.into(),
8620            }),
8621        ];
8622        if let Some(idx) = index {
8623            tokens.push(Shared::new(Token {
8624                range: Range::default(),
8625                kind: TokenKind::NumberLiteral(idx.into()),
8626                module_id: 1.into(),
8627            }));
8628        }
8629        tokens.push(Shared::new(Token {
8630            range: Range::default(),
8631            kind: TokenKind::RBracket,
8632            module_id: 1.into(),
8633        }));
8634        tokens.push(Shared::new(Token {
8635            range: Range::default(),
8636            kind: TokenKind::Eof,
8637            module_id: 1.into(),
8638        }));
8639
8640        let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID)
8641            .parse()
8642            .expect("parse error");
8643
8644        assert_eq!(result.len(), 1);
8645        let Expr::Block(nodes) = &*result[0].expr else {
8646            panic!("expected Block, got {:?}", result[0].expr);
8647        };
8648        assert_eq!(nodes.len(), expected.len());
8649        for (node, sel) in nodes.iter().zip(expected.iter()) {
8650            let Expr::Selector(actual) = &*node.expr else {
8651                panic!("expected Selector, got {:?}", node.expr);
8652            };
8653            assert_eq!(actual, sel);
8654        }
8655    }
8656
8657    #[test]
8658    fn test_parse_as_binding() {
8659        let mut arena = Arena::new(10);
8660        let tokens = [
8661            Shared::new(Token {
8662                range: Range::default(),
8663                kind: TokenKind::NumberLiteral(42.into()),
8664                module_id: 1.into(),
8665            }),
8666            Shared::new(Token {
8667                range: Range::default(),
8668                kind: TokenKind::As,
8669                module_id: 1.into(),
8670            }),
8671            Shared::new(Token {
8672                range: Range::default(),
8673                kind: TokenKind::Ident("x".into()),
8674                module_id: 1.into(),
8675            }),
8676            Shared::new(Token {
8677                range: Range::default(),
8678                kind: TokenKind::Eof,
8679                module_id: 1.into(),
8680            }),
8681        ];
8682        let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8683        assert!(result.is_ok());
8684        let program = result.unwrap();
8685        assert_eq!(program.len(), 1);
8686        let Expr::As(ident, inner) = &*program[0].expr else {
8687            panic!("expected Expr::As, got {:?}", program[0].expr);
8688        };
8689        assert_eq!(ident.name.as_str(), "x");
8690        assert!(matches!(*inner.expr, Expr::Literal(Literal::Number(_))));
8691    }
8692
8693    #[test]
8694    fn test_parse_env() {
8695        unsafe { std::env::set_var("MQ_TEST_VAR", "test_value") };
8696
8697        let mut arena = Arena::new(10);
8698        let tokens = [
8699            Shared::new(Token {
8700                range: Range::default(),
8701                kind: TokenKind::Env("MQ_TEST_VAR".into()),
8702                module_id: 1.into(),
8703            }),
8704            Shared::new(Token {
8705                range: Range::default(),
8706                kind: TokenKind::Eof,
8707                module_id: 1.into(),
8708            }),
8709        ];
8710
8711        let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8712
8713        match result {
8714            Ok(program) => {
8715                assert_eq!(program.len(), 1);
8716                if let Expr::Literal(Literal::String(value)) = &*program[0].expr {
8717                    assert_eq!(value, "test_value");
8718                } else {
8719                    panic!("Expected String literal, got {:?}", program[0].expr);
8720                }
8721            }
8722            Err(err) => panic!("Parse error: {:?}", err),
8723        }
8724    }
8725
8726    #[test]
8727    fn test_parse_env_not_found() {
8728        let mut arena = Arena::new(10);
8729        let token = Shared::new(Token {
8730            range: Range::default(),
8731            kind: TokenKind::Env("MQ_NONEXISTENT_VAR".into()),
8732            module_id: 1.into(),
8733        });
8734
8735        let tokens = [
8736            Shared::clone(&token),
8737            Shared::new(Token {
8738                range: Range::default(),
8739                kind: TokenKind::Eof,
8740                module_id: 1.into(),
8741            }),
8742        ];
8743
8744        let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8745
8746        assert!(matches!(
8747            result,
8748            Err(SyntaxError::EnvNotFound(_, var)) if var == "MQ_NONEXISTENT_VAR"
8749        ));
8750    }
8751
8752    #[test]
8753    fn test_parse_env_in_arguments() {
8754        unsafe { std::env::set_var("MQ_ARG_TEST", "env_arg_value") };
8755
8756        let mut arena = Arena::new(10);
8757        let tokens = [
8758            Shared::new(Token {
8759                range: Range::default(),
8760                kind: TokenKind::Ident(SmolStr::new("function")),
8761                module_id: 1.into(),
8762            }),
8763            Shared::new(Token {
8764                range: Range::default(),
8765                kind: TokenKind::LParen,
8766                module_id: 1.into(),
8767            }),
8768            Shared::new(Token {
8769                range: Range::default(),
8770                kind: TokenKind::Env("MQ_ARG_TEST".into()),
8771                module_id: 1.into(),
8772            }),
8773            Shared::new(Token {
8774                range: Range::default(),
8775                kind: TokenKind::RParen,
8776                module_id: 1.into(),
8777            }),
8778            Shared::new(Token {
8779                range: Range::default(),
8780                kind: TokenKind::Eof,
8781                module_id: 1.into(),
8782            }),
8783        ];
8784
8785        let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8786
8787        match result {
8788            Ok(program) => {
8789                assert_eq!(program.len(), 1);
8790                if let Expr::Call(ident, args) = &*program[0].expr {
8791                    assert_eq!(ident.name, "function".into());
8792                    assert_eq!(args.len(), 1);
8793                    if let Expr::Literal(Literal::String(value)) = &*args[0].expr {
8794                        assert_eq!(value, "env_arg_value");
8795                    } else {
8796                        panic!("Expected String literal in argument, got {:?}", args[0].expr);
8797                    }
8798                } else {
8799                    panic!("Expected Call expression, got {:?}", program[0].expr);
8800                }
8801            }
8802            Err(err) => panic!("Parse error: {:?}", err),
8803        }
8804    }
8805
8806    #[rstest]
8807    #[case::lang(".lang", "lang")]
8808    #[case::value(".value", "value")]
8809    #[case::depth(".depth", "depth")]
8810    fn test_parse_standalone_attr_selector(#[case] selector: &str, #[case] attribute: &str) {
8811        let mut arena = Arena::new(10);
8812        let tokens = [
8813            Shared::new(Token {
8814                range: Range::default(),
8815                kind: TokenKind::Selector(SmolStr::new(selector)),
8816                module_id: 1.into(),
8817            }),
8818            Shared::new(Token {
8819                range: Range::default(),
8820                kind: TokenKind::Eof,
8821                module_id: 1.into(),
8822            }),
8823        ];
8824
8825        let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8826
8827        match result {
8828            Ok(program) => {
8829                assert_eq!(program.len(), 1);
8830                if let Expr::Call(ident, args) = &*program[0].expr {
8831                    assert_eq!(ident.name, "attr".into());
8832                    assert_eq!(args.len(), 2);
8833                    assert!(matches!(&*args[0].expr, Expr::Self_));
8834                    if let Expr::Literal(Literal::String(attr_str)) = &*args[1].expr {
8835                        assert_eq!(attr_str, attribute);
8836                    } else {
8837                        panic!("Expected String literal in second argument, got {:?}", args[1].expr);
8838                    }
8839                } else {
8840                    panic!("Expected Call expression, got {:?}", program[0].expr);
8841                }
8842            }
8843            Err(err) => panic!("Parse error: {:?}", err),
8844        }
8845    }
8846
8847    #[rstest]
8848    #[case::h_value(vec![".h", ".value"], "h", "value")]
8849    #[case::h1_value(vec![".h1", ".value"], "h1", "value")]
8850    #[case::code_lang(vec![".code", ".lang"], "code", "lang")]
8851    #[case::text_value(vec![".text", ".value"], "text", "value")]
8852    fn test_parse_selector_with_attribute(
8853        #[case] selectors: Vec<&str>,
8854        #[case] base_selector: &str,
8855        #[case] attribute: &str,
8856    ) {
8857        let mut arena = Arena::new(10);
8858        let mut tokens = selectors
8859            .iter()
8860            .map(|selector| {
8861                Shared::new(Token {
8862                    range: Range::default(),
8863                    kind: TokenKind::Selector(SmolStr::new(selector)),
8864                    module_id: 1.into(),
8865                })
8866            })
8867            .collect::<Vec<_>>();
8868
8869        tokens.push(Shared::new(Token {
8870            range: Range::default(),
8871            kind: TokenKind::Eof,
8872            module_id: 1.into(),
8873        }));
8874
8875        let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
8876
8877        match result {
8878            Ok(program) => {
8879                assert_eq!(program.len(), 1);
8880                if let Expr::Call(ident, args) = &*program[0].expr {
8881                    // Should be transformed to attr(base_selector, "attribute")
8882                    assert_eq!(ident.name, "attr".into());
8883                    assert_eq!(args.len(), 2);
8884
8885                    // First argument should be the base selector
8886                    if let Expr::Selector(selector) = &*args[0].expr {
8887                        match base_selector {
8888                            "h" => assert_eq!(*selector, Selector::Heading(None)),
8889                            "h1" => assert_eq!(*selector, Selector::Heading(Some(1))),
8890                            "code" => assert_eq!(*selector, Selector::Code),
8891                            "text" => assert_eq!(*selector, Selector::Text),
8892                            _ => panic!("Unexpected base selector: {}", base_selector),
8893                        }
8894                    } else {
8895                        panic!("Expected Selector expression in first argument, got {:?}", args[0].expr);
8896                    }
8897
8898                    // Second argument should be the attribute string
8899                    if let Expr::Literal(Literal::String(attr_str)) = &*args[1].expr {
8900                        assert_eq!(attr_str, attribute);
8901                    } else {
8902                        panic!("Expected String literal in second argument, got {:?}", args[1].expr);
8903                    }
8904                } else {
8905                    panic!("Expected Call expression, got {:?}", program[0].expr);
8906                }
8907            }
8908            Err(err) => panic!("Parse error: {:?}", err),
8909        }
8910    }
8911
8912    #[rstest]
8913    #[case::match_simple_literal(
8914        vec![
8915            token(TokenKind::Match),
8916            token(TokenKind::LParen),
8917            token(TokenKind::Ident(SmolStr::new("x"))),
8918            token(TokenKind::RParen),
8919            token(TokenKind::Colon),
8920            token(TokenKind::Pipe),
8921            token(TokenKind::NumberLiteral(1.into())),
8922            token(TokenKind::Colon),
8923            token(TokenKind::StringLiteral("one".to_owned())),
8924            token(TokenKind::Pipe),
8925            token(TokenKind::NumberLiteral(2.into())),
8926            token(TokenKind::Colon),
8927            token(TokenKind::StringLiteral("two".to_owned())),
8928            token(TokenKind::Pipe),
8929            token(TokenKind::Ident(SmolStr::new("_"))),
8930            token(TokenKind::Colon),
8931            token(TokenKind::StringLiteral("other".to_owned())),
8932            token(TokenKind::End),
8933            token(TokenKind::Eof)
8934        ],
8935        Ok(vec![
8936            Shared::new(Node {
8937                token_id: 0.into(),
8938                expr: Shared::new(Expr::Match(
8939                    Shared::new(Node {
8940                        token_id: 1.into(),
8941                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
8942                            range: Range::default(),
8943                            kind: TokenKind::Ident(SmolStr::new("x")),
8944                            module_id: 1.into()
8945                        })))))
8946                    }),
8947                    smallvec![
8948                        MatchArm {
8949                            pattern: Pattern::Literal(Literal::Number(1.into())),
8950                            guard: None,
8951                            body: Shared::new(Node {
8952                                token_id: 5.into(),
8953                                expr: Shared::new(Expr::Literal(Literal::String("one".to_owned())))
8954                            })
8955                        },
8956                        MatchArm {
8957                            pattern: Pattern::Literal(Literal::Number(2.into())),
8958                            guard: None,
8959                            body: Shared::new(Node {
8960                                token_id: 8.into(),
8961                                expr: Shared::new(Expr::Literal(Literal::String("two".to_owned())))
8962                            })
8963                        },
8964                        MatchArm {
8965                            pattern: Pattern::Wildcard,
8966                            guard: None,
8967                            body: Shared::new(Node {
8968                                token_id: 11.into(),
8969                                expr: Shared::new(Expr::Literal(Literal::String("other".to_owned())))
8970                            })
8971                        }
8972                    ]
8973                ))
8974            })
8975        ]))]
8976    #[case::match_type_pattern(
8977        vec![
8978            token(TokenKind::Match),
8979            token(TokenKind::LParen),
8980            token(TokenKind::Ident(SmolStr::new("value"))),
8981            token(TokenKind::RParen),
8982            token(TokenKind::Colon),
8983            token(TokenKind::Pipe),
8984            token(TokenKind::Colon),
8985            token(TokenKind::Ident(SmolStr::new("string"))),
8986            token(TokenKind::Colon),
8987            token(TokenKind::StringLiteral("is string".to_owned())),
8988            token(TokenKind::Pipe),
8989            token(TokenKind::Colon),
8990            token(TokenKind::Ident(SmolStr::new("number"))),
8991            token(TokenKind::Colon),
8992            token(TokenKind::StringLiteral("is number".to_owned())),
8993            token(TokenKind::End),
8994            token(TokenKind::Eof)
8995        ],
8996        Ok(vec![
8997            Shared::new(Node {
8998                token_id: 0.into(),
8999                expr: Shared::new(Expr::Match(
9000                    Shared::new(Node {
9001                        token_id: 1.into(),
9002                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("value", Some(Shared::new(Token {
9003                            range: Range::default(),
9004                            kind: TokenKind::Ident(SmolStr::new("value")),
9005                            module_id: 1.into()
9006                        })))))
9007                    }),
9008                    smallvec![
9009                        MatchArm {
9010                            pattern: Pattern::Type(Ident::new("string")),
9011                            guard: None,
9012                            body: Shared::new(Node {
9013                                token_id: 5.into(),
9014                                expr: Shared::new(Expr::Literal(Literal::String("is string".to_owned())))
9015                            })
9016                        },
9017                        MatchArm {
9018                            pattern: Pattern::Type(Ident::new("number")),
9019                            guard: None,
9020                            body: Shared::new(Node {
9021                                token_id: 8.into(),
9022                                expr: Shared::new(Expr::Literal(Literal::String("is number".to_owned())))
9023                            })
9024                        }
9025                    ]
9026                ))
9027            })
9028        ]))]
9029    #[case::match_array_pattern(
9030        vec![
9031            token(TokenKind::Match),
9032            token(TokenKind::LParen),
9033            token(TokenKind::Ident(SmolStr::new("arr"))),
9034            token(TokenKind::RParen),
9035            token(TokenKind::Colon),
9036            token(TokenKind::Pipe),
9037            token(TokenKind::LBracket),
9038            token(TokenKind::Ident(SmolStr::new("x"))),
9039            token(TokenKind::Comma),
9040            token(TokenKind::Ident(SmolStr::new("y"))),
9041            token(TokenKind::RBracket),
9042            token(TokenKind::Colon),
9043            token(TokenKind::StringLiteral("two elements".to_owned())),
9044            token(TokenKind::End),
9045            token(TokenKind::Eof)
9046        ],
9047        Ok(vec![
9048            Shared::new(Node {
9049                token_id: 0.into(),
9050                expr: Shared::new(Expr::Match(
9051                    Shared::new(Node {
9052                        token_id: 1.into(),
9053                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(Token {
9054                            range: Range::default(),
9055                            kind: TokenKind::Ident(SmolStr::new("arr")),
9056                            module_id: 1.into()
9057                        })))))
9058                    }),
9059                    smallvec![
9060                        MatchArm {
9061                            pattern: Pattern::Array(vec![
9062                                Pattern::Ident(IdentWithToken::new("x")),
9063                                Pattern::Ident(IdentWithToken::new("y"))
9064                            ]),
9065                            guard: None,
9066                            body: Shared::new(Node {
9067                                token_id: 5.into(),
9068                                expr: Shared::new(Expr::Literal(Literal::String("two elements".to_owned())))
9069                            })
9070                        }
9071                    ]
9072                ))
9073            })
9074        ]))]
9075    #[case::match_array_rest_pattern(
9076        vec![
9077            token(TokenKind::Match),
9078            token(TokenKind::LParen),
9079            token(TokenKind::Ident(SmolStr::new("arr"))),
9080            token(TokenKind::RParen),
9081            token(TokenKind::Colon),
9082            token(TokenKind::Pipe),
9083            token(TokenKind::LBracket),
9084            token(TokenKind::Ident(SmolStr::new("first"))),
9085            token(TokenKind::Comma),
9086            token(TokenKind::DoubleDot),
9087            token(TokenKind::Ident(SmolStr::new("rest"))),
9088            token(TokenKind::RBracket),
9089            token(TokenKind::Colon),
9090            token(TokenKind::Ident(SmolStr::new("first"))),
9091            token(TokenKind::End),
9092            token(TokenKind::Eof)
9093        ],
9094        Ok(vec![
9095            Shared::new(Node {
9096                token_id: 0.into(),
9097                expr: Shared::new(Expr::Match(
9098                    Shared::new(Node {
9099                        token_id: 1.into(),
9100                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("arr", Some(Shared::new(Token {
9101                            range: Range::default(),
9102                            kind: TokenKind::Ident(SmolStr::new("arr")),
9103                            module_id: 1.into()
9104                        })))))
9105                    }),
9106                    smallvec![
9107                        MatchArm {
9108                            pattern: Pattern::ArrayRest(
9109                                vec![Pattern::Ident(IdentWithToken::new("first"))],
9110                                IdentWithToken::new("rest")
9111                            ),
9112                            guard: None,
9113                            body: Shared::new(Node {
9114                                token_id: 5.into(),
9115                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("first", Some(Shared::new(Token {
9116                                    range: Range::default(),
9117                                    kind: TokenKind::Ident(SmolStr::new("first")),
9118                                    module_id: 1.into()
9119                                })))))
9120                            })
9121                        }
9122                    ]
9123                ))
9124            })
9125        ]))]
9126    #[case::match_dict_pattern(
9127        vec![
9128            token(TokenKind::Match),
9129            token(TokenKind::LParen),
9130            token(TokenKind::Ident(SmolStr::new("obj"))),
9131            token(TokenKind::RParen),
9132            token(TokenKind::Colon),
9133            token(TokenKind::Pipe),
9134            token(TokenKind::LBrace),
9135            token(TokenKind::Ident(SmolStr::new("name"))),
9136            token(TokenKind::Comma),
9137            token(TokenKind::Ident(SmolStr::new("age"))),
9138            token(TokenKind::RBrace),
9139            token(TokenKind::Colon),
9140            token(TokenKind::Ident(SmolStr::new("name"))),
9141            token(TokenKind::End),
9142            token(TokenKind::Eof)
9143        ],
9144        Ok(vec![
9145            Shared::new(Node {
9146                token_id: 0.into(),
9147                expr: Shared::new(Expr::Match(
9148                    Shared::new(Node {
9149                        token_id: 1.into(),
9150                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("obj", Some(Shared::new(Token {
9151                            range: Range::default(),
9152                            kind: TokenKind::Ident(SmolStr::new("obj")),
9153                            module_id: 1.into()
9154                        })))))
9155                    }),
9156                    smallvec![
9157                        MatchArm {
9158                            pattern: Pattern::Dict(vec![
9159                                (IdentWithToken::new("name"), Pattern::Ident(IdentWithToken::new("name"))),
9160                                (IdentWithToken::new("age"), Pattern::Ident(IdentWithToken::new("age")))
9161                            ]),
9162                            guard: None,
9163                            body: Shared::new(Node {
9164                                token_id: 5.into(),
9165                                expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("name", Some(Shared::new(Token {
9166                                    range: Range::default(),
9167                                    kind: TokenKind::Ident(SmolStr::new("name")),
9168                                    module_id: 1.into()
9169                                })))))
9170                            })
9171                        }
9172                    ]
9173                ))
9174            })
9175        ]))]
9176    #[case::match_with_guard(
9177        vec![
9178            token(TokenKind::Match),
9179            token(TokenKind::LParen),
9180            token(TokenKind::Ident(SmolStr::new("n"))),
9181            token(TokenKind::RParen),
9182            token(TokenKind::Colon),
9183            token(TokenKind::Pipe),
9184            token(TokenKind::Ident(SmolStr::new("x"))),
9185            token(TokenKind::If),
9186            token(TokenKind::LParen),
9187            token(TokenKind::Ident(SmolStr::new("x"))),
9188            token(TokenKind::Gt),
9189            token(TokenKind::NumberLiteral(0.into())),
9190            token(TokenKind::RParen),
9191            token(TokenKind::Colon),
9192            token(TokenKind::StringLiteral("positive".to_owned())),
9193            token(TokenKind::Pipe),
9194            token(TokenKind::Ident(SmolStr::new("x"))),
9195            token(TokenKind::If),
9196            token(TokenKind::LParen),
9197            token(TokenKind::Ident(SmolStr::new("x"))),
9198            token(TokenKind::Lt),
9199            token(TokenKind::NumberLiteral(0.into())),
9200            token(TokenKind::RParen),
9201            token(TokenKind::Colon),
9202            token(TokenKind::StringLiteral("negative".to_owned())),
9203            token(TokenKind::Pipe),
9204            token(TokenKind::Ident(SmolStr::new("_"))),
9205            token(TokenKind::Colon),
9206            token(TokenKind::StringLiteral("zero".to_owned())),
9207            token(TokenKind::End),
9208            token(TokenKind::Eof)
9209        ],
9210        Ok(vec![
9211            Shared::new(Node {
9212                token_id: 0.into(),
9213                expr: Shared::new(Expr::Match(
9214                    Shared::new(Node {
9215                        token_id: 1.into(),
9216                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("n", Some(Shared::new(Token {
9217                            range: Range::default(),
9218                            kind: TokenKind::Ident(SmolStr::new("n")),
9219                            module_id: 1.into()
9220                        })))))
9221                    }),
9222                    smallvec![
9223                        MatchArm {
9224                            pattern: Pattern::Ident(IdentWithToken::new("x")),
9225                            guard: Some(Shared::new(Node {
9226                                token_id: 5.into(),
9227                                expr: Shared::new(Expr::Call(
9228                                    IdentWithToken::new_with_token(constants::builtins::GT, Some(Shared::new(token(TokenKind::Gt)))),
9229                                    smallvec![
9230                                        Shared::new(Node {
9231                                            token_id: 4.into(),
9232                                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9233                                                range: Range::default(),
9234                                                kind: TokenKind::Ident(SmolStr::new("x")),
9235                                                module_id: 1.into()
9236                                            })))))
9237                                        }),
9238                                        Shared::new(Node {
9239                                            token_id: 6.into(),
9240                                            expr: Shared::new(Expr::Literal(Literal::Number(0.into())))
9241                                        })
9242                                    ]
9243                                ))
9244                            })),
9245                            body: Shared::new(Node {
9246                                token_id: 8.into(),
9247                                expr: Shared::new(Expr::Literal(Literal::String("positive".to_owned())))
9248                            })
9249                        },
9250                        MatchArm {
9251                            pattern: Pattern::Ident(IdentWithToken::new("x")),
9252                            guard: Some(Shared::new(Node {
9253                                token_id: 11.into(),
9254                                expr: Shared::new(Expr::Call(
9255                                    IdentWithToken::new_with_token(constants::builtins::LT, Some(Shared::new(token(TokenKind::Lt)))),
9256                                    smallvec![
9257                                        Shared::new(Node {
9258                                            token_id: 10.into(),
9259                                            expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9260                                                range: Range::default(),
9261                                                kind: TokenKind::Ident(SmolStr::new("x")),
9262                                                module_id: 1.into()
9263                                            })))))
9264                                        }),
9265                                        Shared::new(Node {
9266                                            token_id: 12.into(),
9267                                            expr: Shared::new(Expr::Literal(Literal::Number(0.into())))
9268                                        })
9269                                    ]
9270                                ))
9271                            })),
9272                            body: Shared::new(Node {
9273                                token_id: 14.into(),
9274                                expr: Shared::new(Expr::Literal(Literal::String("negative".to_owned())))
9275                            })
9276                        },
9277                        MatchArm {
9278                            pattern: Pattern::Wildcard,
9279                            guard: None,
9280                            body: Shared::new(Node {
9281                                token_id: 17.into(),
9282                                expr: Shared::new(Expr::Literal(Literal::String("zero".to_owned())))
9283                            })
9284                        }
9285                    ]
9286                ))
9287            })
9288        ]))]
9289    #[case::match_do_end(
9290        vec![
9291            token(TokenKind::Match),
9292            token(TokenKind::LParen),
9293            token(TokenKind::NumberLiteral(2.into())),
9294            token(TokenKind::RParen),
9295            token(TokenKind::Do),
9296            token(TokenKind::Pipe),
9297            token(TokenKind::NumberLiteral(1.into())),
9298            token(TokenKind::Colon),
9299            token(TokenKind::StringLiteral("one".to_owned())),
9300            token(TokenKind::Pipe),
9301            token(TokenKind::NumberLiteral(2.into())),
9302            token(TokenKind::Colon),
9303            token(TokenKind::StringLiteral("two".to_owned())),
9304            token(TokenKind::Pipe),
9305            token(TokenKind::Ident(SmolStr::new("_"))),
9306            token(TokenKind::Colon),
9307            token(TokenKind::StringLiteral("other".to_owned())),
9308            token(TokenKind::End),
9309            token(TokenKind::Eof)
9310        ],
9311        Ok(vec![
9312            Shared::new(Node {
9313                token_id: 0.into(),
9314                expr: Shared::new(Expr::Match(
9315                    Shared::new(Node {
9316                        token_id: 1.into(),
9317                        expr: Shared::new(Expr::Literal(Literal::Number(2.into())))
9318                    }),
9319                    smallvec![
9320                        MatchArm {
9321                            pattern: Pattern::Literal(Literal::Number(1.into())),
9322                            guard: None,
9323                            body: Shared::new(Node {
9324                                token_id: 5.into(),
9325                                expr: Shared::new(Expr::Literal(Literal::String("one".to_owned())))
9326                            })
9327                        },
9328                        MatchArm {
9329                            pattern: Pattern::Literal(Literal::Number(2.into())),
9330                            guard: None,
9331                            body: Shared::new(Node {
9332                                token_id: 8.into(),
9333                                expr: Shared::new(Expr::Literal(Literal::String("two".to_owned())))
9334                            })
9335                        },
9336                        MatchArm {
9337                            pattern: Pattern::Wildcard,
9338                            guard: None,
9339                            body: Shared::new(Node {
9340                                token_id: 11.into(),
9341                                expr: Shared::new(Expr::Literal(Literal::String("other".to_owned())))
9342                            })
9343                        }
9344                    ]
9345                ))
9346            })
9347        ]))]
9348    // --- or-pattern parser tests ---
9349    // Arena allocation order for match(x): COLON | pattern COLON body ...
9350    //   id 0: Match, id 1: Ident("x"), id 2: Colon (consume_colon_or_do)
9351    //   per arm: id N: Pipe, id N+1: Colon, id N+2: body literal
9352    #[case::match_or_two_literal_numbers(
9353        vec![
9354            token(TokenKind::Match),
9355            token(TokenKind::LParen),
9356            token(TokenKind::Ident(SmolStr::new("x"))),
9357            token(TokenKind::RParen),
9358            token(TokenKind::Colon),
9359            token(TokenKind::Pipe),
9360            token(TokenKind::NumberLiteral(1.into())),
9361            token(TokenKind::Or),
9362            token(TokenKind::NumberLiteral(2.into())),
9363            token(TokenKind::Colon),
9364            token(TokenKind::StringLiteral("matched".to_owned())),
9365            token(TokenKind::Pipe),
9366            token(TokenKind::Ident(SmolStr::new("_"))),
9367            token(TokenKind::Colon),
9368            token(TokenKind::StringLiteral("other".to_owned())),
9369            token(TokenKind::End),
9370            token(TokenKind::Eof),
9371        ],
9372        Ok(vec![
9373            Shared::new(Node {
9374                token_id: 0.into(),
9375                expr: Shared::new(Expr::Match(
9376                    Shared::new(Node {
9377                        token_id: 1.into(),
9378                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9379                            range: Range::default(),
9380                            kind: TokenKind::Ident(SmolStr::new("x")),
9381                            module_id: 1.into()
9382                        })))))
9383                    }),
9384                    smallvec![
9385                        MatchArm {
9386                            pattern: Pattern::Or(vec![
9387                                Pattern::Literal(Literal::Number(1.into())),
9388                                Pattern::Literal(Literal::Number(2.into())),
9389                            ]),
9390                            guard: None,
9391                            body: Shared::new(Node {
9392                                token_id: 5.into(),
9393                                expr: Shared::new(Expr::Literal(Literal::String("matched".to_owned())))
9394                            })
9395                        },
9396                        MatchArm {
9397                            pattern: Pattern::Wildcard,
9398                            guard: None,
9399                            body: Shared::new(Node {
9400                                token_id: 8.into(),
9401                                expr: Shared::new(Expr::Literal(Literal::String("other".to_owned())))
9402                            })
9403                        },
9404                    ]
9405                ))
9406            })
9407        ]))]
9408    #[case::match_or_string_literals(
9409        vec![
9410            token(TokenKind::Match),
9411            token(TokenKind::LParen),
9412            token(TokenKind::Ident(SmolStr::new("x"))),
9413            token(TokenKind::RParen),
9414            token(TokenKind::Colon),
9415            token(TokenKind::Pipe),
9416            token(TokenKind::StringLiteral("a".to_owned())),
9417            token(TokenKind::Or),
9418            token(TokenKind::StringLiteral("b".to_owned())),
9419            token(TokenKind::Colon),
9420            token(TokenKind::StringLiteral("matched".to_owned())),
9421            token(TokenKind::Pipe),
9422            token(TokenKind::Ident(SmolStr::new("_"))),
9423            token(TokenKind::Colon),
9424            token(TokenKind::StringLiteral("other".to_owned())),
9425            token(TokenKind::End),
9426            token(TokenKind::Eof),
9427        ],
9428        Ok(vec![
9429            Shared::new(Node {
9430                token_id: 0.into(),
9431                expr: Shared::new(Expr::Match(
9432                    Shared::new(Node {
9433                        token_id: 1.into(),
9434                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9435                            range: Range::default(),
9436                            kind: TokenKind::Ident(SmolStr::new("x")),
9437                            module_id: 1.into()
9438                        })))))
9439                    }),
9440                    smallvec![
9441                        MatchArm {
9442                            pattern: Pattern::Or(vec![
9443                                Pattern::Literal(Literal::String("a".to_owned())),
9444                                Pattern::Literal(Literal::String("b".to_owned())),
9445                            ]),
9446                            guard: None,
9447                            body: Shared::new(Node {
9448                                token_id: 5.into(),
9449                                expr: Shared::new(Expr::Literal(Literal::String("matched".to_owned())))
9450                            })
9451                        },
9452                        MatchArm {
9453                            pattern: Pattern::Wildcard,
9454                            guard: None,
9455                            body: Shared::new(Node {
9456                                token_id: 8.into(),
9457                                expr: Shared::new(Expr::Literal(Literal::String("other".to_owned())))
9458                            })
9459                        },
9460                    ]
9461                ))
9462            })
9463        ]))]
9464    #[case::match_or_type_patterns(
9465        vec![
9466            token(TokenKind::Match),
9467            token(TokenKind::LParen),
9468            token(TokenKind::Ident(SmolStr::new("x"))),
9469            token(TokenKind::RParen),
9470            token(TokenKind::Colon),
9471            token(TokenKind::Pipe),
9472            token(TokenKind::Colon),
9473            token(TokenKind::Ident(SmolStr::new("string"))),
9474            token(TokenKind::Or),
9475            token(TokenKind::Colon),
9476            token(TokenKind::Ident(SmolStr::new("number"))),
9477            token(TokenKind::Colon),
9478            token(TokenKind::StringLiteral("str or num".to_owned())),
9479            token(TokenKind::End),
9480            token(TokenKind::Eof),
9481        ],
9482        Ok(vec![
9483            Shared::new(Node {
9484                token_id: 0.into(),
9485                expr: Shared::new(Expr::Match(
9486                    Shared::new(Node {
9487                        token_id: 1.into(),
9488                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9489                            range: Range::default(),
9490                            kind: TokenKind::Ident(SmolStr::new("x")),
9491                            module_id: 1.into()
9492                        })))))
9493                    }),
9494                    smallvec![
9495                        MatchArm {
9496                            pattern: Pattern::Or(vec![
9497                                Pattern::Type(Ident::new("string")),
9498                                Pattern::Type(Ident::new("number")),
9499                            ]),
9500                            guard: None,
9501                            body: Shared::new(Node {
9502                                token_id: 5.into(),
9503                                expr: Shared::new(Expr::Literal(Literal::String("str or num".to_owned())))
9504                            })
9505                        },
9506                    ]
9507                ))
9508            })
9509        ]))]
9510    #[case::match_or_three_alternatives(
9511        vec![
9512            token(TokenKind::Match),
9513            token(TokenKind::LParen),
9514            token(TokenKind::Ident(SmolStr::new("x"))),
9515            token(TokenKind::RParen),
9516            token(TokenKind::Colon),
9517            token(TokenKind::Pipe),
9518            token(TokenKind::NumberLiteral(1.into())),
9519            token(TokenKind::Or),
9520            token(TokenKind::NumberLiteral(2.into())),
9521            token(TokenKind::Or),
9522            token(TokenKind::NumberLiteral(3.into())),
9523            token(TokenKind::Colon),
9524            token(TokenKind::StringLiteral("matched".to_owned())),
9525            token(TokenKind::Pipe),
9526            token(TokenKind::Ident(SmolStr::new("_"))),
9527            token(TokenKind::Colon),
9528            token(TokenKind::StringLiteral("other".to_owned())),
9529            token(TokenKind::End),
9530            token(TokenKind::Eof),
9531        ],
9532        Ok(vec![
9533            Shared::new(Node {
9534                token_id: 0.into(),
9535                expr: Shared::new(Expr::Match(
9536                    Shared::new(Node {
9537                        token_id: 1.into(),
9538                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9539                            range: Range::default(),
9540                            kind: TokenKind::Ident(SmolStr::new("x")),
9541                            module_id: 1.into()
9542                        })))))
9543                    }),
9544                    smallvec![
9545                        MatchArm {
9546                            pattern: Pattern::Or(vec![
9547                                Pattern::Literal(Literal::Number(1.into())),
9548                                Pattern::Literal(Literal::Number(2.into())),
9549                                Pattern::Literal(Literal::Number(3.into())),
9550                            ]),
9551                            guard: None,
9552                            body: Shared::new(Node {
9553                                token_id: 5.into(),
9554                                expr: Shared::new(Expr::Literal(Literal::String("matched".to_owned())))
9555                            })
9556                        },
9557                        MatchArm {
9558                            pattern: Pattern::Wildcard,
9559                            guard: None,
9560                            body: Shared::new(Node {
9561                                token_id: 8.into(),
9562                                expr: Shared::new(Expr::Literal(Literal::String("other".to_owned())))
9563                            })
9564                        },
9565                    ]
9566                ))
9567            })
9568        ]))]
9569    #[case::match_or_bool_literals(
9570        vec![
9571            token(TokenKind::Match),
9572            token(TokenKind::LParen),
9573            token(TokenKind::Ident(SmolStr::new("x"))),
9574            token(TokenKind::RParen),
9575            token(TokenKind::Colon),
9576            token(TokenKind::Pipe),
9577            token(TokenKind::BoolLiteral(true)),
9578            token(TokenKind::Or),
9579            token(TokenKind::BoolLiteral(false)),
9580            token(TokenKind::Colon),
9581            token(TokenKind::StringLiteral("bool".to_owned())),
9582            token(TokenKind::End),
9583            token(TokenKind::Eof),
9584        ],
9585        Ok(vec![
9586            Shared::new(Node {
9587                token_id: 0.into(),
9588                expr: Shared::new(Expr::Match(
9589                    Shared::new(Node {
9590                        token_id: 1.into(),
9591                        expr: Shared::new(Expr::Ident(IdentWithToken::new_with_token("x", Some(Shared::new(Token {
9592                            range: Range::default(),
9593                            kind: TokenKind::Ident(SmolStr::new("x")),
9594                            module_id: 1.into()
9595                        })))))
9596                    }),
9597                    smallvec![
9598                        MatchArm {
9599                            pattern: Pattern::Or(vec![
9600                                Pattern::Literal(Literal::Bool(true)),
9601                                Pattern::Literal(Literal::Bool(false)),
9602                            ]),
9603                            guard: None,
9604                            body: Shared::new(Node {
9605                                token_id: 5.into(),
9606                                expr: Shared::new(Expr::Literal(Literal::String("bool".to_owned())))
9607                            })
9608                        },
9609                    ]
9610                ))
9611            })
9612        ]))]
9613    fn test_parse_match(#[case] input: Vec<Token>, #[case] expected: Result<Program, SyntaxError>) {
9614        let mut arena = Arena::new(10);
9615        let tokens: Vec<Shared<Token>> = input.into_iter().map(Shared::new).collect();
9616        let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
9617        assert_eq!(result, expected);
9618    }
9619
9620    #[rstest]
9621    #[case::expr_literal(
9622        vec![
9623            lexer::token::StringSegment::Text("Value: ".to_string(), Range::default()),
9624            lexer::token::StringSegment::Expr("42".into(), Range::default()),
9625        ],
9626        2,
9627        |segments: &[StringSegment]| {
9628            matches!(&segments[0], StringSegment::Text(s) if s == "Value: ") &&
9629            matches!(&segments[1], StringSegment::Expr(node) if matches!(&*node.expr, Expr::Literal(Literal::Number(_))))
9630        }
9631    )]
9632    #[case::expr_string(
9633        vec![
9634            lexer::token::StringSegment::Text("Result: ".to_string(), Range::default()),
9635            lexer::token::StringSegment::Expr("\"hello\"".into(), Range::default()),
9636        ],
9637        2,
9638        |segments: &[StringSegment]| {
9639            matches!(&segments[0], StringSegment::Text(s) if s == "Result: ") &&
9640            matches!(&segments[1], StringSegment::Expr(node) if matches!(&*node.expr, Expr::Literal(Literal::String(s)) if s == "hello"))
9641        }
9642    )]
9643    #[case::expr_call(
9644        vec![
9645            lexer::token::StringSegment::Text("Result: ".to_string(), Range::default()),
9646            lexer::token::StringSegment::Expr("add(1, 2)".into(), Range::default()),
9647        ],
9648        2,
9649        |segments: &[StringSegment]| {
9650            matches!(&segments[0], StringSegment::Text(s) if s == "Result: ") &&
9651            if let StringSegment::Expr(node) = &segments[1] {
9652                if let Expr::Call(ident, args) = &*node.expr {
9653                    ident.name == "add".into() && args.len() == 2
9654                } else {
9655                    false
9656                }
9657            } else {
9658                false
9659            }
9660        }
9661    )]
9662    #[case::expr_self(
9663        vec![
9664            lexer::token::StringSegment::Text("Value: ".to_string(), Range::default()),
9665            lexer::token::StringSegment::Expr("self".into(), Range::default()),
9666        ],
9667        2,
9668        |segments: &[StringSegment]| {
9669            matches!(&segments[0], StringSegment::Text(s) if s == "Value: ") &&
9670            matches!(&segments[1], StringSegment::Self_)
9671        }
9672    )]
9673    #[case::expr_env(
9674        vec![
9675            lexer::token::StringSegment::Text("Env: ".to_string(), Range::default()),
9676            lexer::token::StringSegment::Expr("$MQ_TEST_INTERPOLATION".into(), Range::default()),
9677        ],
9678        2,
9679        |segments: &[StringSegment]| {
9680            unsafe { std::env::set_var("MQ_TEST_INTERPOLATION", "test_value") };
9681            matches!(&segments[0], StringSegment::Text(s) if s == "Env: ") &&
9682            matches!(&segments[1], StringSegment::Env(var) if var == "MQ_TEST_INTERPOLATION")
9683        }
9684    )]
9685    #[case::multiple_exprs(
9686        vec![
9687            lexer::token::StringSegment::Text("A: ".to_string(), Range::default()),
9688            lexer::token::StringSegment::Expr("1".into(), Range::default()),
9689            lexer::token::StringSegment::Text(", B: ".to_string(), Range::default()),
9690            lexer::token::StringSegment::Expr("2".into(), Range::default()),
9691        ],
9692        4,
9693        |segments: &[StringSegment]| {
9694            matches!(&segments[0], StringSegment::Text(s) if s == "A: ") &&
9695            matches!(&segments[1], StringSegment::Expr(_)) &&
9696            matches!(&segments[2], StringSegment::Text(s) if s == ", B: ") &&
9697            matches!(&segments[3], StringSegment::Expr(_))
9698        }
9699    )]
9700    #[case::mixed_segments(
9701        vec![
9702            lexer::token::StringSegment::Text("Literal, ".to_string(), Range::default()),
9703            lexer::token::StringSegment::Expr("self".into(), Range::default()),
9704            lexer::token::StringSegment::Text(", ".to_string(), Range::default()),
9705            lexer::token::StringSegment::Expr("$MQ_MIXED_TEST".into(), Range::default()),
9706            lexer::token::StringSegment::Text(", ".to_string(), Range::default()),
9707            lexer::token::StringSegment::Expr("42".into(), Range::default()),
9708        ],
9709        6,
9710        |segments: &[StringSegment]| {
9711            unsafe { std::env::set_var("MQ_MIXED_TEST", "env_value") };
9712            matches!(&segments[0], StringSegment::Text(s) if s == "Literal, ") &&
9713            matches!(&segments[1], StringSegment::Self_) &&
9714            matches!(&segments[2], StringSegment::Text(s) if s == ", ") &&
9715            matches!(&segments[3], StringSegment::Env(var) if var == "MQ_MIXED_TEST") &&
9716            matches!(&segments[4], StringSegment::Text(s) if s == ", ") &&
9717            matches!(&segments[5], StringSegment::Expr(_))
9718        }
9719    )]
9720    #[case::expr_bool(
9721        vec![
9722            lexer::token::StringSegment::Text("Bool: ".to_string(), Range::default()),
9723            lexer::token::StringSegment::Expr("true".into(), Range::default()),
9724        ],
9725        2,
9726        |segments: &[StringSegment]| {
9727            matches!(&segments[0], StringSegment::Text(s) if s == "Bool: ") &&
9728            matches!(&segments[1], StringSegment::Expr(node) if matches!(&*node.expr, Expr::Literal(Literal::Bool(true))))
9729        }
9730    )]
9731    fn test_parse_interpolated_string_with_expr(
9732        #[case] input_segments: Vec<lexer::token::StringSegment>,
9733        #[case] expected_len: usize,
9734        #[case] validator: fn(&[StringSegment]) -> bool,
9735    ) {
9736        let mut arena = Arena::new(10);
9737        let tokens = [
9738            Shared::new(Token {
9739                range: Range::default(),
9740                kind: TokenKind::InterpolatedString(input_segments),
9741                module_id: 1.into(),
9742            }),
9743            Shared::new(Token {
9744                range: Range::default(),
9745                kind: TokenKind::Eof,
9746                module_id: 1.into(),
9747            }),
9748        ];
9749
9750        let result = Parser::new(tokens.iter(), &mut arena, Module::TOP_LEVEL_MODULE_ID).parse();
9751
9752        match result {
9753            Ok(program) => {
9754                assert_eq!(program.len(), 1);
9755                if let Expr::InterpolatedString(segments) = &*program[0].expr {
9756                    assert_eq!(segments.len(), expected_len);
9757                    assert!(validator(segments), "Validator failed for segments");
9758                } else {
9759                    panic!("Expected InterpolatedString, got {:?}", program[0].expr);
9760                }
9761            }
9762            Err(err) => panic!("Parse error: {:?}", err),
9763        }
9764    }
9765}