ruchy/frontend/
ast.rs

1//! Abstract Syntax Tree definitions for Ruchy
2
3use serde::{Deserialize, Serialize};
4use std::fmt;
5
6/// Source location tracking for error reporting
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
8pub struct Span {
9    pub start: usize,
10    pub end: usize,
11}
12
13impl Span {
14    #[must_use]
15    pub fn new(start: usize, end: usize) -> Self {
16        Self { start, end }
17    }
18
19    #[must_use]
20    pub fn merge(self, other: Self) -> Self {
21        Self {
22            start: self.start.min(other.start),
23            end: self.end.max(other.end),
24        }
25    }
26}
27
28/// Catch clause in try-catch blocks
29#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
30pub struct CatchClause {
31    pub pattern: Pattern,  // The error pattern to match
32    pub body: Box<Expr>,    // The catch block body
33}
34
35/// The main AST node type for expressions
36#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
37pub struct Expr {
38    pub kind: ExprKind,
39    pub span: Span,
40    pub attributes: Vec<Attribute>,
41}
42
43impl Expr {
44    #[must_use]
45    pub fn new(kind: ExprKind, span: Span) -> Self {
46        Self {
47            kind,
48            span,
49            attributes: Vec::new(),
50        }
51    }
52
53    #[must_use]
54    pub fn with_attributes(kind: ExprKind, span: Span, attributes: Vec<Attribute>) -> Self {
55        Self {
56            kind,
57            span,
58            attributes,
59        }
60    }
61}
62
63#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
64pub enum ExprKind {
65    Literal(Literal),
66    Identifier(String),
67    QualifiedName {
68        module: String,
69        name: String,
70    },
71    StringInterpolation {
72        parts: Vec<StringPart>,
73    },
74    Binary {
75        left: Box<Expr>,
76        op: BinaryOp,
77        right: Box<Expr>,
78    },
79    Unary {
80        op: UnaryOp,
81        operand: Box<Expr>,
82    },
83    Throw {
84        expr: Box<Expr>,
85    },
86    TryCatch {
87        try_block: Box<Expr>,
88        catch_clauses: Vec<CatchClause>,
89        finally_block: Option<Box<Expr>>,
90    },
91    Ok {
92        value: Box<Expr>,
93    },
94    Err {
95        error: Box<Expr>,
96    },
97    Some {
98        value: Box<Expr>,
99    },
100    None,
101    TypeCast {
102        expr: Box<Expr>,
103        target_type: String,
104    },
105    Try {
106        expr: Box<Expr>,
107    },
108    Await {
109        expr: Box<Expr>,
110    },
111    AsyncBlock {
112        body: Box<Expr>,
113    },
114    If {
115        condition: Box<Expr>,
116        then_branch: Box<Expr>,
117        else_branch: Option<Box<Expr>>,
118    },
119    IfLet {
120        pattern: Pattern,
121        expr: Box<Expr>,
122        then_branch: Box<Expr>,
123        else_branch: Option<Box<Expr>>,
124    },
125    Let {
126        name: String,
127        type_annotation: Option<Type>,
128        value: Box<Expr>,
129        body: Box<Expr>,
130        is_mutable: bool,
131    },
132    LetPattern {
133        pattern: Pattern,
134        type_annotation: Option<Type>,
135        value: Box<Expr>,
136        body: Box<Expr>,
137        is_mutable: bool,
138    },
139    Function {
140        name: String,
141        type_params: Vec<String>,
142        params: Vec<Param>,
143        return_type: Option<Type>,
144        body: Box<Expr>,
145        is_async: bool,
146        is_pub: bool,
147    },
148    Lambda {
149        params: Vec<Param>,
150        body: Box<Expr>,
151    },
152    Struct {
153        name: String,
154        type_params: Vec<String>,
155        fields: Vec<StructField>,
156        is_pub: bool,
157    },
158    Enum {
159        name: String,
160        type_params: Vec<String>,
161        variants: Vec<EnumVariant>,
162        is_pub: bool,
163    },
164    StructLiteral {
165        name: String,
166        fields: Vec<(String, Expr)>,
167    },
168    ObjectLiteral {
169        fields: Vec<ObjectField>,
170    },
171    FieldAccess {
172        object: Box<Expr>,
173        field: String,
174    },
175    OptionalFieldAccess {
176        object: Box<Expr>,
177        field: String,
178    },
179    IndexAccess {
180        object: Box<Expr>,
181        index: Box<Expr>,
182    },
183    Slice {
184        object: Box<Expr>,
185        start: Option<Box<Expr>>,
186        end: Option<Box<Expr>>,
187    },
188    Trait {
189        name: String,
190        type_params: Vec<String>,
191        methods: Vec<TraitMethod>,
192        is_pub: bool,
193    },
194    Impl {
195        type_params: Vec<String>,
196        trait_name: Option<String>,
197        for_type: String,
198        methods: Vec<ImplMethod>,
199        is_pub: bool,
200    },
201    Actor {
202        name: String,
203        state: Vec<StructField>,
204        handlers: Vec<ActorHandler>,
205    },
206    Send {
207        actor: Box<Expr>,
208        message: Box<Expr>,
209    },
210    Command {
211        program: String,
212        args: Vec<String>,
213        env: Vec<(String, String)>,
214        working_dir: Option<String>,
215    },
216    Ask {
217        actor: Box<Expr>,
218        message: Box<Expr>,
219        timeout: Option<Box<Expr>>,
220    },
221    /// Fire-and-forget actor send (left <- right)
222    ActorSend {
223        actor: Box<Expr>,
224        message: Box<Expr>,
225    },
226    /// Actor query with reply (left <? right)
227    ActorQuery {
228        actor: Box<Expr>,
229        message: Box<Expr>,
230    },
231    Call {
232        func: Box<Expr>,
233        args: Vec<Expr>,
234    },
235    Macro {
236        name: String,
237        args: Vec<Expr>,
238    },
239    MethodCall {
240        receiver: Box<Expr>,
241        method: String,
242        args: Vec<Expr>,
243    },
244    OptionalMethodCall {
245        receiver: Box<Expr>,
246        method: String,
247        args: Vec<Expr>,
248    },
249    Block(Vec<Expr>),
250    Pipeline {
251        expr: Box<Expr>,
252        stages: Vec<PipelineStage>,
253    },
254    Match {
255        expr: Box<Expr>,
256        arms: Vec<MatchArm>,
257    },
258    List(Vec<Expr>),
259    ArrayInit {
260        value: Box<Expr>,
261        size: Box<Expr>,
262    },
263    Tuple(Vec<Expr>),
264    Spread {
265        expr: Box<Expr>,
266    },
267    ListComprehension {
268        element: Box<Expr>,
269        variable: String,
270        iterable: Box<Expr>,
271        condition: Option<Box<Expr>>,
272    },
273    DataFrame {
274        columns: Vec<DataFrameColumn>,
275    },
276    DataFrameOperation {
277        source: Box<Expr>,
278        operation: DataFrameOp,
279    },
280    For {
281        var: String,  // Keep for backward compatibility
282        pattern: Option<Pattern>,  // New: Support destructuring patterns
283        iter: Box<Expr>,
284        body: Box<Expr>,
285    },
286    While {
287        condition: Box<Expr>,
288        body: Box<Expr>,
289    },
290    WhileLet {
291        pattern: Pattern,
292        expr: Box<Expr>,
293        body: Box<Expr>,
294    },
295    Loop {
296        body: Box<Expr>,
297    },
298    Range {
299        start: Box<Expr>,
300        end: Box<Expr>,
301        inclusive: bool,
302    },
303    Import {
304        path: String,
305        items: Vec<ImportItem>,
306    },
307    Module {
308        name: String,
309        body: Box<Expr>,
310    },
311    Export {
312        items: Vec<String>,
313    },
314    Break {
315        label: Option<String>,
316    },
317    Continue {
318        label: Option<String>,
319    },
320    Return {
321        value: Option<Box<Expr>>,
322    },
323    Assign {
324        target: Box<Expr>,
325        value: Box<Expr>,
326    },
327    CompoundAssign {
328        target: Box<Expr>,
329        op: BinaryOp,
330        value: Box<Expr>,
331    },
332    PreIncrement {
333        target: Box<Expr>,
334    },
335    PostIncrement {
336        target: Box<Expr>,
337    },
338    PreDecrement {
339        target: Box<Expr>,
340    },
341    PostDecrement {
342        target: Box<Expr>,
343    },
344    Extension {
345        target_type: String,
346        methods: Vec<ImplMethod>,
347    },
348}
349
350#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
351pub enum Literal {
352    Integer(i64),
353    Float(f64),
354    String(String),
355    Bool(bool),
356    Char(char),
357    Unit,
358}
359
360impl Literal {
361    /// Convert a REPL Value to a Literal (for synthetic expressions)
362    pub fn from_value(value: &crate::runtime::repl::Value) -> Self {
363        use crate::runtime::repl::Value;
364        match value {
365            Value::Int(i) => Literal::Integer(*i),
366            Value::Float(f) => Literal::Float(*f),
367            Value::String(s) => Literal::String(s.clone()),
368            Value::Bool(b) => Literal::Bool(*b),
369            Value::Char(c) => Literal::Char(*c),
370            Value::Unit => Literal::Unit,
371            _ => Literal::Unit, // Fallback for complex types
372        }
373    }
374}
375
376/// String interpolation parts - either literal text or an expression
377#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
378pub enum StringPart {
379    /// Literal text portion of the string
380    Text(String),
381    /// Expression to be interpolated without format specifier
382    Expr(Box<Expr>),
383    /// Expression with format specifier (e.g., {value:.2})
384    ExprWithFormat {
385        expr: Box<Expr>,
386        format_spec: String,
387    },
388}
389
390#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
391pub enum BinaryOp {
392    // Arithmetic
393    Add,
394    Subtract,
395    Multiply,
396    Divide,
397    Modulo,
398    Power,
399
400    // Comparison
401    Equal,
402    NotEqual,
403    Less,
404    LessEqual,
405    Greater,
406    GreaterEqual,
407
408    // Logical
409    And,
410    Or,
411    NullCoalesce,
412
413    // Bitwise
414    BitwiseAnd,
415    BitwiseOr,
416    BitwiseXor,
417    LeftShift,
418}
419
420#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
421pub enum UnaryOp {
422    Not,
423    Negate,
424    BitwiseNot,
425    Reference,
426}
427
428#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
429pub struct Param {
430    pub pattern: Pattern,
431    pub ty: Type,
432    pub span: Span,
433    pub is_mutable: bool,
434    pub default_value: Option<Box<Expr>>,
435}
436
437impl Param {
438    /// Get the primary name from this parameter pattern.
439    /// For complex patterns, this returns the first/primary identifier.
440    /// For simple patterns, this returns the identifier itself.
441    #[must_use]
442    pub fn name(&self) -> String {
443        self.pattern.primary_name()
444    }
445}
446
447#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
448pub struct StructField {
449    pub name: String,
450    pub ty: Type,
451    pub is_pub: bool,
452}
453
454#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
455pub struct EnumVariant {
456    pub name: String,
457    pub fields: Option<Vec<Type>>, // None for unit variant, Some for tuple variant
458    pub discriminant: Option<i64>, // Explicit discriminant value for TypeScript compatibility
459}
460
461#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
462pub enum ObjectField {
463    KeyValue { key: String, value: Expr },
464    Spread { expr: Expr },
465}
466
467#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
468pub struct TraitMethod {
469    pub name: String,
470    pub params: Vec<Param>,
471    pub return_type: Option<Type>,
472    pub body: Option<Box<Expr>>, // None for method signatures, Some for default implementations
473    pub is_pub: bool,
474}
475
476#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
477pub struct ImplMethod {
478    pub name: String,
479    pub params: Vec<Param>,
480    pub return_type: Option<Type>,
481    pub body: Box<Expr>,
482    pub is_pub: bool,
483}
484
485#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
486pub struct ActorHandler {
487    pub message_type: String,
488    pub params: Vec<Param>,
489    pub body: Box<Expr>,
490}
491
492#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
493pub struct Type {
494    pub kind: TypeKind,
495    pub span: Span,
496}
497
498#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
499pub enum TypeKind {
500    Named(String),
501    Generic { base: String, params: Vec<Type> },
502    Optional(Box<Type>),
503    List(Box<Type>),
504    Array { elem_type: Box<Type>, size: usize },
505    Tuple(Vec<Type>),
506    Function { params: Vec<Type>, ret: Box<Type> },
507    DataFrame { columns: Vec<(String, Type)> },
508    Series { dtype: Box<Type> },
509    Reference { is_mut: bool, inner: Box<Type> },
510}
511
512#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
513pub struct PipelineStage {
514    pub op: Box<Expr>,
515    pub span: Span,
516}
517
518#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
519pub struct MatchArm {
520    pub pattern: Pattern,
521    pub guard: Option<Box<Expr>>,  // Pattern guard: if condition
522    pub body: Box<Expr>,
523    pub span: Span,
524}
525
526#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
527pub enum Pattern {
528    Wildcard,
529    Literal(Literal),
530    Identifier(String),
531    QualifiedName(Vec<String>), // For patterns like Ordering::Less
532    Tuple(Vec<Pattern>),
533    List(Vec<Pattern>),
534    Struct {
535        name: String,
536        fields: Vec<StructPatternField>,
537        has_rest: bool,
538    },
539    Range {
540        start: Box<Pattern>,
541        end: Box<Pattern>,
542        inclusive: bool,
543    },
544    Or(Vec<Pattern>),
545    Rest, // For ... patterns
546    RestNamed(String), // For ..name patterns
547    WithDefault {
548        pattern: Box<Pattern>,
549        default: Box<Expr>,
550    }, // For patterns with default values like a = 10
551    Ok(Box<Pattern>),
552    Err(Box<Pattern>),
553    Some(Box<Pattern>),
554    None,
555}
556
557impl Pattern {
558    /// Get the primary identifier name from this pattern.
559    /// For complex patterns, returns the first/most significant identifier.
560    #[must_use]
561    pub fn primary_name(&self) -> String {
562        match self {
563            Pattern::Identifier(name) => name.clone(),
564            Pattern::QualifiedName(path) => path.join("::"),
565            Pattern::Tuple(patterns) => {
566                // Return the name of the first pattern
567                patterns
568                    .first()
569                    .map_or_else(|| "_tuple".to_string(), Pattern::primary_name)
570            }
571            Pattern::List(patterns) => {
572                // Return the name of the first pattern
573                patterns
574                    .first()
575                    .map_or_else(|| "_list".to_string(), Pattern::primary_name)
576            }
577            Pattern::Struct { name, fields, .. } => {
578                // Return the struct type name, or first field name if anonymous
579                if name.is_empty() {
580                    fields.first().map_or_else(|| "_struct".to_string(), |f| f.name.clone())
581                } else {
582                    name.clone()
583                }
584            }
585            Pattern::Ok(inner) | Pattern::Err(inner) | Pattern::Some(inner) => inner.primary_name(),
586            Pattern::None => "_none".to_string(),
587            Pattern::Or(patterns) => {
588                // Return the name of the first pattern
589                patterns
590                    .first()
591                    .map_or_else(|| "_or".to_string(), Pattern::primary_name)
592            }
593            Pattern::Wildcard => "_".to_string(),
594            Pattern::Rest => "_rest".to_string(),
595            Pattern::RestNamed(name) => name.clone(),
596            Pattern::WithDefault { pattern, .. } => pattern.primary_name(),
597            Pattern::Literal(lit) => format!("_literal_{lit:?}"),
598            Pattern::Range { .. } => "_range".to_string(),
599        }
600    }
601}
602
603#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
604pub struct StructPatternField {
605    pub name: String,
606    pub pattern: Option<Pattern>, // None for shorthand like { x } instead of { x: x }
607}
608
609
610/// Custom error type definition
611#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
612pub struct ErrorTypeDef {
613    pub name: String,
614    pub fields: Vec<StructField>,
615    pub extends: Option<String>, // Parent error type
616}
617
618/// Attribute for annotating expressions (e.g., `#[property]`)
619#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
620pub struct Attribute {
621    pub name: String,
622    pub args: Vec<String>,
623    pub span: Span,
624}
625
626#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
627pub struct DataFrameColumn {
628    pub name: String,
629    pub values: Vec<Expr>,
630}
631
632#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
633pub enum DataFrameOp {
634    Filter(Box<Expr>),
635    Select(Vec<String>),
636    GroupBy(Vec<String>),
637    Sort(Vec<String>),
638    Join {
639        other: Box<Expr>,
640        on: Vec<String>,
641        how: JoinType,
642    },
643    Aggregate(Vec<AggregateOp>),
644    Limit(usize),
645    Head(usize),
646    Tail(usize),
647}
648
649#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
650pub enum JoinType {
651    Inner,
652    Left,
653    Right,
654    Outer,
655}
656
657#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
658pub enum ImportItem {
659    /// Import a specific name: `use std::collections::HashMap`
660    Named(String),
661    /// Import with alias: `use std::collections::HashMap as Map`
662    Aliased { name: String, alias: String },
663    /// Import all: `use std::collections::*`
664    Wildcard,
665}
666
667impl ImportItem {
668    /// Check if this import is for a URL module
669    pub fn is_url_import(path: &str) -> bool {
670        path.starts_with("https://") || path.starts_with("http://")
671    }
672}
673
674#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
675pub enum AggregateOp {
676    Sum(String),
677    Mean(String),
678    Min(String),
679    Max(String),
680    Count(String),
681    Std(String),
682    Var(String),
683}
684
685impl fmt::Display for BinaryOp {
686    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
687        match self {
688            Self::Add => write!(f, "+"),
689            Self::Subtract => write!(f, "-"),
690            Self::Multiply => write!(f, "*"),
691            Self::Divide => write!(f, "/"),
692            Self::Modulo => write!(f, "%"),
693            Self::Power => write!(f, "**"),
694            Self::Equal => write!(f, "=="),
695            Self::NotEqual => write!(f, "!="),
696            Self::Less => write!(f, "<"),
697            Self::LessEqual => write!(f, "<="),
698            Self::Greater => write!(f, ">"),
699            Self::GreaterEqual => write!(f, ">="),
700            Self::And => write!(f, "&&"),
701            Self::Or => write!(f, "||"),
702            Self::NullCoalesce => write!(f, "??"),
703            Self::BitwiseAnd => write!(f, "&"),
704            Self::BitwiseOr => write!(f, "|"),
705            Self::BitwiseXor => write!(f, "^"),
706            Self::LeftShift => write!(f, "<<"),
707        }
708    }
709}
710
711impl fmt::Display for UnaryOp {
712    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
713        match self {
714            Self::Not => write!(f, "!"),
715            Self::Negate => write!(f, "-"),
716            Self::BitwiseNot => write!(f, "~"),
717            Self::Reference => write!(f, "&"),
718        }
719    }
720}
721
722#[cfg(test)]
723#[allow(clippy::unwrap_used, clippy::panic, clippy::expect_used)]
724#[allow(clippy::unwrap_used)]
725#[allow(clippy::panic)]
726mod tests {
727    use super::*;
728    use proptest::prelude::*;
729
730    proptest! {
731        #[test]
732        fn test_span_merge(start1 in 0usize..1000, end1 in 0usize..1000,
733                          start2 in 0usize..1000, end2 in 0usize..1000) {
734            let span1 = Span::new(start1, end1);
735            let span2 = Span::new(start2, end2);
736            let merged = span1.merge(span2);
737
738            prop_assert!(merged.start <= span1.start);
739            prop_assert!(merged.start <= span2.start);
740            prop_assert!(merged.end >= span1.end);
741            prop_assert!(merged.end >= span2.end);
742        }
743    }
744
745    #[test]
746    fn test_ast_size() {
747        // Track AST node sizes for optimization
748        let expr_size = std::mem::size_of::<Expr>();
749        let kind_size = std::mem::size_of::<ExprKind>();
750        // Current sizes are larger than ideal but acceptable for MVP
751        // Future optimization: Use arena allocation and indices
752        assert!(expr_size <= 192, "Expr too large: {expr_size} bytes");
753        assert!(kind_size <= 152, "ExprKind too large: {kind_size} bytes");
754    }
755
756    #[test]
757    fn test_span_creation() {
758        let span = Span::new(10, 20);
759        assert_eq!(span.start, 10);
760        assert_eq!(span.end, 20);
761    }
762
763    #[test]
764    fn test_span_merge_simple() {
765        let span1 = Span::new(5, 10);
766        let span2 = Span::new(8, 15);
767        let merged = span1.merge(span2);
768        assert_eq!(merged.start, 5);
769        assert_eq!(merged.end, 15);
770    }
771
772    #[test]
773    fn test_span_merge_disjoint() {
774        let span1 = Span::new(0, 5);
775        let span2 = Span::new(10, 15);
776        let merged = span1.merge(span2);
777        assert_eq!(merged.start, 0);
778        assert_eq!(merged.end, 15);
779    }
780
781    #[test]
782    fn test_expr_creation() {
783        let span = Span::new(0, 10);
784        let expr = Expr::new(ExprKind::Literal(Literal::Integer(42)), span);
785        assert_eq!(expr.span.start, 0);
786        assert_eq!(expr.span.end, 10);
787        match expr.kind {
788            ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 42),
789            _ => panic!("Wrong expression kind"),
790        }
791    }
792
793    #[test]
794    fn test_literal_variants() {
795        let literals = vec![
796            Literal::Integer(42),
797            #[allow(clippy::approx_constant)]
798            Literal::Float(3.14), // Not PI, just a test value
799            Literal::String("hello".to_string()),
800            Literal::Bool(true),
801            Literal::Unit,
802        ];
803
804        for lit in literals {
805            let expr = Expr::new(ExprKind::Literal(lit.clone()), Span::new(0, 0));
806            match expr.kind {
807                ExprKind::Literal(l) => assert_eq!(l, lit),
808                _ => panic!("Expected literal"),
809            }
810        }
811    }
812
813    #[test]
814    fn test_binary_op_display() {
815        assert_eq!(BinaryOp::Add.to_string(), "+");
816        assert_eq!(BinaryOp::Subtract.to_string(), "-");
817        assert_eq!(BinaryOp::Multiply.to_string(), "*");
818        assert_eq!(BinaryOp::Divide.to_string(), "/");
819        assert_eq!(BinaryOp::Modulo.to_string(), "%");
820        assert_eq!(BinaryOp::Power.to_string(), "**");
821        assert_eq!(BinaryOp::Equal.to_string(), "==");
822        assert_eq!(BinaryOp::NotEqual.to_string(), "!=");
823        assert_eq!(BinaryOp::Less.to_string(), "<");
824        assert_eq!(BinaryOp::LessEqual.to_string(), "<=");
825        assert_eq!(BinaryOp::Greater.to_string(), ">");
826        assert_eq!(BinaryOp::GreaterEqual.to_string(), ">=");
827        assert_eq!(BinaryOp::And.to_string(), "&&");
828        assert_eq!(BinaryOp::Or.to_string(), "||");
829        assert_eq!(BinaryOp::BitwiseAnd.to_string(), "&");
830        assert_eq!(BinaryOp::BitwiseOr.to_string(), "|");
831        assert_eq!(BinaryOp::BitwiseXor.to_string(), "^");
832        assert_eq!(BinaryOp::LeftShift.to_string(), "<<");
833    }
834
835    #[test]
836    fn test_unary_op_display() {
837        assert_eq!(UnaryOp::Not.to_string(), "!");
838        assert_eq!(UnaryOp::Negate.to_string(), "-");
839        assert_eq!(UnaryOp::BitwiseNot.to_string(), "~");
840        assert_eq!(UnaryOp::Reference.to_string(), "&");
841    }
842
843    #[test]
844    fn test_binary_expression() {
845        let left = Box::new(Expr::new(
846            ExprKind::Literal(Literal::Integer(1)),
847            Span::new(0, 1),
848        ));
849        let right = Box::new(Expr::new(
850            ExprKind::Literal(Literal::Integer(2)),
851            Span::new(4, 5),
852        ));
853        let expr = Expr::new(
854            ExprKind::Binary {
855                left,
856                op: BinaryOp::Add,
857                right,
858            },
859            Span::new(0, 5),
860        );
861
862        match expr.kind {
863            ExprKind::Binary {
864                left: l,
865                op,
866                right: r,
867            } => {
868                assert_eq!(op, BinaryOp::Add);
869                match l.kind {
870                    ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 1),
871                    _ => panic!("Wrong left operand"),
872                }
873                match r.kind {
874                    ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 2),
875                    _ => panic!("Wrong right operand"),
876                }
877            }
878            _ => panic!("Expected binary expression"),
879        }
880    }
881
882    #[test]
883    fn test_unary_expression() {
884        let operand = Box::new(Expr::new(
885            ExprKind::Literal(Literal::Bool(true)),
886            Span::new(1, 5),
887        ));
888        let expr = Expr::new(
889            ExprKind::Unary {
890                op: UnaryOp::Not,
891                operand,
892            },
893            Span::new(0, 5),
894        );
895
896        match expr.kind {
897            ExprKind::Unary { op, operand } => {
898                assert_eq!(op, UnaryOp::Not);
899                match operand.kind {
900                    ExprKind::Literal(Literal::Bool(b)) => assert!(b),
901                    _ => panic!("Wrong operand"),
902                }
903            }
904            _ => panic!("Expected unary expression"),
905        }
906    }
907
908    #[test]
909    fn test_if_expression() {
910        let condition = Box::new(Expr::new(
911            ExprKind::Literal(Literal::Bool(true)),
912            Span::new(3, 7),
913        ));
914        let then_branch = Box::new(Expr::new(
915            ExprKind::Literal(Literal::Integer(1)),
916            Span::new(10, 11),
917        ));
918        let else_branch = Some(Box::new(Expr::new(
919            ExprKind::Literal(Literal::Integer(2)),
920            Span::new(17, 18),
921        )));
922
923        let expr = Expr::new(
924            ExprKind::If {
925                condition,
926                then_branch,
927                else_branch,
928            },
929            Span::new(0, 18),
930        );
931
932        match expr.kind {
933            ExprKind::If {
934                condition: c,
935                then_branch: t,
936                else_branch: e,
937            } => {
938                match c.kind {
939                    ExprKind::Literal(Literal::Bool(b)) => assert!(b),
940                    _ => panic!("Wrong condition"),
941                }
942                match t.kind {
943                    ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 1),
944                    _ => panic!("Wrong then branch"),
945                }
946                assert!(e.is_some());
947                if let Some(else_expr) = e {
948                    match else_expr.kind {
949                        ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 2),
950                        _ => panic!("Wrong else branch"),
951                    }
952                }
953            }
954            _ => panic!("Expected if expression"),
955        }
956    }
957
958    #[test]
959    fn test_let_expression() {
960        let value = Box::new(Expr::new(
961            ExprKind::Literal(Literal::Integer(42)),
962            Span::new(8, 10),
963        ));
964        let body = Box::new(Expr::new(
965            ExprKind::Identifier("x".to_string()),
966            Span::new(14, 15),
967        ));
968
969        let expr = Expr::new(
970            ExprKind::Let {
971                name: "x".to_string(),
972                type_annotation: None,
973                value,
974                body,
975                is_mutable: false,
976            },
977            Span::new(0, 15),
978        );
979
980        match expr.kind {
981            ExprKind::Let {
982                name,
983                value: v,
984                body: b,
985                ..
986            } => {
987                assert_eq!(name, "x");
988                match v.kind {
989                    ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 42),
990                    _ => panic!("Wrong value"),
991                }
992                match b.kind {
993                    ExprKind::Identifier(id) => assert_eq!(id, "x"),
994                    _ => panic!("Wrong body"),
995                }
996            }
997            _ => panic!("Expected let expression"),
998        }
999    }
1000
1001    #[test]
1002    fn test_function_expression() {
1003        let params = vec![Param {
1004            pattern: Pattern::Identifier("x".to_string()),
1005            ty: Type {
1006                kind: TypeKind::Named("i32".to_string()),
1007                span: Span::new(10, 13),
1008            },
1009            span: Span::new(8, 13),
1010            is_mutable: false,
1011            default_value: None,
1012        }];
1013        let body = Box::new(Expr::new(
1014            ExprKind::Identifier("x".to_string()),
1015            Span::new(20, 21),
1016        ));
1017
1018        let expr = Expr::new(
1019            ExprKind::Function {
1020                name: "identity".to_string(),
1021                type_params: vec![],
1022                params,
1023                return_type: Some(Type {
1024                    kind: TypeKind::Named("i32".to_string()),
1025                    span: Span::new(16, 19),
1026                }),
1027                body,
1028                is_async: false,
1029                is_pub: false,
1030            },
1031            Span::new(0, 22),
1032        );
1033
1034        match expr.kind {
1035            ExprKind::Function {
1036                name,
1037                params: p,
1038                return_type,
1039                body: b,
1040                ..
1041            } => {
1042                assert_eq!(name, "identity");
1043                assert_eq!(p.len(), 1);
1044                assert_eq!(p[0].name(), "x");
1045                assert!(return_type.is_some());
1046                match b.kind {
1047                    ExprKind::Identifier(id) => assert_eq!(id, "x"),
1048                    _ => panic!("Wrong body"),
1049                }
1050            }
1051            _ => panic!("Expected function expression"),
1052        }
1053    }
1054
1055    #[test]
1056    fn test_call_expression() {
1057        let func = Box::new(Expr::new(
1058            ExprKind::Identifier("add".to_string()),
1059            Span::new(0, 3),
1060        ));
1061        let args = vec![
1062            Expr::new(ExprKind::Literal(Literal::Integer(1)), Span::new(4, 5)),
1063            Expr::new(ExprKind::Literal(Literal::Integer(2)), Span::new(7, 8)),
1064        ];
1065
1066        let expr = Expr::new(ExprKind::Call { func, args }, Span::new(0, 9));
1067
1068        match expr.kind {
1069            ExprKind::Call { func: f, args: a } => {
1070                match f.kind {
1071                    ExprKind::Identifier(name) => assert_eq!(name, "add"),
1072                    _ => panic!("Wrong function"),
1073                }
1074                assert_eq!(a.len(), 2);
1075            }
1076            _ => panic!("Expected call expression"),
1077        }
1078    }
1079
1080    #[test]
1081    fn test_block_expression() {
1082        let exprs = vec![
1083            Expr::new(ExprKind::Literal(Literal::Integer(1)), Span::new(2, 3)),
1084            Expr::new(ExprKind::Literal(Literal::Integer(2)), Span::new(5, 6)),
1085        ];
1086
1087        let expr = Expr::new(ExprKind::Block(exprs), Span::new(0, 8));
1088
1089        match expr.kind {
1090            ExprKind::Block(block) => {
1091                assert_eq!(block.len(), 2);
1092            }
1093            _ => panic!("Expected block expression"),
1094        }
1095    }
1096
1097    #[test]
1098    fn test_list_expression() {
1099        let items = vec![
1100            Expr::new(ExprKind::Literal(Literal::Integer(1)), Span::new(1, 2)),
1101            Expr::new(ExprKind::Literal(Literal::Integer(2)), Span::new(4, 5)),
1102            Expr::new(ExprKind::Literal(Literal::Integer(3)), Span::new(7, 8)),
1103        ];
1104
1105        let expr = Expr::new(ExprKind::List(items), Span::new(0, 9));
1106
1107        match expr.kind {
1108            ExprKind::List(list) => {
1109                assert_eq!(list.len(), 3);
1110            }
1111            _ => panic!("Expected list expression"),
1112        }
1113    }
1114
1115    #[test]
1116    fn test_for_expression() {
1117        let iter = Box::new(Expr::new(
1118            ExprKind::Range {
1119                start: Box::new(Expr::new(
1120                    ExprKind::Literal(Literal::Integer(0)),
1121                    Span::new(10, 11),
1122                )),
1123                end: Box::new(Expr::new(
1124                    ExprKind::Literal(Literal::Integer(10)),
1125                    Span::new(13, 15),
1126                )),
1127                inclusive: false,
1128            },
1129            Span::new(10, 15),
1130        ));
1131        let body = Box::new(Expr::new(
1132            ExprKind::Identifier("i".to_string()),
1133            Span::new(20, 21),
1134        ));
1135
1136        let expr = Expr::new(
1137            ExprKind::For {
1138                var: "i".to_string(),
1139                pattern: None,
1140                iter,
1141                body,
1142            },
1143            Span::new(0, 22),
1144        );
1145
1146        match expr.kind {
1147            ExprKind::For {
1148                var,
1149                iter: it,
1150                body: b,
1151                ..
1152            } => {
1153                assert_eq!(var, "i");
1154                match it.kind {
1155                    ExprKind::Range { .. } => {}
1156                    _ => panic!("Wrong iterator"),
1157                }
1158                match b.kind {
1159                    ExprKind::Identifier(id) => assert_eq!(id, "i"),
1160                    _ => panic!("Wrong body"),
1161                }
1162            }
1163            _ => panic!("Expected for expression"),
1164        }
1165    }
1166
1167    #[test]
1168    fn test_range_expression() {
1169        let start = Box::new(Expr::new(
1170            ExprKind::Literal(Literal::Integer(1)),
1171            Span::new(0, 1),
1172        ));
1173        let end = Box::new(Expr::new(
1174            ExprKind::Literal(Literal::Integer(10)),
1175            Span::new(3, 5),
1176        ));
1177
1178        let expr = Expr::new(
1179            ExprKind::Range {
1180                start,
1181                end,
1182                inclusive: false,
1183            },
1184            Span::new(0, 5),
1185        );
1186
1187        match expr.kind {
1188            ExprKind::Range {
1189                start: s,
1190                end: e,
1191                inclusive,
1192            } => {
1193                assert!(!inclusive);
1194                match s.kind {
1195                    ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 1),
1196                    _ => panic!("Wrong start"),
1197                }
1198                match e.kind {
1199                    ExprKind::Literal(Literal::Integer(n)) => assert_eq!(n, 10),
1200                    _ => panic!("Wrong end"),
1201                }
1202            }
1203            _ => panic!("Expected range expression"),
1204        }
1205    }
1206
1207    #[test]
1208    fn test_import_expression() {
1209        let expr = Expr::new(
1210            ExprKind::Import {
1211                path: "std::collections".to_string(),
1212                items: vec![
1213                    ImportItem::Named("HashMap".to_string()),
1214                    ImportItem::Named("HashSet".to_string()),
1215                ],
1216            },
1217            Span::new(0, 30),
1218        );
1219
1220        match expr.kind {
1221            ExprKind::Import { path, items } => {
1222                assert_eq!(path, "std::collections");
1223                assert_eq!(items.len(), 2);
1224                assert_eq!(items[0], ImportItem::Named("HashMap".to_string()));
1225                assert_eq!(items[1], ImportItem::Named("HashSet".to_string()));
1226            }
1227            _ => panic!("Expected import expression"),
1228        }
1229    }
1230
1231    #[test]
1232    fn test_pipeline_expression() {
1233        let expr_start = Box::new(Expr::new(
1234            ExprKind::List(vec![
1235                Expr::new(ExprKind::Literal(Literal::Integer(1)), Span::new(1, 2)),
1236                Expr::new(ExprKind::Literal(Literal::Integer(2)), Span::new(4, 5)),
1237            ]),
1238            Span::new(0, 6),
1239        ));
1240        let stages = vec![PipelineStage {
1241            op: Box::new(Expr::new(
1242                ExprKind::Identifier("filter".to_string()),
1243                Span::new(10, 16),
1244            )),
1245            span: Span::new(10, 16),
1246        }];
1247
1248        let expr = Expr::new(
1249            ExprKind::Pipeline {
1250                expr: expr_start,
1251                stages,
1252            },
1253            Span::new(0, 16),
1254        );
1255
1256        match expr.kind {
1257            ExprKind::Pipeline { expr: e, stages: s } => {
1258                assert_eq!(s.len(), 1);
1259                match e.kind {
1260                    ExprKind::List(list) => assert_eq!(list.len(), 2),
1261                    _ => panic!("Wrong pipeline start"),
1262                }
1263            }
1264            _ => panic!("Expected pipeline expression"),
1265        }
1266    }
1267
1268    #[test]
1269    fn test_match_expression() {
1270        let expr_to_match = Box::new(Expr::new(
1271            ExprKind::Identifier("x".to_string()),
1272            Span::new(6, 7),
1273        ));
1274        let arms = vec![
1275            MatchArm {
1276                pattern: Pattern::Literal(Literal::Integer(1)),
1277                guard: None,
1278                body: Box::new(Expr::new(
1279                    ExprKind::Literal(Literal::String("one".to_string())),
1280                    Span::new(15, 20),
1281                )),
1282                span: Span::new(10, 20),
1283            },
1284            MatchArm {
1285                pattern: Pattern::Wildcard,
1286                guard: None,
1287                body: Box::new(Expr::new(
1288                    ExprKind::Literal(Literal::String("other".to_string())),
1289                    Span::new(28, 35),
1290                )),
1291                span: Span::new(25, 35),
1292            },
1293        ];
1294
1295        let expr = Expr::new(
1296            ExprKind::Match {
1297                expr: expr_to_match,
1298                arms,
1299            },
1300            Span::new(0, 36),
1301        );
1302
1303        match expr.kind {
1304            ExprKind::Match { expr: e, arms: a } => {
1305                assert_eq!(a.len(), 2);
1306                match e.kind {
1307                    ExprKind::Identifier(id) => assert_eq!(id, "x"),
1308                    _ => panic!("Wrong match expression"),
1309                }
1310            }
1311            _ => panic!("Expected match expression"),
1312        }
1313    }
1314
1315    #[test]
1316    fn test_pattern_variants() {
1317        let patterns = vec![
1318            Pattern::Wildcard,
1319            Pattern::Literal(Literal::Integer(42)),
1320            Pattern::Identifier("x".to_string()),
1321            Pattern::Tuple(vec![
1322                Pattern::Literal(Literal::Integer(1)),
1323                Pattern::Identifier("x".to_string()),
1324            ]),
1325            Pattern::List(vec![
1326                Pattern::Literal(Literal::Integer(1)),
1327                Pattern::Literal(Literal::Integer(2)),
1328            ]),
1329            Pattern::Struct {
1330                name: "Point".to_string(),
1331                fields: vec![StructPatternField {
1332                    name: "x".to_string(),
1333                    pattern: Some(Pattern::Identifier("x".to_string())),
1334                }],
1335                has_rest: false,
1336            },
1337            Pattern::Range {
1338                start: Box::new(Pattern::Literal(Literal::Integer(1))),
1339                end: Box::new(Pattern::Literal(Literal::Integer(10))),
1340                inclusive: true,
1341            },
1342            Pattern::Or(vec![
1343                Pattern::Literal(Literal::Integer(1)),
1344                Pattern::Literal(Literal::Integer(2)),
1345            ]),
1346            Pattern::Rest,
1347        ];
1348
1349        for pattern in patterns {
1350            match pattern {
1351                Pattern::Tuple(list) | Pattern::List(list) => assert!(!list.is_empty()),
1352                Pattern::Struct { fields, .. } => assert!(!fields.is_empty()),
1353                Pattern::Or(patterns) => assert!(!patterns.is_empty()),
1354                Pattern::Range { .. }
1355                | Pattern::Wildcard
1356                | Pattern::Literal(_)
1357                | Pattern::Identifier(_)
1358                | Pattern::Rest
1359                | Pattern::RestNamed(_)
1360                | Pattern::Ok(_)
1361                | Pattern::Err(_)
1362                | Pattern::Some(_)
1363                | Pattern::None
1364                | Pattern::QualifiedName(_) 
1365                | Pattern::WithDefault { .. } => {} // Simple patterns
1366            }
1367        }
1368    }
1369
1370    #[test]
1371    fn test_type_kinds() {
1372        let types = vec![
1373            Type {
1374                kind: TypeKind::Named("i32".to_string()),
1375                span: Span::new(0, 3),
1376            },
1377            Type {
1378                kind: TypeKind::Optional(Box::new(Type {
1379                    kind: TypeKind::Named("String".to_string()),
1380                    span: Span::new(0, 6),
1381                })),
1382                span: Span::new(0, 7),
1383            },
1384            Type {
1385                kind: TypeKind::List(Box::new(Type {
1386                    kind: TypeKind::Named("f64".to_string()),
1387                    span: Span::new(1, 4),
1388                })),
1389                span: Span::new(0, 5),
1390            },
1391            Type {
1392                kind: TypeKind::Function {
1393                    params: vec![Type {
1394                        kind: TypeKind::Named("i32".to_string()),
1395                        span: Span::new(0, 3),
1396                    }],
1397                    ret: Box::new(Type {
1398                        kind: TypeKind::Named("String".to_string()),
1399                        span: Span::new(7, 13),
1400                    }),
1401                },
1402                span: Span::new(0, 13),
1403            },
1404        ];
1405
1406        for ty in types {
1407            match ty.kind {
1408                TypeKind::Named(name) => assert!(!name.is_empty()),
1409                TypeKind::Generic { base, params } => {
1410                    assert!(!base.is_empty());
1411                    assert!(!params.is_empty());
1412                }
1413                TypeKind::Optional(_) | TypeKind::List(_) | TypeKind::Series { .. } => {}
1414                TypeKind::Function { params, .. } => assert!(!params.is_empty()),
1415                TypeKind::DataFrame { columns } => assert!(!columns.is_empty()),
1416                TypeKind::Tuple(ref types) => assert!(!types.is_empty()),
1417                TypeKind::Reference { is_mut: _, ref inner } => {
1418                    // Reference types should have a valid inner type
1419                    if let TypeKind::Named(ref name) = inner.kind { 
1420                        assert!(!name.is_empty());
1421                    }
1422                }
1423                TypeKind::Array { elem_type: _, size } => {
1424                    // Array types should have a valid size
1425                    assert!(size > 0);
1426                }
1427            }
1428        }
1429    }
1430
1431    #[test]
1432    fn test_param_creation() {
1433        let param = Param {
1434            pattern: Pattern::Identifier("count".to_string()),
1435            ty: Type {
1436                kind: TypeKind::Named("usize".to_string()),
1437                span: Span::new(6, 11),
1438            },
1439            span: Span::new(0, 11),
1440            is_mutable: false,
1441            default_value: None,
1442        };
1443
1444        assert_eq!(param.name(), "count");
1445        match param.ty.kind {
1446            TypeKind::Named(name) => assert_eq!(name, "usize"),
1447            _ => panic!("Wrong type kind"),
1448        }
1449    }
1450}