fusabi_frontend/
ast.rs

1//! Core AST (Abstract Syntax Tree) definitions for Fusabi Mini-F#.
2//!
3//! This module defines the foundational types for representing F# expressions
4//! in the Fusabi compiler frontend. The AST serves as the intermediate representation
5//! between parsing and bytecode compilation.
6//!
7//! # Phase 1 MVP Features
8//!
9//! The AST supports:
10//! - Literals: integers, floats, booleans, strings, unit
11//! - Variables and let-bindings
12//! - Lambda functions and function application
13//! - Binary operations (arithmetic, comparison, logical)
14//! - Conditional expressions (if-then-else)
15//! - Tuples (e.g., (1, 2), (x, y, z))
16//! - Lists (e.g., [1; 2; 3], []) and cons operator (::)
17//! - Arrays (e.g., [|1; 2; 3|], arr.\[0\], arr.\[0\] <- 99)
18//! - Records (e.g., type Person = { name: string; age: int })
19//!
20//! # Example
21//!
22//! ```rust
23//! use fusabi_frontend::ast::{Expr, Literal, BinOp};
24//!
25//! // Construct: let x = 42 in x + 1
26//! let expr = Expr::Let {
27//!     name: "x".to_string(),
28//!     value: Box::new(Expr::Lit(Literal::Int(42))),
29//!     body: Box::new(Expr::BinOp {
30//!         op: BinOp::Add,
31//!         left: Box::new(Expr::Var("x".to_string())),
32//!         right: Box::new(Expr::Lit(Literal::Int(1))),
33//!     }),
34//! };
35//! ```
36
37use std::fmt;
38
39/// Literal values in the AST.
40///
41/// Represents constant values that can appear in expressions.
42#[derive(Debug, Clone, PartialEq)]
43pub enum Literal {
44    /// Integer literal (e.g., 42, -10)
45    Int(i64),
46    /// Floating-point literal (e.g., 2.5, -0.5)
47    Float(f64),
48    /// Boolean literal (true or false)
49    Bool(bool),
50    /// String literal (e.g., "hello")
51    Str(String),
52    /// Unit value (equivalent to () in F#)
53    Unit,
54}
55
56impl fmt::Display for Literal {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        match self {
59            Literal::Int(n) => write!(f, "{}", n),
60            Literal::Float(n) => write!(f, "{}", n),
61            Literal::Bool(b) => write!(f, "{}", b),
62            Literal::Str(s) => write!(f, "\"{}\"", s),
63            Literal::Unit => write!(f, "()"),
64        }
65    }
66}
67
68/// Binary operators supported in expressions.
69///
70/// Includes arithmetic, comparison, and logical operators.
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub enum BinOp {
73    // Arithmetic operators
74    /// Addition (+)
75    Add,
76    /// Subtraction (-)
77    Sub,
78    /// Multiplication (*)
79    Mul,
80    /// Division (/)
81    Div,
82    /// String concatenation (++)
83    Concat,
84
85    // Comparison operators
86    /// Equality (=)
87    Eq,
88    /// Inequality (<>)
89    Neq,
90    /// Less than (<)
91    Lt,
92    /// Less than or equal (<=)
93    Lte,
94    /// Greater than (>)
95    Gt,
96    /// Greater than or equal (>=)
97    Gte,
98
99    // Logical operators
100    /// Logical AND (&&)
101    And,
102    /// Logical OR (||)
103    Or,
104}
105
106impl fmt::Display for BinOp {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        let s = match self {
109            BinOp::Add => "+",
110            BinOp::Sub => "-",
111            BinOp::Mul => "*",
112            BinOp::Div => "/",
113            BinOp::Concat => "++",
114            BinOp::Eq => "=",
115            BinOp::Neq => "<>",
116            BinOp::Lt => "<",
117            BinOp::Lte => "<=",
118            BinOp::Gt => ">",
119            BinOp::Gte => ">=",
120            BinOp::And => "&&",
121            BinOp::Or => "||",
122        };
123        write!(f, "{}", s)
124    }
125}
126
127impl BinOp {
128    /// Returns true if this is an arithmetic operator.
129    pub fn is_arithmetic(&self) -> bool {
130        matches!(self, BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div)
131    }
132
133    /// Returns true if this is a comparison operator.
134    pub fn is_comparison(&self) -> bool {
135        matches!(
136            self,
137            BinOp::Eq | BinOp::Neq | BinOp::Lt | BinOp::Lte | BinOp::Gt | BinOp::Gte
138        )
139    }
140
141    /// Returns true if this is a logical operator.
142    pub fn is_logical(&self) -> bool {
143        matches!(self, BinOp::And | BinOp::Or)
144    }
145}
146
147/// Type expressions for record field type annotations.
148///
149/// Represents types that can appear in record definitions.
150#[derive(Debug, Clone, PartialEq, Eq)]
151pub enum TypeExpr {
152    /// Named type (e.g., int, bool, string, UserType)
153    Named(String),
154    /// Tuple type (e.g., int * string)
155    Tuple(Vec<TypeExpr>),
156    /// Function type (e.g., int -> string)
157    Function(Box<TypeExpr>, Box<TypeExpr>),
158}
159
160impl fmt::Display for TypeExpr {
161    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162        match self {
163            TypeExpr::Named(name) => write!(f, "{}", name),
164            TypeExpr::Tuple(types) => {
165                for (i, ty) in types.iter().enumerate() {
166                    if i > 0 {
167                        write!(f, " * ")?;
168                    }
169                    write!(f, "{}", ty)?;
170                }
171                Ok(())
172            }
173            TypeExpr::Function(arg, ret) => write!(f, "{} -> {}", arg, ret),
174        }
175    }
176}
177
178/// Record type definition.
179///
180/// Represents a user-defined record type with named fields.
181/// Example: type Person = { name: string; age: int }
182#[derive(Debug, Clone, PartialEq)]
183pub struct RecordTypeDef {
184    /// Name of the record type
185    pub name: String,
186    /// Field definitions: (field_name, field_type)
187    pub fields: Vec<(String, TypeExpr)>,
188}
189
190impl fmt::Display for RecordTypeDef {
191    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192        write!(f, "type {} = {{ ", self.name)?;
193        for (i, (field_name, field_type)) in self.fields.iter().enumerate() {
194            if i > 0 {
195                write!(f, "; ")?;
196            }
197            write!(f, "{}: {}", field_name, field_type)?;
198        }
199        write!(f, " }}")
200    }
201}
202
203/// Variant definition in a discriminated union.
204///
205/// Represents a single case/variant in a DU.
206/// Example: Circle of float | Rectangle of float * float
207#[derive(Debug, Clone, PartialEq)]
208pub struct VariantDef {
209    /// Name of the variant (e.g., "Some", "None", "Circle")
210    pub name: String,
211    /// Field types for this variant (empty for simple enums)
212    pub fields: Vec<TypeExpr>,
213}
214
215impl fmt::Display for VariantDef {
216    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217        write!(f, "{}", self.name)?;
218        if !self.fields.is_empty() {
219            write!(f, " of ")?;
220            for (i, field) in self.fields.iter().enumerate() {
221                if i > 0 {
222                    write!(f, " * ")?;
223                }
224                write!(f, "{}", field)?;
225            }
226        }
227        Ok(())
228    }
229}
230
231impl VariantDef {
232    /// Create a new variant with no fields
233    pub fn new_simple(name: String) -> Self {
234        VariantDef {
235            name,
236            fields: vec![],
237        }
238    }
239
240    /// Create a new variant with fields
241    pub fn new(name: String, fields: Vec<TypeExpr>) -> Self {
242        VariantDef { name, fields }
243    }
244
245    /// Returns true if this variant has no fields (simple enum case)
246    pub fn is_simple(&self) -> bool {
247        self.fields.is_empty()
248    }
249
250    /// Returns the number of fields
251    pub fn field_count(&self) -> usize {
252        self.fields.len()
253    }
254}
255
256/// Discriminated union type definition.
257///
258/// Represents a discriminated union (algebraic data type).
259/// Example: type Option = Some of int | None
260#[derive(Debug, Clone, PartialEq)]
261pub struct DuTypeDef {
262    /// Name of the DU type
263    pub name: String,
264    /// Variants/cases of this DU
265    pub variants: Vec<VariantDef>,
266}
267
268impl fmt::Display for DuTypeDef {
269    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270        write!(f, "type {} = ", self.name)?;
271        for (i, variant) in self.variants.iter().enumerate() {
272            if i > 0 {
273                write!(f, " | ")?;
274            }
275            write!(f, "{}", variant)?;
276        }
277        Ok(())
278    }
279}
280
281impl DuTypeDef {
282    /// Get all variant names
283    pub fn variant_names(&self) -> Vec<&str> {
284        self.variants.iter().map(|v| v.name.as_str()).collect()
285    }
286
287    /// Find a variant by name
288    pub fn find_variant(&self, name: &str) -> Option<&VariantDef> {
289        self.variants.iter().find(|v| v.name == name)
290    }
291
292    /// Returns true if this is a simple enumeration (all variants have no fields)
293    pub fn is_simple_enum(&self) -> bool {
294        self.variants.iter().all(|v| v.is_simple())
295    }
296
297    /// Returns the number of variants
298    pub fn variant_count(&self) -> usize {
299        self.variants.len()
300    }
301}
302
303/// Type definition variants (Records or Discriminated Unions).
304#[derive(Debug, Clone, PartialEq)]
305pub enum TypeDefinition {
306    /// Record type definition
307    Record(RecordTypeDef),
308    /// Discriminated union type definition
309    Du(DuTypeDef),
310}
311
312impl fmt::Display for TypeDefinition {
313    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
314        match self {
315            TypeDefinition::Record(r) => write!(f, "{}", r),
316            TypeDefinition::Du(du) => write!(f, "{}", du),
317        }
318    }
319}
320
321/// Top-level declaration in a module.
322///
323/// Represents declarations that can appear at the top level of a module.
324#[derive(Debug, Clone, PartialEq)]
325pub enum Declaration {
326    /// Type definition (record or discriminated union)
327    TypeDef(TypeDefinition),
328    /// Let-binding declaration
329    LetBinding {
330        name: String,
331        params: Vec<String>,
332        body: Box<Expr>,
333    },
334}
335
336impl fmt::Display for Declaration {
337    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
338        match self {
339            Declaration::TypeDef(typedef) => write!(f, "{}", typedef),
340            Declaration::LetBinding { name, params, body } => {
341                write!(f, "let {}", name)?;
342                for param in params {
343                    write!(f, " {}", param)?;
344                }
345                write!(f, " = {}", body)
346            }
347        }
348    }
349}
350
351/// Module containing declarations.
352///
353/// Represents a complete module with type definitions and let-bindings.
354#[derive(Debug, Clone, PartialEq)]
355pub struct Module {
356    /// List of declarations in the module
357    pub declarations: Vec<Declaration>,
358}
359
360impl fmt::Display for Module {
361    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362        for (i, decl) in self.declarations.iter().enumerate() {
363            if i > 0 {
364                writeln!(f)?;
365            }
366            write!(f, "{}", decl)?;
367        }
368        Ok(())
369    }
370}
371
372/// Pattern in a match expression.
373///
374/// Patterns can match literals, variables, wildcards, tuples, and DU variants.
375/// Issue #27 supports basic patterns; Issue #28 will add lists/arrays.
376#[derive(Debug, Clone, PartialEq)]
377pub enum Pattern {
378    /// Wildcard pattern (_) - matches anything
379    Wildcard,
380    /// Variable pattern (x) - binds matched value to variable
381    Var(String),
382    /// Literal pattern (42, true, "hello") - matches exact value
383    Literal(Literal),
384    /// Tuple pattern ((p1, p2, ...)) - matches tuples
385    Tuple(Vec<Pattern>),
386    /// Variant pattern (Some(x), Left, Circle(r)) - matches DU constructors
387    Variant {
388        /// Variant constructor name (e.g., "Some", "None", "Circle")
389        variant: String,
390        /// Nested patterns for variant fields (empty for simple variants)
391        patterns: Vec<Pattern>,
392    },
393}
394
395impl fmt::Display for Pattern {
396    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
397        match self {
398            Pattern::Wildcard => write!(f, "_"),
399            Pattern::Var(name) => write!(f, "{}", name),
400            Pattern::Literal(lit) => write!(f, "{}", lit),
401            Pattern::Tuple(patterns) => {
402                write!(f, "(")?;
403                for (i, pat) in patterns.iter().enumerate() {
404                    if i > 0 {
405                        write!(f, ", ")?;
406                    }
407                    write!(f, "{}", pat)?;
408                }
409                write!(f, ")")
410            }
411            Pattern::Variant { variant, patterns } => {
412                write!(f, "{}", variant)?;
413                if !patterns.is_empty() {
414                    write!(f, "(")?;
415                    for (i, pat) in patterns.iter().enumerate() {
416                        if i > 0 {
417                            write!(f, ", ")?;
418                        }
419                        write!(f, "{}", pat)?;
420                    }
421                    write!(f, ")")?;
422                }
423                Ok(())
424            }
425        }
426    }
427}
428
429impl Pattern {
430    /// Returns true if this pattern is a wildcard.
431    pub fn is_wildcard(&self) -> bool {
432        matches!(self, Pattern::Wildcard)
433    }
434
435    /// Returns true if this pattern is a variable.
436    pub fn is_var(&self) -> bool {
437        matches!(self, Pattern::Var(_))
438    }
439
440    /// Returns true if this pattern is a literal.
441    pub fn is_literal(&self) -> bool {
442        matches!(self, Pattern::Literal(_))
443    }
444
445    /// Returns true if this pattern is a tuple.
446    pub fn is_tuple(&self) -> bool {
447        matches!(self, Pattern::Tuple(_))
448    }
449
450    /// Returns the variable name if this is a Var, otherwise None.
451    pub fn as_var(&self) -> Option<&str> {
452        match self {
453            Pattern::Var(name) => Some(name),
454            _ => None,
455        }
456    }
457
458    /// Returns the literal value if this is a Literal, otherwise None.
459    pub fn as_literal(&self) -> Option<&Literal> {
460        match self {
461            Pattern::Literal(lit) => Some(lit),
462            _ => None,
463        }
464    }
465
466    /// Returns the tuple patterns if this is a Tuple, otherwise None.
467    pub fn as_tuple(&self) -> Option<&Vec<Pattern>> {
468        match self {
469            Pattern::Tuple(patterns) => Some(patterns),
470            _ => None,
471        }
472    }
473
474    /// Returns true if this pattern is a variant.
475    pub fn is_variant(&self) -> bool {
476        matches!(self, Pattern::Variant { .. })
477    }
478
479    /// Returns the variant name and patterns if this is a Variant, otherwise None.
480    pub fn as_variant(&self) -> Option<(&str, &Vec<Pattern>)> {
481        match self {
482            Pattern::Variant { variant, patterns } => Some((variant, patterns)),
483            _ => None,
484        }
485    }
486}
487
488/// Match arm in a match expression.
489///
490/// Each arm consists of a pattern and the body expression to evaluate if the pattern matches.
491#[derive(Debug, Clone, PartialEq)]
492pub struct MatchArm {
493    /// The pattern to match against
494    pub pattern: Pattern,
495    /// The expression to evaluate if the pattern matches
496    pub body: Box<Expr>,
497}
498
499impl fmt::Display for MatchArm {
500    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
501        write!(f, "{} -> {}", self.pattern, self.body)
502    }
503}
504
505impl MatchArm {
506    /// Create a new match arm.
507    pub fn new(pattern: Pattern, body: Expr) -> Self {
508        MatchArm {
509            pattern,
510            body: Box::new(body),
511        }
512    }
513
514    /// Returns true if this arm's pattern is a wildcard.
515    pub fn is_wildcard(&self) -> bool {
516        self.pattern.is_wildcard()
517    }
518
519    /// Returns true if this arm's pattern is a variable binding.
520    pub fn is_var(&self) -> bool {
521        self.pattern.is_var()
522    }
523}
524
525/// Statement within a computation expression
526#[derive(Debug, Clone, PartialEq)]
527pub enum CEStatement {
528    /// let x = expr (regular binding)
529    Let { name: String, value: Box<Expr> },
530    /// let! x = expr (bind/await)
531    LetBang { name: String, value: Box<Expr> },
532    /// do! expr (bind with unit result)
533    DoBang { value: Box<Expr> },
534    /// return expr
535    Return { value: Box<Expr> },
536    /// return! expr
537    ReturnBang { value: Box<Expr> },
538    /// yield expr (for sequence builders)
539    Yield { value: Box<Expr> },
540    /// yield! expr
541    YieldBang { value: Box<Expr> },
542    /// Plain expression (last expression or side effects)
543    Expr { value: Box<Expr> },
544}
545
546impl fmt::Display for CEStatement {
547    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
548        match self {
549            CEStatement::Let { name, value } => write!(f, "let {} = {}", name, value),
550            CEStatement::LetBang { name, value } => write!(f, "let! {} = {}", name, value),
551            CEStatement::DoBang { value } => write!(f, "do! {}", value),
552            CEStatement::Return { value } => write!(f, "return {}", value),
553            CEStatement::ReturnBang { value } => write!(f, "return! {}", value),
554            CEStatement::Yield { value } => write!(f, "yield {}", value),
555            CEStatement::YieldBang { value } => write!(f, "yield! {}", value),
556            CEStatement::Expr { value } => write!(f, "{}", value),
557        }
558    }
559}
560
561/// Core expression types in the AST.
562///
563/// Represents all expression forms supported in Phase 1 of Fusabi.
564#[derive(Debug, Clone, PartialEq)]
565pub enum Expr {
566    /// Variable reference (e.g., x, foo)
567    Var(String),
568
569    /// Literal value
570    Lit(Literal),
571
572    /// Binary operation (e.g., x + 1, a && b)
573    BinOp {
574        op: BinOp,
575        left: Box<Expr>,
576        right: Box<Expr>,
577    },
578
579    /// Let-binding (e.g., let x = 5 in x + 1)
580    Let {
581        name: String,
582        value: Box<Expr>,
583        body: Box<Expr>,
584    },
585
586    /// Recursive let-binding (e.g., let rec fact n = if n <= 1 then 1 else n * fact (n - 1))
587    LetRec {
588        name: String,
589        value: Box<Expr>,
590        body: Box<Expr>,
591    },
592
593    /// Mutually recursive let-bindings (e.g., let rec even n = ... and odd n = ...)
594    LetRecMutual {
595        bindings: Vec<(String, Expr)>,
596        body: Box<Expr>,
597    },
598
599    /// Lambda function (e.g., fun x -> x + 1)
600    Lambda { param: String, body: Box<Expr> },
601
602    /// Function application (e.g., f x, add 1 2)
603    App { func: Box<Expr>, arg: Box<Expr> },
604
605    /// Conditional expression (e.g., if x > 0 then 1 else -1)
606    If {
607        cond: Box<Expr>,
608        then_branch: Box<Expr>,
609        else_branch: Box<Expr>,
610    },
611
612    /// Match expression (e.g., match x with | 0 -> "zero" | _ -> "nonzero")
613    Match {
614        scrutinee: Box<Expr>,
615        arms: Vec<MatchArm>,
616    },
617
618    /// Tuple expression (e.g., (1, 2), (x, y, z))
619    /// Empty tuple () is represented as Lit(Literal::Unit)
620    Tuple(Vec<Expr>),
621
622    /// List expression (e.g., [1; 2; 3], [])
623    List(Vec<Expr>),
624
625    /// Cons operator (e.g., 1 :: [2; 3], x :: xs)
626    Cons { head: Box<Expr>, tail: Box<Expr> },
627
628    /// Array literal (e.g., [|1; 2; 3|], [||])
629    Array(Vec<Expr>),
630
631    /// Array indexing (e.g., arr.\[0\], arr.\[i\])
632    ArrayIndex { array: Box<Expr>, index: Box<Expr> },
633
634    /// Array update (e.g., arr.\[0\] <- 99) - immutable, returns new array
635    ArrayUpdate {
636        array: Box<Expr>,
637        index: Box<Expr>,
638        value: Box<Expr>,
639    },
640
641    /// Array length (e.g., Array.length arr)
642    ArrayLength(Box<Expr>),
643
644    /// Record literal (e.g., { name = "John"; age = 30 })
645    RecordLiteral {
646        type_name: String,    // Filled by typechecker, empty during parsing
647        fields: RecordFields, // (field_name, value_expr)
648    },
649
650    /// Record field access (e.g., person.name, record.field)
651    RecordAccess { record: Box<Expr>, field: String },
652
653    /// Record update (e.g., { person with age = 31 })
654    RecordUpdate {
655        record: Box<Expr>,
656        fields: RecordFields, // Fields to update
657    },
658
659    /// Variant constructor (e.g., Some(42), Left, Circle(10.0))
660    VariantConstruct {
661        /// Type name (filled by typechecker, may be empty during parsing)
662        type_name: String,
663        /// Variant name (e.g., "Some", "None", "Circle")
664        variant: String,
665        /// Field values for this variant (empty for simple variants)
666        fields: Vec<Box<Expr>>,
667    },
668
669    /// Method call on an object (e.g., obj.method(arg1, arg2))
670    MethodCall {
671        /// Receiver expression (the object)
672        receiver: Box<Expr>,
673        /// Method name
674        method_name: String,
675        /// Method arguments
676        args: Vec<Expr>,
677    },
678
679    /// While loop (e.g., while x > 0 do x <- x - 1)
680    While {
681        /// Loop condition
682        cond: Box<Expr>,
683        /// Loop body
684        body: Box<Expr>,
685    },
686
687    /// Break statement (exits current loop)
688    Break,
689
690    /// Continue statement (skips to next iteration)
691    Continue,
692
693    /// Computation expression: async { ... }, seq { ... }, etc.
694    ComputationExpr {
695        /// Builder name (e.g., "async", "seq", "option", "result")
696        builder: String,
697        /// Statements in the CE body
698        body: Vec<CEStatement>,
699    },
700}
701
702/// Type alias for record field list: (field_name, value_expression)
703pub type RecordFields = Vec<(String, Box<Expr>)>;
704
705impl Expr {
706    /// Returns true if this expression is a literal.
707    pub fn is_literal(&self) -> bool {
708        matches!(self, Expr::Lit(_))
709    }
710
711    /// Returns true if this expression is a variable.
712    pub fn is_var(&self) -> bool {
713        matches!(self, Expr::Var(_))
714    }
715
716    /// Returns true if this expression is a binary operation.
717    pub fn is_binop(&self) -> bool {
718        matches!(self, Expr::BinOp { .. })
719    }
720
721    /// Returns true if this expression is a let-binding.
722    pub fn is_let(&self) -> bool {
723        matches!(self, Expr::Let { .. })
724    }
725
726    /// Returns true if this expression is a recursive let-binding.
727    pub fn is_let_rec(&self) -> bool {
728        matches!(self, Expr::LetRec { .. })
729    }
730
731    /// Returns true if this expression is a mutually recursive let-binding.
732    pub fn is_let_rec_mutual(&self) -> bool {
733        matches!(self, Expr::LetRecMutual { .. })
734    }
735
736    /// Returns true if this expression is a lambda.
737    pub fn is_lambda(&self) -> bool {
738        matches!(self, Expr::Lambda { .. })
739    }
740
741    /// Returns true if this expression is a function application.
742    pub fn is_app(&self) -> bool {
743        matches!(self, Expr::App { .. })
744    }
745
746    /// Returns true if this expression is a conditional.
747    pub fn is_if(&self) -> bool {
748        matches!(self, Expr::If { .. })
749    }
750
751    /// Returns true if this expression is a match.
752    pub fn is_match(&self) -> bool {
753        matches!(self, Expr::Match { .. })
754    }
755
756    /// Returns true if this expression is a tuple.
757    pub fn is_tuple(&self) -> bool {
758        matches!(self, Expr::Tuple(_))
759    }
760
761    /// Returns true if this expression is a list.
762    pub fn is_list(&self) -> bool {
763        matches!(self, Expr::List(_))
764    }
765
766    /// Returns true if this expression is a cons.
767    pub fn is_cons(&self) -> bool {
768        matches!(self, Expr::Cons { .. })
769    }
770
771    /// Returns true if this expression is an array.
772    pub fn is_array(&self) -> bool {
773        matches!(self, Expr::Array(_))
774    }
775
776    /// Returns true if this expression is an array index.
777    pub fn is_array_index(&self) -> bool {
778        matches!(self, Expr::ArrayIndex { .. })
779    }
780
781    /// Returns true if this expression is an array update.
782    pub fn is_array_update(&self) -> bool {
783        matches!(self, Expr::ArrayUpdate { .. })
784    }
785
786    /// Returns true if this expression is an array length.
787    pub fn is_array_length(&self) -> bool {
788        matches!(self, Expr::ArrayLength(_))
789    }
790
791    /// Returns true if this expression is a record literal.
792    pub fn is_record_literal(&self) -> bool {
793        matches!(self, Expr::RecordLiteral { .. })
794    }
795
796    /// Returns true if this expression is a record access.
797    pub fn is_record_access(&self) -> bool {
798        matches!(self, Expr::RecordAccess { .. })
799    }
800
801    /// Returns true if this expression is a record update.
802    pub fn is_record_update(&self) -> bool {
803        matches!(self, Expr::RecordUpdate { .. })
804    }
805
806    /// Returns true if this expression is a variant constructor.
807    pub fn is_variant_construct(&self) -> bool {
808        matches!(self, Expr::VariantConstruct { .. })
809    }
810
811    /// Returns true if this expression is a method call.
812    pub fn is_method_call(&self) -> bool {
813        matches!(self, Expr::MethodCall { .. })
814    }
815
816    /// Returns true if this expression is a while loop.
817    pub fn is_while(&self) -> bool {
818        matches!(self, Expr::While { .. })
819    }
820
821    /// Returns true if this expression is a break statement.
822    pub fn is_break(&self) -> bool {
823        matches!(self, Expr::Break)
824    }
825
826    /// Returns true if this expression is a continue statement.
827    pub fn is_continue(&self) -> bool {
828        matches!(self, Expr::Continue)
829    }
830
831    /// Returns true if this expression is a computation expression.
832    pub fn is_computation_expr(&self) -> bool {
833        matches!(self, Expr::ComputationExpr { .. })
834    }
835
836    /// Returns the variable name if this is a Var, otherwise None.
837    pub fn as_var(&self) -> Option<&str> {
838        match self {
839            Expr::Var(name) => Some(name),
840            _ => None,
841        }
842    }
843
844    /// Returns the literal value if this is a Lit, otherwise None.
845    pub fn as_literal(&self) -> Option<&Literal> {
846        match self {
847            Expr::Lit(lit) => Some(lit),
848            _ => None,
849        }
850    }
851
852    /// Returns the tuple elements if this is a Tuple, otherwise None.
853    pub fn as_tuple(&self) -> Option<&Vec<Expr>> {
854        match self {
855            Expr::Tuple(elements) => Some(elements),
856            _ => None,
857        }
858    }
859
860    /// Returns the list elements if this is a List, otherwise None.
861    pub fn as_list(&self) -> Option<&Vec<Expr>> {
862        match self {
863            Expr::List(elements) => Some(elements),
864            _ => None,
865        }
866    }
867
868    /// Returns the head and tail if this is a Cons, otherwise None.
869    pub fn as_cons(&self) -> Option<(&Expr, &Expr)> {
870        match self {
871            Expr::Cons { head, tail } => Some((head, tail)),
872            _ => None,
873        }
874    }
875
876    /// Returns the array elements if this is an Array, otherwise None.
877    pub fn as_array(&self) -> Option<&Vec<Expr>> {
878        match self {
879            Expr::Array(elements) => Some(elements),
880            _ => None,
881        }
882    }
883
884    /// Returns the record fields if this is a RecordLiteral, otherwise None.
885    pub fn as_record_literal(&self) -> Option<(&str, &RecordFields)> {
886        match self {
887            Expr::RecordLiteral { type_name, fields } => Some((type_name, fields)),
888            _ => None,
889        }
890    }
891
892    /// Returns the scrutinee and arms if this is a Match, otherwise None.
893    pub fn as_match(&self) -> Option<(&Expr, &Vec<MatchArm>)> {
894        match self {
895            Expr::Match { scrutinee, arms } => Some((scrutinee, arms)),
896            _ => None,
897        }
898    }
899
900    /// Returns the builder name and body if this is a ComputationExpr, otherwise None.
901    pub fn as_computation_expr(&self) -> Option<(&str, &Vec<CEStatement>)> {
902        match self {
903            Expr::ComputationExpr { builder, body } => Some((builder, body)),
904            _ => None,
905        }
906    }
907}
908
909impl fmt::Display for Expr {
910    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
911        match self {
912            Expr::Var(name) => write!(f, "{}", name),
913            Expr::Lit(lit) => write!(f, "{}", lit),
914            Expr::BinOp { op, left, right } => {
915                write!(f, "({} {} {})", left, op, right)
916            }
917            Expr::Let { name, value, body } => {
918                write!(f, "(let {} = {} in {})", name, value, body)
919            }
920            Expr::LetRec { name, value, body } => {
921                write!(f, "(let rec {} = {} in {})", name, value, body)
922            }
923            Expr::LetRecMutual { bindings, body } => {
924                write!(f, "(let rec ")?;
925                for (i, (name, value)) in bindings.iter().enumerate() {
926                    if i > 0 {
927                        write!(f, " and ")?;
928                    }
929                    write!(f, "{} = {}", name, value)?;
930                }
931                write!(f, " in {})", body)
932            }
933            Expr::Lambda { param, body } => {
934                write!(f, "(fun {} -> {})", param, body)
935            }
936            Expr::App { func, arg } => {
937                write!(f, "({} {})", func, arg)
938            }
939            Expr::If {
940                cond,
941                then_branch,
942                else_branch,
943            } => {
944                write!(f, "(if {} then {} else {})", cond, then_branch, else_branch)
945            }
946            Expr::Match { scrutinee, arms } => {
947                write!(f, "(match {} with", scrutinee)?;
948                for arm in arms {
949                    write!(f, " | {}", arm)?;
950                }
951                write!(f, ")")
952            }
953            Expr::Tuple(elements) => {
954                write!(f, "(")?;
955                for (i, element) in elements.iter().enumerate() {
956                    if i > 0 {
957                        write!(f, ", ")?;
958                    }
959                    write!(f, "{}", element)?;
960                }
961                write!(f, ")")
962            }
963            Expr::List(elements) => {
964                write!(f, "[")?;
965                for (i, element) in elements.iter().enumerate() {
966                    if i > 0 {
967                        write!(f, "; ")?;
968                    }
969                    write!(f, "{}", element)?;
970                }
971                write!(f, "]")
972            }
973            Expr::Cons { head, tail } => {
974                write!(f, "({} :: {})", head, tail)
975            }
976            Expr::Array(elements) => {
977                write!(f, "[|")?;
978                for (i, element) in elements.iter().enumerate() {
979                    if i > 0 {
980                        write!(f, "; ")?;
981                    }
982                    write!(f, "{}", element)?;
983                }
984                write!(f, "|]")
985            }
986            Expr::ArrayIndex { array, index } => {
987                write!(f, "({}.[{}])", array, index)
988            }
989            Expr::ArrayUpdate {
990                array,
991                index,
992                value,
993            } => {
994                write!(f, "({}.[{}] <- {})", array, index, value)
995            }
996            Expr::ArrayLength(arr) => {
997                write!(f, "(Array.length {})", arr)
998            }
999            Expr::RecordLiteral { type_name, fields } => {
1000                if !type_name.is_empty() {
1001                    write!(f, "({} ", type_name)?;
1002                }
1003                write!(f, "{{ ")?;
1004                for (i, (field_name, field_expr)) in fields.iter().enumerate() {
1005                    if i > 0 {
1006                        write!(f, "; ")?;
1007                    }
1008                    write!(f, "{} = {}", field_name, field_expr)?;
1009                }
1010                write!(f, " }}")?;
1011                if !type_name.is_empty() {
1012                    write!(f, ")")?;
1013                }
1014                Ok(())
1015            }
1016            Expr::RecordAccess { record, field } => {
1017                write!(f, "({}.{})", record, field)
1018            }
1019            Expr::RecordUpdate { record, fields } => {
1020                write!(f, "({{ {} with ", record)?;
1021                for (i, (field_name, field_expr)) in fields.iter().enumerate() {
1022                    if i > 0 {
1023                        write!(f, "; ")?;
1024                    }
1025                    write!(f, "{} = {}", field_name, field_expr)?;
1026                }
1027                write!(f, " }})")
1028            }
1029            Expr::VariantConstruct {
1030                type_name: _,
1031                variant,
1032                fields,
1033            } => {
1034                write!(f, "{}", variant)?;
1035                if !fields.is_empty() {
1036                    write!(f, "(")?;
1037                    for (i, field_expr) in fields.iter().enumerate() {
1038                        if i > 0 {
1039                            write!(f, ", ")?;
1040                        }
1041                        write!(f, "{}", field_expr)?;
1042                    }
1043                    write!(f, ")")?;
1044                }
1045                Ok(())
1046            }
1047            Expr::MethodCall {
1048                receiver,
1049                method_name,
1050                args,
1051            } => {
1052                write!(f, "({}.{}(", receiver, method_name)?;
1053                for (i, arg) in args.iter().enumerate() {
1054                    if i > 0 {
1055                        write!(f, ", ")?;
1056                    }
1057                    write!(f, "{}", arg)?;
1058                }
1059                write!(f, "))")
1060            }
1061            Expr::While { cond, body } => {
1062                write!(f, "(while {} do {})", cond, body)
1063            }
1064            Expr::Break => write!(f, "break"),
1065            Expr::Continue => write!(f, "continue"),
1066            Expr::ComputationExpr { builder, body } => {
1067                write!(f, "{} {{ ... ({} statements) }}", builder, body.len())
1068            }
1069        }
1070    }
1071}
1072// ========================================================================
1073// Module System Types (Phase 3)
1074// ========================================================================
1075
1076/// Named module definition with nested items
1077///
1078/// Represents a module with a name and contained items (bindings, types, nested modules).
1079/// Example: module Math = let add x y = x + y
1080#[derive(Debug, Clone, PartialEq)]
1081pub struct ModuleDef {
1082    /// Module name
1083    pub name: String,
1084    /// Items contained in this module
1085    pub items: Vec<ModuleItem>,
1086}
1087
1088impl fmt::Display for ModuleDef {
1089    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1090        write!(f, "module {} = ", self.name)?;
1091        for (i, item) in self.items.iter().enumerate() {
1092            if i > 0 {
1093                writeln!(f)?;
1094            }
1095            write!(f, "{}", item)?;
1096        }
1097        Ok(())
1098    }
1099}
1100
1101/// Items that can appear inside a module
1102#[derive(Debug, Clone, PartialEq)]
1103pub enum ModuleItem {
1104    /// Let binding: let x = expr (or let _ = expr for discard)
1105    Let(Option<String>, Expr),
1106    /// Recursive let binding: let rec f = expr
1107    LetRec(Vec<(String, Expr)>),
1108    /// Type definition (record or DU)
1109    TypeDef(TypeDefinition),
1110    /// Nested module
1111    Module(Box<ModuleDef>),
1112}
1113
1114impl fmt::Display for ModuleItem {
1115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1116        match self {
1117            ModuleItem::Let(name, expr) => {
1118                write!(f, "let {} = {}", name.as_deref().unwrap_or("_"), expr)
1119            }
1120            ModuleItem::LetRec(bindings) => {
1121                write!(f, "let rec ")?;
1122                for (i, (name, expr)) in bindings.iter().enumerate() {
1123                    if i > 0 {
1124                        write!(f, " and ")?;
1125                    }
1126                    write!(f, "{} = {}", name, expr)?;
1127                }
1128                Ok(())
1129            }
1130            ModuleItem::TypeDef(typedef) => write!(f, "{}", typedef),
1131            ModuleItem::Module(module_def) => write!(f, "{}", module_def),
1132        }
1133    }
1134}
1135
1136/// Import/Open statement
1137///
1138/// Represents importing bindings from a module into scope.
1139/// Example: open Math
1140#[derive(Debug, Clone, PartialEq)]
1141pub struct Import {
1142    /// Module path (e.g., ["Math", "Geometry"])
1143    pub module_path: Vec<String>,
1144    /// Whether this is qualified access only (false for "open")
1145    pub is_qualified: bool,
1146}
1147
1148impl fmt::Display for Import {
1149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1150        if self.is_qualified {
1151            write!(f, "// qualified import: {}", self.module_path.join("."))
1152        } else {
1153            write!(f, "open {}", self.module_path.join("."))
1154        }
1155    }
1156}
1157
1158/// Load directive for multi-file module system
1159///
1160/// Represents a #load directive that imports another .fsx file.
1161/// Example: #load "utils.fsx"
1162#[derive(Debug, Clone, PartialEq)]
1163pub struct LoadDirective {
1164    /// Path to the file to load
1165    pub path: String,
1166}
1167
1168impl fmt::Display for LoadDirective {
1169    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1170        write!(f, "#load \"{}\"", self.path)
1171    }
1172}
1173
1174/// Complete program with modules and main expression
1175///
1176/// Top-level structure representing a complete Fusabi program with
1177/// module definitions, imports, and an optional main expression.
1178#[derive(Debug, Clone, PartialEq)]
1179pub struct Program {
1180    /// Load directives (must appear before other declarations)
1181    pub directives: Vec<LoadDirective>,
1182    /// Module definitions
1183    pub modules: Vec<ModuleDef>,
1184    /// Import statements
1185    pub imports: Vec<Import>,
1186    /// Top-level items (let bindings, types, etc.)
1187    pub items: Vec<ModuleItem>,
1188    /// Main expression to evaluate (if any)
1189    pub main_expr: Option<Expr>,
1190}
1191
1192impl fmt::Display for Program {
1193    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1194        for directive in &self.directives {
1195            writeln!(f, "{}", directive)?;
1196        }
1197        if !self.directives.is_empty() && (!self.imports.is_empty() || !self.modules.is_empty()) {
1198            writeln!(f)?;
1199        }
1200        for import in &self.imports {
1201            writeln!(f, "{}", import)?;
1202        }
1203        if !self.imports.is_empty() && !self.modules.is_empty() {
1204            writeln!(f)?;
1205        }
1206        for (i, module) in self.modules.iter().enumerate() {
1207            if i > 0 {
1208                writeln!(f)?;
1209                writeln!(f)?;
1210            }
1211            write!(f, "{}", module)?;
1212        }
1213        if !self.modules.is_empty() && !self.items.is_empty() {
1214            writeln!(f)?;
1215            writeln!(f)?;
1216        }
1217        for (i, item) in self.items.iter().enumerate() {
1218            if i > 0 {
1219                writeln!(f)?;
1220            }
1221            write!(f, "{}", item)?;
1222        }
1223        if let Some(ref expr) = self.main_expr {
1224            if !self.modules.is_empty() || !self.items.is_empty() {
1225                writeln!(f)?;
1226                writeln!(f)?;
1227            }
1228            write!(f, "{}", expr)?;
1229        }
1230        Ok(())
1231    }
1232}
1233
1234#[cfg(test)]
1235mod tests {
1236    use super::*;
1237
1238    // ========================================================================
1239    // Literal Tests
1240    // ========================================================================
1241
1242    #[test]
1243    fn test_literal_int() {
1244        let lit = Literal::Int(42);
1245        assert_eq!(lit, Literal::Int(42));
1246        assert_eq!(format!("{}", lit), "42");
1247    }
1248
1249    #[test]
1250    fn test_literal_float() {
1251        let lit = Literal::Float(2.5);
1252        assert_eq!(lit, Literal::Float(2.5));
1253        assert_eq!(format!("{}", lit), "2.5");
1254    }
1255
1256    #[test]
1257    fn test_literal_bool() {
1258        let lit_true = Literal::Bool(true);
1259        let lit_false = Literal::Bool(false);
1260        assert_eq!(lit_true, Literal::Bool(true));
1261        assert_eq!(lit_false, Literal::Bool(false));
1262        assert_eq!(format!("{}", lit_true), "true");
1263        assert_eq!(format!("{}", lit_false), "false");
1264    }
1265
1266    #[test]
1267    fn test_literal_str() {
1268        let lit = Literal::Str("hello".to_string());
1269        assert_eq!(lit, Literal::Str("hello".to_string()));
1270        assert_eq!(format!("{}", lit), "\"hello\"");
1271    }
1272
1273    #[test]
1274    fn test_literal_unit() {
1275        let lit = Literal::Unit;
1276        assert_eq!(lit, Literal::Unit);
1277        assert_eq!(format!("{}", lit), "()");
1278    }
1279
1280    #[test]
1281    fn test_literal_clone() {
1282        let lit = Literal::Int(42);
1283        let cloned = lit.clone();
1284        assert_eq!(lit, cloned);
1285    }
1286
1287    // ========================================================================
1288    // BinOp Tests
1289    // ========================================================================
1290
1291    #[test]
1292    fn test_binop_arithmetic() {
1293        assert!(BinOp::Add.is_arithmetic());
1294        assert!(BinOp::Sub.is_arithmetic());
1295        assert!(BinOp::Mul.is_arithmetic());
1296        assert!(BinOp::Div.is_arithmetic());
1297        assert!(!BinOp::Eq.is_arithmetic());
1298        assert!(!BinOp::And.is_arithmetic());
1299    }
1300
1301    #[test]
1302    fn test_binop_comparison() {
1303        assert!(BinOp::Eq.is_comparison());
1304        assert!(BinOp::Neq.is_comparison());
1305        assert!(BinOp::Lt.is_comparison());
1306        assert!(BinOp::Lte.is_comparison());
1307        assert!(BinOp::Gt.is_comparison());
1308        assert!(BinOp::Gte.is_comparison());
1309        assert!(!BinOp::Add.is_comparison());
1310        assert!(!BinOp::And.is_comparison());
1311    }
1312
1313    #[test]
1314    fn test_binop_logical() {
1315        assert!(BinOp::And.is_logical());
1316        assert!(BinOp::Or.is_logical());
1317        assert!(!BinOp::Add.is_logical());
1318        assert!(!BinOp::Eq.is_logical());
1319    }
1320
1321    #[test]
1322    fn test_binop_display() {
1323        assert_eq!(format!("{}", BinOp::Add), "+");
1324        assert_eq!(format!("{}", BinOp::Sub), "-");
1325        assert_eq!(format!("{}", BinOp::Mul), "*");
1326        assert_eq!(format!("{}", BinOp::Div), "/");
1327        assert_eq!(format!("{}", BinOp::Eq), "=");
1328        assert_eq!(format!("{}", BinOp::Neq), "<>");
1329        assert_eq!(format!("{}", BinOp::Lt), "<");
1330        assert_eq!(format!("{}", BinOp::Lte), "<=");
1331        assert_eq!(format!("{}", BinOp::Gt), ">");
1332        assert_eq!(format!("{}", BinOp::Gte), ">=");
1333        assert_eq!(format!("{}", BinOp::And), "&&");
1334        assert_eq!(format!("{}", BinOp::Or), "||");
1335    }
1336
1337    // ========================================================================
1338    // TypeExpr Tests (Issue #15 Layer 1)
1339    // ========================================================================
1340
1341    #[test]
1342    fn test_type_expr_named() {
1343        let ty = TypeExpr::Named("int".to_string());
1344        assert_eq!(ty, TypeExpr::Named("int".to_string()));
1345        assert_eq!(format!("{}", ty), "int");
1346    }
1347
1348    #[test]
1349    fn test_type_expr_tuple() {
1350        let ty = TypeExpr::Tuple(vec![
1351            TypeExpr::Named("int".to_string()),
1352            TypeExpr::Named("string".to_string()),
1353        ]);
1354        assert_eq!(format!("{}", ty), "int * string");
1355    }
1356
1357    #[test]
1358    fn test_type_expr_function() {
1359        let ty = TypeExpr::Function(
1360            Box::new(TypeExpr::Named("int".to_string())),
1361            Box::new(TypeExpr::Named("string".to_string())),
1362        );
1363        assert_eq!(format!("{}", ty), "int -> string");
1364    }
1365
1366    #[test]
1367    fn test_type_expr_complex() {
1368        // (int * string) -> bool
1369        let ty = TypeExpr::Function(
1370            Box::new(TypeExpr::Tuple(vec![
1371                TypeExpr::Named("int".to_string()),
1372                TypeExpr::Named("string".to_string()),
1373            ])),
1374            Box::new(TypeExpr::Named("bool".to_string())),
1375        );
1376        assert_eq!(format!("{}", ty), "int * string -> bool");
1377    }
1378
1379    #[test]
1380    fn test_type_expr_clone() {
1381        let ty1 = TypeExpr::Named("int".to_string());
1382        let ty2 = ty1.clone();
1383        assert_eq!(ty1, ty2);
1384    }
1385
1386    // ========================================================================
1387    // RecordTypeDef Tests (Issue #15 Layer 1)
1388    // ========================================================================
1389
1390    #[test]
1391    fn test_record_typedef_empty() {
1392        let typedef = RecordTypeDef {
1393            name: "Empty".to_string(),
1394            fields: vec![],
1395        };
1396        assert_eq!(typedef.name, "Empty");
1397        assert_eq!(typedef.fields.len(), 0);
1398        assert_eq!(format!("{}", typedef), "type Empty = {  }");
1399    }
1400
1401    #[test]
1402    fn test_record_typedef_single_field() {
1403        let typedef = RecordTypeDef {
1404            name: "Age".to_string(),
1405            fields: vec![("age".to_string(), TypeExpr::Named("int".to_string()))],
1406        };
1407        assert_eq!(typedef.name, "Age");
1408        assert_eq!(typedef.fields.len(), 1);
1409        assert_eq!(format!("{}", typedef), "type Age = { age: int }");
1410    }
1411
1412    #[test]
1413    fn test_record_typedef_multiple_fields() {
1414        let typedef = RecordTypeDef {
1415            name: "Person".to_string(),
1416            fields: vec![
1417                ("name".to_string(), TypeExpr::Named("string".to_string())),
1418                ("age".to_string(), TypeExpr::Named("int".to_string())),
1419                ("active".to_string(), TypeExpr::Named("bool".to_string())),
1420            ],
1421        };
1422        assert_eq!(typedef.name, "Person");
1423        assert_eq!(typedef.fields.len(), 3);
1424        assert_eq!(
1425            format!("{}", typedef),
1426            "type Person = { name: string; age: int; active: bool }"
1427        );
1428    }
1429
1430    #[test]
1431    fn test_record_typedef_with_tuple_type() {
1432        let typedef = RecordTypeDef {
1433            name: "Point".to_string(),
1434            fields: vec![(
1435                "coords".to_string(),
1436                TypeExpr::Tuple(vec![
1437                    TypeExpr::Named("int".to_string()),
1438                    TypeExpr::Named("int".to_string()),
1439                ]),
1440            )],
1441        };
1442        assert_eq!(format!("{}", typedef), "type Point = { coords: int * int }");
1443    }
1444
1445    #[test]
1446    fn test_record_typedef_with_function_type() {
1447        let typedef = RecordTypeDef {
1448            name: "Processor".to_string(),
1449            fields: vec![(
1450                "process".to_string(),
1451                TypeExpr::Function(
1452                    Box::new(TypeExpr::Named("int".to_string())),
1453                    Box::new(TypeExpr::Named("string".to_string())),
1454                ),
1455            )],
1456        };
1457        assert_eq!(
1458            format!("{}", typedef),
1459            "type Processor = { process: int -> string }"
1460        );
1461    }
1462
1463    #[test]
1464    fn test_record_typedef_clone() {
1465        let typedef1 = RecordTypeDef {
1466            name: "Person".to_string(),
1467            fields: vec![("name".to_string(), TypeExpr::Named("string".to_string()))],
1468        };
1469        let typedef2 = typedef1.clone();
1470        assert_eq!(typedef1, typedef2);
1471    }
1472
1473    // ========================================================================
1474    // Declaration Tests (Issue #15 Layer 1)
1475    // ========================================================================
1476
1477    #[test]
1478    fn test_declaration_typedef() {
1479        let decl = Declaration::TypeDef(TypeDefinition::Record(RecordTypeDef {
1480            name: "Person".to_string(),
1481            fields: vec![("name".to_string(), TypeExpr::Named("string".to_string()))],
1482        }));
1483        assert!(matches!(decl, Declaration::TypeDef(_)));
1484        assert_eq!(format!("{}", decl), "type Person = { name: string }");
1485    }
1486
1487    #[test]
1488    fn test_declaration_let_binding_simple() {
1489        let decl = Declaration::LetBinding {
1490            name: "x".to_string(),
1491            params: vec![],
1492            body: Box::new(Expr::Lit(Literal::Int(42))),
1493        };
1494        assert!(matches!(decl, Declaration::LetBinding { .. }));
1495        assert_eq!(format!("{}", decl), "let x = 42");
1496    }
1497
1498    #[test]
1499    fn test_declaration_let_binding_with_params() {
1500        let decl = Declaration::LetBinding {
1501            name: "add".to_string(),
1502            params: vec!["x".to_string(), "y".to_string()],
1503            body: Box::new(Expr::BinOp {
1504                op: BinOp::Add,
1505                left: Box::new(Expr::Var("x".to_string())),
1506                right: Box::new(Expr::Var("y".to_string())),
1507            }),
1508        };
1509        assert_eq!(format!("{}", decl), "let add x y = (x + y)");
1510    }
1511
1512    #[test]
1513    fn test_declaration_clone() {
1514        let decl1 = Declaration::TypeDef(TypeDefinition::Record(RecordTypeDef {
1515            name: "Person".to_string(),
1516            fields: vec![],
1517        }));
1518        let decl2 = decl1.clone();
1519        assert_eq!(decl1, decl2);
1520    }
1521
1522    // ========================================================================
1523    // Module Tests (Issue #15 Layer 1)
1524    // ========================================================================
1525
1526    #[test]
1527    fn test_module_empty() {
1528        let module = Module {
1529            declarations: vec![],
1530        };
1531        assert_eq!(module.declarations.len(), 0);
1532        assert_eq!(format!("{}", module), "");
1533    }
1534
1535    #[test]
1536    fn test_module_single_typedef() {
1537        let module = Module {
1538            declarations: vec![Declaration::TypeDef(TypeDefinition::Record(
1539                RecordTypeDef {
1540                    name: "Person".to_string(),
1541                    fields: vec![("name".to_string(), TypeExpr::Named("string".to_string()))],
1542                },
1543            ))],
1544        };
1545        assert_eq!(module.declarations.len(), 1);
1546        assert_eq!(format!("{}", module), "type Person = { name: string }");
1547    }
1548
1549    #[test]
1550    fn test_module_multiple_declarations() {
1551        let module = Module {
1552            declarations: vec![
1553                Declaration::TypeDef(TypeDefinition::Record(RecordTypeDef {
1554                    name: "Person".to_string(),
1555                    fields: vec![("name".to_string(), TypeExpr::Named("string".to_string()))],
1556                })),
1557                Declaration::LetBinding {
1558                    name: "john".to_string(),
1559                    params: vec![],
1560                    body: Box::new(Expr::RecordLiteral {
1561                        type_name: String::new(),
1562                        fields: vec![(
1563                            "name".to_string(),
1564                            Box::new(Expr::Lit(Literal::Str("John".to_string()))),
1565                        )],
1566                    }),
1567                },
1568            ],
1569        };
1570        assert_eq!(module.declarations.len(), 2);
1571    }
1572
1573    #[test]
1574    fn test_module_clone() {
1575        let module1 = Module {
1576            declarations: vec![],
1577        };
1578        let module2 = module1.clone();
1579        assert_eq!(module1, module2);
1580    }
1581
1582    // ========================================================================
1583    // Expr Record Tests (Issue #15 Layer 1)
1584    // ========================================================================
1585
1586    #[test]
1587    fn test_expr_record_literal_empty() {
1588        let expr = Expr::RecordLiteral {
1589            type_name: String::new(),
1590            fields: vec![],
1591        };
1592        assert!(expr.is_record_literal());
1593        assert!(!expr.is_literal());
1594        assert_eq!(format!("{}", expr), "{  }");
1595    }
1596
1597    #[test]
1598    fn test_expr_record_literal_single_field() {
1599        let expr = Expr::RecordLiteral {
1600            type_name: String::new(),
1601            fields: vec![(
1602                "name".to_string(),
1603                Box::new(Expr::Lit(Literal::Str("John".to_string()))),
1604            )],
1605        };
1606        assert!(expr.is_record_literal());
1607        assert_eq!(format!("{}", expr), "{ name = \"John\" }");
1608    }
1609
1610    #[test]
1611    fn test_expr_record_literal_multiple_fields() {
1612        let expr = Expr::RecordLiteral {
1613            type_name: String::new(),
1614            fields: vec![
1615                (
1616                    "name".to_string(),
1617                    Box::new(Expr::Lit(Literal::Str("John".to_string()))),
1618                ),
1619                ("age".to_string(), Box::new(Expr::Lit(Literal::Int(30)))),
1620                (
1621                    "active".to_string(),
1622                    Box::new(Expr::Lit(Literal::Bool(true))),
1623                ),
1624            ],
1625        };
1626        assert!(expr.is_record_literal());
1627        assert_eq!(
1628            format!("{}", expr),
1629            "{ name = \"John\"; age = 30; active = true }"
1630        );
1631    }
1632
1633    #[test]
1634    fn test_expr_record_literal_with_type_name() {
1635        let expr = Expr::RecordLiteral {
1636            type_name: "Person".to_string(),
1637            fields: vec![(
1638                "name".to_string(),
1639                Box::new(Expr::Lit(Literal::Str("John".to_string()))),
1640            )],
1641        };
1642        assert_eq!(format!("{}", expr), "(Person { name = \"John\" })");
1643    }
1644
1645    #[test]
1646    fn test_expr_record_access_simple() {
1647        let expr = Expr::RecordAccess {
1648            record: Box::new(Expr::Var("person".to_string())),
1649            field: "name".to_string(),
1650        };
1651        assert!(expr.is_record_access());
1652        assert!(!expr.is_record_literal());
1653        assert_eq!(format!("{}", expr), "(person.name)");
1654    }
1655
1656    #[test]
1657    fn test_expr_record_access_nested() {
1658        let expr = Expr::RecordAccess {
1659            record: Box::new(Expr::RecordAccess {
1660                record: Box::new(Expr::Var("company".to_string())),
1661                field: "employee".to_string(),
1662            }),
1663            field: "name".to_string(),
1664        };
1665        assert!(expr.is_record_access());
1666        assert_eq!(format!("{}", expr), "((company.employee).name)");
1667    }
1668
1669    #[test]
1670    fn test_expr_record_update_single_field() {
1671        let expr = Expr::RecordUpdate {
1672            record: Box::new(Expr::Var("person".to_string())),
1673            fields: vec![("age".to_string(), Box::new(Expr::Lit(Literal::Int(31))))],
1674        };
1675        assert!(expr.is_record_update());
1676        assert!(!expr.is_record_literal());
1677        assert_eq!(format!("{}", expr), "({ person with age = 31 })");
1678    }
1679
1680    #[test]
1681    fn test_expr_record_update_multiple_fields() {
1682        let expr = Expr::RecordUpdate {
1683            record: Box::new(Expr::Var("person".to_string())),
1684            fields: vec![
1685                ("age".to_string(), Box::new(Expr::Lit(Literal::Int(31)))),
1686                (
1687                    "active".to_string(),
1688                    Box::new(Expr::Lit(Literal::Bool(false))),
1689                ),
1690            ],
1691        };
1692        assert!(expr.is_record_update());
1693        assert_eq!(
1694            format!("{}", expr),
1695            "({ person with age = 31; active = false })"
1696        );
1697    }
1698
1699    #[test]
1700    fn test_expr_record_as_record_literal() {
1701        let expr = Expr::RecordLiteral {
1702            type_name: "Person".to_string(),
1703            fields: vec![(
1704                "name".to_string(),
1705                Box::new(Expr::Lit(Literal::Str("John".to_string()))),
1706            )],
1707        };
1708        let result = expr.as_record_literal();
1709        assert!(result.is_some());
1710        let (type_name, fields) = result.unwrap();
1711        assert_eq!(type_name, "Person");
1712        assert_eq!(fields.len(), 1);
1713    }
1714
1715    #[test]
1716    fn test_expr_record_clone() {
1717        let expr1 = Expr::RecordLiteral {
1718            type_name: String::new(),
1719            fields: vec![(
1720                "name".to_string(),
1721                Box::new(Expr::Lit(Literal::Str("John".to_string()))),
1722            )],
1723        };
1724        let expr2 = expr1.clone();
1725        assert_eq!(expr1, expr2);
1726    }
1727
1728    #[test]
1729    fn test_expr_record_equality() {
1730        let expr1 = Expr::RecordLiteral {
1731            type_name: String::new(),
1732            fields: vec![(
1733                "name".to_string(),
1734                Box::new(Expr::Lit(Literal::Str("John".to_string()))),
1735            )],
1736        };
1737        let expr2 = Expr::RecordLiteral {
1738            type_name: String::new(),
1739            fields: vec![(
1740                "name".to_string(),
1741                Box::new(Expr::Lit(Literal::Str("John".to_string()))),
1742            )],
1743        };
1744        assert_eq!(expr1, expr2);
1745    }
1746
1747    #[test]
1748    fn test_expr_record_inequality_different_fields() {
1749        let expr1 = Expr::RecordLiteral {
1750            type_name: String::new(),
1751            fields: vec![(
1752                "name".to_string(),
1753                Box::new(Expr::Lit(Literal::Str("John".to_string()))),
1754            )],
1755        };
1756        let expr2 = Expr::RecordLiteral {
1757            type_name: String::new(),
1758            fields: vec![(
1759                "name".to_string(),
1760                Box::new(Expr::Lit(Literal::Str("Jane".to_string()))),
1761            )],
1762        };
1763        assert_ne!(expr1, expr2);
1764    }
1765
1766    #[test]
1767    fn test_expr_record_literal_with_expressions() {
1768        let expr = Expr::RecordLiteral {
1769            type_name: String::new(),
1770            fields: vec![
1771                (
1772                    "x".to_string(),
1773                    Box::new(Expr::BinOp {
1774                        op: BinOp::Add,
1775                        left: Box::new(Expr::Lit(Literal::Int(1))),
1776                        right: Box::new(Expr::Lit(Literal::Int(2))),
1777                    }),
1778                ),
1779                (
1780                    "y".to_string(),
1781                    Box::new(Expr::BinOp {
1782                        op: BinOp::Mul,
1783                        left: Box::new(Expr::Lit(Literal::Int(3))),
1784                        right: Box::new(Expr::Lit(Literal::Int(4))),
1785                    }),
1786                ),
1787            ],
1788        };
1789        assert_eq!(format!("{}", expr), "{ x = (1 + 2); y = (3 * 4) }");
1790    }
1791
1792    #[test]
1793    fn test_expr_record_update_with_expression() {
1794        let expr = Expr::RecordUpdate {
1795            record: Box::new(Expr::Var("person".to_string())),
1796            fields: vec![(
1797                "age".to_string(),
1798                Box::new(Expr::BinOp {
1799                    op: BinOp::Add,
1800                    left: Box::new(Expr::RecordAccess {
1801                        record: Box::new(Expr::Var("person".to_string())),
1802                        field: "age".to_string(),
1803                    }),
1804                    right: Box::new(Expr::Lit(Literal::Int(1))),
1805                }),
1806            )],
1807        };
1808        assert_eq!(
1809            format!("{}", expr),
1810            "({ person with age = ((person.age) + 1) })"
1811        );
1812    }
1813
1814    #[test]
1815    fn test_expr_record_nested_literal() {
1816        // { outer = { inner = 42 } }
1817        let expr = Expr::RecordLiteral {
1818            type_name: String::new(),
1819            fields: vec![(
1820                "outer".to_string(),
1821                Box::new(Expr::RecordLiteral {
1822                    type_name: String::new(),
1823                    fields: vec![("inner".to_string(), Box::new(Expr::Lit(Literal::Int(42))))],
1824                }),
1825            )],
1826        };
1827        assert_eq!(format!("{}", expr), "{ outer = { inner = 42 } }");
1828    }
1829
1830    // Continue with existing tests from original file...
1831    // (I'll include a few key tests for continuity)
1832
1833    #[test]
1834    fn test_expr_var() {
1835        let expr = Expr::Var("x".to_string());
1836        assert!(expr.is_var());
1837        assert!(!expr.is_literal());
1838        assert_eq!(expr.as_var(), Some("x"));
1839        assert_eq!(format!("{}", expr), "x");
1840    }
1841
1842    #[test]
1843    fn test_expr_lit() {
1844        let expr = Expr::Lit(Literal::Int(42));
1845        assert!(expr.is_literal());
1846        assert!(!expr.is_var());
1847        assert_eq!(expr.as_literal(), Some(&Literal::Int(42)));
1848        assert_eq!(format!("{}", expr), "42");
1849    }
1850
1851    #[test]
1852    fn test_expr_tuple_pair() {
1853        let expr = Expr::Tuple(vec![Expr::Lit(Literal::Int(1)), Expr::Lit(Literal::Int(2))]);
1854        assert!(expr.is_tuple());
1855        assert!(!expr.is_literal());
1856        assert_eq!(format!("{}", expr), "(1, 2)");
1857    }
1858
1859    #[test]
1860    fn test_list_empty() {
1861        let expr = Expr::List(vec![]);
1862        assert!(expr.is_list());
1863        assert_eq!(format!("{}", expr), "[]");
1864    }
1865
1866    #[test]
1867    fn test_array_empty() {
1868        let expr = Expr::Array(vec![]);
1869        assert!(expr.is_array());
1870        assert_eq!(format!("{}", expr), "[||]");
1871    }
1872}
1873
1874// ========================================================================
1875// Pattern Tests (Issue #27 Layer 1)
1876// ========================================================================
1877
1878#[test]
1879fn test_pattern_wildcard() {
1880    let pat = Pattern::Wildcard;
1881    assert!(pat.is_wildcard());
1882    assert!(!pat.is_var());
1883    assert!(!pat.is_literal());
1884    assert!(!pat.is_tuple());
1885    assert_eq!(format!("{}", pat), "_");
1886}
1887
1888#[test]
1889fn test_pattern_var() {
1890    let pat = Pattern::Var("x".to_string());
1891    assert!(pat.is_var());
1892    assert!(!pat.is_wildcard());
1893    assert!(!pat.is_literal());
1894    assert_eq!(pat.as_var(), Some("x"));
1895    assert_eq!(format!("{}", pat), "x");
1896}
1897
1898#[test]
1899fn test_pattern_literal_int() {
1900    let pat = Pattern::Literal(Literal::Int(42));
1901    assert!(pat.is_literal());
1902    assert!(!pat.is_var());
1903    assert!(!pat.is_wildcard());
1904    assert_eq!(pat.as_literal(), Some(&Literal::Int(42)));
1905    assert_eq!(format!("{}", pat), "42");
1906}
1907
1908#[test]
1909fn test_pattern_literal_bool() {
1910    let pat_true = Pattern::Literal(Literal::Bool(true));
1911    let pat_false = Pattern::Literal(Literal::Bool(false));
1912    assert!(pat_true.is_literal());
1913    assert!(pat_false.is_literal());
1914    assert_eq!(format!("{}", pat_true), "true");
1915    assert_eq!(format!("{}", pat_false), "false");
1916}
1917
1918#[test]
1919fn test_pattern_literal_string() {
1920    let pat = Pattern::Literal(Literal::Str("hello".to_string()));
1921    assert!(pat.is_literal());
1922    assert_eq!(format!("{}", pat), "\"hello\"");
1923}
1924
1925#[test]
1926fn test_pattern_tuple_empty() {
1927    let pat = Pattern::Tuple(vec![]);
1928    assert!(pat.is_tuple());
1929    assert!(!pat.is_literal());
1930    assert_eq!(pat.as_tuple(), Some(&vec![]));
1931    assert_eq!(format!("{}", pat), "()");
1932}
1933
1934#[test]
1935fn test_pattern_tuple_simple() {
1936    let pat = Pattern::Tuple(vec![
1937        Pattern::Var("x".to_string()),
1938        Pattern::Var("y".to_string()),
1939    ]);
1940    assert!(pat.is_tuple());
1941    assert_eq!(format!("{}", pat), "(x, y)");
1942}
1943
1944#[test]
1945fn test_pattern_tuple_mixed() {
1946    let pat = Pattern::Tuple(vec![
1947        Pattern::Literal(Literal::Int(0)),
1948        Pattern::Var("y".to_string()),
1949        Pattern::Wildcard,
1950    ]);
1951    assert!(pat.is_tuple());
1952    assert_eq!(format!("{}", pat), "(0, y, _)");
1953}
1954
1955#[test]
1956fn test_pattern_tuple_nested() {
1957    let pat = Pattern::Tuple(vec![
1958        Pattern::Var("x".to_string()),
1959        Pattern::Tuple(vec![
1960            Pattern::Var("y".to_string()),
1961            Pattern::Var("z".to_string()),
1962        ]),
1963    ]);
1964    assert!(pat.is_tuple());
1965    assert_eq!(format!("{}", pat), "(x, (y, z))");
1966}
1967
1968#[test]
1969fn test_pattern_clone() {
1970    let pat1 = Pattern::Var("x".to_string());
1971    let pat2 = pat1.clone();
1972    assert_eq!(pat1, pat2);
1973}
1974
1975#[test]
1976fn test_pattern_equality() {
1977    let pat1 = Pattern::Var("x".to_string());
1978    let pat2 = Pattern::Var("x".to_string());
1979    let pat3 = Pattern::Var("y".to_string());
1980    assert_eq!(pat1, pat2);
1981    assert_ne!(pat1, pat3);
1982}
1983
1984#[test]
1985fn test_pattern_as_var_none() {
1986    let pat = Pattern::Wildcard;
1987    assert_eq!(pat.as_var(), None);
1988}
1989
1990#[test]
1991fn test_pattern_as_literal_none() {
1992    let pat = Pattern::Var("x".to_string());
1993    assert_eq!(pat.as_literal(), None);
1994}
1995
1996#[test]
1997fn test_pattern_as_tuple_none() {
1998    let pat = Pattern::Wildcard;
1999    assert_eq!(pat.as_tuple(), None);
2000}
2001
2002#[test]
2003fn test_pattern_all_variants() {
2004    let patterns = [
2005        Pattern::Wildcard,
2006        Pattern::Var("x".to_string()),
2007        Pattern::Literal(Literal::Int(42)),
2008        Pattern::Tuple(vec![Pattern::Wildcard]),
2009    ];
2010    assert_eq!(patterns.len(), 4);
2011}
2012
2013// ========================================================================
2014// MatchArm Tests (Issue #27 Layer 1)
2015// ========================================================================
2016
2017#[test]
2018fn test_match_arm_simple() {
2019    let arm = MatchArm::new(Pattern::Wildcard, Expr::Lit(Literal::Int(42)));
2020    assert!(arm.is_wildcard());
2021    assert!(!arm.is_var());
2022    assert_eq!(format!("{}", arm), "_ -> 42");
2023}
2024
2025#[test]
2026fn test_match_arm_with_var() {
2027    let arm = MatchArm::new(Pattern::Var("x".to_string()), Expr::Var("x".to_string()));
2028    assert!(arm.is_var());
2029    assert!(!arm.is_wildcard());
2030    assert_eq!(format!("{}", arm), "x -> x");
2031}
2032
2033#[test]
2034fn test_match_arm_with_literal() {
2035    let arm = MatchArm::new(
2036        Pattern::Literal(Literal::Int(0)),
2037        Expr::Lit(Literal::Str("zero".to_string())),
2038    );
2039    assert!(!arm.is_wildcard());
2040    assert!(!arm.is_var());
2041    assert_eq!(format!("{}", arm), "0 -> \"zero\"");
2042}
2043
2044#[test]
2045fn test_match_arm_with_tuple_pattern() {
2046    let arm = MatchArm::new(
2047        Pattern::Tuple(vec![
2048            Pattern::Var("x".to_string()),
2049            Pattern::Var("y".to_string()),
2050        ]),
2051        Expr::BinOp {
2052            op: BinOp::Add,
2053            left: Box::new(Expr::Var("x".to_string())),
2054            right: Box::new(Expr::Var("y".to_string())),
2055        },
2056    );
2057    assert_eq!(format!("{}", arm), "(x, y) -> (x + y)");
2058}
2059
2060#[test]
2061fn test_match_arm_clone() {
2062    let arm1 = MatchArm::new(Pattern::Wildcard, Expr::Lit(Literal::Int(42)));
2063    let arm2 = arm1.clone();
2064    assert_eq!(arm1, arm2);
2065}
2066
2067#[test]
2068fn test_match_arm_equality() {
2069    let arm1 = MatchArm::new(Pattern::Wildcard, Expr::Lit(Literal::Int(42)));
2070    let arm2 = MatchArm::new(Pattern::Wildcard, Expr::Lit(Literal::Int(42)));
2071    assert_eq!(arm1, arm2);
2072}
2073
2074// ========================================================================
2075// Match Expression Tests (Issue #27 Layer 1)
2076// ========================================================================
2077
2078#[test]
2079fn test_expr_match_simple() {
2080    let expr = Expr::Match {
2081        scrutinee: Box::new(Expr::Var("x".to_string())),
2082        arms: vec![
2083            MatchArm::new(
2084                Pattern::Literal(Literal::Int(0)),
2085                Expr::Lit(Literal::Str("zero".to_string())),
2086            ),
2087            MatchArm::new(
2088                Pattern::Wildcard,
2089                Expr::Lit(Literal::Str("nonzero".to_string())),
2090            ),
2091        ],
2092    };
2093    assert!(expr.is_match());
2094    assert!(!expr.is_if());
2095    assert_eq!(
2096        format!("{}", expr),
2097        "(match x with | 0 -> \"zero\" | _ -> \"nonzero\")"
2098    );
2099}
2100
2101#[test]
2102fn test_expr_match_multiple_arms() {
2103    let expr = Expr::Match {
2104        scrutinee: Box::new(Expr::Var("n".to_string())),
2105        arms: vec![
2106            MatchArm::new(
2107                Pattern::Literal(Literal::Int(0)),
2108                Expr::Lit(Literal::Str("zero".to_string())),
2109            ),
2110            MatchArm::new(
2111                Pattern::Literal(Literal::Int(1)),
2112                Expr::Lit(Literal::Str("one".to_string())),
2113            ),
2114            MatchArm::new(
2115                Pattern::Literal(Literal::Int(2)),
2116                Expr::Lit(Literal::Str("two".to_string())),
2117            ),
2118            MatchArm::new(
2119                Pattern::Wildcard,
2120                Expr::Lit(Literal::Str("many".to_string())),
2121            ),
2122        ],
2123    };
2124    assert!(expr.is_match());
2125    assert_eq!(expr.as_match().unwrap().1.len(), 4);
2126}
2127
2128#[test]
2129fn test_expr_match_with_var_binding() {
2130    let expr = Expr::Match {
2131        scrutinee: Box::new(Expr::Var("x".to_string())),
2132        arms: vec![
2133            MatchArm::new(
2134                Pattern::Literal(Literal::Int(0)),
2135                Expr::Lit(Literal::Str("zero".to_string())),
2136            ),
2137            MatchArm::new(Pattern::Var("n".to_string()), Expr::Var("n".to_string())),
2138        ],
2139    };
2140    assert!(expr.is_match());
2141    let (scrutinee, arms) = expr.as_match().unwrap();
2142    assert_eq!(scrutinee.as_var(), Some("x"));
2143    assert_eq!(arms.len(), 2);
2144    assert!(arms[1].is_var());
2145}
2146
2147#[test]
2148fn test_expr_match_with_tuple_pattern() {
2149    let expr = Expr::Match {
2150        scrutinee: Box::new(Expr::Var("pair".to_string())),
2151        arms: vec![
2152            MatchArm::new(
2153                Pattern::Tuple(vec![
2154                    Pattern::Literal(Literal::Int(0)),
2155                    Pattern::Literal(Literal::Int(0)),
2156                ]),
2157                Expr::Lit(Literal::Str("origin".to_string())),
2158            ),
2159            MatchArm::new(
2160                Pattern::Tuple(vec![
2161                    Pattern::Var("x".to_string()),
2162                    Pattern::Var("y".to_string()),
2163                ]),
2164                Expr::Lit(Literal::Str("point".to_string())),
2165            ),
2166        ],
2167    };
2168    assert!(expr.is_match());
2169    let (_, arms) = expr.as_match().unwrap();
2170    assert_eq!(arms.len(), 2);
2171    assert!(arms[0].pattern.is_tuple());
2172}
2173
2174#[test]
2175fn test_expr_match_nested_in_let() {
2176    let expr = Expr::Let {
2177        name: "result".to_string(),
2178        value: Box::new(Expr::Match {
2179            scrutinee: Box::new(Expr::Var("x".to_string())),
2180            arms: vec![
2181                MatchArm::new(
2182                    Pattern::Literal(Literal::Int(0)),
2183                    Expr::Lit(Literal::Int(1)),
2184                ),
2185                MatchArm::new(Pattern::Wildcard, Expr::Lit(Literal::Int(0))),
2186            ],
2187        }),
2188        body: Box::new(Expr::Var("result".to_string())),
2189    };
2190    assert!(expr.is_let());
2191    if let Expr::Let { value, .. } = &expr {
2192        assert!(value.is_match());
2193    }
2194}
2195
2196#[test]
2197fn test_expr_match_with_bool_patterns() {
2198    let expr = Expr::Match {
2199        scrutinee: Box::new(Expr::Var("flag".to_string())),
2200        arms: vec![
2201            MatchArm::new(
2202                Pattern::Literal(Literal::Bool(true)),
2203                Expr::Lit(Literal::Str("yes".to_string())),
2204            ),
2205            MatchArm::new(
2206                Pattern::Literal(Literal::Bool(false)),
2207                Expr::Lit(Literal::Str("no".to_string())),
2208            ),
2209        ],
2210    };
2211    assert!(expr.is_match());
2212}
2213
2214#[test]
2215fn test_expr_match_as_match() {
2216    let expr = Expr::Match {
2217        scrutinee: Box::new(Expr::Var("x".to_string())),
2218        arms: vec![MatchArm::new(
2219            Pattern::Wildcard,
2220            Expr::Lit(Literal::Int(42)),
2221        )],
2222    };
2223    let result = expr.as_match();
2224    assert!(result.is_some());
2225    let (scrutinee, arms) = result.unwrap();
2226    assert_eq!(scrutinee.as_var(), Some("x"));
2227    assert_eq!(arms.len(), 1);
2228}
2229
2230#[test]
2231fn test_expr_match_as_match_none() {
2232    let expr = Expr::Lit(Literal::Int(42));
2233    assert_eq!(expr.as_match(), None);
2234}
2235
2236#[test]
2237fn test_expr_match_clone() {
2238    let expr1 = Expr::Match {
2239        scrutinee: Box::new(Expr::Var("x".to_string())),
2240        arms: vec![MatchArm::new(
2241            Pattern::Wildcard,
2242            Expr::Lit(Literal::Int(42)),
2243        )],
2244    };
2245    let expr2 = expr1.clone();
2246    assert_eq!(expr1, expr2);
2247}
2248
2249#[test]
2250fn test_expr_match_equality() {
2251    let expr1 = Expr::Match {
2252        scrutinee: Box::new(Expr::Var("x".to_string())),
2253        arms: vec![MatchArm::new(
2254            Pattern::Wildcard,
2255            Expr::Lit(Literal::Int(42)),
2256        )],
2257    };
2258    let expr2 = Expr::Match {
2259        scrutinee: Box::new(Expr::Var("x".to_string())),
2260        arms: vec![MatchArm::new(
2261            Pattern::Wildcard,
2262            Expr::Lit(Literal::Int(42)),
2263        )],
2264    };
2265    assert_eq!(expr1, expr2);
2266}
2267
2268#[test]
2269fn test_expr_match_complex_body() {
2270    let expr = Expr::Match {
2271        scrutinee: Box::new(Expr::Var("x".to_string())),
2272        arms: vec![
2273            MatchArm::new(
2274                Pattern::Literal(Literal::Int(0)),
2275                Expr::BinOp {
2276                    op: BinOp::Add,
2277                    left: Box::new(Expr::Lit(Literal::Int(1))),
2278                    right: Box::new(Expr::Lit(Literal::Int(2))),
2279                },
2280            ),
2281            MatchArm::new(Pattern::Wildcard, Expr::Lit(Literal::Int(0))),
2282        ],
2283    };
2284    assert!(expr.is_match());
2285}