fusabi_frontend/
parser.rs

1//! Recursive-descent parser for Mini-F# expressions.
2//!
3//! This module implements a recursive-descent parser that converts a stream of tokens
4//! from the lexer into an Abstract Syntax Tree (AST). The parser supports:
5//!
6//! - Literals: integers, floats, booleans, strings, unit
7//! - Variables and identifiers
8//! - Let-bindings: `let x = expr in body`
9//! - Multi-parameter functions (curried): `let f x y = expr in body`
10//! - Lambda functions: `fun x -> body` and multi-parameter `fun x y -> body`
11//! - Function application: `f x y`
12//! - Binary operations: arithmetic, comparison, logical
13//! - Conditional expressions: `if cond then expr1 else expr2`
14//! - Tuples: `(1, 2)`, `(x, y, z)`, `(42,)` (single-element)
15//! - Lists: `[1, 2, 3]`, `[1; 2; 3]`, `[]`
16//! - Arrays: `[|1; 2; 3|]`, `arr.[0]`, `arr.[0] <- 99`
17//! - Records: `type Person = { name: string }`, `{ name = "John" }`, `person.name`, `{ person with age = 31 }`
18//! - Discriminated Unions: `type Option = Some of int | None`, `Some(42)`, `None`, `Some 42`
19//! - Cons operator: `1 :: [2; 3]`, `x :: xs`
20//! - Unary minus: `-42`, `-x`
21//! - Modules: `module Math = ...`, `open Math`
22//! - Proper operator precedence
23//! - Error recovery and reporting
24//!
25//! module     ::= declaration*
26//! declaration::= type_def | let_binding
27//! type_def   ::= "type" IDENT "=" "{" (IDENT ":" type_expr (";" IDENT ":" type_expr)* ";"?)? "}"
28//!              | "type" IDENT "=" variant ("|" variant)*
29//! variant    ::= IDENT ("of" type_expr ("*" type_expr)*)?
30//! type_expr  ::= simple_type ("->" type_expr)? | simple_type ("*" simple_type)*
31//! simple_type::= IDENT
32//! let_binding::= "let" IDENT IDENT* "=" expr
33//! # Grammar (Simplified)
34//!
35//! ```text
36//! program    ::= import* module_def* expr?
37//! import     ::= "open" IDENT ("." IDENT)*
38//! module_def ::= "module" IDENT "=" module_item*
39//! module_item::= let_binding | type_def | module_def
40//! expr       ::= let_expr | if_expr | lambda_expr | or_expr
41//! let_expr   ::= "let" IDENT IDENT* "=" expr "in" expr
42//! if_expr    ::= "if" expr "then" expr "else" expr
43//! lambda_expr::= "fun" IDENT+ "->" expr
44//! or_expr    ::= and_expr ("||" and_expr)*
45//! and_expr   ::= comp_expr ("&&" comp_expr)*
46//! comp_expr  ::= cons_expr (("=" | "==" | "<>" | "<" | "<=" | ">" | ">=") cons_expr)?
47//! cons_expr  ::= add_expr ("::" cons_expr)?
48//! add_expr   ::= mul_expr (("+" | "-") mul_expr)*
49//! mul_expr   ::= unary_expr (("*" | "/") unary_expr)*
50//! unary_expr ::= "-" unary_expr | app_expr
51//! app_expr   ::= postfix_expr (postfix_expr)*
52//! postfix_expr ::= primary (".[" expr "]" ("<-" expr)?)*
53//! primary    ::= INT | FLOAT | BOOL | STRING | IDENT | "(" expr ")" | tuple | list | array | "Array.length" primary | variant_construct
54//! tuple      ::= "(" ")" | "(" expr ("," expr)* ","? ")"
55//! list       ::= "[" "]" | "[" expr (("," | ";") expr)* ("," | ";")? "]"
56//! array      ::= "[|" "]" | "[|" expr (";" expr)* ";"? "|]"
57//! record_literal ::= "{" (IDENT "=" expr (";" IDENT "=" expr)* ";"?)? "}"
58//! record_update  ::= "{" expr "with" IDENT "=" expr (";" IDENT "=" expr)* ";"? "}"
59//! variant_construct ::= IDENT ("(" expr ("," expr)* ")")? | IDENT expr
60//! ```
61//!
62//! # Example
63//!
64//! ```rust
65//! use fusabi_frontend::parser::Parser;
66//! use fusabi_frontend::lexer::Lexer;
67//! use fusabi_frontend::ast::{Expr, Literal, BinOp};
68//!
69//! let mut lexer = Lexer::new("let x = 42 in x + 1");
70//! let tokens = lexer.tokenize().unwrap();
71//! let mut parser = Parser::new(tokens);
72//! let ast = parser.parse().unwrap();
73//!
74//! // AST represents: let x = 42 in (x + 1)
75//! assert!(ast.is_let());
76//! ```
77use crate::ast::{
78    BinOp, CEStatement, DuTypeDef, Expr, Import, Literal, LoadDirective, MatchArm, ModuleDef,
79    ModuleItem, Pattern, Program, TypeDefinition, TypeExpr, VariantDef,
80};
81use crate::lexer::{Position, Token, TokenWithPos};
82use std::fmt;
83
84/// Parse errors with position information.
85#[derive(Debug, Clone, PartialEq)]
86pub enum ParseError {
87    /// Unexpected token encountered
88    UnexpectedToken {
89        expected: String,
90        found: Token,
91        pos: Position,
92    },
93    /// Unexpected end of input
94    UnexpectedEof { expected: String },
95    /// Invalid expression
96    InvalidExpr { message: String, pos: Position },
97}
98
99impl fmt::Display for ParseError {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        match self {
102            ParseError::UnexpectedToken {
103                expected,
104                found,
105                pos,
106            } => {
107                write!(
108                    f,
109                    "Parse error at {}: expected {}, found {}",
110                    pos, expected, found
111                )
112            }
113            ParseError::UnexpectedEof { expected } => {
114                write!(
115                    f,
116                    "Parse error: unexpected end of file, expected {}",
117                    expected
118                )
119            }
120            ParseError::InvalidExpr { message, pos } => {
121                write!(f, "Parse error at {}: {}", pos, message)
122            }
123        }
124    }
125}
126
127impl std::error::Error for ParseError {}
128
129type Result<T> = std::result::Result<T, ParseError>;
130
131/// Result of parsing a `let` construct, which could be a ModuleItem or an Expr
132enum LetResult {
133    Item(ModuleItem),
134    Expr(Expr),
135}
136
137/// Recursive-descent parser for Mini-F# expressions.
138pub struct Parser {
139    tokens: Vec<TokenWithPos>,
140    pos: usize,
141}
142
143impl Parser {
144    /// Create a new parser from a token stream.
145    pub fn new(tokens: Vec<TokenWithPos>) -> Self {
146        Parser { tokens, pos: 0 }
147    }
148
149    /// Parse the token stream into an expression AST.
150    ///
151    /// This is the main entry point for parsing. It delegates to `parse_expr` for
152    /// expression parsing. For backward compatibility with existing code.
153    pub fn parse(&mut self) -> Result<Expr> {
154        let expr = self.parse_expr()?;
155
156        // Ensure we've consumed all tokens (except EOF)
157        if !self.is_at_end() {
158            let tok = self.current_token();
159            return Err(ParseError::UnexpectedToken {
160                expected: "end of input".to_string(),
161                found: tok.token.clone(),
162                pos: tok.pos,
163            });
164        }
165
166        Ok(expr)
167    }
168
169    /// Parse a complete program with modules, imports, and main expression.
170    ///
171    /// This is the new entry point for parsing programs with module system support.
172    pub fn parse_program(&mut self) -> Result<Program> {
173        let mut directives = vec![];
174        let mut imports = vec![];
175        let mut modules = vec![];
176        let mut items = vec![];
177        let mut main_expr = None;
178
179        // Parse load directives first (must come before everything else)
180        while let Some(Token::LoadDirective(_)) = self.peek() {
181            directives.push(self.parse_load_directive()?);
182        }
183
184        // Parse imports
185        while self.peek() == Some(&Token::Open) {
186            imports.push(self.parse_import()?);
187        }
188
189        // Parse module definitions
190        while self.peek() == Some(&Token::Module) {
191            modules.push(self.parse_module()?);
192        }
193
194        // Parse top-level items and main expression
195        while !self.is_at_end() {
196            let tok = self.current_token();
197            match tok.token {
198                Token::Let => {
199                    // Check if it's a top-level binding or a let expression
200                    // We parse the binding part first
201                    let binding = self.parse_let_binding_or_expr()?;
202                    match binding {
203                        LetResult::Item(item) => items.push(item),
204                        LetResult::Expr(expr) => {
205                            main_expr = Some(expr);
206                            // If we found a main expression (e.g., let ... in ...),
207                            // we shouldn't expect more top-level items unless they are part of that expression
208                            // (which parse_expr handles).
209                            // However, if there's trailing junk, verify EOF?
210                            // For now, let's assume this completes the program or fail if more follows?
211                            // F# doesn't really allow `let ... in ...; let ...` at top level.
212                            break;
213                        }
214                    }
215                }
216                Token::Do => {
217                    // do expr is syntax sugar for let _ = expr
218                    self.advance();
219                    let expr = self.parse_expr()?;
220                    items.push(ModuleItem::Let(None, expr));
221                }
222                Token::Type => {
223                    let type_def = self.parse_type_def()?;
224                    items.push(ModuleItem::TypeDef(type_def));
225                }
226                _ => {
227                    // Assume main expression
228                    let expr = self.parse_expr()?;
229                    main_expr = Some(expr);
230                    break;
231                }
232            }
233        }
234
235        Ok(Program {
236            directives,
237            modules,
238            imports,
239            items,
240            main_expr,
241        })
242    }
243
244    /// Parse a module definition: module Math = <items>
245    fn parse_module(&mut self) -> Result<ModuleDef> {
246        self.expect_token(Token::Module)?;
247        let name = self.expect_ident()?;
248        self.expect_token(Token::Eq)?;
249
250        let items = self.parse_module_items()?;
251
252        Ok(ModuleDef { name, items })
253    }
254
255    /// Parse module items (let bindings, types, nested modules)
256    fn parse_module_items(&mut self) -> Result<Vec<ModuleItem>> {
257        let mut items = vec![];
258
259        // Continue until we hit EOF or another module keyword
260        while !self.is_at_end()
261            && self.peek() != Some(&Token::Module)
262            && self.peek() != Some(&Token::Open)
263        {
264            let tok = &self.current_token().token;
265
266            match tok {
267                Token::Let => {
268                    // Inside a module, we expect items, but let's handle potential ambiguity properly
269                    // although technically 'in' is not valid inside a module unless it's inside an expr.
270                    // But parse_let_binding_or_expr handles top-level context.
271                    // For modules, we expect declarations.
272                    // However, parse_let_binding_parts is what we used before.
273                    // Let's use parse_let_binding_or_expr and ensure it returns an Item.
274                    let result = self.parse_let_binding_or_expr()?;
275                    match result {
276                        LetResult::Item(item) => items.push(item),
277                        LetResult::Expr(_) => {
278                            return Err(ParseError::UnexpectedToken {
279                                expected: "module item".to_string(),
280                                found: Token::In,
281                                pos: self.current_token().pos,
282                            });
283                        }
284                    }
285                }
286                Token::Do => {
287                    // do expr is syntax sugar for let _ = expr
288                    self.advance();
289                    let expr = self.parse_expr()?;
290                    items.push(ModuleItem::Let(None, expr));
291                }
292                Token::Type => {
293                    let type_def = self.parse_type_def()?;
294                    items.push(ModuleItem::TypeDef(type_def));
295                }
296                _ => break,
297            }
298        }
299
300        Ok(items)
301    }
302
303    /// Helper: parse a let construct that could be a binding or an expression
304    fn parse_let_binding_or_expr(&mut self) -> Result<LetResult> {
305        self.expect_token(Token::Let)?;
306
307        // Check for "rec" keyword
308        let is_rec = self.match_token(&Token::Rec);
309
310        if is_rec {
311            // Recursive binding(s)
312            let first_name = self.expect_ident()?;
313            let mut params = vec![];
314            while let Token::Ident(_) = &self.current_token().token {
315                params.push(self.expect_ident()?);
316            }
317
318            self.expect_token(Token::Eq)?;
319            let mut first_value = self.parse_expr()?;
320
321            // Desugar params
322            if !params.is_empty() {
323                first_value =
324                    params
325                        .into_iter()
326                        .rev()
327                        .fold(first_value, |acc, param| Expr::Lambda {
328                            param,
329                            body: Box::new(acc),
330                        });
331            }
332
333            // Check for mutual recursion ('and')
334            if self.match_token(&Token::AndKeyword) {
335                let mut bindings = vec![(first_name, first_value)];
336
337                loop {
338                    let name = self.expect_ident()?;
339                    let mut params = vec![];
340                    while let Token::Ident(_) = &self.current_token().token {
341                        params.push(self.expect_ident()?);
342                    }
343                    self.expect_token(Token::Eq)?;
344                    let mut value = self.parse_expr()?;
345
346                    if !params.is_empty() {
347                        value = params
348                            .into_iter()
349                            .rev()
350                            .fold(value, |acc, param| Expr::Lambda {
351                                param,
352                                body: Box::new(acc),
353                            });
354                    }
355                    bindings.push((name, value));
356
357                    if !self.match_token(&Token::AndKeyword) {
358                        break;
359                    }
360                }
361
362                // Now check for 'in'
363                if self.match_token(&Token::In) {
364                    let body = self.parse_expr()?;
365                    Ok(LetResult::Expr(Expr::LetRecMutual {
366                        bindings,
367                        body: Box::new(body),
368                    }))
369                } else {
370                    // It's a LetRec item.
371                    // Convert (name, val) pairs.
372                    // ModuleItem::LetRec takes a Vec.
373                    Ok(LetResult::Item(ModuleItem::LetRec(bindings)))
374                }
375            } else {
376                // Single recursive binding
377                // Expect 'in' - wait, for top-level item, 'in' is NOT expected.
378                // If 'in' is present, it is an expression.
379                if self.match_token(&Token::In) {
380                    let body = self.parse_expr()?;
381                    Ok(LetResult::Expr(Expr::LetRec {
382                        name: first_name,
383                        value: Box::new(first_value),
384                        body: Box::new(body),
385                    }))
386                } else {
387                    Ok(LetResult::Item(ModuleItem::LetRec(vec![(
388                        first_name,
389                        first_value,
390                    )])))
391                }
392            }
393        } else {
394            // Simple Let
395            // Check for discard pattern '_'
396            let name = match &self.current_token().token {
397                Token::Underscore => {
398                    self.advance();
399                    None
400                }
401                Token::Ident(id) if id == "_" => {
402                    self.advance();
403                    None
404                }
405                _ => Some(self.expect_ident()?),
406            };
407
408            let mut params = vec![];
409            while let Token::Ident(_) = &self.current_token().token {
410                params.push(self.expect_ident()?);
411            }
412
413            self.expect_token(Token::Eq)?;
414            let mut value = self.parse_expr()?;
415
416            if !params.is_empty() {
417                value = params
418                    .into_iter()
419                    .rev()
420                    .fold(value, |acc, param| Expr::Lambda {
421                        param,
422                        body: Box::new(acc),
423                    });
424            }
425
426            if self.match_token(&Token::In) {
427                let body = self.parse_expr()?;
428                // Discard variables not allowed in let...in expressions
429                if name.is_none() {
430                    return Err(ParseError::UnexpectedToken {
431                        expected: "identifier".to_string(),
432                        found: Token::Ident("_".to_string()),
433                        pos: self.current_token().pos,
434                    });
435                }
436                Ok(LetResult::Expr(Expr::Let {
437                    name: name.unwrap(),
438                    value: Box::new(value),
439                    body: Box::new(body),
440                }))
441            } else {
442                Ok(LetResult::Item(ModuleItem::Let(name, value)))
443            }
444        }
445    }
446
447    /// Parse an import statement: open Math or open Math.Geometry
448    /// Parse a load directive: #load "path.fsx"
449    fn parse_load_directive(&mut self) -> Result<LoadDirective> {
450        if let Some(Token::LoadDirective(path)) = self.peek() {
451            let path = path.clone();
452            self.advance();
453            Ok(LoadDirective { path })
454        } else {
455            let tok = self.current_token();
456            Err(ParseError::UnexpectedToken {
457                expected: "#load directive".to_string(),
458                found: tok.token.clone(),
459                pos: tok.pos,
460            })
461        }
462    }
463
464    fn parse_import(&mut self) -> Result<Import> {
465        self.expect_token(Token::Open)?;
466
467        let mut path = vec![self.expect_ident()?];
468
469        // Handle qualified names: open Math.Geometry
470        while self.check(&Token::Dot) {
471            self.advance();
472            path.push(self.expect_ident()?);
473        }
474
475        Ok(Import {
476            module_path: path,
477            is_qualified: false,
478        })
479    }
480
481    /// Parse a type definition (record or discriminated union)
482    fn parse_type_def(&mut self) -> Result<TypeDefinition> {
483        // For now, delegate to existing parse_du_type_def
484        // In the future, this should also handle records
485        let du_def = self.parse_du_type_def()?;
486        Ok(TypeDefinition::Du(du_def))
487    }
488
489    // ========================================================================
490    // Expression Parsing
491    // ========================================================================
492
493    /// Parse an expression
494    fn parse_expr(&mut self) -> Result<Expr> {
495        // Try let, if, lambda, match, while first, then fall through to parse_pipeline_expr
496        let tok = &self.current_token().token;
497        match tok {
498            Token::Let => self.parse_let(),
499            Token::If => self.parse_if(),
500            Token::Fun => self.parse_lambda(),
501            Token::Match => self.parse_match(),
502            Token::While => self.parse_while(),
503            Token::Break => {
504                self.advance();
505                Ok(Expr::Break)
506            }
507            Token::Continue => {
508                self.advance();
509                Ok(Expr::Continue)
510            }
511            _ => self.parse_pipeline_expr(), // Start parsing from pipeline operator level
512        }
513    }
514
515    /// Parse let-binding: let x = expr in body
516    fn parse_let(&mut self) -> Result<Expr> {
517        self.expect_token(Token::Let)?;
518
519        // Check for "rec" keyword (recursive let)
520        if self.match_token(&Token::Rec) {
521            return self.parse_let_rec();
522        }
523
524        let name = self.expect_ident()?;
525
526        // Parse optional parameter list (for multi-parameter functions)
527        // Example: let f x y = ...
528        let mut params = vec![];
529        while let Token::Ident(_) = &self.current_token().token {
530            params.push(self.expect_ident()?);
531        }
532
533        self.expect_token(Token::Eq)?;
534        let mut value = self.parse_expr()?;
535
536        // If we have params, desugar into nested lambdas
537        // let f x y = body  =>  let f = fun x -> fun y -> body
538        if !params.is_empty() {
539            value = params
540                .into_iter()
541                .rev()
542                .fold(value, |acc, param| Expr::Lambda {
543                    param,
544                    body: Box::new(acc),
545                });
546        }
547
548        self.expect_token(Token::In)?;
549        let body = self.parse_expr()?;
550
551        Ok(Expr::Let {
552            name,
553            value: Box::new(value),
554            body: Box::new(body),
555        })
556    }
557
558    /// Parse recursive let-binding: let rec f x = ... in body
559    fn parse_let_rec(&mut self) -> Result<Expr> {
560        // Expect function name
561        let first_name = self.expect_ident()?;
562
563        // Parse parameters
564        let mut params = vec![];
565        while let Token::Ident(_) = &self.current_token().token {
566            params.push(self.expect_ident()?);
567        }
568
569        self.expect_token(Token::Eq)?;
570        let mut first_value = self.parse_expr()?;
571
572        // Desugar params into nested lambdas
573        if !params.is_empty() {
574            first_value = params
575                .into_iter()
576                .rev()
577                .fold(first_value, |acc, param| Expr::Lambda {
578                    param,
579                    body: Box::new(acc),
580                });
581        }
582
583        // Check for mutual recursion ('and')
584        if self.match_token(&Token::AndKeyword) {
585            let mut bindings = vec![(first_name, first_value)];
586
587            loop {
588                let name = self.expect_ident()?;
589                let mut params = vec![];
590                while let Token::Ident(_) = &self.current_token().token {
591                    params.push(self.expect_ident()?);
592                }
593                self.expect_token(Token::Eq)?;
594                let mut value = self.parse_expr()?;
595
596                if !params.is_empty() {
597                    value = params
598                        .into_iter()
599                        .rev()
600                        .fold(value, |acc, param| Expr::Lambda {
601                            param,
602                            body: Box::new(acc),
603                        });
604                }
605                bindings.push((name, value));
606
607                if !self.match_token(&Token::AndKeyword) {
608                    break;
609                }
610            }
611
612            self.expect_token(Token::In)?;
613            let body = self.parse_expr()?;
614
615            Ok(Expr::LetRecMutual {
616                bindings,
617                body: Box::new(body),
618            })
619        } else {
620            // Single recursive function
621            self.expect_token(Token::In)?;
622            let body = self.parse_expr()?;
623
624            Ok(Expr::LetRec {
625                name: first_name,
626                value: Box::new(first_value),
627                body: Box::new(body),
628            })
629        }
630    }
631
632    /// Parse conditional: if cond then expr1 else expr2
633    fn parse_if(&mut self) -> Result<Expr> {
634        self.expect_token(Token::If)?;
635
636        let cond = self.parse_expr()?;
637
638        self.expect_token(Token::Then)?;
639        let then_branch = self.parse_expr()?;
640
641        self.expect_token(Token::Else)?;
642        let else_branch = self.parse_expr()?;
643
644        Ok(Expr::If {
645            cond: Box::new(cond),
646            then_branch: Box::new(then_branch),
647            else_branch: Box::new(else_branch),
648        })
649    }
650
651    /// Parse lambda function: fun x -> body or fun x y -> body
652    fn parse_lambda(&mut self) -> Result<Expr> {
653        self.expect_token(Token::Fun)?;
654
655        // Parse parameter list
656        let mut params = vec![];
657        while let Token::Ident(_) = &self.current_token().token {
658            params.push(self.expect_ident()?);
659        }
660
661        if params.is_empty() {
662            let tok = self.current_token();
663            return Err(ParseError::UnexpectedToken {
664                expected: "parameter".to_string(),
665                found: tok.token.clone(),
666                pos: tok.pos,
667            });
668        }
669
670        self.expect_token(Token::Arrow)?;
671        let body = self.parse_expr()?;
672
673        // Desugar multi-param lambda into nested lambdas
674        // fun x y -> body  =>  fun x -> fun y -> body
675        Ok(params
676            .into_iter()
677            .rev()
678            .fold(body, |acc, param| Expr::Lambda {
679                param,
680                body: Box::new(acc),
681            }))
682    }
683
684    /// Parse match expression: match expr with | pattern -> expr
685    fn parse_match(&mut self) -> Result<Expr> {
686        self.expect_token(Token::Match)?;
687
688        let scrutinee = Box::new(self.parse_expr()?);
689
690        self.expect_token(Token::With)?;
691
692        let mut arms = vec![];
693
694        // Parse match arms
695        loop {
696            // Optional leading pipe
697            self.match_token(&Token::Pipe);
698
699            let pattern = self.parse_pattern()?;
700
701            self.expect_token(Token::Arrow)?;
702
703            let body = Box::new(self.parse_expr()?);
704
705            arms.push(MatchArm { pattern, body });
706
707            // Check if there's another arm (starts with |)
708            if !self.check(&Token::Pipe) {
709                break;
710            }
711        }
712
713        Ok(Expr::Match { scrutinee, arms })
714    }
715
716    /// Parse while loop: while cond do body
717    fn parse_while(&mut self) -> Result<Expr> {
718        self.expect_token(Token::While)?;
719
720        let cond = Box::new(self.parse_expr()?);
721
722        self.expect_token(Token::Do)?;
723
724        let body = Box::new(self.parse_expr()?);
725
726        Ok(Expr::While { cond, body })
727    }
728
729    /// Parse a pattern for match expressions
730    fn parse_pattern(&mut self) -> Result<Pattern> {
731        let tok = self.current_token();
732
733        match &tok.token {
734            Token::Underscore => {
735                self.advance();
736                Ok(Pattern::Wildcard)
737            }
738            Token::Ident(name) => {
739                let val = name.clone();
740                self.advance();
741
742                // Check if this is a variant constructor with patterns
743                if Self::is_uppercase_ident(&val) {
744                    // Variant pattern
745                    if self.match_token(&Token::LParen) {
746                        // Variant with nested patterns: Some(x), Circle(r)
747                        let mut patterns = vec![];
748
749                        if !matches!(self.current_token().token, Token::RParen) {
750                            loop {
751                                patterns.push(self.parse_pattern()?);
752
753                                if self.match_token(&Token::Comma) {
754                                    if matches!(self.current_token().token, Token::RParen) {
755                                        break;
756                                    }
757                                } else {
758                                    break;
759                                }
760                            }
761                        }
762
763                        self.expect_token(Token::RParen)?;
764                        Ok(Pattern::Variant {
765                            variant: val,
766                            patterns,
767                        })
768                    } else {
769                        // Simple variant without patterns: None, Left
770                        Ok(Pattern::Variant {
771                            variant: val,
772                            patterns: vec![],
773                        })
774                    }
775                } else {
776                    // Variable pattern
777                    Ok(Pattern::Var(val))
778                }
779            }
780            Token::Int(n) => {
781                let val = *n;
782                self.advance();
783                Ok(Pattern::Literal(Literal::Int(val)))
784            }
785            Token::Float(f) => {
786                let val = *f;
787                self.advance();
788                Ok(Pattern::Literal(Literal::Float(val)))
789            }
790            Token::Bool(b) => {
791                let val = *b;
792                self.advance();
793                Ok(Pattern::Literal(Literal::Bool(val)))
794            }
795            Token::String(s) => {
796                let val = s.clone();
797                self.advance();
798                Ok(Pattern::Literal(Literal::Str(val)))
799            }
800            Token::LParen => {
801                self.advance(); // consume '('
802
803                // Handle unit pattern: ()
804                if self.match_token(&Token::RParen) {
805                    return Ok(Pattern::Literal(Literal::Unit));
806                }
807
808                // Parse first pattern
809                let first_pat = self.parse_pattern()?;
810
811                // Check if it's a tuple (has comma) or grouped pattern (no comma)
812                if self.match_token(&Token::Comma) {
813                    // It's a tuple: (p1, p2, ...)
814                    let mut patterns = vec![first_pat];
815
816                    // Check for trailing comma or continue with more patterns
817                    if !matches!(self.current_token().token, Token::RParen) {
818                        loop {
819                            patterns.push(self.parse_pattern()?);
820
821                            if self.match_token(&Token::Comma) {
822                                // Check for trailing comma before RParen
823                                if matches!(self.current_token().token, Token::RParen) {
824                                    break;
825                                }
826                            } else {
827                                break;
828                            }
829                        }
830                    }
831
832                    self.expect_token(Token::RParen)?;
833                    Ok(Pattern::Tuple(patterns))
834                } else {
835                    // No comma, it's a grouped pattern: (p)
836                    self.expect_token(Token::RParen)?;
837                    Ok(first_pat)
838                }
839            }
840            _ => Err(ParseError::UnexpectedToken {
841                expected: "pattern".to_string(),
842                found: tok.token.clone(),
843                pos: tok.pos,
844            }),
845        }
846    }
847
848    /// Parse logical OR expression
849    fn parse_or_expr(&mut self) -> Result<Expr> {
850        let mut left = self.parse_and_expr()?;
851
852        while self.match_token(&Token::Or) {
853            let right = self.parse_and_expr()?;
854            left = Expr::BinOp {
855                op: BinOp::Or,
856                left: Box::new(left),
857                right: Box::new(right),
858            };
859        }
860
861        Ok(left)
862    }
863
864    /// Parse logical AND expression
865    fn parse_and_expr(&mut self) -> Result<Expr> {
866        let mut left = self.parse_comp_expr()?;
867
868        while self.match_token(&Token::And) {
869            let right = self.parse_comp_expr()?;
870            left = Expr::BinOp {
871                op: BinOp::And,
872                left: Box::new(left),
873                right: Box::new(right),
874            };
875        }
876
877        Ok(left)
878    }
879
880    /// Parse comparison expression
881    fn parse_comp_expr(&mut self) -> Result<Expr> {
882        let left = self.parse_cons_expr()?;
883
884        if let Some(op) = self.match_comparison_op() {
885            let right = self.parse_cons_expr()?;
886            Ok(Expr::BinOp {
887                op,
888                left: Box::new(left),
889                right: Box::new(right),
890            })
891        } else {
892            Ok(left)
893        }
894    }
895
896    /// Parse cons expression (list cons operator ::)
897    fn parse_cons_expr(&mut self) -> Result<Expr> {
898        let left = self.parse_add_expr()?;
899
900        if self.match_token(&Token::ColonColon) {
901            let right = self.parse_cons_expr()?; // Right-associative
902            Ok(Expr::Cons {
903                head: Box::new(left),
904                tail: Box::new(right),
905            })
906        } else {
907            Ok(left)
908        }
909    }
910
911    /// Parse addition/subtraction expression
912    fn parse_add_expr(&mut self) -> Result<Expr> {
913        let mut left = self.parse_mul_expr()?;
914
915        while let Some(op) = self.match_add_op() {
916            let right = self.parse_mul_expr()?;
917            left = Expr::BinOp {
918                op,
919                left: Box::new(left),
920                right: Box::new(right),
921            };
922        }
923
924        Ok(left)
925    }
926
927    /// Parse multiplication/division expression
928    fn parse_mul_expr(&mut self) -> Result<Expr> {
929        let mut left = self.parse_unary_expr()?;
930
931        while let Some(op) = self.match_mul_op() {
932            let right = self.parse_unary_expr()?;
933            left = Expr::BinOp {
934                op,
935                left: Box::new(left),
936                right: Box::new(right),
937            };
938        }
939
940        Ok(left)
941    }
942
943    /// Parse unary expressions (unary minus)
944    fn parse_unary_expr(&mut self) -> Result<Expr> {
945        if self.match_token(&Token::Minus) {
946            let expr = self.parse_unary_expr()?;
947            // Desugar unary minus as (0 - expr)
948            Ok(Expr::BinOp {
949                op: BinOp::Sub,
950                left: Box::new(Expr::Lit(Literal::Int(0))),
951                right: Box::new(expr),
952            })
953        } else {
954            self.parse_app_expr()
955        }
956    }
957
958    /// Parse pipeline expression: expr |> func
959    fn parse_pipeline_expr(&mut self) -> Result<Expr> {
960        let mut left = self.parse_or_expr()?;
961
962        while self.match_token(&Token::PipeRight) {
963            let func_expr = self.parse_app_expr()?; // The function to pipe into
964            left = Expr::App {
965                func: Box::new(func_expr),
966                arg: Box::new(left),
967            };
968        }
969
970        Ok(left)
971    }
972
973    /// Parse function application
974    fn parse_app_expr(&mut self) -> Result<Expr> {
975        let mut func = self.parse_postfix_expr()?;
976
977        // Repeatedly parse arguments while we see primary expressions
978        while self.is_primary_start() {
979            // Heuristic: if the argument is at column 1 (start of line),
980            // treat it as a new statement/expression, not an argument.
981            if self.current_token().pos.column == 1 {
982                break;
983            }
984
985            let arg = self.parse_postfix_expr()?;
986            func = Expr::App {
987                func: Box::new(func),
988                arg: Box::new(arg),
989            };
990        }
991
992        // Post-process: convert variant constructor applications to VariantConstruct
993        // This handles `Some 42` syntax by converting App(Some, 42) to VariantConstruct
994        func = self.convert_variant_app_to_construct(func);
995
996        Ok(func)
997    }
998
999    /// Convert function applications of variant constructors into VariantConstruct nodes.
1000    ///
1001    /// This enables F#-style variant syntax like `Some 42` instead of just `Some(42)`.
1002    /// The function recursively collects all arguments applied to a variant constructor
1003    /// and creates a single VariantConstruct with those arguments as fields.
1004    ///
1005    /// Examples:
1006    /// - `Some 42` (App { func: VariantConstruct("Some", []), arg: 42 })
1007    ///   becomes `VariantConstruct("Some", [42])`
1008    /// - `Rectangle 10 20` becomes `VariantConstruct("Rectangle", [10, 20])`
1009    fn convert_variant_app_to_construct(&self, expr: Expr) -> Expr {
1010        match expr {
1011            Expr::App { func, arg } => {
1012                // Check if the function is a VariantConstruct (possibly nested in more Apps)
1013                let (variant_opt, mut args) = self.extract_variant_and_args(*func, vec![]);
1014                args.push(*arg);
1015
1016                if let Some((type_name, variant)) = variant_opt {
1017                    // Convert to VariantConstruct with all collected arguments as fields
1018                    Expr::VariantConstruct {
1019                        type_name,
1020                        variant,
1021                        fields: args.into_iter().map(Box::new).collect(),
1022                    }
1023                } else {
1024                    // Not a variant application, just return the original App
1025                    // Rebuild from the collected expressions
1026                    self.rebuild_app_from_args(args)
1027                }
1028            }
1029            _ => expr,
1030        }
1031    }
1032    /// Extract variant constructor and arguments from a chain of App nodes.
1033    /// Returns (Some((type_name, variant)), args) if leftmost is a VariantConstruct,
1034    /// or (None, args) otherwise.
1035    fn extract_variant_and_args(
1036        &self,
1037        func: Expr,
1038        mut current_args: Vec<Expr>,
1039    ) -> (Option<(String, String)>, Vec<Expr>) {
1040        match func {
1041            Expr::VariantConstruct {
1042                type_name,
1043                variant,
1044                fields,
1045            } => {
1046                // Found the variant constructor
1047                // Prepend any existing fields to our arguments
1048                let mut all_fields: Vec<Expr> = fields.into_iter().map(|b| *b).collect();
1049                all_fields.extend(current_args);
1050                (Some((type_name, variant)), all_fields)
1051            }
1052            Expr::App {
1053                func: inner_func,
1054                arg,
1055            } => {
1056                // Another App in the chain, collect the argument and recurse
1057                current_args.insert(0, *arg);
1058                self.extract_variant_and_args(*inner_func, current_args)
1059            }
1060            _ => {
1061                // Not a variant constructor, return None and include the leftmost expr in args
1062                current_args.insert(0, func);
1063                (None, current_args)
1064            }
1065        }
1066    }
1067
1068    /// Extract the leftmost expression and all arguments from a chain of App nodes.
1069    fn extract_app_chain(&self, expr: Expr) -> (Expr, Vec<Expr>) {
1070        match expr {
1071            Expr::App { func, arg } => {
1072                let (leftmost, mut args) = self.extract_app_chain(*func);
1073                args.push(*arg);
1074                (leftmost, args)
1075            }
1076            _ => (expr, vec![]),
1077        }
1078    }
1079
1080    /// Rebuild App nodes from a list of expressions (left-associative).
1081    fn rebuild_app_from_args(&self, mut exprs: Vec<Expr>) -> Expr {
1082        if exprs.is_empty() {
1083            return Expr::Lit(Literal::Unit); // Shouldn't happen
1084        }
1085
1086        let mut result = exprs.remove(0);
1087        for arg in exprs {
1088            result = Expr::App {
1089                func: Box::new(result),
1090                arg: Box::new(arg),
1091            };
1092        }
1093        result
1094    }
1095
1096    /// Parse postfix expressions (array indexing, array update, record access)
1097    fn parse_postfix_expr(&mut self) -> Result<Expr> {
1098        let mut expr = self.parse_primary()?;
1099
1100        loop {
1101            let tok = &self.current_token().token;
1102            match tok {
1103                // Array indexing: arr.[index] or arr.[index] <- value
1104                Token::Dot => {
1105                    self.advance(); // consume '.'
1106                                    // Check if it's array indexing: .[
1107                    if self.match_token(&Token::LBracket) {
1108                        let index = Box::new(self.parse_expr()?);
1109                        self.expect_token(Token::RBracket)?;
1110
1111                        // Check for array update: <- value
1112                        if self.match_token(&Token::LArrow) {
1113                            let value = Box::new(self.parse_expr()?);
1114                            expr = Expr::ArrayUpdate {
1115                                array: Box::new(expr),
1116                                index,
1117                                value,
1118                            };
1119                        } else {
1120                            expr = Expr::ArrayIndex {
1121                                array: Box::new(expr),
1122                                index,
1123                            };
1124                        }
1125                    } else {
1126                        // Could be record field access or method call
1127                        let field = self.expect_ident()?;
1128
1129                        // Check if the base expression is a module (uppercase identifier)
1130                        // If so, use record access (for F#-style Module.function calls)
1131                        // not method call syntax
1132                        let is_module =
1133                            matches!(&expr, Expr::Var(name) if Self::is_uppercase_ident(name));
1134
1135                        // Check if followed by '(' to distinguish method call from field access
1136                        // But don't use method call for module access (List.map, Array.ofList, etc.)
1137                        if self.current_token().token == Token::LParen && !is_module {
1138                            // Method call: obj.method(args)
1139                            self.advance(); // consume '('
1140
1141                            let mut args = vec![];
1142
1143                            // Parse arguments
1144                            if !matches!(self.current_token().token, Token::RParen) {
1145                                loop {
1146                                    args.push(self.parse_expr()?);
1147
1148                                    if !self.match_token(&Token::Comma) {
1149                                        break;
1150                                    }
1151                                }
1152                            }
1153
1154                            self.expect_token(Token::RParen)?;
1155
1156                            expr = Expr::MethodCall {
1157                                receiver: Box::new(expr),
1158                                method_name: field,
1159                                args,
1160                            };
1161                        } else {
1162                            // Regular field access (also for module function access)
1163                            expr = Expr::RecordAccess {
1164                                record: Box::new(expr),
1165                                field,
1166                            };
1167                        }
1168                    }
1169                }
1170                _ => break,
1171            }
1172        }
1173
1174        Ok(expr)
1175    }
1176
1177    /// Parse record literal or record update: { name = "John" } or { person with age = 31 }
1178    fn parse_record_literal(&mut self) -> Result<Expr> {
1179        self.expect_token(Token::LBrace)?;
1180
1181        // Empty record: {}
1182        if self.match_token(&Token::RBrace) {
1183            return Ok(Expr::RecordLiteral {
1184                type_name: String::new(),
1185                fields: vec![],
1186            });
1187        }
1188
1189        // Check if this is a record update: { record with field = value }
1190        // We need to lookahead to distinguish between:
1191        // - { person with age = 31 }  (record update)
1192        // - { name = "John" }          (record literal)
1193
1194        // Save position to potentially backtrack
1195        let save_pos = self.pos;
1196
1197        // Try to parse first identifier
1198        if let Ok(_first_ident) = self.expect_ident() {
1199            // Check if followed by 'with' keyword
1200            if self.match_token(&Token::With) {
1201                // This is a record update: { record with ... }
1202                // The first_ident is actually an expression (variable), so restore and parse it properly
1203                self.pos = save_pos;
1204                let record = Box::new(self.parse_expr()?);
1205
1206                // Expect 'with' keyword
1207                self.expect_token(Token::With)?;
1208
1209                // Parse update fields
1210                let mut fields = vec![];
1211
1212                loop {
1213                    let field_name = self.expect_ident()?;
1214                    self.expect_token(Token::Eq)?;
1215                    let value = self.parse_expr()?;
1216                    fields.push((field_name, Box::new(value)));
1217
1218                    // Check for semicolon or closing brace
1219                    if self.match_token(&Token::Semicolon) {
1220                        // Check for trailing semicolon before }
1221                        if matches!(self.current_token().token, Token::RBrace) {
1222                            break;
1223                        }
1224                    } else {
1225                        break;
1226                    }
1227                }
1228
1229                self.expect_token(Token::RBrace)?;
1230
1231                return Ok(Expr::RecordUpdate { record, fields });
1232            }
1233        }
1234
1235        // Not a record update, restore position and parse as record literal
1236        self.pos = save_pos;
1237
1238        // Parse record literal fields
1239        let mut fields = vec![];
1240
1241        loop {
1242            let field_name = self.expect_ident()?;
1243            self.expect_token(Token::Eq)?;
1244            let value = self.parse_expr()?;
1245            fields.push((field_name, Box::new(value)));
1246
1247            // Check for semicolon or closing brace
1248            if self.match_token(&Token::Semicolon) {
1249                // Check for trailing semicolon before }
1250                if matches!(self.current_token().token, Token::RBrace) {
1251                    break;
1252                }
1253            } else {
1254                break;
1255            }
1256        }
1257
1258        self.expect_token(Token::RBrace)?;
1259
1260        Ok(Expr::RecordLiteral {
1261            type_name: String::new(),
1262            fields,
1263        })
1264    }
1265
1266    /// Parse anonymous record literal: {| name = "John"; age = 30 |}
1267    /// Anonymous records use the {| ... |} syntax and work exactly like regular records
1268    /// but without requiring a type declaration.
1269    fn parse_anonymous_record_literal(&mut self) -> Result<Expr> {
1270        self.expect_token(Token::LBracePipe)?;
1271
1272        // Empty anonymous record: {||}
1273        if self.match_token(&Token::PipeRBrace) {
1274            return Ok(Expr::RecordLiteral {
1275                type_name: String::new(),
1276                fields: vec![],
1277            });
1278        }
1279
1280        // Anonymous records don't support the 'with' update syntax in the literal itself
1281        // Parse fields
1282        let mut fields = vec![];
1283
1284        loop {
1285            let field_name = self.expect_ident()?;
1286            self.expect_token(Token::Eq)?;
1287            let value = self.parse_expr()?;
1288            fields.push((field_name, Box::new(value)));
1289
1290            // Check for semicolon or closing brace
1291            if self.match_token(&Token::Semicolon) {
1292                // Check for trailing semicolon before |}
1293                if matches!(self.current_token().token, Token::PipeRBrace) {
1294                    break;
1295                }
1296            } else if matches!(self.current_token().token, Token::PipeRBrace) {
1297                // No semicolon, but closing brace - this is ok for last field
1298                break;
1299            } else {
1300                // No semicolon and no closing brace - error
1301                let tok = self.current_token();
1302                return Err(ParseError::UnexpectedToken {
1303                    expected: "';' or '|}'".to_string(),
1304                    found: tok.token.clone(),
1305                    pos: tok.pos,
1306                });
1307            }
1308        }
1309
1310        self.expect_token(Token::PipeRBrace)?;
1311
1312        Ok(Expr::RecordLiteral {
1313            type_name: String::new(), // Anonymous records have no type name
1314            fields,
1315        })
1316    }
1317
1318    /// Parse variant constructor: Some(42), Left, Rectangle(10.0, 20.0)
1319    fn parse_variant_construct(&mut self, variant_name: String) -> Result<Expr> {
1320        // Check if this is a variant constructor with arguments: Some(42)
1321        if self.match_token(&Token::LParen) {
1322            // Parse variant field values
1323            let mut fields = vec![];
1324
1325            // Check for empty args: Some()
1326            if !matches!(self.current_token().token, Token::RParen) {
1327                loop {
1328                    fields.push(Box::new(self.parse_expr()?));
1329
1330                    if self.match_token(&Token::Comma) {
1331                        // Check for trailing comma before RParen
1332                        if matches!(self.current_token().token, Token::RParen) {
1333                            break;
1334                        }
1335                    } else {
1336                        break;
1337                    }
1338                }
1339            }
1340
1341            self.expect_token(Token::RParen)?;
1342            Ok(Expr::VariantConstruct {
1343                type_name: String::new(), // Filled by typechecker
1344                variant: variant_name,
1345                fields,
1346            })
1347        } else {
1348            // Simple variant without fields: None, Left
1349            // This will be converted to VariantConstruct with fields if followed by arguments
1350            Ok(Expr::VariantConstruct {
1351                type_name: String::new(),
1352                variant: variant_name,
1353                fields: vec![],
1354            })
1355        }
1356    }
1357
1358    /// Check if an identifier starts with uppercase letter (heuristic for variant constructor)
1359    fn is_uppercase_ident(s: &str) -> bool {
1360        s.chars().next().is_some_and(|c| c.is_uppercase())
1361    }
1362
1363    /// Parse primary expression (literals, variables, parenthesized expressions, tuples, lists)
1364    fn parse_primary(&mut self) -> Result<Expr> {
1365        let tok = self.current_token();
1366
1367        match &tok.token {
1368            Token::Int(n) => {
1369                let val = *n;
1370                self.advance();
1371                Ok(Expr::Lit(Literal::Int(val)))
1372            }
1373            Token::Float(f) => {
1374                let val = *f;
1375                self.advance();
1376                Ok(Expr::Lit(Literal::Float(val)))
1377            }
1378            Token::Bool(b) => {
1379                let val = *b;
1380                self.advance();
1381                Ok(Expr::Lit(Literal::Bool(val)))
1382            }
1383            Token::String(s) => {
1384                let val = s.clone();
1385                self.advance();
1386                Ok(Expr::Lit(Literal::Str(val)))
1387            }
1388            Token::Ident(name) => {
1389                let val = name.clone();
1390                self.advance();
1391
1392                // Check for Array.length (special case for compatibility)
1393                if val == "Array" && self.match_token(&Token::Dot) {
1394                    let method = self.expect_ident()?;
1395                    if method == "length" {
1396                        let arr = Box::new(self.parse_postfix_expr()?);
1397                        return Ok(Expr::ArrayLength(arr));
1398                    } else {
1399                        // For other Array methods, treat as module access like List.map
1400                        let record = Expr::Var("Array".to_string());
1401                        return Ok(Expr::RecordAccess {
1402                            record: Box::new(record),
1403                            field: method,
1404                        });
1405                    }
1406                }
1407
1408                // Check if this could be a variant constructor
1409                // Use uppercase heuristic: if identifier starts with uppercase, it's likely a variant
1410                // Exception: if followed by '.', it's likely a module access (e.g. String.length)
1411                if (Self::is_uppercase_ident(&val) && !self.check(&Token::Dot))
1412                    || matches!(self.current_token().token, Token::LParen)
1413                {
1414                    // This looks like a variant constructor
1415                    self.parse_variant_construct(val)
1416                } else {
1417                    // Just a regular variable
1418                    Ok(Expr::Var(val))
1419                }
1420            }
1421            Token::LParen => {
1422                self.advance(); // consume '('
1423
1424                // Handle empty tuple/unit: ()
1425                if self.match_token(&Token::RParen) {
1426                    return Ok(Expr::Lit(Literal::Unit));
1427                }
1428
1429                // Parse first expression
1430                let first_expr = self.parse_expr()?;
1431
1432                // Check if it's a tuple (has comma) or grouped expression (no comma)
1433                if self.match_token(&Token::Comma) {
1434                    // It's a tuple: (e1, e2, ...)
1435                    let mut elements = vec![first_expr];
1436
1437                    // Check for trailing comma: (e,) or continue with more elements
1438                    if !matches!(self.current_token().token, Token::RParen) {
1439                        // Parse remaining elements
1440                        loop {
1441                            elements.push(self.parse_expr()?);
1442
1443                            if self.match_token(&Token::Comma) {
1444                                // Check for trailing comma before RParen
1445                                if matches!(self.current_token().token, Token::RParen) {
1446                                    break;
1447                                }
1448                                // Otherwise continue parsing
1449                            } else {
1450                                break;
1451                            }
1452                        }
1453                    }
1454
1455                    self.expect_token(Token::RParen)?;
1456                    Ok(Expr::Tuple(elements))
1457                } else {
1458                    // Just grouped expression: (e)
1459                    self.expect_token(Token::RParen)?;
1460                    Ok(first_expr)
1461                }
1462            }
1463            Token::LBracket => self.parse_list(),
1464            Token::LBracketPipe => self.parse_array(),
1465            Token::LBracePipe => self.parse_anonymous_record_literal(),
1466            Token::LBrace => self.parse_record_literal(),
1467            Token::Async => self.parse_computation_expr(),
1468            _ => {
1469                let tok = self.current_token();
1470                Err(ParseError::UnexpectedToken {
1471                    expected: "expression".to_string(),
1472                    found: tok.token.clone(),
1473                    pos: tok.pos,
1474                })
1475            }
1476        }
1477    }
1478
1479    /// Parse list: [1, 2, 3] or [1; 2; 3] or []
1480    ///
1481    /// Supports both comma and semicolon separators for backward compatibility.
1482    /// Trailing separators are allowed: [1, 2, 3,] or [1; 2; 3;]
1483    fn parse_list(&mut self) -> Result<Expr> {
1484        self.expect_token(Token::LBracket)?;
1485
1486        // Empty list: []
1487        if self.match_token(&Token::RBracket) {
1488            return Ok(Expr::List(vec![]));
1489        }
1490
1491        // Parse list elements
1492        let mut elements = vec![];
1493
1494        loop {
1495            elements.push(self.parse_expr()?);
1496
1497            // Check for comma or semicolon separator
1498            if self.match_token(&Token::Comma) || self.match_token(&Token::Semicolon) {
1499                // Check for trailing separator before ]
1500                if matches!(self.current_token().token, Token::RBracket) {
1501                    break;
1502                }
1503                // Otherwise continue parsing
1504            } else {
1505                break;
1506            }
1507        }
1508
1509        self.expect_token(Token::RBracket)?;
1510
1511        Ok(Expr::List(elements))
1512    }
1513
1514    /// Parse array: [|1; 2; 3|] or [||]
1515    fn parse_array(&mut self) -> Result<Expr> {
1516        self.expect_token(Token::LBracketPipe)?;
1517
1518        // Empty array: [||]
1519        if self.match_token(&Token::PipeRBracket) {
1520            return Ok(Expr::Array(vec![]));
1521        }
1522
1523        // Parse array elements
1524        let mut elements = vec![];
1525
1526        loop {
1527            elements.push(self.parse_expr()?);
1528
1529            // Check for semicolon separator
1530            if self.match_token(&Token::Semicolon) {
1531                // Check for trailing semicolon before |]
1532                if matches!(self.current_token().token, Token::PipeRBracket) {
1533                    break;
1534                }
1535                // Otherwise continue parsing
1536            } else {
1537                break;
1538            }
1539        }
1540
1541        self.expect_token(Token::PipeRBracket)?;
1542
1543        Ok(Expr::Array(elements))
1544    }
1545
1546    /// Parse DU type definition: type Option = Some of int | None
1547    pub fn parse_du_type_def(&mut self) -> Result<DuTypeDef> {
1548        self.expect_token(Token::Type)?;
1549
1550        let type_name = self.expect_ident()?;
1551
1552        self.expect_token(Token::Eq)?;
1553
1554        // Parse variants
1555        let mut variants = vec![];
1556
1557        // Optional leading pipe
1558        if self.match_token(&Token::Pipe) {
1559            // If we consumed a leading pipe, there must be a variant name following
1560            // This catches errors like "type T = | " or "type T = | |"
1561            let tok = self.current_token();
1562            if !matches!(&tok.token, Token::Ident(_)) {
1563                return Err(ParseError::UnexpectedToken {
1564                    expected: "variant name".to_string(),
1565                    found: tok.token.clone(),
1566                    pos: tok.pos,
1567                });
1568            }
1569        }
1570
1571        loop {
1572            let variant_name = self.expect_ident()?;
1573
1574            // Check for 'of' keyword (variant with fields)
1575            let fields = if self.match_token(&Token::Of) {
1576                let mut field_types = vec![];
1577
1578                loop {
1579                    let ty = self.parse_type_expr()?;
1580                    field_types.push(ty);
1581
1582                    // Check for * separator (for tuple-like fields)
1583                    if !self.match_token(&Token::Star) {
1584                        break;
1585                    }
1586                }
1587
1588                field_types
1589            } else {
1590                vec![]
1591            };
1592
1593            variants.push(VariantDef {
1594                name: variant_name,
1595                fields,
1596            });
1597
1598            // Check for another variant (starts with |)
1599            if !self.match_token(&Token::Pipe) {
1600                break;
1601            }
1602        }
1603
1604        Ok(DuTypeDef {
1605            name: type_name,
1606            variants,
1607        })
1608    }
1609
1610    /// Parse type expression for type annotations
1611    fn parse_type_expr(&mut self) -> Result<TypeExpr> {
1612        // Parse a simple type or function type
1613        // Note: tuple types (int * int) are handled by the caller (parse_du_type_def)
1614        // because the * separator is used differently in DU definitions
1615        let left = self.parse_simple_type()?;
1616
1617        // Check for function type: int -> string
1618        if self.match_token(&Token::Arrow) {
1619            let right = self.parse_type_expr()?; // Right-associative
1620            return Ok(TypeExpr::Function(Box::new(left), Box::new(right)));
1621        }
1622
1623        Ok(left)
1624    }
1625
1626    /// Parse simple type (identifier)
1627    fn parse_simple_type(&mut self) -> Result<TypeExpr> {
1628        let name = self.expect_ident()?;
1629        Ok(TypeExpr::Named(name))
1630    }
1631
1632    // ========================================================================
1633    // Computation Expression Parsing
1634    // ========================================================================
1635
1636    /// Parse computation expression: async { statements... }
1637    ///
1638    /// A computation expression is of the form:
1639    ///   async { let! x = expr; do! expr; return expr }
1640    ///
1641    /// Future: could support other builders like "seq", "option", "result"
1642    fn parse_computation_expr(&mut self) -> Result<Expr> {
1643        // Get builder name from current token
1644        let builder = match &self.current_token().token {
1645            Token::Async => {
1646                self.advance(); // consume 'async'
1647                "async".to_string()
1648            }
1649            _ => {
1650                let tok = self.current_token();
1651                return Err(ParseError::UnexpectedToken {
1652                    expected: "computation expression keyword".to_string(),
1653                    found: tok.token.clone(),
1654                    pos: tok.pos,
1655                });
1656            }
1657        };
1658
1659        // Expect '{'
1660        self.expect_token(Token::LBrace)?;
1661
1662        // Parse CE statements
1663        let mut body = Vec::new();
1664        while !self.check(&Token::RBrace) && !self.is_at_end() {
1665            body.push(self.parse_ce_statement()?);
1666            // Optional semicolons between statements
1667            self.match_token(&Token::Semicolon);
1668        }
1669
1670        // Expect '}'
1671        self.expect_token(Token::RBrace)?;
1672
1673        Ok(Expr::ComputationExpr { builder, body })
1674    }
1675
1676    /// Parse a single CE statement
1677    ///
1678    /// CE statements include:
1679    /// - let! x = expr    (bind operation)
1680    /// - let x = expr     (regular binding)
1681    /// - do! expr         (bind with unit result)
1682    /// - return expr      (return value)
1683    /// - return! expr     (return from another CE)
1684    /// - yield expr       (yield value for sequence)
1685    /// - yield! expr      (yield from another sequence)
1686    /// - expr             (plain expression)
1687    fn parse_ce_statement(&mut self) -> Result<CEStatement> {
1688        let tok = &self.current_token().token;
1689
1690        match tok {
1691            Token::LetBang => {
1692                self.advance(); // consume let!
1693                let name = if self.match_token(&Token::Underscore) {
1694                    "_".to_string()
1695                } else {
1696                    self.expect_ident()?
1697                };
1698                self.expect_token(Token::Eq)?;
1699                let value = Box::new(self.parse_expr()?);
1700                Ok(CEStatement::LetBang { name, value })
1701            }
1702            Token::Let => {
1703                self.advance(); // consume let
1704                let name = if self.match_token(&Token::Underscore) {
1705                    "_".to_string()
1706                } else {
1707                    self.expect_ident()?
1708                };
1709                self.expect_token(Token::Eq)?;
1710                let value = Box::new(self.parse_expr()?);
1711                Ok(CEStatement::Let { name, value })
1712            }
1713            Token::DoBang => {
1714                self.advance(); // consume do!
1715                let value = Box::new(self.parse_expr()?);
1716                Ok(CEStatement::DoBang { value })
1717            }
1718            Token::Return => {
1719                self.advance(); // consume return
1720                let value = Box::new(self.parse_expr()?);
1721                Ok(CEStatement::Return { value })
1722            }
1723            Token::ReturnBang => {
1724                self.advance(); // consume return!
1725                let value = Box::new(self.parse_expr()?);
1726                Ok(CEStatement::ReturnBang { value })
1727            }
1728            Token::Yield => {
1729                self.advance(); // consume yield
1730                let value = Box::new(self.parse_expr()?);
1731                Ok(CEStatement::Yield { value })
1732            }
1733            Token::YieldBang => {
1734                self.advance(); // consume yield!
1735                let value = Box::new(self.parse_expr()?);
1736                Ok(CEStatement::YieldBang { value })
1737            }
1738            _ => {
1739                // Plain expression
1740                let value = Box::new(self.parse_expr()?);
1741                Ok(CEStatement::Expr { value })
1742            }
1743        }
1744    }
1745
1746    // ========================================================================
1747    // Helper Methods
1748    // ========================================================================
1749
1750    /// Get the current token (or EOF if at end)
1751    fn current_token(&self) -> &TokenWithPos {
1752        if self.is_at_end() {
1753            // Return a special EOF token
1754            static EOF_TOKEN: std::sync::OnceLock<TokenWithPos> = std::sync::OnceLock::new();
1755            EOF_TOKEN.get_or_init(|| TokenWithPos {
1756                token: Token::Eof,
1757                pos: Position::new(0, 0, 0),
1758            })
1759        } else {
1760            &self.tokens[self.pos]
1761        }
1762    }
1763
1764    /// Peek at the current token without consuming it
1765    fn peek(&self) -> Option<&Token> {
1766        if self.is_at_end() {
1767            None
1768        } else {
1769            Some(&self.tokens[self.pos].token)
1770        }
1771    }
1772
1773    /// Check if current token matches without consuming
1774    fn check(&self, token: &Token) -> bool {
1775        !self.is_at_end() && &self.tokens[self.pos].token == token
1776    }
1777
1778    /// Advance to next token
1779    fn advance(&mut self) {
1780        if !self.is_at_end() {
1781            self.pos += 1;
1782        }
1783    }
1784
1785    /// Check if we're at EOF
1786    fn is_at_end(&self) -> bool {
1787        self.pos >= self.tokens.len() || matches!(self.tokens[self.pos].token, Token::Eof)
1788    }
1789
1790    /// Match and consume token if it matches
1791    fn match_token(&mut self, token: &Token) -> bool {
1792        if self.check(token) {
1793            self.advance();
1794            true
1795        } else {
1796            false
1797        }
1798    }
1799
1800    /// Expect a specific token and consume it
1801    fn expect_token(&mut self, expected: Token) -> Result<()> {
1802        if self.check(&expected) {
1803            self.advance();
1804            Ok(())
1805        } else {
1806            let tok = self.current_token();
1807            Err(ParseError::UnexpectedToken {
1808                expected: format!("{}", expected),
1809                found: tok.token.clone(),
1810                pos: tok.pos,
1811            })
1812        }
1813    }
1814
1815    /// Expect an identifier and return it
1816    fn expect_ident(&mut self) -> Result<String> {
1817        let tok = self.current_token();
1818        match &tok.token {
1819            Token::Ident(name) => {
1820                let val = name.clone();
1821                self.advance();
1822                Ok(val)
1823            }
1824            _ => Err(ParseError::UnexpectedToken {
1825                expected: "identifier".to_string(),
1826                found: tok.token.clone(),
1827                pos: tok.pos,
1828            }),
1829        }
1830    }
1831
1832    /// Check if current token could start a primary expression
1833    fn is_primary_start(&self) -> bool {
1834        if self.is_at_end() {
1835            return false;
1836        }
1837
1838        matches!(
1839            &self.current_token().token,
1840            Token::Int(_)
1841                | Token::Float(_)
1842                | Token::Bool(_)
1843                | Token::String(_)
1844                | Token::Ident(_)
1845                | Token::LParen
1846                | Token::LBracket
1847                | Token::LBracketPipe
1848                | Token::LBrace
1849        )
1850    }
1851
1852    /// Try to match comparison operator
1853    fn match_comparison_op(&mut self) -> Option<BinOp> {
1854        let tok = &self.current_token().token;
1855        let op = match tok {
1856            Token::Eq => Some(BinOp::Eq),
1857            Token::EqEq => Some(BinOp::Eq),
1858            Token::Neq => Some(BinOp::Neq),
1859            Token::Lt => Some(BinOp::Lt),
1860            Token::Lte => Some(BinOp::Lte),
1861            Token::Gt => Some(BinOp::Gt),
1862            Token::Gte => Some(BinOp::Gte),
1863            _ => None,
1864        };
1865
1866        if op.is_some() {
1867            self.advance();
1868        }
1869
1870        op
1871    }
1872
1873    /// Try to match addition operator
1874    fn match_add_op(&mut self) -> Option<BinOp> {
1875        let tok = &self.current_token().token;
1876        let op = match tok {
1877            Token::Plus => Some(BinOp::Add),
1878            Token::Minus => Some(BinOp::Sub),
1879            Token::PlusPlus => Some(BinOp::Concat),
1880            _ => None,
1881        };
1882
1883        if op.is_some() {
1884            self.advance();
1885        }
1886
1887        op
1888    }
1889
1890    /// Try to match multiplication operator
1891    fn match_mul_op(&mut self) -> Option<BinOp> {
1892        let tok = &self.current_token().token;
1893        let op = match tok {
1894            Token::Star => Some(BinOp::Mul),
1895            Token::Slash => Some(BinOp::Div),
1896            _ => None,
1897        };
1898
1899        if op.is_some() {
1900            self.advance();
1901        }
1902
1903        op
1904    }
1905}
1906
1907#[cfg(test)]
1908mod tests {
1909    use super::*;
1910    use crate::lexer::Lexer;
1911
1912    fn parse_str(input: &str) -> Result<Expr> {
1913        let mut lexer = Lexer::new(input);
1914        let tokens = lexer.tokenize().unwrap();
1915        let mut parser = Parser::new(tokens);
1916        parser.parse()
1917    }
1918
1919    #[test]
1920    fn test_parse_int() {
1921        let expr = parse_str("42").unwrap();
1922        assert!(matches!(expr, Expr::Lit(Literal::Int(42))));
1923    }
1924
1925    #[test]
1926    fn test_parse_let() {
1927        let expr = parse_str("let x = 42 in x").unwrap();
1928        assert!(expr.is_let());
1929    }
1930
1931    #[test]
1932    fn test_parse_application() {
1933        let expr = parse_str("f x").unwrap();
1934        assert!(expr.is_app());
1935    }
1936
1937    #[test]
1938    fn test_parse_lambda() {
1939        let expr = parse_str("fun x -> x").unwrap();
1940        assert!(expr.is_lambda());
1941    }
1942
1943    #[test]
1944    fn test_parse_string_concat() {
1945        let expr = parse_str(r#""hello" ++ "world""#).unwrap();
1946        match expr {
1947            Expr::BinOp { op, left, right } => {
1948                assert_eq!(op, BinOp::Concat);
1949                assert!(matches!(*left, Expr::Lit(Literal::Str(_))));
1950                assert!(matches!(*right, Expr::Lit(Literal::Str(_))));
1951            }
1952            _ => panic!("Expected BinOp with Concat"),
1953        }
1954    }
1955
1956    #[test]
1957    fn test_parse_string_concat_chain() {
1958        let expr = parse_str(r#""a" ++ "b" ++ "c""#).unwrap();
1959        // Should parse as left-associative: ("a" ++ "b") ++ "c"
1960        match expr {
1961            Expr::BinOp { op, left, right: _ } => {
1962                assert_eq!(op, BinOp::Concat);
1963                match *left {
1964                    Expr::BinOp { op, .. } => {
1965                        assert_eq!(op, BinOp::Concat);
1966                    }
1967                    _ => panic!("Expected nested BinOp"),
1968                }
1969            }
1970            _ => panic!("Expected BinOp"),
1971        }
1972    }
1973
1974    #[test]
1975    fn test_parse_concat_precedence() {
1976        // ++ should have same precedence as +, so this should parse correctly
1977        let expr = parse_str(r#""http://" ++ host ++ ":" ++ port"#).unwrap();
1978        match expr {
1979            Expr::BinOp { op, .. } => {
1980                assert_eq!(op, BinOp::Concat);
1981            }
1982            _ => panic!("Expected BinOp"),
1983        }
1984    }
1985
1986    // ========================================================================
1987    // Computation Expression Tests
1988    // ========================================================================
1989
1990    #[test]
1991    fn test_parse_async_block_empty() {
1992        let mut lexer = Lexer::new("async { }");
1993        let tokens = lexer.tokenize().unwrap();
1994        let mut parser = Parser::new(tokens);
1995        let expr = parser.parse().unwrap();
1996
1997        assert!(expr.is_computation_expr());
1998        match expr {
1999            Expr::ComputationExpr { builder, body } => {
2000                assert_eq!(builder, "async");
2001                assert_eq!(body.len(), 0);
2002            }
2003            _ => panic!("Expected ComputationExpr"),
2004        }
2005    }
2006
2007    #[test]
2008    fn test_parse_async_block_return() {
2009        let mut lexer = Lexer::new("async { return 42 }");
2010        let tokens = lexer.tokenize().unwrap();
2011        let mut parser = Parser::new(tokens);
2012        let expr = parser.parse().unwrap();
2013
2014        assert!(expr.is_computation_expr());
2015        match expr {
2016            Expr::ComputationExpr { builder, body } => {
2017                assert_eq!(builder, "async");
2018                assert_eq!(body.len(), 1);
2019                match &body[0] {
2020                    CEStatement::Return { value } => {
2021                        assert!(matches!(**value, Expr::Lit(Literal::Int(42))));
2022                    }
2023                    _ => panic!("Expected Return statement"),
2024                }
2025            }
2026            _ => panic!("Expected ComputationExpr"),
2027        }
2028    }
2029
2030    #[test]
2031    fn test_parse_let_bang() {
2032        let mut lexer = Lexer::new("async { let! x = op; return x }");
2033        let tokens = lexer.tokenize().unwrap();
2034        let mut parser = Parser::new(tokens);
2035        let expr = parser.parse().unwrap();
2036
2037        assert!(expr.is_computation_expr());
2038        match expr {
2039            Expr::ComputationExpr { builder, body } => {
2040                assert_eq!(builder, "async");
2041                assert_eq!(body.len(), 2);
2042
2043                // First statement: let! x = op
2044                match &body[0] {
2045                    CEStatement::LetBang { name, value } => {
2046                        assert_eq!(name, "x");
2047                        assert!(matches!(**value, Expr::Var(_)));
2048                    }
2049                    _ => panic!("Expected LetBang statement"),
2050                }
2051
2052                // Second statement: return x
2053                match &body[1] {
2054                    CEStatement::Return { value } => {
2055                        assert!(matches!(**value, Expr::Var(_)));
2056                    }
2057                    _ => panic!("Expected Return statement"),
2058                }
2059            }
2060            _ => panic!("Expected ComputationExpr"),
2061        }
2062    }
2063
2064    #[test]
2065    fn test_parse_do_bang() {
2066        let mut lexer = Lexer::new("async { do! print 42 }");
2067        let tokens = lexer.tokenize().unwrap();
2068        let mut parser = Parser::new(tokens);
2069        let expr = parser.parse().unwrap();
2070
2071        match expr {
2072            Expr::ComputationExpr { builder, body } => {
2073                assert_eq!(builder, "async");
2074                assert_eq!(body.len(), 1);
2075                match &body[0] {
2076                    CEStatement::DoBang { value } => {
2077                        assert!(matches!(**value, Expr::App { .. }));
2078                    }
2079                    _ => panic!("Expected DoBang statement"),
2080                }
2081            }
2082            _ => panic!("Expected ComputationExpr"),
2083        }
2084    }
2085
2086    #[test]
2087    fn test_parse_regular_let_in_ce() {
2088        let mut lexer = Lexer::new("async { let x = 42; return x }");
2089        let tokens = lexer.tokenize().unwrap();
2090        let mut parser = Parser::new(tokens);
2091        let expr = parser.parse().unwrap();
2092
2093        match expr {
2094            Expr::ComputationExpr { builder, body } => {
2095                assert_eq!(builder, "async");
2096                assert_eq!(body.len(), 2);
2097
2098                // First statement: let x = 42
2099                match &body[0] {
2100                    CEStatement::Let { name, value } => {
2101                        assert_eq!(name, "x");
2102                        assert!(matches!(**value, Expr::Lit(Literal::Int(42))));
2103                    }
2104                    _ => panic!("Expected Let statement"),
2105                }
2106            }
2107            _ => panic!("Expected ComputationExpr"),
2108        }
2109    }
2110
2111    #[test]
2112    fn test_parse_return_bang() {
2113        let mut lexer = Lexer::new("async { return! other }");
2114        let tokens = lexer.tokenize().unwrap();
2115        let mut parser = Parser::new(tokens);
2116        let expr = parser.parse().unwrap();
2117
2118        match expr {
2119            Expr::ComputationExpr { builder, body } => {
2120                assert_eq!(builder, "async");
2121                assert_eq!(body.len(), 1);
2122                match &body[0] {
2123                    CEStatement::ReturnBang { value } => {
2124                        assert!(matches!(**value, Expr::Var(_)));
2125                    }
2126                    _ => panic!("Expected ReturnBang statement"),
2127                }
2128            }
2129            _ => panic!("Expected ComputationExpr"),
2130        }
2131    }
2132
2133    #[test]
2134    fn test_parse_yield() {
2135        let mut lexer = Lexer::new("async { yield 1; yield 2 }");
2136        let tokens = lexer.tokenize().unwrap();
2137        let mut parser = Parser::new(tokens);
2138        let expr = parser.parse().unwrap();
2139
2140        match expr {
2141            Expr::ComputationExpr { builder, body } => {
2142                assert_eq!(builder, "async");
2143                assert_eq!(body.len(), 2);
2144                match &body[0] {
2145                    CEStatement::Yield { value } => {
2146                        assert!(matches!(**value, Expr::Lit(Literal::Int(1))));
2147                    }
2148                    _ => panic!("Expected Yield statement"),
2149                }
2150            }
2151            _ => panic!("Expected ComputationExpr"),
2152        }
2153    }
2154
2155    #[test]
2156    fn test_parse_yield_bang() {
2157        let mut lexer = Lexer::new("async { yield! sequence }");
2158        let tokens = lexer.tokenize().unwrap();
2159        let mut parser = Parser::new(tokens);
2160        let expr = parser.parse().unwrap();
2161
2162        match expr {
2163            Expr::ComputationExpr { builder, body } => {
2164                assert_eq!(builder, "async");
2165                assert_eq!(body.len(), 1);
2166                match &body[0] {
2167                    CEStatement::YieldBang { value } => {
2168                        assert!(matches!(**value, Expr::Var(_)));
2169                    }
2170                    _ => panic!("Expected YieldBang statement"),
2171                }
2172            }
2173            _ => panic!("Expected ComputationExpr"),
2174        }
2175    }
2176
2177    #[test]
2178    fn test_parse_plain_expr_in_ce() {
2179        let mut lexer = Lexer::new("async { 1 + 2 }");
2180        let tokens = lexer.tokenize().unwrap();
2181        let mut parser = Parser::new(tokens);
2182        let expr = parser.parse().unwrap();
2183
2184        match expr {
2185            Expr::ComputationExpr { builder, body } => {
2186                assert_eq!(builder, "async");
2187                assert_eq!(body.len(), 1);
2188                match &body[0] {
2189                    CEStatement::Expr { value } => {
2190                        assert!(matches!(**value, Expr::BinOp { .. }));
2191                    }
2192                    _ => panic!("Expected Expr statement"),
2193                }
2194            }
2195            _ => panic!("Expected ComputationExpr"),
2196        }
2197    }
2198
2199    #[test]
2200    fn test_parse_complex_async_block() {
2201        let input = r#"
2202            async {
2203                let! x = fetchData;
2204                let y = x + 1;
2205                do! printValue y;
2206                return y
2207            }
2208        "#;
2209        let mut lexer = Lexer::new(input);
2210        let tokens = lexer.tokenize().unwrap();
2211        let mut parser = Parser::new(tokens);
2212        let expr = parser.parse().unwrap();
2213
2214        match expr {
2215            Expr::ComputationExpr { builder, body } => {
2216                assert_eq!(builder, "async");
2217                assert_eq!(body.len(), 4);
2218
2219                // Verify statement types
2220                assert!(matches!(body[0], CEStatement::LetBang { .. }));
2221                assert!(matches!(body[1], CEStatement::Let { .. }));
2222                assert!(matches!(body[2], CEStatement::DoBang { .. }));
2223                assert!(matches!(body[3], CEStatement::Return { .. }));
2224            }
2225            _ => panic!("Expected ComputationExpr"),
2226        }
2227    }
2228
2229    #[test]
2230    fn test_parse_nested_async_blocks() {
2231        let input = "async { let! x = async { return 42 }; return x }";
2232        let mut lexer = Lexer::new(input);
2233        let tokens = lexer.tokenize().unwrap();
2234        let mut parser = Parser::new(tokens);
2235        let expr = parser.parse().unwrap();
2236
2237        match expr {
2238            Expr::ComputationExpr { builder, body } => {
2239                assert_eq!(builder, "async");
2240                assert_eq!(body.len(), 2);
2241
2242                // First statement should have nested CE
2243                match &body[0] {
2244                    CEStatement::LetBang { value, .. } => {
2245                        assert!(matches!(**value, Expr::ComputationExpr { .. }));
2246                    }
2247                    _ => panic!("Expected LetBang"),
2248                }
2249            }
2250            _ => panic!("Expected ComputationExpr"),
2251        }
2252    }
2253
2254    #[test]
2255    fn test_parse_async_with_optional_semicolons() {
2256        // Test that semicolons are optional between statements
2257        let input = "async { let x = 1 let y = 2 return x }";
2258        let mut lexer = Lexer::new(input);
2259        let tokens = lexer.tokenize().unwrap();
2260        let mut parser = Parser::new(tokens);
2261        let expr = parser.parse().unwrap();
2262
2263        match expr {
2264            Expr::ComputationExpr { builder, body } => {
2265                assert_eq!(builder, "async");
2266                assert_eq!(body.len(), 3);
2267            }
2268            _ => panic!("Expected ComputationExpr"),
2269        }
2270    }
2271
2272    #[test]
2273    fn test_parse_async_with_trailing_semicolon() {
2274        let input = "async { return 42; }";
2275        let mut lexer = Lexer::new(input);
2276        let tokens = lexer.tokenize().unwrap();
2277        let mut parser = Parser::new(tokens);
2278        let expr = parser.parse().unwrap();
2279
2280        match expr {
2281            Expr::ComputationExpr { builder, body } => {
2282                assert_eq!(builder, "async");
2283                assert_eq!(body.len(), 1);
2284            }
2285            _ => panic!("Expected ComputationExpr"),
2286        }
2287    }
2288
2289    #[test]
2290    fn test_computation_expr_helpers() {
2291        let expr = Expr::ComputationExpr {
2292            builder: "async".to_string(),
2293            body: vec![],
2294        };
2295
2296        assert!(expr.is_computation_expr());
2297        assert!(!expr.is_let());
2298        assert!(!expr.is_if());
2299
2300        let result = expr.as_computation_expr();
2301        assert!(result.is_some());
2302        let (builder, body) = result.unwrap();
2303        assert_eq!(builder, "async");
2304        assert_eq!(body.len(), 0);
2305    }
2306}