Skip to main content

ion_core/
parser.rs

1use crate::ast::*;
2use crate::error::IonError;
3use crate::token::{SpannedToken, Token};
4
5/// Result of parsing: partial AST + accumulated errors.
6pub struct ParseOutput {
7    pub program: Program,
8    pub errors: Vec<IonError>,
9}
10
11pub struct Parser {
12    tokens: Vec<SpannedToken>,
13    pos: usize,
14    errors: Vec<IonError>,
15}
16
17impl Parser {
18    pub fn new(tokens: Vec<SpannedToken>) -> Self {
19        Self {
20            tokens,
21            pos: 0,
22            errors: Vec::new(),
23        }
24    }
25
26    /// Parse the full program, recovering from errors at statement boundaries.
27    /// Returns a `ParseOutput` containing both the partial AST and any errors.
28    pub fn parse_program_recovering(&mut self) -> ParseOutput {
29        let mut stmts = Vec::new();
30        while !self.is_at_end() {
31            let before = self.pos;
32            match self.parse_stmt() {
33                Ok(stmt) => stmts.push(stmt),
34                Err(e) => {
35                    self.errors.push(e);
36                    self.synchronize();
37                    // If no progress was made, force advance to prevent infinite loop
38                    if self.pos == before {
39                        self.advance();
40                    }
41                }
42            }
43        }
44        ParseOutput {
45            program: Program { stmts },
46            errors: std::mem::take(&mut self.errors),
47        }
48    }
49
50    /// Parse the full program, returning an error if any parse errors occurred.
51    /// For multi-error reporting, use `parse_program_recovering` instead.
52    pub fn parse_program(&mut self) -> Result<Program, IonError> {
53        let output = self.parse_program_recovering();
54        if output.errors.is_empty() {
55            Ok(output.program)
56        } else {
57            let mut errors = output.errors;
58            let mut first = errors.remove(0);
59            first.additional = errors;
60            Err(first)
61        }
62    }
63
64    /// Advance past the current error to the next statement boundary.
65    /// Respects brace nesting — stops at `}` that closes the current block.
66    fn synchronize(&mut self) {
67        let mut brace_depth = 0i32;
68        while !self.is_at_end() {
69            // If we just passed a semicolon at the same brace depth, we're at a new statement
70            if self.pos > 0 && brace_depth == 0 {
71                if let Token::Semicolon = &self.tokens[self.pos - 1].token {
72                    return;
73                }
74            }
75            match self.peek() {
76                // Track brace depth to avoid skipping past a closing }
77                Token::LBrace => {
78                    brace_depth += 1;
79                    self.advance();
80                }
81                Token::RBrace => {
82                    if brace_depth > 0 {
83                        brace_depth -= 1;
84                        self.advance();
85                    } else {
86                        // This } closes the enclosing block — stop before it
87                        return;
88                    }
89                }
90                // Stop at tokens that typically begin a new statement (if at top level)
91                Token::Let | Token::Fn | Token::For | Token::While | Token::If
92                | Token::Return | Token::Match | Token::Loop | Token::Try
93                | Token::Break | Token::Continue | Token::Use
94                    if brace_depth == 0 =>
95                {
96                    return;
97                }
98                _ => {
99                    self.advance();
100                }
101            }
102        }
103    }
104
105    // --- Helpers ---
106
107    fn peek(&self) -> &Token {
108        &self.tokens[self.pos].token
109    }
110
111    fn span(&self) -> Span {
112        let t = &self.tokens[self.pos];
113        Span {
114            line: t.line,
115            col: t.col,
116        }
117    }
118
119    fn prev_span(&self) -> Span {
120        if self.pos > 0 {
121            let t = &self.tokens[self.pos - 1];
122            Span {
123                line: t.line,
124                col: t.col,
125            }
126        } else {
127            self.span()
128        }
129    }
130
131    fn advance(&mut self) -> &SpannedToken {
132        let tok = &self.tokens[self.pos];
133        if !self.is_at_end() {
134            self.pos += 1;
135        }
136        tok
137    }
138
139    fn is_at_end(&self) -> bool {
140        matches!(self.peek(), Token::Eof)
141    }
142
143    fn check(&self, token: &Token) -> bool {
144        std::mem::discriminant(self.peek()) == std::mem::discriminant(token)
145    }
146
147    fn eat(&mut self, expected: &Token) -> Result<(), IonError> {
148        if self.check(expected) {
149            self.advance();
150            Ok(())
151        } else {
152            let s = self.span();
153            Err(IonError::parse(
154                format!(
155                    "{}{:?}{}{:?}",
156                    ion_str!("expected "),
157                    expected,
158                    ion_str!(", found "),
159                    self.peek()
160                ),
161                s.line,
162                s.col,
163            ))
164        }
165    }
166
167    fn eat_ident(&mut self) -> Result<String, IonError> {
168        if let Token::Ident(name) = self.peek().clone() {
169            self.advance();
170            Ok(name)
171        } else {
172            let s = self.span();
173            Err(IonError::parse(
174                format!(
175                    "{}{:?}",
176                    ion_str!("expected identifier, found "),
177                    self.peek()
178                ),
179                s.line,
180                s.col,
181            ))
182        }
183    }
184
185    // --- Statement Parsing ---
186
187    fn parse_stmt(&mut self) -> Result<Stmt, IonError> {
188        let span = self.span();
189        match self.peek().clone() {
190            Token::Let => self.parse_let_stmt(),
191            Token::Fn => self.parse_fn_decl(),
192            Token::For => self.parse_for_stmt(),
193            Token::While => self.parse_while_stmt(),
194            Token::Loop => self.parse_loop_stmt(),
195            Token::Break => self.parse_break_stmt(),
196            Token::Continue => {
197                self.advance();
198                self.eat(&Token::Semicolon)?;
199                Ok(Stmt {
200                    kind: StmtKind::Continue,
201                    span,
202                })
203            }
204            Token::Return => self.parse_return_stmt(),
205            Token::Use => self.parse_use_stmt(),
206            _ => self.parse_expr_or_assign_stmt(),
207        }
208    }
209
210    fn parse_let_stmt(&mut self) -> Result<Stmt, IonError> {
211        let span = self.span();
212        self.eat(&Token::Let)?;
213        let mutable = if self.check(&Token::Mut) {
214            self.advance();
215            true
216        } else {
217            false
218        };
219        let pattern = self.parse_pattern()?;
220        let type_ann = if self.check(&Token::Colon) {
221            self.advance();
222            Some(self.parse_type_ann()?)
223        } else {
224            None
225        };
226        self.eat(&Token::Eq)?;
227        let value = self.parse_expr()?;
228        self.eat(&Token::Semicolon)?;
229        Ok(Stmt {
230            kind: StmtKind::Let {
231                mutable,
232                pattern,
233                type_ann,
234                value,
235            },
236            span,
237        })
238    }
239
240    fn parse_type_ann(&mut self) -> Result<TypeAnn, IonError> {
241        // `fn` is a keyword token, so eat it specially
242        if self.check(&Token::Fn) {
243            self.advance();
244            return Ok(TypeAnn::Simple("fn".to_string()));
245        }
246        let name = self.eat_ident()?;
247        match name.as_str() {
248            "Option" => {
249                self.eat(&Token::Lt)?;
250                let inner = self.parse_type_ann()?;
251                self.eat(&Token::Gt)?;
252                Ok(TypeAnn::Option(Box::new(inner)))
253            }
254            "Result" => {
255                self.eat(&Token::Lt)?;
256                let ok = self.parse_type_ann()?;
257                self.eat(&Token::Comma)?;
258                let err = self.parse_type_ann()?;
259                self.eat(&Token::Gt)?;
260                Ok(TypeAnn::Result(Box::new(ok), Box::new(err)))
261            }
262            "list" => {
263                if self.check(&Token::Lt) {
264                    self.advance();
265                    let inner = self.parse_type_ann()?;
266                    self.eat(&Token::Gt)?;
267                    Ok(TypeAnn::List(Box::new(inner)))
268                } else {
269                    Ok(TypeAnn::Simple(name))
270                }
271            }
272            "dict" => {
273                if self.check(&Token::Lt) {
274                    self.advance();
275                    let key = self.parse_type_ann()?;
276                    self.eat(&Token::Comma)?;
277                    let val = self.parse_type_ann()?;
278                    self.eat(&Token::Gt)?;
279                    Ok(TypeAnn::Dict(Box::new(key), Box::new(val)))
280                } else {
281                    Ok(TypeAnn::Simple(name))
282                }
283            }
284            _ => Ok(TypeAnn::Simple(name)),
285        }
286    }
287
288    fn parse_fn_decl(&mut self) -> Result<Stmt, IonError> {
289        let span = self.span();
290        self.eat(&Token::Fn)?;
291        let name = self.eat_ident()?;
292        self.eat(&Token::LParen)?;
293        let params = self.parse_params()?;
294        self.eat(&Token::RParen)?;
295        self.eat(&Token::LBrace)?;
296        let body = self.parse_block_stmts()?;
297        self.eat(&Token::RBrace)?;
298        Ok(Stmt {
299            kind: StmtKind::FnDecl { name, params, body },
300            span,
301        })
302    }
303
304    fn parse_params(&mut self) -> Result<Vec<Param>, IonError> {
305        let mut params = Vec::new();
306        while !self.check(&Token::RParen) {
307            let name = self.eat_ident()?;
308            let default = if self.check(&Token::Eq) {
309                self.advance();
310                Some(self.parse_expr()?)
311            } else {
312                None
313            };
314            params.push(Param { name, default });
315            if !self.check(&Token::RParen) {
316                self.eat(&Token::Comma)?;
317            }
318        }
319        Ok(params)
320    }
321
322    fn parse_for_stmt(&mut self) -> Result<Stmt, IonError> {
323        let span = self.span();
324        self.eat(&Token::For)?;
325        let pattern = self.parse_pattern()?;
326        self.eat(&Token::In)?;
327        let iter = self.parse_expr()?;
328        self.eat(&Token::LBrace)?;
329        let body = self.parse_block_stmts()?;
330        self.eat(&Token::RBrace)?;
331        Ok(Stmt {
332            kind: StmtKind::For {
333                pattern,
334                iter,
335                body,
336            },
337            span,
338        })
339    }
340
341    fn parse_while_stmt(&mut self) -> Result<Stmt, IonError> {
342        let span = self.span();
343        self.eat(&Token::While)?;
344        // while let ...
345        if self.check(&Token::Let) {
346            self.advance();
347            let pattern = self.parse_pattern()?;
348            self.eat(&Token::Eq)?;
349            let expr = self.parse_expr()?;
350            self.eat(&Token::LBrace)?;
351            let body = self.parse_block_stmts()?;
352            self.eat(&Token::RBrace)?;
353            return Ok(Stmt {
354                kind: StmtKind::WhileLet {
355                    pattern,
356                    expr,
357                    body,
358                },
359                span,
360            });
361        }
362        let cond = self.parse_expr()?;
363        self.eat(&Token::LBrace)?;
364        let body = self.parse_block_stmts()?;
365        self.eat(&Token::RBrace)?;
366        Ok(Stmt {
367            kind: StmtKind::While { cond, body },
368            span,
369        })
370    }
371
372    fn parse_loop_stmt(&mut self) -> Result<Stmt, IonError> {
373        let span = self.span();
374        self.eat(&Token::Loop)?;
375        self.eat(&Token::LBrace)?;
376        let body = self.parse_block_stmts()?;
377        self.eat(&Token::RBrace)?;
378        Ok(Stmt {
379            kind: StmtKind::Loop { body },
380            span,
381        })
382    }
383
384    fn parse_break_stmt(&mut self) -> Result<Stmt, IonError> {
385        let span = self.span();
386        self.eat(&Token::Break)?;
387        let value = if self.check(&Token::Semicolon) {
388            None
389        } else {
390            Some(self.parse_expr()?)
391        };
392        self.eat(&Token::Semicolon)?;
393        Ok(Stmt {
394            kind: StmtKind::Break { value },
395            span,
396        })
397    }
398
399    fn parse_return_stmt(&mut self) -> Result<Stmt, IonError> {
400        let span = self.span();
401        self.eat(&Token::Return)?;
402        let value = if self.check(&Token::Semicolon) {
403            None
404        } else {
405            Some(self.parse_expr()?)
406        };
407        self.eat(&Token::Semicolon)?;
408        Ok(Stmt {
409            kind: StmtKind::Return { value },
410            span,
411        })
412    }
413
414    /// Parse `use path::name;` or `use path::{a, b};` or `use path::*;`
415    fn parse_use_stmt(&mut self) -> Result<Stmt, IonError> {
416        let span = self.span();
417        self.eat(&Token::Use)?;
418
419        // Parse the module path: `a::b::...`
420        let mut path = Vec::new();
421        path.push(self.eat_ident()?);
422        while self.check(&Token::ColonColon) {
423            self.advance();
424            // Check what follows ::
425            if self.check(&Token::Star) {
426                // use path::*
427                self.advance();
428                self.eat(&Token::Semicolon)?;
429                return Ok(Stmt {
430                    kind: StmtKind::Use {
431                        path,
432                        imports: UseImports::Glob,
433                    },
434                    span,
435                });
436            } else if self.check(&Token::LBrace) {
437                // use path::{a, b, c}
438                self.advance();
439                let mut names = Vec::new();
440                while !self.check(&Token::RBrace) && !self.is_at_end() {
441                    names.push(self.eat_ident()?);
442                    if !self.check(&Token::RBrace) {
443                        self.eat(&Token::Comma)?;
444                    }
445                }
446                self.eat(&Token::RBrace)?;
447                self.eat(&Token::Semicolon)?;
448                return Ok(Stmt {
449                    kind: StmtKind::Use {
450                        path,
451                        imports: UseImports::Names(names),
452                    },
453                    span,
454                });
455            } else {
456                // More path segments or final single name
457                path.push(self.eat_ident()?);
458            }
459        }
460
461        // `use path::name;` — last segment is the imported name
462        self.eat(&Token::Semicolon)?;
463        if path.len() < 2 {
464            return Err(IonError::parse(
465                ion_str!("use statement requires at least module::name"),
466                span.line,
467                span.col,
468            ));
469        }
470        let name = path.pop().unwrap();
471        Ok(Stmt {
472            kind: StmtKind::Use {
473                path,
474                imports: UseImports::Single(name),
475            },
476            span,
477        })
478    }
479
480    fn parse_expr_or_assign_stmt(&mut self) -> Result<Stmt, IonError> {
481        let span = self.span();
482        let expr = self.parse_expr()?;
483
484        // Check for assignment
485        let assign_op = match self.peek() {
486            Token::Eq => Some(AssignOp::Eq),
487            Token::PlusEq => Some(AssignOp::PlusEq),
488            Token::MinusEq => Some(AssignOp::MinusEq),
489            Token::StarEq => Some(AssignOp::StarEq),
490            Token::SlashEq => Some(AssignOp::SlashEq),
491            _ => None,
492        };
493
494        if let Some(op) = assign_op {
495            self.advance();
496            let target = self.expr_to_assign_target(&expr)?;
497            let value = self.parse_expr()?;
498            self.eat(&Token::Semicolon)?;
499            Ok(Stmt {
500                kind: StmtKind::Assign { target, op, value },
501                span,
502            })
503        } else {
504            let has_semi = self.check(&Token::Semicolon);
505            if has_semi {
506                self.advance();
507            }
508            Ok(Stmt {
509                kind: StmtKind::ExprStmt { expr, has_semi },
510                span,
511            })
512        }
513    }
514
515    fn expr_to_assign_target(&self, expr: &Expr) -> Result<AssignTarget, IonError> {
516        match &expr.kind {
517            ExprKind::Ident(name) => Ok(AssignTarget::Ident(name.clone())),
518            ExprKind::Index { expr, index } => Ok(AssignTarget::Index(expr.clone(), index.clone())),
519            ExprKind::FieldAccess { expr, field } => {
520                Ok(AssignTarget::Field(expr.clone(), field.clone()))
521            }
522            _ => Err(IonError::parse(
523                ion_str!("invalid assignment target").to_string(),
524                expr.span.line,
525                expr.span.col,
526            )),
527        }
528    }
529
530    fn parse_block_stmts(&mut self) -> Result<Vec<Stmt>, IonError> {
531        let mut stmts = Vec::new();
532        while !self.check(&Token::RBrace) && !self.is_at_end() {
533            let before = self.pos;
534            match self.parse_stmt() {
535                Ok(stmt) => stmts.push(stmt),
536                Err(e) => {
537                    self.errors.push(e);
538                    self.synchronize();
539                    // If no progress was made, force advance to prevent infinite loop
540                    if self.pos == before {
541                        self.advance();
542                    }
543                }
544            }
545        }
546        Ok(stmts)
547    }
548
549    // --- Expression Parsing (Pratt) ---
550
551    fn parse_expr(&mut self) -> Result<Expr, IonError> {
552        self.parse_pipe()
553    }
554
555    fn parse_pipe(&mut self) -> Result<Expr, IonError> {
556        let mut left = self.parse_or()?;
557        while self.check(&Token::Pipe) {
558            self.advance();
559            let right = self.parse_or()?;
560            let span = left.span;
561            left = Expr {
562                kind: ExprKind::PipeOp {
563                    left: Box::new(left),
564                    right: Box::new(right),
565                },
566                span,
567            };
568        }
569        Ok(left)
570    }
571
572    fn parse_or(&mut self) -> Result<Expr, IonError> {
573        let mut left = self.parse_and()?;
574        while self.check(&Token::Or) {
575            self.advance();
576            let right = self.parse_and()?;
577            let span = left.span;
578            left = Expr {
579                kind: ExprKind::BinOp {
580                    left: Box::new(left),
581                    op: BinOp::Or,
582                    right: Box::new(right),
583                },
584                span,
585            };
586        }
587        Ok(left)
588    }
589
590    fn parse_and(&mut self) -> Result<Expr, IonError> {
591        let mut left = self.parse_bitwise_or()?;
592        while self.check(&Token::And) {
593            self.advance();
594            let right = self.parse_bitwise_or()?;
595            let span = left.span;
596            left = Expr {
597                kind: ExprKind::BinOp {
598                    left: Box::new(left),
599                    op: BinOp::And,
600                    right: Box::new(right),
601                },
602                span,
603            };
604        }
605        Ok(left)
606    }
607
608    fn parse_bitwise_or(&mut self) -> Result<Expr, IonError> {
609        let mut left = self.parse_bitwise_xor()?;
610        while self.check(&Token::PipeSym) {
611            self.advance();
612            let right = self.parse_bitwise_xor()?;
613            let span = left.span;
614            left = Expr {
615                kind: ExprKind::BinOp {
616                    left: Box::new(left),
617                    op: BinOp::BitOr,
618                    right: Box::new(right),
619                },
620                span,
621            };
622        }
623        Ok(left)
624    }
625
626    fn parse_bitwise_xor(&mut self) -> Result<Expr, IonError> {
627        let mut left = self.parse_bitwise_and()?;
628        while self.check(&Token::Caret) {
629            self.advance();
630            let right = self.parse_bitwise_and()?;
631            let span = left.span;
632            left = Expr {
633                kind: ExprKind::BinOp {
634                    left: Box::new(left),
635                    op: BinOp::BitXor,
636                    right: Box::new(right),
637                },
638                span,
639            };
640        }
641        Ok(left)
642    }
643
644    fn parse_bitwise_and(&mut self) -> Result<Expr, IonError> {
645        let mut left = self.parse_equality()?;
646        while self.check(&Token::Ampersand) {
647            self.advance();
648            let right = self.parse_equality()?;
649            let span = left.span;
650            left = Expr {
651                kind: ExprKind::BinOp {
652                    left: Box::new(left),
653                    op: BinOp::BitAnd,
654                    right: Box::new(right),
655                },
656                span,
657            };
658        }
659        Ok(left)
660    }
661
662    fn parse_equality(&mut self) -> Result<Expr, IonError> {
663        let mut left = self.parse_comparison()?;
664        loop {
665            let op = match self.peek() {
666                Token::EqEq => BinOp::Eq,
667                Token::BangEq => BinOp::Ne,
668                _ => break,
669            };
670            self.advance();
671            let right = self.parse_comparison()?;
672            let span = left.span;
673            left = Expr {
674                kind: ExprKind::BinOp {
675                    left: Box::new(left),
676                    op,
677                    right: Box::new(right),
678                },
679                span,
680            };
681        }
682        Ok(left)
683    }
684
685    fn parse_comparison(&mut self) -> Result<Expr, IonError> {
686        let mut left = self.parse_shift()?;
687        loop {
688            let op = match self.peek() {
689                Token::Lt => BinOp::Lt,
690                Token::Gt => BinOp::Gt,
691                Token::LtEq => BinOp::Le,
692                Token::GtEq => BinOp::Ge,
693                _ => break,
694            };
695            self.advance();
696            let right = self.parse_shift()?;
697            let span = left.span;
698            left = Expr {
699                kind: ExprKind::BinOp {
700                    left: Box::new(left),
701                    op,
702                    right: Box::new(right),
703                },
704                span,
705            };
706        }
707        Ok(left)
708    }
709
710    fn parse_shift(&mut self) -> Result<Expr, IonError> {
711        let mut left = self.parse_range()?;
712        loop {
713            let op = match self.peek() {
714                Token::Shl => BinOp::Shl,
715                Token::Shr => BinOp::Shr,
716                _ => break,
717            };
718            self.advance();
719            let right = self.parse_range()?;
720            let span = left.span;
721            left = Expr {
722                kind: ExprKind::BinOp {
723                    left: Box::new(left),
724                    op,
725                    right: Box::new(right),
726                },
727                span,
728            };
729        }
730        Ok(left)
731    }
732
733    fn parse_range(&mut self) -> Result<Expr, IonError> {
734        let left = self.parse_addition()?;
735        match self.peek() {
736            Token::DotDot => {
737                self.advance();
738                let right = self.parse_addition()?;
739                let span = left.span;
740                Ok(Expr {
741                    kind: ExprKind::Range {
742                        start: Box::new(left),
743                        end: Box::new(right),
744                        inclusive: false,
745                    },
746                    span,
747                })
748            }
749            Token::DotDotEq => {
750                self.advance();
751                let right = self.parse_addition()?;
752                let span = left.span;
753                Ok(Expr {
754                    kind: ExprKind::Range {
755                        start: Box::new(left),
756                        end: Box::new(right),
757                        inclusive: true,
758                    },
759                    span,
760                })
761            }
762            _ => Ok(left),
763        }
764    }
765
766    fn parse_addition(&mut self) -> Result<Expr, IonError> {
767        let mut left = self.parse_multiplication()?;
768        loop {
769            let op = match self.peek() {
770                Token::Plus => BinOp::Add,
771                Token::Minus => BinOp::Sub,
772                _ => break,
773            };
774            self.advance();
775            let right = self.parse_multiplication()?;
776            let span = left.span;
777            left = Expr {
778                kind: ExprKind::BinOp {
779                    left: Box::new(left),
780                    op,
781                    right: Box::new(right),
782                },
783                span,
784            };
785        }
786        Ok(left)
787    }
788
789    fn parse_multiplication(&mut self) -> Result<Expr, IonError> {
790        let mut left = self.parse_unary()?;
791        loop {
792            let op = match self.peek() {
793                Token::Star => BinOp::Mul,
794                Token::Slash => BinOp::Div,
795                Token::Percent => BinOp::Mod,
796                _ => break,
797            };
798            self.advance();
799            let right = self.parse_unary()?;
800            let span = left.span;
801            left = Expr {
802                kind: ExprKind::BinOp {
803                    left: Box::new(left),
804                    op,
805                    right: Box::new(right),
806                },
807                span,
808            };
809        }
810        Ok(left)
811    }
812
813    fn parse_unary(&mut self) -> Result<Expr, IonError> {
814        let span = self.span();
815        match self.peek() {
816            Token::Minus => {
817                self.advance();
818                let expr = self.parse_unary()?;
819                Ok(Expr {
820                    kind: ExprKind::UnaryOp {
821                        op: UnaryOp::Neg,
822                        expr: Box::new(expr),
823                    },
824                    span,
825                })
826            }
827            Token::Bang => {
828                self.advance();
829                let expr = self.parse_unary()?;
830                Ok(Expr {
831                    kind: ExprKind::UnaryOp {
832                        op: UnaryOp::Not,
833                        expr: Box::new(expr),
834                    },
835                    span,
836                })
837            }
838            _ => self.parse_postfix(),
839        }
840    }
841
842    fn parse_postfix(&mut self) -> Result<Expr, IonError> {
843        let mut expr = self.parse_primary()?;
844
845        loop {
846            match self.peek() {
847                Token::Question => {
848                    self.advance();
849                    let span = expr.span;
850                    expr = Expr {
851                        kind: ExprKind::Try(Box::new(expr)),
852                        span,
853                    };
854                }
855                Token::Dot => {
856                    self.advance();
857                    // .await is special syntax
858                    if self.check(&Token::Await) {
859                        self.advance();
860                        let span = expr.span;
861                        expr = Expr {
862                            kind: ExprKind::AwaitExpr(Box::new(expr)),
863                            span,
864                        };
865                        continue;
866                    }
867                    let field = self.eat_ident()?;
868                    if self.check(&Token::LParen) {
869                        // Method call
870                        self.advance();
871                        let args = self.parse_call_args()?;
872                        self.eat(&Token::RParen)?;
873                        let span = expr.span;
874                        expr = Expr {
875                            kind: ExprKind::MethodCall {
876                                expr: Box::new(expr),
877                                method: field,
878                                args,
879                            },
880                            span,
881                        };
882                    } else {
883                        let span = expr.span;
884                        expr = Expr {
885                            kind: ExprKind::FieldAccess {
886                                expr: Box::new(expr),
887                                field,
888                            },
889                            span,
890                        };
891                    }
892                }
893                Token::LBracket => {
894                    self.advance();
895                    let span = expr.span;
896                    // Check for [..end] or [..=end] or [..]
897                    if self.check(&Token::DotDot) || self.check(&Token::DotDotEq) {
898                        let inclusive = self.check(&Token::DotDotEq);
899                        self.advance();
900                        let end = if self.check(&Token::RBracket) {
901                            None
902                        } else {
903                            Some(Box::new(self.parse_expr()?))
904                        };
905                        self.eat(&Token::RBracket)?;
906                        expr = Expr {
907                            kind: ExprKind::Slice {
908                                expr: Box::new(expr),
909                                start: None,
910                                end,
911                                inclusive,
912                            },
913                            span,
914                        };
915                        continue;
916                    }
917                    // Parse index/start using parse_addition (stops before ..)
918                    let first = self.parse_addition()?;
919                    if self.check(&Token::DotDot) || self.check(&Token::DotDotEq) {
920                        let inclusive = self.check(&Token::DotDotEq);
921                        self.advance();
922                        let end = if self.check(&Token::RBracket) {
923                            None
924                        } else {
925                            Some(Box::new(self.parse_expr()?))
926                        };
927                        self.eat(&Token::RBracket)?;
928                        expr = Expr {
929                            kind: ExprKind::Slice {
930                                expr: Box::new(expr),
931                                start: Some(Box::new(first)),
932                                end,
933                                inclusive,
934                            },
935                            span,
936                        };
937                    } else {
938                        self.eat(&Token::RBracket)?;
939                        expr = Expr {
940                            kind: ExprKind::Index {
941                                expr: Box::new(expr),
942                                index: Box::new(first),
943                            },
944                            span,
945                        };
946                    }
947                }
948                Token::LParen => {
949                    // Check if this is truly a call (the expr must be callable)
950                    self.advance();
951                    let args = self.parse_call_args()?;
952                    self.eat(&Token::RParen)?;
953                    let span = expr.span;
954                    expr = Expr {
955                        kind: ExprKind::Call {
956                            func: Box::new(expr),
957                            args,
958                        },
959                        span,
960                    };
961                }
962                _ => break,
963            }
964        }
965        Ok(expr)
966    }
967
968    fn parse_call_args(&mut self) -> Result<Vec<CallArg>, IonError> {
969        let mut args = Vec::new();
970        while !self.check(&Token::RParen) && !self.is_at_end() {
971            // Check for named argument: `name: value`
972            let arg = if let Token::Ident(name) = self.peek().clone() {
973                if self.tokens.get(self.pos + 1).map(|t| &t.token) == Some(&Token::Colon) {
974                    let name = name.clone();
975                    self.advance(); // ident
976                    self.advance(); // colon
977                    let value = self.parse_expr()?;
978                    CallArg {
979                        name: Some(name),
980                        value,
981                    }
982                } else {
983                    let value = self.parse_expr()?;
984                    CallArg { name: None, value }
985                }
986            } else {
987                let value = self.parse_expr()?;
988                CallArg { name: None, value }
989            };
990            args.push(arg);
991            if !self.check(&Token::RParen) {
992                self.eat(&Token::Comma)?;
993            }
994        }
995        Ok(args)
996    }
997
998    fn parse_primary(&mut self) -> Result<Expr, IonError> {
999        let span = self.span();
1000        match self.peek().clone() {
1001            Token::Int(n) => {
1002                self.advance();
1003                Ok(Expr {
1004                    kind: ExprKind::Int(n),
1005                    span,
1006                })
1007            }
1008            Token::Float(n) => {
1009                self.advance();
1010                Ok(Expr {
1011                    kind: ExprKind::Float(n),
1012                    span,
1013                })
1014            }
1015            Token::True => {
1016                self.advance();
1017                Ok(Expr {
1018                    kind: ExprKind::Bool(true),
1019                    span,
1020                })
1021            }
1022            Token::False => {
1023                self.advance();
1024                Ok(Expr {
1025                    kind: ExprKind::Bool(false),
1026                    span,
1027                })
1028            }
1029            Token::Str(s) => {
1030                self.advance();
1031                Ok(Expr {
1032                    kind: ExprKind::Str(s),
1033                    span,
1034                })
1035            }
1036            Token::Bytes(b) => {
1037                self.advance();
1038                Ok(Expr {
1039                    kind: ExprKind::Bytes(b),
1040                    span,
1041                })
1042            }
1043            Token::FStr(template) => {
1044                self.advance();
1045                let parts = self.parse_fstr_parts(&template, span)?;
1046                Ok(Expr {
1047                    kind: ExprKind::FStr(parts),
1048                    span,
1049                })
1050            }
1051            Token::None => {
1052                self.advance();
1053                Ok(Expr {
1054                    kind: ExprKind::None,
1055                    span,
1056                })
1057            }
1058            Token::Some => {
1059                self.advance();
1060                self.eat(&Token::LParen)?;
1061                let expr = self.parse_expr()?;
1062                self.eat(&Token::RParen)?;
1063                Ok(Expr {
1064                    kind: ExprKind::SomeExpr(Box::new(expr)),
1065                    span,
1066                })
1067            }
1068            Token::Ok => {
1069                self.advance();
1070                self.eat(&Token::LParen)?;
1071                let expr = self.parse_expr()?;
1072                self.eat(&Token::RParen)?;
1073                Ok(Expr {
1074                    kind: ExprKind::OkExpr(Box::new(expr)),
1075                    span,
1076                })
1077            }
1078            Token::Err => {
1079                self.advance();
1080                self.eat(&Token::LParen)?;
1081                let expr = self.parse_expr()?;
1082                self.eat(&Token::RParen)?;
1083                Ok(Expr {
1084                    kind: ExprKind::ErrExpr(Box::new(expr)),
1085                    span,
1086                })
1087            }
1088            Token::LParen => {
1089                self.advance();
1090                // Check for closure: |
1091                // or tuple: (a, b, c)
1092                // or grouping: (expr)
1093                if self.check(&Token::RParen) {
1094                    self.advance();
1095                    return Ok(Expr {
1096                        kind: ExprKind::Unit,
1097                        span,
1098                    });
1099                }
1100                let first = self.parse_expr()?;
1101                if self.check(&Token::Comma) {
1102                    // Tuple
1103                    let mut items = vec![first];
1104                    while self.check(&Token::Comma) {
1105                        self.advance();
1106                        if self.check(&Token::RParen) {
1107                            break;
1108                        }
1109                        items.push(self.parse_expr()?);
1110                    }
1111                    self.eat(&Token::RParen)?;
1112                    Ok(Expr {
1113                        kind: ExprKind::Tuple(items),
1114                        span,
1115                    })
1116                } else {
1117                    self.eat(&Token::RParen)?;
1118                    Ok(first) // grouping
1119                }
1120            }
1121            Token::LBracket => {
1122                self.advance();
1123                if self.check(&Token::RBracket) {
1124                    self.advance();
1125                    return Ok(Expr {
1126                        kind: ExprKind::List(vec![]),
1127                        span,
1128                    });
1129                }
1130                // Check for spread as first entry
1131                let first_entry = if self.check(&Token::DotDotDot) {
1132                    self.advance();
1133                    ListEntry::Spread(self.parse_expr()?)
1134                } else {
1135                    ListEntry::Elem(self.parse_expr()?)
1136                };
1137                // Check for list comprehension: [expr for pattern in iter]
1138                if let ListEntry::Elem(ref first) = first_entry {
1139                    if self.check(&Token::For) {
1140                        self.advance();
1141                        let pattern = self.parse_pattern()?;
1142                        self.eat(&Token::In)?;
1143                        let iter = self.parse_expr()?;
1144                        let cond = if self.check(&Token::If) {
1145                            self.advance();
1146                            Some(Box::new(self.parse_expr()?))
1147                        } else {
1148                            None
1149                        };
1150                        self.eat(&Token::RBracket)?;
1151                        return Ok(Expr {
1152                            kind: ExprKind::ListComp {
1153                                expr: Box::new(first.clone()),
1154                                pattern,
1155                                iter: Box::new(iter),
1156                                cond,
1157                            },
1158                            span,
1159                        });
1160                    }
1161                }
1162                let mut items = vec![first_entry];
1163                while self.check(&Token::Comma) {
1164                    self.advance();
1165                    if self.check(&Token::RBracket) {
1166                        break;
1167                    }
1168                    if self.check(&Token::DotDotDot) {
1169                        self.advance();
1170                        items.push(ListEntry::Spread(self.parse_expr()?));
1171                    } else {
1172                        items.push(ListEntry::Elem(self.parse_expr()?));
1173                    }
1174                }
1175                self.eat(&Token::RBracket)?;
1176                Ok(Expr {
1177                    kind: ExprKind::List(items),
1178                    span,
1179                })
1180            }
1181            Token::HashBrace => {
1182                self.advance();
1183                if self.check(&Token::RBrace) {
1184                    self.advance();
1185                    return Ok(Expr {
1186                        kind: ExprKind::Dict(vec![]),
1187                        span,
1188                    });
1189                }
1190                // Check for spread first entry
1191                if self.check(&Token::DotDotDot) {
1192                    return self.parse_dict_entries(span);
1193                }
1194                let first_key = self.parse_dict_key()?;
1195                self.eat(&Token::Colon)?;
1196                let first_val = self.parse_expr()?;
1197                // Check for dict comprehension: #{ key: val for pat in iter }
1198                if self.check(&Token::For) {
1199                    self.advance();
1200                    let pattern = self.parse_pattern()?;
1201                    self.eat(&Token::In)?;
1202                    let iter = self.parse_expr()?;
1203                    let cond = if self.check(&Token::If) {
1204                        self.advance();
1205                        Some(Box::new(self.parse_expr()?))
1206                    } else {
1207                        None
1208                    };
1209                    self.eat(&Token::RBrace)?;
1210                    return Ok(Expr {
1211                        kind: ExprKind::DictComp {
1212                            key: Box::new(first_key),
1213                            value: Box::new(first_val),
1214                            pattern,
1215                            iter: Box::new(iter),
1216                            cond,
1217                        },
1218                        span,
1219                    });
1220                }
1221                let mut entries = vec![DictEntry::KeyValue(first_key, first_val)];
1222                while self.check(&Token::Comma) {
1223                    self.advance();
1224                    if self.check(&Token::RBrace) {
1225                        break;
1226                    }
1227                    if self.check(&Token::DotDotDot) {
1228                        self.advance();
1229                        entries.push(DictEntry::Spread(self.parse_expr()?));
1230                    } else {
1231                        let key = self.parse_dict_key()?;
1232                        self.eat(&Token::Colon)?;
1233                        let value = self.parse_expr()?;
1234                        entries.push(DictEntry::KeyValue(key, value));
1235                    }
1236                }
1237                self.eat(&Token::RBrace)?;
1238                Ok(Expr {
1239                    kind: ExprKind::Dict(entries),
1240                    span,
1241                })
1242            }
1243            Token::PipeSym => {
1244                // Lambda: |params| body
1245                self.advance();
1246                let mut params = Vec::new();
1247                if !self.check(&Token::PipeSym) {
1248                    params.push(self.eat_ident()?);
1249                    while self.check(&Token::Comma) {
1250                        self.advance();
1251                        params.push(self.eat_ident()?);
1252                    }
1253                }
1254                self.eat(&Token::PipeSym)?;
1255                let body = if self.check(&Token::LBrace) {
1256                    self.advance();
1257                    let stmts = self.parse_block_stmts()?;
1258                    self.eat(&Token::RBrace)?;
1259                    Expr {
1260                        kind: ExprKind::Block(stmts),
1261                        span,
1262                    }
1263                } else {
1264                    self.parse_expr()?
1265                };
1266                Ok(Expr {
1267                    kind: ExprKind::Lambda {
1268                        params,
1269                        body: Box::new(body),
1270                    },
1271                    span,
1272                })
1273            }
1274            Token::Or => {
1275                // Zero-arg lambda: || body
1276                self.advance();
1277                let body = if self.check(&Token::LBrace) {
1278                    self.advance();
1279                    let stmts = self.parse_block_stmts()?;
1280                    self.eat(&Token::RBrace)?;
1281                    Expr {
1282                        kind: ExprKind::Block(stmts),
1283                        span,
1284                    }
1285                } else {
1286                    self.parse_expr()?
1287                };
1288                Ok(Expr {
1289                    kind: ExprKind::Lambda {
1290                        params: Vec::new(),
1291                        body: Box::new(body),
1292                    },
1293                    span,
1294                })
1295            }
1296            Token::If => self.parse_if_expr(),
1297            Token::Match => self.parse_match_expr(),
1298            Token::Loop => {
1299                self.advance();
1300                self.eat(&Token::LBrace)?;
1301                let body = self.parse_block_stmts()?;
1302                self.eat(&Token::RBrace)?;
1303                Ok(Expr {
1304                    kind: ExprKind::LoopExpr(body),
1305                    span,
1306                })
1307            }
1308            Token::Try => {
1309                self.advance();
1310                self.eat(&Token::LBrace)?;
1311                let body = self.parse_block_stmts()?;
1312                self.eat(&Token::RBrace)?;
1313                self.eat(&Token::Catch)?;
1314                let var = match self.peek() {
1315                    Token::Ident(name) => {
1316                        let name = name.clone();
1317                        self.advance();
1318                        name
1319                    }
1320                    _ => {
1321                        return Err(IonError::parse(
1322                            ion_str!("expected identifier after 'catch'").to_string(),
1323                            self.span().line,
1324                            self.span().col,
1325                        ));
1326                    }
1327                };
1328                self.eat(&Token::LBrace)?;
1329                let handler = self.parse_block_stmts()?;
1330                self.eat(&Token::RBrace)?;
1331                Ok(Expr {
1332                    kind: ExprKind::TryCatch { body, var, handler },
1333                    span,
1334                })
1335            }
1336            Token::Async => {
1337                self.advance();
1338                self.eat(&Token::LBrace)?;
1339                let body = self.parse_block_stmts()?;
1340                self.eat(&Token::RBrace)?;
1341                Ok(Expr {
1342                    kind: ExprKind::AsyncBlock(body),
1343                    span,
1344                })
1345            }
1346            Token::Spawn => {
1347                self.advance();
1348                let expr = self.parse_expr()?;
1349                Ok(Expr {
1350                    kind: ExprKind::SpawnExpr(Box::new(expr)),
1351                    span,
1352                })
1353            }
1354            Token::Select => {
1355                self.advance();
1356                self.eat(&Token::LBrace)?;
1357                let mut branches = Vec::new();
1358                while !self.check(&Token::RBrace) {
1359                    let pattern = self.parse_pattern()?;
1360                    self.eat(&Token::Eq)?;
1361                    let future_expr = self.parse_expr()?;
1362                    self.eat(&Token::Arrow)?;
1363                    let body = self.parse_expr()?;
1364                    branches.push(SelectBranch {
1365                        pattern,
1366                        future_expr,
1367                        body,
1368                    });
1369                    if self.check(&Token::Comma) {
1370                        self.advance();
1371                    }
1372                }
1373                self.eat(&Token::RBrace)?;
1374                Ok(Expr {
1375                    kind: ExprKind::SelectExpr(branches),
1376                    span,
1377                })
1378            }
1379            Token::LBrace => {
1380                self.advance();
1381                let stmts = self.parse_block_stmts()?;
1382                self.eat(&Token::RBrace)?;
1383                Ok(Expr {
1384                    kind: ExprKind::Block(stmts),
1385                    span,
1386                })
1387            }
1388            Token::Ident(name) => {
1389                self.advance();
1390                // Check for :: (enum variant or module path)
1391                if self.check(&Token::ColonColon) {
1392                    self.advance();
1393                    let second = self.eat_ident()?;
1394                    // If more :: segments follow, it's a module path: a::b::c::...
1395                    if self.check(&Token::ColonColon) {
1396                        let mut segments = vec![name, second];
1397                        while self.check(&Token::ColonColon) {
1398                            self.advance();
1399                            segments.push(self.eat_ident()?);
1400                        }
1401                        Ok(Expr {
1402                            kind: ExprKind::ModulePath(segments),
1403                            span,
1404                        })
1405                    }
1406                    // Two segments: could be enum variant or module path
1407                    // Enum variants have uppercase first char (e.g. Color::Red)
1408                    else if name.chars().next().is_some_and(|c| c.is_uppercase()) {
1409                        // Enum variant — check for call args
1410                        if self.check(&Token::LParen) {
1411                            self.advance();
1412                            let mut args = Vec::new();
1413                            while !self.check(&Token::RParen) && !self.is_at_end() {
1414                                args.push(self.parse_expr()?);
1415                                if !self.check(&Token::RParen) {
1416                                    self.eat(&Token::Comma)?;
1417                                }
1418                            }
1419                            self.eat(&Token::RParen)?;
1420                            Ok(Expr {
1421                                kind: ExprKind::EnumVariantCall {
1422                                    enum_name: name,
1423                                    variant: second,
1424                                    args,
1425                                },
1426                                span,
1427                            })
1428                        } else {
1429                            Ok(Expr {
1430                                kind: ExprKind::EnumVariant {
1431                                    enum_name: name,
1432                                    variant: second,
1433                                },
1434                                span,
1435                            })
1436                        }
1437                    }
1438                    // Two segments, lowercase first: module path (e.g. fs::read)
1439                    else {
1440                        Ok(Expr {
1441                            kind: ExprKind::ModulePath(vec![name, second]),
1442                            span,
1443                        })
1444                    }
1445                }
1446                // Check for struct construction: Name { ... }
1447                else if self.check(&Token::LBrace)
1448                    && name.chars().next().is_some_and(|c| c.is_uppercase())
1449                {
1450                    self.advance();
1451                    let mut fields = Vec::new();
1452                    let mut spread = None;
1453                    while !self.check(&Token::RBrace) && !self.is_at_end() {
1454                        if self.check(&Token::DotDotDot) {
1455                            self.advance();
1456                            spread = Some(Box::new(self.parse_expr()?));
1457                            if !self.check(&Token::RBrace) {
1458                                self.eat(&Token::Comma)?;
1459                            }
1460                            continue;
1461                        }
1462                        let field_name = self.eat_ident()?;
1463                        self.eat(&Token::Colon)?;
1464                        let field_value = self.parse_expr()?;
1465                        fields.push((field_name, field_value));
1466                        if !self.check(&Token::RBrace) {
1467                            self.eat(&Token::Comma)?;
1468                        }
1469                    }
1470                    self.eat(&Token::RBrace)?;
1471                    Ok(Expr {
1472                        kind: ExprKind::StructConstruct {
1473                            name,
1474                            fields,
1475                            spread,
1476                        },
1477                        span,
1478                    })
1479                } else {
1480                    Ok(Expr {
1481                        kind: ExprKind::Ident(name),
1482                        span,
1483                    })
1484                }
1485            }
1486            _ => {
1487                let s = self.span();
1488                Err(IonError::parse(
1489                    format!("{}{:?}", ion_str!("unexpected token: "), self.peek()),
1490                    s.line,
1491                    s.col,
1492                ))
1493            }
1494        }
1495    }
1496
1497    /// Parse dict entries when the first token is `...` (spread).
1498    /// Parse a dict key: if it's an identifier followed by `:`, treat as string literal.
1499    fn parse_dict_key(&mut self) -> Result<Expr, IonError> {
1500        let span = self.span();
1501        if let Token::Ident(name) = self.peek().clone() {
1502            // Lookahead: if next token is `:`, this is a shorthand key
1503            if self.tokens.get(self.pos + 1).map(|t| &t.token) == Some(&Token::Colon) {
1504                self.advance(); // consume the identifier
1505                return Ok(Expr {
1506                    kind: ExprKind::Str(name),
1507                    span,
1508                });
1509            }
1510        }
1511        self.parse_expr()
1512    }
1513
1514    fn parse_dict_entries(&mut self, span: Span) -> Result<Expr, IonError> {
1515        let mut entries = Vec::new();
1516        // First entry is a spread
1517        self.advance(); // consume `...`
1518        entries.push(DictEntry::Spread(self.parse_expr()?));
1519        while self.check(&Token::Comma) {
1520            self.advance();
1521            if self.check(&Token::RBrace) {
1522                break;
1523            }
1524            if self.check(&Token::DotDotDot) {
1525                self.advance();
1526                entries.push(DictEntry::Spread(self.parse_expr()?));
1527            } else {
1528                let key = self.parse_dict_key()?;
1529                self.eat(&Token::Colon)?;
1530                let value = self.parse_expr()?;
1531                entries.push(DictEntry::KeyValue(key, value));
1532            }
1533        }
1534        self.eat(&Token::RBrace)?;
1535        Ok(Expr {
1536            kind: ExprKind::Dict(entries),
1537            span,
1538        })
1539    }
1540
1541    fn parse_if_expr(&mut self) -> Result<Expr, IonError> {
1542        let span = self.span();
1543        self.eat(&Token::If)?;
1544
1545        // if let pattern = expr { ... }
1546        if self.check(&Token::Let) {
1547            self.advance();
1548            let pattern = self.parse_pattern()?;
1549            self.eat(&Token::Eq)?;
1550            let expr = self.parse_expr()?;
1551            self.eat(&Token::LBrace)?;
1552            let then_body = self.parse_block_stmts()?;
1553            self.eat(&Token::RBrace)?;
1554            let else_body = if self.check(&Token::Else) {
1555                self.advance();
1556                self.eat(&Token::LBrace)?;
1557                let stmts = self.parse_block_stmts()?;
1558                self.eat(&Token::RBrace)?;
1559                Some(stmts)
1560            } else {
1561                None
1562            };
1563            return Ok(Expr {
1564                kind: ExprKind::IfLet {
1565                    pattern,
1566                    expr: Box::new(expr),
1567                    then_body,
1568                    else_body,
1569                },
1570                span,
1571            });
1572        }
1573
1574        let cond = self.parse_expr()?;
1575        self.eat(&Token::LBrace)?;
1576        let then_body = self.parse_block_stmts()?;
1577        self.eat(&Token::RBrace)?;
1578        let else_body = if self.check(&Token::Else) {
1579            self.advance();
1580            if self.check(&Token::If) {
1581                // else if
1582                let else_if = self.parse_if_expr()?;
1583                Some(vec![Stmt {
1584                    kind: StmtKind::ExprStmt {
1585                        expr: else_if,
1586                        has_semi: false,
1587                    },
1588                    span: self.prev_span(),
1589                }])
1590            } else {
1591                self.eat(&Token::LBrace)?;
1592                let stmts = self.parse_block_stmts()?;
1593                self.eat(&Token::RBrace)?;
1594                Some(stmts)
1595            }
1596        } else {
1597            None
1598        };
1599        Ok(Expr {
1600            kind: ExprKind::If {
1601                cond: Box::new(cond),
1602                then_body,
1603                else_body,
1604            },
1605            span,
1606        })
1607    }
1608
1609    fn parse_match_expr(&mut self) -> Result<Expr, IonError> {
1610        let span = self.span();
1611        self.eat(&Token::Match)?;
1612        let expr = self.parse_expr()?;
1613        self.eat(&Token::LBrace)?;
1614        let mut arms = Vec::new();
1615        while !self.check(&Token::RBrace) && !self.is_at_end() {
1616            let pattern = self.parse_pattern()?;
1617            let guard = if self.check(&Token::If) {
1618                self.advance();
1619                Some(self.parse_expr()?)
1620            } else {
1621                None
1622            };
1623            self.eat(&Token::Arrow)?;
1624            let body = self.parse_expr()?;
1625            arms.push(MatchArm {
1626                pattern,
1627                guard,
1628                body,
1629            });
1630            if !self.check(&Token::RBrace) {
1631                self.eat(&Token::Comma)?;
1632            }
1633        }
1634        self.eat(&Token::RBrace)?;
1635        Ok(Expr {
1636            kind: ExprKind::Match {
1637                expr: Box::new(expr),
1638                arms,
1639            },
1640            span,
1641        })
1642    }
1643
1644    // --- Pattern Parsing ---
1645
1646    fn parse_pattern(&mut self) -> Result<Pattern, IonError> {
1647        match self.peek().clone() {
1648            Token::Ident(name) if name == "_" => {
1649                self.advance();
1650                Ok(Pattern::Wildcard)
1651            }
1652            Token::Ident(name) => {
1653                self.advance();
1654                // Check for :: (enum variant)
1655                if self.check(&Token::ColonColon) {
1656                    self.advance();
1657                    let variant = self.eat_ident()?;
1658                    let fields = if self.check(&Token::LParen) {
1659                        self.advance();
1660                        let mut pats = Vec::new();
1661                        while !self.check(&Token::RParen) && !self.is_at_end() {
1662                            pats.push(self.parse_pattern()?);
1663                            if !self.check(&Token::RParen) {
1664                                self.eat(&Token::Comma)?;
1665                            }
1666                        }
1667                        self.eat(&Token::RParen)?;
1668                        EnumPatternFields::Positional(pats)
1669                    } else if self.check(&Token::LBrace) {
1670                        self.advance();
1671                        let mut fields = Vec::new();
1672                        while !self.check(&Token::RBrace) && !self.is_at_end() {
1673                            let field_name = self.eat_ident()?;
1674                            let pat = if self.check(&Token::Colon) {
1675                                self.advance();
1676                                Some(self.parse_pattern()?)
1677                            } else {
1678                                None
1679                            };
1680                            fields.push((field_name, pat));
1681                            if !self.check(&Token::RBrace) {
1682                                self.eat(&Token::Comma)?;
1683                            }
1684                        }
1685                        self.eat(&Token::RBrace)?;
1686                        EnumPatternFields::Named(fields)
1687                    } else {
1688                        EnumPatternFields::None
1689                    };
1690                    Ok(Pattern::EnumVariant {
1691                        enum_name: name,
1692                        variant,
1693                        fields,
1694                    })
1695                }
1696                // Check for struct pattern: Name { ... }
1697                else if self.check(&Token::LBrace)
1698                    && name.chars().next().is_some_and(|c| c.is_uppercase())
1699                {
1700                    self.advance();
1701                    let mut fields = Vec::new();
1702                    while !self.check(&Token::RBrace) && !self.is_at_end() {
1703                        let field_name = self.eat_ident()?;
1704                        let pat = if self.check(&Token::Colon) {
1705                            self.advance();
1706                            Some(self.parse_pattern()?)
1707                        } else {
1708                            None
1709                        };
1710                        fields.push((field_name, pat));
1711                        if !self.check(&Token::RBrace) {
1712                            self.eat(&Token::Comma)?;
1713                        }
1714                    }
1715                    self.eat(&Token::RBrace)?;
1716                    Ok(Pattern::Struct { name, fields })
1717                } else {
1718                    Ok(Pattern::Ident(name))
1719                }
1720            }
1721            Token::Int(n) => {
1722                self.advance();
1723                Ok(Pattern::Int(n))
1724            }
1725            Token::Float(n) => {
1726                self.advance();
1727                Ok(Pattern::Float(n))
1728            }
1729            Token::True => {
1730                self.advance();
1731                Ok(Pattern::Bool(true))
1732            }
1733            Token::False => {
1734                self.advance();
1735                Ok(Pattern::Bool(false))
1736            }
1737            Token::Str(s) => {
1738                self.advance();
1739                Ok(Pattern::Str(s))
1740            }
1741            Token::Bytes(b) => {
1742                self.advance();
1743                Ok(Pattern::Bytes(b))
1744            }
1745            Token::None => {
1746                self.advance();
1747                Ok(Pattern::None)
1748            }
1749            Token::Some => {
1750                self.advance();
1751                self.eat(&Token::LParen)?;
1752                let inner = self.parse_pattern()?;
1753                self.eat(&Token::RParen)?;
1754                Ok(Pattern::Some(Box::new(inner)))
1755            }
1756            Token::Ok => {
1757                self.advance();
1758                self.eat(&Token::LParen)?;
1759                let inner = self.parse_pattern()?;
1760                self.eat(&Token::RParen)?;
1761                Ok(Pattern::Ok(Box::new(inner)))
1762            }
1763            Token::Err => {
1764                self.advance();
1765                self.eat(&Token::LParen)?;
1766                let inner = self.parse_pattern()?;
1767                self.eat(&Token::RParen)?;
1768                Ok(Pattern::Err(Box::new(inner)))
1769            }
1770            Token::LParen => {
1771                self.advance();
1772                let mut pats = Vec::new();
1773                while !self.check(&Token::RParen) && !self.is_at_end() {
1774                    pats.push(self.parse_pattern()?);
1775                    if !self.check(&Token::RParen) {
1776                        self.eat(&Token::Comma)?;
1777                    }
1778                }
1779                self.eat(&Token::RParen)?;
1780                Ok(Pattern::Tuple(pats))
1781            }
1782            Token::LBracket => {
1783                self.advance();
1784                let mut pats = Vec::new();
1785                let mut rest = None;
1786                while !self.check(&Token::RBracket) && !self.is_at_end() {
1787                    if self.check(&Token::DotDotDot) {
1788                        self.advance();
1789                        let rest_name = self.eat_ident()?;
1790                        rest = Some(Box::new(Pattern::Ident(rest_name)));
1791                        if !self.check(&Token::RBracket) {
1792                            self.eat(&Token::Comma)?;
1793                        }
1794                        continue;
1795                    }
1796                    pats.push(self.parse_pattern()?);
1797                    if !self.check(&Token::RBracket) {
1798                        self.eat(&Token::Comma)?;
1799                    }
1800                }
1801                self.eat(&Token::RBracket)?;
1802                Ok(Pattern::List(pats, rest))
1803            }
1804            _ => {
1805                let s = self.span();
1806                Err(IonError::parse(
1807                    format!(
1808                        "{}{:?}",
1809                        ion_str!("unexpected token in pattern: "),
1810                        self.peek()
1811                    ),
1812                    s.line,
1813                    s.col,
1814                ))
1815            }
1816        }
1817    }
1818
1819    // --- F-string parsing ---
1820
1821    fn parse_fstr_parts(&self, template: &str, span: Span) -> Result<Vec<FStrPart>, IonError> {
1822        let mut parts = Vec::new();
1823        let mut chars = template.chars().peekable();
1824        let mut current = String::new();
1825
1826        while let Some(ch) = chars.next() {
1827            if ch == '{' {
1828                if !current.is_empty() {
1829                    parts.push(FStrPart::Literal(std::mem::take(&mut current)));
1830                }
1831                let mut expr_str = String::new();
1832                let mut depth = 1;
1833                for inner in chars.by_ref() {
1834                    if inner == '{' {
1835                        depth += 1;
1836                    } else if inner == '}' {
1837                        depth -= 1;
1838                        if depth == 0 {
1839                            break;
1840                        }
1841                    }
1842                    expr_str.push(inner);
1843                }
1844                if depth != 0 {
1845                    return Err(IonError::parse(
1846                        ion_str!("unterminated expression in f-string").to_string(),
1847                        span.line,
1848                        span.col,
1849                    ));
1850                }
1851                let mut lexer = crate::lexer::Lexer::new(&expr_str);
1852                let tokens = lexer.tokenize()?;
1853                let mut parser = Parser::new(tokens);
1854                let expr = parser.parse_expr()?;
1855                parts.push(FStrPart::Expr(expr));
1856            } else {
1857                current.push(ch);
1858            }
1859        }
1860        if !current.is_empty() {
1861            parts.push(FStrPart::Literal(current));
1862        }
1863        Ok(parts)
1864    }
1865}
1866
1867#[cfg(test)]
1868mod tests {
1869    use super::*;
1870    use crate::lexer::Lexer;
1871
1872    fn parse(src: &str) -> Program {
1873        let tokens = Lexer::new(src).tokenize().unwrap();
1874        Parser::new(tokens).parse_program().unwrap()
1875    }
1876
1877    #[test]
1878    fn test_let_stmt() {
1879        let prog = parse("let x = 42;");
1880        assert_eq!(prog.stmts.len(), 1);
1881        assert!(matches!(
1882            &prog.stmts[0].kind,
1883            StmtKind::Let { mutable: false, .. }
1884        ));
1885    }
1886
1887    #[test]
1888    fn test_let_mut() {
1889        let prog = parse("let mut x = 42;");
1890        assert!(matches!(
1891            &prog.stmts[0].kind,
1892            StmtKind::Let { mutable: true, .. }
1893        ));
1894    }
1895
1896    #[test]
1897    fn test_fn_decl() {
1898        let prog = parse("fn add(a, b) { a + b }");
1899        assert!(matches!(&prog.stmts[0].kind, StmtKind::FnDecl { .. }));
1900    }
1901
1902    #[test]
1903    fn test_if_expr() {
1904        let prog = parse("let x = if true { 1 } else { 2 };");
1905        assert!(matches!(&prog.stmts[0].kind, StmtKind::Let { .. }));
1906    }
1907
1908    #[test]
1909    fn test_match_expr() {
1910        let prog = parse(r#"let x = match y { 1 => "one", _ => "other" };"#);
1911        assert!(matches!(&prog.stmts[0].kind, StmtKind::Let { .. }));
1912    }
1913
1914    #[test]
1915    fn test_lambda() {
1916        let prog = parse("let f = |x| x + 1;");
1917        assert!(matches!(&prog.stmts[0].kind, StmtKind::Let { .. }));
1918    }
1919
1920    #[test]
1921    fn test_dict() {
1922        let prog = parse(r#"let d = #{ "a": 1, "b": 2 };"#);
1923        assert!(matches!(&prog.stmts[0].kind, StmtKind::Let { .. }));
1924    }
1925
1926    #[test]
1927    fn test_for_loop() {
1928        let prog = parse("for x in items { x; }");
1929        assert!(matches!(&prog.stmts[0].kind, StmtKind::For { .. }));
1930    }
1931}