Coverage Report

Created: 2025-09-08 21:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/noah/src/ruchy/src/backend/transpiler/mod.rs
Line
Count
Source
1
//! Modular transpiler for Ruchy language
2
//!
3
//! This module is responsible for converting Ruchy AST into Rust code using `proc_macro2` `TokenStream`.
4
5
#![allow(clippy::missing_errors_doc)]
6
#![allow(clippy::too_many_lines)]
7
8
mod actors;
9
mod dataframe;
10
mod dataframe_builder;
11
mod dataframe_helpers;
12
mod dispatcher;
13
mod expressions;
14
mod method_call_refactored;
15
mod patterns;
16
mod result_type;
17
mod statements;
18
mod type_conversion_refactored;
19
mod type_inference;
20
mod types;
21
pub mod codegen_minimal;
22
23
use crate::frontend::ast::{Attribute, Expr, ExprKind, Span, Type};
24
use crate::backend::module_resolver::ModuleResolver;
25
use anyhow::Result;
26
use proc_macro2::TokenStream;
27
use quote::{format_ident, quote};
28
29
// Module exports are handled by the impl blocks in each module
30
31
/// Block categorization result: (functions, statements, modules, `has_main`, `main_expr`)
32
type BlockCategorization<'a> = (Vec<TokenStream>, Vec<TokenStream>, Vec<TokenStream>, bool, Option<&'a Expr>);
33
34
/// Function signature information for type coercion
35
#[derive(Debug, Clone)]
36
pub struct FunctionSignature {
37
    pub name: String,
38
    pub param_types: Vec<String>,  // Simplified: just the type name as string
39
}
40
41
/// The main transpiler struct
42
pub struct Transpiler {
43
    /// Track whether we're in an async context
44
    pub in_async_context: bool,
45
    /// Track variables that need to be mutable (for auto-mutability)
46
    pub mutable_vars: std::collections::HashSet<String>,
47
    /// Track function signatures for type coercion
48
    pub function_signatures: std::collections::HashMap<String, FunctionSignature>,
49
}
50
51
impl Default for Transpiler {
52
0
    fn default() -> Self {
53
0
        Self::new()
54
0
    }
55
}
56
57
impl Transpiler {
58
    /// Creates a new transpiler instance without module loader
59
    ///
60
    /// # Examples
61
    ///
62
    /// ```
63
    /// use ruchy::Transpiler;
64
    /// 
65
    /// let transpiler = Transpiler::new();
66
    /// assert!(!transpiler.in_async_context);
67
    /// ```
68
0
    pub fn new() -> Self {
69
0
        Self {
70
0
            in_async_context: false,
71
0
            mutable_vars: std::collections::HashSet::new(),
72
0
            function_signatures: std::collections::HashMap::new(),
73
0
        }
74
0
    }
75
76
    /// Centralized result printing logic - ONE PLACE FOR ALL RESULT PRINTING
77
    /// This eliminates code duplication and ensures consistent Unit type handling
78
0
    fn generate_result_printing_tokens(&self) -> TokenStream {
79
0
        quote! {
80
            // Check the type name first to avoid Unit type Display error
81
            if std::any::type_name_of_val(&result) == "()" {
82
                // Don't print Unit type
83
            } else if std::any::type_name_of_val(&result).contains("String") || 
84
                      std::any::type_name_of_val(&result).contains("&str") {
85
                println!("{}", result);
86
            } else {
87
                println!("{:?}", result);
88
            }
89
        }
90
0
    }
91
    
92
    /// Centralized value printing logic for functions like println
93
0
    fn generate_value_printing_tokens(&self, value_expr: TokenStream, func_tokens: TokenStream) -> TokenStream {
94
0
        quote! {
95
            {
96
                use std::any::Any;
97
                let value = #value_expr;
98
                // Special handling for String and &str types to avoid quotes
99
                if let Some(s) = (&value as &dyn Any).downcast_ref::<String>() {
100
                    #func_tokens!("{}", s)
101
                } else if let Some(s) = (&value as &dyn Any).downcast_ref::<&str>() {
102
                    #func_tokens!("{}", s)
103
                } else {
104
                    #func_tokens!("{:?}", value)
105
                }
106
            }
107
        }
108
0
    }
109
110
    /// Analyze expressions to determine which variables need to be mutable
111
0
    pub fn analyze_mutability(&mut self, exprs: &[Expr]) {
112
0
        for expr in exprs {
113
0
            self.analyze_expr_mutability(expr);
114
0
        }
115
0
    }
116
    
117
    /// Collect function signatures for type coercion
118
0
    pub fn collect_function_signatures(&mut self, exprs: &[Expr]) {
119
0
        for expr in exprs {
120
0
            self.collect_signatures_from_expr(expr);
121
0
        }
122
0
    }
123
    
124
0
    fn collect_signatures_from_expr(&mut self, expr: &Expr) {
125
        use crate::frontend::ast::ExprKind;
126
        
127
0
        match &expr.kind {
128
0
            ExprKind::Function { name, params, .. } => {
129
0
                let param_types: Vec<String> = params.iter()
130
0
                    .map(|param| self.type_to_string(&param.ty))
131
0
                    .collect();
132
                    
133
0
                let signature = FunctionSignature {
134
0
                    name: name.clone(),
135
0
                    param_types,
136
0
                };
137
                
138
0
                self.function_signatures.insert(name.clone(), signature);
139
            }
140
0
            ExprKind::Block(exprs) => {
141
0
                for e in exprs {
142
0
                    self.collect_signatures_from_expr(e);
143
0
                }
144
            }
145
0
            ExprKind::Let { body, .. } => {
146
0
                self.collect_signatures_from_expr(body);
147
0
            }
148
0
            _ => {}
149
        }
150
0
    }
151
    
152
0
    fn type_to_string(&self, ty: &crate::frontend::ast::Type) -> String {
153
        use crate::frontend::ast::TypeKind;
154
        
155
0
        match &ty.kind {
156
0
            TypeKind::Named(name) => name.clone(),
157
0
            TypeKind::Reference { inner, .. } => format!("&{}", self.type_to_string(inner)),
158
0
            _ => "Unknown".to_string(),
159
        }
160
0
    }
161
    
162
0
    fn analyze_expr_mutability(&mut self, expr: &Expr) {
163
        use crate::frontend::ast::ExprKind;
164
        
165
0
        match &expr.kind {
166
            // Direct assignment marks the target as mutable
167
0
            ExprKind::Assign { target, value } => {
168
0
                if let ExprKind::Identifier(name) = &target.kind {
169
0
                    self.mutable_vars.insert(name.clone());
170
0
                }
171
0
                self.analyze_expr_mutability(value);
172
            }
173
            // Compound assignment marks the target as mutable
174
0
            ExprKind::CompoundAssign { target, value, .. } => {
175
0
                if let ExprKind::Identifier(name) = &target.kind {
176
0
                    self.mutable_vars.insert(name.clone());
177
0
                }
178
0
                self.analyze_expr_mutability(value);
179
            }
180
            // Pre/Post increment/decrement mark the target as mutable
181
0
            ExprKind::PreIncrement { target } |
182
0
            ExprKind::PostIncrement { target } |
183
0
            ExprKind::PreDecrement { target } |
184
0
            ExprKind::PostDecrement { target } => {
185
0
                if let ExprKind::Identifier(name) = &target.kind {
186
0
                    self.mutable_vars.insert(name.clone());
187
0
                }
188
            }
189
            // Recursively analyze blocks
190
0
            ExprKind::Block(exprs) => {
191
0
                for e in exprs {
192
0
                    self.analyze_expr_mutability(e);
193
0
                }
194
            }
195
            // Analyze control flow
196
0
            ExprKind::If { condition, then_branch, else_branch } => {
197
0
                self.analyze_expr_mutability(condition);
198
0
                self.analyze_expr_mutability(then_branch);
199
0
                if let Some(else_expr) = else_branch {
200
0
                    self.analyze_expr_mutability(else_expr);
201
0
                }
202
            }
203
0
            ExprKind::While { condition, body } => {
204
0
                self.analyze_expr_mutability(condition);
205
0
                self.analyze_expr_mutability(body);
206
0
            }
207
0
            ExprKind::For { body, iter, .. } => {
208
0
                self.analyze_expr_mutability(iter);
209
0
                self.analyze_expr_mutability(body);
210
0
            }
211
            // Analyze match arms
212
0
            ExprKind::Match { expr, arms } => {
213
0
                self.analyze_expr_mutability(expr);
214
0
                for arm in arms {
215
0
                    self.analyze_expr_mutability(&arm.body);
216
0
                }
217
            }
218
            // Analyze let bodies
219
0
            ExprKind::Let { body, value, .. } | ExprKind::LetPattern { body, value, .. } => {
220
0
                self.analyze_expr_mutability(value);
221
0
                self.analyze_expr_mutability(body);
222
0
            }
223
            // Analyze function bodies
224
0
            ExprKind::Function { body, .. } => {
225
0
                self.analyze_expr_mutability(body);
226
0
            }
227
0
            ExprKind::Lambda { body, .. } => {
228
0
                self.analyze_expr_mutability(body);
229
0
            }
230
            // Analyze binary/unary operations
231
0
            ExprKind::Binary { left, right, .. } => {
232
0
                self.analyze_expr_mutability(left);
233
0
                self.analyze_expr_mutability(right);
234
0
            }
235
0
            ExprKind::Unary { operand, .. } => {
236
0
                self.analyze_expr_mutability(operand);
237
0
            }
238
            // Analyze calls
239
0
            ExprKind::Call { func, args } => {
240
0
                self.analyze_expr_mutability(func);
241
0
                for arg in args {
242
0
                    self.analyze_expr_mutability(arg);
243
0
                }
244
            }
245
0
            ExprKind::MethodCall { receiver, args, .. } => {
246
0
                self.analyze_expr_mutability(receiver);
247
0
                for arg in args {
248
0
                    self.analyze_expr_mutability(arg);
249
0
                }
250
            }
251
0
            _ => {}
252
        }
253
0
    }
254
    
255
    /// Resolves file imports in the AST using `ModuleResolver`
256
    #[allow(dead_code)]
257
0
    fn resolve_imports(&self, expr: &Expr) -> Result<Expr> {
258
        // For now, just use default search paths since we don't have file context here
259
0
        let mut resolver = ModuleResolver::new();
260
0
        resolver.resolve_imports(expr.clone())
261
0
    }
262
263
    /// Resolves file imports with a specific file context for search paths
264
0
    fn resolve_imports_with_context(&self, expr: &Expr, file_path: Option<&std::path::Path>) -> Result<Expr> {
265
0
        let mut resolver = ModuleResolver::new();
266
        
267
        // Add the file's directory to search paths if provided
268
0
        if let Some(path) = file_path {
269
0
            if let Some(dir) = path.parent() {
270
0
                resolver.add_search_path(dir);
271
0
            }
272
0
        }
273
        
274
0
        resolver.resolve_imports(expr.clone())
275
0
    }
276
277
    /// Transpiles an expression to a `TokenStream`
278
    ///
279
    /// # Examples
280
    ///
281
    /// ```
282
    /// use ruchy::{Transpiler, Parser};
283
    /// 
284
    /// let mut parser = Parser::new("42");
285
    /// let ast = parser.parse().unwrap();
286
    /// 
287
    /// let transpiler = Transpiler::new();
288
    /// let result = transpiler.transpile(&ast);
289
    /// assert!(result.is_ok());
290
    /// ```
291
    ///
292
    /// # Errors
293
    ///
294
    /// Returns an error if the AST cannot be transpiled to valid Rust code.
295
0
    pub fn transpile(&self, expr: &Expr) -> Result<TokenStream> {
296
0
        self.transpile_expr(expr)
297
0
    }
298
299
    /// Check if AST contains `HashMap` operations requiring `std::collections::HashMap` import
300
0
    fn contains_hashmap(expr: &Expr) -> bool {
301
        use crate::frontend::ast::{ExprKind, Literal};
302
        
303
0
        match &expr.kind {
304
0
            ExprKind::ObjectLiteral { .. } => true,
305
0
            ExprKind::Call { func, .. } => {
306
                // Check for HashMap methods like .get(), .insert(), etc.
307
0
                if let ExprKind::FieldAccess { field, .. } = &func.kind {
308
0
                    matches!(field.as_str(), "get" | "insert" | "remove" | "contains_key" | "keys" | "values")
309
                } else {
310
0
                    false
311
                }
312
            }
313
0
            ExprKind::IndexAccess { object: _, index } => {
314
                // String literal index access suggests HashMap
315
0
                matches!(&index.kind, ExprKind::Literal(Literal::String(_)))
316
            }
317
0
            ExprKind::Block(exprs) => exprs.iter().any(Self::contains_hashmap),
318
0
            ExprKind::Function { body, .. } => Self::contains_hashmap(body),
319
0
            ExprKind::If { condition, then_branch, else_branch } => {
320
0
                Self::contains_hashmap(condition) || 
321
0
                Self::contains_hashmap(then_branch) ||
322
0
                else_branch.as_ref().is_some_and(|e| Self::contains_hashmap(e))
323
            }
324
0
            ExprKind::Binary { left, right, .. } => {
325
0
                Self::contains_hashmap(left) || Self::contains_hashmap(right)
326
            }
327
0
            _ => false,
328
        }
329
0
    }
330
331
    /// Checks if an expression contains `DataFrame` operations (simplified for complexity)
332
0
    fn contains_dataframe(expr: &Expr) -> bool {
333
0
        matches!(
334
0
            expr.kind,
335
            ExprKind::DataFrame { .. } | ExprKind::DataFrameOperation { .. }
336
        )
337
0
    }
338
339
    /// Wraps transpiled code in a complete Rust program with necessary imports
340
    ///
341
    /// # Examples
342
    ///
343
    /// ```
344
    /// use ruchy::{Transpiler, Parser};
345
    /// 
346
    /// let mut parser = Parser::new("42");
347
    /// let ast = parser.parse().unwrap();
348
    /// 
349
    /// let transpiler = Transpiler::new();
350
    /// let result = transpiler.transpile_to_program(&ast);
351
    /// assert!(result.is_ok());
352
    /// 
353
    /// let code = result.unwrap().to_string();
354
    /// assert!(code.contains("fn main"));
355
    /// assert!(code.contains("42"));
356
    /// ```
357
    ///
358
    /// # Errors
359
    ///
360
    /// Returns an error if the AST cannot be transpiled to a valid Rust program.
361
0
    pub fn transpile_to_program(&mut self, expr: &Expr) -> Result<TokenStream> {
362
        // First analyze the entire program to detect mutable variables and function signatures
363
0
        if let ExprKind::Block(exprs) = &expr.kind {
364
0
            self.analyze_mutability(exprs);
365
0
            self.collect_function_signatures(exprs);
366
0
        } else {
367
0
            self.analyze_expr_mutability(expr);
368
0
            self.collect_signatures_from_expr(expr);
369
0
        }
370
        
371
0
        let result = self.transpile_to_program_with_context(expr, None);
372
0
        if let Ok(ref token_stream) = result {
373
0
            // Debug: Write the generated Rust code to a debug file
374
0
            let rust_code = token_stream.to_string();
375
0
            std::fs::write("/tmp/debug_transpiler_output.rs", &rust_code).ok();
376
0
        }
377
0
        result
378
0
    }
379
380
    /// Transpile with file context for module resolution
381
0
    pub fn transpile_to_program_with_context(&self, expr: &Expr, file_path: Option<&std::path::Path>) -> Result<TokenStream> {
382
        // First, resolve any file imports using the module resolver
383
0
        let resolved_expr = self.resolve_imports_with_context(expr, file_path)?;
384
0
        let needs_polars = Self::contains_dataframe(&resolved_expr);
385
0
        let needs_hashmap = Self::contains_hashmap(&resolved_expr);
386
        
387
0
        match &resolved_expr.kind {
388
0
            ExprKind::Function { name, .. } => {
389
0
                self.transpile_single_function(&resolved_expr, name, needs_polars, needs_hashmap)
390
            }
391
0
            ExprKind::Block(exprs) => {
392
0
                self.transpile_program_block(exprs, needs_polars, needs_hashmap)
393
            }
394
            _ => {
395
0
                self.transpile_expression_program(&resolved_expr, needs_polars, needs_hashmap)
396
            }
397
        }
398
0
    }
399
    
400
0
    fn transpile_single_function(&self, expr: &Expr, name: &str, needs_polars: bool, needs_hashmap: bool) -> Result<TokenStream> {
401
        // Use the proper function expression transpiler to handle attributes correctly
402
0
        let func = match &expr.kind {
403
0
            crate::frontend::ast::ExprKind::Function { .. } => self.transpile_function_expr(expr)?,
404
0
            _ => self.transpile_expr(expr)?,
405
        };
406
0
        let needs_main = name != "main";
407
        
408
0
        match (needs_polars, needs_hashmap, needs_main) {
409
0
            (true, true, true) => Ok(quote! {
410
0
                use polars::prelude::*;
411
0
                use std::collections::HashMap;
412
0
                #func
413
0
                fn main() { /* Function defined but not called */ }
414
0
            }),
415
0
            (true, true, false) => Ok(quote! {
416
0
                use polars::prelude::*;
417
0
                use std::collections::HashMap;
418
0
                #func
419
0
            }),
420
0
            (true, false, true) => Ok(quote! {
421
0
                use polars::prelude::*;
422
0
                #func
423
0
                fn main() { /* Function defined but not called */ }
424
0
            }),
425
0
            (true, false, false) => Ok(quote! {
426
0
                use polars::prelude::*;
427
0
                #func
428
0
            }),
429
0
            (false, true, true) => Ok(quote! {
430
0
                use std::collections::HashMap;
431
0
                #func
432
0
                fn main() { /* Function defined but not called */ }
433
0
            }),
434
0
            (false, true, false) => Ok(quote! {
435
0
                use std::collections::HashMap;
436
0
                #func
437
0
            }),
438
0
            (false, false, true) => Ok(quote! {
439
0
                #func
440
0
                fn main() { /* Function defined but not called */ }
441
0
            }),
442
0
            (false, false, false) => Ok(quote! { 
443
0
                #func 
444
0
            })
445
        }
446
0
    }
447
    
448
0
    fn transpile_program_block(&self, exprs: &[Expr], needs_polars: bool, needs_hashmap: bool) -> Result<TokenStream> {
449
0
        let (functions, statements, modules, has_main, main_expr) = self.categorize_block_expressions(exprs)?;
450
        
451
0
        if functions.is_empty() && !has_main && modules.is_empty() {
452
0
            self.transpile_statement_only_block(exprs, needs_polars, needs_hashmap)
453
0
        } else if has_main || !modules.is_empty() {
454
0
            self.transpile_block_with_main_function(&functions, &statements, &modules, main_expr, needs_polars, needs_hashmap)
455
        } else {
456
0
            self.transpile_block_with_functions(&functions, &statements, needs_polars, needs_hashmap)
457
        }
458
0
    }
459
    
460
0
    fn categorize_block_expressions<'a>(&self, exprs: &'a [Expr]) -> Result<BlockCategorization<'a>> {
