Skip to main content

portalis_transpiler/
python_to_rust.rs

1//! Python to Rust translator
2//!
3//! Translates Python AST to Rust code, implementing the 527 Python language features.
4//! Starting with Low complexity features for Phase 1.
5
6use crate::python_ast::*;
7use crate::stdlib_mapper::StdlibMapper;
8use crate::{Error, Result};
9use std::collections::HashMap;
10
11/// Type inference engine for Python → Rust translation
12#[derive(Debug, Clone)]
13pub struct TypeInference {
14    /// Variable name → inferred Rust type
15    type_map: HashMap<String, RustType>,
16}
17
18/// Rust type representation
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub enum RustType {
21    I32,
22    I64,
23    F64,
24    Bool,
25    String,
26    Unit,
27    Vec(Box<RustType>),
28    Option(Box<RustType>),
29    Unknown,
30}
31
32impl RustType {
33    /// Convert to Rust type string
34    pub fn to_rust_str(&self) -> String {
35        match self {
36            RustType::I32 => "i32".to_string(),
37            RustType::I64 => "i64".to_string(),
38            RustType::F64 => "f64".to_string(),
39            RustType::Bool => "bool".to_string(),
40            RustType::String => "String".to_string(),
41            RustType::Unit => "()".to_string(),
42            RustType::Vec(inner) => format!("Vec<{}>", inner.to_rust_str()),
43            RustType::Option(inner) => format!("Option<{}>", inner.to_rust_str()),
44            RustType::Unknown => "()".to_string(),
45        }
46    }
47}
48
49impl TypeInference {
50    pub fn new() -> Self {
51        Self {
52            type_map: HashMap::new(),
53        }
54    }
55
56    /// Infer type from Python literal
57    pub fn infer_from_literal(&self, lit: &PyLiteral) -> RustType {
58        match lit {
59            PyLiteral::Int(n) => {
60                // Use i32 for small integers, i64 for large
61                if *n >= i32::MIN as i64 && *n <= i32::MAX as i64 {
62                    RustType::I32
63                } else {
64                    RustType::I64
65                }
66            }
67            PyLiteral::Float(_) => RustType::F64,
68            PyLiteral::String(_) => RustType::String,
69            PyLiteral::Bool(_) => RustType::Bool,
70            PyLiteral::None => RustType::Option(Box::new(RustType::Unknown)),
71            PyLiteral::Bytes(_) => RustType::Vec(Box::new(RustType::I32)), // Vec<u8> simplified to Vec<i32>
72        }
73    }
74
75    /// Infer type from Python expression
76    pub fn infer_expr(&mut self, expr: &PyExpr) -> RustType {
77        match expr {
78            PyExpr::Literal(lit) => self.infer_from_literal(lit),
79            PyExpr::Name(name) => self
80                .type_map
81                .get(name)
82                .cloned()
83                .unwrap_or(RustType::Unknown),
84            PyExpr::BinOp { left, op, right } => {
85                let left_type = self.infer_expr(left);
86                let right_type = self.infer_expr(right);
87
88                // Simplistic type inference
89                match op {
90                    BinOp::Add | BinOp::Sub | BinOp::Mult | BinOp::Mod => {
91                        // Numeric operations
92                        if left_type == RustType::F64 || right_type == RustType::F64 {
93                            RustType::F64
94                        } else if left_type == RustType::I64 || right_type == RustType::I64 {
95                            RustType::I64
96                        } else {
97                            RustType::I32
98                        }
99                    }
100                    BinOp::Div => RustType::F64, // Division always returns float in Python 3
101                    BinOp::FloorDiv => RustType::I32,
102                    _ => RustType::Unknown,
103                }
104            }
105            PyExpr::UnaryOp { op, operand } => {
106                let operand_type = self.infer_expr(operand);
107                match op {
108                    UnaryOp::Not => RustType::Bool,
109                    UnaryOp::USub | UnaryOp::UAdd => operand_type,
110                    _ => RustType::Unknown,
111                }
112            }
113            PyExpr::List(elements) => {
114                if elements.is_empty() {
115                    RustType::Vec(Box::new(RustType::Unknown))
116                } else {
117                    let first_type = self.infer_expr(&elements[0]);
118                    RustType::Vec(Box::new(first_type))
119                }
120            }
121            PyExpr::Tuple(elements) => {
122                if elements.is_empty() {
123                    RustType::Unknown
124                } else {
125                    // For simplicity, tuples become unit type in many contexts
126                    // but when unpacked, elements get individual types
127                    RustType::Unknown
128                }
129            }
130            PyExpr::Compare { .. } => {
131                // Comparison operators always return bool
132                RustType::Bool
133            }
134            PyExpr::Call { func, args, .. } => {
135                // Check if it's a method call (func is an Attribute)
136                if let PyExpr::Attribute { value: _, attr } = func.as_ref() {
137                    // Method call - infer based on method name
138                    match attr.as_str() {
139                        "split" | "splitlines" => RustType::Vec(Box::new(RustType::String)),
140                        "strip" | "lstrip" | "rstrip" | "lower" | "upper" | "replace" => RustType::String,
141                        "append" | "extend" | "remove" | "clear" | "sort" | "reverse" => {
142                            RustType::Unknown // Mutating methods return ()
143                        }
144                        "pop" => {
145                            // Return element type of the collection
146                            RustType::Unknown // Would need collection tracking
147                        }
148                        "join" => RustType::String,
149                        "format" => RustType::String,
150                        "items" | "keys" | "values" => RustType::Unknown, // Dict methods
151                        "count" | "index" | "find" => RustType::I32,
152                        _ => RustType::Unknown,
153                    }
154                } else if let PyExpr::Name(name) = func.as_ref() {
155                    // Function call - infer based on function name
156                    match name.as_str() {
157                        "len" => RustType::I32,
158                        "sum" => RustType::I32, // Could be smarter based on input
159                        "min" | "max" => {
160                            // Return element type of the collection
161                            if !args.is_empty() {
162                                let arg_type = self.infer_expr(&args[0]);
163                                if let RustType::Vec(inner) = arg_type {
164                                    *inner
165                                } else {
166                                    arg_type // For non-Vec args like max(a, b, c)
167                                }
168                            } else {
169                                RustType::I32
170                            }
171                        }
172                        "abs" => {
173                            if !args.is_empty() {
174                                self.infer_expr(&args[0])
175                            } else {
176                                RustType::I32
177                            }
178                        }
179                        "int" => RustType::I32,
180                        "float" => RustType::F64,
181                        "str" => RustType::String,
182                        "bool" => RustType::Bool,
183                        "range" => RustType::Unknown, // range is an iterator
184                        "enumerate" | "zip" => RustType::Unknown, // iterators
185                        "sorted" | "reversed" => {
186                            // Return Vec of same type
187                            if !args.is_empty() {
188                                self.infer_expr(&args[0])
189                            } else {
190                                RustType::Vec(Box::new(RustType::Unknown))
191                            }
192                        }
193                        "list" => {
194                            // list(iterable) returns Vec
195                            if !args.is_empty() {
196                                if let RustType::Vec(inner) = self.infer_expr(&args[0]) {
197                                    RustType::Vec(inner)
198                                } else {
199                                    RustType::Vec(Box::new(RustType::Unknown))
200                                }
201                            } else {
202                                RustType::Vec(Box::new(RustType::Unknown))
203                            }
204                        }
205                        "any" | "all" => RustType::Bool,
206                        _ => RustType::Unknown,
207                    }
208                } else {
209                    RustType::Unknown
210                }
211            }
212            PyExpr::Attribute { value, attr } => {
213                // Infer type based on method call
214                match attr.as_str() {
215                    "len" => RustType::I32,
216                    "abs" => self.infer_expr(value),
217                    "split" => RustType::Vec(Box::new(RustType::String)),
218                    "strip" | "lower" | "upper" | "replace" => RustType::String,
219                    "append" | "extend" | "remove" | "pop" | "clear" | "sort" | "reverse" => {
220                        RustType::Unknown // Mutating methods return ()
221                    }
222                    _ => RustType::Unknown,
223                }
224            }
225            _ => RustType::Unknown,
226        }
227    }
228
229    /// Record type for a variable
230    pub fn record_type(&mut self, name: String, rust_type: RustType) {
231        self.type_map.insert(name, rust_type);
232    }
233}
234
235impl Default for TypeInference {
236    fn default() -> Self {
237        Self::new()
238    }
239}
240
241/// Python to Rust code generator
242pub struct PythonToRustTranslator {
243    type_inference: TypeInference,
244    indent_level: usize,
245    stdlib_mapper: StdlibMapper,
246    imported_modules: Vec<String>,
247    /// Maps aliases to actual module names (alias -> module)
248    module_aliases: HashMap<String, String>,
249}
250
251impl PythonToRustTranslator {
252    pub fn new() -> Self {
253        Self {
254            type_inference: TypeInference::new(),
255            indent_level: 0,
256            stdlib_mapper: StdlibMapper::new(),
257            imported_modules: Vec::new(),
258            module_aliases: HashMap::new(),
259        }
260    }
261
262    /// Set imported modules for attribute resolution
263    pub fn set_imports(&mut self, imports: Vec<String>) {
264        self.imported_modules = imports;
265    }
266
267    /// Set module aliases (alias -> actual module name)
268    pub fn set_aliases(&mut self, aliases: HashMap<String, String>) {
269        self.module_aliases = aliases;
270    }
271
272    /// Resolve module name from alias or return original
273    fn resolve_module_name(&self, name: &str) -> String {
274        self.module_aliases.get(name).cloned().unwrap_or_else(|| name.to_string())
275    }
276
277    /// Extract full module path from nested attributes
278    /// e.g., os.path.exists -> "os.path"
279    /// Returns (module_path, final_attr)
280    fn extract_module_path(&self, expr: &PyExpr) -> Option<(String, String)> {
281        match expr {
282            PyExpr::Attribute { value, attr } => {
283                match value.as_ref() {
284                    // Simple case: module.attr (e.g., math.pi)
285                    PyExpr::Name(name) => {
286                        let resolved = self.resolve_module_name(name);
287                        Some((resolved, attr.clone()))
288                    }
289                    // Nested case: module.submodule.attr (e.g., os.path.exists)
290                    PyExpr::Attribute { value: inner_value, attr: inner_attr } => {
291                        if let PyExpr::Name(module_name) = inner_value.as_ref() {
292                            let resolved = self.resolve_module_name(module_name);
293                            let full_module = format!("{}.{}", resolved, inner_attr);
294                            Some((full_module, attr.clone()))
295                        } else {
296                            None
297                        }
298                    }
299                    _ => None,
300                }
301            }
302            _ => None,
303        }
304    }
305
306    /// Get indentation string
307    fn indent(&self) -> String {
308        "    ".repeat(self.indent_level)
309    }
310
311    /// Translate Python module to Rust code
312    pub fn translate_module(&mut self, module: &PyModule) -> Result<String> {
313        let mut code = String::new();
314
315        // Add header
316        code.push_str("// Generated by Portalis Python → Rust Translator\n");
317        code.push_str("#![allow(unused)]\n\n");
318
319        // Translate statements
320        for stmt in &module.statements {
321            code.push_str(&self.translate_stmt(stmt)?);
322        }
323
324        Ok(code)
325    }
326
327    /// Translate Python statement to Rust
328    pub fn translate_stmt(&mut self, stmt: &PyStmt) -> Result<String> {
329        match stmt {
330            PyStmt::Expr(expr) => {
331                let expr_code = self.translate_expr(expr)?;
332                Ok(format!("{}{};\n", self.indent(), expr_code))
333            }
334
335            PyStmt::Assign {
336                target,
337                value,
338            } => {
339                let value_code = self.translate_expr(value)?;
340
341                // Infer type from value
342                let rust_type = self.type_inference.infer_expr(value);
343                let type_str = rust_type.to_rust_str();
344
345                // Get target name (simplified - assumes Name expression)
346                let target_name = match target {
347                    PyExpr::Name(name) => name.clone(),
348                    _ => {
349                        return Err(Error::CodeGeneration(
350                            "Complex assignment targets not yet supported".to_string()
351                        ))
352                    }
353                };
354
355                // Record type for future reference
356                self.type_inference
357                    .record_type(target_name.clone(), rust_type.clone());
358
359                Ok(format!(
360                    "{}let {}: {} = {};\n",
361                    self.indent(),
362                    target_name,
363                    type_str,
364                    value_code
365                ))
366            }
367
368            PyStmt::AugAssign { target, op, value } => {
369                let target_code = self.translate_expr(target)?;
370                let value_code = self.translate_expr(value)?;
371                let op_str = self.binop_to_rust(*op);
372                Ok(format!(
373                    "{}{} {}= {};\n",
374                    self.indent(),
375                    target_code,
376                    op_str,
377                    value_code
378                ))
379            }
380
381            PyStmt::FunctionDef {
382                name,
383                params,
384                body,
385                return_type,
386                decorators,
387                is_async,
388            } => {
389                let mut code = String::new();
390
391                // Translate decorators to Rust attributes
392                for decorator in decorators {
393                    let rust_attr = self.translate_decorator(decorator);
394                    if !rust_attr.is_empty() {
395                        code.push_str(&format!("{}{}\n", self.indent(), rust_attr));
396                    }
397                }
398
399                // Function signature
400                let async_keyword = if *is_async { "async " } else { "" };
401                code.push_str(&format!("{}pub {}fn {}(", self.indent(), async_keyword, name));
402
403                // Parameters
404                let param_strs: Vec<String> = params
405                    .iter()
406                    .map(|param| {
407                        let rust_type = if let Some(annotation) = &param.type_annotation {
408                            self.type_annotation_to_rust(annotation)
409                        } else {
410                            RustType::Unknown
411                        };
412                        format!("{}: {}", param.name, rust_type.to_rust_str())
413                    })
414                    .collect();
415                code.push_str(&param_strs.join(", "));
416
417                // Return type
418                let ret_type = if let Some(annotation) = return_type {
419                    self.type_annotation_to_rust(annotation)
420                } else {
421                    RustType::Unit
422                };
423                code.push_str(&format!(") -> {} {{\n", ret_type.to_rust_str()));
424
425                // Body
426                self.indent_level += 1;
427                for stmt in body {
428                    code.push_str(&self.translate_stmt(stmt)?);
429                }
430                self.indent_level -= 1;
431
432                code.push_str(&format!("{}}}\n\n", self.indent()));
433
434                Ok(code)
435            }
436
437            PyStmt::Return { value } => {
438                if let Some(e) = value {
439                    let expr_code = self.translate_expr(e)?;
440                    Ok(format!("{}return {};\n", self.indent(), expr_code))
441                } else {
442                    Ok(format!("{}return;\n", self.indent()))
443                }
444            }
445
446            PyStmt::Assert { test, msg } => {
447                let test_code = self.translate_expr(test)?;
448                if let Some(msg_expr) = msg {
449                    let msg_code = self.translate_expr(msg_expr)?;
450                    Ok(format!("{}assert!({}, {});\n", self.indent(), test_code, msg_code))
451                } else {
452                    Ok(format!("{}assert!({});\n", self.indent(), test_code))
453                }
454            }
455
456            PyStmt::If { test, body, orelse } => {
457                let mut code = String::new();
458                let test_code = self.translate_expr(test)?;
459
460                code.push_str(&format!("{}if {} {{\n", self.indent(), test_code));
461
462                self.indent_level += 1;
463                for stmt in body {
464                    code.push_str(&self.translate_stmt(stmt)?);
465                }
466                self.indent_level -= 1;
467
468                code.push_str(&format!("{}}}", self.indent()));
469
470                if !orelse.is_empty() {
471                    code.push_str(" else {\n");
472                    self.indent_level += 1;
473                    for stmt in orelse {
474                        code.push_str(&self.translate_stmt(stmt)?);
475                    }
476                    self.indent_level -= 1;
477                    code.push_str(&format!("{}}}", self.indent()));
478                }
479
480                code.push('\n');
481                Ok(code)
482            }
483
484            PyStmt::While { test, body, orelse } => {
485                let mut code = String::new();
486                let test_code = self.translate_expr(test)?;
487
488                // While-else requires a flag to track if loop completed normally
489                if !orelse.is_empty() {
490                    code.push_str(&format!("{}let mut _loop_completed = true;\n", self.indent()));
491                }
492
493                code.push_str(&format!("{}while {} {{\n", self.indent(), test_code));
494
495                self.indent_level += 1;
496                for stmt in body {
497                    // If body contains break and we have an else clause, set flag to false BEFORE break
498                    if !orelse.is_empty() && matches!(stmt, PyStmt::Break) {
499                        code.push_str(&format!("{}_loop_completed = false;\n", self.indent()));
500                    }
501                    let stmt_code = self.translate_stmt(stmt)?;
502                    code.push_str(&stmt_code);
503                }
504                self.indent_level -= 1;
505
506                code.push_str(&format!("{}}}\n", self.indent()));
507
508                // Handle else clause - executes only if loop completed normally (no break)
509                if !orelse.is_empty() {
510                    code.push_str(&format!("{}if _loop_completed {{\n", self.indent()));
511                    self.indent_level += 1;
512                    for stmt in orelse {
513                        code.push_str(&self.translate_stmt(stmt)?);
514                    }
515                    self.indent_level -= 1;
516                    code.push_str(&format!("{}}}\n", self.indent()));
517                }
518
519                Ok(code)
520            }
521
522            PyStmt::For { target, iter, body, orelse } => {
523                let mut code = String::new();
524                // Translate the iterator expression (range() is already handled in translate_expr)
525                let rust_iter = self.translate_expr(iter)?;
526
527                // Get target name (simplified - assumes Name expression)
528                let rust_target = match target {
529                    PyExpr::Name(name) => {
530                        // Register loop variable type (assume i32 for range iterations)
531                        self.type_inference.type_map.insert(name.clone(), RustType::I32);
532                        name.clone()
533                    }
534                    _ => {
535                        return Err(Error::CodeGeneration(
536                            "Complex for loop targets not yet supported".to_string()
537                        ))
538                    }
539                };
540
541                // For-else requires a flag to track if loop completed normally
542                if !orelse.is_empty() {
543                    code.push_str(&format!("{}let mut _loop_completed = true;\n", self.indent()));
544                }
545
546                code.push_str(&format!("{}for {} in {} {{\n", self.indent(), rust_target, rust_iter));
547
548                self.indent_level += 1;
549                for stmt in body {
550                    // If body contains break and we have an else clause, set flag to false BEFORE break
551                    if !orelse.is_empty() && matches!(stmt, PyStmt::Break) {
552                        code.push_str(&format!("{}_loop_completed = false;\n", self.indent()));
553                    }
554                    let stmt_code = self.translate_stmt(stmt)?;
555                    code.push_str(&stmt_code);
556                }
557                self.indent_level -= 1;
558
559                code.push_str(&format!("{}}}\n", self.indent()));
560
561                // Handle else clause - executes only if loop completed normally (no break)
562                if !orelse.is_empty() {
563                    code.push_str(&format!("{}if _loop_completed {{\n", self.indent()));
564                    self.indent_level += 1;
565                    for stmt in orelse {
566                        code.push_str(&self.translate_stmt(stmt)?);
567                    }
568                    self.indent_level -= 1;
569                    code.push_str(&format!("{}}}\n", self.indent()));
570                }
571
572                Ok(code)
573            }
574
575            PyStmt::Pass => Ok(format!("{}// pass\n", self.indent())),
576
577            PyStmt::Break => Ok(format!("{}break;\n", self.indent())),
578
579            PyStmt::Continue => Ok(format!("{}continue;\n", self.indent())),
580
581            PyStmt::ClassDef {
582                name,
583                bases: _,
584                body,
585                decorators: _,
586            } => {
587                let mut code = String::new();
588
589                // Struct definition
590                code.push_str(&format!("{}pub struct {} {{\n", self.indent(), name));
591
592                // Find __init__ to extract attributes
593                let mut attributes = vec![];
594                for stmt in body {
595                    if let PyStmt::FunctionDef {
596                        name: func_name,
597                        body: func_body,
598                        ..
599                    } = stmt
600                    {
601                        if func_name == "__init__" {
602                            // Extract self.x = ... assignments
603                            for init_stmt in func_body {
604                                if let PyStmt::Assign { target, value } = init_stmt {
605                                    // Extract attribute name from target expression
606                                    if let PyExpr::Attribute { value: obj, attr } = target {
607                                        if let PyExpr::Name(name) = obj.as_ref() {
608                                            if name == "self" {
609                                                let attr_type = self.type_inference.infer_expr(value);
610                                                attributes.push((attr.clone(), attr_type));
611                                            }
612                                        }
613                                    }
614                                }
615                            }
616                        }
617                    }
618                }
619
620                // Generate struct fields
621                self.indent_level += 1;
622                for (attr_name, attr_type) in &attributes {
623                    code.push_str(&format!(
624                        "{}pub {}: {},\n",
625                        self.indent(),
626                        attr_name,
627                        attr_type.to_rust_str()
628                    ));
629                }
630                self.indent_level -= 1;
631                code.push_str(&format!("{}}}\n\n", self.indent()));
632
633                // Impl block
634                code.push_str(&format!("{}impl {} {{\n", self.indent(), name));
635                self.indent_level += 1;
636
637                // Translate methods
638                for stmt in body {
639                    if let PyStmt::FunctionDef {
640                        name: func_name,
641                        params,
642                        body: func_body,
643                        return_type,
644                        ..
645                    } = stmt
646                    {
647                        // Skip __init__ - it becomes the struct
648                        if func_name == "__init__" {
649                            // Generate new() constructor
650                            code.push_str(&format!("{}pub fn new(", self.indent()));
651
652                            // Parameters (skip self)
653                            let param_strs: Vec<String> = params
654                                .iter()
655                                .filter(|param| param.name != "self")
656                                .map(|param| {
657                                    let rust_type = if let Some(annotation) = &param.type_annotation {
658                                        self.type_annotation_to_rust(annotation)
659                                    } else {
660                                        RustType::Unknown
661                                    };
662                                    format!("{}: {}", param.name, rust_type.to_rust_str())
663                                })
664                                .collect();
665                            code.push_str(&param_strs.join(", "));
666                            code.push_str(&format!(") -> Self {{\n"));
667
668                            // Body: create struct
669                            self.indent_level += 1;
670                            code.push_str(&format!("{}Self {{\n", self.indent()));
671                            self.indent_level += 1;
672                            for (attr_name, _) in &attributes {
673                                code.push_str(&format!("{}{},\n", self.indent(), attr_name));
674                            }
675                            self.indent_level -= 1;
676                            code.push_str(&format!("{}}}\n", self.indent()));
677                            self.indent_level -= 1;
678                            code.push_str(&format!("{}}}\n\n", self.indent()));
679                        } else {
680                            // Regular method
681                            code.push_str(&format!("{}pub fn {}(", self.indent(), func_name));
682
683                            // Parameters (including &self or &mut self)
684                            let param_strs: Vec<String> = params
685                                .iter()
686                                .map(|param| {
687                                    if param.name == "self" {
688                                        "&self".to_string()
689                                    } else {
690                                        let rust_type = if let Some(annotation) = &param.type_annotation {
691                                            self.type_annotation_to_rust(annotation)
692                                        } else {
693                                            RustType::Unknown
694                                        };
695                                        format!("{}: {}", param.name, rust_type.to_rust_str())
696                                    }
697                                })
698                                .collect();
699                            code.push_str(&param_strs.join(", "));
700
701                            // Return type
702                            let ret_type = if let Some(hint) = return_type {
703                                self.type_annotation_to_rust(hint)
704                            } else {
705                                RustType::Unit
706                            };
707                            code.push_str(&format!(") -> {} {{\n", ret_type.to_rust_str()));
708
709                            // Body
710                            self.indent_level += 1;
711                            for body_stmt in func_body {
712                                code.push_str(&self.translate_stmt(body_stmt)?);
713                            }
714                            self.indent_level -= 1;
715                            code.push_str(&format!("{}}}\n\n", self.indent()));
716                        }
717                    }
718                }
719
720                self.indent_level -= 1;
721                code.push_str(&format!("{}}}\n\n", self.indent()));
722
723                Ok(code)
724            }
725
726            PyStmt::Try { body, handlers, orelse, finalbody } => {
727                let mut code = String::new();
728
729                // In Rust, we'll use a closure + match pattern for try-except
730                // try: body -> (|| { body })()
731                // except: handlers -> match on Result or panic handling
732
733                if !finalbody.is_empty() {
734                    // With finally, we need a more complex pattern
735                    code.push_str(&format!("{}// try-except-finally\n", self.indent()));
736                    code.push_str(&format!("{}{{\n", self.indent()));
737                    self.indent_level += 1;
738
739                    // Try body with panic catching (simplified)
740                    code.push_str(&format!("{}let _result = std::panic::catch_unwind(|| {{\n", self.indent()));
741                    self.indent_level += 1;
742                    for stmt in body {
743                        code.push_str(&self.translate_stmt(stmt)?);
744                    }
745                    self.indent_level -= 1;
746                    code.push_str(&format!("{}}});\n\n", self.indent()));
747
748                    // Exception handlers
749                    if !handlers.is_empty() {
750                        code.push_str(&format!("{}if _result.is_err() {{\n", self.indent()));
751                        self.indent_level += 1;
752                        for handler in handlers {
753                            for stmt in &handler.body {
754                                code.push_str(&self.translate_stmt(stmt)?);
755                            }
756                        }
757                        self.indent_level -= 1;
758                        code.push_str(&format!("{}}}\n", self.indent()));
759                    }
760
761                    // Else clause (executes if no exception)
762                    if !orelse.is_empty() {
763                        code.push_str(&format!("{}if _result.is_ok() {{\n", self.indent()));
764                        self.indent_level += 1;
765                        for stmt in orelse {
766                            code.push_str(&self.translate_stmt(stmt)?);
767                        }
768                        self.indent_level -= 1;
769                        code.push_str(&format!("{}}}\n", self.indent()));
770                    }
771
772                    // Finally block (always executes)
773                    code.push_str(&format!("{}// finally\n", self.indent()));
774                    for stmt in finalbody {
775                        code.push_str(&self.translate_stmt(stmt)?);
776                    }
777
778                    self.indent_level -= 1;
779                    code.push_str(&format!("{}}}\n", self.indent()));
780                } else {
781                    // Simpler pattern without finally
782                    code.push_str(&format!("{}// try-except\n", self.indent()));
783                    for stmt in body {
784                        code.push_str(&self.translate_stmt(stmt)?);
785                    }
786
787                    // For now, just add comments for except blocks
788                    for (_i, handler) in handlers.iter().enumerate() {
789                        if let Some(exc_type_expr) = &handler.exception_type {
790                            let exc_type = self.translate_expr(exc_type_expr)?;
791                            code.push_str(&format!("{}// except {}\n", self.indent(), exc_type));
792                        } else {
793                            code.push_str(&format!("{}// except (bare)\n", self.indent()));
794                        }
795                    }
796                }
797
798                Ok(code)
799            }
800
801            PyStmt::Raise { exception } => {
802                if let Some(e) = exception {
803                    let exc_code = self.translate_expr(e)?;
804                    Ok(format!("{}panic!(\"{{:?}}\", {});\n", self.indent(), exc_code))
805                } else {
806                    Ok(format!("{}panic!(\"Exception raised\");\n", self.indent()))
807                }
808            }
809
810            PyStmt::Import { modules: _ } => {
811                // Import statements are handled at module level
812                // modules is Vec<(String, Option<String>)> - (module_name, optional_alias)
813                Ok(String::new())
814            }
815
816            PyStmt::ImportFrom { module: _, names: _, level: _ } => {
817                // From-import statements are handled at module level
818                // module is Option<String>, names is Vec<(String, Option<String>)>, level is usize
819                Ok(String::new())
820            }
821
822            PyStmt::With { items, body } => {
823                let mut code = String::new();
824
825                // Translate context managers to Rust scoped blocks
826                // For file operations, we'll use explicit scope + drop
827                // For locks/other resources, similar pattern
828
829                for (idx, item) in items.iter().enumerate() {
830                    let context_code = self.translate_expr(&item.context_expr)?;
831
832                    // Determine if this is a file operation or other resource
833                    let is_file_like = context_code.contains("open(")
834                        || context_code.contains("File::open")
835                        || context_code.contains("File::create");
836
837                    if let Some(var) = &item.optional_vars {
838                        let var_name = self.translate_expr(var)?;
839                        if is_file_like {
840                            // File operations: let var = File::open(...)?;
841                            code.push_str(&format!(
842                                "{}let mut {} = {};\n",
843                                self.indent(),
844                                var_name,
845                                context_code
846                            ));
847                        } else {
848                            // Generic resource: create scoped binding
849                            code.push_str(&format!(
850                                "{}let {} = {};\n",
851                                self.indent(),
852                                var_name,
853                                context_code
854                            ));
855                        }
856                    } else {
857                        // No variable binding - just execute
858                        code.push_str(&format!(
859                            "{}{};\n",
860                            self.indent(),
861                            context_code
862                        ));
863                    }
864
865                    // Open scope for resource cleanup
866                    if idx == items.len() - 1 {
867                        code.push_str(&format!("{}{{\n", self.indent()));
868                    }
869                }
870
871                // Translate body
872                self.indent_level += 1;
873                for stmt in body {
874                    code.push_str(&self.translate_stmt(stmt)?);
875                }
876                self.indent_level -= 1;
877
878                // Close scope (resources will be dropped)
879                code.push_str(&format!("{}}}\n", self.indent()));
880                code.push_str(&format!("{}// End of with block\n", self.indent()));
881
882                Ok(code)
883            }
884
885            _ => Err(Error::CodeGeneration(format!(
886                "Statement type not yet implemented: {:?}",
887                stmt
888            ))),
889        }
890    }
891
892    /// Translate Python expression to Rust
893    pub fn translate_expr(&mut self, expr: &PyExpr) -> Result<String> {
894        match expr {
895            PyExpr::Literal(lit) => self.translate_literal(lit),
896
897            PyExpr::Name(name) => Ok(name.clone()),
898
899            PyExpr::Await(value) => {
900                let value_code = self.translate_expr(value)?;
901                Ok(format!("{}.await", value_code))
902            }
903
904            PyExpr::BinOp { left, op, right } => {
905                let left_code = self.translate_expr(left)?;
906                let right_code = self.translate_expr(right)?;
907                let op_str = self.binop_to_rust(*op);
908                Ok(format!("{} {} {}", left_code, op_str, right_code))
909            }
910
911            PyExpr::UnaryOp { op, operand } => {
912                let operand_code = self.translate_expr(operand)?;
913                let op_str = self.unaryop_to_rust(*op);
914                Ok(format!("{}{}", op_str, operand_code))
915            }
916
917            PyExpr::Call { func, args, .. } => {
918                // Check if it's a method call (object.method())
919                if let PyExpr::Attribute { value, attr } = func.as_ref() {
920                    // Try to extract module path (handles nested like os.path.exists())
921                    if let Some((module_path, final_attr)) = self.extract_module_path(func) {
922                        let parts: Vec<&str> = module_path.split('.').collect();
923                        let base_module = parts[0];
924
925                        if self.imported_modules.contains(&module_path) || self.imported_modules.contains(&base_module.to_string()) {
926                            let args_code: Vec<String> = args
927                                .iter()
928                                .map(|arg| self.translate_expr(arg))
929                                .collect::<Result<Vec<_>>>()?;
930
931                            // Handle special cases for known modules
932                            if module_path == "math" && final_attr == "sqrt" {
933                                if !args_code.is_empty() {
934                                    return Ok(format!("({} as f64).sqrt()", args_code[0]));
935                                }
936                            }
937                            if module_path == "math" && final_attr == "pow" {
938                                if args_code.len() >= 2 {
939                                    return Ok(format!("({} as f64).powf({} as f64)", args_code[0], args_code[1]));
940                                }
941                            }
942                            if module_path == "json" && final_attr == "dumps" {
943                                if !args_code.is_empty() {
944                                    return Ok(format!("serde_json::to_string(&{})?", args_code[0]));
945                                }
946                            }
947                            if module_path == "json" && final_attr == "loads" {
948                                if !args_code.is_empty() {
949                                    return Ok(format!("serde_json::from_str({})?", args_code[0]));
950                                }
951                            }
952                            // Handle nested module functions like os.path.exists()
953                            if module_path == "os.path" && final_attr == "exists" {
954                                if !args_code.is_empty() {
955                                    return Ok(format!("std::path::Path::new(&{}).exists()", args_code[0]));
956                                }
957                            }
958                            if module_path == "os.path" && final_attr == "join" {
959                                if args_code.len() >= 2 {
960                                    return Ok(format!("std::path::Path::new(&{}).join({})", args_code[0], args_code[1]));
961                                }
962                            }
963                        }
964                    }
965
966                    let value_code = self.translate_expr(value)?;
967                    let args_code: Vec<String> = args
968                        .iter()
969                        .map(|arg| self.translate_expr(arg))
970                        .collect::<Result<Vec<_>>>()?;
971
972                    // Translate common string methods
973                    match attr.as_str() {
974                        "upper" => return Ok(format!("{}.to_uppercase()", value_code)),
975                        "lower" => return Ok(format!("{}.to_lowercase()", value_code)),
976                        "strip" => return Ok(format!("{}.trim()", value_code)),
977                        "lstrip" => return Ok(format!("{}.trim_start()", value_code)),
978                        "rstrip" => return Ok(format!("{}.trim_end()", value_code)),
979                        "split" => {
980                            if args_code.is_empty() {
981                                return Ok(format!("{}.split_whitespace().collect::<Vec<_>>()", value_code));
982                            } else {
983                                return Ok(format!("{}.split({}).collect::<Vec<_>>()", value_code, args_code[0]));
984                            }
985                        }
986                        "join" => {
987                            if args_code.len() == 1 {
988                                return Ok(format!("{}.join(&{})", args_code[0], value_code));
989                            }
990                        }
991                        "replace" => {
992                            if args_code.len() == 2 {
993                                return Ok(format!("{}.replace({}, {})", value_code, args_code[0], args_code[1]));
994                            }
995                        }
996                        "startswith" => {
997                            if args_code.len() == 1 {
998                                return Ok(format!("{}.starts_with({})", value_code, args_code[0]));
999                            }
1000                        }
1001                        "endswith" => {
1002                            if args_code.len() == 1 {
1003                                return Ok(format!("{}.ends_with({})", value_code, args_code[0]));
1004                            }
1005                        }
1006                        "find" => {
1007                            if args_code.len() == 1 {
1008                                return Ok(format!("{}.find({}).unwrap_or(-1_isize) as i32", value_code, args_code[0]));
1009                            }
1010                        }
1011                        "count" => {
1012                            if args_code.len() == 1 {
1013                                return Ok(format!("{}.matches({}).count()", value_code, args_code[0]));
1014                            }
1015                        }
1016                        // List methods
1017                        "append" => {
1018                            if args_code.len() == 1 {
1019                                return Ok(format!("{}.push({})", value_code, args_code[0]));
1020                            }
1021                        }
1022                        "extend" => {
1023                            if args_code.len() == 1 {
1024                                return Ok(format!("{}.extend({})", value_code, args_code[0]));
1025                            }
1026                        }
1027                        "pop" => {
1028                            if args_code.is_empty() {
1029                                return Ok(format!("{}.pop().unwrap()", value_code));
1030                            } else {
1031                                return Ok(format!("{}.remove({} as usize)", value_code, args_code[0]));
1032                            }
1033                        }
1034                        "remove" => {
1035                            if args_code.len() == 1 {
1036                                return Ok(format!("{{ if let Some(pos) = {}.iter().position(|x| x == &{}) {{ {}.remove(pos); }} }}",
1037                                    value_code, args_code[0], value_code));
1038                            }
1039                        }
1040                        "clear" => return Ok(format!("{}.clear()", value_code)),
1041                        "reverse" => return Ok(format!("{}.reverse()", value_code)),
1042                        "sort" => return Ok(format!("{}.sort()", value_code)),
1043                        _ => {
1044                            // Default method call
1045                            return Ok(format!("{}.{}({})", value_code, attr, args_code.join(", ")));
1046                        }
1047                    }
1048                }
1049
1050                // Check if it's a built-in function that needs special translation
1051                if let PyExpr::Name(func_name) = func.as_ref() {
1052                    let args_code: Vec<String> = args
1053                        .iter()
1054                        .map(|arg| self.translate_expr(arg))
1055                        .collect::<Result<Vec<_>>>()?;
1056
1057                    match func_name.as_str() {
1058                        // Built-in functions with special translation
1059                        "len" => {
1060                            if args_code.len() == 1 {
1061                                return Ok(format!("{}.len()", args_code[0]));
1062                            }
1063                        }
1064                        "max" => {
1065                            if args_code.len() == 1 {
1066                                // max(list) -> *list.iter().max().unwrap()
1067                                return Ok(format!("*{}.iter().max().unwrap()", args_code[0]));
1068                            } else if args_code.len() > 1 {
1069                                // max(a, b, c) -> *[a, b, c].iter().max().unwrap()
1070                                return Ok(format!("*[{}].iter().max().unwrap()", args_code.join(", ")));
1071                            }
1072                        }
1073                        "min" => {
1074                            if args_code.len() == 1 {
1075                                return Ok(format!("*{}.iter().min().unwrap()", args_code[0]));
1076                            } else if args_code.len() > 1 {
1077                                return Ok(format!("*[{}].iter().min().unwrap()", args_code.join(", ")));
1078                            }
1079                        }
1080                        "sum" => {
1081                            if args_code.len() == 1 {
1082                                return Ok(format!("{}.iter().sum::<i32>()", args_code[0]));
1083                            }
1084                        }
1085                        "abs" => {
1086                            if args_code.len() == 1 {
1087                                return Ok(format!("{}.abs()", args_code[0]));
1088                            }
1089                        }
1090                        "sorted" => {
1091                            if args_code.len() == 1 {
1092                                return Ok(format!("{{ let mut v = {}.clone(); v.sort(); v }}", args_code[0]));
1093                            }
1094                        }
1095                        "reversed" => {
1096                            if args_code.len() == 1 {
1097                                return Ok(format!("{{ let mut v = {}.clone(); v.reverse(); v }}", args_code[0]));
1098                            }
1099                        }
1100                        "print" => {
1101                            return Ok(format!("println!(\"{{:?}}\", {})", args_code.join(", ")));
1102                        }
1103                        "range" => {
1104                            // Translate range() to Rust range syntax
1105                            // Note: Do NOT add parentheses - they'll be added by caller if needed
1106                            if args_code.len() == 1 {
1107                                return Ok(format!("0..{}", args_code[0]));
1108                            } else if args_code.len() == 2 {
1109                                return Ok(format!("{}..{}", args_code[0], args_code[1]));
1110                            } else if args_code.len() == 3 {
1111                                // range(start, stop, step) - step requires wrapping
1112                                return Ok(format!("({}..{}).step_by({} as usize)", args_code[0], args_code[1], args_code[2]));
1113                            }
1114                        }
1115                        "enumerate" => {
1116                            if args_code.len() == 1 {
1117                                return Ok(format!("{}.iter().enumerate()", args_code[0]));
1118                            }
1119                        }
1120                        "zip" => {
1121                            if args_code.len() == 2 {
1122                                return Ok(format!("{}.iter().zip({}.iter())", args_code[0], args_code[1]));
1123                            } else if args_code.len() > 2 {
1124                                // For multiple iterables, chain zip calls
1125                                let mut result = format!("{}.iter().zip({}.iter())", args_code[0], args_code[1]);
1126                                for arg in &args_code[2..] {
1127                                    result = format!("{}.zip({}.iter())", result, arg);
1128                                }
1129                                return Ok(result);
1130                            }
1131                        }
1132                        "any" => {
1133                            if args_code.len() == 1 {
1134                                return Ok(format!("{}.iter().any(|x| *x)", args_code[0]));
1135                            }
1136                        }
1137                        "all" => {
1138                            if args_code.len() == 1 {
1139                                return Ok(format!("{}.iter().all(|x| *x)", args_code[0]));
1140                            }
1141                        }
1142                        "isinstance" => {
1143                            // isinstance is complex, just generate a comment for now
1144                            return Ok(format!("/* isinstance({}, {}) */true", args_code.join(", "), ""));
1145                        }
1146                        "type" => {
1147                            if args_code.len() == 1 {
1148                                return Ok(format!("/* type({}) */", args_code[0]));
1149                            }
1150                        }
1151                        "list" => {
1152                            // list() constructor - convert iterator to Vec
1153                            if args_code.len() == 1 {
1154                                // Check if it's already an iterator expression
1155                                if args_code[0].contains(".iter()") || args_code[0].contains("..") {
1156                                    return Ok(format!("{}.collect::<Vec<_>>()", args_code[0]));
1157                                } else {
1158                                    return Ok(format!("{}.iter().collect::<Vec<_>>()", args_code[0]));
1159                                }
1160                            } else if args_code.is_empty() {
1161                                return Ok("Vec::new()".to_string());
1162                            }
1163                        }
1164                        "dict" => {
1165                            if args_code.is_empty() {
1166                                return Ok("HashMap::new()".to_string());
1167                            }
1168                        }
1169                        "str" => {
1170                            if args_code.len() == 1 {
1171                                return Ok(format!("{}.to_string()", args_code[0]));
1172                            }
1173                        }
1174                        "int" => {
1175                            if args_code.len() == 1 {
1176                                return Ok(format!("({} as i32)", args_code[0]));
1177                            }
1178                        }
1179                        "float" => {
1180                            if args_code.len() == 1 {
1181                                return Ok(format!("({} as f64)", args_code[0]));
1182                            }
1183                        }
1184                        "bool" => {
1185                            if args_code.len() == 1 {
1186                                return Ok(format!("({} as bool)", args_code[0]));
1187                            }
1188                        }
1189                        _ => {
1190                            // Default: translate as regular function call
1191                            return Ok(format!("{}({})", func_name, args_code.join(", ")));
1192                        }
1193                    }
1194                }
1195
1196                // Fallback for non-Name function expressions
1197                let func_code = self.translate_expr(func)?;
1198                let args_code: Vec<String> = args
1199                    .iter()
1200                    .map(|arg| self.translate_expr(arg))
1201                    .collect::<Result<Vec<_>>>()?;
1202                Ok(format!("{}({})", func_code, args_code.join(", ")))
1203            }
1204
1205            PyExpr::List(elements) => {
1206                let elements_code: Vec<String> = elements
1207                    .iter()
1208                    .map(|e| self.translate_expr(e))
1209                    .collect::<Result<Vec<_>>>()?;
1210                Ok(format!("vec![{}]", elements_code.join(", ")))
1211            }
1212
1213            PyExpr::Tuple(elements) => {
1214                let elements_code: Vec<String> = elements
1215                    .iter()
1216                    .map(|e| self.translate_expr(e))
1217                    .collect::<Result<Vec<_>>>()?;
1218                Ok(format!("({})", elements_code.join(", ")))
1219            }
1220
1221            PyExpr::Compare { left, op, right } => {
1222                let left_code = self.translate_expr(left)?;
1223                let right_code = self.translate_expr(right)?;
1224                let op_str = self.cmpop_to_rust(*op);
1225                Ok(format!("{} {} {}", left_code, op_str, right_code))
1226            }
1227
1228            PyExpr::Subscript { value, index } => {
1229                let value_code = self.translate_expr(value)?;
1230                let index_code = self.translate_expr(index)?;
1231                Ok(format!("{}[{}]", value_code, index_code))
1232            }
1233
1234            PyExpr::Slice { value, lower, upper, step } => {
1235                let value_code = self.translate_expr(value)?;
1236
1237                // Translate Python slices to Rust slice syntax
1238                // Python: list[1:3] -> Rust: &list[1..3]
1239                // Python: list[:5] -> Rust: &list[..5]
1240                // Python: list[2:] -> Rust: &list[2..]
1241                // Python: list[::2] -> Rust: list.iter().step_by(2).copied().collect::<Vec<_>>()
1242                // Python: list[1:10:2] -> more complex
1243
1244                if step.is_some() {
1245                    // Slicing with step requires iterator approach
1246                    let step_code = self.translate_expr(step.as_ref().unwrap())?;
1247
1248                    let range_str = if lower.is_some() && upper.is_some() {
1249                        let lower_code = self.translate_expr(lower.as_ref().unwrap())?;
1250                        let upper_code = self.translate_expr(upper.as_ref().unwrap())?;
1251                        format!("{}..{}", lower_code, upper_code)
1252                    } else if lower.is_some() {
1253                        let lower_code = self.translate_expr(lower.as_ref().unwrap())?;
1254                        format!("{}..", lower_code)
1255                    } else if upper.is_some() {
1256                        let upper_code = self.translate_expr(upper.as_ref().unwrap())?;
1257                        format!("..{}", upper_code)
1258                    } else {
1259                        "..".to_string()
1260                    };
1261
1262                    Ok(format!(
1263                        "{}[{}].iter().step_by({} as usize).copied().collect::<Vec<_>>()",
1264                        value_code, range_str, step_code
1265                    ))
1266                } else {
1267                    // Simple slice without step
1268                    let slice_str = if lower.is_some() && upper.is_some() {
1269                        let lower_code = self.translate_expr(lower.as_ref().unwrap())?;
1270                        let upper_code = self.translate_expr(upper.as_ref().unwrap())?;
1271                        format!("{}..{}", lower_code, upper_code)
1272                    } else if lower.is_some() {
1273                        let lower_code = self.translate_expr(lower.as_ref().unwrap())?;
1274                        format!("{}..", lower_code)
1275                    } else if upper.is_some() {
1276                        let upper_code = self.translate_expr(upper.as_ref().unwrap())?;
1277                        format!("..{}", upper_code)
1278                    } else {
1279                        "..".to_string()
1280                    };
1281
1282                    Ok(format!("&{}[{}]", value_code, slice_str))
1283                }
1284            }
1285
1286            PyExpr::Attribute { value, attr } => {
1287                // Try to extract module path (handles nested attributes like os.path.exists)
1288                if let Some((module_path, final_attr)) = self.extract_module_path(&PyExpr::Attribute {
1289                    value: value.clone(),
1290                    attr: attr.clone()
1291                }) {
1292                    // Check if this module path was imported (either "os" or "os.path")
1293                    let parts: Vec<&str> = module_path.split('.').collect();
1294                    let base_module = parts[0];
1295
1296                    if self.imported_modules.contains(&module_path) || self.imported_modules.contains(&base_module.to_string()) {
1297                        // Try to translate using stdlib mapper with full path
1298                        if let Some(rust_equiv) = self.stdlib_mapper.get_function(&module_path, &final_attr) {
1299                            // For constants like math.pi, return the full path
1300                            if rust_equiv.contains("::") {
1301                                return Ok(rust_equiv.clone());
1302                            }
1303                        }
1304
1305                        // Check for module-level constants
1306                        if let Some(_mapping) = self.stdlib_mapper.get_module(&module_path) {
1307                            // Special cases for constants
1308                            if module_path == "math" && final_attr == "pi" {
1309                                return Ok("std::f64::consts::PI".to_string());
1310                            }
1311                            if module_path == "math" && final_attr == "e" {
1312                                return Ok("std::f64::consts::E".to_string());
1313                            }
1314                        }
1315                    }
1316                }
1317
1318                // Default attribute access
1319                let value_code = self.translate_expr(value)?;
1320                Ok(format!("{}.{}", value_code, attr))
1321            }
1322
1323            PyExpr::Dict { keys, values } => {
1324                if keys.is_empty() {
1325                    return Ok("HashMap::new()".to_string());
1326                }
1327
1328                let mut pairs = vec![];
1329                for (key, value) in keys.iter().zip(values.iter()) {
1330                    let key_code = self.translate_expr(key)?;
1331                    let value_code = self.translate_expr(value)?;
1332                    pairs.push(format!("({}, {})", key_code, value_code));
1333                }
1334
1335                Ok(format!(
1336                    "HashMap::from([{}])",
1337                    pairs.join(", ")
1338                ))
1339            }
1340
1341            PyExpr::ListComp { element, generators } => {
1342                // Translate to iterator chain: iter.map(...).filter(...).collect()
1343                if generators.is_empty() {
1344                    return Err(Error::CodeGeneration("List comprehension with no generators".to_string()));
1345                }
1346
1347                let comp = &generators[0];
1348                let iter_code = self.translate_expr(&comp.iter)?;
1349                let element_code = self.translate_expr(element)?;
1350
1351                // Convert range() to Rust range
1352                let rust_iter = if iter_code.starts_with("range(") {
1353                    let args = &iter_code[6..iter_code.len() - 1];
1354                    if args.contains(',') {
1355                        let parts: Vec<&str> = args.split(',').collect();
1356                        format!("({}..{})", parts[0].trim(), parts[1].trim())
1357                    } else {
1358                        format!("(0..{})", args)
1359                    }
1360                } else {
1361                    iter_code
1362                };
1363
1364                // Build the iterator chain
1365                let target_var = self.translate_expr(&comp.target)?;
1366                let mut code = format!("{}.map(|{}| {})", rust_iter, target_var, element_code);
1367
1368                // Add filter if there are conditions
1369                if !comp.ifs.is_empty() {
1370                    for condition in &comp.ifs {
1371                        let condition_code = self.translate_expr(condition)?;
1372                        code = format!("{}.filter(|{}| {})", code, target_var, condition_code);
1373                    }
1374                }
1375
1376                // Collect into Vec
1377                code = format!("{}.collect::<Vec<_>>()", code);
1378
1379                Ok(code)
1380            }
1381
1382            PyExpr::Lambda { args, body } => {
1383                // Translate Python lambda to Rust closure
1384                // Python: lambda x: x + 1 -> Rust: |x| x + 1
1385                // Python: lambda x, y: x + y -> Rust: |x, y| x + y
1386
1387                let args_str = args.join(", ");
1388                let body_code = self.translate_expr(body)?;
1389
1390                Ok(format!("|{}| {}", args_str, body_code))
1391            }
1392
1393            _ => Err(Error::CodeGeneration(format!(
1394                "Expression type not yet implemented: {:?}",
1395                expr
1396            ))),
1397        }
1398    }
1399
1400    /// Convert Python comparison operator to Rust
1401    fn cmpop_to_rust(&self, op: CmpOp) -> &str {
1402        match op {
1403            CmpOp::Eq => "==",
1404            CmpOp::NotEq => "!=",
1405            CmpOp::Lt => "<",
1406            CmpOp::LtE => "<=",
1407            CmpOp::Gt => ">",
1408            CmpOp::GtE => ">=",
1409            CmpOp::Is => "==", // Simplified
1410            CmpOp::IsNot => "!=", // Simplified
1411            CmpOp::In => "contains", // Needs special handling
1412            CmpOp::NotIn => "!contains", // Needs special handling
1413        }
1414    }
1415
1416    /// Translate Python literal to Rust
1417    fn translate_literal(&self, lit: &PyLiteral) -> Result<String> {
1418        match lit {
1419            PyLiteral::Int(n) => Ok(n.to_string()),
1420            PyLiteral::Float(f) => Ok(f.to_string()),
1421            PyLiteral::String(s) => Ok(format!("\"{}\"", s)),
1422            PyLiteral::Bool(b) => Ok(b.to_string()),
1423            PyLiteral::None => Ok("None".to_string()), // Will need Option handling
1424            PyLiteral::Bytes(_) => Ok("vec![]".to_string()), // Simplified
1425        }
1426    }
1427
1428    /// Convert Python binary operator to Rust
1429    fn binop_to_rust(&self, op: BinOp) -> &str {
1430        match op {
1431            BinOp::Add => "+",
1432            BinOp::Sub => "-",
1433            BinOp::Mult => "*",
1434            BinOp::Div => "/",
1435            BinOp::FloorDiv => "/", // Need to add integer division handling
1436            BinOp::Mod => "%",
1437            BinOp::Pow => "pow", // Need function call
1438            BinOp::LShift => "<<",
1439            BinOp::RShift => ">>",
1440            BinOp::BitOr => "|",
1441            BinOp::BitXor => "^",
1442            BinOp::BitAnd => "&",
1443            BinOp::MatMult => "*", // Simplified
1444        }
1445    }
1446
1447    /// Convert Python unary operator to Rust
1448    fn unaryop_to_rust(&self, op: UnaryOp) -> &str {
1449        match op {
1450            UnaryOp::Invert => "!",
1451            UnaryOp::Not => "!",
1452            UnaryOp::UAdd => "+",
1453            UnaryOp::USub => "-",
1454        }
1455    }
1456
1457    /// Convert TypeAnnotation to Rust type
1458    fn type_annotation_to_rust(&self, annotation: &TypeAnnotation) -> RustType {
1459        match annotation {
1460            TypeAnnotation::Name(name) => self.python_type_to_rust(name),
1461            TypeAnnotation::Generic { base, args } => {
1462                // Handle generic types like List[int], Dict[str, int]
1463                let base_type = if let TypeAnnotation::Name(name) = base.as_ref() {
1464                    name.as_str()
1465                } else {
1466                    return RustType::Unknown;
1467                };
1468
1469                match base_type {
1470                    "List" | "list" => {
1471                        if let Some(inner) = args.first() {
1472                            let inner_type = self.type_annotation_to_rust(inner);
1473                            RustType::Vec(Box::new(inner_type))
1474                        } else {
1475                            RustType::Vec(Box::new(RustType::Unknown))
1476                        }
1477                    }
1478                    "Optional" | "Option" => {
1479                        if let Some(inner) = args.first() {
1480                            let inner_type = self.type_annotation_to_rust(inner);
1481                            RustType::Option(Box::new(inner_type))
1482                        } else {
1483                            RustType::Option(Box::new(RustType::Unknown))
1484                        }
1485                    }
1486                    _ => RustType::Unknown,
1487                }
1488            }
1489        }
1490    }
1491
1492    /// Convert Python type hint string to Rust type
1493    fn python_type_to_rust(&self, hint: &str) -> RustType {
1494        match hint {
1495            "int" => RustType::I32,
1496            "float" => RustType::F64,
1497            "str" => RustType::String,
1498            "bool" => RustType::Bool,
1499            _ => RustType::Unknown,
1500        }
1501    }
1502
1503    /// Translate Python decorator to Rust attribute
1504    fn translate_decorator(&self, decorator: &PyExpr) -> String {
1505        // Extract decorator name from expression
1506        let decorator_name = match decorator {
1507            PyExpr::Name(name) => name.as_str(),
1508            PyExpr::Call { func, .. } => {
1509                // For decorator calls like @lru_cache(maxsize=128)
1510                if let PyExpr::Name(name) = func.as_ref() {
1511                    name.as_str()
1512                } else {
1513                    return String::new();
1514                }
1515            }
1516            _ => return String::new(),
1517        };
1518
1519        match decorator_name {
1520            // Common Python decorators -> Rust attributes
1521            "staticmethod" => "#[allow(non_snake_case)]".to_string(),
1522            "classmethod" => "#[allow(non_snake_case)]".to_string(),
1523            "property" => "#[inline]".to_string(),
1524            "abstractmethod" => "".to_string(), // No direct equivalent
1525            "dataclass" => "#[derive(Debug, Clone)]".to_string(),
1526            "lru_cache" | "cache" => "// TODO: Add caching".to_string(),
1527            "override" => "#[inline]".to_string(),
1528            "deprecated" => "#[deprecated]".to_string(),
1529            "async" | "asyncio.coroutine" => "#[tokio::main]".to_string(),
1530            "pytest.fixture" => "#[test]".to_string(),
1531            "unittest.mock.patch" => "// Mock decorator".to_string(),
1532            _ => {
1533                // For unknown decorators, add as comment
1534                format!("// @{}", decorator_name)
1535            }
1536        }
1537    }
1538}
1539
1540impl Default for PythonToRustTranslator {
1541    fn default() -> Self {
1542        Self::new()
1543    }
1544}
1545
1546#[cfg(test)]
1547mod tests {
1548    use super::*;
1549
1550    #[test]
1551    fn test_translate_simple_assignment() {
1552        let mut translator = PythonToRustTranslator::new();
1553
1554        let module = PyModule {
1555            statements: vec![PyStmt::Assign {
1556                target: PyExpr::Name("x".to_string()),
1557                value: PyExpr::Literal(PyLiteral::Int(42)),
1558            }],
1559        };
1560
1561        let result = translator.translate_module(&module).unwrap();
1562        assert!(result.contains("let x: i32 = 42;"));
1563    }
1564
1565    #[test]
1566    fn test_translate_function() {
1567        let mut translator = PythonToRustTranslator::new();
1568
1569        let module = PyModule {
1570            statements: vec![PyStmt::FunctionDef {
1571                name: "add".to_string(),
1572                params: vec![
1573                    FunctionParam {
1574                        name: "a".to_string(),
1575                        type_annotation: Some(TypeAnnotation::Name("int".to_string())),
1576                        default_value: None,
1577                    },
1578                    FunctionParam {
1579                        name: "b".to_string(),
1580                        type_annotation: Some(TypeAnnotation::Name("int".to_string())),
1581                        default_value: None,
1582                    },
1583                ],
1584                body: vec![PyStmt::Return {
1585                    value: Some(PyExpr::BinOp {
1586                        left: Box::new(PyExpr::Name("a".to_string())),
1587                        op: BinOp::Add,
1588                        right: Box::new(PyExpr::Name("b".to_string())),
1589                    })
1590                }],
1591                return_type: Some(TypeAnnotation::Name("int".to_string())),
1592                decorators: vec![],
1593                is_async: false,
1594            }],
1595        };
1596
1597        let result = translator.translate_module(&module).unwrap();
1598        assert!(result.contains("pub fn add(a: i32, b: i32) -> i32"));
1599        assert!(result.contains("return a + b;"));
1600    }
1601
1602    #[test]
1603    fn test_type_inference_int() {
1604        let inference = TypeInference::new();
1605        let lit = PyLiteral::Int(42);
1606        assert_eq!(inference.infer_from_literal(&lit), RustType::I32);
1607    }
1608
1609    #[test]
1610    fn test_type_inference_float() {
1611        let inference = TypeInference::new();
1612        let lit = PyLiteral::Float(3.14);
1613        assert_eq!(inference.infer_from_literal(&lit), RustType::F64);
1614    }
1615
1616    #[test]
1617    fn test_type_inference_string() {
1618        let inference = TypeInference::new();
1619        let lit = PyLiteral::String("hello".to_string());
1620        assert_eq!(inference.infer_from_literal(&lit), RustType::String);
1621    }
1622}