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