Skip to main content

hiko_syntax/
parser.rs

1use crate::ast::*;
2use crate::intern::{StringInterner, Symbol};
3use crate::span::Span;
4use crate::token::{Token, TokenKind};
5
6#[derive(Debug, Clone)]
7pub struct ParseError {
8    pub message: String,
9    pub span: Span,
10}
11
12pub struct Parser {
13    tokens: Vec<Token>,
14    pos: usize,
15    depth: u32,
16    interner: StringInterner,
17}
18
19impl Parser {
20    pub fn new(tokens: Vec<Token>) -> Self {
21        Self {
22            tokens,
23            pos: 0,
24            depth: 0,
25            interner: StringInterner::new(),
26        }
27    }
28
29    pub fn with_interner(tokens: Vec<Token>, interner: StringInterner) -> Self {
30        Self {
31            tokens,
32            pos: 0,
33            depth: 0,
34            interner,
35        }
36    }
37
38    // ── Utility ──────────────────────────────────────────────────────
39
40    fn peek(&self) -> &TokenKind {
41        &self.tokens[self.pos].kind
42    }
43
44    fn span(&self) -> Span {
45        self.tokens[self.pos].span
46    }
47
48    fn advance(&mut self) {
49        if self.pos + 1 < self.tokens.len() {
50            self.pos += 1;
51        }
52    }
53
54    fn eat(&mut self, kind: &TokenKind) -> Option<Span> {
55        if std::mem::discriminant(self.peek()) == std::mem::discriminant(kind) {
56            let span = self.span();
57            self.advance();
58            Some(span)
59        } else {
60            None
61        }
62    }
63
64    fn expect(&mut self, kind: &TokenKind, desc: &str) -> Result<Span, ParseError> {
65        self.eat(kind)
66            .ok_or_else(|| self.err(&format!("expected {desc}")))
67    }
68
69    /// Take an identifier/tyvar payload from the current token, intern it, and advance.
70    fn take_symbol(&mut self) -> Symbol {
71        let s = match &mut self.tokens[self.pos].kind {
72            TokenKind::Ident(s) | TokenKind::UpperIdent(s) | TokenKind::TyVar(s) => {
73                std::mem::take(s)
74            }
75            _ => String::new(),
76        };
77        self.advance();
78        self.interner.intern(&s)
79    }
80
81    /// Take a string literal payload from the current token and advance.
82    fn take_string_lit(&mut self) -> String {
83        let s = match &mut self.tokens[self.pos].kind {
84            TokenKind::StringLit(s) => std::mem::take(s),
85            _ => String::new(),
86        };
87        self.advance();
88        s
89    }
90
91    fn expect_ident(&mut self) -> Result<(Symbol, Span), ParseError> {
92        if matches!(self.peek(), TokenKind::Ident(_)) {
93            let span = self.span();
94            Ok((self.take_symbol(), span))
95        } else {
96            Err(self.err("expected identifier"))
97        }
98    }
99
100    fn expect_ident_or_wildcard(&mut self) -> Result<(Symbol, Span), ParseError> {
101        if matches!(self.peek(), TokenKind::Ident(_)) {
102            let span = self.span();
103            Ok((self.take_symbol(), span))
104        } else if matches!(self.peek(), TokenKind::Underscore) {
105            let span = self.span();
106            self.advance();
107            Ok((self.interner.intern("_"), span))
108        } else {
109            Err(self.err("expected identifier or _"))
110        }
111    }
112
113    fn expect_upper_ident(&mut self) -> Result<(Symbol, Span), ParseError> {
114        if matches!(self.peek(), TokenKind::UpperIdent(_)) {
115            let span = self.span();
116            Ok((self.take_symbol(), span))
117        } else {
118            Err(self.err("expected constructor name"))
119        }
120    }
121
122    fn expect_name(&mut self) -> Result<(Symbol, Span), ParseError> {
123        if matches!(self.peek(), TokenKind::Ident(_) | TokenKind::UpperIdent(_)) {
124            let span = self.span();
125            Ok((self.take_symbol(), span))
126        } else {
127            Err(self.err("expected name"))
128        }
129    }
130
131    fn expect_tyvar(&mut self) -> Result<Symbol, ParseError> {
132        if matches!(self.peek(), TokenKind::TyVar(_)) {
133            Ok(self.take_symbol())
134        } else {
135            Err(self.err("expected type variable"))
136        }
137    }
138
139    fn err(&self, message: &str) -> ParseError {
140        ParseError {
141            message: message.to_string(),
142            span: self.span(),
143        }
144    }
145
146    fn guard_depth(&mut self) -> Result<(), ParseError> {
147        self.depth += 1;
148        if self.depth > 256 {
149            Err(self.err("expression nesting limit exceeded"))
150        } else {
151            Ok(())
152        }
153    }
154
155    fn unguard_depth(&mut self) {
156        self.depth -= 1;
157    }
158
159    fn can_start_app_arg(&self) -> bool {
160        matches!(
161            self.peek(),
162            TokenKind::IntLit(_)
163                | TokenKind::FloatLit(_)
164                | TokenKind::StringLit(_)
165                | TokenKind::CharLit(_)
166                | TokenKind::True
167                | TokenKind::False
168                | TokenKind::Ident(_)
169                | TokenKind::UpperIdent(_)
170                | TokenKind::Tilde
171                | TokenKind::Not
172                | TokenKind::LParen
173                | TokenKind::LBracket
174        )
175    }
176
177    fn can_start_atom_pat(&self) -> bool {
178        matches!(
179            self.peek(),
180            TokenKind::Underscore
181                | TokenKind::IntLit(_)
182                | TokenKind::FloatLit(_)
183                | TokenKind::StringLit(_)
184                | TokenKind::CharLit(_)
185                | TokenKind::True
186                | TokenKind::False
187                | TokenKind::Ident(_)
188                | TokenKind::UpperIdent(_)
189                | TokenKind::LParen
190                | TokenKind::LBracket
191                | TokenKind::Tilde
192        )
193    }
194
195    // ── Program ──────────────────────────────────────────────────────
196
197    pub fn parse_program(&mut self) -> Result<Program, ParseError> {
198        let mut decls = Vec::new();
199        while !matches!(self.peek(), TokenKind::Eof) {
200            decls.push(self.parse_decl()?);
201        }
202        Ok(Program {
203            decls,
204            interner: std::mem::take(&mut self.interner),
205        })
206    }
207
208    // ── Declarations ─────────────────────────────────────────────────
209
210    fn parse_decl(&mut self) -> Result<Decl, ParseError> {
211        match self.peek() {
212            TokenKind::Val => self.parse_val_decl(),
213            TokenKind::Fun => self.parse_fun_decl(),
214            TokenKind::Datatype => self.parse_datatype_decl(),
215            TokenKind::Type => self.parse_type_alias_decl(),
216            TokenKind::Local => self.parse_local_decl(),
217            TokenKind::Use => self.parse_use_decl(),
218            TokenKind::Effect => self.parse_effect_decl(),
219            _ => {
220                Err(self
221                    .err("expected declaration (val, fun, datatype, type, local, use, or effect)"))
222            }
223        }
224    }
225
226    fn parse_val_decl(&mut self) -> Result<Decl, ParseError> {
227        let start = self.span();
228        self.advance(); // consume `val`
229
230        if self.eat(&TokenKind::Rec).is_some() {
231            let (name, _) = self.expect_ident()?;
232            self.expect(&TokenKind::Eq, "=")?;
233            if !matches!(self.peek(), TokenKind::Fn) {
234                return Err(self.err("val rec requires fn on the right-hand side"));
235            }
236            let body = self.parse_expr()?;
237            let span = start.merge(body.span);
238            return Ok(Decl {
239                kind: DeclKind::ValRec(name, body),
240                span,
241            });
242        }
243
244        let pat = self.parse_pat()?;
245        self.expect(&TokenKind::Eq, "=")?;
246        let body = self.parse_expr()?;
247        let span = start.merge(body.span);
248        Ok(Decl {
249            kind: DeclKind::Val(pat, body),
250            span,
251        })
252    }
253
254    fn parse_fun_decl(&mut self) -> Result<Decl, ParseError> {
255        let start = self.span();
256        self.advance(); // consume `fun`
257
258        let mut bindings = Vec::new();
259        loop {
260            bindings.push(self.parse_fun_binding()?);
261            if self.eat(&TokenKind::And).is_none() {
262                break;
263            }
264        }
265        let span = start.merge(bindings.last().unwrap().span);
266        Ok(Decl {
267            kind: DeclKind::Fun(bindings),
268            span,
269        })
270    }
271
272    fn parse_fun_binding(&mut self) -> Result<FunBinding, ParseError> {
273        let (name, name_span) = self.expect_ident()?;
274        let mut clauses = Vec::new();
275
276        loop {
277            let clause_start = self.span();
278            let mut pats = Vec::new();
279            while self.can_start_atom_pat() {
280                pats.push(self.parse_atom_pat()?);
281            }
282            if pats.is_empty() {
283                return Err(self.err("expected at least one parameter pattern"));
284            }
285            self.expect(&TokenKind::Eq, "=")?;
286            let body = self.parse_expr()?;
287            let clause_span = clause_start.merge(body.span);
288            clauses.push(FunClause {
289                pats,
290                body,
291                span: clause_span,
292            });
293
294            // Check for another clause: | name ...
295            if matches!(self.peek(), TokenKind::Bar) {
296                self.advance(); // consume |
297                // Expect the same function name
298                let (next_name, _) = self.expect_ident()?;
299                if next_name != name {
300                    return Err(self.err(&format!(
301                        "clausal function name mismatch: expected '{}', found '{}'",
302                        self.interner.resolve(name),
303                        self.interner.resolve(next_name),
304                    )));
305                }
306            } else {
307                break;
308            }
309        }
310
311        let span = name_span.merge(clauses.last().unwrap().span);
312        Ok(FunBinding {
313            name,
314            clauses,
315            span,
316        })
317    }
318
319    fn parse_datatype_decl(&mut self) -> Result<Decl, ParseError> {
320        let start = self.span();
321        self.advance(); // consume `datatype`
322
323        let tyvars = self.parse_tyvar_params()?;
324        let (name, _) = self.expect_name()?;
325        self.expect(&TokenKind::Eq, "=")?;
326
327        self.eat(&TokenKind::Bar); // optional leading |
328        let mut constructors = Vec::new();
329        loop {
330            let con_start = self.span();
331            let (con_name, _) = self.expect_upper_ident()?;
332            let payload = if self.eat(&TokenKind::Of).is_some() {
333                Some(self.parse_type_expr()?)
334            } else {
335                None
336            };
337            let con_span = if let Some(ref ty) = payload {
338                con_start.merge(ty.span)
339            } else {
340                con_start
341            };
342            constructors.push(ConDecl {
343                name: con_name,
344                payload,
345                span: con_span,
346            });
347            if self.eat(&TokenKind::Bar).is_none() {
348                break;
349            }
350        }
351
352        let span = start.merge(constructors.last().unwrap().span);
353        Ok(Decl {
354            kind: DeclKind::Datatype(DatatypeDecl {
355                tyvars,
356                name,
357                constructors,
358                span,
359            }),
360            span,
361        })
362    }
363
364    fn parse_type_alias_decl(&mut self) -> Result<Decl, ParseError> {
365        let start = self.span();
366        self.advance(); // consume `type`
367        let tyvars = self.parse_tyvar_params()?;
368        let (name, _) = self.expect_name()?;
369        self.expect(&TokenKind::Eq, "=")?;
370        let ty = self.parse_type_expr()?;
371        let span = start.merge(ty.span);
372        Ok(Decl {
373            kind: DeclKind::TypeAlias(TypeAliasDecl {
374                tyvars,
375                name,
376                ty,
377                span,
378            }),
379            span,
380        })
381    }
382
383    fn parse_local_decl(&mut self) -> Result<Decl, ParseError> {
384        let start = self.span();
385        self.advance(); // consume `local`
386        let mut locals = Vec::new();
387        while !matches!(self.peek(), TokenKind::In | TokenKind::Eof) {
388            locals.push(self.parse_decl()?);
389        }
390        self.expect(&TokenKind::In, "in")?;
391        let mut body = Vec::new();
392        while !matches!(self.peek(), TokenKind::End | TokenKind::Eof) {
393            body.push(self.parse_decl()?);
394        }
395        let end_span = self.expect(&TokenKind::End, "end")?;
396        let span = start.merge(end_span);
397        Ok(Decl {
398            kind: DeclKind::Local(locals, body),
399            span,
400        })
401    }
402
403    fn parse_use_decl(&mut self) -> Result<Decl, ParseError> {
404        let start = self.span();
405        self.advance(); // consume `use`
406        if matches!(self.peek(), TokenKind::StringLit(_)) {
407            let end = self.span();
408            let path = self.take_string_lit();
409            let span = start.merge(end);
410            Ok(Decl {
411                kind: DeclKind::Use(path),
412                span,
413            })
414        } else {
415            Err(self.err("expected string literal after 'use'"))
416        }
417    }
418
419    fn parse_effect_decl(&mut self) -> Result<Decl, ParseError> {
420        let start = self.span();
421        self.advance(); // consume `effect`
422        let (name, end) = self.expect_upper_ident()?;
423        let payload = if self.eat(&TokenKind::Of).is_some() {
424            Some(self.parse_type_expr()?)
425        } else {
426            None
427        };
428        let span = start.merge(payload.as_ref().map_or(end, |t| t.span));
429        Ok(Decl {
430            kind: DeclKind::Effect(name, payload),
431            span,
432        })
433    }
434
435    fn parse_tyvar_params(&mut self) -> Result<Vec<Symbol>, ParseError> {
436        if matches!(self.peek(), TokenKind::TyVar(_)) {
437            return Ok(vec![self.take_symbol()]);
438        }
439        if self.eat(&TokenKind::LParen).is_none() {
440            return Ok(vec![]);
441        }
442        let mut vars = vec![self.expect_tyvar()?];
443        while self.eat(&TokenKind::Comma).is_some() {
444            vars.push(self.expect_tyvar()?);
445        }
446        self.expect(&TokenKind::RParen, ")")?;
447        Ok(vars)
448    }
449
450    // ── Expressions (lowest to highest precedence) ───────────────────
451
452    fn parse_expr(&mut self) -> Result<Expr, ParseError> {
453        self.guard_depth()?;
454        let result = self.parse_expr_inner();
455        self.unguard_depth();
456        result
457    }
458
459    fn parse_expr_inner(&mut self) -> Result<Expr, ParseError> {
460        let expr = self.parse_orelse()?;
461        if self.eat(&TokenKind::Colon).is_some() {
462            let ty = self.parse_type_expr()?;
463            let span = expr.span.merge(ty.span);
464            Ok(Expr {
465                kind: ExprKind::Ann(Box::new(expr), ty),
466                span,
467            })
468        } else {
469            Ok(expr)
470        }
471    }
472
473    fn parse_orelse(&mut self) -> Result<Expr, ParseError> {
474        let lhs = self.parse_andalso()?;
475        if self.eat(&TokenKind::Orelse).is_some() {
476            let rhs = self.parse_orelse()?; // right-associative
477            let span = lhs.span.merge(rhs.span);
478            Ok(Expr {
479                kind: ExprKind::BinOp(BinOp::Orelse, Box::new(lhs), Box::new(rhs)),
480                span,
481            })
482        } else {
483            Ok(lhs)
484        }
485    }
486
487    fn parse_andalso(&mut self) -> Result<Expr, ParseError> {
488        let lhs = self.parse_comp()?;
489        if self.eat(&TokenKind::Andalso).is_some() {
490            let rhs = self.parse_andalso()?; // right-associative
491            let span = lhs.span.merge(rhs.span);
492            Ok(Expr {
493                kind: ExprKind::BinOp(BinOp::Andalso, Box::new(lhs), Box::new(rhs)),
494                span,
495            })
496        } else {
497            Ok(lhs)
498        }
499    }
500
501    fn parse_comp(&mut self) -> Result<Expr, ParseError> {
502        let lhs = self.parse_cons()?;
503        let op = match self.peek() {
504            TokenKind::Eq => Some(BinOp::Eq),
505            TokenKind::Ne => Some(BinOp::Ne),
506            TokenKind::Lt => Some(BinOp::LtInt),
507            TokenKind::Gt => Some(BinOp::GtInt),
508            TokenKind::Le => Some(BinOp::LeInt),
509            TokenKind::Ge => Some(BinOp::GeInt),
510            TokenKind::LtDot => Some(BinOp::LtFloat),
511            TokenKind::GtDot => Some(BinOp::GtFloat),
512            TokenKind::LeDot => Some(BinOp::LeFloat),
513            TokenKind::GeDot => Some(BinOp::GeFloat),
514            _ => None,
515        };
516        if let Some(op) = op {
517            self.advance();
518            let rhs = self.parse_cons()?;
519            let span = lhs.span.merge(rhs.span);
520            Ok(Expr {
521                kind: ExprKind::BinOp(op, Box::new(lhs), Box::new(rhs)),
522                span,
523            })
524        } else {
525            Ok(lhs)
526        }
527    }
528
529    fn parse_cons(&mut self) -> Result<Expr, ParseError> {
530        let lhs = self.parse_add()?;
531        if self.eat(&TokenKind::ColonColon).is_some() {
532            let rhs = self.parse_cons()?; // right-associative
533            let span = lhs.span.merge(rhs.span);
534            Ok(Expr {
535                kind: ExprKind::Cons(Box::new(lhs), Box::new(rhs)),
536                span,
537            })
538        } else {
539            Ok(lhs)
540        }
541    }
542
543    fn parse_add(&mut self) -> Result<Expr, ParseError> {
544        let mut lhs = self.parse_mul()?;
545        loop {
546            let op = match self.peek() {
547                TokenKind::Plus => Some(BinOp::AddInt),
548                TokenKind::Minus => Some(BinOp::SubInt),
549                TokenKind::PlusDot => Some(BinOp::AddFloat),
550                TokenKind::MinusDot => Some(BinOp::SubFloat),
551                TokenKind::Caret => Some(BinOp::ConcatStr),
552                _ => None,
553            };
554            if let Some(op) = op {
555                self.advance();
556                let rhs = self.parse_mul()?;
557                let span = lhs.span.merge(rhs.span);
558                lhs = Expr {
559                    kind: ExprKind::BinOp(op, Box::new(lhs), Box::new(rhs)),
560                    span,
561                };
562            } else {
563                break;
564            }
565        }
566        Ok(lhs)
567    }
568
569    fn parse_mul(&mut self) -> Result<Expr, ParseError> {
570        let mut lhs = self.parse_unary()?;
571        loop {
572            let op = match self.peek() {
573                TokenKind::Star => Some(BinOp::MulInt),
574                TokenKind::Slash => Some(BinOp::DivInt),
575                TokenKind::Mod => Some(BinOp::ModInt),
576                TokenKind::StarDot => Some(BinOp::MulFloat),
577                TokenKind::SlashDot => Some(BinOp::DivFloat),
578                _ => None,
579            };
580            if let Some(op) = op {
581                self.advance();
582                let rhs = self.parse_unary()?;
583                let span = lhs.span.merge(rhs.span);
584                lhs = Expr {
585                    kind: ExprKind::BinOp(op, Box::new(lhs), Box::new(rhs)),
586                    span,
587                };
588            } else {
589                break;
590            }
591        }
592        Ok(lhs)
593    }
594
595    fn parse_unary(&mut self) -> Result<Expr, ParseError> {
596        if matches!(self.peek(), TokenKind::Tilde) {
597            let start = self.span();
598            self.advance();
599            let operand = self.parse_unary()?;
600            let span = start.merge(operand.span);
601            return Ok(Expr {
602                kind: ExprKind::UnaryNeg(Box::new(operand)),
603                span,
604            });
605        }
606        if matches!(self.peek(), TokenKind::Not) {
607            let start = self.span();
608            self.advance();
609            let operand = self.parse_unary()?;
610            let span = start.merge(operand.span);
611            return Ok(Expr {
612                kind: ExprKind::Not(Box::new(operand)),
613                span,
614            });
615        }
616        self.parse_app()
617    }
618
619    fn parse_app(&mut self) -> Result<Expr, ParseError> {
620        let mut lhs = self.parse_atom_expr()?;
621        while self.can_start_app_arg() {
622            let arg = self.parse_app_arg()?;
623            let span = lhs.span.merge(arg.span);
624            lhs = Expr {
625                kind: ExprKind::App(Box::new(lhs), Box::new(arg)),
626                span,
627            };
628        }
629        Ok(lhs)
630    }
631
632    /// Parse an application argument: an atom, or a unary prefix (~, not) applied to an atom.
633    fn parse_app_arg(&mut self) -> Result<Expr, ParseError> {
634        let start = self.span();
635        if matches!(self.peek(), TokenKind::Tilde) {
636            self.advance();
637            let operand = self.parse_atom_expr()?;
638            let span = start.merge(operand.span);
639            return Ok(Expr {
640                kind: ExprKind::UnaryNeg(Box::new(operand)),
641                span,
642            });
643        }
644        if matches!(self.peek(), TokenKind::Not) {
645            self.advance();
646            let operand = self.parse_atom_expr()?;
647            let span = start.merge(operand.span);
648            return Ok(Expr {
649                kind: ExprKind::Not(Box::new(operand)),
650                span,
651            });
652        }
653        self.parse_atom_expr()
654    }
655
656    fn parse_atom_expr(&mut self) -> Result<Expr, ParseError> {
657        let start = self.span();
658        match self.peek() {
659            TokenKind::IntLit(n) => {
660                let n = *n;
661                self.advance();
662                Ok(Expr {
663                    kind: ExprKind::IntLit(n),
664                    span: start,
665                })
666            }
667            TokenKind::FloatLit(f) => {
668                let f = *f;
669                self.advance();
670                Ok(Expr {
671                    kind: ExprKind::FloatLit(f),
672                    span: start,
673                })
674            }
675            TokenKind::StringLit(_) => {
676                let s = self.take_string_lit();
677                Ok(Expr {
678                    kind: ExprKind::StringLit(s),
679                    span: start,
680                })
681            }
682            TokenKind::CharLit(c) => {
683                let c = *c;
684                self.advance();
685                Ok(Expr {
686                    kind: ExprKind::CharLit(c),
687                    span: start,
688                })
689            }
690            TokenKind::True => {
691                self.advance();
692                Ok(Expr {
693                    kind: ExprKind::BoolLit(true),
694                    span: start,
695                })
696            }
697            TokenKind::False => {
698                self.advance();
699                Ok(Expr {
700                    kind: ExprKind::BoolLit(false),
701                    span: start,
702                })
703            }
704            TokenKind::Ident(_) => {
705                let name = self.take_symbol();
706                Ok(Expr {
707                    kind: ExprKind::Var(name),
708                    span: start,
709                })
710            }
711            TokenKind::UpperIdent(_) => {
712                let name = self.take_symbol();
713                Ok(Expr {
714                    kind: ExprKind::Constructor(name),
715                    span: start,
716                })
717            }
718            TokenKind::LParen => {
719                self.advance();
720                if self.eat(&TokenKind::RParen).is_some() {
721                    return Ok(Expr {
722                        kind: ExprKind::Unit,
723                        span: start.merge(self.tokens[self.pos - 1].span),
724                    });
725                }
726                let first = self.parse_expr()?;
727                if self.eat(&TokenKind::Comma).is_some() {
728                    let mut elems = vec![first];
729                    elems.push(self.parse_expr()?);
730                    while self.eat(&TokenKind::Comma).is_some() {
731                        elems.push(self.parse_expr()?);
732                    }
733                    let end = self.expect(&TokenKind::RParen, ")")?;
734                    let span = start.merge(end);
735                    Ok(Expr {
736                        kind: ExprKind::Tuple(elems),
737                        span,
738                    })
739                } else {
740                    let end = self.expect(&TokenKind::RParen, ")")?;
741                    let span = start.merge(end);
742                    Ok(Expr {
743                        kind: ExprKind::Paren(Box::new(first)),
744                        span,
745                    })
746                }
747            }
748            TokenKind::LBracket => {
749                self.advance();
750                if self.eat(&TokenKind::RBracket).is_some() {
751                    return Ok(Expr {
752                        kind: ExprKind::List(vec![]),
753                        span: start.merge(self.tokens[self.pos - 1].span),
754                    });
755                }
756                let mut elems = vec![self.parse_expr()?];
757                while self.eat(&TokenKind::Comma).is_some() {
758                    elems.push(self.parse_expr()?);
759                }
760                let end = self.expect(&TokenKind::RBracket, "]")?;
761                let span = start.merge(end);
762                Ok(Expr {
763                    kind: ExprKind::List(elems),
764                    span,
765                })
766            }
767            TokenKind::If => self.parse_if_expr(),
768            TokenKind::Let => self.parse_let_expr(),
769            TokenKind::Case => self.parse_case_expr(),
770            TokenKind::Fn => self.parse_fn_expr(),
771            TokenKind::Handle => self.parse_handle_expr(),
772            TokenKind::Perform => self.parse_perform_expr(),
773            TokenKind::Resume => self.parse_resume_expr(),
774            _ => Err(self.err("expected expression")),
775        }
776    }
777
778    fn parse_handle_expr(&mut self) -> Result<Expr, ParseError> {
779        let start = self.span();
780        self.advance(); // consume `handle`
781        let body = self.parse_expr()?;
782        self.expect(&TokenKind::With, "with")?;
783        self.expect(&TokenKind::Return, "return")?;
784        let (return_var, _) = self.expect_ident_or_wildcard()?;
785        self.expect(&TokenKind::Arrow, "=>")?;
786        let return_body = self.parse_expr()?;
787        let mut handlers = Vec::new();
788        while self.eat(&TokenKind::Bar).is_some() {
789            let hstart = self.span();
790            let (effect_name, _) = self.expect_upper_ident()?;
791            let (payload_var, _) = self.expect_ident_or_wildcard()?;
792            let (cont_var, _) = self.expect_ident_or_wildcard()?;
793            self.expect(&TokenKind::Arrow, "=>")?;
794            let hbody = self.parse_expr()?;
795            let hspan = hstart.merge(hbody.span);
796            handlers.push(EffectHandler {
797                effect_name,
798                payload_var,
799                cont_var,
800                body: hbody,
801                span: hspan,
802            });
803        }
804        let end_span = handlers.last().map(|h| h.span).unwrap_or(return_body.span);
805        let span = start.merge(end_span);
806        Ok(Expr {
807            kind: ExprKind::Handle {
808                body: Box::new(body),
809                return_var,
810                return_body: Box::new(return_body),
811                handlers,
812            },
813            span,
814        })
815    }
816
817    fn parse_perform_expr(&mut self) -> Result<Expr, ParseError> {
818        let start = self.span();
819        self.advance(); // consume `perform`
820        let (name, _) = self.expect_upper_ident()?;
821        let arg = self.parse_atom_expr()?;
822        let span = start.merge(arg.span);
823        Ok(Expr {
824            kind: ExprKind::Perform(name, Box::new(arg)),
825            span,
826        })
827    }
828
829    fn parse_resume_expr(&mut self) -> Result<Expr, ParseError> {
830        let start = self.span();
831        self.advance(); // consume `resume`
832        let cont = self.parse_atom_expr()?;
833        let arg = self.parse_atom_expr()?;
834        let span = start.merge(arg.span);
835        Ok(Expr {
836            kind: ExprKind::Resume(Box::new(cont), Box::new(arg)),
837            span,
838        })
839    }
840
841    fn parse_if_expr(&mut self) -> Result<Expr, ParseError> {
842        let start = self.span();
843        self.advance(); // consume `if`
844        let cond = self.parse_expr()?;
845        self.expect(&TokenKind::Then, "then")?;
846        let then_br = self.parse_expr()?;
847        self.expect(&TokenKind::Else, "else")?;
848        let else_br = self.parse_expr()?;
849        let span = start.merge(else_br.span);
850        Ok(Expr {
851            kind: ExprKind::If(Box::new(cond), Box::new(then_br), Box::new(else_br)),
852            span,
853        })
854    }
855
856    fn parse_let_expr(&mut self) -> Result<Expr, ParseError> {
857        let start = self.span();
858        self.advance(); // consume `let`
859        let mut decls = Vec::new();
860        while !matches!(self.peek(), TokenKind::In | TokenKind::Eof) {
861            decls.push(self.parse_decl()?);
862        }
863        self.expect(&TokenKind::In, "in")?;
864        let body = self.parse_expr()?;
865        let end = self.expect(&TokenKind::End, "end")?;
866        let span = start.merge(end);
867        Ok(Expr {
868            kind: ExprKind::Let(decls, Box::new(body)),
869            span,
870        })
871    }
872
873    fn parse_case_expr(&mut self) -> Result<Expr, ParseError> {
874        let start = self.span();
875        self.advance(); // consume `case`
876        let scrutinee = self.parse_expr()?;
877        self.expect(&TokenKind::Of, "of")?;
878        self.eat(&TokenKind::Bar); // optional leading |
879        let mut branches = Vec::new();
880        loop {
881            let pat = self.parse_pat()?;
882            self.expect(&TokenKind::Arrow, "=>")?;
883            let body = self.parse_expr()?;
884            branches.push((pat, body));
885            if self.eat(&TokenKind::Bar).is_none() {
886                break;
887            }
888        }
889        let last_span = branches.last().unwrap().1.span;
890        let span = start.merge(last_span);
891        Ok(Expr {
892            kind: ExprKind::Case(Box::new(scrutinee), branches),
893            span,
894        })
895    }
896
897    fn parse_fn_expr(&mut self) -> Result<Expr, ParseError> {
898        let start = self.span();
899        self.advance(); // consume `fn`
900        let pat = self.parse_pat()?;
901        self.expect(&TokenKind::Arrow, "=>")?;
902        let body = self.parse_expr()?;
903        let span = start.merge(body.span);
904        Ok(Expr {
905            kind: ExprKind::Fn(pat, Box::new(body)),
906            span,
907        })
908    }
909
910    // ── Patterns ─────────────────────────────────────────────────────
911
912    fn parse_pat(&mut self) -> Result<Pat, ParseError> {
913        self.guard_depth()?;
914        let result = self.parse_pat_inner_dispatch();
915        self.unguard_depth();
916        result
917    }
918
919    fn parse_pat_inner_dispatch(&mut self) -> Result<Pat, ParseError> {
920        let pat = self.parse_as_pat()?;
921        if self.eat(&TokenKind::Colon).is_some() {
922            let ty = self.parse_type_expr()?;
923            let span = pat.span.merge(ty.span);
924            Ok(Pat {
925                kind: PatKind::Ann(Box::new(pat), ty),
926                span,
927            })
928        } else {
929            Ok(pat)
930        }
931    }
932
933    fn parse_as_pat(&mut self) -> Result<Pat, ParseError> {
934        // Check for `ident as pat`
935        if matches!(self.peek(), TokenKind::Ident(_))
936            && self.pos + 1 < self.tokens.len()
937            && matches!(self.tokens[self.pos + 1].kind, TokenKind::As)
938        {
939            let start = self.span();
940            let name = self.take_symbol(); // consume ident
941            self.advance(); // consume `as`
942            let inner = self.parse_as_pat()?;
943            let span = start.merge(inner.span);
944            return Ok(Pat {
945                kind: PatKind::As(name, Box::new(inner)),
946                span,
947            });
948        }
949        self.parse_cons_pat()
950    }
951
952    fn parse_cons_pat(&mut self) -> Result<Pat, ParseError> {
953        let lhs = self.parse_app_pat()?;
954        if self.eat(&TokenKind::ColonColon).is_some() {
955            let rhs = self.parse_cons_pat()?; // right-associative
956            let span = lhs.span.merge(rhs.span);
957            Ok(Pat {
958                kind: PatKind::Cons(Box::new(lhs), Box::new(rhs)),
959                span,
960            })
961        } else {
962            Ok(lhs)
963        }
964    }
965
966    fn parse_app_pat(&mut self) -> Result<Pat, ParseError> {
967        if matches!(self.peek(), TokenKind::UpperIdent(_)) {
968            let start = self.span();
969            let name = self.take_symbol();
970            if self.can_start_atom_pat() {
971                let payload = self.parse_atom_pat()?;
972                let span = start.merge(payload.span);
973                Ok(Pat {
974                    kind: PatKind::Constructor(name, Some(Box::new(payload))),
975                    span,
976                })
977            } else {
978                Ok(Pat {
979                    kind: PatKind::Constructor(name, None),
980                    span: start,
981                })
982            }
983        } else {
984            self.parse_atom_pat()
985        }
986    }
987
988    fn parse_atom_pat(&mut self) -> Result<Pat, ParseError> {
989        let start = self.span();
990        match self.peek() {
991            TokenKind::Underscore => {
992                self.advance();
993                Ok(Pat {
994                    kind: PatKind::Wildcard,
995                    span: start,
996                })
997            }
998            TokenKind::Ident(_) => {
999                let name = self.take_symbol();
1000                Ok(Pat {
1001                    kind: PatKind::Var(name),
1002                    span: start,
1003                })
1004            }
1005            TokenKind::UpperIdent(_) => {
1006                let name = self.take_symbol();
1007                Ok(Pat {
1008                    kind: PatKind::Constructor(name, None),
1009                    span: start,
1010                })
1011            }
1012            TokenKind::IntLit(n) => {
1013                let n = *n;
1014                self.advance();
1015                Ok(Pat {
1016                    kind: PatKind::IntLit(n),
1017                    span: start,
1018                })
1019            }
1020            TokenKind::FloatLit(f) => {
1021                let f = *f;
1022                self.advance();
1023                Ok(Pat {
1024                    kind: PatKind::FloatLit(f),
1025                    span: start,
1026                })
1027            }
1028            TokenKind::StringLit(_) => {
1029                let s = self.take_string_lit();
1030                Ok(Pat {
1031                    kind: PatKind::StringLit(s),
1032                    span: start,
1033                })
1034            }
1035            TokenKind::CharLit(c) => {
1036                let c = *c;
1037                self.advance();
1038                Ok(Pat {
1039                    kind: PatKind::CharLit(c),
1040                    span: start,
1041                })
1042            }
1043            TokenKind::True => {
1044                self.advance();
1045                Ok(Pat {
1046                    kind: PatKind::BoolLit(true),
1047                    span: start,
1048                })
1049            }
1050            TokenKind::False => {
1051                self.advance();
1052                Ok(Pat {
1053                    kind: PatKind::BoolLit(false),
1054                    span: start,
1055                })
1056            }
1057            TokenKind::Tilde => {
1058                self.advance();
1059                match self.peek() {
1060                    TokenKind::IntLit(n) => {
1061                        let n = *n;
1062                        let end = self.span();
1063                        self.advance();
1064                        Ok(Pat {
1065                            kind: PatKind::IntLit(-n),
1066                            span: start.merge(end),
1067                        })
1068                    }
1069                    TokenKind::FloatLit(f) => {
1070                        let f = *f;
1071                        let end = self.span();
1072                        self.advance();
1073                        Ok(Pat {
1074                            kind: PatKind::FloatLit(-f),
1075                            span: start.merge(end),
1076                        })
1077                    }
1078                    _ => Err(self.err("expected number after ~ in pattern")),
1079                }
1080            }
1081            TokenKind::LParen => {
1082                self.advance();
1083                if self.eat(&TokenKind::RParen).is_some() {
1084                    return Ok(Pat {
1085                        kind: PatKind::Unit,
1086                        span: start.merge(self.tokens[self.pos - 1].span),
1087                    });
1088                }
1089                let first = self.parse_pat()?;
1090                if self.eat(&TokenKind::Comma).is_some() {
1091                    let mut elems = vec![first];
1092                    elems.push(self.parse_pat()?);
1093                    while self.eat(&TokenKind::Comma).is_some() {
1094                        elems.push(self.parse_pat()?);
1095                    }
1096                    let end = self.expect(&TokenKind::RParen, ")")?;
1097                    let span = start.merge(end);
1098                    Ok(Pat {
1099                        kind: PatKind::Tuple(elems),
1100                        span,
1101                    })
1102                } else {
1103                    let end = self.expect(&TokenKind::RParen, ")")?;
1104                    let span = start.merge(end);
1105                    Ok(Pat {
1106                        kind: PatKind::Paren(Box::new(first)),
1107                        span,
1108                    })
1109                }
1110            }
1111            TokenKind::LBracket => {
1112                self.advance();
1113                if self.eat(&TokenKind::RBracket).is_some() {
1114                    return Ok(Pat {
1115                        kind: PatKind::List(vec![]),
1116                        span: start.merge(self.tokens[self.pos - 1].span),
1117                    });
1118                }
1119                let mut elems = vec![self.parse_pat()?];
1120                while self.eat(&TokenKind::Comma).is_some() {
1121                    elems.push(self.parse_pat()?);
1122                }
1123                let end = self.expect(&TokenKind::RBracket, "]")?;
1124                let span = start.merge(end);
1125                Ok(Pat {
1126                    kind: PatKind::List(elems),
1127                    span,
1128                })
1129            }
1130            _ => Err(self.err("expected pattern")),
1131        }
1132    }
1133
1134    // ── Type expressions ─────────────────────────────────────────────
1135
1136    fn parse_type_expr(&mut self) -> Result<TypeExpr, ParseError> {
1137        self.guard_depth()?;
1138        let result = self.parse_arrow_type();
1139        self.unguard_depth();
1140        result
1141    }
1142
1143    fn parse_arrow_type(&mut self) -> Result<TypeExpr, ParseError> {
1144        let lhs = self.parse_tuple_type()?;
1145        if self.eat(&TokenKind::ThinArrow).is_some() {
1146            let rhs = self.parse_arrow_type()?; // right-associative
1147            let span = lhs.span.merge(rhs.span);
1148            Ok(TypeExpr {
1149                kind: TypeExprKind::Arrow(Box::new(lhs), Box::new(rhs)),
1150                span,
1151            })
1152        } else {
1153            Ok(lhs)
1154        }
1155    }
1156
1157    fn parse_tuple_type(&mut self) -> Result<TypeExpr, ParseError> {
1158        let first = self.parse_app_type()?;
1159        if matches!(self.peek(), TokenKind::Star) {
1160            let mut elems = vec![first];
1161            while self.eat(&TokenKind::Star).is_some() {
1162                elems.push(self.parse_app_type()?);
1163            }
1164            let span = elems[0].span.merge(elems.last().unwrap().span);
1165            Ok(TypeExpr {
1166                kind: TypeExprKind::Tuple(elems),
1167                span,
1168            })
1169        } else {
1170            Ok(first)
1171        }
1172    }
1173
1174    fn parse_app_type(&mut self) -> Result<TypeExpr, ParseError> {
1175        let mut ty = self.parse_atom_type()?;
1176        while matches!(self.peek(), TokenKind::Ident(_) | TokenKind::UpperIdent(_)) {
1177            let end = self.span();
1178            let name = self.take_symbol();
1179            let (args, base_span) = match ty.kind {
1180                TypeExprKind::Tuple(elems) => (elems, ty.span),
1181                _ => {
1182                    let span = ty.span;
1183                    (vec![ty], span)
1184                }
1185            };
1186            let span = base_span.merge(end);
1187            ty = TypeExpr {
1188                kind: TypeExprKind::App(name, args),
1189                span,
1190            };
1191        }
1192        Ok(ty)
1193    }
1194
1195    fn parse_atom_type(&mut self) -> Result<TypeExpr, ParseError> {
1196        let start = self.span();
1197        match self.peek() {
1198            TokenKind::TyVar(_) => {
1199                let name = self.take_symbol();
1200                Ok(TypeExpr {
1201                    kind: TypeExprKind::Var(name),
1202                    span: start,
1203                })
1204            }
1205            TokenKind::Ident(_) | TokenKind::UpperIdent(_) => {
1206                let name = self.take_symbol();
1207                Ok(TypeExpr {
1208                    kind: TypeExprKind::Named(name),
1209                    span: start,
1210                })
1211            }
1212            TokenKind::LParen => {
1213                self.advance();
1214                let first = self.parse_type_expr()?;
1215                if self.eat(&TokenKind::Comma).is_some() {
1216                    // Multi-arg: (ty1, ty2, ...) stored as Tuple, converted to App in parse_app_type
1217                    let mut elems = vec![first];
1218                    elems.push(self.parse_type_expr()?);
1219                    while self.eat(&TokenKind::Comma).is_some() {
1220                        elems.push(self.parse_type_expr()?);
1221                    }
1222                    let end = self.expect(&TokenKind::RParen, ")")?;
1223                    let span = start.merge(end);
1224                    Ok(TypeExpr {
1225                        kind: TypeExprKind::Tuple(elems),
1226                        span,
1227                    })
1228                } else {
1229                    let end = self.expect(&TokenKind::RParen, ")")?;
1230                    let span = start.merge(end);
1231                    Ok(TypeExpr {
1232                        kind: TypeExprKind::Paren(Box::new(first)),
1233                        span,
1234                    })
1235                }
1236            }
1237            _ => Err(self.err("expected type")),
1238        }
1239    }
1240}
1241
1242#[cfg(test)]
1243mod tests {
1244    use super::*;
1245    use crate::lexer::Lexer;
1246
1247    fn parse(input: &str) -> Program {
1248        let mut lexer = Lexer::new(input, 0);
1249        let tokens = lexer.tokenize().expect("lex error");
1250        let mut parser = Parser::new(tokens);
1251        parser.parse_program().expect("parse error")
1252    }
1253
1254    #[allow(dead_code)]
1255    fn parse_err(input: &str) -> String {
1256        let mut lexer = Lexer::new(input, 0);
1257        let tokens = lexer.tokenize().expect("lex error");
1258        let mut parser = Parser::new(tokens);
1259        parser.parse_program().unwrap_err().message
1260    }
1261
1262    #[test]
1263    fn test_val_binding() {
1264        let prog = parse("val x = 42");
1265        assert_eq!(prog.decls.len(), 1);
1266        assert!(matches!(&prog.decls[0].kind, DeclKind::Val(_, _)));
1267    }
1268
1269    #[test]
1270    fn test_val_rec() {
1271        let prog = parse("val rec f = fn x => x");
1272        if let DeclKind::ValRec(name, _) = &prog.decls[0].kind {
1273            assert_eq!(prog.interner.resolve(*name), "f");
1274        } else {
1275            panic!("expected ValRec");
1276        }
1277    }
1278
1279    #[test]
1280    fn test_val_rec_requires_fn() {
1281        assert_eq!(
1282            parse_err("val rec x = 1"),
1283            "val rec requires fn on the right-hand side"
1284        );
1285    }
1286
1287    #[test]
1288    fn test_app_with_unary_neg() {
1289        // f ~1 should parse as App(f, UnaryNeg(1))
1290        let prog = parse("val x = f ~1");
1291        if let DeclKind::Val(_, ref expr) = prog.decls[0].kind {
1292            if let ExprKind::App(_, ref arg) = expr.kind {
1293                assert!(matches!(&arg.kind, ExprKind::UnaryNeg(_)));
1294            } else {
1295                panic!("expected App");
1296            }
1297        }
1298    }
1299
1300    #[test]
1301    fn test_app_with_not() {
1302        let prog = parse("val x = f not true");
1303        if let DeclKind::Val(_, ref expr) = prog.decls[0].kind {
1304            if let ExprKind::App(_, ref arg) = expr.kind {
1305                assert!(matches!(&arg.kind, ExprKind::Not(_)));
1306            } else {
1307                panic!("expected App");
1308            }
1309        }
1310    }
1311
1312    #[test]
1313    fn test_constructor_with_unary_neg() {
1314        let prog = parse("val x = Some ~1");
1315        if let DeclKind::Val(_, ref expr) = prog.decls[0].kind {
1316            if let ExprKind::App(_, ref arg) = expr.kind {
1317                assert!(matches!(&arg.kind, ExprKind::UnaryNeg(_)));
1318            } else {
1319                panic!("expected App");
1320            }
1321        }
1322    }
1323
1324    #[test]
1325    fn test_fun_simple() {
1326        let prog = parse("fun add x y = x + y");
1327        if let DeclKind::Fun(bindings) = &prog.decls[0].kind {
1328            assert_eq!(prog.interner.resolve(bindings[0].name), "add");
1329            assert_eq!(bindings[0].clauses[0].pats.len(), 2);
1330        } else {
1331            panic!("expected fun");
1332        }
1333    }
1334
1335    #[test]
1336    fn test_fun_clausal() {
1337        let prog = parse("fun f 0 = 1 | f n = n");
1338        if let DeclKind::Fun(bindings) = &prog.decls[0].kind {
1339            assert_eq!(bindings[0].clauses.len(), 2);
1340        } else {
1341            panic!("expected fun");
1342        }
1343    }
1344
1345    #[test]
1346    fn test_fun_mutual() {
1347        let prog = parse("fun f x = g x and g y = f y");
1348        if let DeclKind::Fun(bindings) = &prog.decls[0].kind {
1349            assert_eq!(bindings.len(), 2);
1350            assert_eq!(prog.interner.resolve(bindings[0].name), "f");
1351            assert_eq!(prog.interner.resolve(bindings[1].name), "g");
1352        } else {
1353            panic!("expected fun");
1354        }
1355    }
1356
1357    #[test]
1358    fn test_datatype_simple() {
1359        let prog = parse("datatype shape = Circle of Float | Rect of Float * Float");
1360        if let DeclKind::Datatype(dt) = &prog.decls[0].kind {
1361            assert_eq!(prog.interner.resolve(dt.name), "shape");
1362            assert_eq!(dt.tyvars.len(), 0);
1363            assert_eq!(dt.constructors.len(), 2);
1364        } else {
1365            panic!("expected datatype");
1366        }
1367    }
1368
1369    #[test]
1370    fn test_datatype_parameterized() {
1371        let prog = parse("datatype 'a option = None | Some of 'a");
1372        if let DeclKind::Datatype(dt) = &prog.decls[0].kind {
1373            let tyvars: Vec<&str> = dt
1374                .tyvars
1375                .iter()
1376                .map(|s| prog.interner.resolve(*s))
1377                .collect();
1378            assert_eq!(tyvars, vec!["'a"]);
1379            assert_eq!(dt.constructors.len(), 2);
1380        } else {
1381            panic!("expected datatype");
1382        }
1383    }
1384
1385    #[test]
1386    fn test_datatype_multi_param() {
1387        let prog = parse("datatype ('a, 'b) either = Left of 'a | Right of 'b");
1388        if let DeclKind::Datatype(dt) = &prog.decls[0].kind {
1389            let tyvars: Vec<&str> = dt
1390                .tyvars
1391                .iter()
1392                .map(|s| prog.interner.resolve(*s))
1393                .collect();
1394            assert_eq!(tyvars, vec!["'a", "'b"]);
1395        } else {
1396            panic!("expected datatype");
1397        }
1398    }
1399
1400    #[test]
1401    fn test_type_alias() {
1402        let prog = parse("type point = Float * Float");
1403        assert!(matches!(&prog.decls[0].kind, DeclKind::TypeAlias(_)));
1404    }
1405
1406    #[test]
1407    fn test_use_decl() {
1408        let prog = parse(r#"use "foo.hml""#);
1409        assert!(matches!(&prog.decls[0].kind, DeclKind::Use(path) if path == "foo.hml"));
1410    }
1411
1412    #[test]
1413    fn test_let_expr() {
1414        let prog = parse("val x = let val a = 1 in a + 2 end");
1415        assert!(matches!(&prog.decls[0].kind, DeclKind::Val(_, _)));
1416    }
1417
1418    #[test]
1419    fn test_case_expr() {
1420        let prog = parse("val x = case y of 0 => 1 | n => n");
1421        assert!(matches!(&prog.decls[0].kind, DeclKind::Val(_, _)));
1422    }
1423
1424    #[test]
1425    fn test_fn_expr() {
1426        let prog = parse("val f = fn x => x + 1");
1427        assert!(matches!(&prog.decls[0].kind, DeclKind::Val(_, _)));
1428    }
1429
1430    #[test]
1431    fn test_if_expr() {
1432        let prog = parse("val x = if true then 1 else 2");
1433        assert!(matches!(&prog.decls[0].kind, DeclKind::Val(_, _)));
1434    }
1435
1436    #[test]
1437    fn test_tuple_expr() {
1438        let prog = parse("val x = (1, 2, 3)");
1439        if let DeclKind::Val(_, ref expr) = prog.decls[0].kind {
1440            assert!(matches!(&expr.kind, ExprKind::Tuple(elems) if elems.len() == 3));
1441        }
1442    }
1443
1444    #[test]
1445    fn test_list_expr() {
1446        let prog = parse("val x = [1, 2, 3]");
1447        if let DeclKind::Val(_, ref expr) = prog.decls[0].kind {
1448            assert!(matches!(&expr.kind, ExprKind::List(elems) if elems.len() == 3));
1449        }
1450    }
1451
1452    #[test]
1453    fn test_cons_expr() {
1454        let prog = parse("val x = 1 :: 2 :: []");
1455        if let DeclKind::Val(_, ref expr) = prog.decls[0].kind {
1456            assert!(matches!(&expr.kind, ExprKind::Cons(_, _)));
1457        }
1458    }
1459
1460    #[test]
1461    fn test_operator_precedence() {
1462        // 1 + 2 * 3 should be 1 + (2 * 3)
1463        let prog = parse("val x = 1 + 2 * 3");
1464        if let DeclKind::Val(_, ref expr) = prog.decls[0].kind {
1465            if let ExprKind::BinOp(BinOp::AddInt, _, ref rhs) = expr.kind {
1466                assert!(matches!(&rhs.kind, ExprKind::BinOp(BinOp::MulInt, _, _)));
1467            } else {
1468                panic!("expected AddInt at top");
1469            }
1470        }
1471    }
1472
1473    #[test]
1474    fn test_application() {
1475        let prog = parse("val x = f a b");
1476        if let DeclKind::Val(_, ref expr) = prog.decls[0].kind {
1477            // f a b = (f a) b
1478            if let ExprKind::App(ref func, _) = expr.kind {
1479                assert!(matches!(&func.kind, ExprKind::App(_, _)));
1480            } else {
1481                panic!("expected App");
1482            }
1483        }
1484    }
1485
1486    #[test]
1487    fn test_pattern_cons() {
1488        let prog = parse("val (x :: xs) = [1, 2]");
1489        if let DeclKind::Val(ref pat, _) = prog.decls[0].kind {
1490            if let PatKind::Paren(ref inner) = pat.kind {
1491                assert!(matches!(&inner.kind, PatKind::Cons(_, _)));
1492            }
1493        }
1494    }
1495
1496    #[test]
1497    fn test_pattern_constructor() {
1498        let prog = parse("fun f (Some x) = x | f None = 0");
1499        if let DeclKind::Fun(ref bindings) = prog.decls[0].kind {
1500            assert_eq!(bindings[0].clauses.len(), 2);
1501        }
1502    }
1503
1504    #[test]
1505    fn test_type_annotation() {
1506        let prog = parse("val x = (42 : Int)");
1507        assert!(matches!(&prog.decls[0].kind, DeclKind::Val(_, _)));
1508    }
1509
1510    #[test]
1511    fn test_arrow_type() {
1512        let prog = parse("type f = Int -> Bool");
1513        if let DeclKind::TypeAlias(ref ta) = prog.decls[0].kind {
1514            assert!(matches!(&ta.ty.kind, TypeExprKind::Arrow(_, _)));
1515        }
1516    }
1517
1518    #[test]
1519    fn test_type_app() {
1520        let prog = parse("type xs = Int list");
1521        if let DeclKind::TypeAlias(ref ta) = prog.decls[0].kind {
1522            if let TypeExprKind::App(sym, _) = &ta.ty.kind {
1523                assert_eq!(prog.interner.resolve(*sym), "list");
1524            } else {
1525                panic!("expected App");
1526            }
1527        }
1528    }
1529
1530    #[test]
1531    fn test_local_decl() {
1532        let prog = parse("local val x = 1 in val y = x end");
1533        assert!(matches!(&prog.decls[0].kind, DeclKind::Local(_, _)));
1534    }
1535
1536    #[test]
1537    fn test_negative_pattern() {
1538        let prog = parse("fun f ~1 = true | f _ = false");
1539        if let DeclKind::Fun(ref bindings) = prog.decls[0].kind {
1540            if let PatKind::IntLit(n) = &bindings[0].clauses[0].pats[0].kind {
1541                assert_eq!(*n, -1);
1542            }
1543        }
1544    }
1545
1546    #[test]
1547    fn test_as_pattern() {
1548        let prog = parse("val (x as Some _) = y");
1549        if let DeclKind::Val(ref pat, _) = prog.decls[0].kind {
1550            if let PatKind::Paren(ref inner) = pat.kind {
1551                if let PatKind::As(sym, _) = &inner.kind {
1552                    assert_eq!(prog.interner.resolve(*sym), "x");
1553                } else {
1554                    panic!("expected As");
1555                }
1556            }
1557        }
1558    }
1559
1560    #[test]
1561    fn test_float_operators() {
1562        let prog = parse("val x = 1.0 +. 2.0 *. 3.0");
1563        if let DeclKind::Val(_, ref expr) = prog.decls[0].kind {
1564            if let ExprKind::BinOp(BinOp::AddFloat, _, ref rhs) = expr.kind {
1565                assert!(matches!(&rhs.kind, ExprKind::BinOp(BinOp::MulFloat, _, _)));
1566            } else {
1567                panic!("expected AddFloat");
1568            }
1569        }
1570    }
1571
1572    #[test]
1573    fn test_unit_expr() {
1574        let prog = parse("val x = ()");
1575        if let DeclKind::Val(_, ref expr) = prog.decls[0].kind {
1576            assert!(matches!(&expr.kind, ExprKind::Unit));
1577        }
1578    }
1579
1580    #[test]
1581    fn test_empty_list() {
1582        let prog = parse("val x = []");
1583        if let DeclKind::Val(_, ref expr) = prog.decls[0].kind {
1584            assert!(matches!(&expr.kind, ExprKind::List(elems) if elems.is_empty()));
1585        }
1586    }
1587
1588    #[test]
1589    fn test_orelse_right_assoc() {
1590        // a orelse b orelse c should be a orelse (b orelse c)
1591        let prog = parse("val x = a orelse b orelse c");
1592        if let DeclKind::Val(_, ref expr) = prog.decls[0].kind {
1593            if let ExprKind::BinOp(BinOp::Orelse, _, ref rhs) = expr.kind {
1594                assert!(matches!(&rhs.kind, ExprKind::BinOp(BinOp::Orelse, _, _)));
1595            } else {
1596                panic!("expected Orelse at top");
1597            }
1598        }
1599    }
1600
1601    #[test]
1602    fn test_andalso_right_assoc() {
1603        let prog = parse("val x = a andalso b andalso c");
1604        if let DeclKind::Val(_, ref expr) = prog.decls[0].kind {
1605            if let ExprKind::BinOp(BinOp::Andalso, _, ref rhs) = expr.kind {
1606                assert!(matches!(&rhs.kind, ExprKind::BinOp(BinOp::Andalso, _, _)));
1607            } else {
1608                panic!("expected Andalso at top");
1609            }
1610        }
1611    }
1612
1613    #[test]
1614    fn test_complex_program() {
1615        // A realistic multi-declaration program
1616        let src = r#"
1617            datatype 'a option = None | Some of 'a
1618
1619            fun map_option f opt =
1620              case opt of
1621                None   => None
1622              | Some x => Some (f x)
1623
1624            val result = map_option (fn x => x + 1) (Some 42)
1625        "#;
1626        let prog = parse(src);
1627        assert_eq!(prog.decls.len(), 3);
1628    }
1629}