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/statements.rs
Line
Count
Source
1
//! Statement and control flow transpilation
2
3
#![allow(clippy::missing_errors_doc)]
4
#![allow(clippy::wildcard_imports)]
5
#![allow(clippy::collapsible_else_if)]
6
7
use super::*;
8
use crate::frontend::ast::{CatchClause, Literal, Param, Pattern, PipelineStage, UnaryOp};
9
use anyhow::{Result, bail};
10
use proc_macro2::TokenStream;
11
use quote::{format_ident, quote};
12
13
impl Transpiler {
14
    /// Checks if a variable is mutated (reassigned or modified) in an expression tree
15
0
    fn is_variable_mutated(name: &str, expr: &Expr) -> bool {
16
        use crate::frontend::ast::ExprKind;
17
        
18
0
        match &expr.kind {
19
            // Direct assignment to the variable
20
0
            ExprKind::Assign { target, value: _ } => {
21
0
                if let ExprKind::Identifier(var_name) = &target.kind {
22
0
                    if var_name == name {
23
0
                        return true;
24
0
                    }
25
0
                }
26
0
                false
27
            }
28
            // Compound assignment (+=, -=, etc.)
29
0
            ExprKind::CompoundAssign { target, value: _, .. } => {
30
0
                if let ExprKind::Identifier(var_name) = &target.kind {
31
0
                    if var_name == name {
32
0
                        return true;
33
0
                    }
34
0
                }
35
0
                false
36
            }
37
            // Pre/Post increment/decrement
38
0
            ExprKind::PreIncrement { target } | 
39
0
            ExprKind::PostIncrement { target } |
40
0
            ExprKind::PreDecrement { target } |
41
0
            ExprKind::PostDecrement { target } => {
42
0
                if let ExprKind::Identifier(var_name) = &target.kind {
43
0
                    if var_name == name {
44
0
                        return true;
45
0
                    }
46
0
                }
47
0
                false
48
            }
49
            // Check in blocks
50
0
            ExprKind::Block(exprs) => {
51
0
                exprs.iter().any(|e| Self::is_variable_mutated(name, e))
52
            }
53
            // Check in if branches
54
0
            ExprKind::If { condition, then_branch, else_branch } => {
55
0
                Self::is_variable_mutated(name, condition) ||
56
0
                Self::is_variable_mutated(name, then_branch) ||
57
0
                else_branch.as_ref().is_some_and(|e| Self::is_variable_mutated(name, e))
58
            }
59
            // Check in while loops
60
0
            ExprKind::While { condition, body } => {
61
0
                Self::is_variable_mutated(name, condition) ||
62
0
                Self::is_variable_mutated(name, body)
63
            }
64
            // Check in for loops
65
0
            ExprKind::For { body, .. } => {
66
0
                Self::is_variable_mutated(name, body)
67
            }
68
            // Check in match expressions
69
0
            ExprKind::Match { expr, arms } => {
70
0
                Self::is_variable_mutated(name, expr) ||
71
0
                arms.iter().any(|arm| Self::is_variable_mutated(name, &arm.body))
72
            }
73
            // Check in nested let expressions
74
0
            ExprKind::Let { body, .. } | ExprKind::LetPattern { body, .. } => {
75
0
                Self::is_variable_mutated(name, body)
76
            }
77
            // Check in function bodies
78
0
            ExprKind::Function { body, .. } => {
79
0
                Self::is_variable_mutated(name, body)
80
            }
81
            // Check in lambda bodies
82
0
            ExprKind::Lambda { body, .. } => {
83
0
                Self::is_variable_mutated(name, body)
84
            }
85
            // Check binary operations
86
0
            ExprKind::Binary { left, right, .. } => {
87
0
                Self::is_variable_mutated(name, left) ||
88
0
                Self::is_variable_mutated(name, right)
89
            }
90
            // Check unary operations
91
0
            ExprKind::Unary { operand, .. } => {
92
0
                Self::is_variable_mutated(name, operand)
93
            }
94
            // Check function/method calls
95
0
            ExprKind::Call { func, args } => {
96
0
                Self::is_variable_mutated(name, func) ||
97
0
                args.iter().any(|a| Self::is_variable_mutated(name, a))
98
            }
99
0
            ExprKind::MethodCall { receiver, args, .. } => {
100
0
                Self::is_variable_mutated(name, receiver) ||
101
0
                args.iter().any(|a| Self::is_variable_mutated(name, a))
102
            }
103
            // Other expressions don't contain mutations
104
0
            _ => false,
105
        }
106
0
    }
107
108
    /// Transpiles if expressions
109
0
    pub fn transpile_if(
110
0
        &self,
111
0
        condition: &Expr,
112
0
        then_branch: &Expr,
113
0
        else_branch: Option<&Expr>,
114
0
    ) -> Result<TokenStream> {
115
0
        let cond_tokens = self.transpile_expr(condition)?;
116
0
        let then_tokens = self.transpile_expr(then_branch)?;
117
118
0
        if let Some(else_expr) = else_branch {
119
0
            let else_tokens = self.transpile_expr(else_expr)?;
120
0
            Ok(quote! {
121
0
                if #cond_tokens {
122
0
                    #then_tokens
123
0
                } else {
124
0
                    #else_tokens
125
0
                }
126
0
            })
127
        } else {
128
0
            Ok(quote! {
129
0
                if #cond_tokens {
130
0
                    #then_tokens
131
0
                }
132
0
            })
133
        }
134
0
    }
135
136
    /// Transpiles let bindings
