Skip to main content

verificar/generator/
ruchy_enum.rs

1//! Ruchy exhaustive enumeration
2//!
3//! Generates all valid Ruchy programs up to a specified AST depth.
4//! Ruchy is a Rust-like language with actor model and effect system.
5
6use super::GeneratedCode;
7use crate::Language;
8
9/// Ruchy AST node types for generation
10#[derive(Debug, Clone, PartialEq)]
11#[allow(missing_docs)]
12pub enum RuchyNode {
13    /// Module (root node)
14    Module(Vec<RuchyNode>),
15    /// Function definition
16    FnDef {
17        /// Function name
18        name: String,
19        /// Parameters (name, type)
20        params: Vec<(String, RuchyType)>,
21        /// Return type
22        return_type: Option<RuchyType>,
23        /// Function body
24        body: Vec<RuchyNode>,
25    },
26    /// Let binding
27    Let {
28        /// Variable name
29        name: String,
30        /// Optional type annotation
31        ty: Option<RuchyType>,
32        /// Value expression
33        value: Box<RuchyNode>,
34        /// Is mutable
35        mutable: bool,
36    },
37    /// Assignment
38    Assign {
39        /// Target
40        target: Box<RuchyNode>,
41        /// Value
42        value: Box<RuchyNode>,
43    },
44    /// Binary operation
45    BinOp {
46        /// Left operand
47        left: Box<RuchyNode>,
48        /// Operator
49        op: RuchyBinaryOp,
50        /// Right operand
51        right: Box<RuchyNode>,
52    },
53    /// Unary operation
54    UnaryOp {
55        /// Operator
56        op: RuchyUnaryOp,
57        /// Operand
58        operand: Box<RuchyNode>,
59    },
60    /// Integer literal
61    IntLit(i64),
62    /// Float literal
63    FloatLit(f64),
64    /// String literal
65    StrLit(String),
66    /// Boolean literal
67    BoolLit(bool),
68    /// Identifier
69    Ident(String),
70    /// If expression
71    If {
72        /// Condition
73        cond: Box<RuchyNode>,
74        /// Then branch
75        then_body: Vec<RuchyNode>,
76        /// Else branch
77        else_body: Vec<RuchyNode>,
78    },
79    /// Match expression
80    Match {
81        /// Value being matched
82        value: Box<RuchyNode>,
83        /// Match arms (pattern, body)
84        arms: Vec<(RuchyNode, Vec<RuchyNode>)>,
85    },
86    /// While loop
87    While {
88        /// Condition
89        cond: Box<RuchyNode>,
90        /// Body
91        body: Vec<RuchyNode>,
92    },
93    /// For loop (for x in iter)
94    For {
95        /// Variable name
96        var: String,
97        /// Iterator expression
98        iter: Box<RuchyNode>,
99        /// Body
100        body: Vec<RuchyNode>,
101    },
102    /// Return expression
103    Return(Option<Box<RuchyNode>>),
104    /// Break expression
105    Break,
106    /// Continue expression
107    Continue,
108    /// Function call
109    Call {
110        /// Function expression
111        func: Box<RuchyNode>,
112        /// Arguments
113        args: Vec<RuchyNode>,
114    },
115    /// Method call
116    MethodCall {
117        /// Receiver
118        receiver: Box<RuchyNode>,
119        /// Method name
120        method: String,
121        /// Arguments
122        args: Vec<RuchyNode>,
123    },
124    /// Struct definition
125    StructDef {
126        /// Struct name
127        name: String,
128        /// Fields (name, type)
129        fields: Vec<(String, RuchyType)>,
130    },
131    /// Struct instantiation
132    StructInit {
133        /// Struct name
134        name: String,
135        /// Field initializers
136        fields: Vec<(String, RuchyNode)>,
137    },
138    /// Field access
139    FieldAccess {
140        /// Receiver
141        receiver: Box<RuchyNode>,
142        /// Field name
143        field: String,
144    },
145    /// Optional chaining (?.)
146    OptionalChain {
147        /// Receiver
148        receiver: Box<RuchyNode>,
149        /// Field name
150        field: String,
151    },
152    /// Pipeline operator (|>)
153    Pipeline {
154        /// Left expression
155        left: Box<RuchyNode>,
156        /// Right function
157        right: Box<RuchyNode>,
158    },
159    /// Array literal
160    Array(Vec<RuchyNode>),
161    /// Range (start..end)
162    Range {
163        /// Start
164        start: Box<RuchyNode>,
165        /// End
166        end: Box<RuchyNode>,
167        /// Inclusive
168        inclusive: bool,
169    },
170    /// Closure
171    Closure {
172        /// Parameters
173        params: Vec<String>,
174        /// Body
175        body: Box<RuchyNode>,
176    },
177    /// Block expression
178    Block(Vec<RuchyNode>),
179    /// Actor spawn
180    Spawn(Box<RuchyNode>),
181    /// Send message
182    Send {
183        /// Target actor
184        target: Box<RuchyNode>,
185        /// Message
186        message: Box<RuchyNode>,
187    },
188    /// Comparison
189    Compare {
190        /// Left operand
191        left: Box<RuchyNode>,
192        /// Operator
193        op: RuchyCompareOp,
194        /// Right operand
195        right: Box<RuchyNode>,
196    },
197    /// Null coalescing (??)
198    NullCoalesce {
199        /// Value
200        value: Box<RuchyNode>,
201        /// Default
202        default: Box<RuchyNode>,
203    },
204    /// Pattern for match
205    Pattern(RuchyPattern),
206}
207
208/// Ruchy types
209#[derive(Debug, Clone, PartialEq, Eq)]
210pub enum RuchyType {
211    /// i32
212    I32,
213    /// i64
214    I64,
215    /// f64
216    F64,
217    /// bool
218    Bool,
219    /// String
220    String,
221    /// Unit ()
222    Unit,
223    /// Option<T>
224    Option(Box<RuchyType>),
225    /// Vec<T>
226    Vec(Box<RuchyType>),
227    /// Custom type
228    Custom(String),
229}
230
231impl RuchyType {
232    /// Get all basic types
233    #[must_use]
234    pub fn all_basic() -> &'static [Self] {
235        &[Self::I32, Self::I64, Self::F64, Self::Bool, Self::String]
236    }
237
238    /// Convert to Ruchy type string
239    #[must_use]
240    pub fn to_str(&self) -> String {
241        match self {
242            Self::I32 => "i32".to_string(),
243            Self::I64 => "i64".to_string(),
244            Self::F64 => "f64".to_string(),
245            Self::Bool => "bool".to_string(),
246            Self::String => "String".to_string(),
247            Self::Unit => "()".to_string(),
248            Self::Option(inner) => format!("Option<{}>", inner.to_str()),
249            Self::Vec(inner) => format!("Vec<{}>", inner.to_str()),
250            Self::Custom(name) => name.clone(),
251        }
252    }
253}
254
255/// Ruchy binary operators
256#[derive(Debug, Clone, Copy, PartialEq, Eq)]
257pub enum RuchyBinaryOp {
258    /// Addition
259    Add,
260    /// Subtraction
261    Sub,
262    /// Multiplication
263    Mul,
264    /// Division
265    Div,
266    /// Modulo
267    Mod,
268    /// Logical AND
269    And,
270    /// Logical OR
271    Or,
272    /// Bitwise AND
273    BitAnd,
274    /// Bitwise OR
275    BitOr,
276    /// Bitwise XOR
277    BitXor,
278}
279
280impl RuchyBinaryOp {
281    /// Get arithmetic operators
282    #[must_use]
283    pub fn arithmetic() -> &'static [Self] {
284        &[Self::Add, Self::Sub, Self::Mul, Self::Div, Self::Mod]
285    }
286
287    /// Convert to Ruchy operator string
288    #[must_use]
289    pub fn to_str(self) -> &'static str {
290        match self {
291            Self::Add => "+",
292            Self::Sub => "-",
293            Self::Mul => "*",
294            Self::Div => "/",
295            Self::Mod => "%",
296            Self::And => "&&",
297            Self::Or => "||",
298            Self::BitAnd => "&",
299            Self::BitOr => "|",
300            Self::BitXor => "^",
301        }
302    }
303}
304
305/// Ruchy unary operators
306#[derive(Debug, Clone, Copy, PartialEq, Eq)]
307pub enum RuchyUnaryOp {
308    /// Negation
309    Neg,
310    /// Logical NOT
311    Not,
312    /// Reference
313    Ref,
314    /// Mutable reference
315    RefMut,
316    /// Dereference
317    Deref,
318}
319
320impl RuchyUnaryOp {
321    /// Get all unary operators
322    #[must_use]
323    pub fn all() -> &'static [Self] {
324        &[Self::Neg, Self::Not]
325    }
326
327    /// Convert to Ruchy operator string
328    #[must_use]
329    pub fn to_str(self) -> &'static str {
330        match self {
331            Self::Neg => "-",
332            Self::Not => "!",
333            Self::Ref => "&",
334            Self::RefMut => "&mut ",
335            Self::Deref => "*",
336        }
337    }
338}
339
340/// Ruchy comparison operators
341#[derive(Debug, Clone, Copy, PartialEq, Eq)]
342pub enum RuchyCompareOp {
343    /// Equal
344    Eq,
345    /// Not equal
346    Ne,
347    /// Less than
348    Lt,
349    /// Greater than
350    Gt,
351    /// Less than or equal
352    Le,
353    /// Greater than or equal
354    Ge,
355}
356
357impl RuchyCompareOp {
358    /// Get all comparison operators
359    #[must_use]
360    pub fn all() -> &'static [Self] {
361        &[Self::Eq, Self::Ne, Self::Lt, Self::Gt, Self::Le, Self::Ge]
362    }
363
364    /// Convert to Ruchy operator string
365    #[must_use]
366    pub fn to_str(self) -> &'static str {
367        match self {
368            Self::Eq => "==",
369            Self::Ne => "!=",
370            Self::Lt => "<",
371            Self::Gt => ">",
372            Self::Le => "<=",
373            Self::Ge => ">=",
374        }
375    }
376}
377
378/// Ruchy patterns for match
379#[derive(Debug, Clone, PartialEq)]
380pub enum RuchyPattern {
381    /// Wildcard _
382    Wildcard,
383    /// Variable binding
384    Binding(String),
385    /// Literal
386    Literal(Box<RuchyNode>),
387    /// Tuple pattern
388    Tuple(Vec<RuchyPattern>),
389}
390
391impl RuchyNode {
392    /// Convert AST node to Ruchy code string
393    #[must_use]
394    #[allow(clippy::too_many_lines)]
395    pub fn to_code(&self, indent: usize) -> String {
396        let indent_str = "    ".repeat(indent);
397        match self {
398            Self::Module(items) => items
399                .iter()
400                .map(|item| item.to_code(0))
401                .collect::<Vec<_>>()
402                .join("\n\n"),
403            Self::FnDef {
404                name,
405                params,
406                return_type,
407                body,
408            } => {
409                let params_str = params
410                    .iter()
411                    .map(|(n, t)| format!("{}: {}", n, t.to_str()))
412                    .collect::<Vec<_>>()
413                    .join(", ");
414                let ret_str = return_type
415                    .as_ref()
416                    .map_or(String::new(), |t| format!(" -> {}", t.to_str()));
417                let body_str = body
418                    .iter()
419                    .map(|s| s.to_code(indent + 1))
420                    .collect::<Vec<_>>()
421                    .join("\n");
422                format!(
423                    "{indent_str}fn {name}({params_str}){ret_str} {{\n{body_str}\n{indent_str}}}"
424                )
425            }
426            Self::Let {
427                name,
428                ty,
429                value,
430                mutable,
431            } => {
432                let mut_str = if *mutable { "mut " } else { "" };
433                let ty_str = ty
434                    .as_ref()
435                    .map_or(String::new(), |t| format!(": {}", t.to_str()));
436                format!(
437                    "{}let {}{}{} = {};",
438                    indent_str,
439                    mut_str,
440                    name,
441                    ty_str,
442                    value.to_code(0)
443                )
444            }
445            Self::Assign { target, value } => {
446                format!(
447                    "{}{} = {};",
448                    indent_str,
449                    target.to_code(0),
450                    value.to_code(0)
451                )
452            }
453            Self::BinOp { left, op, right } => {
454                format!("({} {} {})", left.to_code(0), op.to_str(), right.to_code(0))
455            }
456            Self::UnaryOp { op, operand } => {
457                format!("({}{})", op.to_str(), operand.to_code(0))
458            }
459            Self::IntLit(n) => n.to_string(),
460            Self::FloatLit(f) => format!("{f:.1}"),
461            Self::StrLit(s) => format!("\"{s}\""),
462            Self::BoolLit(b) => b.to_string(),
463            Self::Ident(name) => name.clone(),
464            Self::If {
465                cond,
466                then_body,
467                else_body,
468            } => {
469                let then_str = then_body
470                    .iter()
471                    .map(|s| s.to_code(indent + 1))
472                    .collect::<Vec<_>>()
473                    .join("\n");
474                if else_body.is_empty() {
475                    format!(
476                        "{}if {} {{\n{}\n{}}}",
477                        indent_str,
478                        cond.to_code(0),
479                        then_str,
480                        indent_str
481                    )
482                } else {
483                    let else_str = else_body
484                        .iter()
485                        .map(|s| s.to_code(indent + 1))
486                        .collect::<Vec<_>>()
487                        .join("\n");
488                    format!(
489                        "{}if {} {{\n{}\n{}}} else {{\n{}\n{}}}",
490                        indent_str,
491                        cond.to_code(0),
492                        then_str,
493                        indent_str,
494                        else_str,
495                        indent_str
496                    )
497                }
498            }
499            Self::Match { value, arms } => {
500                let arms_str = arms
501                    .iter()
502                    .map(|(pat, body)| {
503                        let body_str = body
504                            .iter()
505                            .map(|s| s.to_code(0))
506                            .collect::<Vec<_>>()
507                            .join("; ");
508                        format!("{}    {} => {{ {} }}", indent_str, pat.to_code(0), body_str)
509                    })
510                    .collect::<Vec<_>>()
511                    .join(",\n");
512                format!(
513                    "{}match {} {{\n{}\n{}}}",
514                    indent_str,
515                    value.to_code(0),
516                    arms_str,
517                    indent_str
518                )
519            }
520            Self::While { cond, body } => {
521                let body_str = body
522                    .iter()
523                    .map(|s| s.to_code(indent + 1))
524                    .collect::<Vec<_>>()
525                    .join("\n");
526                format!(
527                    "{}while {} {{\n{}\n{}}}",
528                    indent_str,
529                    cond.to_code(0),
530                    body_str,
531                    indent_str
532                )
533            }
534            Self::For { var, iter, body } => {
535                let body_str = body
536                    .iter()
537                    .map(|s| s.to_code(indent + 1))
538                    .collect::<Vec<_>>()
539                    .join("\n");
540                format!(
541                    "{}for {} in {} {{\n{}\n{}}}",
542                    indent_str,
543                    var,
544                    iter.to_code(0),
545                    body_str,
546                    indent_str
547                )
548            }
549            Self::Return(expr) => {
550                if let Some(e) = expr {
551                    format!("{}return {};", indent_str, e.to_code(0))
552                } else {
553                    format!("{indent_str}return;")
554                }
555            }
556            Self::Break => format!("{indent_str}break;"),
557            Self::Continue => format!("{indent_str}continue;"),
558            Self::Call { func, args } => {
559                let args_str = args
560                    .iter()
561                    .map(|a| a.to_code(0))
562                    .collect::<Vec<_>>()
563                    .join(", ");
564                format!("{}({})", func.to_code(0), args_str)
565            }
566            Self::MethodCall {
567                receiver,
568                method,
569                args,
570            } => {
571                let args_str = args
572                    .iter()
573                    .map(|a| a.to_code(0))
574                    .collect::<Vec<_>>()
575                    .join(", ");
576                format!("{}.{}({})", receiver.to_code(0), method, args_str)
577            }
578            Self::StructDef { name, fields } => {
579                let fields_str = fields
580                    .iter()
581                    .map(|(n, t)| format!("{}    {}: {},", indent_str, n, t.to_str()))
582                    .collect::<Vec<_>>()
583                    .join("\n");
584                format!("{indent_str}struct {name} {{\n{fields_str}\n{indent_str}}}")
585            }
586            Self::StructInit { name, fields } => {
587                let fields_str = fields
588                    .iter()
589                    .map(|(n, v)| format!("{}: {}", n, v.to_code(0)))
590                    .collect::<Vec<_>>()
591                    .join(", ");
592                format!("{name} {{ {fields_str} }}")
593            }
594            Self::FieldAccess { receiver, field } => {
595                format!("{}.{}", receiver.to_code(0), field)
596            }
597            Self::OptionalChain { receiver, field } => {
598                format!("{}?.{}", receiver.to_code(0), field)
599            }
600            Self::Pipeline { left, right } => {
601                format!("{} |> {}", left.to_code(0), right.to_code(0))
602            }
603            Self::Array(items) => {
604                let items_str = items
605                    .iter()
606                    .map(|i| i.to_code(0))
607                    .collect::<Vec<_>>()
608                    .join(", ");
609                format!("[{items_str}]")
610            }
611            Self::Range {
612                start,
613                end,
614                inclusive,
615            } => {
616                let op = if *inclusive { "..=" } else { ".." };
617                format!("{}{}{}", start.to_code(0), op, end.to_code(0))
618            }
619            Self::Closure { params, body } => {
620                let params_str = params.join(", ");
621                format!("|{}| {}", params_str, body.to_code(0))
622            }
623            Self::Block(stmts) => {
624                let stmts_str = stmts
625                    .iter()
626                    .map(|s| s.to_code(indent + 1))
627                    .collect::<Vec<_>>()
628                    .join("\n");
629                format!("{indent_str}{{\n{stmts_str}\n{indent_str}}}")
630            }
631            Self::Spawn(expr) => format!("spawn {}", expr.to_code(0)),
632            Self::Send { target, message } => {
633                format!("{} <- {}", target.to_code(0), message.to_code(0))
634            }
635            Self::Compare { left, op, right } => {
636                format!("({} {} {})", left.to_code(0), op.to_str(), right.to_code(0))
637            }
638            Self::NullCoalesce { value, default } => {
639                format!("{} ?? {}", value.to_code(0), default.to_code(0))
640            }
641            Self::Pattern(pat) => pat.to_code(),
642        }
643    }
644
645    /// Calculate AST depth
646    #[must_use]
647    pub fn depth(&self) -> usize {
648        match self {
649            Self::Module(items) => 1 + items.iter().map(Self::depth).max().unwrap_or(0),
650            Self::FnDef { body, .. } => 1 + body.iter().map(Self::depth).max().unwrap_or(0),
651            Self::Let { value, .. } => 1 + value.depth(),
652            Self::Assign { target, value } => 1 + target.depth().max(value.depth()),
653            Self::BinOp { left, right, .. } | Self::Compare { left, right, .. } => {
654                1 + left.depth().max(right.depth())
655            }
656            Self::UnaryOp { operand, .. } => 1 + operand.depth(),
657            Self::If {
658                cond,
659                then_body,
660                else_body,
661            } => {
662                let then_depth = then_body.iter().map(Self::depth).max().unwrap_or(0);
663                let else_depth = else_body.iter().map(Self::depth).max().unwrap_or(0);
664                1 + cond.depth().max(then_depth).max(else_depth)
665            }
666            Self::Match { value, arms } => {
667                let arms_depth = arms
668                    .iter()
669                    .flat_map(|(_, body)| body.iter().map(Self::depth))
670                    .max()
671                    .unwrap_or(0);
672                1 + value.depth().max(arms_depth)
673            }
674            Self::While { cond, body } => {
675                let body_depth = body.iter().map(Self::depth).max().unwrap_or(0);
676                1 + cond.depth().max(body_depth)
677            }
678            Self::For { iter, body, .. } => {
679                let body_depth = body.iter().map(Self::depth).max().unwrap_or(0);
680                1 + iter.depth().max(body_depth)
681            }
682            Self::Return(Some(e)) => 1 + e.depth(),
683            Self::Call { func, args } => {
684                let args_depth = args.iter().map(Self::depth).max().unwrap_or(0);
685                1 + func.depth().max(args_depth)
686            }
687            Self::MethodCall { receiver, args, .. } => {
688                let args_depth = args.iter().map(Self::depth).max().unwrap_or(0);
689                1 + receiver.depth().max(args_depth)
690            }
691            Self::FieldAccess { receiver, .. } | Self::OptionalChain { receiver, .. } => {
692                1 + receiver.depth()
693            }
694            Self::Pipeline { left, right }
695            | Self::NullCoalesce {
696                value: left,
697                default: right,
698            } => 1 + left.depth().max(right.depth()),
699            Self::Array(items) => 1 + items.iter().map(Self::depth).max().unwrap_or(0),
700            Self::Range { start, end, .. } => 1 + start.depth().max(end.depth()),
701            Self::Closure { body, .. } => 1 + body.depth(),
702            Self::Block(stmts) => 1 + stmts.iter().map(Self::depth).max().unwrap_or(0),
703            Self::Spawn(e) => 1 + e.depth(),
704            Self::Send { target, message } => 1 + target.depth().max(message.depth()),
705            Self::StructInit { fields, .. } => {
706                1 + fields.iter().map(|(_, v)| v.depth()).max().unwrap_or(0)
707            }
708            // Terminal nodes
709            Self::Return(None)
710            | Self::Break
711            | Self::Continue
712            | Self::IntLit(_)
713            | Self::FloatLit(_)
714            | Self::StrLit(_)
715            | Self::BoolLit(_)
716            | Self::Ident(_)
717            | Self::StructDef { .. }
718            | Self::Pattern(_) => 1,
719        }
720    }
721}
722
723impl RuchyPattern {
724    /// Convert pattern to code
725    #[must_use]
726    pub fn to_code(&self) -> String {
727        match self {
728            Self::Wildcard => "_".to_string(),
729            Self::Binding(name) => name.clone(),
730            Self::Literal(lit) => lit.to_code(0),
731            Self::Tuple(pats) => {
732                let pats_str = pats
733                    .iter()
734                    .map(Self::to_code)
735                    .collect::<Vec<_>>()
736                    .join(", ");
737                format!("({pats_str})")
738            }
739        }
740    }
741}
742
743/// Exhaustive Ruchy program enumerator
744#[derive(Debug)]
745pub struct RuchyEnumerator {
746    max_depth: usize,
747    var_names: Vec<String>,
748    int_values: Vec<i64>,
749}
750
751impl Default for RuchyEnumerator {
752    fn default() -> Self {
753        Self::new(3)
754    }
755}
756
757impl RuchyEnumerator {
758    /// Create a new enumerator with specified max depth
759    #[must_use]
760    pub fn new(max_depth: usize) -> Self {
761        Self {
762            max_depth,
763            var_names: vec!["x".to_string(), "y".to_string(), "n".to_string()],
764            int_values: vec![0, 1, -1, 2, 10, 42],
765        }
766    }
767
768    /// Enumerate all expressions up to the given depth
769    pub fn enumerate_expressions(&self, depth: usize) -> Vec<RuchyNode> {
770        if depth == 0 {
771            return vec![];
772        }
773
774        let mut results = Vec::new();
775
776        // Depth 1: literals and names
777        for val in &self.int_values {
778            results.push(RuchyNode::IntLit(*val));
779        }
780        results.push(RuchyNode::BoolLit(true));
781        results.push(RuchyNode::BoolLit(false));
782        for name in &self.var_names {
783            results.push(RuchyNode::Ident(name.clone()));
784        }
785
786        if depth >= 2 {
787            // Binary operations
788            let sub_exprs = self.enumerate_expressions(depth - 1);
789            let limited: Vec<_> = sub_exprs.iter().take(15).collect();
790
791            for left in &limited {
792                for right in limited.iter().take(10) {
793                    for op in RuchyBinaryOp::arithmetic() {
794                        results.push(RuchyNode::BinOp {
795                            left: Box::new((*left).clone()),
796                            op: *op,
797                            right: Box::new((*right).clone()),
798                        });
799                    }
800                }
801            }
802
803            // Comparisons
804            for left in &limited {
805                for right in limited.iter().take(10) {
806                    for op in RuchyCompareOp::all() {
807                        results.push(RuchyNode::Compare {
808                            left: Box::new((*left).clone()),
809                            op: *op,
810                            right: Box::new((*right).clone()),
811                        });
812                    }
813                }
814            }
815
816            // Unary operations
817            for operand in limited.iter().take(8) {
818                for op in RuchyUnaryOp::all() {
819                    results.push(RuchyNode::UnaryOp {
820                        op: *op,
821                        operand: Box::new((*operand).clone()),
822                    });
823                }
824            }
825
826            // Ranges
827            for start in self.int_values.iter().take(3) {
828                for end in self.int_values.iter().take(3) {
829                    results.push(RuchyNode::Range {
830                        start: Box::new(RuchyNode::IntLit(*start)),
831                        end: Box::new(RuchyNode::IntLit(*end)),
832                        inclusive: false,
833                    });
834                }
835            }
836
837            // Pipeline
838            for left in limited.iter().take(5) {
839                results.push(RuchyNode::Pipeline {
840                    left: Box::new((*left).clone()),
841                    right: Box::new(RuchyNode::Ident("f".to_string())),
842                });
843            }
844        }
845
846        results
847    }
848
849    /// Enumerate all statements up to the given depth
850    pub fn enumerate_statements(&self, depth: usize) -> Vec<RuchyNode> {
851        if depth == 0 {
852            return vec![];
853        }
854
855        let mut results = Vec::new();
856
857        let exprs = self.enumerate_expressions(depth - 1);
858        let limited_exprs: Vec<_> = exprs.iter().take(20).collect();
859
860        // Let bindings
861        for name in &self.var_names {
862            for value in &limited_exprs {
863                results.push(RuchyNode::Let {
864                    name: name.clone(),
865                    ty: None,
866                    value: Box::new((*value).clone()),
867                    mutable: false,
868                });
869                results.push(RuchyNode::Let {
870                    name: name.clone(),
871                    ty: None,
872                    value: Box::new((*value).clone()),
873                    mutable: true,
874                });
875            }
876        }
877
878        // Return statements
879        results.push(RuchyNode::Return(None));
880        for expr in limited_exprs.iter().take(10) {
881            results.push(RuchyNode::Return(Some(Box::new((*expr).clone()))));
882        }
883
884        // Break and continue
885        results.push(RuchyNode::Break);
886        results.push(RuchyNode::Continue);
887
888        if depth >= 2 {
889            // If expressions
890            let conditions: Vec<_> = exprs
891                .iter()
892                .filter(|e| matches!(e, RuchyNode::Compare { .. } | RuchyNode::BoolLit(_)))
893                .take(5)
894                .collect();
895
896            let body_stmts = self.enumerate_statements(depth - 1);
897            let limited_body: Vec<_> = body_stmts.iter().take(5).collect();
898
899            for cond in &conditions {
900                for body in &limited_body {
901                    results.push(RuchyNode::If {
902                        cond: Box::new((*cond).clone()),
903                        then_body: vec![(*body).clone()],
904                        else_body: vec![],
905                    });
906                }
907            }
908
909            // While loops
910            for cond in &conditions {
911                results.push(RuchyNode::While {
912                    cond: Box::new((*cond).clone()),
913                    body: vec![RuchyNode::Break],
914                });
915            }
916
917            // For loops
918            for name in self.var_names.iter().take(2) {
919                results.push(RuchyNode::For {
920                    var: name.clone(),
921                    iter: Box::new(RuchyNode::Range {
922                        start: Box::new(RuchyNode::IntLit(0)),
923                        end: Box::new(RuchyNode::IntLit(10)),
924                        inclusive: false,
925                    }),
926                    body: vec![RuchyNode::Break],
927                });
928            }
929        }
930
931        results
932    }
933
934    /// Enumerate complete programs
935    #[must_use]
936    pub fn enumerate_programs(&self) -> Vec<GeneratedCode> {
937        let mut results = Vec::new();
938
939        let stmts = self.enumerate_statements(self.max_depth);
940
941        // Simple main functions with single statement
942        for stmt in stmts.iter().take(50) {
943            let func = RuchyNode::FnDef {
944                name: "main".to_string(),
945                params: vec![],
946                return_type: None,
947                body: vec![stmt.clone()],
948            };
949            let module = RuchyNode::Module(vec![func]);
950            let code = module.to_code(0);
951            results.push(GeneratedCode {
952                code,
953                language: Language::Ruchy,
954                ast_depth: stmt.depth() + 2,
955                features: self.extract_features(stmt),
956            });
957        }
958
959        // Functions with parameters
960        for stmt in stmts.iter().take(20) {
961            let func = RuchyNode::FnDef {
962                name: "compute".to_string(),
963                params: vec![
964                    ("a".to_string(), RuchyType::I32),
965                    ("b".to_string(), RuchyType::I32),
966                ],
967                return_type: Some(RuchyType::I32),
968                body: vec![stmt.clone()],
969            };
970            let module = RuchyNode::Module(vec![func]);
971            let code = module.to_code(0);
972            results.push(GeneratedCode {
973                code,
974                language: Language::Ruchy,
975                ast_depth: stmt.depth() + 2,
976                features: self.extract_features(stmt),
977            });
978        }
979
980        results
981    }
982
983    /// Extract feature labels from an AST node
984    fn extract_features(&self, node: &RuchyNode) -> Vec<String> {
985        let mut features = Vec::new();
986
987        match node {
988            RuchyNode::Let { mutable, .. } => {
989                features.push("let".to_string());
990                if *mutable {
991                    features.push("mut".to_string());
992                }
993            }
994            RuchyNode::BinOp { op, .. } => {
995                features.push("binop".to_string());
996                features.push(format!("op_{}", op.to_str()));
997            }
998            RuchyNode::If { else_body, .. } => {
999                features.push("if".to_string());
1000                if !else_body.is_empty() {
1001                    features.push("else".to_string());
1002                }
1003            }
1004            RuchyNode::While { .. } => features.push("while".to_string()),
1005            RuchyNode::For { .. } => features.push("for".to_string()),
1006            RuchyNode::Return(_) => features.push("return".to_string()),
1007            RuchyNode::Compare { op, .. } => {
1008                features.push("compare".to_string());
1009                features.push(format!("cmp_{}", op.to_str()));
1010            }
1011            RuchyNode::Pipeline { .. } => features.push("pipeline".to_string()),
1012            RuchyNode::Range { inclusive, .. } => {
1013                features.push("range".to_string());
1014                if *inclusive {
1015                    features.push("inclusive".to_string());
1016                }
1017            }
1018            RuchyNode::Match { .. } => features.push("match".to_string()),
1019            RuchyNode::Spawn(_) => features.push("spawn".to_string()),
1020            RuchyNode::Send { .. } => features.push("send".to_string()),
1021            _ => {}
1022        }
1023
1024        features
1025    }
1026}
1027
1028#[cfg(test)]
1029mod tests {
1030    use super::*;
1031
1032    #[test]
1033    fn test_int_lit_to_code() {
1034        let node = RuchyNode::IntLit(42);
1035        assert_eq!(node.to_code(0), "42");
1036    }
1037
1038    #[test]
1039    fn test_let_to_code() {
1040        let node = RuchyNode::Let {
1041            name: "x".to_string(),
1042            ty: None,
1043            value: Box::new(RuchyNode::IntLit(0)),
1044            mutable: false,
1045        };
1046        assert_eq!(node.to_code(0), "let x = 0;");
1047    }
1048
1049    #[test]
1050    fn test_let_mut_to_code() {
1051        let node = RuchyNode::Let {
1052            name: "x".to_string(),
1053            ty: Some(RuchyType::I32),
1054            value: Box::new(RuchyNode::IntLit(0)),
1055            mutable: true,
1056        };
1057        assert_eq!(node.to_code(0), "let mut x: i32 = 0;");
1058    }
1059
1060    #[test]
1061    fn test_fn_def_to_code() {
1062        let node = RuchyNode::FnDef {
1063            name: "main".to_string(),
1064            params: vec![],
1065            return_type: None,
1066            body: vec![RuchyNode::Return(None)],
1067        };
1068        let code = node.to_code(0);
1069        assert!(code.contains("fn main()"));
1070        assert!(code.contains("return;"));
1071    }
1072
1073    #[test]
1074    fn test_pipeline_to_code() {
1075        let node = RuchyNode::Pipeline {
1076            left: Box::new(RuchyNode::IntLit(1)),
1077            right: Box::new(RuchyNode::Ident("f".to_string())),
1078        };
1079        assert_eq!(node.to_code(0), "1 |> f");
1080    }
1081
1082    #[test]
1083    fn test_range_to_code() {
1084        let node = RuchyNode::Range {
1085            start: Box::new(RuchyNode::IntLit(0)),
1086            end: Box::new(RuchyNode::IntLit(10)),
1087            inclusive: false,
1088        };
1089        assert_eq!(node.to_code(0), "0..10");
1090
1091        let inclusive = RuchyNode::Range {
1092            start: Box::new(RuchyNode::IntLit(0)),
1093            end: Box::new(RuchyNode::IntLit(10)),
1094            inclusive: true,
1095        };
1096        assert_eq!(inclusive.to_code(0), "0..=10");
1097    }
1098
1099    #[test]
1100    fn test_for_to_code() {
1101        let node = RuchyNode::For {
1102            var: "i".to_string(),
1103            iter: Box::new(RuchyNode::Range {
1104                start: Box::new(RuchyNode::IntLit(0)),
1105                end: Box::new(RuchyNode::IntLit(10)),
1106                inclusive: false,
1107            }),
1108            body: vec![RuchyNode::Break],
1109        };
1110        let code = node.to_code(0);
1111        assert!(code.contains("for i in 0..10"));
1112        assert!(code.contains("break;"));
1113    }
1114
1115    #[test]
1116    fn test_enumerator_creates_programs() {
1117        let enumerator = RuchyEnumerator::new(2);
1118        let programs = enumerator.enumerate_programs();
1119        assert!(!programs.is_empty(), "Should generate programs");
1120    }
1121
1122    #[test]
1123    fn test_programs_are_ruchy() {
1124        let enumerator = RuchyEnumerator::new(2);
1125        let programs = enumerator.enumerate_programs();
1126        for prog in &programs {
1127            assert_eq!(prog.language, Language::Ruchy);
1128        }
1129    }
1130
1131    #[test]
1132    fn test_depth_calculation() {
1133        let node = RuchyNode::BinOp {
1134            left: Box::new(RuchyNode::IntLit(1)),
1135            op: RuchyBinaryOp::Add,
1136            right: Box::new(RuchyNode::BinOp {
1137                left: Box::new(RuchyNode::IntLit(2)),
1138                op: RuchyBinaryOp::Mul,
1139                right: Box::new(RuchyNode::IntLit(3)),
1140            }),
1141        };
1142        assert_eq!(node.depth(), 3);
1143    }
1144
1145    #[test]
1146    fn test_type_to_str() {
1147        assert_eq!(RuchyType::I32.to_str(), "i32");
1148        assert_eq!(
1149            RuchyType::Option(Box::new(RuchyType::I32)).to_str(),
1150            "Option<i32>"
1151        );
1152    }
1153
1154    #[test]
1155    fn test_extract_features() {
1156        let enumerator = RuchyEnumerator::new(2);
1157        let node = RuchyNode::Let {
1158            name: "x".to_string(),
1159            ty: None,
1160            value: Box::new(RuchyNode::IntLit(0)),
1161            mutable: true,
1162        };
1163        let features = enumerator.extract_features(&node);
1164        assert!(features.contains(&"let".to_string()));
1165        assert!(features.contains(&"mut".to_string()));
1166    }
1167}