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