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