Skip to main content

crisp_parser/
parser.rs

1use crisp_ast::{
2    Span,
3    expr::{
4        BinaryOp, Block, Expr, ExprKind, FieldInit, MatchArm, Ownership, Param, Stmt, StringPart,
5        StringParts, UnaryOp,
6    },
7    ident::Ident,
8    item::{
9        ConstDef, ExternBlock, ExternFn, FieldDef, FunctionDef, ImplBlock, Item, ShapeDef,
10        ShapeField, SourceFile, TestDef, TraitDef, TraitItem, TypeBody, TypeDef, UseDecl,
11        UseImport, VariantDef,
12    },
13    pat::{FieldPat, Pat, PatKind},
14    ty::{ErrorType, Type, TypeBound, TypeKind},
15};
16use crisp_lexer::{Kw, Token, TokenKind, lex};
17use thiserror::Error;
18
19#[derive(Debug, Error)]
20pub enum ParseError {
21    #[error("lex error: {0}")]
22    Lex(#[from] crisp_lexer::LexError),
23    #[error("{}", format_unexpected(.expected, .found, .pos, .help))]
24    Unexpected {
25        expected: &'static str,
26        found: TokenKind,
27        pos: u32,
28        help: Option<&'static str>,
29    },
30    #[error("unexpected end of file, expected {expected}")]
31    UnexpectedEof { expected: &'static str },
32    #[error("invalid pattern at byte {pos}")]
33    InvalidPat { pos: u32 },
34}
35
36fn format_unexpected(
37    expected: &&'static str,
38    found: &TokenKind,
39    pos: &u32,
40    help: &Option<&'static str>,
41) -> String {
42    let mut msg = format!("unexpected token {found:?} at byte {pos}, expected {expected}");
43    if let Some(h) = help {
44        msg.push_str("\nhelp: ");
45        msg.push_str(h);
46    }
47    msg
48}
49
50pub struct Parser {
51    tokens: Vec<Token>,
52    pos: usize,
53    /// When false, `Name { … }` is not parsed as a struct literal (Rust-style
54    /// restriction for `if`/`while`/`for` conditions so `{` can start the body).
55    allow_struct_lit: bool,
56}
57
58impl Parser {
59    pub fn new(source: &str) -> Result<Self, ParseError> {
60        Self::with_span_base(source, 0)
61    }
62
63    /// Lex `source` as if it began at byte `base` in the outer file (interpolation, #95).
64    pub fn with_span_base(source: &str, base: u32) -> Result<Self, ParseError> {
65        let mut tokens = lex(source)?;
66        if base != 0 {
67            for t in &mut tokens {
68                t.start = t.start.saturating_add(base);
69                t.end = t.end.saturating_add(base);
70            }
71        }
72        Ok(Self {
73            tokens,
74            pos: 0,
75            allow_struct_lit: true,
76        })
77    }
78
79    fn with_no_struct_lit<T>(
80        &mut self,
81        f: impl FnOnce(&mut Self) -> Result<T, ParseError>,
82    ) -> Result<T, ParseError> {
83        let prev = self.allow_struct_lit;
84        self.allow_struct_lit = false;
85        let result = f(self);
86        self.allow_struct_lit = prev;
87        result
88    }
89
90    pub fn parse_file(&mut self) -> Result<SourceFile, ParseError> {
91        let start = self.current_start();
92        let mut items = Vec::new();
93        while !self.check(TokenKind::Eof) {
94            items.push(self.parse_item()?);
95        }
96        let end = if items.is_empty() {
97            start
98        } else {
99            items.last().unwrap().span().end
100        };
101        Ok(SourceFile {
102            items,
103            span: Span::new(start, end),
104        })
105    }
106
107    pub fn parse_module(&mut self) -> Result<Vec<Item>, ParseError> {
108        Ok(self.parse_file()?.items)
109    }
110
111    // ── Items ─────────────────────────────────────────────────────────────
112
113    fn parse_item(&mut self) -> Result<Item, ParseError> {
114        let pub_span = if self.match_kw(Kw::Pub) {
115            Some(self.previous_span())
116        } else {
117            None
118        };
119        let is_pub = pub_span.is_some();
120
121        if self.match_kw(Kw::Type) {
122            return Ok(Item::TypeDef(self.parse_type_def(is_pub)?));
123        }
124        if self.match_kw(Kw::Trait) {
125            return Ok(Item::TraitDef(self.parse_trait_def()?));
126        }
127        if self.match_kw(Kw::Shape) {
128            return Ok(Item::ShapeDef(self.parse_shape_def()?));
129        }
130        if self.match_kw(Kw::Impl) {
131            return Ok(Item::Impl(self.parse_impl_block()?));
132        }
133        if self.match_kw(Kw::Use) {
134            return Ok(Item::Use(self.parse_use_decl(is_pub)?));
135        }
136        if self.match_kw(Kw::Extern) {
137            return Ok(Item::Extern(self.parse_extern_block()?));
138        }
139        if self.match_kw(Kw::TestCompileFail) {
140            return Ok(Item::TestCompileFail(self.parse_test_def()?));
141        }
142        if self.match_kw(Kw::Test) {
143            return Ok(Item::Test(self.parse_test_def()?));
144        }
145
146        let name = self.expect_ident()?;
147        if self.check(TokenKind::Lt) || self.check(TokenKind::LParen) {
148            return Ok(Item::Function(
149                self.parse_function_after_name(is_pub, name)?,
150            ));
151        }
152        if self.check(TokenKind::Assign) {
153            self.advance();
154            let value = self.parse_expr()?;
155            let span = name.span.merge(value.span);
156            return Ok(Item::Const(ConstDef { name, value, span }));
157        }
158
159        Err(self.unexpected("item", self.peek_kind()))
160    }
161
162    fn parse_function_after_name(
163        &mut self,
164        is_pub: bool,
165        name: Ident,
166    ) -> Result<FunctionDef, ParseError> {
167        let start = name.span.start;
168        let generics = self.parse_optional_generics()?;
169        self.expect(TokenKind::LParen)?;
170        let params = self.parse_params()?;
171        self.expect(TokenKind::RParen)?;
172        let ret_type = if self.match_token(TokenKind::Arrow) {
173            Some(self.parse_type()?)
174        } else {
175            None
176        };
177        let error_type = if self.check(TokenKind::Bang) {
178            Some(self.parse_error_type()?)
179        } else {
180            None
181        };
182        self.expect(TokenKind::Assign)?;
183        let body = self.parse_expr()?;
184        let end = body.span.end;
185        Ok(FunctionDef {
186            is_pub,
187            name,
188            generics,
189            params,
190            ret_type,
191            error_type,
192            body,
193            span: Span::new(start, end),
194        })
195    }
196
197    fn parse_params(&mut self) -> Result<Vec<Param>, ParseError> {
198        let mut params = Vec::new();
199        if self.check(TokenKind::RParen) {
200            return Ok(params);
201        }
202        loop {
203            params.push(self.parse_param()?);
204            if !self.match_token(TokenKind::Comma) {
205                break;
206            }
207        }
208        Ok(params)
209    }
210
211    fn parse_param(&mut self) -> Result<Param, ParseError> {
212        let start = self.current_start();
213        let lifetime = if self.check_lifetime() {
214            Some(self.parse_lifetime_ident()?)
215        } else {
216            None
217        };
218        let ownership = if self.match_kw(Kw::Own) {
219            Some(Ownership::Own)
220        } else if self.match_token(TokenKind::AmpMut) {
221            Some(Ownership::RefMut)
222        } else if self.match_token(TokenKind::Amp) {
223            Some(Ownership::Ref)
224        } else {
225            None
226        };
227        let name = self.expect_ident()?;
228        let ty = if self.match_token(TokenKind::Colon) {
229            Some(self.parse_type()?)
230        } else {
231            None
232        };
233        Ok(Param {
234            lifetime,
235            ownership,
236            name,
237            ty,
238            span: Span::new(start, self.previous_end()),
239        })
240    }
241
242    fn parse_type_def(&mut self, is_pub: bool) -> Result<TypeDef, ParseError> {
243        let start = self.previous_start();
244        let name = self.expect_ident()?;
245        let generics = self.parse_optional_generics()?;
246        self.expect(TokenKind::Assign)?;
247        let (body, end) = if self.match_token(TokenKind::LBrace) {
248            let fields = self.parse_struct_fields()?;
249            self.expect(TokenKind::RBrace)?;
250            let end = self.previous_end();
251            (TypeBody::Struct(fields), end)
252        } else if self.match_token(TokenKind::Pipe) {
253            let variants = self.parse_enum_variants()?;
254            (TypeBody::Enum(variants), self.previous_end())
255        } else {
256            let ty = self.parse_type()?;
257            (TypeBody::Alias(ty.clone()), ty.span.end)
258        };
259        Ok(TypeDef {
260            is_pub,
261            name,
262            generics,
263            body,
264            span: Span::new(start, end),
265        })
266    }
267
268    fn parse_struct_fields(&mut self) -> Result<Vec<FieldDef>, ParseError> {
269        let mut fields = Vec::new();
270        while !self.check(TokenKind::RBrace) && !self.check(TokenKind::Eof) {
271            let start = self.current_start();
272            let name = self.expect_ident()?;
273            self.expect(TokenKind::Colon)?;
274            let ty = self.parse_type()?;
275            let default = if self.match_token(TokenKind::Assign) {
276                Some(self.parse_expr()?)
277            } else {
278                None
279            };
280            fields.push(FieldDef {
281                name,
282                ty,
283                default,
284                span: Span::new(start, self.previous_end()),
285            });
286        }
287        Ok(fields)
288    }
289
290    fn parse_enum_variants(&mut self) -> Result<Vec<VariantDef>, ParseError> {
291        let mut variants = Vec::new();
292        loop {
293            let start = self.current_start();
294            let name = self.expect_ident()?;
295            let fields = if self.match_token(TokenKind::LParen) {
296                let mut types = Vec::new();
297                while !self.check(TokenKind::RParen) {
298                    types.push(self.parse_type()?);
299                    if !self.match_token(TokenKind::Comma) {
300                        break;
301                    }
302                }
303                self.expect(TokenKind::RParen)?;
304                types
305            } else {
306                vec![]
307            };
308            variants.push(VariantDef {
309                name,
310                fields,
311                span: Span::new(start, self.previous_end()),
312            });
313            if !self.match_token(TokenKind::Pipe) {
314                break;
315            }
316        }
317        Ok(variants)
318    }
319
320    fn parse_trait_def(&mut self) -> Result<TraitDef, ParseError> {
321        let start = self.previous_start();
322        let name = self.expect_ident()?;
323        let generics = self.parse_optional_generics()?;
324        self.expect(TokenKind::Assign)?;
325        self.expect(TokenKind::LBrace)?;
326        let mut items = Vec::new();
327        while !self.check(TokenKind::RBrace) && !self.check(TokenKind::Eof) {
328            items.push(self.parse_trait_item()?);
329        }
330        self.expect(TokenKind::RBrace)?;
331        Ok(TraitDef {
332            name,
333            generics,
334            items,
335            span: Span::new(start, self.previous_end()),
336        })
337    }
338
339    fn parse_trait_item(&mut self) -> Result<TraitItem, ParseError> {
340        let start = self.current_start();
341        let name = self.expect_ident()?;
342        self.expect(TokenKind::LParen)?;
343        let params = self.parse_params()?;
344        self.expect(TokenKind::RParen)?;
345        let ret_type = if self.match_token(TokenKind::Arrow) {
346            Some(self.parse_type()?)
347        } else {
348            None
349        };
350        let default_body = if self.match_token(TokenKind::Assign) {
351            Some(self.parse_expr()?)
352        } else {
353            None
354        };
355        Ok(TraitItem {
356            name,
357            params,
358            ret_type,
359            default_body,
360            span: Span::new(start, self.previous_end()),
361        })
362    }
363
364    fn parse_shape_def(&mut self) -> Result<ShapeDef, ParseError> {
365        let start = self.previous_start();
366        let name = self.expect_ident()?;
367        let generics = self.parse_optional_generics()?;
368        self.expect(TokenKind::Assign)?;
369        self.expect(TokenKind::LBrace)?;
370        let mut fields = Vec::new();
371        while !self.check(TokenKind::RBrace) && !self.check(TokenKind::Eof) {
372            fields.push(self.parse_shape_field()?);
373        }
374        self.expect(TokenKind::RBrace)?;
375        Ok(ShapeDef {
376            name,
377            generics,
378            fields,
379            span: Span::new(start, self.previous_end()),
380        })
381    }
382
383    fn parse_shape_field(&mut self) -> Result<ShapeField, ParseError> {
384        let start = self.current_start();
385        let name = self.expect_ident()?;
386        if self.match_token(TokenKind::Colon) {
387            let ty = self.parse_type()?;
388            return Ok(ShapeField::Data {
389                name,
390                ty,
391                span: Span::new(start, self.previous_end()),
392            });
393        }
394        self.expect(TokenKind::LParen)?;
395        let params = self.parse_params()?;
396        self.expect(TokenKind::RParen)?;
397        self.expect(TokenKind::Arrow)?;
398        let ret_type = self.parse_type()?;
399        Ok(ShapeField::Method {
400            name,
401            params,
402            ret_type,
403            span: Span::new(start, self.previous_end()),
404        })
405    }
406
407    fn parse_impl_block(&mut self) -> Result<ImplBlock, ParseError> {
408        let start = self.previous_start();
409        let first = self.expect_ident()?;
410        let trait_args = self.parse_optional_type_args()?;
411        let (trait_name, ty) = if self.match_kw(Kw::For) {
412            let ty = self.parse_type()?;
413            (Some(first), ty)
414        } else {
415            (
416                None,
417                Type {
418                    kind: TypeKind::Named(first.clone()),
419                    span: first.span,
420                },
421            )
422        };
423        let mut items = Vec::new();
424        if self.match_token(TokenKind::Assign) {
425            self.expect(TokenKind::LBrace)?;
426            while !self.check(TokenKind::RBrace) && !self.check(TokenKind::Eof) {
427                let is_pub = self.match_kw(Kw::Pub);
428                let name = self.expect_ident()?;
429                items.push(self.parse_function_after_name(is_pub, name)?);
430            }
431            self.expect(TokenKind::RBrace)?;
432        }
433        Ok(ImplBlock {
434            trait_name,
435            trait_args,
436            ty,
437            items,
438            span: Span::new(start, self.previous_end()),
439        })
440    }
441
442    fn parse_use_decl(&mut self, is_pub: bool) -> Result<UseDecl, ParseError> {
443        let start = self.previous_start();
444        let mut path = vec![self.expect_ident()?];
445        // Crisp module paths use `.`; spec §14.2 also writes `use rust::crate` — accept both.
446        while self.match_token(TokenKind::Dot) || self.match_colon_colon() {
447            path.push(self.expect_ident()?);
448        }
449        let imports = if self.match_token(TokenKind::LBrace) {
450            let mut list = Vec::new();
451            while !self.check(TokenKind::RBrace) {
452                let s = self.current_start();
453                let name = self.expect_ident()?;
454                let alias = if self.match_kw(Kw::As) {
455                    Some(self.expect_ident()?)
456                } else {
457                    None
458                };
459                list.push(UseImport {
460                    name,
461                    alias,
462                    span: Span::new(s, self.previous_end()),
463                });
464                if !self.match_token(TokenKind::Comma) {
465                    break;
466                }
467            }
468            self.expect(TokenKind::RBrace)?;
469            Some(list)
470        } else {
471            None
472        };
473        Ok(UseDecl {
474            is_pub,
475            path,
476            imports,
477            span: Span::new(start, self.previous_end()),
478        })
479    }
480
481    fn parse_extern_block(&mut self) -> Result<ExternBlock, ParseError> {
482        let start = self.previous_start();
483        let abi = self.expect_string_lit()?;
484        self.expect(TokenKind::LBrace)?;
485        let mut functions = Vec::new();
486        while !self.check(TokenKind::RBrace) && !self.check(TokenKind::Eof) {
487            let s = self.current_start();
488            let name = self.expect_ident()?;
489            self.expect(TokenKind::LParen)?;
490            let params = self.parse_params()?;
491            self.expect(TokenKind::RParen)?;
492            let ret_type = if self.match_token(TokenKind::Arrow) {
493                Some(self.parse_type()?)
494            } else {
495                None
496            };
497            functions.push(ExternFn {
498                name,
499                params,
500                ret_type,
501                span: Span::new(s, self.previous_end()),
502            });
503        }
504        self.expect(TokenKind::RBrace)?;
505        Ok(ExternBlock {
506            abi,
507            functions,
508            span: Span::new(start, self.previous_end()),
509        })
510    }
511
512    fn parse_test_def(&mut self) -> Result<TestDef, ParseError> {
513        let start = self.previous_start();
514        let name = self.expect_string_lit()?;
515        self.expect(TokenKind::Assign)?;
516        let body = self.parse_block()?;
517        let end = body.span.end;
518        Ok(TestDef {
519            name,
520            body,
521            span: Span::new(start, end),
522        })
523    }
524
525    // ── Types ─────────────────────────────────────────────────────────────
526
527    fn parse_type(&mut self) -> Result<Type, ParseError> {
528        let start = self.current_start();
529        if self.match_token(TokenKind::Question) {
530            let inner = self.parse_type()?;
531            return Ok(Type {
532                kind: TypeKind::Option(Box::new(inner)),
533                span: Span::new(start, self.previous_end()),
534            });
535        }
536        if self.match_token(TokenKind::AmpMut) {
537            let inner = self.parse_type()?;
538            return Ok(Type {
539                kind: TypeKind::Ref {
540                    mutable: true,
541                    inner: Box::new(inner),
542                },
543                span: Span::new(start, self.previous_end()),
544            });
545        }
546        if self.match_token(TokenKind::Amp) {
547            let inner = self.parse_type()?;
548            return Ok(Type {
549                kind: TypeKind::Ref {
550                    mutable: false,
551                    inner: Box::new(inner),
552                },
553                span: Span::new(start, self.previous_end()),
554            });
555        }
556        if self.match_token(TokenKind::LParen) {
557            if self.check(TokenKind::RParen) {
558                self.advance();
559                return Ok(Type {
560                    kind: TypeKind::Unit,
561                    span: Span::new(start, self.previous_end()),
562                });
563            }
564            let mut types = vec![self.parse_type()?];
565            while self.match_token(TokenKind::Comma) {
566                types.push(self.parse_type()?);
567            }
568            self.expect(TokenKind::RParen)?;
569            if types.len() == 1 && self.check(TokenKind::Arrow) {
570                self.advance();
571                let ret = self.parse_type()?;
572                return Ok(Type {
573                    kind: TypeKind::Fn {
574                        params: types,
575                        ret: Box::new(ret),
576                    },
577                    span: Span::new(start, self.previous_end()),
578                });
579            }
580            return Ok(Type {
581                kind: TypeKind::Tuple(types),
582                span: Span::new(start, self.previous_end()),
583            });
584        }
585        if self.match_token(TokenKind::LBracket) {
586            let elem = self.parse_type()?;
587            if self.match_token(TokenKind::Semi) && self.is_int() {
588                let TokenKind::Int(n) = self.advance().kind else {
589                    unreachable!();
590                };
591                self.expect(TokenKind::RBracket)?;
592                return Ok(Type {
593                    kind: TypeKind::Array {
594                        elem: Box::new(elem),
595                        len: n as u64,
596                    },
597                    span: Span::new(start, self.previous_end()),
598                });
599            }
600            self.expect(TokenKind::RBracket)?;
601            return Ok(Type {
602                kind: TypeKind::Slice(Box::new(elem)),
603                span: Span::new(start, self.previous_end()),
604            });
605        }
606
607        let base = self.parse_type_primary()?;
608        let mut ty = base;
609        if self.match_token(TokenKind::Lt) {
610            let mut args = vec![self.parse_type()?];
611            while self.match_token(TokenKind::Comma) {
612                args.push(self.parse_type()?);
613            }
614            self.expect(TokenKind::Gt)?;
615            ty = Type {
616                kind: TypeKind::Generic {
617                    base: Box::new(ty),
618                    args,
619                },
620                span: Span::new(start, self.previous_end()),
621            };
622        }
623        while self.match_token(TokenKind::Plus) {
624            let mut bounds = vec![self.parse_type_bound()?];
625            while self.match_token(TokenKind::Plus) {
626                bounds.push(self.parse_type_bound()?);
627            }
628            ty = Type {
629                kind: TypeKind::Constrained {
630                    inner: Box::new(ty),
631                    bounds,
632                },
633                span: Span::new(start, self.previous_end()),
634            };
635        }
636        Ok(ty)
637    }
638
639    fn parse_type_primary(&mut self) -> Result<Type, ParseError> {
640        let start = self.current_start();
641        if let Some(kw) = self.match_kw_opt() {
642            let name = match kw {
643                Kw::True | Kw::False => "bool",
644                _ => return Err(self.unexpected("type", TokenKind::Kw(kw))),
645            };
646            return Ok(Type {
647                kind: TypeKind::Named(Ident::new(name, Span::new(start, self.previous_end()))),
648                span: Span::new(start, self.previous_end()),
649            });
650        }
651        let name = self.expect_ident()?;
652        let kind = match name.name.as_str() {
653            "Never" => TypeKind::Never,
654            "()" => TypeKind::Unit,
655            _ => TypeKind::Named(name.clone()),
656        };
657        Ok(Type {
658            kind,
659            span: name.span,
660        })
661    }
662
663    fn parse_type_bound(&mut self) -> Result<TypeBound, ParseError> {
664        if self.match_kw(Kw::Shape) {
665            return Ok(TypeBound::Shape(self.expect_ident()?));
666        }
667        Ok(TypeBound::Trait(self.expect_ident()?))
668    }
669
670    fn parse_error_type(&mut self) -> Result<ErrorType, ParseError> {
671        let start = self.current_start();
672        self.expect(TokenKind::Bang)?;
673        if self.match_kw(Kw::False) {
674            // !never — use Never keyword path; accept `!never` as ident
675        }
676        let first = self.parse_type()?;
677        let mut variants = vec![first];
678        while self.match_token(TokenKind::Pipe) {
679            variants.push(self.parse_type()?);
680        }
681        Ok(ErrorType {
682            variants,
683            span: Span::new(start, self.previous_end()),
684        })
685    }
686
687    fn parse_optional_generics(&mut self) -> Result<Vec<Ident>, ParseError> {
688        if !self.match_token(TokenKind::Lt) {
689            return Ok(vec![]);
690        }
691        let mut names = vec![self.expect_ident()?];
692        while self.match_token(TokenKind::Comma) {
693            names.push(self.expect_ident()?);
694        }
695        self.expect(TokenKind::Gt)?;
696        Ok(names)
697    }
698
699    fn parse_optional_type_args(&mut self) -> Result<Vec<Type>, ParseError> {
700        if !self.match_token(TokenKind::Lt) {
701            return Ok(vec![]);
702        }
703        let mut args = vec![self.parse_type()?];
704        while self.match_token(TokenKind::Comma) {
705            args.push(self.parse_type()?);
706        }
707        self.expect(TokenKind::Gt)?;
708        Ok(args)
709    }
710
711    // ── Expressions ───────────────────────────────────────────────────────
712
713    fn parse_expr(&mut self) -> Result<Expr, ParseError> {
714        self.parse_pipe()
715    }
716
717    fn parse_pipe(&mut self) -> Result<Expr, ParseError> {
718        let mut left = self.parse_assign()?;
719        while self.match_token(TokenKind::PipeGt) {
720            let right = self.parse_assign()?;
721            let span = left.span.merge(right.span);
722            left = Expr {
723                kind: ExprKind::Pipe {
724                    left: Box::new(left),
725                    right: Box::new(right),
726                },
727                span,
728            };
729        }
730        left = self.parse_catch_suffix(left)?;
731        Ok(left)
732    }
733
734    fn parse_catch_suffix(&mut self, expr: Expr) -> Result<Expr, ParseError> {
735        let mut arms = Vec::new();
736        while self.match_kw(Kw::Catch) {
737            let start = self.previous_start();
738            let pat = self.parse_pat()?;
739            self.expect(TokenKind::Arrow)?;
740            let body = self.parse_pipe()?;
741            let body_end = body.span.end;
742            arms.push(crisp_ast::expr::CatchArm {
743                pat,
744                body,
745                span: Span::new(start, body_end),
746            });
747        }
748        if arms.is_empty() {
749            return Ok(expr);
750        }
751        let expr_start = expr.span.start;
752        let end = arms.last().map(|a| a.span.end).unwrap_or(expr.span.end);
753        Ok(Expr {
754            kind: ExprKind::Catch {
755                body: Box::new(expr),
756                arms,
757            },
758            span: Span::new(expr_start, end),
759        })
760    }
761
762    fn parse_assign(&mut self) -> Result<Expr, ParseError> {
763        let expr = self.parse_or()?;
764        if self.match_token(TokenKind::Assign) {
765            let (name, id_span) = match &expr.kind {
766                ExprKind::Ident(id) => (id.name.clone(), id.span),
767                _ => return Err(self.unexpected("assignable identifier", self.peek_kind())),
768            };
769            let value = self.parse_assign()?;
770            let span = id_span.merge(value.span);
771            return Ok(Expr {
772                kind: ExprKind::Assign {
773                    target: Ident::new(name, id_span),
774                    value: Box::new(value),
775                },
776                span,
777            });
778        }
779        Ok(expr)
780    }
781
782    fn parse_or(&mut self) -> Result<Expr, ParseError> {
783        self.parse_binary(Self::parse_and, TokenKind::Or, BinaryOp::Or)
784    }
785
786    fn parse_and(&mut self) -> Result<Expr, ParseError> {
787        self.parse_binary(Self::parse_equality, TokenKind::And, BinaryOp::And)
788    }
789
790    fn parse_equality(&mut self) -> Result<Expr, ParseError> {
791        let mut left = self.parse_comparison()?;
792        while matches!(self.peek_kind(), TokenKind::EqEq | TokenKind::Ne) {
793            let op = match self.advance().kind {
794                TokenKind::EqEq => BinaryOp::Eq,
795                TokenKind::Ne => BinaryOp::Ne,
796                _ => unreachable!(),
797            };
798            let right = self.parse_comparison()?;
799            let span = left.span.merge(right.span);
800            left = Expr {
801                kind: ExprKind::Binary {
802                    op,
803                    left: Box::new(left),
804                    right: Box::new(right),
805                },
806                span,
807            };
808        }
809        Ok(left)
810    }
811
812    fn parse_comparison(&mut self) -> Result<Expr, ParseError> {
813        let mut left = self.parse_concat()?;
814        while matches!(
815            self.peek_kind(),
816            TokenKind::Lt | TokenKind::Le | TokenKind::Gt | TokenKind::Ge
817        ) {
818            let op = match self.advance().kind {
819                TokenKind::Lt => BinaryOp::Lt,
820                TokenKind::Le => BinaryOp::Le,
821                TokenKind::Gt => BinaryOp::Gt,
822                TokenKind::Ge => BinaryOp::Ge,
823                _ => unreachable!(),
824            };
825            let right = self.parse_concat()?;
826            let span = left.span.merge(right.span);
827            left = Expr {
828                kind: ExprKind::Binary {
829                    op,
830                    left: Box::new(left),
831                    right: Box::new(right),
832                },
833                span,
834            };
835        }
836        Ok(left)
837    }
838
839    fn parse_concat(&mut self) -> Result<Expr, ParseError> {
840        self.parse_binary(Self::parse_additive, TokenKind::PlusPlus, BinaryOp::Concat)
841    }
842
843    fn parse_additive(&mut self) -> Result<Expr, ParseError> {
844        let mut left = self.parse_multiplicative()?;
845        loop {
846            let op = match self.peek_kind() {
847                TokenKind::Plus => BinaryOp::Add,
848                TokenKind::Minus => BinaryOp::Sub,
849                _ => break,
850            };
851            self.advance();
852            let right = self.parse_multiplicative()?;
853            let span = left.span.merge(right.span);
854            left = Expr {
855                kind: ExprKind::Binary {
856                    op,
857                    left: Box::new(left),
858                    right: Box::new(right),
859                },
860                span,
861            };
862        }
863        Ok(left)
864    }
865
866    fn parse_multiplicative(&mut self) -> Result<Expr, ParseError> {
867        let mut left = self.parse_power()?;
868        loop {
869            let op = match self.peek_kind() {
870                TokenKind::Star => BinaryOp::Mul,
871                TokenKind::Slash => BinaryOp::Div,
872                TokenKind::Percent => BinaryOp::Mod,
873                _ => break,
874            };
875            self.advance();
876            let right = self.parse_power()?;
877            let span = left.span.merge(right.span);
878            left = Expr {
879                kind: ExprKind::Binary {
880                    op,
881                    left: Box::new(left),
882                    right: Box::new(right),
883                },
884                span,
885            };
886        }
887        Ok(left)
888    }
889
890    fn parse_power(&mut self) -> Result<Expr, ParseError> {
891        let mut left = self.parse_unary()?;
892        if self.match_token(TokenKind::StarStar) {
893            let right = self.parse_power()?;
894            let span = left.span.merge(right.span);
895            left = Expr {
896                kind: ExprKind::Binary {
897                    op: BinaryOp::Pow,
898                    left: Box::new(left),
899                    right: Box::new(right),
900                },
901                span,
902            };
903        }
904        Ok(left)
905    }
906
907    fn parse_unary(&mut self) -> Result<Expr, ParseError> {
908        let start = self.current_start();
909        if self.match_token(TokenKind::Bang) {
910            let expr = self.parse_unary()?;
911            let end = expr.span.end;
912            return Ok(Expr {
913                kind: ExprKind::Unary {
914                    op: UnaryOp::Not,
915                    expr: Box::new(expr),
916                },
917                span: Span::new(start, end),
918            });
919        }
920        if self.match_token(TokenKind::Minus) {
921            let expr = self.parse_unary()?;
922            let end = expr.span.end;
923            return Ok(Expr {
924                kind: ExprKind::Unary {
925                    op: UnaryOp::Neg,
926                    expr: Box::new(expr),
927                },
928                span: Span::new(start, end),
929            });
930        }
931        if self.match_kw(Kw::Async) {
932            let body = self.parse_unary()?;
933            let end = body.span.end;
934            return Ok(Expr {
935                kind: ExprKind::Async(Box::new(body)),
936                span: Span::new(start, end),
937            });
938        }
939        if self.match_kw(Kw::Await) {
940            let body = self.parse_unary()?;
941            let end = body.span.end;
942            return Ok(Expr {
943                kind: ExprKind::Await(Box::new(body)),
944                span: Span::new(start, end),
945            });
946        }
947        if self.match_kw(Kw::Spawn) {
948            let body = self.parse_unary()?;
949            let end = body.span.end;
950            return Ok(Expr {
951                kind: ExprKind::Spawn(Box::new(body)),
952                span: Span::new(start, end),
953            });
954        }
955        if self.match_kw(Kw::Unsafe) {
956            let body = self.parse_unary()?;
957            let end = body.span.end;
958            return Ok(Expr {
959                kind: ExprKind::Unsafe(Box::new(body)),
960                span: Span::new(start, end),
961            });
962        }
963        if self.match_kw(Kw::Return) {
964            let value = if self.check_expr_start() {
965                Some(Box::new(self.parse_expr()?))
966            } else {
967                None
968            };
969            let end = value
970                .as_ref()
971                .map(|v| v.span.end)
972                .unwrap_or(self.previous_end());
973            return Ok(Expr {
974                kind: ExprKind::Return(value),
975                span: Span::new(start, end),
976            });
977        }
978        if self.match_kw(Kw::Break) {
979            let value = if self.check_expr_start() {
980                Some(Box::new(self.parse_expr()?))
981            } else {
982                None
983            };
984            let end = value
985                .as_ref()
986                .map(|v| v.span.end)
987                .unwrap_or(self.previous_end());
988            return Ok(Expr {
989                kind: ExprKind::Break(value),
990                span: Span::new(start, end),
991            });
992        }
993        if self.match_kw(Kw::Continue) {
994            return Ok(Expr {
995                kind: ExprKind::Continue,
996                span: Span::new(start, self.previous_end()),
997            });
998        }
999        if self.match_kw(Kw::Throw) {
1000            let expr = self.parse_unary()?;
1001            let end = expr.span.end;
1002            return Ok(Expr {
1003                kind: ExprKind::Throw(Box::new(expr)),
1004                span: Span::new(start, end),
1005            });
1006        }
1007        self.parse_postfix()
1008    }
1009
1010    fn parse_postfix(&mut self) -> Result<Expr, ParseError> {
1011        let mut expr = self.parse_primary()?;
1012        // `while { … }` followed by `(lo + hi) / 2.0` is a sibling tail, not a call (#96).
1013        if is_control_expr(&expr.kind) {
1014            return Ok(expr);
1015        }
1016        loop {
1017            match self.peek_kind() {
1018                TokenKind::LParen => {
1019                    self.advance();
1020                    let args = self.parse_args()?;
1021                    self.expect(TokenKind::RParen)?;
1022                    let span = expr
1023                        .span
1024                        .merge(Span::new(self.previous_start(), self.previous_end()));
1025                    expr = Expr {
1026                        kind: ExprKind::Call {
1027                            func: Box::new(expr),
1028                            args,
1029                        },
1030                        span,
1031                    };
1032                }
1033                TokenKind::LBrace if self.peek_kind_at(1) == TokenKind::Pipe => {
1034                    let start = self.current_start();
1035                    self.advance();
1036                    let lam = self.parse_lambda(start)?;
1037                    self.expect(TokenKind::RBrace)?;
1038                    let span = expr.span.merge(lam.span);
1039                    expr = match expr.kind {
1040                        ExprKind::Call { func, mut args } => {
1041                            args.push(lam);
1042                            Expr {
1043                                kind: ExprKind::Call { func, args },
1044                                span,
1045                            }
1046                        }
1047                        kind => Expr {
1048                            kind: ExprKind::Call {
1049                                func: Box::new(Expr {
1050                                    kind,
1051                                    span: expr.span,
1052                                }),
1053                                args: vec![lam],
1054                            },
1055                            span,
1056                        },
1057                    };
1058                }
1059                TokenKind::Dot => {
1060                    self.advance();
1061                    let field = self.expect_ident()?;
1062                    let span = expr.span.merge(field.span);
1063                    expr = Expr {
1064                        kind: ExprKind::Field {
1065                            base: Box::new(expr),
1066                            field,
1067                        },
1068                        span,
1069                    };
1070                }
1071                TokenKind::LBracket => {
1072                    self.advance();
1073                    let index = self.parse_expr()?;
1074                    self.expect(TokenKind::RBracket)?;
1075                    let span = expr.span.merge(index.span);
1076                    expr = Expr {
1077                        kind: ExprKind::Index {
1078                            base: Box::new(expr),
1079                            index: Box::new(index),
1080                        },
1081                        span,
1082                    };
1083                }
1084                TokenKind::Question => {
1085                    self.advance();
1086                    let span = expr
1087                        .span
1088                        .merge(Span::new(self.previous_start(), self.previous_end()));
1089                    expr = Expr {
1090                        kind: ExprKind::Try(Box::new(expr)),
1091                        span,
1092                    };
1093                }
1094                _ => break,
1095            }
1096        }
1097        Ok(expr)
1098    }
1099}
1100
1101fn is_control_expr(kind: &ExprKind) -> bool {
1102    matches!(
1103        kind,
1104        ExprKind::If { .. }
1105            | ExprKind::Match { .. }
1106            | ExprKind::While { .. }
1107            | ExprKind::For { .. }
1108            | ExprKind::Loop(_)
1109            | ExprKind::Block(_)
1110    )
1111}
1112
1113impl Parser {
1114    fn parse_primary(&mut self) -> Result<Expr, ParseError> {
1115        let start = self.current_start();
1116        match self.peek_kind() {
1117            TokenKind::Int(n) => {
1118                self.advance();
1119                Ok(Expr {
1120                    kind: ExprKind::Int(n),
1121                    span: Span::new(start, self.previous_end()),
1122                })
1123            }
1124            TokenKind::Float(f) => {
1125                self.advance();
1126                Ok(Expr {
1127                    kind: ExprKind::Float(f),
1128                    span: Span::new(start, self.previous_end()),
1129                })
1130            }
1131            TokenKind::String(ref s) => {
1132                self.advance();
1133                Ok(Expr {
1134                    kind: ExprKind::Str(self.parse_string_parts(s, start)?),
1135                    span: Span::new(start, self.previous_end()),
1136                })
1137            }
1138            TokenKind::Char(c) => {
1139                self.advance();
1140                Ok(Expr {
1141                    kind: ExprKind::Char(c),
1142                    span: Span::new(start, self.previous_end()),
1143                })
1144            }
1145            TokenKind::Kw(Kw::True) => {
1146                self.advance();
1147                Ok(Expr {
1148                    kind: ExprKind::Bool(true),
1149                    span: Span::new(start, self.previous_end()),
1150                })
1151            }
1152            TokenKind::Kw(Kw::False) => {
1153                self.advance();
1154                Ok(Expr {
1155                    kind: ExprKind::Bool(false),
1156                    span: Span::new(start, self.previous_end()),
1157                })
1158            }
1159            TokenKind::Kw(Kw::None) => {
1160                self.advance();
1161                Ok(self.parse_none_some_call(false, start)?)
1162            }
1163            TokenKind::Kw(Kw::Some) => {
1164                self.advance();
1165                Ok(self.parse_none_some_call(true, start)?)
1166            }
1167            TokenKind::Ident(_) | TokenKind::Kw(_) => {
1168                if self.match_kw(Kw::If) {
1169                    return self.parse_if_expr(start);
1170                }
1171                if self.match_kw(Kw::Match) {
1172                    return self.parse_match_expr(start);
1173                }
1174                if self.match_kw(Kw::For) {
1175                    return self.parse_for_expr(start);
1176                }
1177                if self.match_kw(Kw::While) {
1178                    return self.parse_while_expr(start);
1179                }
1180                if self.match_kw(Kw::Loop) {
1181                    return self.parse_loop_expr(start);
1182                }
1183                let id = self.expect_ident_or_kw_as_ident()?;
1184                let span = id.span;
1185                // Trailing last-arg lambda: `run { |x| … }` — not a struct literal (#88).
1186                if self.check(TokenKind::LBrace) && self.peek_kind_at(1) == TokenKind::Pipe {
1187                    return Ok(Expr {
1188                        kind: ExprKind::Ident(id),
1189                        span,
1190                    });
1191                }
1192                // struct literal: Name { ... } (disabled in if/while/for heads)
1193                if self.allow_struct_lit && self.check(TokenKind::LBrace) {
1194                    return self.parse_struct_lit(id);
1195                }
1196                Ok(Expr {
1197                    kind: ExprKind::Ident(id),
1198                    span,
1199                })
1200            }
1201            TokenKind::LBrace => Ok(Expr {
1202                kind: ExprKind::Block(self.parse_block()?),
1203                span: Span::new(start, self.previous_end()),
1204            }),
1205            TokenKind::Dot => self.parse_point_free_section(start),
1206            TokenKind::LParen => {
1207                self.advance();
1208                if self.check(TokenKind::RParen) {
1209                    self.advance();
1210                    return Ok(Expr {
1211                        kind: ExprKind::Unit,
1212                        span: Span::new(start, self.previous_end()),
1213                    });
1214                }
1215                if self.check(TokenKind::Pipe)
1216                    || (self.is_ident() && self.peek_kind_at(1) == TokenKind::Pipe)
1217                {
1218                    let lam = self.parse_lambda(start)?;
1219                    self.expect(TokenKind::RParen)?;
1220                    return Ok(lam);
1221                }
1222                let expr = self.parse_expr()?;
1223                self.expect(TokenKind::RParen)?;
1224                Ok(expr)
1225            }
1226            TokenKind::Pipe => self.parse_lambda(start),
1227            TokenKind::Or => {
1228                // `|| expr` lexes as one `Or` token; treat as a nullary lambda.
1229                self.advance();
1230                let body = self.parse_expr()?;
1231                let end = body.span.end;
1232                Ok(Expr {
1233                    kind: ExprKind::Lambda {
1234                        params: Vec::new(),
1235                        body: Box::new(body),
1236                    },
1237                    span: Span::new(start, end),
1238                })
1239            }
1240            _ => Err(self.unexpected("expression", self.peek_kind())),
1241        }
1242    }
1243
1244    fn parse_none_some_call(&mut self, some: bool, start: u32) -> Result<Expr, ParseError> {
1245        if self.match_token(TokenKind::LParen) {
1246            let inner = self.parse_expr()?;
1247            self.expect(TokenKind::RParen)?;
1248            let name = if some { "some" } else { "none" };
1249            return Ok(Expr {
1250                kind: ExprKind::Call {
1251                    func: Box::new(Expr {
1252                        kind: ExprKind::Ident(Ident::new(name, Span::new(start, start))),
1253                        span: Span::new(start, start),
1254                    }),
1255                    args: if some { vec![inner] } else { vec![] },
1256                },
1257                span: Span::new(start, self.previous_end()),
1258            });
1259        }
1260        let name = if some { "some" } else { "none" };
1261        Ok(Expr {
1262            kind: ExprKind::Ident(Ident::new(name, Span::new(start, self.previous_end()))),
1263            span: Span::new(start, self.previous_end()),
1264        })
1265    }
1266
1267    fn parse_lambda(&mut self, start: u32) -> Result<Expr, ParseError> {
1268        self.expect(TokenKind::Pipe)?;
1269        let params = if self.check(TokenKind::Pipe) {
1270            Vec::new()
1271        } else {
1272            self.parse_params()?
1273        };
1274        self.expect(TokenKind::Pipe)?;
1275        let body = self.parse_expr()?;
1276        let end = body.span.end;
1277        Ok(Expr {
1278            kind: ExprKind::Lambda {
1279                params,
1280                body: Box::new(body),
1281            },
1282            span: Span::new(start, end),
1283        })
1284    }
1285
1286    fn parse_if_expr(&mut self, start: u32) -> Result<Expr, ParseError> {
1287        let cond = self.with_no_struct_lit(|p| p.parse_expr())?;
1288        let then_branch = if self.match_kw(Kw::Then) {
1289            Box::new(self.parse_expr()?)
1290        } else {
1291            Box::new(Expr {
1292                kind: ExprKind::Block(self.parse_block()?),
1293                span: Span::new(self.current_start(), self.previous_end()),
1294            })
1295        };
1296        let else_branch = if self.match_kw(Kw::Else) {
1297            if self.check(TokenKind::Kw(Kw::If)) {
1298                Some(Box::new(self.parse_if_expr(self.current_start())?))
1299            } else if self.check(TokenKind::LBrace) {
1300                Some(Box::new(Expr {
1301                    kind: ExprKind::Block(self.parse_block()?),
1302                    span: Span::new(self.current_start(), self.previous_end()),
1303                }))
1304            } else {
1305                Some(Box::new(self.parse_expr()?))
1306            }
1307        } else {
1308            None
1309        };
1310        let end = else_branch
1311            .as_ref()
1312            .map(|e| e.span.end)
1313            .unwrap_or(then_branch.span.end);
1314        Ok(Expr {
1315            kind: ExprKind::If {
1316                cond: Box::new(cond),
1317                then_branch,
1318                else_branch,
1319            },
1320            span: Span::new(start, end),
1321        })
1322    }
1323
1324    fn parse_match_expr(&mut self, start: u32) -> Result<Expr, ParseError> {
1325        let scrutinee = self.parse_match_scrutinee()?;
1326        self.expect(TokenKind::LBrace)?;
1327        let mut arms = Vec::new();
1328        while !self.check(TokenKind::RBrace) {
1329            arms.push(self.parse_match_arm()?);
1330        }
1331        self.expect(TokenKind::RBrace)?;
1332        Ok(Expr {
1333            kind: ExprKind::Match {
1334                scrutinee: Box::new(scrutinee),
1335                arms,
1336            },
1337            span: Span::new(start, self.previous_end()),
1338        })
1339    }
1340
1341    /// Scrutinee parsing that does not treat `name {` as a struct literal.
1342    /// `match color { … }` would otherwise consume `color { … }` as `StructLit`.
1343    fn parse_match_scrutinee(&mut self) -> Result<Expr, ParseError> {
1344        if matches!(self.peek_kind(), TokenKind::Ident(_))
1345            && matches!(self.peek_kind_at(1), TokenKind::LBrace)
1346        {
1347            let id = self.expect_ident()?;
1348            return Ok(Expr {
1349                kind: ExprKind::Ident(id.clone()),
1350                span: id.span,
1351            });
1352        }
1353        self.parse_expr()
1354    }
1355
1356    fn parse_match_arm(&mut self) -> Result<MatchArm, ParseError> {
1357        let start = self.current_start();
1358        let pat = self.parse_pat()?;
1359        let guard = if self.match_kw(Kw::If) {
1360            Some(self.parse_expr()?)
1361        } else {
1362            None
1363        };
1364        if !self.match_token(TokenKind::Arrow) {
1365            return Err(ParseError::Unexpected {
1366                expected: "`->`",
1367                found: self.peek_kind(),
1368                pos: self.current_start(),
1369                help: Some(
1370                    "if the match scrutinee is a struct literal, wrap it in parentheses: \
1371match (Name { field: value }) { ... }",
1372                ),
1373            });
1374        }
1375        let body = self.parse_expr()?;
1376        let end = body.span.end;
1377        Ok(MatchArm {
1378            pat,
1379            guard,
1380            body,
1381            span: Span::new(start, end),
1382        })
1383    }
1384
1385    fn parse_for_expr(&mut self, start: u32) -> Result<Expr, ParseError> {
1386        let pat = self.parse_pat()?;
1387        self.expect_kw(Kw::In)?;
1388        let iter = self.with_no_struct_lit(|p| p.parse_expr())?;
1389        let body = Expr {
1390            kind: ExprKind::Block(self.parse_block()?),
1391            span: Span::new(self.current_start(), self.previous_end()),
1392        };
1393        let end = body.span.end;
1394        Ok(Expr {
1395            kind: ExprKind::For {
1396                pat,
1397                iter: Box::new(iter),
1398                body: Box::new(body),
1399            },
1400            span: Span::new(start, end),
1401        })
1402    }
1403
1404    fn parse_while_expr(&mut self, start: u32) -> Result<Expr, ParseError> {
1405        let cond = self.with_no_struct_lit(|p| p.parse_expr())?;
1406        let body = Expr {
1407            kind: ExprKind::Block(self.parse_block()?),
1408            span: Span::new(self.current_start(), self.previous_end()),
1409        };
1410        let end = body.span.end;
1411        Ok(Expr {
1412            kind: ExprKind::While {
1413                cond: Box::new(cond),
1414                body: Box::new(body),
1415            },
1416            span: Span::new(start, end),
1417        })
1418    }
1419
1420    fn parse_loop_expr(&mut self, start: u32) -> Result<Expr, ParseError> {
1421        let body = Expr {
1422            kind: ExprKind::Block(self.parse_block()?),
1423            span: Span::new(self.current_start(), self.previous_end()),
1424        };
1425        let end = body.span.end;
1426        Ok(Expr {
1427            kind: ExprKind::Loop(Box::new(body)),
1428            span: Span::new(start, end),
1429        })
1430    }
1431
1432    fn parse_struct_lit(&mut self, name: Ident) -> Result<Expr, ParseError> {
1433        let start = name.span.start;
1434        self.expect(TokenKind::LBrace)?;
1435        let mut fields = Vec::new();
1436        while !self.check(TokenKind::RBrace) {
1437            let s = self.current_start();
1438            let fname = self.expect_ident()?;
1439            self.expect(TokenKind::Colon)?;
1440            let value = self.parse_expr()?;
1441            fields.push(FieldInit {
1442                name: fname,
1443                value,
1444                span: Span::new(s, self.previous_end()),
1445            });
1446        }
1447        self.expect(TokenKind::RBrace)?;
1448        Ok(Expr {
1449            kind: ExprKind::StructLit { name, fields },
1450            span: Span::new(start, self.previous_end()),
1451        })
1452    }
1453
1454    fn parse_block(&mut self) -> Result<Block, ParseError> {
1455        let start = self.current_start();
1456        self.expect(TokenKind::LBrace)?;
1457        let mut stmts = Vec::new();
1458        let mut tail = None;
1459        while !self.check(TokenKind::RBrace) && !self.check(TokenKind::Eof) {
1460            let saved = self.pos;
1461            if let Ok(stmt) = self.try_parse_binding_stmt() {
1462                stmts.push(stmt);
1463                continue;
1464            }
1465            self.pos = saved;
1466
1467            if self.is_ident() && self.peek_kind_at(1) == TokenKind::Assign {
1468                let target = self.expect_ident()?;
1469                self.advance();
1470                let value = self.parse_expr()?;
1471                stmts.push(Stmt::Assign { target, value });
1472                continue;
1473            }
1474
1475            let expr = self.parse_expr()?;
1476            if self.check(TokenKind::RBrace) {
1477                tail = Some(Box::new(expr));
1478                break;
1479            }
1480            stmts.push(Stmt::Expr(expr));
1481        }
1482        self.expect(TokenKind::RBrace)?;
1483        Ok(Block {
1484            stmts,
1485            tail,
1486            span: Span::new(start, self.previous_end()),
1487        })
1488    }
1489
1490    fn try_parse_binding_stmt(&mut self) -> Result<Stmt, ParseError> {
1491        let pat = self.parse_pat()?;
1492        let mutable = if self.match_token(TokenKind::MutColonEq) {
1493            true
1494        } else if self.match_token(TokenKind::ColonEq) {
1495            false
1496        } else {
1497            return Err(ParseError::Unexpected {
1498                expected: "`:=` or `mut:`=",
1499                found: self.peek_kind(),
1500                pos: self.current_start(),
1501                help: None,
1502            });
1503        };
1504        let value = self.parse_expr()?;
1505        Ok(Stmt::Bind {
1506            pat,
1507            mutable,
1508            value,
1509        })
1510    }
1511
1512    // ── Patterns ──────────────────────────────────────────────────────────
1513
1514    fn parse_pat(&mut self) -> Result<Pat, ParseError> {
1515        let start = self.current_start();
1516        if let TokenKind::Ident(name) = self.peek_kind()
1517            && name == "_"
1518        {
1519            self.advance();
1520            return Ok(Pat {
1521                kind: PatKind::Wildcard,
1522                span: Span::new(start, self.previous_end()),
1523            });
1524        }
1525        if self.is_int() || self.is_string() {
1526            let expr = self.parse_primary()?;
1527            return Ok(Pat {
1528                kind: PatKind::Literal(Box::new(expr)),
1529                span: Span::new(start, self.previous_end()),
1530            });
1531        }
1532        if self.match_token(TokenKind::LParen) {
1533            if self.check(TokenKind::RParen) {
1534                self.advance();
1535                return Ok(Pat {
1536                    kind: PatKind::Literal(Box::new(Expr {
1537                        kind: ExprKind::Unit,
1538                        span: Span::new(start, self.previous_end()),
1539                    })),
1540                    span: Span::new(start, self.previous_end()),
1541                });
1542            }
1543            let mut pats = vec![self.parse_pat()?];
1544            while self.match_token(TokenKind::Comma) {
1545                pats.push(self.parse_pat()?);
1546            }
1547            self.expect(TokenKind::RParen)?;
1548            return Ok(Pat {
1549                kind: PatKind::Tuple(pats),
1550                span: Span::new(start, self.previous_end()),
1551            });
1552        }
1553        if self.match_token(TokenKind::LBrace) {
1554            let name = self.expect_ident()?;
1555            let mut fields = Vec::new();
1556            let mut rest = None;
1557            while !self.check(TokenKind::RBrace) {
1558                if self.match_token(TokenKind::DotDot) {
1559                    rest = Some(self.expect_ident()?);
1560                    break;
1561                }
1562                let fname = self.expect_ident()?;
1563                let pat = if self.match_token(TokenKind::Colon) {
1564                    Some(self.parse_pat()?)
1565                } else {
1566                    None
1567                };
1568                fields.push(FieldPat {
1569                    name: fname,
1570                    pat,
1571                    span: Span::new(start, self.previous_end()),
1572                });
1573            }
1574            self.expect(TokenKind::RBrace)?;
1575            return Ok(Pat {
1576                kind: PatKind::Struct { name, fields, rest },
1577                span: Span::new(start, self.previous_end()),
1578            });
1579        }
1580        let name = self.expect_ident()?;
1581        // Qualified enum pattern: Color.Red / Color.Custom(r, g, b)
1582        if self.match_token(TokenKind::Dot) {
1583            let variant = self.expect_ident()?;
1584            let args = if self.match_token(TokenKind::LParen) {
1585                let mut args = Vec::new();
1586                while !self.check(TokenKind::RParen) {
1587                    args.push(self.parse_pat()?);
1588                    if !self.match_token(TokenKind::Comma) {
1589                        break;
1590                    }
1591                }
1592                self.expect(TokenKind::RParen)?;
1593                args
1594            } else {
1595                vec![]
1596            };
1597            return Ok(Pat {
1598                kind: PatKind::Enum {
1599                    name,
1600                    variant,
1601                    args,
1602                },
1603                span: Span::new(start, self.previous_end()),
1604            });
1605        }
1606        // Unqualified ctor pattern: Custom(r, g, b) — variant name equals type slot
1607        if self.match_token(TokenKind::LParen) {
1608            let mut args = Vec::new();
1609            while !self.check(TokenKind::RParen) {
1610                args.push(self.parse_pat()?);
1611                if !self.match_token(TokenKind::Comma) {
1612                    break;
1613                }
1614            }
1615            self.expect(TokenKind::RParen)?;
1616            return Ok(Pat {
1617                kind: PatKind::Enum {
1618                    name: name.clone(),
1619                    variant: name,
1620                    args,
1621                },
1622                span: Span::new(start, self.previous_end()),
1623            });
1624        }
1625        Ok(Pat {
1626            kind: PatKind::Ident(name),
1627            span: Span::new(start, self.previous_end()),
1628        })
1629    }
1630
1631    // ── Helpers ───────────────────────────────────────────────────────────
1632
1633    fn parse_binary<F>(
1634        &mut self,
1635        mut next: F,
1636        tok: TokenKind,
1637        op: BinaryOp,
1638    ) -> Result<Expr, ParseError>
1639    where
1640        F: FnMut(&mut Self) -> Result<Expr, ParseError>,
1641    {
1642        let mut left = next(self)?;
1643        while self.check(tok.clone()) {
1644            self.advance();
1645            let right = next(self)?;
1646            let span = left.span.merge(right.span);
1647            left = Expr {
1648                kind: ExprKind::Binary {
1649                    op,
1650                    left: Box::new(left),
1651                    right: Box::new(right),
1652                },
1653                span,
1654            };
1655        }
1656        Ok(left)
1657    }
1658
1659    fn parse_string_parts(&mut self, s: &str, start: u32) -> Result<StringParts, ParseError> {
1660        let mut parts = Vec::new();
1661        let mut lit = String::new();
1662        let inner_base = start.saturating_add(1); // skip opening `"`
1663        let mut byte_i = 0usize;
1664        while byte_i < s.len() {
1665            let Some(c) = s[byte_i..].chars().next() else {
1666                break;
1667            };
1668            if c == '{' {
1669                if !lit.is_empty() {
1670                    parts.push(StringPart::Lit(std::mem::take(&mut lit)));
1671                }
1672                let expr_start = byte_i + c.len_utf8();
1673                let mut depth = 1i32;
1674                let mut expr_end = expr_start;
1675                while expr_end < s.len() {
1676                    let Some(ch) = s[expr_end..].chars().next() else {
1677                        break;
1678                    };
1679                    if ch == '{' {
1680                        depth += 1;
1681                    }
1682                    if ch == '}' {
1683                        depth -= 1;
1684                        if depth == 0 {
1685                            break;
1686                        }
1687                    }
1688                    expr_end += ch.len_utf8();
1689                }
1690                let expr_text = &s[expr_start..expr_end];
1691                let expr_base = inner_base.saturating_add(expr_start as u32);
1692                let mut sub = Parser::with_span_base(expr_text, expr_base)?;
1693                let expr = sub.parse_expr()?;
1694                parts.push(StringPart::Expr(Box::new(expr)));
1695                byte_i = if expr_end < s.len() {
1696                    expr_end + 1
1697                } else {
1698                    expr_end
1699                };
1700            } else {
1701                lit.push(c);
1702                byte_i += c.len_utf8();
1703            }
1704        }
1705        if !lit.is_empty() {
1706            parts.push(StringPart::Lit(lit));
1707        }
1708        if parts.is_empty() {
1709            parts.push(StringPart::Lit(String::new()));
1710        }
1711        Ok(StringParts(parts))
1712    }
1713
1714    fn parse_args(&mut self) -> Result<Vec<Expr>, ParseError> {
1715        let mut args = Vec::new();
1716        if self.check(TokenKind::RParen) {
1717            return Ok(args);
1718        }
1719        loop {
1720            args.push(self.parse_expr()?);
1721            if !self.match_token(TokenKind::Comma) {
1722                break;
1723            }
1724        }
1725        Ok(args)
1726    }
1727
1728    fn is_ident(&self) -> bool {
1729        matches!(self.peek_kind(), TokenKind::Ident(_))
1730    }
1731
1732    fn is_int(&self) -> bool {
1733        matches!(self.peek_kind(), TokenKind::Int(_))
1734    }
1735
1736    fn is_string(&self) -> bool {
1737        matches!(self.peek_kind(), TokenKind::String(_))
1738    }
1739
1740    fn check_expr_start(&self) -> bool {
1741        !matches!(
1742            self.peek_kind(),
1743            TokenKind::RBrace | TokenKind::Eof | TokenKind::RParen
1744        )
1745    }
1746
1747    fn check_lifetime(&self) -> bool {
1748        matches!(self.peek_kind(), TokenKind::Lifetime(_))
1749    }
1750
1751    fn parse_lifetime_ident(&mut self) -> Result<Ident, ParseError> {
1752        let t = self.advance();
1753        let TokenKind::Lifetime(name) = t.kind else {
1754            return Err(self.unexpected("lifetime", t.kind));
1755        };
1756        Ok(Ident::new(name, Span::new(t.start, t.end)))
1757    }
1758
1759    fn expect_ident(&mut self) -> Result<Ident, ParseError> {
1760        let t = self.advance();
1761        match t.kind {
1762            TokenKind::Ident(name) => Ok(Ident::new(name, Span::new(t.start, t.end))),
1763            other => Err(ParseError::Unexpected {
1764                expected: "identifier",
1765                found: other,
1766                pos: t.start,
1767                help: None,
1768            }),
1769        }
1770    }
1771
1772    fn expect_ident_or_kw_as_ident(&mut self) -> Result<Ident, ParseError> {
1773        self.expect_ident()
1774    }
1775
1776    fn expect_string_lit(&mut self) -> Result<String, ParseError> {
1777        let t = self.advance();
1778        match t.kind {
1779            TokenKind::String(s) => Ok(s),
1780            other => Err(ParseError::Unexpected {
1781                expected: "string literal",
1782                found: other,
1783                pos: t.start,
1784                help: None,
1785            }),
1786        }
1787    }
1788
1789    fn expect_kw(&mut self, kw: Kw) -> Result<(), ParseError> {
1790        if self.match_kw(kw) {
1791            Ok(())
1792        } else {
1793            Err(self.unexpected(
1794                std::str::from_utf8(kw_bytes(kw)).unwrap_or("keyword"),
1795                self.peek_kind(),
1796            ))
1797        }
1798    }
1799
1800    fn expect(&mut self, kind: TokenKind) -> Result<(), ParseError> {
1801        if self.match_token(kind.clone()) {
1802            Ok(())
1803        } else {
1804            Err(self.unexpected("token", self.peek_kind()))
1805        }
1806    }
1807
1808    fn match_kw(&mut self, kw: Kw) -> bool {
1809        if matches!(self.peek_kind(), TokenKind::Kw(k) if k == kw) {
1810            self.advance();
1811            true
1812        } else {
1813            false
1814        }
1815    }
1816
1817    fn match_kw_opt(&mut self) -> Option<Kw> {
1818        if let TokenKind::Kw(kw) = self.peek_kind() {
1819            let k = kw;
1820            self.advance();
1821            Some(k)
1822        } else {
1823            None
1824        }
1825    }
1826
1827    fn match_token(&mut self, kind: TokenKind) -> bool {
1828        if self.check(kind.clone()) {
1829            self.advance();
1830            true
1831        } else {
1832            false
1833        }
1834    }
1835
1836    /// Path separator `::` (two `Colon` tokens), for `use rust::serde_json { … }`.
1837    fn match_colon_colon(&mut self) -> bool {
1838        if self.check(TokenKind::Colon) && self.peek_kind_at(1) == TokenKind::Colon {
1839            self.advance();
1840            self.advance();
1841            true
1842        } else {
1843            false
1844        }
1845    }
1846
1847    fn check(&self, kind: TokenKind) -> bool {
1848        self.peek_kind() == kind
1849    }
1850
1851    fn peek_kind(&self) -> TokenKind {
1852        self.tokens
1853            .get(self.pos)
1854            .map(|t| t.kind.clone())
1855            .unwrap_or(TokenKind::Eof)
1856    }
1857
1858    fn peek_kind_at(&self, offset: usize) -> TokenKind {
1859        self.tokens
1860            .get(self.pos + offset)
1861            .map(|t| t.kind.clone())
1862            .unwrap_or(TokenKind::Eof)
1863    }
1864
1865    fn advance(&mut self) -> Token {
1866        let t = self.tokens[self.pos].clone();
1867        if !matches!(t.kind, TokenKind::Eof) {
1868            self.pos += 1;
1869        }
1870        t
1871    }
1872
1873    fn current_start(&self) -> u32 {
1874        self.tokens.get(self.pos).map(|t| t.start).unwrap_or(0)
1875    }
1876
1877    fn previous_start(&self) -> u32 {
1878        if self.pos == 0 {
1879            0
1880        } else {
1881            self.tokens[self.pos - 1].start
1882        }
1883    }
1884
1885    fn previous_end(&self) -> u32 {
1886        if self.pos == 0 {
1887            0
1888        } else {
1889            self.tokens[self.pos - 1].end
1890        }
1891    }
1892
1893    fn previous_span(&self) -> Span {
1894        Span::new(self.previous_start(), self.previous_end())
1895    }
1896
1897    /// Point-free section (#89): `.name` → `|_sec| _sec.name`;
1898    /// `.magnitude()` / `.scale(2.0)` → `|_sec| _sec.magnitude()` / `|_sec| _sec.scale(2.0)`.
1899    /// Extra method args are baked into the section; they are not extra lambda params.
1900    fn parse_point_free_section(&mut self, start: u32) -> Result<Expr, ParseError> {
1901        self.advance();
1902        let field = self.expect_ident()?;
1903        let recv = Ident::new("_sec", Span::new(start, field.span.end));
1904        let field_expr = Expr {
1905            kind: ExprKind::Field {
1906                base: Box::new(Expr {
1907                    kind: ExprKind::Ident(recv.clone()),
1908                    span: recv.span,
1909                }),
1910                field,
1911            },
1912            span: Span::new(start, self.previous_end()),
1913        };
1914        let body = if self.check(TokenKind::LParen) {
1915            self.advance();
1916            let args = self.parse_args()?;
1917            self.expect(TokenKind::RParen)?;
1918            Expr {
1919                kind: ExprKind::Call {
1920                    func: Box::new(field_expr),
1921                    args,
1922                },
1923                span: Span::new(start, self.previous_end()),
1924            }
1925        } else {
1926            field_expr
1927        };
1928        let span = Span::new(start, self.previous_end());
1929        Ok(Expr {
1930            kind: ExprKind::Lambda {
1931                params: vec![Param {
1932                    lifetime: None,
1933                    ownership: None,
1934                    name: recv,
1935                    ty: None,
1936                    span,
1937                }],
1938                body: Box::new(body),
1939            },
1940            span,
1941        })
1942    }
1943
1944    fn unexpected(&self, expected: &'static str, found: TokenKind) -> ParseError {
1945        ParseError::Unexpected {
1946            expected,
1947            found,
1948            pos: self.current_start(),
1949            help: None,
1950        }
1951    }
1952}
1953
1954fn kw_bytes(_kw: Kw) -> &'static [u8] {
1955    b"keyword"
1956}
1957
1958trait ItemSpan {
1959    fn span(&self) -> Span;
1960}
1961
1962impl ItemSpan for Item {
1963    fn span(&self) -> Span {
1964        match self {
1965            Item::Function(f) => f.span,
1966            Item::TypeDef(t) => t.span,
1967            Item::TraitDef(t) => t.span,
1968            Item::ShapeDef(s) => s.span,
1969            Item::Impl(i) => i.span,
1970            Item::Use(u) => u.span,
1971            Item::Const(c) => c.span,
1972            Item::Extern(e) => e.span,
1973            Item::Test(t) => t.span,
1974            Item::TestCompileFail(t) => t.span,
1975        }
1976    }
1977}