137
0
    pub fn transpile_let(
138
0
        &self,
139
0
        name: &str,
140
0
        value: &Expr,
141
0
        body: &Expr,
142
0
        is_mutable: bool,
143
0
    ) -> Result<TokenStream> {
144
        // Handle Rust reserved keywords by prefixing with r#
145
0
        let safe_name = if Self::is_rust_reserved_keyword(name) {
146
0
            format!("r#{name}")
147
        } else {
148
0
            name.to_string()
149
        };
150
0
        let name_ident = format_ident!("{}", safe_name);
151
        
152
        // Auto-detect mutability: check if variable is in the mutable_vars set or is reassigned in body
153
0
        let effective_mutability = is_mutable || 
154
0
                                  self.mutable_vars.contains(name) || 
155
0
                                  Self::is_variable_mutated(name, body);
156
        
157
        // Convert string literals to String type at variable declaration time
158
        // This ensures string variables are String, not &str, making function calls work
159
0
        let value_tokens = match &value.kind {
160
0
            crate::frontend::ast::ExprKind::Literal(crate::frontend::ast::Literal::String(s)) => {
161
0
                quote! { #s.to_string() }
162
            }
163
0
            _ => self.transpile_expr(value)?
164
        };
165
        
166
        // HOTFIX: If body is Unit, this is a top-level let statement without scoping
167
0
        if matches!(body.kind, crate::frontend::ast::ExprKind::Literal(crate::frontend::ast::Literal::Unit)) {
168
0
            if effective_mutability {
169
0
                Ok(quote! { let mut #name_ident = #value_tokens; })
170
            } else {
171
0
                Ok(quote! { let #name_ident = #value_tokens; })
172
            }
173
        } else {
174
            // Check if body is a Block containing sequential let statements
175
            // This flattens nested let expressions to avoid excessive nesting
176
0
            if let crate::frontend::ast::ExprKind::Block(exprs) = &body.kind {
177
                // Flatten sequential let statements into a single block
178
0
                let mut statements = Vec::new();
179
                
180
                // Add the current let statement
181
0
                if effective_mutability {
182
0
                    statements.push(quote! { let mut #name_ident = #value_tokens; });
183
0
                } else {
184
0
                    statements.push(quote! { let #name_ident = #value_tokens; });
185
0
                }
186
                
187
                // Add all the block expressions
188
0
                for (i, expr) in exprs.iter().enumerate() {
189
0
                    let expr_tokens = self.transpile_expr(expr)?;
190
                    
191
                    // Check if this is a Let expression with Unit body (standalone let statement)
192
                    // These already have semicolons from transpile_let
193
0
                    let is_standalone_let = matches!(&expr.kind, 
194
0
                        crate::frontend::ast::ExprKind::Let { body, .. } 
195
0
                        if matches!(body.kind, crate::frontend::ast::ExprKind::Literal(crate::frontend::ast::Literal::Unit))
196
                    );
197
                    
198
0
                    if is_standalone_let {
199
0
                        // Standalone let statements already have semicolons
200
0
                        statements.push(expr_tokens);
201
0
                    } else if i < exprs.len() - 1 {
202
0
                        // Not the last statement - add semicolon
203
0
                        statements.push(quote! { #expr_tokens; });
204
0
                    } else {
205
                        // Last expression - check if it's void
206
0
                        if self.is_void_expression(expr) {
207
0
                            statements.push(quote! { #expr_tokens; });
208
0
                        } else {
209
0
                            statements.push(expr_tokens);
210
0
                        }
211
                    }
212
                }
213
                
214
0
                Ok(quote! { #(#statements)* })
215
            } else {
216
                // Traditional let-in expression with proper scoping
217
0
                let body_tokens = self.transpile_expr(body)?;
218
0
                if effective_mutability {
219
0
                    Ok(quote! {
220
0
                        {
221
0
                            let mut #name_ident = #value_tokens;
222
0
                            #body_tokens
223
0
                        }
224
0
                    })
225
                } else {
226
0
                    Ok(quote! {
227
0
                        {
228
0
                            let #name_ident = #value_tokens;
229
0
                            #body_tokens
230
0
                        }
231
0
                    })
232
                }
233
            }
234
        }
235
0
    }
236
237
    /// Transpiles let pattern bindings (destructuring)
238
0
    pub fn transpile_let_pattern(
239
0
        &self,
240
0
        pattern: &crate::frontend::ast::Pattern,
241
0
        value: &Expr,
242
0
        body: &Expr,
243
0
    ) -> Result<TokenStream> {
244
0
        let pattern_tokens = self.transpile_pattern(pattern)?;
245
0
        let value_tokens = self.transpile_expr(value)?;
246
        
247
        // HOTFIX: If body is Unit, this is a top-level let statement without scoping
248
0
        if matches!(body.kind, crate::frontend::ast::ExprKind::Literal(crate::frontend::ast::Literal::Unit)) {
249
0
            Ok(quote! { let #pattern_tokens = #value_tokens })
250
        } else {
251
            // Traditional let-in expression with proper scoping
252
0
            let body_tokens = self.transpile_expr(body)?;
253
0
            Ok(quote! {
254
0
                {
255
0
                    let #pattern_tokens = #value_tokens;
256
0
                    #body_tokens
257
0
                }
258
0
            })
259
        }
260
0
    }
261
262
    /// Check if function name suggests numeric operations
263
0
    fn looks_like_numeric_function(&self, name: &str) -> bool {
264
0
        matches!(name, 
265
0
            "add" | "subtract" | "multiply" | "divide" | "sum" | "product" | 
266
0
            "min" | "max" | "abs" | "sqrt" | "pow" | "mod" | "gcd" | "lcm" |
267
0
            "factorial" | "fibonacci" | "prime" | "even" | "odd" | "square" | "cube" |
268
0
            "double" | "triple" | "quadruple"  // Added common numeric function names
269
        )
270
0
    }
271
272
273
    /// Check if expression is a void/unit function call
274
0
    fn is_void_function_call(&self, expr: &Expr) -> bool {
275
0
        match &expr.kind {
276
0
            crate::frontend::ast::ExprKind::Call { func, .. } => {
277
0
                if let crate::frontend::ast::ExprKind::Identifier(name) = &func.kind {
278
                    // Comprehensive list of void functions
279
0
                    matches!(name.as_str(), 
280
                        // Output functions
281
0
                        "println" | "print" | "eprintln" | "eprint" |
282
                        // Debug functions
283
0
                        "dbg" | "debug" | "trace" | "info" | "warn" | "error" |
284
                        // Control flow functions
285
0
                        "panic" | "assert" | "assert_eq" | "assert_ne" |
286
0
                        "todo" | "unimplemented" | "unreachable"
287
                    )
288
                } else {
289
0
                    false
290
                }
291
            }
292
0
            _ => false
293
        }
294
0
    }
295
    
296
    /// Check if an expression is void (returns unit/nothing)
297
0
    fn is_void_expression(&self, expr: &Expr) -> bool {
298
0
        match &expr.kind {
299
            // Unit literal is void
300
0
            crate::frontend::ast::ExprKind::Literal(crate::frontend::ast::Literal::Unit) => true,
301
            
302
            // Void function calls
303
0
            crate::frontend::ast::ExprKind::Call { .. } if self.is_void_function_call(expr) => true,
304
            
305
            // Assignments are void
306
            crate::frontend::ast::ExprKind::Assign { .. } |
307
0
            crate::frontend::ast::ExprKind::CompoundAssign { .. } => true,
308
            
309
            // Loops are void
310
            crate::frontend::ast::ExprKind::While { .. } |
311
0
            crate::frontend::ast::ExprKind::For { .. } => true,
312
            
313
            // Let bindings - check the body expression
314
0
            crate::frontend::ast::ExprKind::Let { body, .. } => {
315
0
                self.is_void_expression(body)
316
            }
317
            
318
            // Block - check last expression
319
0
            crate::frontend::ast::ExprKind::Block(exprs) => {
320
0
                exprs.last().is_none_or(|e| self.is_void_expression(e))
321
            }
322
            
323
            // If expression - both branches must be void
324
0
            crate::frontend::ast::ExprKind::If { then_branch, else_branch, .. } => {
325
0
                self.is_void_expression(then_branch) && 
326
0
                else_branch.as_ref().is_none_or(|e| self.is_void_expression(e))
327
            }
328
            
329
            // Match expression - all arms must be void
330
0
            crate::frontend::ast::ExprKind::Match { arms, .. } => {
331
0
                arms.iter().all(|arm| self.is_void_expression(&arm.body))
332
            }
333
            
334
            // Return without value is void
335
0
            crate::frontend::ast::ExprKind::Return { value } if value.is_none() => true,
336
            
337
            // Everything else produces a value
338
0
            _ => false
339
        }
340
0
    }
341
342
    /// Check if expression has a non-unit value (i.e., returns something meaningful)
343
0
    fn has_non_unit_expression(&self, body: &Expr) -> bool {
344
0
        !self.is_void_expression(body)
345
0
    }
346
347
348
    /// Transpiles function definitions
349
    #[allow(clippy::too_many_arguments)]
350
    /// Infer parameter type based on usage in function body
351
0
    fn infer_param_type(&self, param: &Param, body: &Expr, func_name: &str) -> TokenStream {
352
        use super::type_inference::{is_param_used_as_function, is_param_used_numerically, is_param_used_as_function_argument};
353
        
354
0
        if is_param_used_as_function(&param.name(), body) {
355
0
            quote! { impl Fn(i32) -> i32 }
356
0
        } else if is_param_used_numerically(&param.name(), body) || 
357
0
                  self.looks_like_numeric_function(func_name) ||
358
0
                  is_param_used_as_function_argument(&param.name(), body) {
359
0
            quote! { i32 }
360
        } else {
361
0
            quote! { String }
362
        }
363
0
    }
364
365
    /// Generate parameter tokens with proper type inference
366
0
    fn generate_param_tokens(&self, params: &[Param], body: &Expr, func_name: &str) -> Result<Vec<TokenStream>> {
367
0
        params
368
0
            .iter()
369
0
            .map(|p| {
370
0
                let param_name = format_ident!("{}", p.name());
371
0
                let type_tokens = if let Ok(tokens) = self.transpile_type(&p.ty) {
372
0
                    let token_str = tokens.to_string();
373
0
                    if token_str == "_" {
374
0
                        self.infer_param_type(p, body, func_name)
375
                    } else {
376
0
                        tokens
377
                    }
378
                } else {
379
0
                    self.infer_param_type(p, body, func_name)
380
                };
381
0
                Ok(quote! { #param_name: #type_tokens })
382
0
            })
383
0
            .collect()
384
0
    }
385
386
    /// Generate return type tokens based on function analysis
387
0
    fn generate_return_type_tokens(&self, name: &str, return_type: Option<&Type>, body: &Expr) -> Result<TokenStream> {
388
        // FIRST CHECK: Override for test functions
389
0
        if name.starts_with("test_") {
390
0
            return Ok(quote! {});
391
0
        }
392
        
393
0
        if let Some(ty) = return_type {
394
0
            let ty_tokens = self.transpile_type(ty)?;
395
0
            Ok(quote! { -> #ty_tokens })
396
0
        } else if name == "main" {
397
0
            Ok(quote! {})
398
0
        } else if self.looks_like_numeric_function(name) {
399
0
            Ok(quote! { -> i32 })
400
0
        } else if self.has_non_unit_expression(body) {
401
0
            Ok(quote! { -> i32 })
402
        } else {
403
0
            Ok(quote! {})
404
        }
405
0
    }
406
407
    /// Generate body tokens with async support
408
0
    fn generate_body_tokens(&self, body: &Expr, is_async: bool) -> Result<TokenStream> {
409
0
        if is_async {
410
0
            let mut async_transpiler = Transpiler::new();
411
0
            async_transpiler.in_async_context = true;
412
0
            async_transpiler.transpile_expr(body)
413
        } else {
414
            // Check if body is already a block to avoid double-wrapping
415
0
            match &body.kind {
416
0
                ExprKind::Block(exprs) => {
417
                    // For function bodies that are blocks, transpile the contents directly
418
0
                    if exprs.len() == 1 {
419
                        // Single expression block - transpile the expression directly
420
0
                        self.transpile_expr(&exprs[0])
421
                    } else {
422
                        // Multiple expressions - need proper semicolons between statements
423
0
                        let mut statements = Vec::new();
424
0
                        for (i, expr) in exprs.iter().enumerate() {
425
0
                            let expr_tokens = self.transpile_expr(expr)?;
426
                            
427
                            // Add semicolons to all statements except the last one
428
                            // (unless it's a void expression that needs a semicolon)
429
0
                            if i < exprs.len() - 1 {
430
0
                                // Not the last statement - always add semicolon
431
0
                                statements.push(quote! { #expr_tokens; });
432
0
                            } else {
433
                                // Last statement - check if it's void
434
0
                                if self.is_void_expression(expr) {
435
0
                                    // Void expressions should have semicolons
436
0
                                    statements.push(quote! { #expr_tokens; });
437
0
                                } else {
438
0
                                    // Non-void last expression - no semicolon (it's the return value)
439
0
                                    statements.push(expr_tokens);
440
0
                                }
441
                            }
442
                        }
443
                        
444
0
                        if statements.is_empty() {
445
0
                            Ok(quote! {})
446
                        } else {
447
0
                            Ok(quote! { #(#statements)* })
448
                        }
449
                    }
450
                },
451
                _ => {
452
                    // Not a block - transpile normally
453
0
                    self.transpile_expr(body)
454
                }
455
            }
456
        }
457
0
    }
458
459
    /// Generate type parameter tokens with trait bound support
460
0
    fn generate_type_param_tokens(&self, type_params: &[String]) -> Result<Vec<TokenStream>> {
461
0
        Ok(type_params
462
0
            .iter()
463
0
            .map(|p| {
464
0
                if p.contains(':') {
465
                    // Complex trait bound - parse as TokenStream
466
0
                    p.parse().unwrap_or_else(|_| quote! { T })
467
                } else {
468
                    // Simple type parameter
469
0
                    let ident = format_ident!("{}", p);
470
0
                    quote! { #ident }
471
                }
472
0
            })
473
0
            .collect())
474
0
    }
475
476
    /// Generate complete function signature
477
0
    fn generate_function_signature(
478
0
        &self,
479
0
        is_pub: bool,
480
0
        is_async: bool,
481
0
        fn_name: &proc_macro2::Ident,
482
0
        type_param_tokens: &[TokenStream],
483
0
        param_tokens: &[TokenStream],
484
0
        return_type_tokens: &TokenStream,
485
0
        body_tokens: &TokenStream,
486
0
        attributes: &[crate::frontend::ast::Attribute],
487
0
    ) -> Result<TokenStream> {
488
        // Override return type for test functions
489
0
        let final_return_type = if fn_name.to_string().starts_with("test_") {
490
0
            quote! {}
491
        } else {
492
0
            return_type_tokens.clone()
493
        };
494
0
        let visibility = if is_pub { quote! { pub } } else { quote! {} };
495
        
496
        // Generate attribute tokens
497
0
        let attr_tokens: Vec<TokenStream> = attributes.iter()
498
0
            .map(|attr| {
499
0
                let attr_name = format_ident!("{}", attr.name);
500
0
                if attr.args.is_empty() {
501
0
                    quote! { #[#attr_name] }
502
                } else {
503
0
                    let args: Vec<TokenStream> = attr.args.iter()
504
0
                        .map(|arg| arg.parse().unwrap_or_else(|_| quote! { #arg }))
505
0
                        .collect();
506
0
                    quote! { #[#attr_name(#(#args),*)] }
507
                }
508
0
            })
509
0
            .collect();
510
        
511
0
        Ok(match (type_param_tokens.is_empty(), is_async) {
512
0
            (true, false) => quote! {
513
                #(#attr_tokens)*
514
                #visibility fn #fn_name(#(#param_tokens),*) #final_return_type {
515
                    #body_tokens
516
                }
517
            },
518
0
            (true, true) => quote! {
519
                #(#attr_tokens)*
520
                #visibility async fn #fn_name(#(#param_tokens),*) #final_return_type {
521
                    #body_tokens
522
                }
523
            },
524
0
            (false, false) => quote! {
525
                #(#attr_tokens)*
526
                #visibility fn #fn_name<#(#type_param_tokens),*>(#(#param_tokens),*) #final_return_type {
527
                    #body_tokens
528
                }
529
            },
530
0
            (false, true) => quote! {
531
                #(#attr_tokens)*
532
                #visibility async fn #fn_name<#(#type_param_tokens),*>(#(#param_tokens),*) #final_return_type {
533
                    #body_tokens
534
                }
535
            },
536
        })
537
0
    }
538
539
0
    pub fn transpile_function(
540
0
        &self,
541
0
        name: &str,
542
0
        type_params: &[String],
543
0
        params: &[Param],
544
0
        body: &Expr,
545
0
        is_async: bool,
546
0
        return_type: Option<&Type>,
547
0
        is_pub: bool,
548
0
        attributes: &[crate::frontend::ast::Attribute],
549
0
    ) -> Result<TokenStream> {
550
0
        let fn_name = format_ident!("{}", name);
551
0
        let param_tokens = self.generate_param_tokens(params, body, name)?;
552
0
        let body_tokens = self.generate_body_tokens(body, is_async)?;
553
        
554
        // Check for #[test] attribute and override return type if found
555
0
        let has_test_attribute = attributes.iter().any(|attr| attr.name == "test");
556
        
557
0
        let effective_return_type = if has_test_attribute {
558
0
            None // Test functions should have unit return type
559
        } else {
560
0
            return_type
561
        };
562
        
563
0
        let return_type_tokens = self.generate_return_type_tokens(name, effective_return_type, body)?;
564
0
        let type_param_tokens = self.generate_type_param_tokens(type_params)?;
565
566
0
        self.generate_function_signature(
567
0
            is_pub, 
568
0
            is_async, 
569
0
            &fn_name, 
570
0
            &type_param_tokens, 
571
0
            &param_tokens, 
572
0
            &return_type_tokens, 
573
0
            &body_tokens,
574
0
            attributes
575
        )
576
0
    }
577
578
    /// Transpiles lambda expressions
579
0
    pub fn transpile_lambda(&self, params: &[Param], body: &Expr) -> Result<TokenStream> {
580
0
        let param_names: Vec<_> = params
581
0
            .iter()
582
0
            .map(|p| format_ident!("{}", p.name()))
583
0
            .collect();
584
0
        let body_tokens = self.transpile_expr(body)?;
585
586
        // Generate closure with proper formatting (no spaces around commas)
587
0
        if param_names.is_empty() {
588
0
            Ok(quote! { || #body_tokens })
589
        } else {
590
            // Use a more controlled approach to avoid extra spaces
591
0
            let param_list = param_names
592
0
                .iter()
593
0
                .map(std::string::ToString::to_string)
594
0
                .collect::<Vec<_>>()
595
0
                .join(",");
596
0
            let closure_str = format!("|{param_list}| {body_tokens}");
597
0
            closure_str
598
0
                .parse()
599
0
                .map_err(|e| anyhow::anyhow!("Failed to parse closure: {}", e))
600
        }
601
0
    }
602
603
    /// Transpiles function calls
604
    /// 
605
    /// # Examples
606
    /// 
607
    /// ```
608
    /// use ruchy::{Transpiler, Parser};
609
    /// 
610
    /// let transpiler = Transpiler::new();
611
    /// let mut parser = Parser::new(r#"println("Hello, {}", name)"#);
612
    /// let ast = parser.parse().unwrap();
613
    /// let result = transpiler.transpile(&ast).unwrap().to_string();
614
    /// assert!(result.contains("println !"));
615
    /// assert!(result.contains("Hello, {}"));
616
    /// ```
617
    /// 
618
    /// ```
619
    /// use ruchy::{Transpiler, Parser};
620
    /// 
621
    /// let transpiler = Transpiler::new();
622
    /// let mut parser = Parser::new(r#"println("Simple message")"#);
623
    /// let ast = parser.parse().unwrap();
624
    /// let result = transpiler.transpile(&ast).unwrap().to_string();
625
    /// assert!(result.contains("println !"));
626
    /// assert!(result.contains("Simple message"));
627
    /// ```
628
    /// 
629
    /// ```
630
    /// use ruchy::{Transpiler, Parser};
631
    /// 
632
    /// let transpiler = Transpiler::new();
633
    /// let mut parser = Parser::new("some_function(\"test\")");
634
    /// let ast = parser.parse().unwrap();
635
    /// let result = transpiler.transpile(&ast).unwrap().to_string();
636
    /// assert!(result.contains("some_function"));
637
    /// assert!(result.contains("test"));
638
    /// ```
639
0
    pub fn transpile_call(&self, func: &Expr, args: &[Expr]) -> Result<TokenStream> {
640
0
        let func_tokens = self.transpile_expr(func)?;
641
642
        // Check if this is a built-in function with special handling
643
0
        if let ExprKind::Identifier(name) = &func.kind {
644
0
            let base_name = if name.ends_with('!') {
645
0
                name.strip_suffix('!').unwrap_or(name)
646
            } else {
647
0
                name
648
            };
649
            
650
            // Try specialized handlers in order of precedence
651
0
            if let Some(result) = self.try_transpile_print_macro(&func_tokens, base_name, args)? {
652
0
                return Ok(result);
653
0
            }
654
            
655
0
            if let Some(result) = self.try_transpile_math_function(base_name, args)? {
656
0
                return Ok(result);
657
0
            }
658
            
659
0
            if let Some(result) = self.try_transpile_input_function(base_name, args)? {
660
0
                return Ok(result);
661
0
            }
662
            
663
0
            if let Some(result) = self.try_transpile_assert_function(&func_tokens, base_name, args)? {
664
0
                return Ok(result);
665
0
            }
666
            
667
0
            if let Some(result) = self.try_transpile_type_conversion(base_name, args)? {
668
0
                return Ok(result);
669
0
            }
670
            
671
0
            if let Some(result) = self.try_transpile_math_functions(base_name, args)? {
672
0
                return Ok(result);
673
0
            }
674
            
675
0
            if let Some(result) = self.try_transpile_collection_constructor(base_name, args)? {
676
0
                return Ok(result);
677
0
            }
678
            
679
0
            if let Some(result) = self.try_transpile_dataframe_function(base_name, args)? {
680
0
                return Ok(result);
681
0
            }
682
0
        }
683
684
        // Default: regular function call with string conversion
685
0
        self.transpile_regular_function_call(&func_tokens, args)
686
0
    }
687
688
689
    /// Transpiles println/print with string interpolation directly
690
0
    fn transpile_print_with_interpolation(
691
0
        &self,
692
0
        func_name: &str,
693
0
        parts: &[crate::frontend::ast::StringPart],
694
0
    ) -> Result<TokenStream> {
695
0
        if parts.is_empty() {
696
0
            let func_tokens = proc_macro2::Ident::new(func_name, proc_macro2::Span::call_site());
697
0
            return Ok(quote! { #func_tokens!("") });
698
0
        }
699
700
0
        let mut format_string = String::new();
701
0
        let mut args = Vec::new();
702
703
0
        for part in parts {
704
0
            match part {
705
0
                crate::frontend::ast::StringPart::Text(s) => {
706
0
                    // Escape any format specifiers in literal parts
707
0
                    format_string.push_str(&s.replace('{', "{{").replace('}', "}}"));
708
0
                }
709
0
                crate::frontend::ast::StringPart::Expr(expr) => {
710
0
                    format_string.push_str("{}");
711
0
                    let expr_tokens = self.transpile_expr(expr)?;
712
0
                    args.push(expr_tokens);
713
                }
714
0
                crate::frontend::ast::StringPart::ExprWithFormat { expr, format_spec } => {
715
                    // Include the format specifier in the format string
716
0
                    format_string.push('{');
717
0
                    format_string.push_str(format_spec);
718
0
                    format_string.push('}');
719
0
                    let expr_tokens = self.transpile_expr(expr)?;
720
0
                    args.push(expr_tokens);
721
                }
722
            }
723
        }
724
725
0
        let func_tokens = proc_macro2::Ident::new(func_name, proc_macro2::Span::call_site());
726
727
0
        Ok(quote! {
728
            #func_tokens!(#format_string #(, #args)*)
729
        })
730
0
    }
731
732
    /// Transpiles method calls
733
    #[allow(clippy::cognitive_complexity)]
734
0
    pub fn transpile_method_call(
735
0
        &self,
736
0
        object: &Expr,
737
0
        method: &str,
738
0
        args: &[Expr],
739
0
    ) -> Result<TokenStream> {
740
        // Check if this is part of a DataFrame builder pattern
741
0
        if method == "column" || method == "build" {
742
            // Build the full method call expression to check for builder pattern
743
0
            let method_call_expr = Expr {
744
0
                kind: ExprKind::MethodCall {
745
0
                    receiver: Box::new(object.clone()),
746
0
                    method: method.to_string(),
747
0
                    args: args.to_vec(),
748
0
                },
749
0
                span: object.span,
750
0
                attributes: vec![],
751
0
            };
752
            
753
0
            if let Some(tokens) = self.transpile_dataframe_builder(&method_call_expr)? {
754
0
                return Ok(tokens);
755
0
            }
756
0
        }
757
        
758
        // Use the old implementation for other cases
759
0
        self.transpile_method_call_old(object, method, args)
760
0
    }
761
    
762
    #[allow(dead_code)]
763
0
    fn transpile_method_call_old(
764
0
        &self,
765
0
        object: &Expr,
766
0
        method: &str,
767
0
        args: &[Expr],
768
0
    ) -> Result<TokenStream> {
769
0
        let obj_tokens = self.transpile_expr(object)?;
770
0
        let method_ident = format_ident!("{}", method);
771
0
        let arg_tokens: Result<Vec<_>> = args.iter().map(|a| self.transpile_expr(a)).collect();
772
0
        let arg_tokens = arg_tokens?;
773
774
        // Check DataFrame methods FIRST before generic collection methods
775
0
        if self.is_dataframe_expr(object) && matches!(method, 
776
0
            "get" | "rows" | "columns" | "select" | "filter" | "sort" | 
777
0
            "head" | "tail" | "mean" | "std" | "min" | "max" | "sum" | "count"
778
        ) {
779
0
            return self.transpile_dataframe_method(object, method, args);
780
0
        }
781
        
782
        // Dispatch to specialized handlers based on method category
783
0
        match method {
784
            // Iterator operations (map, filter, reduce)
785
0
            "map" | "filter" | "reduce" => {
786
0
                self.transpile_iterator_methods(&obj_tokens, method, &arg_tokens)
787
            }
788
            // HashMap/HashSet methods (get, contains_key, items, etc.)
789
0
            "get" | "contains_key" | "keys" | "values" | "entry" | "items" |
790
0
            "update" | "add" => {
791
0
                self.transpile_map_set_methods(&obj_tokens, &method_ident, method, &arg_tokens)
792
            }
793
            // Set operations (union, intersection, difference, symmetric_difference)
794
0
            "union" | "intersection" | "difference" | "symmetric_difference" => {
795
0
                self.transpile_set_operations(&obj_tokens, method, &arg_tokens)
796
            }
797
            // Common collection methods (insert, remove, clear, len, is_empty, iter)
798
0
            "insert" | "remove" | "clear" | "len" | "is_empty" | "iter" => {
799
0
                Ok(quote! { #obj_tokens.#method_ident(#(#arg_tokens),*) })
800
            }
801
            // DataFrame operations - use special handling for correct Polars API
802
0
            "select" | "groupby" | "group_by" | "agg" | "sort" | "mean" | "std" | "min"
803
0
            | "max" | "sum" | "count" | "drop_nulls" | "fill_null" | "pivot"
804
0
            | "melt" | "head" | "tail" | "sample" | "describe" | "rows" | "columns" | "column" | "build" => {
805
                // Check if this is a DataFrame operation
806
0
                if self.is_dataframe_expr(object) {
807
0
                    self.transpile_dataframe_method(object, method, args)
808
                } else {
809
0
                    Ok(quote! { #obj_tokens.#method_ident(#(#arg_tokens),*) })
810
                }
811
            }
812
            // String methods (Python-style and Rust-style)
813
0
            "to_s" | "to_string" | "to_upper" | "to_lower" | "upper" | "lower" | 
814
0
            "length" | "substring" | "strip" | "lstrip" | "rstrip" | 
815
0
            "startswith" | "endswith" | "split" | "replace" => {
816
0
                self.transpile_string_methods(&obj_tokens, method, &arg_tokens)
817
            }
818
            // List/Vec methods (Python-style)
819
0
            "append" => {
820
                // Python's append() -> Rust's push()
821
0
                Ok(quote! { #obj_tokens.push(#(#arg_tokens),*) })
822
            }
823
0
            "extend" => {
824
                // Python's extend() -> Rust's extend()
825
0
                Ok(quote! { #obj_tokens.extend(#(#arg_tokens),*) })
826
            }
827
            // Collection methods that work as-is (not already handled above)
828
0
            "push" | "pop" | "contains" => {
829
0
                Ok(quote! { #obj_tokens.#method_ident(#(#arg_tokens),*) })
830
            }
831
            // Advanced collection methods (slice, concat, flatten, unique, join)
832
0
            "slice" | "concat" | "flatten" | "unique" | "join" => {
833
0
                self.transpile_advanced_collection_methods(&obj_tokens, method, &arg_tokens)
834
            }
835
            _ => {
836
                // Regular method call
837
0
                Ok(quote! { #obj_tokens.#method_ident(#(#arg_tokens),*) })
838
            }
839
        }
840
0
    }
841
    
842
    /// Handle iterator operations: map, filter, reduce
843
0
    fn transpile_iterator_methods(&self, obj_tokens: &TokenStream, method: &str, arg_tokens: &[TokenStream]) -> Result<TokenStream> {
844
0
        match method {
845
0
            "map" => {
846
                // vec.map(f) -> vec.iter().map(f).collect::<Vec<_>>()
847
0
                Ok(quote! { #obj_tokens.iter().map(#(#arg_tokens),*).collect::<Vec<_>>() })
848
            }
849
0
            "filter" => {
850
                // vec.filter(f) -> vec.into_iter().filter(f).collect::<Vec<_>>()
851
0
                Ok(quote! { #obj_tokens.into_iter().filter(#(#arg_tokens),*).collect::<Vec<_>>() })
852
            }
853
0
            "reduce" => {
854
                // vec.reduce(f) -> vec.into_iter().reduce(f)
855
0
                Ok(quote! { #obj_tokens.into_iter().reduce(#(#arg_tokens),*) })
856
            }
857
0
            _ => unreachable!("Non-iterator method passed to transpile_iterator_methods"),
858
        }
859
0
    }
860
    
861
    /// Handle HashMap/HashSet methods: get, `contains_key`, items, etc.
862
0
    fn transpile_map_set_methods(&self, obj_tokens: &TokenStream, method_ident: &proc_macro2::Ident, method: &str, arg_tokens: &[TokenStream]) -> Result<TokenStream> {
863
0
        match method {
864
0
            "get" => {
865
                // HashMap.get() returns Option<&V>, but we want owned values
866
0
                Ok(quote! { #obj_tokens.#method_ident(#(#arg_tokens),*).cloned() })
867
            }
868
0
            "contains_key" | "keys" | "values" | "entry" | "contains" => {
869
0
                Ok(quote! { #obj_tokens.#method_ident(#(#arg_tokens),*) })
870
            }
871
0
            "items" => {
872
                // HashMap.items() -> iterator of (K, V) tuples (not references)
873
0
                Ok(quote! { #obj_tokens.iter().map(|(k, v)| (k.clone(), v.clone())) })
874
            }
875
0
            "update" => {
876
                // Python dict.update(other) -> Rust HashMap.extend(other)
877
0
                Ok(quote! { #obj_tokens.extend(#(#arg_tokens),*) })
878
            }
879
0
            "add" => {
880
                // Python set.add(item) -> Rust HashSet.insert(item)
881
0
                Ok(quote! { #obj_tokens.insert(#(#arg_tokens),*) })
882
            }
883
0
            _ => unreachable!("Non-map/set method {} passed to transpile_map_set_methods", method),
884
        }
885
0
    }
886
    
887
    /// Handle `HashSet` set operations: union, intersection, difference, `symmetric_difference`
888
0
    fn transpile_set_operations(&self, obj_tokens: &TokenStream, method: &str, arg_tokens: &[TokenStream]) -> Result<TokenStream> {
889
0
        if arg_tokens.len() != 1 {
890
0
            bail!("{} requires exactly 1 argument", method);
891
0
        }
892
0
        let other = &arg_tokens[0];
893
0
        let method_ident = format_ident!("{}", method);
894
0
        Ok(quote! { 
895
0
            {
896
0
                use std::collections::HashSet;
897
0
                #obj_tokens.#method_ident(&#other).cloned().collect::<HashSet<_>>()
898
0
            }
899
0
        })
900
0
    }
901
    
902
    /// Handle string methods: Python-style and Rust-style
903
0
    fn transpile_string_methods(&self, obj_tokens: &TokenStream, method: &str, arg_tokens: &[TokenStream]) -> Result<TokenStream> {
904
0
        match method {
905
0
            "to_s" | "to_string" => {
906
                // Convert any value to string - already a String stays String
907
0
                Ok(quote! { #obj_tokens })
908
            }
909
0
            "to_upper" | "upper" => {
910
0
                let rust_method = format_ident!("to_uppercase");
911
0
                Ok(quote! { #obj_tokens.#rust_method(#(#arg_tokens),*) })
912
            }
913
0
            "to_lower" | "lower" => {
914
0
                let rust_method = format_ident!("to_lowercase");
915
0
                Ok(quote! { #obj_tokens.#rust_method(#(#arg_tokens),*) })
916
            }
917
0
            "strip" => {
918
0
                Ok(quote! { #obj_tokens.trim().to_string() })
919
            }
920
0
            "lstrip" => {
921
0
                Ok(quote! { #obj_tokens.trim_start() })
922
            }
923
0
            "rstrip" => {
924
0
                Ok(quote! { #obj_tokens.trim_end() })
925
            }
926
0
            "startswith" => {
927
0
                Ok(quote! { #obj_tokens.starts_with(#(#arg_tokens),*) })
928
            }
929
0
            "endswith" => {
930
0
                Ok(quote! { #obj_tokens.ends_with(#(#arg_tokens),*) })
931
            }
932
0
            "split" => {
933
0
                Ok(quote! { #obj_tokens.split(#(#arg_tokens),*) })
934
            }
935
0
            "replace" => {
936
0
                Ok(quote! { #obj_tokens.replace(#(#arg_tokens),*) })
937
            }
938
0
            "length" => {
939
                // Map Ruchy's length() to Rust's len()
940
0
                let rust_method = format_ident!("len");
941
0
                Ok(quote! { #obj_tokens.#rust_method(#(#arg_tokens),*) })
942
            }
943
0
            "substring" => {
944
                // string.substring(start, end) -> string.chars().skip(start).take(end-start).collect()
945
0
                if arg_tokens.len() != 2 {
946
0
                    bail!("substring requires exactly 2 arguments");
947
0
                }
948
0
                let start = &arg_tokens[0];
949
0
                let end = &arg_tokens[1];
950
0
                Ok(quote! { 
951
0
                    #obj_tokens.chars()
952
0
                        .skip(#start as usize)
953
0
                        .take((#end as usize).saturating_sub(#start as usize))
954
0
                        .collect::<String>()
955
0
                })
956
            }
957
0
            _ => unreachable!("Non-string method {} passed to transpile_string_methods", method),
958
        }
959
0
    }
960
    
961
    /// Handle advanced collection methods: slice, concat, flatten, unique, join
962
0
    fn transpile_advanced_collection_methods(&self, obj_tokens: &TokenStream, method: &str, arg_tokens: &[TokenStream]) -> Result<TokenStream> {
963
0
        match method {
964
0
            "slice" => {
965
                // vec.slice(start, end) -> vec[start..end].to_vec()
966
0
                if arg_tokens.len() != 2 {
967
0
                    bail!("slice requires exactly 2 arguments");
968
0
                }
969
0
                let start = &arg_tokens[0];
970
0
                let end = &arg_tokens[1];
971
0
                Ok(quote! { #obj_tokens[#start as usize..#end as usize].to_vec() })
972
            }
973
0
            "concat" => {
974
                // vec.concat(other) -> [vec, other].concat()
975
0
                if arg_tokens.len() != 1 {
976
0
                    bail!("concat requires exactly 1 argument");
977
0
                }
978
0
                let other = &arg_tokens[0];
979
0
                Ok(quote! { [#obj_tokens, #other].concat() })
980
            }
981
0
            "flatten" => {
982
                // vec.flatten() -> vec.into_iter().flatten().collect()
983
0
                if !arg_tokens.is_empty() {
984
0
                    bail!("flatten requires no arguments");
985
0
                }
986
0
                Ok(quote! { #obj_tokens.into_iter().flatten().collect::<Vec<_>>() })
987
            }
988
0
            "unique" => {
989
                // vec.unique() -> vec.into_iter().collect::<HashSet<_>>().into_iter().collect()
990
0
                if !arg_tokens.is_empty() {
991
0
                    bail!("unique requires no arguments");
992
0
                }
993
0
                Ok(quote! { 
994
0
                    {
995
0
                        use std::collections::HashSet;
996
0
                        #obj_tokens.into_iter().collect::<HashSet<_>>().into_iter().collect::<Vec<_>>()
997
0
                    }
998
0
                })
999
            }
1000
0
            "join" => {
1001
                // vec.join(separator) -> vec.join(separator) (for Vec<String>)
1002
0
                if arg_tokens.len() != 1 {
1003
0
                    bail!("join requires exactly 1 argument");
1004
0
                }
1005
0
                let separator = &arg_tokens[0];
1006
0
                Ok(quote! { #obj_tokens.join(&#separator) })
1007
            }
1008
0
            _ => unreachable!("Non-advanced-collection method passed to transpile_advanced_collection_methods"),
1009
        }
1010
0
    }
1011
1012
    /// Transpiles blocks
1013
0
    pub fn transpile_block(&self, exprs: &[Expr]) -> Result<TokenStream> {
1014
0
        if exprs.is_empty() {
1015
0
            return Ok(quote! { {} });
1016
0
        }
1017
1018
0
        let mut statements = Vec::new();
1019
1020
0
        for (i, expr) in exprs.iter().enumerate() {
1021
0
            let expr_tokens = self.transpile_expr(expr)?;
1022
1023
            // HOTFIX: Never add semicolon to the last expression in a block (it should be the return value)  
1024
0
            if i < exprs.len() - 1 {
1025
0
                statements.push(quote! { #expr_tokens; });
1026
0
            } else {
1027
0
                statements.push(expr_tokens);
1028
0
            }
1029
        }
1030
1031
0
        Ok(quote! {
1032
            {
1033
                #(#statements)*
1034
            }
1035
        })
1036
0
    }
1037
1038
1039
    /// Transpiles pipeline expressions
1040
0
    pub fn transpile_pipeline(&self, expr: &Expr, stages: &[PipelineStage]) -> Result<TokenStream> {
1041
0
        let mut result = self.transpile_expr(expr)?;
1042
1043
0
        for stage in stages {
1044
            // Each stage contains an expression to apply
1045
0
            let stage_expr = &stage.op;
1046
1047
            // Apply the stage - check what kind of expression it is
1048
0
            match &stage_expr.kind {
1049
0
                ExprKind::Call { func, args } => {
1050
0
                    let func_tokens = self.transpile_expr(func)?;
1051
0
                    let arg_tokens: Result<Vec<_>> =
1052
0
                        args.iter().map(|a| self.transpile_expr(a)).collect();
1053
0
                    let arg_tokens = arg_tokens?;
1054
1055
                    // Pipeline passes the previous result as the first argument
1056
0
                    result = quote! { #func_tokens(#result #(, #arg_tokens)*) };
1057
                }
1058
0
                ExprKind::MethodCall { method, args, .. } => {
1059
0
                    let method_ident = format_ident!("{}", method);
1060
0
                    let arg_tokens: Result<Vec<_>> =
1061
0
                        args.iter().map(|a| self.transpile_expr(a)).collect();
1062
0
                    let arg_tokens = arg_tokens?;
1063
1064
0
                    result = quote! { #result.#method_ident(#(#arg_tokens),*) };
1065
                }
1066
                _ => {
1067
                    // For other expressions, apply them directly
1068
0
                    let stage_tokens = self.transpile_expr(stage_expr)?;
1069
0
                    result = quote! { #stage_tokens(#result) };
1070
                }
1071
            }
1072
        }
1073
1074
0
        Ok(result)
1075
0
    }
1076
1077
    /// Transpiles for loops
1078
0
    pub fn transpile_for(&self, var: &str, pattern: Option<&Pattern>, iter: &Expr, body: &Expr) -> Result<TokenStream> {
1079
0
        let iter_tokens = self.transpile_expr(iter)?;
1080
0
        let body_tokens = self.transpile_expr(body)?;
1081
1082
        // If we have a pattern, use it for destructuring
1083
0
        if let Some(pat) = pattern {
1084
0
            let pattern_tokens = self.transpile_pattern(pat)?;
1085
0
            Ok(quote! {
1086
0
                for #pattern_tokens in #iter_tokens {
1087
0
                    #body_tokens
1088
0
                }
1089
0
            })
1090
        } else {
1091
            // Fall back to simple variable
1092
0
            let var_ident = format_ident!("{}", var);
1093
0
            Ok(quote! {
1094
0
                for #var_ident in #iter_tokens {
1095
0
                    #body_tokens
1096
0
                }
1097
0
            })
1098
        }
1099
0
    }
1100
1101
    /// Transpiles while loops
1102
0
    pub fn transpile_while(&self, condition: &Expr, body: &Expr) -> Result<TokenStream> {
1103
0
        let cond_tokens = self.transpile_expr(condition)?;
1104
0
        let body_tokens = self.transpile_expr(body)?;
1105
1106
0
        Ok(quote! {
1107
0
            while #cond_tokens {
1108
0
                #body_tokens
1109
0
            }
1110
0
        })
1111
0
    }
1112
1113
    /// Transpile if-let expression (complexity: 5)
1114
0
    pub fn transpile_if_let(
1115
0
        &self,
1116
0
        pattern: &Pattern,
1117
0
        expr: &Expr,
1118
0
        then_branch: &Expr,
1119
0
        else_branch: Option<&Expr>,
1120
0
    ) -> Result<TokenStream> {
1121
0
        let expr_tokens = self.transpile_expr(expr)?;
1122
0
        let pattern_tokens = self.transpile_pattern(pattern)?;
1123
0
        let then_tokens = self.transpile_expr(then_branch)?;
1124
1125
0
        if let Some(else_expr) = else_branch {
1126
0
            let else_tokens = self.transpile_expr(else_expr)?;
1127
0
            Ok(quote! {
1128
0
                if let #pattern_tokens = #expr_tokens {
1129
0
                    #then_tokens
1130
0
                } else {
1131
0
                    #else_tokens
1132
0
                }
1133
0
            })
1134
        } else {
1135
0
            Ok(quote! {
1136
0
                if let #pattern_tokens = #expr_tokens {
1137
0
                    #then_tokens
1138
0
                }
1139
0
            })
1140
        }
1141
0
    }
1142
1143
    /// Transpile while-let expression (complexity: 4)
1144
0
    pub fn transpile_while_let(
1145
0
        &self,
1146
0
        pattern: &Pattern,
1147
0
        expr: &Expr,
1148
0
        body: &Expr,
1149
0
    ) -> Result<TokenStream> {
1150
0
        let expr_tokens = self.transpile_expr(expr)?;
1151
0
        let pattern_tokens = self.transpile_pattern(pattern)?;
1152
0
        let body_tokens = self.transpile_expr(body)?;
1153
1154
0
        Ok(quote! {
1155
0
            while let #pattern_tokens = #expr_tokens {
1156
0
                #body_tokens
1157
0
            }
1158
0
        })
1159
0
    }
1160
1161
0
    pub fn transpile_loop(&self, body: &Expr) -> Result<TokenStream> {
1162
0
        let body_tokens = self.transpile_expr(body)?;
1163
1164
0
        Ok(quote! {
1165
0
            loop {
1166
0
                #body_tokens
1167
0
            }
1168
0
        })
1169
0
    }
1170
1171
    /// Transpiles try-catch-finally blocks
1172
0
    pub fn transpile_try_catch(
1173
0
        &self, 
1174
0
        try_block: &Expr, 
1175
0
        catch_clauses: &[CatchClause],
1176
0
        finally_block: Option<&Expr>
1177
0
    ) -> Result<TokenStream> {
1178
        // For now, we'll transpile try-catch to a match on Result
1179
        // This is a simplified implementation that handles the common case
1180
0
        let try_body = self.transpile_expr(try_block)?;
1181
        
1182
0
        if catch_clauses.is_empty() {
1183
0
            bail!("Try block must have at least one catch clause");
1184
0
        }
1185
        
1186
        // Generate the catch handling
1187
0
        let catch_pattern = if let Pattern::Identifier(name) = &catch_clauses[0].pattern {
1188
0
            let ident = format_ident!("{}", name);
1189
0
            quote! { #ident }
1190
0
        } else { quote! { _e } };
1191
        
1192
0
        let catch_body = self.transpile_expr(&catch_clauses[0].body)?;
1193
        
1194
        // If there's a finally block, we need to ensure it runs
1195
0
        let result = if let Some(finally) = finally_block {
1196
0
            let finally_tokens = self.transpile_expr(finally)?;
1197
0
            quote! {
1198
                {
1199
                    let _result = (|| -> Result<_, Box<dyn std::error::Error>> {
1200
                        Ok(#try_body)
1201
                    })();
1202
                    
1203
                    let _final_result = match _result {
1204
                        Ok(val) => val,
1205
                        Err(#catch_pattern) => #catch_body
1206
                    };
1207
                    
1208
                    #finally_tokens;
1209
                    _final_result
1210
                }
1211
            }
1212
        } else {
1213
            // Simple try-catch without finally
1214
0
            quote! {
1215
                match (|| -> Result<_, Box<dyn std::error::Error>> {
1216
                    Ok(#try_body)
1217
                })() {
1218
                    Ok(val) => val,
1219
                    Err(#catch_pattern) => #catch_body
1220
                }
1221
            }
1222
        };
1223
        
1224
0
        Ok(result)
1225
0
    }
1226
1227
    /// Transpiles list comprehensions
1228
0
    pub fn transpile_list_comprehension(
1229
0
        &self,
1230
0
        expr: &Expr,
1231
0
        var: &str,
1232
0
        iter: &Expr,
1233
0
        filter: Option<&Expr>,
1234
0
    ) -> Result<TokenStream> {
1235
0
        let var_ident = format_ident!("{}", var);
1236
0
        let iter_tokens = self.transpile_expr(iter)?;
1237
0
        let expr_tokens = self.transpile_expr(expr)?;
1238
1239
0
        if let Some(filter_expr) = filter {
1240
0
            let filter_tokens = self.transpile_expr(filter_expr)?;
1241
0
            Ok(quote! {
1242
0
                #iter_tokens
1243
0
                    .into_iter()
1244
0
                    .filter(|#var_ident| #filter_tokens)
1245
0
                    .map(|#var_ident| #expr_tokens)
1246
0
                    .collect::<Vec<_>>()
1247
0
            })
1248
        } else {
1249
0
            Ok(quote! {
1250
0
                #iter_tokens
1251
0
                    .into_iter()
1252
0
                    .map(|#var_ident| #expr_tokens)
1253
0
                    .collect::<Vec<_>>()
1254
0
            })
1255
        }
1256
0
    }
1257
1258
1259
    /// Transpiles module declarations
1260
0
    pub fn transpile_module(&self, name: &str, body: &Expr) -> Result<TokenStream> {
1261
0
        let module_name = format_ident!("{}", name);
1262
0
        let body_tokens = self.transpile_expr(body)?;
1263
1264
0
        Ok(quote! {
1265
0
            mod #module_name {
1266
0
                #body_tokens
1267
0
            }
1268
0
        })
1269
0
    }
1270
1271
    
1272
    /// Static method for transpiling inline imports (backward compatibility)
1273
0
    pub fn transpile_import(path: &str, items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1274
        
1275
        
1276
        // All imports should have module-level scope, not be wrapped in blocks
1277
        // This includes both std library imports and local module imports
1278
0
        Self::transpile_import_inline(path, items)
1279
0
    }
1280
    
1281
    /// Handle `std::fs` imports and generate file operation functions
1282
0
    fn transpile_std_fs_import(items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1283
        use crate::frontend::ast::ImportItem;
1284
        
1285
0
        let mut tokens = TokenStream::new();
1286
        
1287
        // Always include std::fs for file operations
1288
0
        tokens.extend(quote! { use std::fs; });
1289
        
1290
0
        if items.is_empty() || items.iter().any(|i| matches!(i, ImportItem::Wildcard)) {
1291
0
            // Import all file operations
1292
0
            tokens.extend(Self::generate_all_file_operations());
1293
0
        } else {
1294
            // Import specific operations
1295
0
            for item in items {
1296
0
                match item {
1297
0
                    ImportItem::Named(name) => {
1298
0
                        match name.as_str() {
1299
0
                            "read_file" => tokens.extend(Self::generate_read_file_function()),
1300
0
                            "write_file" => tokens.extend(Self::generate_write_file_function()),
1301
0
                            _ => {
1302
0
                                // Unknown std::fs function, generate stub or error
1303
0
                                let func_name = format_ident!("{}", name);
1304
0
                                tokens.extend(quote! {
1305
0
                                    fn #func_name() -> ! {
1306
0
                                        panic!("std::fs::{} not yet implemented", #name);
1307
0
                                    }
1308
0
                                });
1309
0
                            }
1310
                        }
1311
                    }
1312
0
                    ImportItem::Aliased { name, alias } => {
1313
0
                        let alias_ident = format_ident!("{}", alias);
1314
0
                        match name.as_str() {
1315
0
                            "read_file" => {
1316
0
                                tokens.extend(quote! {
1317
0
                                    fn #alias_ident(filename: String) -> String {
1318
0
                                        fs::read_to_string(filename).unwrap_or_else(|e| panic!("Failed to read file: {}", e))
1319
0
                                    }
1320
0
                                });
1321
0
                            }
1322
0
                            "write_file" => {
1323
0
                                tokens.extend(quote! {
1324
0
                                    fn #alias_ident(filename: String, content: String) {
1325
0
                                        fs::write(filename, content).unwrap_or_else(|e| panic!("Failed to write file: {}", e));
1326
0
                                    }
1327
0
                                });
1328
0
                            }
1329
0
                            _ => {
1330
0
                                tokens.extend(quote! {
1331
0
                                    fn #alias_ident() -> ! {
1332
0
                                        panic!("std::fs::{} not yet implemented", #name);
1333
0
                                    }
1334
0
                                });
1335
0
                            }
1336
                        }
1337
                    }
1338
0
                    ImportItem::Wildcard => {
1339
0
                        tokens.extend(Self::generate_all_file_operations());
1340
0
                    }
1341
                }
1342
            }
1343
        }
1344
        
1345
0
        tokens
1346
0
    }
1347
    
1348
    /// Generate `read_file` function
1349
0
    fn generate_read_file_function() -> TokenStream {
1350
0
        quote! {
1351
            fn read_file(filename: String) -> String {
1352
                fs::read_to_string(filename).unwrap_or_else(|e| panic!("Failed to read file: {}", e))
1353
            }
1354
        }
1355
0
    }
1356
    
1357
    /// Generate `write_file` function  
1358
0
    fn generate_write_file_function() -> TokenStream {
1359
0
        quote! {
1360
            fn write_file(filename: String, content: String) {
1361
                fs::write(filename, content).unwrap_or_else(|e| panic!("Failed to write file: {}", e));
1362
            }
1363
        }
1364
0
    }
1365
    
1366
    /// Generate all file operation functions
1367
0
    fn generate_all_file_operations() -> TokenStream {
1368
0
        let read_func = Self::generate_read_file_function();
1369
0
        let write_func = Self::generate_write_file_function();
1370
        
1371
0
        quote! {
1372
            #read_func
1373
            #write_func
1374
        }
1375
0
    }
1376
    
1377
    /// Handle `std::fs` imports with path-based syntax (import `std::fs::read_file`)
1378
0
    fn transpile_std_fs_import_with_path(path: &str, items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1379
        use crate::frontend::ast::ImportItem;
1380
        
1381
        
1382
0
        let mut tokens = TokenStream::new();
1383
        
1384
        // Always include std::fs for file operations
1385
0
        tokens.extend(quote! { use std::fs; });
1386
        
1387
0
        if path == "std::fs" {
1388
            // Wildcard import or specific items from std::fs
1389
            // Special case: if path is "std::fs" and items contain Named("fs"), treat as wildcard
1390
0
            let is_wildcard_import = items.is_empty() 
1391
0
                || items.iter().any(|i| matches!(i, ImportItem::Wildcard))
1392
0
                || (items.len() == 1 && matches!(&items[0], ImportItem::Named(name) if name == "fs"));
1393
                
1394
0
            if is_wildcard_import {
1395
0
                // Import all file operations for wildcard or empty imports
1396
0
                tokens.extend(Self::generate_all_file_operations());
1397
0
            } else {
1398
                // Import specific operations
1399
0
                for item in items {
1400
0
                    match item {
1401
0
                        ImportItem::Named(name) => {
1402
0
                            match name.as_str() {
1403
0
                                "read_file" => tokens.extend(Self::generate_read_file_function()),
1404
0
                                "write_file" => tokens.extend(Self::generate_write_file_function()),
1405
0
                                _ => {} // Ignore unknown functions
1406
                            }
1407
                        }
1408
                        ImportItem::Wildcard => {
1409
0
                            tokens.extend(Self::generate_all_file_operations());
1410
0
                            break;
1411
                        }
1412
0
                        ImportItem::Aliased { name, alias: _ } => {
1413
                            // Handle aliased imports like "read_file as rf"
1414
0
                            match name.as_str() {
1415
0
                                "read_file" => tokens.extend(Self::generate_read_file_function()),
1416
0
                                "write_file" => tokens.extend(Self::generate_write_file_function()),
1417
0
                                _ => {} // Ignore unknown functions
1418
                            }
1419
                        }
1420
                    }
1421
                }
1422
            }
1423
0
        } else if path.starts_with("std::fs::") {
1424
            // Path-based import like std::fs::read_file
1425
0
            let function_name = path.strip_prefix("std::fs::").unwrap_or("");
1426
0
            match function_name {
1427
0
                "read_file" => tokens.extend(Self::generate_read_file_function()),
1428
0
                "write_file" => tokens.extend(Self::generate_write_file_function()),
1429
0
                _ => {} // Ignore unknown functions
1430
            }
1431
0
        }
1432
        
1433
0
        tokens
1434
0
    }
1435
1436
    /// Handle `std::process` imports with process management functions
1437
0
    fn transpile_std_process_import(_path: &str, _items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1438
        // Generate process functions
1439
0
        quote! {
1440
            mod process {
1441
                pub fn current_pid() -> i32 {
1442
                    std::process::id() as i32
1443
                }
1444
                
1445
                pub fn exit(code: i32) {
1446
                    std::process::exit(code);
1447
                }
1448
                
1449
                pub fn spawn(command: &str) -> Result<i32, String> {
1450
                    match std::process::Command::new(command).spawn() {
1451
                        Ok(child) => Ok(child.id() as i32),
1452
                        Err(e) => Err(e.to_string()),
1453
                    }
1454
                }
1455
            }
1456
        }
1457
0
    }
1458
    
1459
    /// Handle `std::system` imports with system information functions
1460
0
    fn transpile_std_system_import(_path: &str, _items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1461
        // Generate system functions
1462
0
        quote! {
1463
            mod system {
1464
                pub fn get_env(key: &str) -> Option<String> {
1465
                    std::env::var(key).ok()
1466
                }
1467
                
1468
                pub fn set_env(key: &str, value: &str) {
1469
                    std::env::set_var(key, value);
1470
                }
1471
                
1472
                pub fn os_name() -> String {
1473
                    std::env::consts::OS.to_string()
1474
                }
1475
                
1476
                pub fn arch() -> String {
1477
                    std::env::consts::ARCH.to_string()
1478
                }
1479
            }
1480
        }
1481
0
    }
1482
    
1483
    /// Handle `std::signal` imports with signal handling functions
1484
0
    fn transpile_std_signal_import(_path: &str, _items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1485
        // For now, just provide stubs as signal handling is complex and platform-specific
1486
0
        quote! {
1487
            // Import signal constants at top level
1488
            const SIGINT: i32 = 2;
1489
            const SIGTERM: i32 = 15;
1490
            const SIGKILL: i32 = 9;
1491
            
1492
            // Also import exit function for signal handlers
1493
            fn exit(code: i32) {
1494
                std::process::exit(code);
1495
            }
1496
            
1497
            mod signal {
1498
                pub const SIGINT: i32 = 2;
1499
                pub const SIGTERM: i32 = 15;
1500
                pub const SIGKILL: i32 = 9;
1501
                
1502
                pub fn on(_signal: i32, _handler: impl Fn()) {
1503
                    // Signal handling would require unsafe code and platform-specific logic
1504
                    // For now, this is a stub
1505
                }
1506
            }
1507
        }
1508
0
    }
1509
    
1510
    /// Handle `std::net` imports with networking functions
1511
0
    fn transpile_std_net_import(_path: &str, _items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1512
        // Generate networking functions and re-export std types
1513
0
        quote! {
1514
            mod net {
1515
                pub use std::net::*;
1516
                
1517
                pub struct TcpListener;
1518
                
1519
                impl TcpListener {
1520
                    pub fn bind(addr: String) -> Result<Self, String> {
1521
                        println!("Would bind TCP listener to: {}", addr);
1522
                        Ok(TcpListener)
1523
                    }
1524
                    
1525
                    pub fn accept(&self) -> Result<TcpStream, String> {
1526
                        println!("Would accept connection");
1527
                        Ok(TcpStream)
1528
                    }
1529
                }
1530
                
1531
                pub struct TcpStream;
1532
                
1533
                impl TcpStream {
1534
                    pub fn connect(addr: String) -> Result<Self, String> {
1535
                        println!("Would connect to: {}", addr);
1536
                        Ok(TcpStream)
1537
                    }
1538
                }
1539
            }
1540
            
1541
            // Also make available as module for http submodules
1542
            mod http {
1543
                pub struct Server {
1544
                    addr: String,
1545
                }
1546
                
1547
                impl Server {
1548
                    pub fn new(addr: String) -> Self {
1549
                        println!("Creating HTTP server on: {}", addr);
1550
                        Server { addr }
1551
                    }
1552
                    
1553
                    pub fn listen(&self) {
1554
                        println!("HTTP server listening on: {}", self.addr);
1555
                    }
1556
                }
1557
            }
1558
        }
1559
0
    }
1560
1561
0
    fn transpile_std_mem_import(_path: &str, _items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1562
        // Generate memory management functions
1563
0
        quote! {
1564
            mod mem {
1565
                pub struct Array<T> {
1566
                    data: Vec<T>,
1567
                }
1568
                
1569
                impl<T: Clone> Array<T> {
1570
                    pub fn new(size: usize, default_value: T) -> Self {
1571
                        Array {
1572
                            data: vec![default_value; size],
1573
                        }
1574
                    }
1575
                }
1576
                
1577
                pub struct MemoryInfo {
1578
                    pub allocated: usize,
1579
                    pub peak: usize,
1580
                }
1581
                
1582
                impl std::fmt::Display for MemoryInfo {
1583
                    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1584
                        write!(f, "allocated: {}KB, peak: {}KB", self.allocated / 1024, self.peak / 1024)
1585
                    }
1586
                }
1587
                
1588
                pub fn usage() -> MemoryInfo {
1589
                    MemoryInfo {
1590
                        allocated: 1024 * 100, // 100KB stub
1591
                        peak: 1024 * 150,      // 150KB stub
1592
                    }
1593
                }
1594
            }
1595
        }
1596
0
    }
1597
1598
0
    fn transpile_std_parallel_import(_path: &str, _items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1599
        // Generate parallel processing functions
1600
0
        quote! {
1601
            mod parallel {
1602
                pub fn map<T, U, F>(data: Vec<T>, func: F) -> Vec<U>
1603
                where
1604
                    T: Send,
1605
                    U: Send,
1606
                    F: Fn(T) -> U + Send + Sync,
1607
                {
1608
                    // Simple sequential implementation for now (stub)
1609
                    data.into_iter().map(func).collect()
1610
                }
1611
                
1612
                pub fn filter<T, F>(data: Vec<T>, predicate: F) -> Vec<T>
1613
                where
1614
                    T: Send,
1615
                    F: Fn(&T) -> bool + Send + Sync,
1616
                {
1617
                    data.into_iter().filter(|x| predicate(x)).collect()
1618
                }
1619
                
1620
                pub fn reduce<T, F>(data: Vec<T>, func: F) -> Option<T>
1621
                where
1622
                    T: Send,
1623
                    F: Fn(T, T) -> T + Send + Sync,
1624
                {
1625
                    data.into_iter().reduce(func)
1626
                }
1627
            }
1628
        }
1629
0
    }
1630
1631
0
    fn transpile_std_simd_import(_path: &str, _items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1632
        // Generate SIMD vectorization functions
1633
0
        quote! {
1634
            mod simd {
1635
                use std::ops::Add;
1636
                
1637
                pub struct SimdVec<T> {
1638
                    data: Vec<T>,
1639
                }
1640
                
1641
                impl<T> SimdVec<T> {
1642
                    pub fn from_slice(slice: &[T]) -> Self
1643
                    where
1644
                        T: Clone,
1645
                    {
1646
                        SimdVec {
1647
                            data: slice.to_vec(),
1648
                        }
1649
                    }
1650
                }
1651
                
1652
                impl<T> Add for SimdVec<T>
1653
                where
1654
                    T: Add<Output = T> + Copy,
1655
                {
1656
                    type Output = SimdVec<T>;
1657
                    
1658
                    fn add(self, other: SimdVec<T>) -> SimdVec<T> {
1659
                        let result: Vec<T> = self.data.iter()
1660
                            .zip(other.data.iter())
1661
                            .map(|(&a, &b)| a + b)
1662
                            .collect();
1663
                        SimdVec { data: result }
1664
                    }
1665
                }
1666
                
1667
                impl<T> std::fmt::Display for SimdVec<T>
1668
                where
1669
                    T: std::fmt::Display,
1670
                {
1671
                    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1672
                        write!(f, "[{}]", self.data.iter().map(|x| format!("{}", x)).collect::<Vec<_>>().join(", "))
1673
                    }
1674
                }
1675
                
1676
                pub fn from_slice<T: Clone>(slice: &[T]) -> SimdVec<T> {
1677
                    SimdVec::from_slice(slice)
1678
                }
1679
            }
1680
        }
1681
0
    }
1682
1683
0
    fn transpile_std_cache_import(_path: &str, _items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1684
        // Generate caching functions - placeholder for @memoize attribute support
1685
0
        quote! {
1686
            mod cache {
1687
                use std::collections::HashMap;
1688
                
1689
                pub struct Cache<K, V> {
1690
                    data: HashMap<K, V>,
1691
                }
1692
                
1693
                impl<K, V> Cache<K, V>
1694
                where
1695
                    K: std::hash::Hash + Eq,
1696
                {
1697
                    pub fn new() -> Self {
1698
                        Cache {
1699
                            data: HashMap::new(),
1700
                        }
1701
                    }
1702
                    
1703
                    pub fn get(&self, key: &K) -> Option<&V> {
1704
                        self.data.get(key)
1705
                    }
1706
                    
1707
                    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
1708
                        self.data.insert(key, value)
1709
                    }
1710
                }
1711
            }
1712
        }
1713
0
    }
1714
1715
0
    fn transpile_std_bench_import(_path: &str, _items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1716
        // Generate benchmarking functions
1717
0
        quote! {
1718
            mod bench {
1719
                use std::time::{Duration, Instant};
1720
                
1721
                pub struct BenchmarkResult {
1722
                    pub elapsed: u128,
1723
                }
1724
                
1725
                impl BenchmarkResult {
1726
                    pub fn new(elapsed: Duration) -> Self {
1727
                        BenchmarkResult {
1728
                            elapsed: elapsed.as_millis(),
1729
                        }
1730
                    }
1731
                }
1732
                
1733
                impl std::fmt::Display for BenchmarkResult {
1734
                    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1735
                        write!(f, "{}ms", self.elapsed)
1736
                    }
1737
                }
1738
                
1739
                pub fn time<F, T>(mut func: F) -> BenchmarkResult
1740
                where
1741
                    F: FnMut() -> T,
1742
                {
1743
                    let start = Instant::now();
1744
                    let _ = func();
1745
                    let elapsed = start.elapsed();
1746
                    BenchmarkResult::new(elapsed)
1747
                }
1748
            }
1749
        }
1750
0
    }
1751
1752
0
    fn transpile_std_profile_import(_path: &str, _items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1753
        // Generate profiling functions - placeholder for @hot_path attribute support
1754
0
        quote! {
1755
            mod profile {
1756
                pub struct ProfileInfo {
1757
                    pub function_name: String,
1758
                    pub call_count: usize,
1759
                    pub total_time: u128,
1760
                }
1761
                
1762
                impl std::fmt::Display for ProfileInfo {
1763
                    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1764
                        write!(f, "{}: {} calls, {}ms total", 
1765
                               self.function_name, self.call_count, self.total_time)
1766
                    }
1767
                }
1768
                
1769
                pub fn get_stats(function_name: &str) -> ProfileInfo {
1770
                    ProfileInfo {
1771
                        function_name: function_name.to_string(),
1772
                        call_count: 42, // Stub values
1773
                        total_time: 100,
1774
                    }
1775
                }
1776
            }
1777
        }
1778
0
    }
1779
    
1780
    /// Handle `std::system` imports with system information functions
1781
    /// Core inline import transpilation logic - REFACTORED FOR COMPLEXITY REDUCTION
1782
    /// Original: 48 cyclomatic complexity, Target: <20
1783
0
    pub fn transpile_import_inline(path: &str, items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1784
        // Try std module handlers first (complexity: delegated)
1785
0
        if let Some(result) = Self::handle_std_module_import(path, items) {
1786
0
            return result;
1787
0
        }
1788
        
1789
        // Fall back to generic import handling (complexity: delegated)
1790
0
        Self::handle_generic_import(path, items)
1791
0
    }
1792
    
1793
    /// Extract std module dispatcher (complexity ~12)
1794
0
    fn handle_std_module_import(path: &str, items: &[crate::frontend::ast::ImportItem]) -> Option<TokenStream> {
1795
0
        if path.starts_with("std::fs") {
1796
0
            return Some(Self::transpile_std_fs_import_with_path(path, items));
1797
0
        }
1798
0
        if path.starts_with("std::process") {
1799
0
            return Some(Self::transpile_std_process_import(path, items));
1800
0
        }
1801
0
        if path.starts_with("std::system") {
1802
0
            return Some(Self::transpile_std_system_import(path, items));
1803
0
        }
1804
0
        if path.starts_with("std::signal") {
1805
0
            return Some(Self::transpile_std_signal_import(path, items));
1806
0
        }
1807
0
        if path.starts_with("std::net") {
1808
0
            return Some(Self::transpile_std_net_import(path, items));
1809
0
        }
1810
0
        if path.starts_with("std::mem") {
1811
0
            return Some(Self::transpile_std_mem_import(path, items));
1812
0
        }
1813
0
        if path.starts_with("std::parallel") {
1814
0
            return Some(Self::transpile_std_parallel_import(path, items));
1815
0
        }
1816
0
        if path.starts_with("std::simd") {
1817
0
            return Some(Self::transpile_std_simd_import(path, items));
1818
0
        }
1819
0
        if path.starts_with("std::cache") {
1820
0
            return Some(Self::transpile_std_cache_import(path, items));
1821
0
        }
1822
0
        if path.starts_with("std::bench") {
1823
0
            return Some(Self::transpile_std_bench_import(path, items));
1824
0
        }
1825
0
        if path.starts_with("std::profile") {
1826
0
            return Some(Self::transpile_std_profile_import(path, items));
1827
0
        }
1828
0
        None
1829
0
    }
1830
    
1831
    /// Extract generic import handling (complexity ~8)
1832
0
    fn handle_generic_import(path: &str, items: &[crate::frontend::ast::ImportItem]) -> TokenStream {
1833
        
1834
0
        let path_tokens = Self::path_to_tokens(path);
1835
        
1836
0
        if items.is_empty() {
1837
0
            quote! { use #path_tokens::*; }
1838
0
        } else if items.len() == 1 {
1839
0
            Self::handle_single_import_item(&path_tokens, path, &items[0])
1840
        } else {
1841
0
            Self::handle_multiple_import_items(&path_tokens, items)
1842
        }
1843
0
    }
1844
    
1845
    /// Extract path tokenization (complexity ~4)
1846
0
    fn path_to_tokens(path: &str) -> TokenStream {
1847
0
        let mut path_tokens = TokenStream::new();
1848
0
        let segments: Vec<_> = path.split("::").collect();
1849
        
1850
0
        for (i, segment) in segments.iter().enumerate() {
1851
0
            if i > 0 {
1852
0
                path_tokens.extend(quote! { :: });
1853
0
            }
1854
0
            if !segment.is_empty() {
1855
0
                let seg_ident = format_ident!("{}", segment);
1856
0
                path_tokens.extend(quote! { #seg_ident });
1857
0
            }
1858
        }
1859
        
1860
0
        path_tokens
1861
0
    }
1862
    
1863
    /// Extract single item handling (complexity ~5)
1864
0
    fn handle_single_import_item(
1865
0
        path_tokens: &TokenStream, 
1866
0
        path: &str, 
1867
0
        item: &crate::frontend::ast::ImportItem
1868
0
    ) -> TokenStream {
1869
        use crate::frontend::ast::ImportItem;
1870
        
1871
0
        match item {
1872
0
            ImportItem::Named(name) => {
1873
0
                if path.ends_with(&format!("::{name}")) {
1874
0
                    quote! { use #path_tokens; }
1875
                } else {
1876
0
                    let item_ident = format_ident!("{}", name);
1877
0
                    quote! { use #path_tokens::#item_ident; }
1878
                }
1879
            }
1880
0
            ImportItem::Aliased { name, alias } => {
1881
0
                let name_ident = format_ident!("{}", name);
1882
0
                let alias_ident = format_ident!("{}", alias);
1883
0
                quote! { use #path_tokens::#name_ident as #alias_ident; }
1884
            }
1885
0
            ImportItem::Wildcard => quote! { use #path_tokens::*; },
1886
        }
1887
0
    }
1888
    
1889
    /// Extract multiple items handling (complexity ~3)
1890
0
    fn handle_multiple_import_items(
1891
0
        path_tokens: &TokenStream, 
1892
0
        items: &[crate::frontend::ast::ImportItem]
1893
0
    ) -> TokenStream {
1894
0
        let item_tokens = Self::process_import_items(items);
1895
0
        quote! { use #path_tokens::{#(#item_tokens),*}; }
1896
0
    }
1897
    
1898
    /// Extract import items processing (complexity ~3)
1899
0
    fn process_import_items(items: &[crate::frontend::ast::ImportItem]) -> Vec<TokenStream> {
1900
        use crate::frontend::ast::ImportItem;
1901
        
1902
0
        items.iter().map(|item| match item {
1903
0
            ImportItem::Named(name) => {
1904
0
                let name_ident = format_ident!("{}", name);
1905
0
                quote! { #name_ident }
1906
            }
1907
0
            ImportItem::Aliased { name, alias } => {
1908
0
                let name_ident = format_ident!("{}", name);
1909
0
                let alias_ident = format_ident!("{}", alias);
1910
0
                quote! { #name_ident as #alias_ident }
1911
            }
1912
0
            ImportItem::Wildcard => quote! { * },
1913
0
        }).collect()
1914
0
    }
1915
1916
    /// Transpiles export statements
1917
0
    pub fn transpile_export(items: &[String]) -> TokenStream {
1918
0
        let item_idents: Vec<_> = items.iter().map(|s| format_ident!("{}", s)).collect();
1919
1920
0
        if items.len() == 1 {
1921
0
            let item = &item_idents[0];
1922
0
            quote! { pub use #item; }
1923
        } else {
1924
0
            quote! { pub use {#(#item_idents),*}; }
1925
        }
1926
0
    }
1927
1928
    /// Handle print/debug macros (println, print, dbg, panic)
1929
    /// 
1930
    /// # Examples
1931
    /// 
1932
    /// ```
1933
    /// use ruchy::{Transpiler, Parser};
1934
    /// 
1935
    /// // Test println macro handling
1936
    /// let transpiler = Transpiler::new();
1937
    /// let mut parser = Parser::new("println(42)");
1938
    /// let ast = parser.parse().unwrap();
1939
    /// let result = transpiler.transpile(&ast).unwrap().to_string();
1940
    /// assert!(result.contains("println !"));
1941
    /// assert!(result.contains("{}"));
1942
    /// ```
1943
0
    fn try_transpile_print_macro(
1944
0
        &self, 
1945
0
        func_tokens: &TokenStream, 
1946
0
        base_name: &str, 
1947
0
        args: &[Expr]
1948
0
    ) -> Result<Option<TokenStream>> {
1949
0
        if !(base_name == "println" || base_name == "print" || base_name == "dbg" || base_name == "panic") {
1950
0
            return Ok(None);
1951
0
        }
1952
        
1953
        // Handle single argument with string interpolation
1954
0
        if (base_name == "println" || base_name == "print") && args.len() == 1 {
1955
0
            if let ExprKind::StringInterpolation { parts } = &args[0].kind {
1956
0
                return Ok(Some(self.transpile_print_with_interpolation(base_name, parts)?));
1957
0
            }
1958
            // For single non-string arguments, add smart format string
1959
0
            if !matches!(&args[0].kind, ExprKind::Literal(Literal::String(_))) {
1960
0
                let arg_tokens = self.transpile_expr(&args[0])?;
1961
                // Use Debug formatting for safety - works with all types including Vec, tuples, etc.
1962
0
                let format_str = "{:?}";
1963
0
                return Ok(Some(quote! { #func_tokens!(#format_str, #arg_tokens) }));
1964
0
            }
1965
0
        }
1966
        
1967
        // Handle multiple arguments
1968
0
        if args.len() > 1 {
1969
0
            return self.transpile_print_multiple_args(func_tokens, args);
1970
0
        }
1971
        
1972
        // Single string literal or simple case
1973
0
        let arg_tokens: Result<Vec<_>> = args.iter().map(|a| self.transpile_expr(a)).collect();
1974
0
        let arg_tokens = arg_tokens?;
1975
0
        Ok(Some(quote! { #func_tokens!(#(#arg_tokens),*) }))
1976
0
    }
1977
    
1978
    /// Handle multiple arguments for print macros
1979
0
    fn transpile_print_multiple_args(
1980
0
        &self,
1981
0
        func_tokens: &TokenStream,
1982
0
        args: &[Expr]
1983
0
    ) -> Result<Option<TokenStream>> {
1984
        // FIXED: Don't treat first string argument as format string
1985
        // Instead, treat all arguments as values to print with spaces
1986
0
        if args.is_empty() {
1987
0
            return Ok(Some(quote! { #func_tokens!() }));
1988
0
        }
1989
        
1990
0
        let all_args: Result<Vec<_>> = args.iter().map(|a| self.transpile_expr(a)).collect();
1991
0
        let all_args = all_args?;
1992
        
1993
0
        if args.len() == 1 {
1994
            // Single argument - check if it's a string-like expression
1995
0
            match &args[0].kind {
1996
                ExprKind::Literal(Literal::String(_)) | 
1997
                ExprKind::StringInterpolation { .. } => {
1998
                    // String literal or interpolation - use Display format
1999
0
                    Ok(Some(quote! { #func_tokens!("{}", #(#all_args)*) }))
2000
                }
2001
                ExprKind::Identifier(_) => {
2002
                    // For identifiers, we can't know the type at compile time
2003
                    // Use a runtime check to decide format
2004
0
                    let arg = &all_args[0];
2005
0
                    let printing_logic = self.generate_value_printing_tokens(quote! { #arg }, quote! { #func_tokens });
2006
0
                    Ok(Some(printing_logic))
2007
                }
2008
                _ => {
2009
                    // Other types - use Debug format for complex types
2010
0
                    Ok(Some(quote! { #func_tokens!("{:?}", #(#all_args)*) }))
2011
                }
2012
            }
2013
        } else {
2014
            // Multiple arguments - check if first is format string
2015
0
            if let ExprKind::Literal(Literal::String(format_str)) = &args[0].kind {
2016
0
                if format_str.contains("{}") {
2017
                    // First argument is a format string, rest are values
2018
0
                    let format_arg = &all_args[0];
2019
0
                    let value_args = &all_args[1..];
2020
0
                    Ok(Some(quote! { #func_tokens!(#format_arg, #(#value_args),*) }))
2021
                } else {
2022
                    // First argument is regular string, treat all as separate values
2023
0
                    let format_parts: Vec<_> = args.iter().map(|arg| {
2024
0
                        match &arg.kind {
2025
0
                            ExprKind::Literal(Literal::String(_)) => "{}",
2026
0
                            _ => "{:?}"
2027
                        }
2028
0
                    }).collect();
2029
0
                    let format_str = format_parts.join(" ");
2030
0
                    Ok(Some(quote! { #func_tokens!(#format_str, #(#all_args),*) }))
2031
                }
2032
            } else {
2033
                // No format string, treat all as separate values
2034
0
                let format_parts: Vec<_> = args.iter().map(|arg| {
2035
0
                    match &arg.kind {
2036
0
                        ExprKind::Literal(Literal::String(_)) => "{}",
2037
0
                        _ => "{:?}"
2038
                    }
2039
0
                }).collect();
2040
0
                let format_str = format_parts.join(" ");
2041
0
                Ok(Some(quote! { #func_tokens!(#format_str, #(#all_args),*) }))
2042
            }
2043
        }
2044
0
    }
2045
    
2046
    /// Handle math functions (sqrt, pow, abs, min, max, floor, ceil, round)
2047
    /// 
2048
    /// # Examples
2049
    /// 
2050
    /// ```
2051
    /// use ruchy::{Transpiler, Parser};
2052
    /// 
2053
    /// let transpiler = Transpiler::new();
2054
    /// let mut parser = Parser::new("sqrt(4.0)");
2055
    /// let ast = parser.parse().unwrap();
2056
    /// let result = transpiler.transpile(&ast).unwrap().to_string();
2057
    /// assert!(result.contains("sqrt"));
2058
    /// ```
2059
0
    fn try_transpile_math_function(&self, base_name: &str, args: &[Expr]) -> Result<Option<TokenStream>> {
2060
0
        match (base_name, args.len()) {
2061
0
            ("sqrt", 1) => self.transpile_sqrt(&args[0]).map(Some),
2062
0
            ("pow", 2) => self.transpile_pow(&args[0], &args[1]).map(Some),
2063
0
            ("abs", 1) => self.transpile_abs(&args[0]).map(Some),
2064
0
            ("min", 2) => self.transpile_min(&args[0], &args[1]).map(Some),
2065
0
            ("max", 2) => self.transpile_max(&args[0], &args[1]).map(Some),
2066
0
            ("floor", 1) => self.transpile_floor(&args[0]).map(Some),
2067
0
            ("ceil", 1) => self.transpile_ceil(&args[0]).map(Some),
2068
0
            ("round", 1) => self.transpile_round(&args[0]).map(Some),
2069
0
            _ => Ok(None)
2070
        }
2071
0
    }
2072
2073
0
    fn transpile_sqrt(&self, arg: &Expr) -> Result<TokenStream> {
2074
0
        let arg_tokens = self.transpile_expr(arg)?;
2075
0
        Ok(quote! { (#arg_tokens as f64).sqrt() })
2076
0
    }
2077
2078
0
    fn transpile_pow(&self, base: &Expr, exp: &Expr) -> Result<TokenStream> {
2079
0
        let base_tokens = self.transpile_expr(base)?;
2080
0
        let exp_tokens = self.transpile_expr(exp)?;
2081
0
        Ok(quote! { (#base_tokens as f64).powf(#exp_tokens as f64) })
2082
0
    }
2083
2084
0
    fn transpile_abs(&self, arg: &Expr) -> Result<TokenStream> {
2085
0
        let arg_tokens = self.transpile_expr(arg)?;
2086
        // Check if arg is negative literal to handle type
2087
0
        if let ExprKind::Unary { op: UnaryOp::Negate, operand } = &arg.kind {
2088
0
            if matches!(&operand.kind, ExprKind::Literal(Literal::Float(_))) {
2089
0
                return Ok(quote! { (#arg_tokens).abs() });
2090
0
            }
2091
0
        }
2092
        // For all other cases, use standard abs
2093
0
        Ok(quote! { #arg_tokens.abs() })
2094
0
    }
2095
2096
0
    fn transpile_min(&self, a: &Expr, b: &Expr) -> Result<TokenStream> {
2097
0
        let a_tokens = self.transpile_expr(a)?;
2098
0
        let b_tokens = self.transpile_expr(b)?;
2099
        // Check if args are float literals to determine type
2100
0
        let is_float = matches!(&a.kind, ExprKind::Literal(Literal::Float(_))) 
2101
0
            || matches!(&b.kind, ExprKind::Literal(Literal::Float(_)));
2102
0
        if is_float {
2103
0
            Ok(quote! { (#a_tokens as f64).min(#b_tokens as f64) })
2104
        } else {
2105
0
            Ok(quote! { std::cmp::min(#a_tokens, #b_tokens) })
2106
        }
2107
0
    }
2108
2109
0
    fn transpile_max(&self, a: &Expr, b: &Expr) -> Result<TokenStream> {
2110
0
        let a_tokens = self.transpile_expr(a)?;
2111
0
        let b_tokens = self.transpile_expr(b)?;
2112
        // Check if args are float literals to determine type
2113
0
        let is_float = matches!(&a.kind, ExprKind::Literal(Literal::Float(_))) 
2114
0
            || matches!(&b.kind, ExprKind::Literal(Literal::Float(_)));
2115
0
        if is_float {
2116
0
            Ok(quote! { (#a_tokens as f64).max(#b_tokens as f64) })
2117
        } else {
2118
0
            Ok(quote! { std::cmp::max(#a_tokens, #b_tokens) })
2119
        }
2120
0
    }
2121
2122
0
    fn transpile_floor(&self, arg: &Expr) -> Result<TokenStream> {
2123
0
        let arg_tokens = self.transpile_expr(arg)?;
2124
0
        Ok(quote! { (#arg_tokens as f64).floor() })
2125
0
    }
2126
2127
0
    fn transpile_ceil(&self, arg: &Expr) -> Result<TokenStream> {
2128
0
        let arg_tokens = self.transpile_expr(arg)?;
2129
0
        Ok(quote! { (#arg_tokens as f64).ceil() })
2130
0
    }
2131
2132
0
    fn transpile_round(&self, arg: &Expr) -> Result<TokenStream> {
2133
0
        let arg_tokens = self.transpile_expr(arg)?;
2134
0
        Ok(quote! { (#arg_tokens as f64).round() })
2135
0
    }
2136
    
2137
    /// Handle input functions (input, readline)
2138
    /// 
2139
    /// # Examples
2140
    /// 
2141
    /// ```
2142
    /// use ruchy::{Transpiler, Parser};
2143
    /// 
2144
    /// let transpiler = Transpiler::new();
2145
    /// let mut parser = Parser::new("input()");
2146
    /// let ast = parser.parse().unwrap();
2147
    /// let result = transpiler.transpile(&ast).unwrap().to_string();
2148
    /// assert!(result.contains("read_line"));
2149
    /// ```
2150
0
    fn try_transpile_input_function(&self, base_name: &str, args: &[Expr]) -> Result<Option<TokenStream>> {
2151
0
        match base_name {
2152
0
            "input" => {
2153
0
                if args.len() > 1 {
2154
0
                    bail!("input expects 0 or 1 arguments (optional prompt)");
2155
0
                }
2156
0
                if args.is_empty() {
2157
0
                    Ok(Some(self.generate_input_without_prompt()))
2158
                } else {
2159
0
                    let prompt = self.transpile_expr(&args[0])?;
2160
0
                    Ok(Some(self.generate_input_with_prompt(prompt)))
2161
                }
2162
            }
2163
0
            "readline" if args.is_empty() => {
2164
0
                Ok(Some(self.generate_input_without_prompt()))
2165
            }
2166
0
            _ => Ok(None)
2167
        }
2168
0
    }
2169
    
2170
    /// Generate input reading code without prompt
2171
0
    fn generate_input_without_prompt(&self) -> TokenStream {
2172
0
        quote! { 
2173
            {
2174
                let mut input = String::new();
2175
                std::io::stdin().read_line(&mut input).expect("Failed to read input");
2176
                if input.ends_with('\n') {
2177
                    input.pop();
2178
                    if input.ends_with('\r') {
2179
                        input.pop();
2180
                    }
2181
                }
2182
                input
2183
            }
2184
        }
2185
0
    }
2186
    
2187
    /// Generate input reading code with prompt
2188
0
    fn generate_input_with_prompt(&self, prompt: TokenStream) -> TokenStream {
2189
0
        quote! { 
2190
            {
2191
                print!("{}", #prompt);
2192
                std::io::Write::flush(&mut std::io::stdout()).unwrap();
2193
                let mut input = String::new();
2194
                std::io::stdin().read_line(&mut input).expect("Failed to read input");
2195
                if input.ends_with('\n') {
2196
                    input.pop();
2197
                    if input.ends_with('\r') {
2198
                        input.pop();
2199
                    }
2200
                }
2201
                input
2202
            }
2203
        }
2204
0
    }
2205
    
2206
    /// Try to transpile type conversion functions (str, int, float, bool)
2207
    /// 
2208
    /// # Examples
2209
    /// 
2210
    /// ```rust
2211
    /// # use ruchy::backend::transpiler::Transpiler;
2212
    /// let transpiler = Transpiler::new();
2213
    /// // str(42) -> 42.to_string()
2214
    /// // int("42") -> "42".parse::<i64>().unwrap()
2215
    /// // float(42) -> 42 as f64
2216
    /// // bool(1) -> 1 != 0
2217
    /// ```
2218
0
    fn try_transpile_type_conversion(&self, base_name: &str, args: &[Expr]) -> Result<Option<TokenStream>> {
2219
        // Delegate to refactored version with reduced complexity
2220
        // Original complexity: 62, New complexity: <20 per function
2221
0
        self.try_transpile_type_conversion_refactored(base_name, args)
2222
0
    }
2223
    
2224
    // Old implementation kept for reference (will be removed after verification)
2225
    #[allow(dead_code)]
2226
0
    pub fn try_transpile_type_conversion_old(&self, base_name: &str, args: &[Expr]) -> Result<Option<TokenStream>> {
2227
0
        match base_name {
2228
0
            "str" => self.transpile_str_conversion(args).map(Some),
2229
0
            "int" => self.transpile_int_conversion(args).map(Some), 
2230
0
            "float" => self.transpile_float_conversion(args).map(Some),
2231
0
            "bool" => self.transpile_bool_conversion(args).map(Some),
2232
0
            _ => Ok(None)
2233
        }
2234
0
    }
2235
    
2236
    /// Handle `str()` type conversion - extract string representation
2237
0
    fn transpile_str_conversion(&self, args: &[Expr]) -> Result<TokenStream> {
2238
0
        if args.len() != 1 {
2239
0
            bail!("str() expects exactly 1 argument");
2240
0
        }
2241
0
        let value = self.transpile_expr(&args[0])?;
2242
0
        Ok(quote! { format!("{}", #value) })
2243
0
    }
2244
    
2245
    /// Handle `int()` type conversion with literal-specific optimizations
2246
0
    fn transpile_int_conversion(&self, args: &[Expr]) -> Result<TokenStream> {
2247
0
        if args.len() != 1 {
2248
0
            bail!("int() expects exactly 1 argument");
2249
0
        }
2250
        
2251
        // Check if the argument is a literal for compile-time optimizations
2252
0
        match &args[0].kind {
2253
            ExprKind::Literal(Literal::String(_)) => {
2254
0
                let value = self.transpile_expr(&args[0])?;
2255
0
                Ok(quote! { #value.parse::<i64>().expect("Failed to parse integer") })
2256
            }
2257
0
            ExprKind::StringInterpolation { parts } if parts.len() == 1 => {
2258
0
                if let crate::frontend::ast::StringPart::Text(_) = &parts[0] {
2259
0
                    let value = self.transpile_expr(&args[0])?;
2260
0
                    Ok(quote! { #value.parse::<i64>().expect("Failed to parse integer") })
2261
                } else {
2262
0
                    self.transpile_int_generic(&args[0])
2263
                }
2264
            }
2265
            ExprKind::Literal(Literal::Float(_)) => {
2266
0
                let value = self.transpile_expr(&args[0])?;
2267
0
                Ok(quote! { (#value as i64) })
2268
            }
2269
            ExprKind::Literal(Literal::Bool(_)) => {
2270
0
                let value = self.transpile_expr(&args[0])?;
2271
0
                Ok(quote! { if #value { 1i64 } else { 0i64 } })
2272
            }
2273
0
            _ => self.transpile_int_generic(&args[0])
2274
        }
2275
0
    }
2276
    
2277
    /// Generic int conversion for non-literal expressions
2278
0
    fn transpile_int_generic(&self, expr: &Expr) -> Result<TokenStream> {
2279
0
        let value = self.transpile_expr(expr)?;
2280
0
        Ok(quote! { (#value as i64) })
2281
0
    }
2282
    
2283
    /// Handle `float()` type conversion with literal-specific optimizations
2284
0
    fn transpile_float_conversion(&self, args: &[Expr]) -> Result<TokenStream> {
2285
0
        if args.len() != 1 {
2286
0
            bail!("float() expects exactly 1 argument");
2287
0
        }
2288
        
2289
        // Check if the argument is a literal for compile-time optimizations
2290
0
        match &args[0].kind {
2291
            ExprKind::Literal(Literal::String(_)) => {
2292
0
                let value = self.transpile_expr(&args[0])?;
2293
0
                Ok(quote! { #value.parse::<f64>().expect("Failed to parse float") })
2294
            }
2295
0
            ExprKind::StringInterpolation { parts } if parts.len() == 1 => {
2296
0
                if let crate::frontend::ast::StringPart::Text(_) = &parts[0] {
2297
0
                    let value = self.transpile_expr(&args[0])?;
2298
0
                    Ok(quote! { #value.parse::<f64>().expect("Failed to parse float") })
2299
                } else {
2300
0
                    self.transpile_float_generic(&args[0])
2301
                }
2302
            }
2303
            ExprKind::Literal(Literal::Integer(_)) => {
2304
0
                let value = self.transpile_expr(&args[0])?;
2305
0
                Ok(quote! { (#value as f64) })
2306
            }
2307
0
            _ => self.transpile_float_generic(&args[0])
2308
        }
2309
0
    }
2310
    
2311
    /// Generic float conversion for non-literal expressions
2312
0
    fn transpile_float_generic(&self, expr: &Expr) -> Result<TokenStream> {
2313
0
        let value = self.transpile_expr(expr)?;
2314
0
        Ok(quote! { (#value as f64) })
2315
0
    }
2316
    
2317
    /// Handle `bool()` type conversion with type-specific logic
2318
0
    fn transpile_bool_conversion(&self, args: &[Expr]) -> Result<TokenStream> {
2319
0
        if args.len() != 1 {
2320
0
            bail!("bool() expects exactly 1 argument");
2321
0
        }
2322
        
2323
        // Check the type of the argument to generate appropriate conversion
2324
0
        match &args[0].kind {
2325
            ExprKind::Literal(Literal::Integer(_)) => {
2326
0
                let value = self.transpile_expr(&args[0])?;
2327
0
                Ok(quote! { (#value != 0) })
2328
            }
2329
            ExprKind::Literal(Literal::String(_)) => {
2330
0
                let value = self.transpile_expr(&args[0])?;
2331
0
                Ok(quote! { !#value.is_empty() })
2332
            }
2333
0
            ExprKind::StringInterpolation { parts } if parts.len() == 1 => {
2334
0
                let value = self.transpile_expr(&args[0])?;
2335
0
                Ok(quote! { !#value.is_empty() })
2336
            }
2337
            ExprKind::Literal(Literal::Bool(_)) => {
2338
                // Boolean already, just pass through
2339
0
                let value = self.transpile_expr(&args[0])?;
2340
0
                Ok(value)
2341
            }
2342
            _ => {
2343
                // Generic case - for numbers check != 0
2344
0
                let value = self.transpile_expr(&args[0])?;
2345
0
                Ok(quote! { (#value != 0) })
2346
            }
2347
        }
2348
0
    }
2349
    
2350
    /// Try to transpile advanced math functions (sin, cos, tan, log, log10, random)
2351
    /// 
2352
    /// # Examples
2353
    /// 
2354
    /// ```rust
2355
    /// # use ruchy::backend::transpiler::Transpiler;
2356
    /// let transpiler = Transpiler::new();
2357
    /// // sin(x) -> x.sin()
2358
    /// // cos(x) -> x.cos()
2359
    /// // log(x) -> x.ln()
2360
    /// // random() -> rand::random::<f64>()
2361
    /// ```
2362
0
    fn try_transpile_math_functions(&self, base_name: &str, args: &[Expr]) -> Result<Option<TokenStream>> {
2363
0
        match base_name {
2364
0
            "sin" | "cos" | "tan" => {
2365
0
                if args.len() != 1 {
2366
0
                    bail!("{}() expects exactly 1 argument", base_name);
2367
0
                }
2368
0
                let value = self.transpile_expr(&args[0])?;
2369
0
                let method = proc_macro2::Ident::new(base_name, proc_macro2::Span::call_site());
2370
0
                Ok(Some(quote! { ((#value as f64).#method()) }))
2371
            }
2372
0
            "log" => {
2373
0
                if args.len() != 1 {
2374
0
                    bail!("log() expects exactly 1 argument");
2375
0
                }
2376
0
                let value = self.transpile_expr(&args[0])?;
2377
0
                Ok(Some(quote! { ((#value as f64).ln()) }))
2378
            }
2379
0
            "log10" => {
2380
0
                if args.len() != 1 {
2381
0
                    bail!("log10() expects exactly 1 argument");
2382
0
                }
2383
0
                let value = self.transpile_expr(&args[0])?;
2384
0
                Ok(Some(quote! { ((#value as f64).log10()) }))
2385
            }
2386
0
            "random" => {
2387
0
                if !args.is_empty() {
2388
0
                    bail!("random() expects no arguments");
2389
0
                }
2390
                // Use a simple pseudo-random generator
2391
0
                Ok(Some(quote! {
2392
0
                    {
2393
0
                        use std::time::{SystemTime, UNIX_EPOCH};
2394
0
                        let seed = SystemTime::now()
2395
0
                            .duration_since(UNIX_EPOCH)
2396
0
                            .unwrap()
2397
0
                            .as_nanos() as u64;
2398
0
                        // Use a safe LCG that won't overflow
2399
0
                        let a = 1664525u64;
2400
0
                        let c = 1013904223u64;
2401
0
                        let m = 1u64 << 32;
2402
0
                        ((seed.wrapping_mul(a).wrapping_add(c)) % m) as f64 / m as f64
2403
0
                    }
2404
0
                }))
2405
            }
2406
0
            _ => Ok(None)
2407
        }
2408
0
    }
2409
    
2410
    /// Handle assert functions (assert, `assert_eq`, `assert_ne`)
2411
    /// 
2412
    /// # Examples
2413
    /// 
2414
    /// ```
2415
    /// use ruchy::{Transpiler, Parser};
2416
    /// 
2417
    /// let transpiler = Transpiler::new();
2418
    /// let mut parser = Parser::new("assert(true)");
2419
    /// let ast = parser.parse().unwrap();
2420
    /// let result = transpiler.transpile(&ast).unwrap().to_string();
2421
    /// assert!(result.contains("assert !"));
2422
    /// ```
2423
0
    fn try_transpile_assert_function(
2424
0
        &self,
2425
0
        _func_tokens: &TokenStream,
2426
0
        base_name: &str,
2427
0
        args: &[Expr]
2428
0
    ) -> Result<Option<TokenStream>> {
2429
0
        match base_name {
2430
0
            "assert" => {
2431
0
                if args.is_empty() || args.len() > 2 {
2432
0
                    bail!("assert expects 1 or 2 arguments (condition, optional message)");
2433
0
                }
2434
0
                let condition = self.transpile_expr(&args[0])?;
2435
0
                if args.len() == 1 {
2436
0
                    Ok(Some(quote! { assert!(#condition) }))
2437
                } else {
2438
0
                    let message = self.transpile_expr(&args[1])?;
2439
0
                    Ok(Some(quote! { assert!(#condition, "{}", #message) }))
2440
                }
2441
            }
2442
0
            "assert_eq" => {
2443
0
                if args.len() < 2 || args.len() > 3 {
2444
0
                    bail!("assert_eq expects 2 or 3 arguments (left, right, optional message)");
2445
0
                }
2446
0
                let left = self.transpile_expr(&args[0])?;
2447
0
                let right = self.transpile_expr(&args[1])?;
2448
0
                if args.len() == 2 {
2449
0
                    Ok(Some(quote! { assert_eq!(#left, #right) }))
2450
                } else {
2451
0
                    let message = self.transpile_expr(&args[2])?;
2452
0
                    Ok(Some(quote! { assert_eq!(#left, #right, "{}", #message) }))
2453
                }
2454
            }
2455
0
            "assert_ne" => {
2456
0
                if args.len() < 2 || args.len() > 3 {
2457
0
                    bail!("assert_ne expects 2 or 3 arguments (left, right, optional message)");
2458
0
                }
2459
0
                let left = self.transpile_expr(&args[0])?;
2460
0
                let right = self.transpile_expr(&args[1])?;
2461
0
                if args.len() == 2 {
2462
0
                    Ok(Some(quote! { assert_ne!(#left, #right) }))
2463
                } else {
2464
0
                    let message = self.transpile_expr(&args[2])?;
2465
0
                    Ok(Some(quote! { assert_ne!(#left, #right, "{}", #message) }))
2466
                }
2467
            }
2468
0
            _ => Ok(None)
2469
        }
2470
0
    }
2471
    
2472
    /// Handle collection constructors (`HashMap`, `HashSet`)
2473
    /// 
2474
    /// # Examples
2475
    /// 
2476
    /// ```
2477
    /// use ruchy::{Transpiler, Parser};
2478
    /// 
2479
    /// let transpiler = Transpiler::new();
2480
    /// let mut parser = Parser::new("HashMap()");
2481
    /// let ast = parser.parse().unwrap();
2482
    /// let result = transpiler.transpile(&ast).unwrap().to_string();
2483
    /// assert!(result.contains("HashMap"));
2484
    /// ```
2485
0
    fn try_transpile_collection_constructor(&self, base_name: &str, args: &[Expr]) -> Result<Option<TokenStream>> {
2486
0
        match (base_name, args.len()) {
2487
0
            ("HashMap", 0) => Ok(Some(quote! { std::collections::HashMap::new() })),
2488
0
            ("HashSet", 0) => Ok(Some(quote! { std::collections::HashSet::new() })),
2489
0
            _ => Ok(None)
2490
        }
2491
0
    }
2492
    
2493
    /// Handle `DataFrame` functions (col)
2494
    /// 
2495
    /// # Examples
2496
    /// 
2497
    /// ```
2498
    /// use ruchy::{Transpiler, Parser};
2499
    /// 
2500
    /// let transpiler = Transpiler::new();
2501
    /// let mut parser = Parser::new(r#"col("name")"#);
2502
    /// let ast = parser.parse().unwrap();
2503
    /// let result = transpiler.transpile(&ast).unwrap().to_string();
2504
    /// assert!(result.contains("polars"));
2505
    /// ```
2506
0
    fn try_transpile_dataframe_function(&self, base_name: &str, args: &[Expr]) -> Result<Option<TokenStream>> {
2507
        // Handle DataFrame static methods
2508
0
        if base_name.starts_with("DataFrame::") {
2509
0
            let method = base_name.strip_prefix("DataFrame::").unwrap();
2510
0
            match method {
2511
0
                "new" if args.is_empty() => {
2512
0
                    return Ok(Some(quote! { polars::prelude::DataFrame::empty() }));
2513
                }
2514
0
                "from_csv" if args.len() == 1 => {
2515
0
                    let path_tokens = self.transpile_expr(&args[0])?;
2516
0
                    return Ok(Some(quote! { 
2517
0
                        polars::prelude::CsvReader::from_path(#path_tokens)
2518
0
                            .unwrap()
2519
0
                            .finish()
2520
0
                            .unwrap()
2521
0
                    }));
2522
                }
2523
0
                _ => {}
2524
            }
2525
0
        }
2526
        
2527
        // Handle col() function for column references
2528
0
        if base_name == "col" && args.len() == 1 {
2529
0
            if let ExprKind::Literal(Literal::String(col_name)) = &args[0].kind {
2530
0
                return Ok(Some(quote! { polars::prelude::col(#col_name) }));
2531
0
            }
2532
0
        }
2533
0
        Ok(None)
2534
0
    }
2535
    
2536
    /// Handle regular function calls with string literal conversion
2537
    /// 
2538
    /// # Examples
2539
    /// 
2540
    /// ```
2541
    /// use ruchy::{Transpiler, Parser};
2542
    /// 
2543
    /// let transpiler = Transpiler::new();
2544
    /// let mut parser = Parser::new(r#"my_func("test")"#);
2545
    /// let ast = parser.parse().unwrap();
2546
    /// let result = transpiler.transpile(&ast).unwrap().to_string();
2547
    /// assert!(result.contains("my_func"));
2548
    /// ```
2549
0
    fn transpile_regular_function_call(
2550
0
        &self,
2551
0
        func_tokens: &TokenStream,
2552
0
        args: &[Expr]
2553
0
    ) -> Result<TokenStream> {
2554
        // Get function name for signature lookup
2555
0
        let func_name = func_tokens.to_string().trim().to_string();
2556
        
2557
        // Apply type coercion based on function signature
2558
0
        let arg_tokens: Result<Vec<_>> = if let Some(signature) = self.function_signatures.get(&func_name) {
2559
0
            args.iter().enumerate().map(|(i, arg)| {
2560
0
                let base_tokens = self.transpile_expr(arg)?;
2561
                
2562
                // Apply String/&str coercion if needed
2563
0
                if let Some(expected_type) = signature.param_types.get(i) {
2564
0
                    self.apply_string_coercion(arg, &base_tokens, expected_type)
2565
                } else {
2566
0
                    Ok(base_tokens)
2567
                }
2568
0
            }).collect()
2569
        } else {
2570
            // No signature info - transpile as-is
2571
0
            args.iter().map(|a| self.transpile_expr(a)).collect()
2572
        };
2573
        
2574
0
        let arg_tokens = arg_tokens?;
2575
0
        Ok(quote! { #func_tokens(#(#arg_tokens),*) })
2576
0
    }
2577
    
2578
    /// Apply String/&str coercion based on expected type
2579
0
    fn apply_string_coercion(
2580
0
        &self,
2581
0
        arg: &Expr,
2582
0
        tokens: &TokenStream,
2583
0
        expected_type: &str
2584
0
    ) -> Result<TokenStream> {
2585
        use crate::frontend::ast::{ExprKind, Literal};
2586
        
2587
0
        match (&arg.kind, expected_type) {
2588
            // String literal to String parameter: add .to_string()
2589
0
            (ExprKind::Literal(Literal::String(_)), "String") => {
2590
0
                Ok(quote! { #tokens.to_string() })
2591
            }
2592
            // String literal to &str parameter: keep as-is
2593
0
            (ExprKind::Literal(Literal::String(_)), expected) if expected.starts_with('&') => {
2594
0
                Ok(tokens.clone())
2595
            }
2596
            // Variable that might be &str to String parameter
2597
0
            (ExprKind::Identifier(_), "String") => {
2598
                // For now, assume string variables are String type from auto-conversion
2599
                // This matches the existing behavior in transpile_let
2600
0
                Ok(tokens.clone())
2601
            }
2602
            // No coercion needed
2603
0
            _ => Ok(tokens.clone())
2604
        }
2605
0
    }
2606
}
2607
2608
#[cfg(test)]
2609
#[allow(clippy::single_char_pattern)]
2610
mod tests {
2611
    use super::*;
2612
    use crate::Parser;
2613
2614
    fn create_transpiler() -> Transpiler {
2615
        Transpiler::new()
2616
    }
2617
2618
    #[test]
2619
    fn test_transpile_if_with_else() {
2620
        let transpiler = create_transpiler();
2621
        let code = "if true { 1 } else { 2 }";
2622
        let mut parser = Parser::new(code);
2623
        let ast = parser.parse().unwrap();
2624
        
2625
        let result = transpiler.transpile(&ast).unwrap();
2626
        let rust_str = result.to_string();
2627
        
2628
        assert!(rust_str.contains("if"));
2629
        assert!(rust_str.contains("else"));
2630
    }
2631
2632
    #[test]
2633
    fn test_transpile_if_without_else() {
2634
        let transpiler = create_transpiler();
2635
        let code = "if true { 1 }";
2636
        let mut parser = Parser::new(code);
2637
        let ast = parser.parse().unwrap();
2638
        
2639
        let result = transpiler.transpile(&ast).unwrap();
2640
        let rust_str = result.to_string();
2641
        
2642
        assert!(rust_str.contains("if"));
2643
        assert!(!rust_str.contains("else"));
2644
    }
2645
2646
    #[test]
2647
    fn test_transpile_let_binding() {
2648
        let transpiler = create_transpiler();
2649
        let code = "let x = 5; x";
2650
        let mut parser = Parser::new(code);
2651
        let ast = parser.parse().unwrap();
2652
        
2653
        let result = transpiler.transpile(&ast).unwrap();
2654
        let rust_str = result.to_string();
2655
        
2656
        assert!(rust_str.contains("let"));
2657
        assert!(rust_str.contains("x"));
2658
        assert!(rust_str.contains("5"));
2659
    }
2660
2661
    #[test]
2662
    fn test_transpile_mutable_let() {
2663
        let transpiler = create_transpiler();
2664
        let code = "let mut x = 5; x";
2665
        let mut parser = Parser::new(code);
2666
        let ast = parser.parse().unwrap();
2667
        
2668
        let result = transpiler.transpile(&ast).unwrap();
2669
        let rust_str = result.to_string();
2670
        
2671
        assert!(rust_str.contains("mut"));
2672
    }
2673
2674
    #[test]
2675
    fn test_transpile_for_loop() {
2676
        let transpiler = create_transpiler();
2677
        let code = "for x in [1, 2, 3] { x }";
2678
        let mut parser = Parser::new(code);
2679
        let ast = parser.parse().unwrap();
2680
        
2681
        let result = transpiler.transpile(&ast).unwrap();
2682
        let rust_str = result.to_string();
2683
        
2684
        assert!(rust_str.contains("for"));
2685
        assert!(rust_str.contains("in"));
2686
    }
2687
2688
    #[test]
2689
    fn test_transpile_while_loop() {
2690
        let transpiler = create_transpiler();
2691
        let code = "while true { }";
2692
        let mut parser = Parser::new(code);
2693
        let ast = parser.parse().unwrap();
2694
        
2695
        let result = transpiler.transpile(&ast).unwrap();
2696
        let rust_str = result.to_string();
2697
        
2698
        assert!(rust_str.contains("while"));
2699
    }
2700
2701
    #[test]
2702
    fn test_function_with_parameters() {
2703
        let transpiler = create_transpiler();
2704
        let code = "fun add(x, y) { x + y }";
2705
        let mut parser = Parser::new(code);
2706
        let ast = parser.parse().unwrap();
2707
        
2708
        let result = transpiler.transpile(&ast).unwrap();
2709
        let rust_str = result.to_string();
2710
        
2711
        assert!(rust_str.contains("fn add"));
2712
        assert!(rust_str.contains("x"));
2713
        assert!(rust_str.contains("y"));
2714
    }
2715
2716
    #[test]
2717
    fn test_function_without_parameters() {
2718
        let transpiler = create_transpiler();
2719
        let code = "fun hello() { \"world\" }";
2720
        let mut parser = Parser::new(code);
2721
        let ast = parser.parse().unwrap();
2722
        
2723
        let result = transpiler.transpile(&ast).unwrap();
2724
        let rust_str = result.to_string();
2725
        
2726
        assert!(rust_str.contains("fn hello"));
2727
        assert!(rust_str.contains("()"));
2728
    }
2729
2730
    #[test]
2731
    fn test_looks_like_numeric_function() {
2732
        let transpiler = create_transpiler();
2733
        
2734
        // Test known numeric function names
2735
        assert!(transpiler.looks_like_numeric_function("double"));
2736
        assert!(transpiler.looks_like_numeric_function("add"));
2737
        assert!(transpiler.looks_like_numeric_function("square"));
2738
        
2739
        // Test non-numeric function names
2740
        assert!(!transpiler.looks_like_numeric_function("hello"));
2741
        assert!(!transpiler.looks_like_numeric_function("main"));
2742
        assert!(!transpiler.looks_like_numeric_function("test"));
2743
    }
2744
2745
    #[test]
2746
    fn test_match_expression() {
2747
        let transpiler = create_transpiler();
2748
        let code = "match x { 1 => \"one\", _ => \"other\" }";
2749
        let mut parser = Parser::new(code);
2750
        let ast = parser.parse().unwrap();
2751
        
2752
        let result = transpiler.transpile(&ast).unwrap();
2753
        let rust_str = result.to_string();
2754
        
2755
        assert!(rust_str.contains("match"));
2756
    }
2757
2758
    #[test]
2759
    fn test_lambda_expression() {
2760
        let transpiler = create_transpiler();
2761
        let code = "(x) => x + 1";
2762
        let mut parser = Parser::new(code);
2763
        let ast = parser.parse().unwrap();
2764
        
2765
        let result = transpiler.transpile(&ast).unwrap();
2766
        let rust_str = result.to_string();
2767
        
2768
        // Lambda should be transpiled to closure
2769
        assert!(rust_str.contains("|") || rust_str.contains("move"));
2770
    }
2771
2772
    #[test]
2773
    fn test_reserved_keyword_handling() {
2774
        let transpiler = create_transpiler();
2775
        let code = "let final = 5; final";  // Use regular keyword, not r# syntax
2776
        let mut parser = Parser::new(code);
2777
        let ast = parser.parse().unwrap();
2778
        
2779
        let result = transpiler.transpile(&ast).unwrap();
2780
        let rust_str = result.to_string();
2781
        
2782
        // Should handle Rust reserved keywords by prefixing with r#
2783
        assert!(rust_str.contains("r#final") || rust_str.contains("final"));
2784
    }
2785
2786
    #[test]
2787
    fn test_generic_function() {
2788
        let transpiler = create_transpiler();
2789
        let code = "fun identity<T>(x: T) -> T { x }";
2790
        let mut parser = Parser::new(code);
2791
        let ast = parser.parse().unwrap();
2792
        
2793
        let result = transpiler.transpile(&ast).unwrap();
2794
        let rust_str = result.to_string();
2795
        
2796
        assert!(rust_str.contains("fn identity"));
2797
    }
2798
2799
    #[test]
2800
    fn test_main_function_special_case() {
2801
        let transpiler = create_transpiler();
2802
        let code = "fun main() { println(\"Hello\") }";
2803
        let mut parser = Parser::new(code);
2804
        let ast = parser.parse().unwrap();
2805
        
2806
        let result = transpiler.transpile(&ast).unwrap();
2807
        let rust_str = result.to_string();
2808
        
2809
        // main should not have explicit return type
2810
        assert!(!rust_str.contains("fn main() ->"));
2811
        assert!(!rust_str.contains("fn main () ->"));
2812
    }
2813
2814
    #[test]
2815
    fn test_dataframe_function_call() {
2816
        let transpiler = create_transpiler();
2817
        let code = "col(\"name\")";
2818
        let mut parser = Parser::new(code);
2819
        let ast = parser.parse().unwrap();
2820
        
2821
        let result = transpiler.transpile(&ast).unwrap();
2822
        let rust_str = result.to_string();
2823
        
2824
        // Should transpile DataFrame column access
2825
        assert!(rust_str.contains("polars") || rust_str.contains("col"));
2826
    }
2827
2828
    #[test]
2829
    fn test_regular_function_call_string_conversion() {
2830
        let transpiler = create_transpiler();
2831
        let code = "my_func(\"test\")";
2832
        let mut parser = Parser::new(code);
2833
        let ast = parser.parse().unwrap();
2834
        
2835
        let result = transpiler.transpile(&ast).unwrap();
2836
        let rust_str = result.to_string();
2837
        
2838
        // Regular function calls should convert string literals
2839
        assert!(rust_str.contains("my_func"));
2840
        assert!(rust_str.contains("to_string") || rust_str.contains("\"test\""));
2841
    }
2842
2843
    #[test]
2844
    fn test_nested_expressions() {
2845
        let transpiler = create_transpiler();
2846
        let code = "if true { let x = 5; x + 1 } else { 0 }";
2847
        let mut parser = Parser::new(code);
2848
        let ast = parser.parse().unwrap();
2849
        
2850
        let result = transpiler.transpile(&ast).unwrap();
2851
        let rust_str = result.to_string();
2852
        
2853
        // Should handle nested let inside if
2854
        assert!(rust_str.contains("if"));
2855
        assert!(rust_str.contains("let"));
2856
        assert!(rust_str.contains("else"));
2857
    }
2858
2859
    #[test]
2860
    fn test_type_inference_integration() {
2861
        let transpiler = create_transpiler();
2862
        
2863
        // Test function parameter as function
2864
        let code1 = "fun apply(f, x) { f(x) }";
2865
        let mut parser1 = Parser::new(code1);
2866
        let ast1 = parser1.parse().unwrap();
2867
        let result1 = transpiler.transpile(&ast1).unwrap();
2868
        let rust_str1 = result1.to_string();
2869
        assert!(rust_str1.contains("impl Fn"));
2870
        
2871
        // Test numeric parameter
2872
        let code2 = "fun double(n) { n * 2 }";
2873
        let mut parser2 = Parser::new(code2);
2874
        let ast2 = parser2.parse().unwrap();
2875
        let result2 = transpiler.transpile(&ast2).unwrap();
2876
        let rust_str2 = result2.to_string();
2877
        assert!(rust_str2.contains("n : i32") || rust_str2.contains("n: i32"));
2878
        
2879
        // Test string parameter
2880
        let code3 = "fun greet(name) { \"Hello \" + name }";
2881
        let mut parser3 = Parser::new(code3);
2882
        let ast3 = parser3.parse().unwrap();
2883
        let result3 = transpiler.transpile(&ast3).unwrap();
2884
        let rust_str3 = result3.to_string();
2885
        assert!(rust_str3.contains("name : String") || rust_str3.contains("name: String"));
2886
    }
2887
2888
    #[test]
2889
    fn test_return_type_inference() {
2890
        let transpiler = create_transpiler();
2891
        
2892
        // Test numeric function gets return type
2893
        let code = "fun double(n) { n * 2 }";
2894
        let mut parser = Parser::new(code);
2895
        let ast = parser.parse().unwrap();
2896
        let result = transpiler.transpile(&ast).unwrap();
2897
        let rust_str = result.to_string();
2898
        assert!(rust_str.contains("-> i32"));
2899
    }
2900
2901
    #[test]
2902
    fn test_void_function_no_return_type() {
2903
        let transpiler = create_transpiler();
2904
        let code = "fun print_hello() { println(\"Hello\") }";
2905
        let mut parser = Parser::new(code);
2906
        let ast = parser.parse().unwrap();
2907
        let result = transpiler.transpile(&ast).unwrap();
2908
        let rust_str = result.to_string();
2909
        
2910
        // Should not have explicit return type for void functions
2911
        assert!(!rust_str.contains("-> "));
2912
    }
2913
2914
    #[test]
2915
    fn test_complex_function_combinations() {
2916
        let transpiler = create_transpiler();
2917
        let code = "fun transform(f, n, m) { f(n + m) * 2 }";
2918
        let mut parser = Parser::new(code);
2919
        let ast = parser.parse().unwrap();
2920
        let result = transpiler.transpile(&ast).unwrap();
2921
        let rust_str = result.to_string();
2922
        
2923
        // f should be function, n and m should be i32
2924
        assert!(rust_str.contains("impl Fn"));
2925
        assert!(rust_str.contains("n : i32") || rust_str.contains("n: i32"));
2926
        assert!(rust_str.contains("m : i32") || rust_str.contains("m: i32"));
2927
    }
2928
}