461
0
        let mut functions = Vec::new();
462
0
        let mut statements = Vec::new();
463
0
        let mut modules = Vec::new();
464
0
        let mut has_main_function = false;
465
0
        let mut main_function_expr = None;
466
        
467
        
468
0
        for expr in exprs {
469
0
            match &expr.kind {
470
0
                ExprKind::Function { name, .. } => {
471
0
                    if name == "main" {
472
0
                        has_main_function = true;
473
0
                        main_function_expr = Some(expr);
474
0
                    } else {
475
                        // Use proper function transpiler to handle attributes correctly
476
0
                        functions.push(self.transpile_function_expr(expr)?);
477
                    }
478
                },
479
0
                ExprKind::Module { name, body } => {
480
                    // Extract module declarations for top-level placement
481
0
                    modules.push(self.transpile_module_declaration(name, body)?);
482
                },
483
0
                ExprKind::Block(block_exprs) => {
484
                    // Check if this is a module-containing block from the resolver
485
0
                    if block_exprs.len() == 2 
486
0
                        && matches!(block_exprs[0].kind, ExprKind::Module { .. })
487
0
                        && matches!(block_exprs[1].kind, ExprKind::Import { .. }) {
488
                        // This is a module resolver block: extract the module and keep the import as statement
489
0
                        if let ExprKind::Module { name, body } = &block_exprs[0].kind {
490
0
                            modules.push(self.transpile_module_declaration(name, body)?);
491
0
                        }
492
0
                        statements.push(self.transpile_expr(&block_exprs[1])?);
493
                    } else {
494
                        // Regular block, treat as statement
495
0
                        statements.push(self.transpile_expr(expr)?);
496
                    }
497
                },
498
                _ => {
499
0
                    let stmt = self.transpile_expr(expr)?;
500
                    // Ensure statements have semicolons for proper separation
501
0
                    let stmt_str = stmt.to_string();
502
0
                    if !stmt_str.trim().ends_with(';') && !stmt_str.trim().ends_with('}') {
503
0
                        statements.push(quote! { #stmt; });
504
0
                    } else {
505
0
                        statements.push(stmt);
506
0
                    }
507
                }
508
            }
509
        }
510
        
511
0
        Ok((functions, statements, modules, has_main_function, main_function_expr))
512
0
    }
513
514
0
    fn transpile_module_declaration(&self, name: &str, body: &Expr) -> Result<TokenStream> {
515
0
        let module_name = format_ident!("{}", name);
516
        
517
        // Handle module body - if it's a block, transpile its contents as module items
518
0
        let body_tokens = if let ExprKind::Block(exprs) = &body.kind {
519
            // Separate functions from other items in the module
520
0
            let mut module_items = Vec::new();
521
            
522
0
            for expr in exprs {
523
0
                match &expr.kind {
524
                    ExprKind::Function { .. } => {
525
                        // Transpile functions as module items
526
0
                        module_items.push(self.transpile_function_expr(expr)?);
527
                    }
528
                    _ => {
529
                        // Other items (constants, etc.)
530
0
                        module_items.push(self.transpile_expr(expr)?);
531
                    }
532
                }
533
            }
534
            
535
0
            quote! { #(#module_items)* }
536
        } else {
537
            // Single expression - transpile normally
538
0
            self.transpile_expr(body)?
539
        };
540
541
0
        Ok(quote! {
542
0
            mod #module_name {
543
0
                #body_tokens
544
0
            }
545
0
        })
546
0
    }
547
    
548
0
    fn transpile_statement_only_block(&self, exprs: &[Expr], needs_polars: bool, needs_hashmap: bool) -> Result<TokenStream> {
549
        // Check if this is a statement sequence (contains let, assignments, etc.) or an expression sequence
550
0
        let has_statements = exprs.iter().any(|expr| self.is_statement_expr(expr));
551
        
552
0
        if has_statements {
553
            // Split into statements and possible final expression
554
0
            let (statements, final_expr) = if !exprs.is_empty() && !self.is_statement_expr(exprs.last().unwrap()) {
555
                // Last item is an expression, not a statement
556
0
                (&exprs[..exprs.len() - 1], Some(exprs.last().unwrap()))
557
            } else {
558
                // All are statements
559
0
                (exprs, None)
560
            };
561
            
562
            // Transpile all statements and add semicolons intelligently
563
0
            let statement_results: Result<Vec<_>> = statements.iter().map(|expr| {
564
0
                let tokens = self.transpile_expr(expr)?;
565
0
                let tokens_str = tokens.to_string();
566
                // If the statement already ends with a semicolon, don't add another
567
0
                if tokens_str.trim().ends_with(';') {
568
0
                    Ok(tokens)
569
                } else {
570
                    // Add semicolon for statements that need them
571
0
                    Ok(quote! { #tokens; })
572
                }
573
0
            }).collect();
574
0
            let statement_tokens = statement_results?;
575
            
576
            // Handle final expression if present
577
0
            let main_body = if let Some(final_expr) = final_expr {
578
0
                let final_tokens = self.transpile_expr(final_expr)?;
579
0
                let result_printing_logic = self.generate_result_printing_tokens();
580
0
                quote! {
581
                    #(#statement_tokens)*
582
                    let result = #final_tokens;
583
                    #result_printing_logic
584
                }
585
            } else {
586
0
                quote! {
587
                    #(#statement_tokens)*
588
                }
589
            };
590
            
591
0
            match (needs_polars, needs_hashmap) {
592
0
                (true, true) => Ok(quote! {
593
0
                    use polars::prelude::*;
594
0
                    use std::collections::HashMap;
595
0
                    fn main() {
596
0
                        #main_body
597
0
                    }
598
0
                }),
599
0
                (true, false) => Ok(quote! {
600
0
                    use polars::prelude::*;
601
0
                    fn main() {
602
0
                        #main_body
603
0
                    }
604
0
                }),
605
0
                (false, true) => Ok(quote! {
606
0
                    use std::collections::HashMap;
607
0
                    fn main() {
608
0
                        #main_body
609
0
                    }
610
0
                }),
611
0
                (false, false) => Ok(quote! {
612
0
                    fn main() {
613
0
                        #main_body
614
0
                    }
615
0
                })
616
            }
617
        } else {
618
            // Pure expression sequence - use existing result printing approach
619
0
            let block_expr = Expr::new(ExprKind::Block(exprs.to_vec()), Span::new(0, 0));
620
0
            let body = self.transpile_expr(&block_expr)?;
621
0
            self.wrap_in_main_with_result_printing(body, needs_polars, needs_hashmap)
622
        }
623
0
    }
624
    
625
0
    fn is_statement_expr(&self, expr: &Expr) -> bool {
626
0
        match &expr.kind {
627
            // Let bindings are statements
628
0
            ExprKind::Let { .. } | ExprKind::LetPattern { .. } => true,
629
            // Assignment operations are statements  
630
0
            ExprKind::Assign { .. } | ExprKind::CompoundAssign { .. } => true,
631
            // Loops are statements (void/unit type)
632
0
            ExprKind::While { .. } | ExprKind::For { .. } | ExprKind::Loop { .. } => true,
633
            // Function calls that don't return meaningful values (like println)
634
0
            ExprKind::Call { func, .. } => {
635
0
                if let ExprKind::Identifier(name) = &func.kind {
636
0
                    matches!(name.as_str(), "println" | "print" | "dbg")
637
                } else {
638
0
                    false
639
                }
640
            }
641
            // Blocks containing statements
642
0
            ExprKind::Block(exprs) => exprs.iter().any(|e| self.is_statement_expr(e)),
643
            // Most other expressions are not statements
644
0
            _ => false,
645
        }
646
0
    }
647
    
648
0
    fn transpile_block_with_main_function(&self, functions: &[TokenStream], statements: &[TokenStream], modules: &[TokenStream], main_expr: Option<&Expr>, needs_polars: bool, needs_hashmap: bool) -> Result<TokenStream> {
649
0
        if statements.is_empty() && main_expr.is_some() {
650
            // Only functions, just emit them normally (includes user's main)
651
0
            let main_tokens = if let Some(main) = main_expr {
652
0
                self.transpile_expr(main)?
653
            } else {
654
0
                return Err(anyhow::anyhow!("Expected main function expression"));
655
            };
656
            
657
0
            match (needs_polars, needs_hashmap) {
658
0
                (true, true) => Ok(quote! {
659
                    use polars::prelude::*;
660
                    use std::collections::HashMap;
661
                    #(#modules)*
662
                    #(#functions)*
663
                    #main_tokens
664
                }),
665
0
                (true, false) => Ok(quote! {
666
                    use polars::prelude::*;
667
                    #(#modules)*
668
                    #(#functions)*
669
                    #main_tokens
670
                }),
671
0
                (false, true) => Ok(quote! {
672
                    use std::collections::HashMap;
673
                    #(#modules)*
674
                    #(#functions)*
675
                    #main_tokens
676
                }),
677
0
                (false, false) => Ok(quote! {
678
                    #(#modules)*
679
                    #(#functions)*
680
                    #main_tokens
681
                })
682
            }
683
        } else {
684
            // TOP-LEVEL STATEMENTS: Extract main body and combine with statements
685
0
            let main_body = if let Some(main) = main_expr {
686
0
                self.extract_main_function_body(main)?
687
            } else {
688
                // No user main function, just use empty body
689
0
                quote! {}
690
            };
691
            
692
0
            match (needs_polars, needs_hashmap) {
693
0
                (true, true) => Ok(quote! {
694
                    use polars::prelude::*;
695
                    use std::collections::HashMap;
696
                    #(#modules)*
697
                    #(#functions)*
698
                    fn main() {
699
                        // Top-level statements execute first
700
                        #(#statements)*
701
                        
702
                        // Then user's main function body  
703
                        #main_body
704
                    }
705
                }),
706
0
                (true, false) => Ok(quote! {
707
                    use polars::prelude::*;
708
                    #(#modules)*
709
                    #(#functions)*
710
                    fn main() {
711
                        // Top-level statements execute first
712
                        #(#statements)*
713
                        
714
                        // Then user's main function body  
715
                        #main_body
716
                    }
717
                }),
718
0
                (false, true) => Ok(quote! {
719
                    use std::collections::HashMap;
720
                    #(#modules)*
721
                    #(#functions)*
722
                    fn main() {
723
                        // Top-level statements execute first
724
                        #(#statements)*
725
                        
726
                        // Then user's main function body
727
                        #main_body
728
                    }
729
                }),
730
0
                (false, false) => Ok(quote! {
731
                    #(#modules)*
732
                    #(#functions)*
733
                    fn main() {
734
                        // Top-level statements execute first
735
                        #(#statements)*
736
                        
737
                        // Then user's main function body
738
                        #main_body
739
                    }
740
                })
741
            }
742
        }
743
0
    }
744
    
745
    /// Extracts the body of a main function for inlining with top-level statements
746
0
    fn extract_main_function_body(&self, main_expr: &Expr) -> Result<TokenStream> {
747
0
        if let ExprKind::Function { body, .. } = &main_expr.kind {
748
            // Transpile just the body, not the entire function definition
749
0
            self.transpile_expr(body)
750
        } else {
751
0
            Err(anyhow::anyhow!("Expected function expression for main body extraction"))
752
        }
753
0
    }
754
    
755
0
    fn transpile_block_with_functions(&self, functions: &[TokenStream], statements: &[TokenStream], needs_polars: bool, needs_hashmap: bool) -> Result<TokenStream> {
756
        // No main function among extracted functions - create one for statements
757
0
        match (needs_polars, needs_hashmap) {
758
0
            (true, true) => Ok(quote! {
759
                use polars::prelude::*;
760
                use std::collections::HashMap;
761
                #(#functions)*
762
                fn main() { #(#statements)* }
763
            }),
764
0
            (true, false) => Ok(quote! {
765
                use polars::prelude::*;
766
                #(#functions)*
767
                fn main() { #(#statements)* }
768
            }),
769
0
            (false, true) => Ok(quote! {
770
                use std::collections::HashMap;
771
                #(#functions)*
772
                fn main() { #(#statements)* }
773
            }),
774
0
            (false, false) => Ok(quote! {
775
                #(#functions)*
776
                fn main() { #(#statements)* }
777
            })
778
        }
779
0
    }
780
    
781
    
782
0
    fn transpile_expression_program(&self, expr: &Expr, needs_polars: bool, needs_hashmap: bool) -> Result<TokenStream> {
783
0
        let body = self.transpile_expr(expr)?;
784
        
785
        // Check if this is a statement vs expression
786
0
        if self.is_statement_expr(expr) {
787
            // For statements, execute directly without result wrapping
788
0
            self.wrap_statement_in_main(body, needs_polars, needs_hashmap)
789
        } else {
790
            // For expressions, wrap with result printing
791
0
            self.wrap_in_main_with_result_printing(body, needs_polars, needs_hashmap)
792
        }
793
0
    }
794
    
795
0
    fn wrap_statement_in_main(&self, body: TokenStream, needs_polars: bool, needs_hashmap: bool) -> Result<TokenStream> {
796
        // For statements, execute directly without result capture
797
0
        match (needs_polars, needs_hashmap) {
798
0
            (true, true) => Ok(quote! {
799
0
                use polars::prelude::*;
800
0
                use std::collections::HashMap;
801
0
                fn main() {
802
0
                    #body;
803
0
                }
804
0
            }),
805
0
            (true, false) => Ok(quote! {
806
0
                use polars::prelude::*;
807
0
                fn main() {
808
0
                    #body;
809
0
                }
810
0
            }),
811
0
            (false, true) => Ok(quote! {
812
0
                use std::collections::HashMap;
813
0
                fn main() {
814
0
                    #body;
815
0
                }
816
0
            }),
817
0
            (false, false) => Ok(quote! {
818
0
                fn main() {
819
0
                    #body;
820
0
                }
821
0
            })
822
        }
823
0
    }
824
    
825
0
    fn wrap_in_main_with_result_printing(&self, body: TokenStream, needs_polars: bool, needs_hashmap: bool) -> Result<TokenStream> {
826
0
        let result_printing_logic = self.generate_result_printing_tokens();
827
0
        match (needs_polars, needs_hashmap) {
828
0
            (true, true) => Ok(quote! {
829
0
                use polars::prelude::*;
830
0
                use std::collections::HashMap;
831
0
                fn main() {
832
0
                    let result = #body;
833
0
                    #result_printing_logic
834
0
                }
835
0
            }),
836
0
            (true, false) => Ok(quote! {
837
0
                use polars::prelude::*;
838
0
                fn main() {
839
0
                    let result = #body;
840
0
                    #result_printing_logic
841
0
                }
842
0
            }),
843
            (false, true) => {
844
0
                Ok(quote! {
845
0
                    use std::collections::HashMap;
846
0
                    fn main() {
847
0
                        let result = #body;
848
0
                        #result_printing_logic
849
0
                    }
850
0
                })
851
            },
852
            (false, false) => {
853
0
                Ok(quote! {
854
0
                    fn main() {
855
0
                        let result = #body;
856
0
                        #result_printing_logic
857
0
                    }
858
0
                })
859
            }
860
        }
861
0
    }
862
863
    /// Transpiles an expression to a String
864
0
    pub fn transpile_to_string(&self, expr: &Expr) -> Result<String> {
865
0
        let tokens = self.transpile(expr)?;
866
867
        // Format the tokens with rustfmt-like style
868
0
        let mut result = String::new();
869
0
        let token_str = tokens.to_string();
870
871
        // Basic formatting: add newlines after semicolons and braces
872
0
        for ch in token_str.chars() {
873
0
            result.push(ch);
874
0
            if ch == ';' || ch == '{' {
875
0
                result.push('\n');
876
0
            }
877
        }
878
879
0
        Ok(result)
880
0
    }
881
882
    /// Generate minimal code for self-hosting (direct Rust mapping, no optimization)
883
0
    pub fn transpile_minimal(&self, expr: &Expr) -> Result<String> {
884
0
        codegen_minimal::MinimalCodeGen::gen_program(expr)
885
0
    }
886
887
    /// Check if a name is a Rust reserved keyword
888
0
    pub(crate) fn is_rust_reserved_keyword(name: &str) -> bool {
889
        // List of Rust reserved keywords that would conflict
890
0
        matches!(name, 
891
0
            "as" | "break" | "const" | "continue" | "crate" | "else" | "enum" | "extern" |
892
0
            "false" | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "match" |
893
0
            "mod" | "move" | "mut" | "pub" | "ref" | "return" | "self" | "Self" |
894
0
            "static" | "struct" | "super" | "trait" | "true" | "type" | "unsafe" |
895
0
            "use" | "where" | "while" | "async" | "await" | "dyn" | "final" | "try" |
896
0
            "abstract" | "become" | "box" | "do" | "override" | "priv" | "typeof" |
897
0
            "unsized" | "virtual" | "yield"
898
        )
899
0
    }
900
901
    /// Main expression transpilation dispatcher
902
    ///
903
    /// # Panics
904
    ///
905
    /// Panics if label names cannot be parsed as valid Rust tokens
906
0
    pub fn transpile_expr(&self, expr: &Expr) -> Result<TokenStream> {
907
        use ExprKind::{
908
            Actor, ActorQuery, ActorSend, Ask, Assign, AsyncBlock, Await, Binary, Call, Command, CompoundAssign, DataFrame, 
909
            DataFrameOperation, Err, FieldAccess, For, Function, Identifier, If, IfLet, IndexAccess, Lambda, 
910
            List, ListComprehension, Literal, Loop, Macro, Match, MethodCall, None, ObjectLiteral, Ok, QualifiedName, 
911
            Range, Send, Slice, Some, StringInterpolation, Struct, StructLiteral, Throw, Try, TryCatch, TypeCast,
912
            Tuple, Unary, While, WhileLet,
913
        };
914
915
        // Dispatch to specialized handlers to keep complexity below 10
916
0
        match &expr.kind {
917
            // Basic expressions
918
            Literal(_) | Identifier(_) | QualifiedName { .. } | StringInterpolation { .. } | TypeCast { .. } => {
919
0
                self.transpile_basic_expr(expr)
920
            }
921
922
            // Operators and control flow
923
            Binary { .. }
924
            | Unary { .. }
925
            | Assign { .. }
926
            | CompoundAssign { .. }
927
            | Await { .. }
928
            | AsyncBlock { .. }
929
            | If { .. }
930
            | IfLet { .. }
931
            | Match { .. }
932
            | For { .. }
933
            | While { .. }
934
            | WhileLet { .. }
935
            | Loop { .. }
936
0
            | TryCatch { .. } => self.transpile_operator_control_expr(expr),
937
938
            // Functions
939
            Function { .. } | Lambda { .. } | Call { .. } | MethodCall { .. } | Macro { .. } => {
940
0
                self.transpile_function_expr(expr)
941
            }
942
943
            // Structures
944
            Struct { .. } | StructLiteral { .. } | ObjectLiteral { .. } | FieldAccess { .. } 
945
            | IndexAccess { .. } | Slice { .. } => {
946
0
                self.transpile_struct_expr(expr)
947
            }
948
949
            // Data and error handling
950
            DataFrame { .. }
951
            | DataFrameOperation { .. }
952
            | List(_)
953
            | Tuple(_)
954
            | ListComprehension { .. }
955
            | Range { .. }
956
            | Throw { .. }
957
            | Ok { .. }
958
            | Err { .. }
959
            | Some { .. }
960
            | None
961
0
            | Try { .. } => self.transpile_data_error_expr(expr),
962
963
            // Actor system and process execution
964
0
            Actor { .. } | Send { .. } | Ask { .. } | ActorSend { .. } | ActorQuery { .. } | Command { .. } => self.transpile_actor_expr(expr),
965
966
            // Everything else
967
0
            _ => self.transpile_misc_expr(expr),
968
        }
969
0
    }
970
}