Coverage Report

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