Skip to main content

rexlang_parser/parser/
mod.rs

1//! Parser implementation for Rex.
2
3use std::{
4    collections::{BTreeMap, HashSet, VecDeque},
5    sync::Arc,
6    vec,
7};
8
9use rexlang_ast::expr::{
10    ClassDecl, ClassMethodSig, Decl, DeclareFnDecl, Expr, FnDecl, ImportClause, ImportDecl,
11    ImportItem, ImportPath, InstanceDecl, InstanceMethodImpl, NameRef, Pattern, Program, Scope,
12    Symbol, TypeConstraint, TypeDecl, TypeExpr, TypeVariant, Var, intern,
13};
14use rexlang_lexer::{
15    Token, Tokens,
16    span::{Position, Span, Spanned},
17};
18
19use crate::{error::ParserErr, op::Operator};
20use rexlang_util::GasMeter;
21
22pub struct Parser {
23    token_cursor: usize,
24    tokens: Vec<Token>,
25    eof: Span,
26    errors: Vec<ParserErr>,
27    limits: ParserLimits,
28    nesting_depth: usize,
29}
30
31#[derive(Clone, Copy, Debug)]
32pub struct ParserLimits {
33    pub max_nesting: Option<usize>,
34}
35
36impl ParserLimits {
37    pub fn unlimited() -> Self {
38        Self { max_nesting: None }
39    }
40
41    pub fn safe_defaults() -> Self {
42        Self {
43            max_nesting: Some(512),
44        }
45    }
46}
47
48impl Default for ParserLimits {
49    fn default() -> Self {
50        Self::unlimited()
51    }
52}
53
54impl Parser {
55    fn operator_token_name(token: &Token) -> Option<(&'static str, Span)> {
56        match token {
57            Token::Add(span, ..) => Some(("+", *span)),
58            Token::And(span, ..) => Some(("&&", *span)),
59            Token::Concat(span, ..) => Some(("++", *span)),
60            Token::Div(span, ..) => Some(("/", *span)),
61            Token::Eq(span, ..) => Some(("==", *span)),
62            Token::Ne(span, ..) => Some(("!=", *span)),
63            Token::Ge(span, ..) => Some((">=", *span)),
64            Token::Gt(span, ..) => Some((">", *span)),
65            Token::Le(span, ..) => Some(("<=", *span)),
66            Token::Lt(span, ..) => Some(("<", *span)),
67            Token::Mod(span, ..) => Some(("%", *span)),
68            Token::Mul(span, ..) => Some(("*", *span)),
69            Token::Or(span, ..) => Some(("||", *span)),
70            Token::Sub(span, ..) => Some(("-", *span)),
71            _ => None,
72        }
73    }
74
75    fn parse_value_name(&mut self) -> Result<(Symbol, Span), ParserErr> {
76        match self.current_token() {
77            Token::Ident(name, span, ..) => {
78                self.next_token();
79                Ok((intern(&name), span))
80            }
81            token => {
82                if let Some((name, span)) = Self::operator_token_name(&token) {
83                    self.next_token();
84                    Ok((intern(name), span))
85                } else {
86                    Err(ParserErr::new(
87                        *token.span(),
88                        format!("expected identifier or operator name got {}", token),
89                    ))
90                }
91            }
92        }
93    }
94
95    pub fn new(tokens: Tokens) -> Parser {
96        let mut parser = Parser {
97            token_cursor: 0,
98            tokens: tokens
99                .items
100                .into_iter()
101                .filter_map(|token| match token {
102                    Token::Whitespace(..) => None,
103                    token => Some(token),
104                })
105                .collect(),
106            eof: tokens.eof,
107            errors: Vec::new(),
108            limits: ParserLimits::default(),
109            nesting_depth: 0,
110        };
111        // println!("tokens = {:#?}", parser.tokens);
112        parser.strip_comments();
113        parser
114    }
115
116    pub fn set_limits(&mut self, limits: ParserLimits) {
117        self.limits = limits;
118    }
119
120    fn with_nesting<T>(
121        &mut self,
122        span: Span,
123        f: impl FnOnce(&mut Self) -> Result<T, ParserErr>,
124    ) -> Result<T, ParserErr> {
125        if let Some(max) = self.limits.max_nesting
126            && self.nesting_depth >= max
127        {
128            return Err(ParserErr::new(
129                span,
130                format!("maximum nesting depth exceeded (max {max})"),
131            ));
132        }
133        self.nesting_depth += 1;
134        let res = f(self);
135        self.nesting_depth = self.nesting_depth.saturating_sub(1);
136        res
137    }
138
139    fn skip_newlines(&mut self) {
140        while self.token_cursor < self.tokens.len() {
141            if matches!(self.tokens[self.token_cursor], Token::WhitespaceNewline(..)) {
142                self.token_cursor += 1;
143                continue;
144            }
145            break;
146        }
147    }
148
149    fn current_token(&mut self) -> Token {
150        self.skip_newlines();
151        if self.token_cursor < self.tokens.len() {
152            return self.tokens[self.token_cursor].clone();
153        }
154        Token::Eof(self.eof)
155    }
156
157    fn peek_token(&mut self, n: usize) -> Token {
158        self.skip_newlines();
159        let mut cursor = self.token_cursor;
160        let mut seen = 0usize;
161        while cursor < self.tokens.len() {
162            if matches!(self.tokens[cursor], Token::WhitespaceNewline(..)) {
163                cursor += 1;
164                continue;
165            }
166            if seen == n {
167                return self.tokens[cursor].clone();
168            }
169            seen += 1;
170            cursor += 1;
171        }
172        Token::Eof(self.eof)
173    }
174
175    fn next_token(&mut self) {
176        self.token_cursor += 1;
177        self.skip_newlines();
178    }
179
180    fn expect_colon(&mut self) -> Result<(), ParserErr> {
181        let token = self.current_token();
182        match token {
183            Token::Colon(..) => {
184                self.next_token();
185                Ok(())
186            }
187            token => Err(ParserErr::new(
188                *token.span(),
189                format!("expected `:` got {}", token),
190            )),
191        }
192    }
193
194    fn expect_assign(&mut self) -> Result<(), ParserErr> {
195        let token = self.current_token();
196        match token {
197            Token::Assign(..) => {
198                self.next_token();
199                Ok(())
200            }
201            token => Err(ParserErr::new(
202                *token.span(),
203                format!("expected `=` got {}", token),
204            )),
205        }
206    }
207
208    fn expect_paren_r(&mut self) -> Result<Span, ParserErr> {
209        let token = self.current_token();
210        match token {
211            Token::ParenR(span, ..) => {
212                self.next_token();
213                Ok(span)
214            }
215            token => Err(ParserErr::new(
216                *token.span(),
217                format!("expected `)` got {}", token),
218            )),
219        }
220    }
221
222    fn expect_ident(&mut self, what: &str) -> Result<(String, Span), ParserErr> {
223        match self.current_token() {
224            Token::Ident(name, span, ..) => {
225                self.next_token();
226                Ok((name, span))
227            }
228            token => Err(ParserErr::new(
229                *token.span(),
230                format!("expected {what} got {}", token),
231            )),
232        }
233    }
234
235    fn is_value_name_token(token: &Token) -> bool {
236        matches!(token, Token::Ident(..)) || Self::operator_token_name(token).is_some()
237    }
238
239    fn parse_layout_block<T>(
240        &mut self,
241        has_block: bool,
242        block_indent: Option<usize>,
243        mut parse_item: impl FnMut(&mut Self) -> Result<T, ParserErr>,
244    ) -> Result<Vec<T>, ParserErr> {
245        if !has_block {
246            return Ok(Vec::new());
247        }
248
249        let mut items = Vec::new();
250        loop {
251            let token = self.current_token();
252            if !Self::is_value_name_token(&token) {
253                break;
254            }
255            let span = *token.span();
256            if let Some(indent) = block_indent
257                && span.begin.column != indent
258            {
259                break;
260            }
261            items.push(parse_item(self)?);
262        }
263        Ok(items)
264    }
265
266    fn find_token_at_depth0(
267        &self,
268        start: usize,
269        end: usize,
270        mut matches: impl FnMut(&Token) -> bool,
271    ) -> Option<usize> {
272        let mut depth = 0usize;
273        let end = end.min(self.tokens.len());
274        for i in start..end {
275            match &self.tokens[i] {
276                Token::ParenL(..) | Token::BracketL(..) | Token::BraceL(..) => depth += 1,
277                Token::ParenR(..) | Token::BracketR(..) | Token::BraceR(..) => {
278                    depth = depth.saturating_sub(1)
279                }
280                _ => {}
281            }
282            if depth == 0 && matches(&self.tokens[i]) {
283                return Some(i);
284            }
285        }
286        None
287    }
288
289    fn find_same_line_end(&self, start_idx: usize) -> Result<usize, ParserErr> {
290        let start_line = self
291            .tokens
292            .get(start_idx)
293            .ok_or_else(|| ParserErr::new(self.eof, "unexpected EOF".to_string()))?
294            .span()
295            .begin
296            .line;
297
298        let mut depth = 0usize;
299        let mut end_idx = start_idx;
300        for i in start_idx..self.tokens.len() {
301            let tok = &self.tokens[i];
302            if depth == 0 && tok.span().begin.line > start_line {
303                break;
304            }
305            match tok {
306                Token::ParenL(..) | Token::BracketL(..) | Token::BraceL(..) => depth += 1,
307                Token::ParenR(..) | Token::BracketR(..) | Token::BraceR(..) => {
308                    depth = depth.saturating_sub(1)
309                }
310                _ => {}
311            }
312            end_idx = i + 1;
313        }
314        Ok(end_idx)
315    }
316
317    fn find_dedent_end(&self, start_idx: usize, base_indent: usize) -> Result<usize, ParserErr> {
318        let mut depth = 0usize;
319        let mut end_idx = start_idx;
320        for i in start_idx..self.tokens.len() {
321            let tok = &self.tokens[i];
322            match tok {
323                Token::ParenL(..) | Token::BracketL(..) | Token::BraceL(..) => depth += 1,
324                Token::ParenR(..) | Token::BracketR(..) | Token::BraceR(..) => {
325                    depth = depth.saturating_sub(1)
326                }
327                Token::WhitespaceNewline(..) if depth == 0 => {
328                    let mut j = i + 1;
329                    while j < self.tokens.len()
330                        && matches!(self.tokens[j], Token::WhitespaceNewline(..))
331                    {
332                        j += 1;
333                    }
334                    if j >= self.tokens.len() {
335                        return Ok(i);
336                    }
337                    if self.tokens[j].span().begin.column <= base_indent {
338                        return Ok(i);
339                    }
340                }
341                _ => {}
342            }
343            end_idx = i + 1;
344        }
345        Ok(end_idx)
346    }
347
348    fn paren_group_has_top_level_comma(&self, paren_start: usize) -> bool {
349        let mut depth = 0usize;
350        for i in (paren_start + 1)..self.tokens.len() {
351            match self.tokens[i] {
352                Token::ParenL(..) | Token::BracketL(..) | Token::BraceL(..) => depth += 1,
353                Token::ParenR(..) | Token::BracketR(..) | Token::BraceR(..) => {
354                    if depth == 0 {
355                        break;
356                    }
357                    depth = depth.saturating_sub(1)
358                }
359                Token::Comma(..) if depth == 0 => return true,
360                _ => {}
361            }
362        }
363        false
364    }
365
366    fn paren_group_has_top_level_colon(&self, paren_start: usize) -> bool {
367        let mut depth = 0usize;
368        for i in (paren_start + 1)..self.tokens.len() {
369            match self.tokens[i] {
370                Token::ParenL(..) | Token::BracketL(..) | Token::BraceL(..) => depth += 1,
371                Token::ParenR(..) | Token::BracketR(..) | Token::BraceR(..) => {
372                    if depth == 0 {
373                        break;
374                    }
375                    depth = depth.saturating_sub(1)
376                }
377                Token::Colon(..) if depth == 0 => return true,
378                _ => {}
379            }
380        }
381        false
382    }
383
384    fn parse_legacy_param_group(&mut self) -> Result<Vec<(Var, TypeExpr)>, ParserErr> {
385        match self.current_token() {
386            Token::ParenL(..) => self.next_token(),
387            token => {
388                return Err(ParserErr::new(
389                    *token.span(),
390                    format!("expected `(` got {}", token),
391                ));
392            }
393        }
394
395        let mut params = Vec::new();
396        if matches!(self.current_token(), Token::ParenR(..)) {
397            self.next_token();
398            return Ok(params);
399        }
400
401        loop {
402            let (param_name, param_span) = self.expect_ident("parameter name")?;
403            self.expect_colon()?;
404
405            let ty_start = self.token_cursor;
406            let ty_end = self
407                .find_token_at_depth0(ty_start, self.tokens.len(), |t| {
408                    matches!(t, Token::Comma(..) | Token::ParenR(..))
409                })
410                .ok_or_else(|| {
411                    ParserErr::new(
412                        self.eof,
413                        "expected `,` or `)` after parameter type".to_string(),
414                    )
415                })?;
416            let ann = self.parse_type_expr_slice(&self.tokens[ty_start..ty_end])?;
417            self.token_cursor = ty_end;
418            params.push((Var::with_span(param_span, param_name), ann));
419
420            match self.current_token() {
421                Token::Comma(..) => {
422                    self.next_token();
423                    continue;
424                }
425                Token::ParenR(..) => {
426                    self.next_token();
427                    break;
428                }
429                token => {
430                    return Err(ParserErr::new(
431                        *token.span(),
432                        format!("expected `,` or `)` got {}", token),
433                    ));
434                }
435            }
436        }
437
438        Ok(params)
439    }
440
441    // Advances by exactly one token and does *not* skip newlines.
442    //
443    // We use this for layout-sensitive headers (`class`/`instance`) where the
444    // newline boundary matters. Most of the parser treats newlines as whitespace,
445    // but for optional-`where` method blocks we need to know what was on the
446    // header line vs. what starts the indented block.
447    fn next_token_raw(&mut self) {
448        self.token_cursor += 1;
449    }
450
451    fn strip_comments(&mut self) {
452        let mut cursor = 0;
453
454        while cursor < self.tokens.len() {
455            match self.tokens[cursor] {
456                Token::CommentL(..) => {
457                    self.tokens.remove(cursor);
458                    while cursor < self.tokens.len() {
459                        if let Token::CommentR(..) = self.tokens[cursor] {
460                            self.tokens.remove(cursor);
461                            break;
462                        }
463                        self.tokens.remove(cursor);
464                    }
465                }
466                _ => {
467                    cursor += 1;
468                    continue;
469                }
470            }
471        }
472    }
473
474    fn record_error(&mut self, e: ParserErr) {
475        self.errors.push(e);
476    }
477
478    fn parse_program_core(&mut self) -> Result<Program, Vec<ParserErr>> {
479        let mut decls = Vec::new();
480        loop {
481            let mut is_pub = false;
482            if let Token::Pub(..) = self.current_token() {
483                is_pub = true;
484                self.next_token();
485            }
486
487            match self.current_token() {
488                Token::Type(..) => match self.parse_type_decl(is_pub) {
489                    Ok(decl) => decls.push(Decl::Type(decl)),
490                    Err(e) => {
491                        self.record_error(e);
492                        break;
493                    }
494                },
495                Token::Fn(..) => match self.parse_fn_decl(is_pub) {
496                    Ok(decl) => decls.push(Decl::Fn(decl)),
497                    Err(e) => {
498                        self.record_error(e);
499                        break;
500                    }
501                },
502                Token::Declare(..) => match self.parse_declare_fn_decl_toplevel(is_pub) {
503                    Ok(decl) => decls.push(Decl::DeclareFn(decl)),
504                    Err(e) => {
505                        self.record_error(e);
506                        break;
507                    }
508                },
509                Token::Import(..) => match self.parse_import_decl(is_pub) {
510                    Ok(decl) => decls.push(Decl::Import(decl)),
511                    Err(e) => {
512                        self.record_error(e);
513                        break;
514                    }
515                },
516                Token::Class(..) => match self.parse_class_decl(is_pub) {
517                    Ok(decl) => decls.push(Decl::Class(decl)),
518                    Err(e) => {
519                        self.record_error(e);
520                        break;
521                    }
522                },
523                Token::Instance(..) => match self.parse_instance_decl(is_pub) {
524                    Ok(decl) => decls.push(Decl::Instance(decl)),
525                    Err(e) => {
526                        self.record_error(e);
527                        break;
528                    }
529                },
530                _ => break,
531            }
532        }
533
534        let expr = if matches!(self.current_token(), Token::Eof(..)) {
535            // The trailing expression is optional; a declarations-only file
536            // evaluates to unit `()`.
537            Expr::Tuple(self.eof, vec![])
538        } else {
539            match self.parse_expr() {
540                Ok(expr) => expr,
541                Err(e) => {
542                    self.record_error(e);
543                    return Err(self.errors.clone());
544                }
545            }
546        };
547
548        // Make sure there's no trailing tokens. The whole program
549        // should be one expression.
550        match self.current_token() {
551            Token::Eof(..) => {}
552            token => self.record_error(ParserErr::new(
553                *token.span(),
554                format!("unexpected {}", token),
555            )),
556        }
557
558        if !self.errors.is_empty() {
559            Err(self.errors.clone())
560        } else {
561            Ok(Program {
562                decls,
563                expr: Arc::new(expr),
564            })
565        }
566    }
567
568    pub fn parse_program(&mut self, gas: &mut GasMeter) -> Result<Program, Vec<ParserErr>> {
569        let token_cost = gas
570            .costs
571            .parse_token
572            .saturating_mul(self.tokens.len() as u64);
573        if let Err(e) = gas.charge(token_cost) {
574            return Err(vec![ParserErr::new(Span::default(), e.to_string())]);
575        }
576
577        let program = self.parse_program_core()?;
578        let expr_nodes = count_expr_nodes(program.expr.as_ref());
579        let decl_nodes = program.decls.len() as u64;
580        let node_cost = gas
581            .costs
582            .parse_node
583            .saturating_mul(expr_nodes.saturating_add(decl_nodes));
584        if let Err(e) = gas.charge(node_cost) {
585            return Err(vec![ParserErr::new(Span::default(), e.to_string())]);
586        }
587        Ok(program)
588    }
589
590    fn parse_expr(&mut self) -> Result<Expr, ParserErr> {
591        let span = *self.current_token().span();
592        self.with_nesting(span, |this| {
593            let lhs_expr = this.parse_unary_expr()?;
594            this.parse_binary_expr(lhs_expr)
595        })
596    }
597
598    fn parse_binary_expr(&mut self, lhs_expr: Expr) -> Result<Expr, ParserErr> {
599        let span = *lhs_expr.span();
600        self.with_nesting(span, move |this| {
601            let lhs_expr_span = lhs_expr.span();
602
603            // Get the next token.
604            let token = match this.current_token() {
605                // Having no next token should finish the parsing of the binary
606                // expression.
607                Token::Eof(..) => return Ok(lhs_expr),
608                token => token,
609            };
610            let prec = token.precedence();
611
612            // Parse the binary operator.
613            let operator = match token {
614                Token::Add(..) => Operator::Add,
615                Token::And(..) => Operator::And,
616                Token::Concat(..) => Operator::Concat,
617                Token::ColonColon(..) => {
618                    let operator_span = token.span();
619                    this.next_token();
620
621                    let rhs_expr = this.parse_unary_expr()?;
622                    let rhs_expr_span = *rhs_expr.span();
623
624                    let next_binary_expr_takes_precedence = match this.current_token() {
625                        Token::Eof(..) => false,
626                        token if prec > token.precedence() => false,
627                        token if prec == token.precedence() => !matches!(
628                            token,
629                            Token::Add(..)
630                                | Token::And(..)
631                                | Token::Concat(..)
632                                | Token::Div(..)
633                                | Token::Mul(..)
634                                | Token::Mod(..)
635                                | Token::Or(..)
636                                | Token::Sub(..)
637                        ),
638                        _ => true,
639                    };
640
641                    let rhs_expr = if next_binary_expr_takes_precedence {
642                        this.parse_binary_expr(rhs_expr)?
643                    } else {
644                        rhs_expr
645                    };
646
647                    let cons_span = Span::from_begin_end(lhs_expr_span.begin, operator_span.end);
648                    let outer_span = Span::from_begin_end(lhs_expr_span.begin, rhs_expr_span.end);
649                    return this.parse_binary_expr(Expr::App(
650                        outer_span,
651                        Arc::new(Expr::App(
652                            cons_span,
653                            Arc::new(Expr::Var(Var::with_span(*operator_span, "Cons"))),
654                            Arc::new(lhs_expr),
655                        )),
656                        Arc::new(rhs_expr),
657                    ));
658                }
659                Token::Div(..) => Operator::Div,
660                Token::Eq(..) => Operator::Eq,
661                Token::Ne(..) => Operator::Ne,
662                Token::Ge(..) => Operator::Ge,
663                Token::Gt(..) => Operator::Gt,
664                Token::Le(..) => Operator::Le,
665                Token::Lt(..) => Operator::Lt,
666                Token::Mod(..) => Operator::Mod,
667                Token::Mul(..) => Operator::Mul,
668                Token::Or(..) => Operator::Or,
669                Token::Sub(..) => Operator::Sub,
670                _ => {
671                    return Ok(lhs_expr);
672                }
673            };
674            let operator_span = token.span();
675
676            // We have now decided that this token can be parsed so we consume it.
677            this.next_token();
678
679            // Parse the next part of this binary expression.
680            let rhs_expr = this.parse_unary_expr()?;
681            let rhs_expr_span = *rhs_expr.span();
682
683            let next_binary_expr_takes_precedence = match this.current_token() {
684                // No more tokens
685                Token::Eof(..) => false,
686                // Next token has lower precedence
687                token if prec > token.precedence() => false,
688                // Next token has the same precedence
689                token if prec == token.precedence() => {
690                    // Right-associative unless token is one of the left-associative ops.
691                    !matches!(
692                        token,
693                        Token::Add(..)
694                            | Token::And(..)
695                            | Token::Concat(..)
696                            | Token::Div(..)
697                            | Token::Mul(..)
698                            | Token::Mod(..)
699                            | Token::Or(..)
700                            | Token::Sub(..)
701                    )
702                }
703                // Next token has higher precedence
704                _ => true,
705            };
706
707            let rhs_expr = if next_binary_expr_takes_precedence {
708                this.parse_binary_expr(rhs_expr)?
709            } else {
710                rhs_expr
711            };
712
713            let inner_span = Span::from_begin_end(lhs_expr_span.begin, operator_span.end);
714            let outer_span = Span::from_begin_end(lhs_expr_span.begin, rhs_expr_span.end);
715
716            this.parse_binary_expr(Expr::App(
717                outer_span,
718                Arc::new(Expr::App(
719                    inner_span,
720                    Arc::new(Expr::Var(Var::with_span(
721                        *operator_span,
722                        operator.to_string(),
723                    ))),
724                    Arc::new(lhs_expr),
725                )),
726                Arc::new(rhs_expr),
727            ))
728        })
729    }
730
731    fn parse_unary_expr(&mut self) -> Result<Expr, ParserErr> {
732        // println!("parse_unary_expr: self.current_token() = {:#?}", self.current_token());
733        let mut call_base_expr = self.parse_postfix_expr()?;
734        let call_base_expr_span = *call_base_expr.span();
735
736        let mut call_arg_exprs = VecDeque::new();
737        loop {
738            let call_arg_expr = match self.current_token() {
739                Token::ParenL(..)
740                | Token::BracketL(..)
741                | Token::BraceL(..)
742                | Token::Bool(..)
743                | Token::Float(..)
744                | Token::Int(..)
745                | Token::String(..)
746                | Token::Question(..)
747                | Token::Ident(..)
748                | Token::BackSlash(..)
749                | Token::Let(..)
750                | Token::If(..)
751                | Token::Match(..) => self.parse_postfix_expr(),
752                _ => break,
753            }?;
754            call_arg_exprs.push_back(call_arg_expr);
755        }
756
757        while let Some(call_arg_expr) = call_arg_exprs.pop_front() {
758            let call_arg_expr_span_end = call_arg_expr.span().end;
759            call_base_expr = Expr::App(
760                Span::from_begin_end(call_base_expr_span.begin, call_arg_expr_span_end),
761                Arc::new(call_base_expr),
762                Arc::new(call_arg_expr),
763            );
764        }
765        while let Token::Is(..) = self.current_token() {
766            self.next_token();
767            let ann = self.parse_type_expr()?;
768            let span = Span::from_begin_end(call_base_expr.span().begin, ann.span().end);
769            call_base_expr = Expr::Ann(span, Arc::new(call_base_expr), ann);
770        }
771        Ok(call_base_expr)
772    }
773
774    fn parse_postfix_expr(&mut self) -> Result<Expr, ParserErr> {
775        let mut base = self.parse_atom_expr()?;
776        while let Token::Dot(..) = self.current_token() {
777            self.next_token();
778
779            let (field, end) = match self.current_token() {
780                Token::Ident(name, span, ..) => {
781                    let name = intern(&name);
782                    let end = span.end;
783                    self.next_token();
784                    (name, end)
785                }
786                Token::Int(value, span) => {
787                    let name = intern(&value.to_string());
788                    let end = span.end;
789                    self.next_token();
790                    (name, end)
791                }
792                token => {
793                    return Err(ParserErr::new(
794                        *token.span(),
795                        "expected field name after `.`",
796                    ));
797                }
798            };
799
800            let span = Span::from_begin_end(base.span().begin, end);
801            base = Expr::Project(span, Arc::new(base), field);
802        }
803        Ok(base)
804    }
805
806    fn parse_atom_expr(&mut self) -> Result<Expr, ParserErr> {
807        match self.current_token() {
808            Token::ParenL(..) => self.parse_paren_expr(),
809            Token::BracketL(..) => self.parse_bracket_expr(),
810            Token::BraceL(..) => self.parse_brace_expr(),
811            Token::Bool(..) => self.parse_literal_bool_expr(),
812            Token::Float(..) => self.parse_literal_float_expr(),
813            Token::Int(..) => self.parse_literal_int_expr(),
814            Token::String(..) => self.parse_literal_str_expr(),
815            Token::Question(..) => self.parse_hole_expr(),
816            Token::Ident(..) => self.parse_ident_expr(),
817            Token::BackSlash(..) => self.parse_lambda_expr(),
818            Token::Let(..) => self.parse_let_expr(),
819            Token::If(..) => self.parse_if_expr(),
820            Token::Match(..) => self.parse_match_expr(),
821            Token::Sub(..) => self.parse_neg_expr(),
822            Token::Eof(span) => Err(ParserErr::new(span, "unexpected EOF".to_string())),
823            token => Err(ParserErr::new(
824                *token.span(),
825                format!("unexpected {}", token),
826            )),
827        }
828    }
829
830    fn parse_paren_expr(&mut self) -> Result<Expr, ParserErr> {
831        // Eat the left parenthesis.
832        let span_begin = match self.current_token() {
833            Token::ParenL(span, ..) => {
834                self.next_token();
835                span
836            }
837            token => {
838                return Err(ParserErr::new(
839                    *token.span(),
840                    format!("expected `(` got {}", token),
841                ));
842            }
843        };
844
845        self.with_nesting(span_begin, |this| {
846            // Parse the inner expression.
847            let expr = match this.current_token() {
848                Token::ParenR(span, ..) => {
849                    this.next_token();
850                    // Empty tuple
851                    return Ok(Expr::Tuple(
852                        Span::from_begin_end(span_begin.begin, span.end),
853                        vec![],
854                    ));
855                }
856                Token::Add(span, ..) => {
857                    this.next_token();
858                    Expr::Var(Var::with_span(span, "+"))
859                }
860                Token::And(span, ..) => {
861                    this.next_token();
862                    Expr::Var(Var::with_span(span, "&&"))
863                }
864                Token::Concat(span, ..) => {
865                    this.next_token();
866                    Expr::Var(Var::with_span(span, "++"))
867                }
868                Token::Div(span, ..) => {
869                    this.next_token();
870                    Expr::Var(Var::with_span(span, "/"))
871                }
872                Token::Eq(span, ..) => {
873                    this.next_token();
874                    Expr::Var(Var::with_span(span, "=="))
875                }
876                Token::Ge(span, ..) => {
877                    this.next_token();
878                    Expr::Var(Var::with_span(span, ">="))
879                }
880                Token::Gt(span, ..) => {
881                    this.next_token();
882                    Expr::Var(Var::with_span(span, ">"))
883                }
884                Token::Le(span, ..) => {
885                    this.next_token();
886                    Expr::Var(Var::with_span(span, "<="))
887                }
888                Token::Lt(span, ..) => {
889                    this.next_token();
890                    Expr::Var(Var::with_span(span, "<"))
891                }
892                Token::Mod(span, ..) => {
893                    this.next_token();
894                    Expr::Var(Var::with_span(span, "%"))
895                }
896                Token::Mul(span, ..) => {
897                    this.next_token();
898                    Expr::Var(Var::with_span(span, "*"))
899                }
900                Token::Or(span, ..) => {
901                    this.next_token();
902                    Expr::Var(Var::with_span(span, "||"))
903                }
904                Token::Sub(span, ..) => {
905                    if let Token::ParenR(..) = this.peek_token(1) {
906                        // In the case of the `-` operator we need to explicitly
907                        // check for the closing right parenthesis, because it is
908                        // valid to have an expressions like `(- 69)`. This is
909                        // different from other operators, because it is not valid
910                        // to have an expression like `(+ 69)`` or `(>= 3)``.
911                        //
912                        // It would not be a crazy idea to explicitly check for the
913                        // closing right parenthesis in other operators. Although we
914                        // do not want to allow expressions like `(+ 420)` the
915                        // explicit check will allow for better error messages.
916                        this.next_token();
917                        Expr::Var(Var::with_span(span, "-"))
918                    } else {
919                        this.parse_expr()?
920                    }
921                }
922                _ => this.parse_expr()?,
923            };
924
925            // Eat the right parenthesis.
926            let span_end = match this.current_token() {
927                Token::ParenR(span, ..) => {
928                    this.next_token();
929                    span
930                }
931                Token::Comma(..) => {
932                    // parse inner expressions
933                    return this.parse_tuple(span_begin, expr);
934                }
935                token => {
936                    this.record_error(ParserErr::new(*token.span(), "expected `)`"));
937                    return Ok(expr);
938                }
939            };
940
941            let expr = expr.with_span_begin_end(span_begin.begin, span_end.end);
942            Ok(expr)
943        })
944    }
945
946    fn parse_tuple(&mut self, span_begin: Span, first_item: Expr) -> Result<Expr, ParserErr> {
947        let mut items = vec![Arc::new(first_item)];
948        loop {
949            // eat the comma
950            match self.current_token() {
951                Token::Comma(..) => self.next_token(),
952                Token::ParenR(end_span) => {
953                    self.next_token();
954                    return Ok(Expr::Tuple(
955                        Span::from_begin_end(span_begin.begin, end_span.end),
956                        items,
957                    ));
958                }
959                _ => items.push(Arc::new(self.parse_expr()?)),
960            }
961        }
962    }
963
964    fn parse_bracket_expr(&mut self) -> Result<Expr, ParserErr> {
965        // Eat the left bracket.
966        let span_begin = match self.current_token() {
967            Token::BracketL(span, ..) => {
968                self.next_token();
969                span
970            }
971            token => {
972                return Err(ParserErr::new(
973                    *token.span(),
974                    format!("expected `[` got {}", token),
975                ));
976            }
977        };
978
979        self.with_nesting(span_begin, |this| {
980            let mut exprs = Vec::new();
981            loop {
982                if let Token::BracketR(..) = this.current_token() {
983                    break;
984                }
985
986                // Parse the next expression.
987                exprs.push(Arc::new(this.parse_expr()?));
988                // Eat the comma.
989                match this.current_token() {
990                    Token::Comma(..) => this.next_token(),
991                    Token::Eof(span) => {
992                        this.record_error(ParserErr::new(span, "expected `,` or `]`"));
993                        break;
994                    }
995                    _ => {
996                        break;
997                    }
998                };
999            }
1000
1001            // Eat the right bracket.
1002            let span_end = match this.current_token() {
1003                Token::BracketR(span, ..) => {
1004                    this.next_token();
1005                    span.end
1006                }
1007                token => {
1008                    this.record_error(ParserErr::new(
1009                        *token.span(),
1010                        format!("expected `]` got {}", token),
1011                    ));
1012
1013                    return Ok(Expr::List(
1014                        Span::from_begin_end(span_begin.begin, token.span().end),
1015                        exprs,
1016                    ));
1017                }
1018            };
1019
1020            Ok(Expr::List(
1021                Span::from_begin_end(span_begin.begin, span_end),
1022                exprs,
1023            ))
1024        })
1025    }
1026
1027    fn parse_brace_expr(&mut self) -> Result<Expr, ParserErr> {
1028        // Eat the left brace.
1029        let span_begin = match self.current_token() {
1030            Token::BraceL(span, ..) => {
1031                self.next_token();
1032                span
1033            }
1034            token => {
1035                return Err(ParserErr::new(
1036                    *token.span(),
1037                    format!("expected `{{` got {}", token),
1038                ));
1039            }
1040        };
1041
1042        self.with_nesting(span_begin, |this| {
1043            let span_begin_pos = span_begin.begin;
1044
1045            // `{}` is always an empty dict literal.
1046            if let Token::BraceR(span, ..) = this.current_token() {
1047                this.next_token();
1048                return Ok(Expr::Dict(
1049                    Span::from_begin_end(span_begin_pos, span.end),
1050                    BTreeMap::new(),
1051                ));
1052            }
1053
1054            // Disambiguate:
1055            // - `{ x = e }` is a dict literal
1056            // - `{ base with { x = e } }` is a record-update expression
1057            let looks_like_dict_literal = matches!(this.current_token(), Token::Ident(..))
1058                && matches!(this.peek_token(1), Token::Assign(..));
1059
1060            if looks_like_dict_literal {
1061                return this.parse_dict_expr_after_lbrace(span_begin_pos);
1062            }
1063
1064            let base = match this.parse_expr() {
1065                Ok(expr) => expr,
1066                Err(err) => {
1067                    this.record_error(err);
1068                    while !matches!(this.current_token(), Token::BraceR(..) | Token::Eof(..)) {
1069                        this.next_token();
1070                    }
1071                    if let Token::BraceR(..) = this.current_token() {
1072                        this.next_token();
1073                    }
1074                    return Ok(Expr::Dict(
1075                        Span::from_begin_end(span_begin_pos, Position::new(0, 0)),
1076                        BTreeMap::new(),
1077                    ));
1078                }
1079            };
1080
1081            match this.current_token() {
1082                Token::With(..) => this.next_token(),
1083                token => {
1084                    this.record_error(ParserErr::new(*token.span(), "expected `with`"));
1085                    while !matches!(this.current_token(), Token::BraceR(..) | Token::Eof(..)) {
1086                        this.next_token();
1087                    }
1088                    if let Token::BraceR(..) = this.current_token() {
1089                        this.next_token();
1090                    }
1091                    return Ok(base);
1092                }
1093            };
1094
1095            let updates = match this.parse_dict_expr() {
1096                Ok(Expr::Dict(_, kvs)) => kvs,
1097                Ok(other) => {
1098                    this.record_error(ParserErr::new(*other.span(), "expected `{...}`"));
1099                    BTreeMap::new()
1100                }
1101                Err(err) => {
1102                    this.record_error(err);
1103                    BTreeMap::new()
1104                }
1105            };
1106
1107            // Eat the right brace of the update expression.
1108            let span_end = match this.current_token() {
1109                Token::BraceR(span, ..) => {
1110                    this.next_token();
1111                    span.end
1112                }
1113                token => {
1114                    this.record_error(ParserErr::new(
1115                        *token.span(),
1116                        format!("expected `}}` got {}", token),
1117                    ));
1118                    Position::new(0, 0)
1119                }
1120            };
1121
1122            Ok(Expr::RecordUpdate(
1123                Span::from_begin_end(span_begin_pos, span_end),
1124                Arc::new(base),
1125                updates,
1126            ))
1127        })
1128    }
1129
1130    fn parse_dict_expr(&mut self) -> Result<Expr, ParserErr> {
1131        // Eat the left brace.
1132        let span_begin = match self.current_token() {
1133            Token::BraceL(span, ..) => {
1134                self.next_token();
1135                span.begin
1136            }
1137            token => {
1138                return Err(ParserErr::new(
1139                    *token.span(),
1140                    format!("expected `{{` got {}", token),
1141                ));
1142            }
1143        };
1144
1145        self.with_nesting(Span::from_begin_end(span_begin, span_begin), |this| {
1146            this.parse_dict_expr_after_lbrace(span_begin)
1147        })
1148    }
1149
1150    fn parse_dict_expr_after_lbrace(&mut self, span_begin: Position) -> Result<Expr, ParserErr> {
1151        let mut kvs = Vec::new();
1152        loop {
1153            if let Token::BraceR(..) = self.current_token() {
1154                break;
1155            }
1156
1157            // Parse the ident.
1158            let var = match self.parse_ident_expr()? {
1159                Expr::Var(var) => var,
1160                _ => unreachable!(),
1161            };
1162            // Eat the =.
1163            match self.current_token() {
1164                Token::Assign(..) => self.next_token(),
1165                token => {
1166                    self.record_error(ParserErr::new(*token.span(), "expected `=`"));
1167                    break;
1168                }
1169            };
1170            // Parse the expression.
1171            kvs.push((var.name, Arc::new(self.parse_expr()?)));
1172            // Eat the comma.
1173            match self.current_token() {
1174                Token::Comma(..) => self.next_token(),
1175                Token::Eof(span) => {
1176                    self.record_error(ParserErr::new(span, "expected `,` or `}`"));
1177                    break;
1178                }
1179                _ => {
1180                    break;
1181                }
1182            };
1183        }
1184
1185        // Eat the right brace.
1186        let span_end = match self.current_token() {
1187            Token::BraceR(span, ..) => {
1188                self.next_token();
1189                span.end
1190            }
1191            token => {
1192                self.record_error(ParserErr::new(
1193                    *token.span(),
1194                    format!("expected `}}` got {}", token),
1195                ));
1196
1197                return Ok(Expr::Dict(
1198                    Span::from_begin_end(span_begin, Position::new(0, 0)),
1199                    kvs.into_iter().collect(),
1200                ));
1201            }
1202        };
1203
1204        Ok(Expr::Dict(
1205            Span::from_begin_end(span_begin, span_end),
1206            kvs.into_iter().collect(),
1207        ))
1208    }
1209
1210    fn parse_neg_expr(&mut self) -> Result<Expr, ParserErr> {
1211        // Eat the minus.
1212        let span_token = match self.current_token() {
1213            Token::Sub(span, ..) => {
1214                self.next_token();
1215                span
1216            }
1217            token => {
1218                return Err(ParserErr::new(
1219                    *token.span(),
1220                    format!("expected `-` got {}", token),
1221                ));
1222            }
1223        };
1224
1225        // Parse the inner expression.
1226        let expr = self.parse_expr()?;
1227        let expr_span_end = expr.span().end;
1228
1229        // Return the negative expression.
1230        Ok(Expr::App(
1231            Span::from_begin_end(span_token.begin, expr_span_end),
1232            Arc::new(Expr::Var(Var::with_span(span_token, "negate"))),
1233            Arc::new(expr),
1234        ))
1235    }
1236
1237    //
1238    fn parse_lambda_expr(&mut self) -> Result<Expr, ParserErr> {
1239        // Eat the backslash.
1240        let span_begin = match self.current_token() {
1241            Token::BackSlash(span, ..) => {
1242                self.next_token();
1243                span.begin
1244            }
1245            token => {
1246                return Err(ParserErr::new(
1247                    *token.span(),
1248                    format!("expected `\\` got {}", token),
1249                ));
1250            }
1251        };
1252
1253        // Parse the params.
1254        let mut params = VecDeque::new();
1255        while let Token::Ident(..) | Token::ParenL(..) = self.current_token() {
1256            let (var, ann, span) = self.parse_lambda_param()?;
1257            params.push_back((span, var, ann));
1258        }
1259
1260        let mut constraints = Vec::new();
1261        if matches!(self.current_token(), Token::Where(..)) {
1262            self.next_token();
1263            constraints = self.parse_type_constraints()?;
1264        }
1265
1266        // Parse the arrow.
1267        let _span_arrow = match self.current_token() {
1268            Token::ArrowR(span, ..) => {
1269                self.next_token();
1270                span
1271            }
1272            token => {
1273                return Err(ParserErr::new(
1274                    *token.span(),
1275                    format!("expected `->` got {}", token),
1276                ));
1277            }
1278        };
1279
1280        // Parse the body
1281        let mut body = self.parse_expr()?;
1282        let mut body_span_end = body.span().end;
1283        while let Some((param_span, param, ann)) = params.pop_back() {
1284            let lam_constraints = if params.is_empty() {
1285                std::mem::take(&mut constraints)
1286            } else {
1287                Vec::new()
1288            };
1289            body = Expr::Lam(
1290                Span::from_begin_end(param_span.begin, body_span_end),
1291                Scope::new_sync(),
1292                param,
1293                ann,
1294                lam_constraints,
1295                Arc::new(body),
1296            );
1297            body_span_end = body.span().end;
1298        }
1299        // Adjust the outer most lambda to include the initial backslash
1300        let body = body.with_span_begin(span_begin);
1301
1302        Ok(body)
1303    }
1304
1305    fn parse_lambda_param(&mut self) -> Result<(Var, Option<TypeExpr>, Span), ParserErr> {
1306        match self.current_token() {
1307            Token::Ident(name, span, ..) => {
1308                self.next_token();
1309                let mut ann = None;
1310                let mut param_span = span;
1311                if let Token::Colon(..) = self.current_token() {
1312                    self.next_token();
1313                    let ann_expr = self.parse_type_expr()?;
1314                    param_span = Span::from_begin_end(span.begin, ann_expr.span().end);
1315                    ann = Some(ann_expr);
1316                }
1317                Ok((Var::with_span(span, name), ann, param_span))
1318            }
1319            Token::ParenL(span_begin, ..) => {
1320                self.next_token();
1321                let (name, name_span) = self.expect_ident("parameter name")?;
1322                self.expect_colon()?;
1323                let ann = self.parse_type_expr()?;
1324                let span_end = self.expect_paren_r()?.end;
1325                Ok((
1326                    Var::with_span(name_span, name),
1327                    Some(ann),
1328                    Span::from_begin_end(span_begin.begin, span_end),
1329                ))
1330            }
1331            token => Err(ParserErr::new(
1332                *token.span(),
1333                format!("expected lambda param got {}", token),
1334            )),
1335        }
1336    }
1337
1338    fn parse_type_constraints(&mut self) -> Result<Vec<TypeConstraint>, ParserErr> {
1339        let mut constraints = Vec::new();
1340        loop {
1341            let (class, _) = self.parse_name_ref_with_span("expected type class name")?;
1342
1343            let typ = self.parse_type_app()?;
1344            constraints.push(TypeConstraint::new(class, typ));
1345
1346            match self.current_token() {
1347                Token::Comma(..) => {
1348                    self.next_token();
1349                    continue;
1350                }
1351                _ => break,
1352            }
1353        }
1354        Ok(constraints)
1355    }
1356
1357    //
1358    fn parse_let_expr(&mut self) -> Result<Expr, ParserErr> {
1359        // Eat the `let` token
1360        let span_begin = match self.current_token() {
1361            Token::Let(span, ..) => {
1362                self.next_token();
1363                span.begin
1364            }
1365            token => {
1366                return Err(ParserErr::new(
1367                    *token.span(),
1368                    format!("expected `let` got {}", token),
1369                ));
1370            }
1371        };
1372
1373        let is_rec = if matches!(self.current_token(), Token::Rec(..)) {
1374            self.next_token();
1375            true
1376        } else {
1377            false
1378        };
1379
1380        if is_rec {
1381            let mut bindings = Vec::new();
1382            loop {
1383                let (pat, ann) = match (self.current_token(), self.peek_token(1)) {
1384                    (Token::Ident(val, span, ..), Token::Colon(..)) => {
1385                        self.next_token();
1386                        self.next_token();
1387                        let var = Var::with_span(span, val);
1388                        let ann = Some(self.parse_type_expr()?);
1389                        (Pattern::Var(var), ann)
1390                    }
1391                    _ => {
1392                        let pat = self.parse_pattern()?;
1393                        let mut ann = None;
1394                        if let Token::Colon(..) = self.current_token() {
1395                            self.next_token();
1396                            ann = Some(self.parse_type_expr()?);
1397                        }
1398                        (pat, ann)
1399                    }
1400                };
1401
1402                let var = match pat {
1403                    Pattern::Var(var) => var,
1404                    other => {
1405                        return Err(ParserErr::new(
1406                            *other.span(),
1407                            "let rec only supports variable bindings".to_string(),
1408                        ));
1409                    }
1410                };
1411
1412                self.expect_assign()?;
1413                let def = Arc::new(self.parse_expr()?);
1414                bindings.push((var, ann, def));
1415
1416                match self.current_token() {
1417                    Token::Comma(..) => {
1418                        self.next_token();
1419                    }
1420                    Token::In(..) => break,
1421                    token => {
1422                        return Err(ParserErr::new(
1423                            *token.span(),
1424                            format!("expected `,` or `in` got {}", token),
1425                        ));
1426                    }
1427                }
1428            }
1429
1430            match self.current_token() {
1431                Token::In(..) => self.next_token(),
1432                token => {
1433                    return Err(ParserErr::new(
1434                        *token.span(),
1435                        format!("expected `in` got {}", token),
1436                    ));
1437                }
1438            };
1439
1440            let body = Arc::new(self.parse_expr()?);
1441            let span = Span::from_begin_end(span_begin, body.span().end);
1442            Ok(Expr::LetRec(span, bindings, body))
1443        } else {
1444            // Parse the variable declarations.
1445            let mut decls = VecDeque::new();
1446            let is_pattern_start = |token: Token| {
1447                matches!(
1448                    token,
1449                    Token::Ident(..) | Token::ParenL(..) | Token::BracketL(..) | Token::BraceL(..)
1450                )
1451            };
1452            while is_pattern_start(self.current_token()) {
1453                let (pat, ann) = match (self.current_token(), self.peek_token(1)) {
1454                    (Token::Ident(val, span, ..), Token::Colon(..)) => {
1455                        self.next_token();
1456                        self.next_token();
1457                        let var = Var::with_span(span, val);
1458                        let ann = Some(self.parse_type_expr()?);
1459                        (Pattern::Var(var), ann)
1460                    }
1461                    _ => {
1462                        let pat = self.parse_pattern()?;
1463                        let mut ann = None;
1464                        if let Token::Colon(..) = self.current_token() {
1465                            self.next_token();
1466                            ann = Some(self.parse_type_expr()?);
1467                        }
1468                        (pat, ann)
1469                    }
1470                };
1471
1472                // =
1473                self.expect_assign()?;
1474                // Parse the variable definition
1475                decls.push_back((pat, ann, self.parse_expr()?));
1476                // Parse `,` or `in`
1477                match self.current_token() {
1478                    Token::Comma(_span, ..) => {
1479                        self.next_token();
1480                        continue;
1481                    }
1482                    Token::In(..) => break,
1483                    token => {
1484                        return Err(ParserErr::new(
1485                            *token.span(),
1486                            format!("expected `,` or `in` got {}", token),
1487                        ));
1488                    }
1489                }
1490            }
1491
1492            // Parse the `in` token
1493            let _span_arrow = match self.current_token() {
1494                Token::In(span, ..) => {
1495                    self.next_token();
1496                    span
1497                }
1498                token => {
1499                    return Err(ParserErr::new(
1500                        *token.span(),
1501                        format!("expected `in` got {}", token),
1502                    ));
1503                }
1504            };
1505
1506            // Parse the body
1507            let mut body = self.parse_expr()?;
1508            let mut body_span_end = body.span().end;
1509            while let Some((pat, ann, def)) = decls.pop_back() {
1510                match pat {
1511                    Pattern::Var(var) => {
1512                        body = Expr::Let(
1513                            Span::from_begin_end(var.span.begin, body_span_end),
1514                            var,
1515                            ann,
1516                            Arc::new(def),
1517                            Arc::new(body),
1518                        );
1519                    }
1520                    pat => {
1521                        let def_expr = match ann {
1522                            Some(ann) => {
1523                                let span = Span::from_begin_end(def.span().begin, ann.span().end);
1524                                Expr::Ann(span, Arc::new(def), ann)
1525                            }
1526                            None => def,
1527                        };
1528                        body = Expr::Match(
1529                            Span::from_begin_end(pat.span().begin, body_span_end),
1530                            Arc::new(def_expr),
1531                            vec![(pat, Arc::new(body))],
1532                        );
1533                    }
1534                }
1535                body_span_end = body.span().end;
1536            }
1537            // Adjust the outer most let-in expression to include the initial let
1538            // token
1539            let body = body.with_span_begin(span_begin);
1540
1541            Ok(body)
1542        }
1543    }
1544
1545    //
1546    fn parse_if_expr(&mut self) -> Result<Expr, ParserErr> {
1547        // Eat the `if` token
1548        let span_begin = match self.current_token() {
1549            Token::If(span, ..) => {
1550                self.next_token();
1551                span.begin
1552            }
1553            token => {
1554                return Err(ParserErr::new(
1555                    *token.span(),
1556                    format!("expected `if` got {}", token),
1557                ));
1558            }
1559        };
1560
1561        // Parse the cond expression
1562        let cond = self.parse_expr()?;
1563
1564        // Parse the `then` token
1565        let _span_arrow = match self.current_token() {
1566            Token::Then(span, ..) => {
1567                self.next_token();
1568                span
1569            }
1570            token => {
1571                return Err(ParserErr::new(
1572                    *token.span(),
1573                    format!("expected `then` got {}", token),
1574                ));
1575            }
1576        };
1577
1578        // Parse the then expression
1579        let then = self.parse_expr()?;
1580
1581        // Parse the `else` token
1582        let _span_arrow = match self.current_token() {
1583            Token::Else(span, ..) => {
1584                self.next_token();
1585                span
1586            }
1587            token => {
1588                return Err(ParserErr::new(
1589                    *token.span(),
1590                    format!("expected `else` got {}", token),
1591                ));
1592            }
1593        };
1594
1595        // Parse the else expression
1596        let r#else = self.parse_expr()?;
1597        let else_span_end = r#else.span().end;
1598
1599        Ok(Expr::Ite(
1600            Span::from_begin_end(span_begin, else_span_end),
1601            Arc::new(cond),
1602            Arc::new(then),
1603            Arc::new(r#else),
1604        ))
1605    }
1606
1607    fn parse_match_expr(&mut self) -> Result<Expr, ParserErr> {
1608        // Eat the `match` token
1609        let span_begin = match self.current_token() {
1610            Token::Match(span, ..) => {
1611                self.next_token();
1612                span.begin
1613            }
1614            token => {
1615                return Err(ParserErr::new(
1616                    *token.span(),
1617                    format!("expected `match` got {}", token),
1618                ));
1619            }
1620        };
1621
1622        let scrutinee = self.parse_atom_expr()?;
1623        let mut arms = Vec::new();
1624        loop {
1625            match self.current_token() {
1626                Token::When(..) => {
1627                    self.next_token();
1628                }
1629                token => {
1630                    return Err(ParserErr::new(
1631                        *token.span(),
1632                        format!("expected `when` got {}", token),
1633                    ));
1634                }
1635            }
1636
1637            let pattern = self.parse_pattern()?;
1638
1639            match self.current_token() {
1640                Token::ArrowR(..) => self.next_token(),
1641                token => {
1642                    return Err(ParserErr::new(
1643                        *token.span(),
1644                        format!("expected `->` got {}", token),
1645                    ));
1646                }
1647            }
1648
1649            let expr = self.parse_expr()?;
1650            arms.push((pattern, Arc::new(expr)));
1651
1652            match self.current_token() {
1653                Token::When(..) => continue,
1654                _ => break,
1655            }
1656        }
1657
1658        let span_end = arms
1659            .last()
1660            .map(|(_, expr)| expr.span().end)
1661            .unwrap_or_else(|| scrutinee.span().end);
1662
1663        Ok(Expr::Match(
1664            Span::from_begin_end(span_begin, span_end),
1665            Arc::new(scrutinee),
1666            arms,
1667        ))
1668    }
1669
1670    fn eof_for_slice(&self, slice: &[Token]) -> Span {
1671        slice.last().map(|t| *t.span()).unwrap_or(self.eof)
1672    }
1673
1674    fn parse_type_expr_slice(&self, slice: &[Token]) -> Result<TypeExpr, ParserErr> {
1675        if slice.is_empty() {
1676            return Err(ParserErr::new(self.eof, "expected type".to_string()));
1677        }
1678        let eof = self.eof_for_slice(slice);
1679        let tokens = Tokens {
1680            items: slice.to_vec(),
1681            eof,
1682        };
1683        let mut parser = Parser::new(tokens);
1684        let expr = parser.parse_type_expr()?;
1685        match parser.current_token() {
1686            Token::Eof(..) => Ok(expr),
1687            token => Err(ParserErr::new(
1688                *token.span(),
1689                format!("unexpected {} in type", token),
1690            )),
1691        }
1692    }
1693
1694    fn parse_type_app_slice(&self, slice: &[Token]) -> Result<TypeExpr, ParserErr> {
1695        if slice.is_empty() {
1696            return Err(ParserErr::new(self.eof, "expected type".to_string()));
1697        }
1698        let eof = self.eof_for_slice(slice);
1699        let tokens = Tokens {
1700            items: slice.to_vec(),
1701            eof,
1702        };
1703        let mut parser = Parser::new(tokens);
1704        let expr = parser.parse_type_app()?;
1705        match parser.current_token() {
1706            Token::Eof(..) => Ok(expr),
1707            token => Err(ParserErr::new(
1708                *token.span(),
1709                format!("unexpected {} in type", token),
1710            )),
1711        }
1712    }
1713
1714    fn parse_type_constraints_slice(
1715        &self,
1716        slice: &[Token],
1717    ) -> Result<Vec<TypeConstraint>, ParserErr> {
1718        if slice.is_empty() {
1719            return Err(ParserErr::new(
1720                self.eof,
1721                "expected type constraint".to_string(),
1722            ));
1723        }
1724        let eof = self.eof_for_slice(slice);
1725        let tokens = Tokens {
1726            items: slice.to_vec(),
1727            eof,
1728        };
1729        let mut parser = Parser::new(tokens);
1730        let constraints = parser.parse_type_constraints()?;
1731        match parser.current_token() {
1732            Token::Eof(..) => Ok(constraints),
1733            token => Err(ParserErr::new(
1734                *token.span(),
1735                format!("unexpected {} in type constraints", token),
1736            )),
1737        }
1738    }
1739
1740    fn parse_expr_slice(&self, slice: &[Token]) -> Result<Expr, ParserErr> {
1741        if slice.is_empty() {
1742            return Err(ParserErr::new(self.eof, "expected expression".to_string()));
1743        }
1744        let eof = self.eof_for_slice(slice);
1745        let tokens = Tokens {
1746            items: slice.to_vec(),
1747            eof,
1748        };
1749        let mut parser = Parser::new(tokens);
1750        let expr = parser.parse_expr()?;
1751        match parser.current_token() {
1752            Token::Eof(..) => Ok(expr),
1753            token => Err(ParserErr::new(
1754                *token.span(),
1755                format!("unexpected {} in expression", token),
1756            )),
1757        }
1758    }
1759
1760    fn parse_class_decl(&mut self, is_pub: bool) -> Result<ClassDecl, ParserErr> {
1761        let span_begin = match self.current_token() {
1762            Token::Class(span, ..) => {
1763                self.next_token();
1764                span.begin
1765            }
1766            token => {
1767                return Err(ParserErr::new(
1768                    *token.span(),
1769                    format!("expected `class` got {}", token),
1770                ));
1771            }
1772        };
1773
1774        let (name, name_span) = match self.current_token() {
1775            Token::Ident(name, span, ..) => {
1776                self.next_token_raw();
1777                (intern(&name), span)
1778            }
1779            token => {
1780                return Err(ParserErr::new(
1781                    *token.span(),
1782                    format!("expected class name got {}", token),
1783                ));
1784            }
1785        };
1786
1787        let class_indent = span_begin.column;
1788        let header_line = name_span.begin.line;
1789        let mut header_end = name_span.end;
1790
1791        let mut params = Vec::new();
1792        while let Some(Token::Ident(p, span, ..)) = self.tokens.get(self.token_cursor).cloned() {
1793            // Parameters only live on the header line. Newlines are significant
1794            // here because `where` is optional and the next line may be a method
1795            // block.
1796            if span.begin.line != header_line {
1797                break;
1798            }
1799            header_end = header_end.max(span.end);
1800            params.push(intern(&p));
1801            self.next_token_raw();
1802        }
1803
1804        let mut supers = Vec::new();
1805        if let Some(Token::Le(span, ..)) = self.tokens.get(self.token_cursor).cloned() {
1806            if span.begin.line == header_line {
1807                self.next_token_raw();
1808                let start_idx = self.token_cursor;
1809                let end_idx = find_layout_header_clause_end(&self.tokens, start_idx, |t| {
1810                    matches!(t, Token::Where(..))
1811                });
1812                supers = self.parse_type_constraints_slice(&self.tokens[start_idx..end_idx])?;
1813                self.token_cursor = end_idx;
1814            }
1815            if let Some(last) = supers.last() {
1816                header_end = header_end.max(last.typ.span().end);
1817            }
1818        }
1819
1820        // `where` is optional. If it is omitted, we only treat the following
1821        // layout block as a list of method signatures when it is clearly a
1822        // method block:
1823        // - It is indented more than the `class` keyword, AND
1824        // - It starts with `name : ...` (operator names allowed).
1825        //
1826        // This keeps parsing unambiguous and prevents accidentally consuming
1827        // the program expression as if it were method signatures.
1828        let mut saw_where = false;
1829        let where_span = match self.current_token() {
1830            Token::Where(span, ..) => {
1831                self.next_token();
1832                header_end = header_end.max(span.end);
1833                saw_where = true;
1834                span
1835            }
1836            _ => Span::default(),
1837        };
1838
1839        // Method signatures are a layout block: each signature starts at the
1840        // indentation of the first method name after `where` (or after the
1841        // class header if `where` is omitted).
1842        let implicit_method_start = if saw_where {
1843            false
1844        } else {
1845            let token = self.current_token();
1846            let token_span = *token.span();
1847            let next = self.peek_token(1);
1848            token_span.begin.column > class_indent
1849                && matches!(next, Token::Colon(..))
1850                && Self::is_value_name_token(&token)
1851        };
1852        let has_method_block = saw_where || implicit_method_start;
1853        let block_indent = if has_method_block {
1854            match self.current_token() {
1855                Token::Ident(_, span, ..) => Some(span.begin.column),
1856                token => Self::operator_token_name(&token).map(|(_, span)| span.begin.column),
1857            }
1858        } else {
1859            None
1860        };
1861
1862        let methods = self.parse_layout_block(has_method_block, block_indent, |parser| {
1863            let (m_name, _name_span) = parser.parse_value_name()?;
1864            parser.expect_colon()?;
1865
1866            let start_idx = parser.token_cursor;
1867            let end_idx =
1868                find_layout_expr_end(&parser.tokens, start_idx, block_indent, |t, next| {
1869                    matches!(next, Token::Colon(..)) && Self::is_value_name_token(t)
1870                });
1871            let typ = parser.parse_type_expr_slice(&parser.tokens[start_idx..end_idx])?;
1872            parser.token_cursor = end_idx;
1873            parser.skip_newlines();
1874            Ok(ClassMethodSig { name: m_name, typ })
1875        })?;
1876
1877        let span_end = methods
1878            .last()
1879            .map(|m| m.typ.span().end)
1880            .or_else(|| supers.last().map(|s| s.typ.span().end))
1881            .unwrap_or(header_end.max(where_span.end));
1882
1883        Ok(ClassDecl {
1884            span: Span::from_begin_end(span_begin, span_end),
1885            is_pub,
1886            name,
1887            params,
1888            supers,
1889            methods,
1890        })
1891    }
1892
1893    fn parse_instance_decl(&mut self, is_pub: bool) -> Result<InstanceDecl, ParserErr> {
1894        let span_begin = match self.current_token() {
1895            Token::Instance(span, ..) => {
1896                self.next_token();
1897                span.begin
1898            }
1899            token => {
1900                return Err(ParserErr::new(
1901                    *token.span(),
1902                    format!("expected `instance` got {}", token),
1903                ));
1904            }
1905        };
1906
1907        let (class_ref, class_span) = self.parse_name_ref_with_span("expected class name")?;
1908        let class = class_ref.to_dotted_symbol();
1909
1910        let instance_indent = span_begin.column;
1911        let header_line = class_span.begin.line;
1912
1913        let start_idx = self.token_cursor;
1914        let end_idx = find_layout_header_clause_end(&self.tokens, start_idx, |t| {
1915            matches!(t, Token::Le(..) | Token::Where(..))
1916        });
1917        if end_idx == start_idx {
1918            let span = self
1919                .tokens
1920                .get(start_idx)
1921                .map(|t| *t.span())
1922                .unwrap_or(self.eof);
1923            return Err(ParserErr::new(span, "expected type".to_string()));
1924        }
1925        let head = self.parse_type_app_slice(&self.tokens[start_idx..end_idx])?;
1926        self.token_cursor = end_idx;
1927        let mut header_end = head.span().end;
1928
1929        let mut context = Vec::new();
1930        if let Some(Token::Le(span, ..)) = self.tokens.get(self.token_cursor).cloned()
1931            && span.begin.line == header_line
1932        {
1933            self.next_token_raw();
1934            let start_idx = self.token_cursor;
1935            let end_idx = find_layout_header_clause_end(&self.tokens, start_idx, |t| {
1936                matches!(t, Token::Where(..))
1937            });
1938            context = self.parse_type_constraints_slice(&self.tokens[start_idx..end_idx])?;
1939            self.token_cursor = end_idx;
1940            if let Some(last) = context.last() {
1941                header_end = header_end.max(last.typ.span().end);
1942            }
1943        }
1944
1945        // `where` is optional. If it is omitted, we only treat the following
1946        // layout block as a list of method implementations when it is clearly
1947        // a method block:
1948        // - It is indented more than the `instance` keyword, AND
1949        // - It starts with `name = ...` (operator names allowed).
1950        let mut saw_where = false;
1951        let where_span = match self.current_token() {
1952            Token::Where(span, ..) => {
1953                self.next_token();
1954                header_end = header_end.max(span.end);
1955                saw_where = true;
1956                span
1957            }
1958            _ => Span::default(),
1959        };
1960
1961        // Instance method implementations are a layout block. We rely on
1962        // indentation (token column) to decide where the block ends.
1963        let has_method_block = if saw_where {
1964            true
1965        } else {
1966            let token = self.current_token();
1967            let token_span = *token.span();
1968            let next = self.peek_token(1);
1969            token_span.begin.column > instance_indent
1970                && matches!(next, Token::Assign(..))
1971                && Self::is_value_name_token(&token)
1972        };
1973
1974        let block_indent = if has_method_block {
1975            match self.current_token() {
1976                Token::Ident(_, span, ..) => Some(span.begin.column),
1977                token => Self::operator_token_name(&token).map(|(_, span)| span.begin.column),
1978            }
1979        } else {
1980            None
1981        };
1982
1983        let methods = self.parse_layout_block(has_method_block, block_indent, |parser| {
1984            let (name, _name_span) = parser.parse_value_name()?;
1985            parser.expect_assign()?;
1986
1987            let start_idx = parser.token_cursor;
1988            let end_idx =
1989                find_layout_expr_end(&parser.tokens, start_idx, block_indent, |t, next| {
1990                    matches!(next, Token::Assign(..)) && Self::is_value_name_token(t)
1991                });
1992            let body = parser.parse_expr_slice(&parser.tokens[start_idx..end_idx])?;
1993            parser.token_cursor = end_idx;
1994            parser.skip_newlines();
1995
1996            Ok(InstanceMethodImpl {
1997                name,
1998                body: Arc::new(body),
1999            })
2000        })?;
2001
2002        let span_end = methods
2003            .last()
2004            .map(|m| m.body.span().end)
2005            .or_else(|| context.last().map(|c| c.typ.span().end))
2006            .unwrap_or(header_end.max(where_span.end));
2007
2008        Ok(InstanceDecl {
2009            span: Span::from_begin_end(span_begin, span_end),
2010            is_pub,
2011            class,
2012            head,
2013            context,
2014            methods,
2015        })
2016    }
2017
2018    fn parse_fn_decl(&mut self, is_pub: bool) -> Result<FnDecl, ParserErr> {
2019        let span_begin = match self.current_token() {
2020            Token::Fn(span, ..) => {
2021                self.next_token();
2022                span.begin
2023            }
2024            token => {
2025                return Err(ParserErr::new(
2026                    *token.span(),
2027                    format!("expected `fn` got {}", token),
2028                ));
2029            }
2030        };
2031
2032        let (name, name_span) = match self.current_token() {
2033            Token::Ident(name, span, ..) => {
2034                self.next_token();
2035                (name, span)
2036            }
2037            token => {
2038                return Err(ParserErr::new(
2039                    *token.span(),
2040                    format!("expected function name got {}", token),
2041                ));
2042            }
2043        };
2044
2045        let name_var = Var::with_span(name_span, name);
2046        let mut params: Vec<(Var, TypeExpr)> = Vec::new();
2047
2048        // Signature form:
2049        //   fn add : i32 -> i32 -> i32 = \x y -> x + y
2050        //
2051        // This desugars back into the existing `FnDecl { params, ret, body }` shape by:
2052        // - flattening the signature `a -> b -> c` into param types `[a, b]` and ret `c`
2053        // - extracting lambda binders from the body when present (so we keep user-chosen arg names)
2054        // - otherwise, eta-expanding the body to match the declared arity
2055        if matches!(self.current_token(), Token::Colon(..)) {
2056            self.next_token();
2057
2058            // Parse a full type signature up to `where` or `=`.
2059            let sig_start = self.token_cursor;
2060            let sig_end = self
2061                .find_token_at_depth0(sig_start, self.tokens.len(), |t| {
2062                    matches!(t, Token::Where(..) | Token::Assign(..))
2063                })
2064                .ok_or_else(|| ParserErr::new(self.eof, "expected `=`".to_string()))?;
2065            let sig = self.parse_type_expr_slice(&self.tokens[sig_start..sig_end])?;
2066            self.token_cursor = sig_end;
2067
2068            let mut constraints = Vec::new();
2069            if matches!(self.current_token(), Token::Where(..)) {
2070                self.next_token();
2071                constraints = self.parse_type_constraints()?;
2072            }
2073
2074            // `=`
2075            self.expect_assign()?;
2076
2077            // Parse a body expression until dedent back to the function's indentation.
2078            let body_start = self.token_cursor;
2079            let body_end = self.find_dedent_end(body_start, span_begin.column)?;
2080            let body_expr = self.parse_expr_slice(&self.tokens[body_start..body_end])?;
2081            self.token_cursor = body_end;
2082            let body = Arc::new(body_expr);
2083            let span_end = body.span().end;
2084
2085            // Flatten `a -> b -> c` into params=[a,b], ret=c so downstream code can
2086            // reconstruct the same function type.
2087            let mut param_tys = Vec::new();
2088            let mut cur = sig;
2089            let ret = loop {
2090                match cur {
2091                    TypeExpr::Fun(_, arg, next_ret) => {
2092                        param_tys.push(*arg);
2093                        cur = *next_ret;
2094                    }
2095                    other => break other,
2096                }
2097            };
2098            if param_tys.is_empty() {
2099                return Err(ParserErr::new(
2100                    *ret.span(),
2101                    "expected function type after `:`; use `let` for values".to_string(),
2102                ));
2103            }
2104
2105            let arity = param_tys.len();
2106            let mut body_constraints = Vec::new();
2107            let (params, body) = if matches!(body.as_ref(), Expr::Lam(..)) {
2108                let mut lam_params: Vec<Var> = Vec::new();
2109                let mut cur = body.clone();
2110                while matches!(cur.as_ref(), Expr::Lam(..)) {
2111                    let Expr::Lam(_span, _scope, param, _ann, lam_constraints, next) = cur.as_ref()
2112                    else {
2113                        break;
2114                    };
2115                    if !lam_constraints.is_empty() {
2116                        body_constraints.extend(lam_constraints.iter().cloned());
2117                    }
2118                    lam_params.push(param.clone());
2119                    cur = next.clone();
2120                }
2121
2122                if lam_params.len() != arity {
2123                    return Err(ParserErr::new(
2124                        *body.span(),
2125                        format!(
2126                            "lambda has {} parameter(s) but signature expects {}",
2127                            lam_params.len(),
2128                            arity
2129                        ),
2130                    ));
2131                }
2132
2133                let params: Vec<(Var, TypeExpr)> = lam_params.into_iter().zip(param_tys).collect();
2134                (params, cur)
2135            } else {
2136                // No leading lambda: eta-expand to match the declared arity.
2137                let var_span = *body.span();
2138                let vars: Vec<Var> = (0..arity)
2139                    .map(|i| Var::with_span(var_span, format!("_arg{i}")))
2140                    .collect();
2141
2142                let mut applied = body.clone();
2143                for v in &vars {
2144                    applied = Arc::new(Expr::App(
2145                        Span::from_begin_end(applied.span().begin, applied.span().end),
2146                        applied,
2147                        Arc::new(Expr::Var(v.clone())),
2148                    ));
2149                }
2150
2151                let params: Vec<(Var, TypeExpr)> = vars.into_iter().zip(param_tys).collect();
2152                (params, applied)
2153            };
2154
2155            constraints.extend(body_constraints);
2156
2157            return Ok(FnDecl {
2158                span: Span::from_begin_end(span_begin, span_end),
2159                is_pub,
2160                name: name_var,
2161                params,
2162                ret,
2163                constraints,
2164                body,
2165            });
2166        }
2167
2168        let is_named_param_head = |token: &Token, next: &Token| {
2169            matches!(token, Token::Ident(..)) && matches!(next, Token::Colon(..))
2170        };
2171        let is_paren_param_head = |token: &Token, next: &Token, next2: &Token| {
2172            matches!(token, Token::ParenL(..))
2173                && matches!(next, Token::Ident(..))
2174                && matches!(next2, Token::Colon(..))
2175        };
2176
2177        // Params (new syntax):
2178        //   fn foo x: a -> y: b -> i32 = ...
2179        //   fn foo (x: a) -> (y: b) -> i32 = ...
2180        //   fn foo (x: a) (y: b) -> i32 = ...
2181        //
2182        // Params (legacy syntax, still accepted):
2183        //   fn foo (x: a, y: b) -> i32 = ...
2184        // First, handle the legacy multi-parameter paren list `(x: a, y: b) -> ...`.
2185        if matches!(self.current_token(), Token::ParenL(..)) {
2186            // `()` is also treated as the legacy group syntax (nullary functions).
2187            if self.paren_group_has_top_level_comma(self.token_cursor)
2188                || matches!(self.peek_token(1), Token::ParenR(..))
2189            {
2190                params = self.parse_legacy_param_group()?;
2191
2192                // `->`
2193                match self.current_token() {
2194                    Token::ArrowR(..) => self.next_token(),
2195                    token => {
2196                        return Err(ParserErr::new(
2197                            *token.span(),
2198                            format!("expected `->` got {}", token),
2199                        ));
2200                    }
2201                }
2202            }
2203        }
2204
2205        // New syntax: a chain of named params (`x: a -> ...`) and/or parenthesized params (`(x: a) -> ...`).
2206        // Parameters are always delimited by `->`. Adjacency is not accepted.
2207        if params.is_empty() {
2208            loop {
2209                let tok = self.current_token();
2210                let next = self.peek_token(1);
2211                let next2 = self.peek_token(2);
2212                if is_paren_param_head(&tok, &next, &next2) {
2213                    // (x: a)
2214                    self.next_token(); // `(`
2215                    let (param_name, param_span) = self.expect_ident("parameter name")?;
2216                    self.expect_colon()?;
2217
2218                    // Parse the parameter type, stopping at the closing `)` at depth 0.
2219                    let ty_start = self.token_cursor;
2220                    let rparen_idx = self
2221                        .find_token_at_depth0(ty_start, self.tokens.len(), |t| {
2222                            matches!(t, Token::ParenR(..))
2223                        })
2224                        .ok_or_else(|| ParserErr::new(self.eof, "expected `)`".to_string()))?;
2225                    let ann = self.parse_type_expr_slice(&self.tokens[ty_start..rparen_idx])?;
2226                    self.token_cursor = rparen_idx;
2227
2228                    let _ = self.expect_paren_r()?;
2229
2230                    params.push((Var::with_span(param_span, param_name), ann));
2231                } else if is_named_param_head(&tok, &next) {
2232                    // x: a -> y: b -> i32
2233                    let (param_name, param_span) = self.expect_ident("parameter name")?;
2234
2235                    self.expect_colon()?;
2236
2237                    // Parse the parameter type, stopping at the `->` separator at depth 0.
2238                    // To use a function type as a parameter type, parentheses are required:
2239                    //   x: (a -> c) -> ...
2240                    let ty_start = self.token_cursor;
2241                    let mut depth = 0usize;
2242                    let mut arrow_idx = None;
2243                    let mut stop_span = None;
2244                    for i in ty_start..self.tokens.len() {
2245                        match self.tokens[i] {
2246                            Token::ParenL(..) | Token::BracketL(..) | Token::BraceL(..) => {
2247                                depth += 1
2248                            }
2249                            Token::ParenR(..) | Token::BracketR(..) | Token::BraceR(..) => {
2250                                depth = depth.saturating_sub(1)
2251                            }
2252                            Token::ArrowR(..) if depth == 0 => {
2253                                arrow_idx = Some(i);
2254                                break;
2255                            }
2256                            Token::Assign(span, ..) | Token::Where(span, ..) if depth == 0 => {
2257                                stop_span = Some(span);
2258                                break;
2259                            }
2260                            _ => {}
2261                        }
2262                    }
2263                    let Some(arrow_idx) = arrow_idx else {
2264                        let span = stop_span.unwrap_or(self.eof);
2265                        return Err(ParserErr::new(
2266                            span,
2267                            "expected `->` after parameter type".to_string(),
2268                        ));
2269                    };
2270                    let ann = self.parse_type_expr_slice(&self.tokens[ty_start..arrow_idx])?;
2271                    self.token_cursor = arrow_idx;
2272                    params.push((Var::with_span(param_span, param_name), ann));
2273                } else {
2274                    return Err(ParserErr::new(
2275                        *tok.span(),
2276                        format!("expected `(` or parameter name got {}", tok),
2277                    ));
2278                }
2279
2280                // Separator: always `->` after a parameter.
2281                match self.current_token() {
2282                    Token::ArrowR(..) => self.next_token(),
2283                    token => {
2284                        return Err(ParserErr::new(
2285                            *token.span(),
2286                            format!("expected `->` got {}", token),
2287                        ));
2288                    }
2289                }
2290
2291                // If another param head follows, keep parsing params; otherwise we are at the return type.
2292                let tok = self.current_token();
2293                let next = self.peek_token(1);
2294                let next2 = self.peek_token(2);
2295                if is_paren_param_head(&tok, &next, &next2) || is_named_param_head(&tok, &next) {
2296                    continue;
2297                }
2298                break;
2299            }
2300        }
2301
2302        // Find `=` and (optional) `where` between return type and `=`.
2303        let ret_start = self.token_cursor;
2304        let assign_idx = self
2305            .find_token_at_depth0(ret_start, self.tokens.len(), |t| {
2306                matches!(t, Token::Assign(..))
2307            })
2308            .ok_or_else(|| {
2309                ParserErr::new(self.eof, "expected `=` in function declaration".to_string())
2310            })?;
2311
2312        let ret_end = self
2313            .find_token_at_depth0(ret_start, assign_idx, |t| matches!(t, Token::Where(..)))
2314            .unwrap_or(assign_idx);
2315        let ret = self.parse_type_expr_slice(&self.tokens[ret_start..ret_end])?;
2316        self.token_cursor = ret_end;
2317
2318        let mut constraints = Vec::new();
2319        if matches!(self.current_token(), Token::Where(..)) {
2320            self.next_token();
2321            constraints = self.parse_type_constraints()?;
2322        }
2323
2324        // `=`
2325        self.expect_assign()?;
2326
2327        // Parse a body expression, delimited by newline (unless inside parens/brackets/braces).
2328        let body_start = self.token_cursor;
2329        let body_end = self.find_same_line_end(body_start)?;
2330        let body = self.parse_expr_slice(&self.tokens[body_start..body_end])?;
2331        self.token_cursor = body_end;
2332        let span_end = body.span().end;
2333
2334        Ok(FnDecl {
2335            span: Span::from_begin_end(span_begin, span_end),
2336            is_pub,
2337            name: name_var,
2338            params,
2339            ret,
2340            constraints,
2341            body: Arc::new(body),
2342        })
2343    }
2344
2345    fn parse_declare_fn_decl_toplevel(&mut self, is_pub: bool) -> Result<DeclareFnDecl, ParserErr> {
2346        let start_idx = self.token_cursor;
2347        // `declare fn` has no body, so we parse only the declaration line.
2348        let end_idx = self.find_same_line_end(start_idx)?;
2349
2350        let eof = self
2351            .tokens
2352            .get(end_idx.saturating_sub(1))
2353            .map(|t| *t.span())
2354            .unwrap_or(self.eof);
2355        let tokens = Tokens {
2356            items: self.tokens[start_idx..end_idx].to_vec(),
2357            eof,
2358        };
2359        let mut parser = Parser::new(tokens);
2360        let decl = parser.parse_declare_fn_decl(is_pub)?;
2361        match parser.current_token() {
2362            Token::Eof(..) => {}
2363            token => {
2364                return Err(ParserErr::new(
2365                    *token.span(),
2366                    format!("unexpected {} in declaration", token),
2367                ));
2368            }
2369        }
2370
2371        self.token_cursor = end_idx;
2372        self.skip_newlines();
2373        Ok(decl)
2374    }
2375
2376    fn parse_declare_fn_decl(&mut self, is_pub: bool) -> Result<DeclareFnDecl, ParserErr> {
2377        let span_begin = match self.current_token() {
2378            Token::Declare(span, ..) => {
2379                self.next_token();
2380                span.begin
2381            }
2382            token => {
2383                return Err(ParserErr::new(
2384                    *token.span(),
2385                    format!("expected `declare` got {}", token),
2386                ));
2387            }
2388        };
2389
2390        match self.current_token() {
2391            Token::Fn(..) => self.next_token(),
2392            token => {
2393                return Err(ParserErr::new(
2394                    *token.span(),
2395                    format!("expected `fn` got {}", token),
2396                ));
2397            }
2398        }
2399
2400        let (name, name_span) = match self.current_token() {
2401            Token::Ident(name, span, ..) => {
2402                self.next_token();
2403                (name, span)
2404            }
2405            token => {
2406                return Err(ParserErr::new(
2407                    *token.span(),
2408                    format!("expected function name got {}", token),
2409                ));
2410            }
2411        };
2412
2413        let name_var = Var::with_span(name_span, name);
2414        let mut params: Vec<(Var, TypeExpr)> = Vec::new();
2415
2416        // Allow an optional signature delimiter:
2417        //   declare fn id : a -> a
2418        if matches!(self.current_token(), Token::Colon(..)) {
2419            self.next_token();
2420        }
2421
2422        let is_named_param_head = |token: &Token, next: &Token| {
2423            matches!(token, Token::Ident(..)) && matches!(next, Token::Colon(..))
2424        };
2425        let is_paren_param_head = |token: &Token, next: &Token, next2: &Token| {
2426            matches!(token, Token::ParenL(..))
2427                && matches!(next, Token::Ident(..))
2428                && matches!(next2, Token::Colon(..))
2429        };
2430
2431        // `declare fn` supports two surface syntaxes:
2432        //  1) A full `fn`-style header with named parameters.
2433        //  2) A bare type signature (like class methods): `declare fn id a -> a`.
2434        let tok = self.current_token();
2435        let next = self.peek_token(1);
2436        let next2 = self.peek_token(2);
2437        let mut use_named_params =
2438            is_named_param_head(&tok, &next) || is_paren_param_head(&tok, &next, &next2);
2439
2440        if !use_named_params && matches!(tok, Token::ParenL(..)) {
2441            // `()` means nullary params in the legacy `fn` syntax, so treat it as named-params mode.
2442            if matches!(next, Token::ParenR(..)) {
2443                use_named_params = true;
2444            } else {
2445                // Disambiguate legacy `(x: a, y: b)` params from grouped type expressions like `(a, b) -> c`.
2446                if self.paren_group_has_top_level_colon(self.token_cursor) {
2447                    use_named_params = true;
2448                }
2449            }
2450        }
2451
2452        if !use_named_params {
2453            // Parse a bare type signature.
2454            let sig_start = self.token_cursor;
2455            let stop_idx = self.find_token_at_depth0(sig_start, self.tokens.len(), |t| {
2456                matches!(t, Token::Where(..) | Token::Assign(..))
2457            });
2458            let sig_end = match stop_idx {
2459                Some(i) => match self.tokens[i] {
2460                    Token::Where(..) => i,
2461                    Token::Assign(span, ..) => {
2462                        return Err(ParserErr::new(
2463                            span,
2464                            "declare fn cannot have a body; use `fn`".to_string(),
2465                        ));
2466                    }
2467                    _ => i,
2468                },
2469                None => self.tokens.len(),
2470            };
2471            let sig = self.parse_type_expr_slice(&self.tokens[sig_start..sig_end])?;
2472            self.token_cursor = sig_end;
2473
2474            let mut constraints = Vec::new();
2475            if matches!(self.current_token(), Token::Where(..)) {
2476                self.next_token();
2477                constraints = self.parse_type_constraints()?;
2478            }
2479
2480            // Flatten `a -> b -> c` into params=[a,b], ret=c so downstream code can
2481            // reconstruct the same function type.
2482            let mut param_tys = Vec::new();
2483            let mut cur = sig;
2484            let ret = loop {
2485                match cur {
2486                    TypeExpr::Fun(_, arg, next_ret) => {
2487                        param_tys.push(*arg);
2488                        cur = *next_ret;
2489                    }
2490                    other => break other,
2491                }
2492            };
2493            params = param_tys
2494                .into_iter()
2495                .enumerate()
2496                .map(|(i, ann)| (Var::with_span(*ann.span(), format!("_arg{i}")), ann))
2497                .collect();
2498
2499            let span_end = constraints
2500                .last()
2501                .map(|c| c.typ.span().end)
2502                .unwrap_or(ret.span().end);
2503            return Ok(DeclareFnDecl {
2504                span: Span::from_begin_end(span_begin, span_end),
2505                is_pub,
2506                name: name_var,
2507                params,
2508                ret,
2509                constraints,
2510            });
2511        }
2512
2513        // Params (new syntax):
2514        //   declare fn foo x: a -> y: b -> i32 where ...
2515        //   declare fn foo (x: a) -> (y: b) -> i32
2516        //
2517        // Params (legacy syntax, still accepted):
2518        //   declare fn foo (x: a, y: b) -> i32
2519        if matches!(self.current_token(), Token::ParenL(..)) {
2520            // `()` is also treated as the legacy group syntax (nullary functions).
2521            if self.paren_group_has_top_level_comma(self.token_cursor)
2522                || matches!(self.peek_token(1), Token::ParenR(..))
2523            {
2524                params = self.parse_legacy_param_group()?;
2525
2526                // `->`
2527                match self.current_token() {
2528                    Token::ArrowR(..) => self.next_token(),
2529                    token => {
2530                        return Err(ParserErr::new(
2531                            *token.span(),
2532                            format!("expected `->` got {}", token),
2533                        ));
2534                    }
2535                }
2536            }
2537        }
2538
2539        // New syntax: a chain of named params (`x: a -> ...`) and/or parenthesized params (`(x: a) -> ...`).
2540        // Parameters are always delimited by `->`. Adjacency is not accepted.
2541        if params.is_empty() {
2542            loop {
2543                let tok = self.current_token();
2544                let next = self.peek_token(1);
2545                let next2 = self.peek_token(2);
2546                if is_paren_param_head(&tok, &next, &next2) {
2547                    // (x: a)
2548                    self.next_token(); // `(`
2549                    let (param_name, param_span) = self.expect_ident("parameter name")?;
2550                    self.expect_colon()?;
2551
2552                    // Parse the parameter type, stopping at the closing `)` at depth 0.
2553                    let ty_start = self.token_cursor;
2554                    let rparen_idx = self
2555                        .find_token_at_depth0(ty_start, self.tokens.len(), |t| {
2556                            matches!(t, Token::ParenR(..))
2557                        })
2558                        .ok_or_else(|| ParserErr::new(self.eof, "expected `)`".to_string()))?;
2559                    let ann = self.parse_type_expr_slice(&self.tokens[ty_start..rparen_idx])?;
2560                    self.token_cursor = rparen_idx;
2561
2562                    let _ = self.expect_paren_r()?;
2563
2564                    params.push((Var::with_span(param_span, param_name), ann));
2565                } else if is_named_param_head(&tok, &next) {
2566                    // x: a -> y: b -> i32
2567                    let (param_name, param_span) = self.expect_ident("parameter name")?;
2568                    self.expect_colon()?;
2569
2570                    // Parse the parameter type, stopping at the `->` separator at depth 0.
2571                    // To use a function type as a parameter type, parentheses are required:
2572                    //   x: (a -> c) -> ...
2573                    let ty_start = self.token_cursor;
2574                    let mut depth = 0usize;
2575                    let mut arrow_idx = None;
2576                    let mut stop_span = None;
2577                    for i in ty_start..self.tokens.len() {
2578                        match self.tokens[i] {
2579                            Token::ParenL(..) | Token::BracketL(..) | Token::BraceL(..) => {
2580                                depth += 1
2581                            }
2582                            Token::ParenR(..) | Token::BracketR(..) | Token::BraceR(..) => {
2583                                depth = depth.saturating_sub(1)
2584                            }
2585                            Token::ArrowR(..) if depth == 0 => {
2586                                arrow_idx = Some(i);
2587                                break;
2588                            }
2589                            Token::Where(span, ..) if depth == 0 => {
2590                                stop_span = Some(span);
2591                                break;
2592                            }
2593                            _ => {}
2594                        }
2595                    }
2596                    let Some(arrow_idx) = arrow_idx else {
2597                        let span = stop_span.unwrap_or(self.eof);
2598                        return Err(ParserErr::new(
2599                            span,
2600                            "expected `->` after parameter type".to_string(),
2601                        ));
2602                    };
2603                    let ann = self.parse_type_expr_slice(&self.tokens[ty_start..arrow_idx])?;
2604                    self.token_cursor = arrow_idx;
2605                    params.push((Var::with_span(param_span, param_name), ann));
2606                } else {
2607                    return Err(ParserErr::new(
2608                        *tok.span(),
2609                        format!("expected `(` or parameter name got {}", tok),
2610                    ));
2611                }
2612
2613                // Separator: always `->` after a parameter.
2614                match self.current_token() {
2615                    Token::ArrowR(..) => self.next_token(),
2616                    token => {
2617                        return Err(ParserErr::new(
2618                            *token.span(),
2619                            format!("expected `->` got {}", token),
2620                        ));
2621                    }
2622                }
2623
2624                // If another param head follows, keep parsing params; otherwise we are at the return type.
2625                let tok = self.current_token();
2626                let next = self.peek_token(1);
2627                let next2 = self.peek_token(2);
2628                if is_paren_param_head(&tok, &next, &next2) || is_named_param_head(&tok, &next) {
2629                    continue;
2630                }
2631                break;
2632            }
2633        }
2634
2635        // Find an (optional) `where` in the remaining tokens. `declare fn` must not have `=`.
2636        let ret_start = self.token_cursor;
2637        let stop_idx = self.find_token_at_depth0(ret_start, self.tokens.len(), |t| {
2638            matches!(t, Token::Where(..) | Token::Assign(..))
2639        });
2640        let ret_end = match stop_idx {
2641            Some(i) => match self.tokens[i] {
2642                Token::Where(..) => i,
2643                Token::Assign(span, ..) => {
2644                    return Err(ParserErr::new(
2645                        span,
2646                        "declare fn cannot have a body; use `fn`".to_string(),
2647                    ));
2648                }
2649                _ => i,
2650            },
2651            None => self.tokens.len(),
2652        };
2653        let ret = self.parse_type_expr_slice(&self.tokens[ret_start..ret_end])?;
2654        self.token_cursor = ret_end;
2655
2656        let mut constraints = Vec::new();
2657        if matches!(self.current_token(), Token::Where(..)) {
2658            self.next_token();
2659            constraints = self.parse_type_constraints()?;
2660        }
2661
2662        let span_end = constraints
2663            .last()
2664            .map(|c| c.typ.span().end)
2665            .unwrap_or(ret.span().end);
2666        Ok(DeclareFnDecl {
2667            span: Span::from_begin_end(span_begin, span_end),
2668            is_pub,
2669            name: name_var,
2670            params,
2671            ret,
2672            constraints,
2673        })
2674    }
2675
2676    fn parse_import_decl(&mut self, is_pub: bool) -> Result<ImportDecl, ParserErr> {
2677        let span_begin = match self.current_token() {
2678            Token::Import(span, ..) => {
2679                self.next_token();
2680                span.begin
2681            }
2682            token => {
2683                return Err(ParserErr::new(
2684                    *token.span(),
2685                    format!("expected `import` got {}", token),
2686                ));
2687            }
2688        };
2689
2690        let (path, mut span_end, default_alias) = match self.current_token() {
2691            Token::HttpsUrl(url, span, ..) => {
2692                let url = url.clone();
2693                self.next_token();
2694                let (base_url, sha) = match url.split_once('#') {
2695                    Some((a, b)) if !b.is_empty() => (a.to_string(), Some(b.to_string())),
2696                    _ => (url, None),
2697                };
2698                let alias = base_url
2699                    .rsplit('/')
2700                    .next()
2701                    .unwrap_or("")
2702                    .trim_end_matches(".rex")
2703                    .to_string();
2704                (
2705                    ImportPath::Remote { url: base_url, sha },
2706                    span.end,
2707                    if alias.is_empty() {
2708                        None
2709                    } else {
2710                        Some(intern(&alias))
2711                    },
2712                )
2713            }
2714            Token::Dot(..) | Token::DotDot(..) => {
2715                let (mut segs, end) = self.parse_relative_import_segments()?;
2716
2717                let sha = if matches!(self.current_token(), Token::HashTag(..)) {
2718                    self.next_token();
2719                    match self.current_token() {
2720                        Token::Ident(s, span, ..) => {
2721                            self.next_token();
2722                            Some((s.clone(), span.end))
2723                        }
2724                        Token::Int(n, span, ..) => {
2725                            self.next_token();
2726                            Some((n.to_string(), span.end))
2727                        }
2728                        token => {
2729                            return Err(ParserErr::new(
2730                                *token.span(),
2731                                format!("expected sha token got {}", token),
2732                            ));
2733                        }
2734                    }
2735                } else {
2736                    None
2737                };
2738                let mut end = end;
2739                let sha = sha.map(|(sha, sha_end)| {
2740                    end = end.max(sha_end);
2741                    sha
2742                });
2743                let default_alias = segs.last().cloned();
2744                if segs.is_empty() {
2745                    return Err(ParserErr::new(
2746                        *self.current_token().span(),
2747                        "relative import must include a library path",
2748                    ));
2749                }
2750                (
2751                    ImportPath::Local {
2752                        segments: std::mem::take(&mut segs),
2753                        sha,
2754                    },
2755                    end,
2756                    default_alias,
2757                )
2758            }
2759            Token::Ident(..) => {
2760                let mut segs: Vec<Symbol> = Vec::new();
2761                let (first, first_span) = match self.current_token() {
2762                    Token::Ident(name, span, ..) => (intern(&name), span),
2763                    token => {
2764                        return Err(ParserErr::new(
2765                            *token.span(),
2766                            format!("expected library path segment got {}", token),
2767                        ));
2768                    }
2769                };
2770                let mut end = first_span.end;
2771                segs.push(first);
2772                self.next_token();
2773
2774                while matches!(self.current_token(), Token::Dot(..)) {
2775                    self.next_token();
2776                    let (seg, seg_span) = match self.current_token() {
2777                        Token::Ident(name, span, ..) => (intern(&name), span),
2778                        token => {
2779                            return Err(ParserErr::new(
2780                                *token.span(),
2781                                format!("expected library path segment got {}", token),
2782                            ));
2783                        }
2784                    };
2785                    segs.push(seg);
2786                    end = seg_span.end;
2787                    self.next_token();
2788                }
2789
2790                let sha = if matches!(self.current_token(), Token::HashTag(..)) {
2791                    self.next_token();
2792                    match self.current_token() {
2793                        Token::Ident(s, span, ..) => {
2794                            self.next_token();
2795                            end = end.max(span.end);
2796                            Some(s.clone())
2797                        }
2798                        Token::Int(n, span, ..) => {
2799                            self.next_token();
2800                            end = end.max(span.end);
2801                            Some(n.to_string())
2802                        }
2803                        token => {
2804                            return Err(ParserErr::new(
2805                                *token.span(),
2806                                format!("expected sha token got {}", token),
2807                            ));
2808                        }
2809                    }
2810                } else {
2811                    None
2812                };
2813                let default_alias = segs.last().cloned();
2814                (
2815                    ImportPath::Local {
2816                        segments: segs,
2817                        sha,
2818                    },
2819                    end,
2820                    default_alias,
2821                )
2822            }
2823            token => {
2824                return Err(ParserErr::new(
2825                    *token.span(),
2826                    format!("expected library path got {}", token),
2827                ));
2828            }
2829        };
2830
2831        let clause = if matches!(self.current_token(), Token::ParenL(..)) {
2832            self.next_token();
2833            if matches!(self.current_token(), Token::Mul(..)) {
2834                self.next_token();
2835                let end = match self.current_token() {
2836                    Token::ParenR(span, ..) => {
2837                        self.next_token();
2838                        span.end
2839                    }
2840                    token => {
2841                        return Err(ParserErr::new(
2842                            *token.span(),
2843                            format!("expected `)` got {}", token),
2844                        ));
2845                    }
2846                };
2847                span_end = span_end.max(end);
2848                Some(ImportClause::All)
2849            } else {
2850                let mut items: Vec<ImportItem> = Vec::new();
2851                let mut local_names: HashSet<Symbol> = HashSet::new();
2852                loop {
2853                    let (name, item_span) = self.parse_value_name()?;
2854                    let mut item_end = item_span.end;
2855                    let alias = if matches!(self.current_token(), Token::As(..)) {
2856                        self.next_token();
2857                        match self.current_token() {
2858                            Token::Ident(alias, alias_span, ..) => {
2859                                self.next_token();
2860                                item_end = alias_span.end;
2861                                Some(intern(&alias))
2862                            }
2863                            token => {
2864                                return Err(ParserErr::new(
2865                                    *token.span(),
2866                                    format!("expected alias name got {}", token),
2867                                ));
2868                            }
2869                        }
2870                    } else {
2871                        None
2872                    };
2873
2874                    let local_name = alias.clone().unwrap_or_else(|| name.clone());
2875                    if local_names.contains(&local_name) {
2876                        return Err(ParserErr::new(
2877                            Span::from_begin_end(item_span.begin, item_end),
2878                            format!("duplicate imported name `{local_name}`"),
2879                        ));
2880                    }
2881                    local_names.insert(local_name);
2882                    items.push(ImportItem { name, alias });
2883
2884                    match self.current_token() {
2885                        Token::Comma(..) => {
2886                            self.next_token();
2887                        }
2888                        Token::ParenR(span, ..) => {
2889                            self.next_token();
2890                            span_end = span_end.max(span.end.max(item_end));
2891                            break;
2892                        }
2893                        token => {
2894                            return Err(ParserErr::new(
2895                                *token.span(),
2896                                format!("expected `,` or `)` got {}", token),
2897                            ));
2898                        }
2899                    }
2900                }
2901                Some(ImportClause::Items(items))
2902            }
2903        } else {
2904            None
2905        };
2906
2907        let alias = if matches!(self.current_token(), Token::As(..)) {
2908            if clause.is_some() {
2909                let span = *self.current_token().span();
2910                return Err(ParserErr::new(
2911                    span,
2912                    "cannot combine `as <alias>` with import clause `(...)`".to_string(),
2913                ));
2914            }
2915            self.next_token();
2916            match self.current_token() {
2917                Token::Ident(name, span, ..) => {
2918                    self.next_token();
2919                    span_end = span_end.max(span.end);
2920                    intern(&name)
2921                }
2922                token => {
2923                    return Err(ParserErr::new(
2924                        *token.span(),
2925                        format!("expected alias name got {}", token),
2926                    ));
2927                }
2928            }
2929        } else {
2930            default_alias
2931                .or_else(|| clause.as_ref().map(|_| intern("_")))
2932                .ok_or_else(|| {
2933                    ParserErr::new(
2934                        Span::from_begin_end(span_begin, span_end),
2935                        "import requires `as <alias>`".to_string(),
2936                    )
2937                })?
2938        };
2939
2940        self.skip_newlines();
2941        Ok(ImportDecl {
2942            span: Span::from_begin_end(span_begin, span_end),
2943            is_pub,
2944            path,
2945            alias,
2946            clause,
2947        })
2948    }
2949
2950    fn parse_relative_import_segments(&mut self) -> Result<(Vec<Symbol>, Position), ParserErr> {
2951        let mut segments: Vec<Symbol> = Vec::new();
2952
2953        loop {
2954            if matches!(self.current_token(), Token::DotDot(..)) {
2955                self.next_token();
2956                segments.push(intern("super"));
2957            } else {
2958                match self.current_token() {
2959                    Token::Dot(..) => self.next_token(),
2960                    token => {
2961                        return Err(ParserErr::new(
2962                            *token.span(),
2963                            "expected `.` or `..` in relative import path",
2964                        ));
2965                    }
2966                }
2967            }
2968
2969            match self.current_token() {
2970                Token::Div(..) => self.next_token(),
2971                token => {
2972                    return Err(ParserErr::new(
2973                        *token.span(),
2974                        "expected `/` in relative import path",
2975                    ));
2976                }
2977            }
2978
2979            if !matches!(self.current_token(), Token::Dot(..) | Token::DotDot(..)) {
2980                break;
2981            }
2982        }
2983
2984        let (first, first_span) = match self.current_token() {
2985            Token::Ident(name, span, ..) => (intern(&name), span),
2986            token => {
2987                return Err(ParserErr::new(
2988                    *token.span(),
2989                    format!("expected library path segment got {}", token),
2990                ));
2991            }
2992        };
2993        segments.push(first);
2994        let mut end = first_span.end;
2995        self.next_token();
2996
2997        loop {
2998            if !matches!(self.current_token(), Token::Dot(..) | Token::Div(..)) {
2999                break;
3000            }
3001            self.next_token();
3002            let (seg, seg_span) = match self.current_token() {
3003                Token::Ident(name, span, ..) => (intern(&name), span),
3004                token => {
3005                    return Err(ParserErr::new(
3006                        *token.span(),
3007                        format!("expected library path segment got {}", token),
3008                    ));
3009                }
3010            };
3011            segments.push(seg);
3012            end = seg_span.end;
3013            self.next_token();
3014        }
3015
3016        Ok((segments, end))
3017    }
3018
3019    fn parse_type_decl(&mut self, is_pub: bool) -> Result<TypeDecl, ParserErr> {
3020        let span_begin = match self.current_token() {
3021            Token::Type(span, ..) => {
3022                self.next_token();
3023                span.begin
3024            }
3025            token => {
3026                return Err(ParserErr::new(
3027                    *token.span(),
3028                    format!("expected `type` got {}", token),
3029                ));
3030            }
3031        };
3032
3033        let (name, _name_span) = match self.current_token() {
3034            Token::Ident(name, span, ..) => {
3035                let name = intern(&name);
3036                self.next_token();
3037                (name, span)
3038            }
3039            token => {
3040                return Err(ParserErr::new(
3041                    *token.span(),
3042                    format!("expected type name got {}", token),
3043                ));
3044            }
3045        };
3046
3047        let mut params = Vec::new();
3048        while let Token::Ident(_param, ..) = self.current_token() {
3049            let name = match self.current_token() {
3050                Token::Ident(param, ..) => intern(&param),
3051                _ => unreachable!(),
3052            };
3053            self.next_token();
3054            params.push(name);
3055        }
3056
3057        match self.current_token() {
3058            Token::Assign(..) => self.next_token(),
3059            token => {
3060                return Err(ParserErr::new(
3061                    *token.span(),
3062                    format!("expected `=` got {}", token),
3063                ));
3064            }
3065        }
3066
3067        let (first, first_span) = self.parse_type_variant()?;
3068        let mut variants = vec![first];
3069        let mut span_end = first_span.end;
3070        while let Token::Pipe(..) = self.current_token() {
3071            self.next_token();
3072            let (variant, vspan) = self.parse_type_variant()?;
3073            span_end = vspan.end;
3074            variants.push(variant);
3075        }
3076
3077        Ok(TypeDecl {
3078            span: Span::from_begin_end(span_begin, span_end),
3079            is_pub,
3080            name,
3081            params,
3082            variants,
3083        })
3084    }
3085
3086    fn parse_type_variant(&mut self) -> Result<(TypeVariant, Span), ParserErr> {
3087        let (name, name_span) = match self.current_token() {
3088            Token::Ident(name, span, ..) => {
3089                let name = intern(&name);
3090                self.next_token();
3091                (name, span)
3092            }
3093            token => {
3094                return Err(ParserErr::new(
3095                    *token.span(),
3096                    format!("expected constructor name got {}", token),
3097                ));
3098            }
3099        };
3100
3101        let mut args = Vec::new();
3102        let mut span_end = name_span.end;
3103        while let Token::Ident(..) | Token::ParenL(..) | Token::BraceL(..) = self.current_token() {
3104            let arg = self.parse_type_atom()?;
3105            span_end = arg.span().end;
3106            args.push(arg);
3107        }
3108
3109        Ok((
3110            TypeVariant { name, args },
3111            Span::from_begin_end(name_span.begin, span_end),
3112        ))
3113    }
3114
3115    fn parse_type_expr(&mut self) -> Result<TypeExpr, ParserErr> {
3116        self.parse_type_fun()
3117    }
3118
3119    fn parse_type_fun(&mut self) -> Result<TypeExpr, ParserErr> {
3120        let span = *self.current_token().span();
3121        self.with_nesting(span, |this| {
3122            let lhs = this.parse_type_app()?;
3123            match this.current_token() {
3124                Token::ArrowR(..) => {
3125                    this.next_token();
3126                    let rhs = this.parse_type_fun()?;
3127                    let span = Span::from_begin_end(lhs.span().begin, rhs.span().end);
3128                    Ok(TypeExpr::Fun(span, Box::new(lhs), Box::new(rhs)))
3129                }
3130                _ => Ok(lhs),
3131            }
3132        })
3133    }
3134
3135    fn parse_type_app(&mut self) -> Result<TypeExpr, ParserErr> {
3136        let mut lhs = self.parse_type_atom()?;
3137        while let Token::Ident(..) | Token::ParenL(..) | Token::BraceL(..) = self.current_token() {
3138            let rhs = self.parse_type_atom()?;
3139            let span = Span::from_begin_end(lhs.span().begin, rhs.span().end);
3140            lhs = TypeExpr::App(span, Box::new(lhs), Box::new(rhs));
3141        }
3142        Ok(lhs)
3143    }
3144
3145    fn parse_type_atom(&mut self) -> Result<TypeExpr, ParserErr> {
3146        match self.current_token() {
3147            Token::Ident(..) => {
3148                let (name, span) = self.parse_name_ref_with_span("expected type identifier")?;
3149                Ok(TypeExpr::Name(span, name))
3150            }
3151            Token::ParenL(..) => self.parse_type_paren(),
3152            Token::BraceL(..) => self.parse_type_record(),
3153            token => Err(ParserErr::new(
3154                *token.span(),
3155                format!("unexpected {} in type", token),
3156            )),
3157        }
3158    }
3159
3160    fn parse_type_paren(&mut self) -> Result<TypeExpr, ParserErr> {
3161        let span_begin = match self.current_token() {
3162            Token::ParenL(span, ..) => {
3163                self.next_token();
3164                span.begin
3165            }
3166            token => {
3167                return Err(ParserErr::new(
3168                    *token.span(),
3169                    format!("expected `(` got {}", token),
3170                ));
3171            }
3172        };
3173
3174        self.with_nesting(Span::from_begin_end(span_begin, span_begin), |this| {
3175            // Unit type: `()`
3176            if let Token::ParenR(span, ..) = this.current_token() {
3177                this.next_token();
3178                return Ok(TypeExpr::Tuple(
3179                    Span::from_begin_end(span_begin, span.end),
3180                    Vec::new(),
3181                ));
3182            }
3183
3184            let first = this.parse_type_expr()?;
3185            let mut elems = Vec::new();
3186            let span_end = match this.current_token() {
3187                Token::Comma(..) => {
3188                    this.next_token();
3189                    elems.push(first);
3190                    loop {
3191                        elems.push(this.parse_type_expr()?);
3192                        match this.current_token() {
3193                            Token::Comma(..) => {
3194                                this.next_token();
3195                                continue;
3196                            }
3197                            Token::ParenR(span, ..) => {
3198                                this.next_token();
3199                                break span.end;
3200                            }
3201                            token => {
3202                                return Err(ParserErr::new(
3203                                    *token.span(),
3204                                    format!("expected `)` got {}", token),
3205                                ));
3206                            }
3207                        }
3208                    }
3209                }
3210                Token::ParenR(_span, ..) => {
3211                    this.next_token();
3212                    return Ok(first);
3213                }
3214                token => {
3215                    return Err(ParserErr::new(
3216                        *token.span(),
3217                        format!("expected `)` or `,` got {}", token),
3218                    ));
3219                }
3220            };
3221
3222            Ok(TypeExpr::Tuple(
3223                Span::from_begin_end(span_begin, span_end),
3224                elems,
3225            ))
3226        })
3227    }
3228
3229    fn parse_type_record(&mut self) -> Result<TypeExpr, ParserErr> {
3230        let span_begin = match self.current_token() {
3231            Token::BraceL(span, ..) => {
3232                self.next_token();
3233                span.begin
3234            }
3235            token => {
3236                return Err(ParserErr::new(
3237                    *token.span(),
3238                    format!("expected `{{` got {}", token),
3239                ));
3240            }
3241        };
3242
3243        self.with_nesting(Span::from_begin_end(span_begin, span_begin), |this| {
3244            let mut fields = Vec::new();
3245            if let Token::BraceR(span, ..) = this.current_token() {
3246                this.next_token();
3247                return Ok(TypeExpr::Record(
3248                    Span::from_begin_end(span_begin, span.end),
3249                    fields,
3250                ));
3251            }
3252
3253            let span_end = loop {
3254                let (name, _span) = match this.current_token() {
3255                    Token::Ident(name, span, ..) => {
3256                        let name = intern(&name);
3257                        this.next_token();
3258                        (name, span)
3259                    }
3260                    token => {
3261                        return Err(ParserErr::new(
3262                            *token.span(),
3263                            format!("expected field name got {}", token),
3264                        ));
3265                    }
3266                };
3267
3268                match this.current_token() {
3269                    Token::Colon(..) => this.next_token(),
3270                    token => {
3271                        return Err(ParserErr::new(
3272                            *token.span(),
3273                            format!("expected `:` got {}", token),
3274                        ));
3275                    }
3276                }
3277
3278                let ty = this.parse_type_expr()?;
3279                fields.push((name, ty));
3280
3281                match this.current_token() {
3282                    Token::Comma(..) => {
3283                        this.next_token();
3284                    }
3285                    Token::BraceR(span, ..) => {
3286                        this.next_token();
3287                        break span.end;
3288                    }
3289                    token => {
3290                        return Err(ParserErr::new(
3291                            *token.span(),
3292                            format!("expected `}}` got {}", token),
3293                        ));
3294                    }
3295                }
3296            };
3297
3298            Ok(TypeExpr::Record(
3299                Span::from_begin_end(span_begin, span_end),
3300                fields,
3301            ))
3302        })
3303    }
3304
3305    fn parse_pattern(&mut self) -> Result<Pattern, ParserErr> {
3306        self.parse_pattern_cons()
3307    }
3308
3309    fn parse_pattern_cons(&mut self) -> Result<Pattern, ParserErr> {
3310        let span = *self.current_token().span();
3311        self.with_nesting(span, |this| {
3312            let mut lhs = this.parse_pattern_app()?;
3313            while let Token::ColonColon(..) = this.current_token() {
3314                this.next_token();
3315                let rhs = this.parse_pattern_cons()?;
3316                let span = Span::from_begin_end(lhs.span().begin, rhs.span().end);
3317                lhs = Pattern::Cons(span, Box::new(lhs), Box::new(rhs));
3318            }
3319            Ok(lhs)
3320        })
3321    }
3322
3323    fn parse_pattern_app(&mut self) -> Result<Pattern, ParserErr> {
3324        let mut head = self.parse_pattern_atom()?;
3325        if let Pattern::Var(var) = &head
3326            && matches!(self.current_token(), Token::Dot(..))
3327        {
3328            let mut segments = vec![var.name.clone()];
3329            let mut end = var.span.end;
3330            while matches!(self.current_token(), Token::Dot(..)) {
3331                self.next_token();
3332                match self.current_token() {
3333                    Token::Ident(name, seg_span, ..) => {
3334                        segments.push(intern(&name));
3335                        end = seg_span.end;
3336                        self.next_token();
3337                    }
3338                    token => {
3339                        return Err(ParserErr::new(
3340                            *token.span(),
3341                            "expected identifier after `.` in constructor pattern",
3342                        ));
3343                    }
3344                }
3345            }
3346            head = Pattern::Named(
3347                Span::from_begin_end(var.span.begin, end),
3348                NameRef::from_segments(segments),
3349                vec![],
3350            );
3351        }
3352
3353        let mut args = Vec::new();
3354        while let Token::Ident(..) | Token::BracketL(..) | Token::BraceL(..) | Token::ParenL(..) =
3355            self.current_token()
3356        {
3357            let arg = self.parse_pattern_atom()?;
3358            args.push(arg);
3359        }
3360
3361        if args.is_empty() {
3362            if let Pattern::Var(var) = &head {
3363                let is_constructor = var
3364                    .name
3365                    .chars()
3366                    .next()
3367                    .map(|c| c.is_uppercase())
3368                    .unwrap_or(false);
3369                if is_constructor {
3370                    return Ok(Pattern::Named(
3371                        var.span,
3372                        NameRef::Unqualified(var.name.clone()),
3373                        vec![],
3374                    ));
3375                }
3376            }
3377            return Ok(head);
3378        }
3379
3380        // If there are args, the head must be a constructor (identifier) pattern
3381        match head {
3382            Pattern::Var(var) => {
3383                let begin = var.span.begin;
3384                let end = args.last().map(|p| p.span().end).unwrap_or(begin);
3385                Ok(Pattern::Named(
3386                    Span::from_begin_end(begin, end),
3387                    NameRef::Unqualified(var.name),
3388                    args,
3389                ))
3390            }
3391            Pattern::Named(span, name, mut existing_args) => {
3392                existing_args.extend(args);
3393                let end = existing_args
3394                    .last()
3395                    .map(|p| p.span().end)
3396                    .unwrap_or(span.end);
3397                Ok(Pattern::Named(
3398                    Span::from_begin_end(span.begin, end),
3399                    name,
3400                    existing_args,
3401                ))
3402            }
3403            _ => {
3404                let span = args
3405                    .first()
3406                    .map(|p| *p.span())
3407                    .unwrap_or_else(|| *self.current_token().span());
3408                Err(ParserErr::new(
3409                    span,
3410                    "constructor patterns must start with an identifier",
3411                ))
3412            }
3413        }
3414    }
3415
3416    fn parse_name_ref_with_span(
3417        &mut self,
3418        expected_message: &str,
3419    ) -> Result<(NameRef, Span), ParserErr> {
3420        let mut segments: Vec<Symbol> = Vec::new();
3421        let start = self.current_token().span().begin;
3422        let mut end = match self.current_token() {
3423            Token::Ident(name, span, ..) => {
3424                segments.push(intern(&name));
3425                self.next_token();
3426                span.end
3427            }
3428            token => return Err(ParserErr::new(*token.span(), expected_message)),
3429        };
3430
3431        while matches!(self.current_token(), Token::Dot(..)) {
3432            self.next_token();
3433            match self.current_token() {
3434                Token::Ident(name, span, ..) => {
3435                    segments.push(intern(&name));
3436                    end = span.end;
3437                    self.next_token();
3438                }
3439                token => {
3440                    return Err(ParserErr::new(
3441                        *token.span(),
3442                        "expected identifier after `.`",
3443                    ));
3444                }
3445            }
3446        }
3447
3448        Ok((
3449            NameRef::from_segments(segments),
3450            Span::from_begin_end(start, end),
3451        ))
3452    }
3453
3454    fn parse_pattern_atom(&mut self) -> Result<Pattern, ParserErr> {
3455        match self.current_token() {
3456            Token::Ident(name, span, ..) if name == "_" => {
3457                self.next_token();
3458                Ok(Pattern::Wildcard(span))
3459            }
3460            Token::Ident(name, span, ..) => {
3461                self.next_token();
3462                Ok(Pattern::Var(Var::with_span(span, name)))
3463            }
3464            Token::BracketL(..) => self.parse_list_pattern(),
3465            Token::BraceL(..) => self.parse_dict_pattern(),
3466            Token::ParenL(..) => self.parse_paren_pattern(),
3467            token => Err(ParserErr::new(
3468                *token.span(),
3469                format!("unexpected {} in pattern", token),
3470            )),
3471        }
3472    }
3473
3474    fn parse_list_pattern(&mut self) -> Result<Pattern, ParserErr> {
3475        let span_begin = match self.current_token() {
3476            Token::BracketL(span, ..) => {
3477                self.next_token();
3478                span.begin
3479            }
3480            token => {
3481                return Err(ParserErr::new(
3482                    *token.span(),
3483                    format!("expected `[` got {}", token),
3484                ));
3485            }
3486        };
3487
3488        self.with_nesting(Span::from_begin_end(span_begin, span_begin), |this| {
3489            if let Token::BracketR(span, ..) = this.current_token() {
3490                this.next_token();
3491                return Ok(Pattern::List(
3492                    Span::from_begin_end(span_begin, span.end),
3493                    Vec::new(),
3494                ));
3495            }
3496
3497            let mut patterns = Vec::new();
3498            let span_end = loop {
3499                patterns.push(this.parse_pattern()?);
3500
3501                match this.current_token() {
3502                    Token::Comma(..) => {
3503                        this.next_token();
3504                    }
3505                    Token::BracketR(span, ..) => {
3506                        this.next_token();
3507                        break span.end;
3508                    }
3509                    token => {
3510                        return Err(ParserErr::new(
3511                            *token.span(),
3512                            format!("expected `,` or `]` got {}", token),
3513                        ));
3514                    }
3515                }
3516            };
3517
3518            Ok(Pattern::List(
3519                Span::from_begin_end(span_begin, span_end),
3520                patterns,
3521            ))
3522        })
3523    }
3524
3525    fn parse_dict_pattern(&mut self) -> Result<Pattern, ParserErr> {
3526        let span_begin = match self.current_token() {
3527            Token::BraceL(span, ..) => {
3528                self.next_token();
3529                span.begin
3530            }
3531            token => {
3532                return Err(ParserErr::new(
3533                    *token.span(),
3534                    format!("expected `{{` got {}", token),
3535                ));
3536            }
3537        };
3538
3539        self.with_nesting(Span::from_begin_end(span_begin, span_begin), |this| {
3540            if let Token::BraceR(span, ..) = this.current_token() {
3541                this.next_token();
3542                return Ok(Pattern::Dict(
3543                    Span::from_begin_end(span_begin, span.end),
3544                    Vec::new(),
3545                ));
3546            }
3547
3548            let mut fields = Vec::new();
3549            let span_end = loop {
3550                match this.current_token() {
3551                    Token::Ident(name, key_span, ..) => {
3552                        let key_name = name;
3553                        let key = intern(&key_name);
3554                        this.next_token();
3555
3556                        let pat = if matches!(this.current_token(), Token::Colon(..)) {
3557                            this.next_token();
3558                            this.parse_pattern()?
3559                        } else {
3560                            Pattern::Var(Var::with_span(key_span, key_name))
3561                        };
3562                        fields.push((key, pat));
3563
3564                        match this.current_token() {
3565                            Token::Comma(..) => {
3566                                this.next_token();
3567                            }
3568                            Token::BraceR(span, ..) => {
3569                                this.next_token();
3570                                break span.end;
3571                            }
3572                            token => {
3573                                return Err(ParserErr::new(
3574                                    *token.span(),
3575                                    format!("expected `,` or `}}` got {}", token),
3576                                ));
3577                            }
3578                        }
3579                    }
3580                    token => {
3581                        return Err(ParserErr::new(
3582                            *token.span(),
3583                            format!("expected identifier in dict pattern got {}", token),
3584                        ));
3585                    }
3586                }
3587            };
3588
3589            Ok(Pattern::Dict(
3590                Span::from_begin_end(span_begin, span_end),
3591                fields,
3592            ))
3593        })
3594    }
3595
3596    fn parse_paren_pattern(&mut self) -> Result<Pattern, ParserErr> {
3597        let span_begin = match self.current_token() {
3598            Token::ParenL(span, ..) => {
3599                self.next_token();
3600                span.begin
3601            }
3602            token => {
3603                return Err(ParserErr::new(
3604                    *token.span(),
3605                    format!("expected `(` got {}", token),
3606                ));
3607            }
3608        };
3609
3610        self.with_nesting(Span::from_begin_end(span_begin, span_begin), |this| {
3611            // Unit tuple pattern: `()`
3612            if let Token::ParenR(span, ..) = this.current_token() {
3613                this.next_token();
3614                return Ok(Pattern::Tuple(
3615                    Span::from_begin_end(span_begin, span.end),
3616                    Vec::new(),
3617                ));
3618            }
3619
3620            let first = this.parse_pattern()?;
3621            let mut elems = Vec::new();
3622            let span_end = match this.current_token() {
3623                Token::Comma(..) => {
3624                    this.next_token();
3625                    elems.push(first);
3626                    loop {
3627                        elems.push(this.parse_pattern()?);
3628                        match this.current_token() {
3629                            Token::Comma(..) => {
3630                                this.next_token();
3631                            }
3632                            Token::ParenR(span, ..) => {
3633                                this.next_token();
3634                                break span.end;
3635                            }
3636                            token => {
3637                                return Err(ParserErr::new(
3638                                    *token.span(),
3639                                    format!("expected `)` got {}", token),
3640                                ));
3641                            }
3642                        }
3643                    }
3644                }
3645                Token::ParenR(span, ..) => {
3646                    this.next_token();
3647                    return Ok(first.with_span(Span::from_begin_end(span_begin, span.end)));
3648                }
3649                token => {
3650                    return Err(ParserErr::new(
3651                        *token.span(),
3652                        format!("expected `)` or `,` got {}", token),
3653                    ));
3654                }
3655            };
3656
3657            Ok(Pattern::Tuple(
3658                Span::from_begin_end(span_begin, span_end),
3659                elems,
3660            ))
3661        })
3662    }
3663
3664    //
3665    fn parse_literal_bool_expr(&mut self) -> Result<Expr, ParserErr> {
3666        let token = self.current_token();
3667        self.next_token();
3668        match token {
3669            Token::Bool(val, span, ..) => Ok(Expr::Bool(span, val)),
3670            token => Err(ParserErr::new(
3671                *token.span(),
3672                format!("expected `bool` got {}", token),
3673            )),
3674        }
3675    }
3676
3677    //
3678    fn parse_literal_float_expr(&mut self) -> Result<Expr, ParserErr> {
3679        let token = self.current_token();
3680        self.next_token();
3681        match token {
3682            Token::Float(val, span, ..) => Ok(Expr::Float(span, val)),
3683            token => Err(ParserErr::new(
3684                *token.span(),
3685                format!("expected `float` got {}", token),
3686            )),
3687        }
3688    }
3689
3690    //
3691    fn parse_literal_int_expr(&mut self) -> Result<Expr, ParserErr> {
3692        let token = self.current_token();
3693        self.next_token();
3694        match token {
3695            Token::Int(val, span, ..) => Ok(Expr::Uint(span, val)),
3696            token => Err(ParserErr::new(
3697                *token.span(),
3698                format!("expected `int` got {}", token),
3699            )),
3700        }
3701    }
3702
3703    //
3704    fn parse_literal_str_expr(&mut self) -> Result<Expr, ParserErr> {
3705        let token = self.current_token();
3706        self.next_token();
3707        match token {
3708            Token::String(val, span, ..) => Ok(Expr::String(span, val)),
3709            token => Err(ParserErr::new(
3710                *token.span(),
3711                format!("expected `str` got {}", token),
3712            )),
3713        }
3714    }
3715
3716    //
3717    fn parse_ident_expr(&mut self) -> Result<Expr, ParserErr> {
3718        let token = self.current_token();
3719        self.next_token();
3720        match token {
3721            Token::Ident(name, span, ..) => Ok(Expr::Var(Var::with_span(span, name))),
3722            token => Err(ParserErr::new(
3723                *token.span(),
3724                format!("expected `ident` got {}", token),
3725            )),
3726        }
3727    }
3728
3729    fn parse_hole_expr(&mut self) -> Result<Expr, ParserErr> {
3730        let token = self.current_token();
3731        self.next_token();
3732        match token {
3733            Token::Question(span, ..) => Ok(Expr::Hole(span)),
3734            token => Err(ParserErr::new(
3735                *token.span(),
3736                format!("expected `?` got {}", token),
3737            )),
3738        }
3739    }
3740}
3741
3742fn find_layout_expr_end(
3743    tokens: &[Token],
3744    start_idx: usize,
3745    block_indent: Option<usize>,
3746    is_stmt_head: impl Fn(&Token, &Token) -> bool,
3747) -> usize {
3748    // Scan forward until we hit either:
3749    // - a newline at depth 0 followed by a next statement head at the block indent
3750    // - a newline at depth 0 followed by a token with indentation < block indent (block end)
3751    let mut depth = 0usize;
3752    let mut idx = start_idx;
3753    while idx < tokens.len() {
3754        match &tokens[idx] {
3755            Token::ParenL(..) | Token::BracketL(..) | Token::BraceL(..) => depth += 1,
3756            Token::ParenR(..) | Token::BracketR(..) | Token::BraceR(..) => {
3757                depth = depth.saturating_sub(1)
3758            }
3759            Token::WhitespaceNewline(nl_span, ..) if depth == 0 => {
3760                let mut j = idx + 1;
3761                while j < tokens.len() && matches!(tokens[j], Token::WhitespaceNewline(..)) {
3762                    j += 1;
3763                }
3764                if j >= tokens.len() {
3765                    return idx;
3766                }
3767                if let Some(indent) = block_indent {
3768                    let next_span = tokens[j].span();
3769                    if next_span.begin.column < indent {
3770                        return idx;
3771                    }
3772                    if next_span.begin.column == indent {
3773                        // Head check needs the following token too.
3774                        let mut k = j + 1;
3775                        while k < tokens.len() && matches!(tokens[k], Token::WhitespaceNewline(..))
3776                        {
3777                            k += 1;
3778                        }
3779                        if k < tokens.len() && is_stmt_head(&tokens[j], &tokens[k]) {
3780                            return idx;
3781                        }
3782                    }
3783                } else {
3784                    let _ = nl_span;
3785                }
3786            }
3787            _ => {}
3788        }
3789        idx += 1;
3790    }
3791    tokens.len()
3792}
3793
3794fn find_layout_header_clause_end(
3795    tokens: &[Token],
3796    start_idx: usize,
3797    is_terminator: impl Fn(&Token) -> bool,
3798) -> usize {
3799    // Scan forward until we hit:
3800    // - a newline at depth 0 (end of the header line), OR
3801    // - a terminator token at depth 0 (e.g. `where` or `<=`).
3802    //
3803    // This is intentionally small and explicit: the parser mostly ignores
3804    // newlines, but `class`/`instance` headers need to stop on the newline so
3805    // optional-`where` layout blocks don't accidentally get pulled into the
3806    // header.
3807    let mut depth = 0usize;
3808    let mut idx = start_idx;
3809    while idx < tokens.len() {
3810        match &tokens[idx] {
3811            Token::ParenL(..) | Token::BracketL(..) | Token::BraceL(..) => depth += 1,
3812            Token::ParenR(..) | Token::BracketR(..) | Token::BraceR(..) => {
3813                depth = depth.saturating_sub(1)
3814            }
3815            Token::WhitespaceNewline(..) if depth == 0 => return idx,
3816            token if depth == 0 && is_terminator(token) => return idx,
3817            _ => {}
3818        }
3819        idx += 1;
3820    }
3821    tokens.len()
3822}
3823
3824fn count_expr_nodes(expr: &Expr) -> u64 {
3825    match expr {
3826        Expr::Bool(..)
3827        | Expr::Uint(..)
3828        | Expr::Int(..)
3829        | Expr::Float(..)
3830        | Expr::String(..)
3831        | Expr::Uuid(..)
3832        | Expr::DateTime(..)
3833        | Expr::Hole(..)
3834        | Expr::Var(..) => 1,
3835        Expr::Tuple(_, xs) | Expr::List(_, xs) => {
3836            1 + xs.iter().map(|e| count_expr_nodes(e)).sum::<u64>()
3837        }
3838        Expr::Dict(_, kvs) => 1 + kvs.values().map(|e| count_expr_nodes(e)).sum::<u64>(),
3839        Expr::RecordUpdate(_, base, updates) => {
3840            1 + count_expr_nodes(base) + updates.values().map(|e| count_expr_nodes(e)).sum::<u64>()
3841        }
3842        Expr::App(_, f, x) => 1 + count_expr_nodes(f) + count_expr_nodes(x),
3843        Expr::Project(_, e, _) => 1 + count_expr_nodes(e),
3844        Expr::Lam(_, _, _, ann, constraints, body) => {
3845            let ann_nodes = ann.as_ref().map(count_type_expr_nodes).unwrap_or(0);
3846            let constraint_nodes = constraints
3847                .iter()
3848                .map(count_type_constraint_nodes)
3849                .sum::<u64>();
3850            1 + ann_nodes + constraint_nodes + count_expr_nodes(body)
3851        }
3852        Expr::Let(_, _, ann, def, body) => {
3853            let ann_nodes = ann.as_ref().map(count_type_expr_nodes).unwrap_or(0);
3854            1 + ann_nodes + count_expr_nodes(def) + count_expr_nodes(body)
3855        }
3856        Expr::LetRec(_, bindings, body) => {
3857            let binding_nodes = bindings
3858                .iter()
3859                .map(|(_, ann, def)| {
3860                    ann.as_ref().map(count_type_expr_nodes).unwrap_or(0) + count_expr_nodes(def)
3861                })
3862                .sum::<u64>();
3863            1 + binding_nodes + count_expr_nodes(body)
3864        }
3865        Expr::Ite(_, a, b, c) => {
3866            1 + count_expr_nodes(a) + count_expr_nodes(b) + count_expr_nodes(c)
3867        }
3868        Expr::Match(_, scrutinee, arms) => {
3869            1 + count_expr_nodes(scrutinee)
3870                + arms
3871                    .iter()
3872                    .map(|(pat, e)| count_pattern_nodes(pat) + count_expr_nodes(e))
3873                    .sum::<u64>()
3874        }
3875        Expr::Ann(_, e, ty) => 1 + count_expr_nodes(e) + count_type_expr_nodes(ty),
3876    }
3877}
3878
3879fn count_pattern_nodes(pat: &Pattern) -> u64 {
3880    match pat {
3881        Pattern::Wildcard(..) | Pattern::Var(..) => 1,
3882        Pattern::Named(_, _, ps) | Pattern::Tuple(_, ps) | Pattern::List(_, ps) => {
3883            1 + ps.iter().map(count_pattern_nodes).sum::<u64>()
3884        }
3885        Pattern::Cons(_, a, b) => 1 + count_pattern_nodes(a) + count_pattern_nodes(b),
3886        Pattern::Dict(_, fields) => {
3887            1 + fields
3888                .iter()
3889                .map(|(_, p)| count_pattern_nodes(p))
3890                .sum::<u64>()
3891        }
3892    }
3893}
3894
3895fn count_type_constraint_nodes(c: &TypeConstraint) -> u64 {
3896    1 + count_type_expr_nodes(&c.typ)
3897}
3898
3899fn count_type_expr_nodes(ty: &TypeExpr) -> u64 {
3900    match ty {
3901        TypeExpr::Name(..) => 1,
3902        TypeExpr::App(_, a, b) | TypeExpr::Fun(_, a, b) => {
3903            1 + count_type_expr_nodes(a) + count_type_expr_nodes(b)
3904        }
3905        TypeExpr::Tuple(_, elems) => 1 + elems.iter().map(count_type_expr_nodes).sum::<u64>(),
3906        TypeExpr::Record(_, fields) => {
3907            1 + fields
3908                .iter()
3909                .map(|(_, t)| count_type_expr_nodes(t))
3910                .sum::<u64>()
3911        }
3912    }
3913}