Skip to main content

oxilean_codegen/python_backend/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::lcnf::*;
6
7use super::types::{
8    FStringPart, MatchArm, PythonBackend, PythonClass, PythonClassVar, PythonExpr, PythonFunction,
9    PythonLit, PythonModule, PythonParam, PythonStmt, PythonType,
10};
11
12pub type FromImports = Vec<(String, Vec<(String, Option<String>)>)>;
13pub(super) fn indent_str(level: usize) -> String {
14    "    ".repeat(level)
15}
16pub(super) fn format_from_import(module: &str, names: &[(String, Option<String>)]) -> String {
17    if names.len() == 1 && names[0].0 == "*" {
18        return format!("from {} import *", module);
19    }
20    let names_str: Vec<String> = names
21        .iter()
22        .map(|(n, a)| match a {
23            Some(alias) => format!("{} as {}", n, alias),
24            None => n.clone(),
25        })
26        .collect();
27    if names_str.len() > 4 {
28        let joined = names_str.join(",\n    ");
29        format!("from {} import (\n    {}\n)", module, joined)
30    } else {
31        format!("from {} import {}", module, names_str.join(", "))
32    }
33}
34pub(super) fn emit_docstring(doc: &str, indent: usize) -> String {
35    let pad = indent_str(indent);
36    format!("{}\"\"\"{}\"\"\"", pad, doc)
37}
38pub(super) fn emit_function(func: &PythonFunction, indent: usize) -> String {
39    let pad = indent_str(indent);
40    let mut out = String::new();
41    for dec in &func.decorators {
42        out.push_str(&format!("{}@{}\n", pad, dec));
43    }
44    if func.is_classmethod && !func.decorators.contains(&"classmethod".to_string()) {
45        out.push_str(&format!("{}@classmethod\n", pad));
46    }
47    if func.is_staticmethod && !func.decorators.contains(&"staticmethod".to_string()) {
48        out.push_str(&format!("{}@staticmethod\n", pad));
49    }
50    if func.is_async {
51        out.push_str(&format!("{}async def {}(", pad, func.name));
52    } else {
53        out.push_str(&format!("{}def {}(", pad, func.name));
54    }
55    let params_str: Vec<String> = func.params.iter().map(|p| p.to_string()).collect();
56    out.push_str(&params_str.join(", "));
57    out.push(')');
58    if let Some(ret) = &func.return_type {
59        out.push_str(&format!(" -> {}", ret));
60    }
61    out.push_str(":\n");
62    if func.body.is_empty() {
63        out.push_str(&format!("{}    pass\n", pad));
64    } else {
65        for stmt in &func.body {
66            out.push_str(&emit_stmt(stmt, indent + 1));
67            out.push('\n');
68        }
69    }
70    out
71}
72pub(super) fn emit_class(cls: &PythonClass, indent: usize) -> String {
73    let pad = indent_str(indent);
74    let mut out = String::new();
75    if cls.is_dataclass && !cls.decorators.contains(&"dataclass".to_string()) {
76        out.push_str(&format!("{}@dataclass\n", pad));
77    }
78    for dec in &cls.decorators {
79        out.push_str(&format!("{}@{}\n", pad, dec));
80    }
81    out.push_str(&format!("{}class {}", pad, cls.name));
82    let mut bases = cls.bases.clone();
83    if cls.is_abstract && !bases.contains(&"ABC".to_string()) {
84        bases.push("ABC".to_string());
85    }
86    if !bases.is_empty() {
87        out.push_str(&format!("({})", bases.join(", ")));
88    }
89    out.push_str(":\n");
90    if let Some(doc) = &cls.docstring {
91        out.push_str(&emit_docstring(doc, indent + 1));
92        out.push('\n');
93    }
94    let mut body_empty = true;
95    for cv in &cls.class_vars {
96        body_empty = false;
97        let inner_pad = indent_str(indent + 1);
98        match &cv.default {
99            Some(default) => {
100                out.push_str(&format!(
101                    "{}{}: {} = {}\n",
102                    inner_pad, cv.name, cv.annotation, default
103                ));
104            }
105            None => {
106                out.push_str(&format!("{}{}: {}\n", inner_pad, cv.name, cv.annotation));
107            }
108        }
109    }
110    for method in &cls.methods {
111        body_empty = false;
112        out.push('\n');
113        out.push_str(&emit_function(method, indent + 1));
114    }
115    if body_empty {
116        out.push_str(&format!("{}    pass\n", pad));
117    }
118    out
119}
120pub(super) fn emit_match_arm(arm: &MatchArm, indent: usize) -> String {
121    let pad = indent_str(indent);
122    let mut out = String::new();
123    match &arm.guard {
124        Some(guard) => out.push_str(&format!("{}case {} if {}:\n", pad, arm.pattern, guard)),
125        None => out.push_str(&format!("{}case {}:\n", pad, arm.pattern)),
126    }
127    if arm.body.is_empty() {
128        out.push_str(&format!("{}    pass\n", pad));
129    } else {
130        for stmt in &arm.body {
131            out.push_str(&emit_stmt(stmt, indent + 1));
132            out.push('\n');
133        }
134    }
135    out
136}
137pub(super) fn emit_stmt(stmt: &PythonStmt, indent: usize) -> String {
138    let pad = indent_str(indent);
139    match stmt {
140        PythonStmt::Expr(e) => format!("{}{}", pad, e),
141        PythonStmt::Assign(targets, value) => {
142            let tgts: Vec<String> = targets.iter().map(|t| format!("{}", t)).collect();
143            format!("{}{} = {}", pad, tgts.join(" = "), value)
144        }
145        PythonStmt::AugAssign(target, op, value) => {
146            format!("{}{} {}= {}", pad, target, op, value)
147        }
148        PythonStmt::AnnAssign(name, ty, value) => match value {
149            Some(v) => format!("{}{}: {} = {}", pad, name, ty, v),
150            None => format!("{}{}: {}", pad, name, ty),
151        },
152        PythonStmt::If(cond, then_body, elif_branches, else_body) => {
153            let mut out = format!("{}if {}:\n", pad, cond);
154            if then_body.is_empty() {
155                out.push_str(&format!("{}    pass\n", pad));
156            } else {
157                for s in then_body {
158                    out.push_str(&emit_stmt(s, indent + 1));
159                    out.push('\n');
160                }
161            }
162            for (elif_cond, elif_body) in elif_branches {
163                out.push_str(&format!("{}elif {}:\n", pad, elif_cond));
164                if elif_body.is_empty() {
165                    out.push_str(&format!("{}    pass\n", pad));
166                } else {
167                    for s in elif_body {
168                        out.push_str(&emit_stmt(s, indent + 1));
169                        out.push('\n');
170                    }
171                }
172            }
173            if !else_body.is_empty() {
174                out.push_str(&format!("{}else:\n", pad));
175                for s in else_body {
176                    out.push_str(&emit_stmt(s, indent + 1));
177                    out.push('\n');
178                }
179            }
180            if out.ends_with('\n') {
181                out.pop();
182            }
183            out
184        }
185        PythonStmt::For(var, iter, body, else_body) => {
186            let mut out = format!("{}for {} in {}:\n", pad, var, iter);
187            if body.is_empty() {
188                out.push_str(&format!("{}    pass\n", pad));
189            } else {
190                for s in body {
191                    out.push_str(&emit_stmt(s, indent + 1));
192                    out.push('\n');
193                }
194            }
195            if !else_body.is_empty() {
196                out.push_str(&format!("{}else:\n", pad));
197                for s in else_body {
198                    out.push_str(&emit_stmt(s, indent + 1));
199                    out.push('\n');
200                }
201            }
202            if out.ends_with('\n') {
203                out.pop();
204            }
205            out
206        }
207        PythonStmt::While(cond, body, else_body) => {
208            let mut out = format!("{}while {}:\n", pad, cond);
209            if body.is_empty() {
210                out.push_str(&format!("{}    pass\n", pad));
211            } else {
212                for s in body {
213                    out.push_str(&emit_stmt(s, indent + 1));
214                    out.push('\n');
215                }
216            }
217            if !else_body.is_empty() {
218                out.push_str(&format!("{}else:\n", pad));
219                for s in else_body {
220                    out.push_str(&emit_stmt(s, indent + 1));
221                    out.push('\n');
222                }
223            }
224            if out.ends_with('\n') {
225                out.pop();
226            }
227            out
228        }
229        PythonStmt::With(items, body) => {
230            let items_str: Vec<String> = items
231                .iter()
232                .map(|(e, alias)| match alias {
233                    Some(a) => format!("{} as {}", e, a),
234                    None => format!("{}", e),
235                })
236                .collect();
237            let mut out = format!("{}with {}:\n", pad, items_str.join(", "));
238            if body.is_empty() {
239                out.push_str(&format!("{}    pass\n", pad));
240            } else {
241                for s in body {
242                    out.push_str(&emit_stmt(s, indent + 1));
243                    out.push('\n');
244                }
245            }
246            if out.ends_with('\n') {
247                out.pop();
248            }
249            out
250        }
251        PythonStmt::Try(try_body, except_clauses, else_body, finally_body) => {
252            let mut out = format!("{}try:\n", pad);
253            if try_body.is_empty() {
254                out.push_str(&format!("{}    pass\n", pad));
255            } else {
256                for s in try_body {
257                    out.push_str(&emit_stmt(s, indent + 1));
258                    out.push('\n');
259                }
260            }
261            for (exc_type, exc_name, exc_body) in except_clauses {
262                match (exc_type, exc_name) {
263                    (Some(t), Some(n)) => out.push_str(&format!("{}except {} as {}:\n", pad, t, n)),
264                    (Some(t), None) => out.push_str(&format!("{}except {}:\n", pad, t)),
265                    (None, _) => out.push_str(&format!("{}except:\n", pad)),
266                }
267                if exc_body.is_empty() {
268                    out.push_str(&format!("{}    pass\n", pad));
269                } else {
270                    for s in exc_body {
271                        out.push_str(&emit_stmt(s, indent + 1));
272                        out.push('\n');
273                    }
274                }
275            }
276            if !else_body.is_empty() {
277                out.push_str(&format!("{}else:\n", pad));
278                for s in else_body {
279                    out.push_str(&emit_stmt(s, indent + 1));
280                    out.push('\n');
281                }
282            }
283            if !finally_body.is_empty() {
284                out.push_str(&format!("{}finally:\n", pad));
285                for s in finally_body {
286                    out.push_str(&emit_stmt(s, indent + 1));
287                    out.push('\n');
288                }
289            }
290            if out.ends_with('\n') {
291                out.pop();
292            }
293            out
294        }
295        PythonStmt::Return(expr) => match expr {
296            Some(e) => format!("{}return {}", pad, e),
297            None => format!("{}return", pad),
298        },
299        PythonStmt::Raise(expr) => match expr {
300            Some(e) => format!("{}raise {}", pad, e),
301            None => format!("{}raise", pad),
302        },
303        PythonStmt::Del(targets) => {
304            let tgts: Vec<String> = targets.iter().map(|t| format!("{}", t)).collect();
305            format!("{}del {}", pad, tgts.join(", "))
306        }
307        PythonStmt::Pass => format!("{}pass", pad),
308        PythonStmt::Break => format!("{}break", pad),
309        PythonStmt::Continue => format!("{}continue", pad),
310        PythonStmt::Import(names) => {
311            let parts: Vec<String> = names
312                .iter()
313                .map(|(n, a)| match a {
314                    Some(alias) => format!("{} as {}", n, alias),
315                    None => n.clone(),
316                })
317                .collect();
318            format!("{}import {}", pad, parts.join(", "))
319        }
320        PythonStmt::From(module, names) => {
321            format!("{}{}", pad, format_from_import(module, names))
322        }
323        PythonStmt::ClassDef(cls) => {
324            let text = emit_class(cls, indent);
325            text.trim_end_matches('\n').to_string()
326        }
327        PythonStmt::FuncDef(func) => {
328            let text = emit_function(func, indent);
329            text.trim_end_matches('\n').to_string()
330        }
331        PythonStmt::AsyncFuncDef(func) => {
332            let mut f = func.clone();
333            f.is_async = true;
334            let text = emit_function(&f, indent);
335            text.trim_end_matches('\n').to_string()
336        }
337        PythonStmt::Docstring(doc) => emit_docstring(doc, indent),
338        PythonStmt::Assert(expr, msg) => match msg {
339            Some(m) => format!("{}assert {}, {}", pad, expr, m),
340            None => format!("{}assert {}", pad, expr),
341        },
342        PythonStmt::Global(names) => format!("{}global {}", pad, names.join(", ")),
343        PythonStmt::Nonlocal(names) => format!("{}nonlocal {}", pad, names.join(", ")),
344        PythonStmt::Match(subject, arms) => {
345            let mut out = format!("{}match {}:\n", pad, subject);
346            for arm in arms {
347                out.push_str(&emit_match_arm(arm, indent + 1));
348            }
349            if out.ends_with('\n') {
350                out.pop();
351            }
352            out
353        }
354        PythonStmt::Raw(text) => format!("{}{}", pad, text),
355    }
356}
357/// Python 3 reserved keywords that must not be used as plain identifiers.
358pub const PYTHON_KEYWORDS: &[&str] = &[
359    "False", "None", "True", "and", "as", "assert", "async", "await", "break", "class", "continue",
360    "def", "del", "elif", "else", "except", "finally", "for", "from", "global", "if", "import",
361    "in", "is", "lambda", "nonlocal", "not", "or", "pass", "raise", "return", "try", "while",
362    "with", "yield", "match", "case", "type",
363];
364#[cfg(test)]
365mod tests {
366    use super::*;
367    #[test]
368    pub(super) fn test_type_int() {
369        assert_eq!(PythonType::Int.to_string(), "int");
370    }
371    #[test]
372    pub(super) fn test_type_float() {
373        assert_eq!(PythonType::Float.to_string(), "float");
374    }
375    #[test]
376    pub(super) fn test_type_str() {
377        assert_eq!(PythonType::Str.to_string(), "str");
378    }
379    #[test]
380    pub(super) fn test_type_bool() {
381        assert_eq!(PythonType::Bool.to_string(), "bool");
382    }
383    #[test]
384    pub(super) fn test_type_none() {
385        assert_eq!(PythonType::None_.to_string(), "None");
386    }
387    #[test]
388    pub(super) fn test_type_list() {
389        let t = PythonType::List(Box::new(PythonType::Int));
390        assert_eq!(t.to_string(), "list[int]");
391    }
392    #[test]
393    pub(super) fn test_type_dict() {
394        let t = PythonType::Dict(Box::new(PythonType::Str), Box::new(PythonType::Int));
395        assert_eq!(t.to_string(), "dict[str, int]");
396    }
397    #[test]
398    pub(super) fn test_type_tuple() {
399        let t = PythonType::Tuple(vec![PythonType::Int, PythonType::Str, PythonType::Bool]);
400        assert_eq!(t.to_string(), "tuple[int, str, bool]");
401    }
402    #[test]
403    pub(super) fn test_type_optional() {
404        let t = PythonType::Optional(Box::new(PythonType::Int));
405        assert_eq!(t.to_string(), "int | None");
406    }
407    #[test]
408    pub(super) fn test_type_union() {
409        let t = PythonType::Union(vec![PythonType::Int, PythonType::Str]);
410        assert_eq!(t.to_string(), "int | str");
411    }
412    #[test]
413    pub(super) fn test_type_custom() {
414        let t = PythonType::Custom("MyClass".to_string());
415        assert_eq!(t.to_string(), "MyClass");
416    }
417    #[test]
418    pub(super) fn test_type_any() {
419        assert_eq!(PythonType::Any.to_string(), "Any");
420    }
421    #[test]
422    pub(super) fn test_lit_int() {
423        assert_eq!(PythonLit::Int(42).to_string(), "42");
424    }
425    #[test]
426    pub(super) fn test_lit_float() {
427        assert_eq!(PythonLit::Float(3.14).to_string(), "3.14");
428    }
429    #[test]
430    pub(super) fn test_lit_float_whole() {
431        assert_eq!(PythonLit::Float(2.0).to_string(), "2.0");
432    }
433    #[test]
434    pub(super) fn test_lit_str() {
435        assert_eq!(PythonLit::Str("hello".to_string()).to_string(), "\"hello\"");
436    }
437    #[test]
438    pub(super) fn test_lit_str_escapes() {
439        let s = PythonLit::Str("a\"b\\c\nd".to_string()).to_string();
440        assert!(s.contains("\\\""));
441        assert!(s.contains("\\\\"));
442        assert!(s.contains("\\n"));
443    }
444    #[test]
445    pub(super) fn test_lit_bool_true() {
446        assert_eq!(PythonLit::Bool(true).to_string(), "True");
447    }
448    #[test]
449    pub(super) fn test_lit_bool_false() {
450        assert_eq!(PythonLit::Bool(false).to_string(), "False");
451    }
452    #[test]
453    pub(super) fn test_lit_none() {
454        assert_eq!(PythonLit::None.to_string(), "None");
455    }
456    #[test]
457    pub(super) fn test_lit_ellipsis() {
458        assert_eq!(PythonLit::Ellipsis.to_string(), "...");
459    }
460    #[test]
461    pub(super) fn test_expr_var() {
462        assert_eq!(PythonExpr::Var("x".to_string()).to_string(), "x");
463    }
464    #[test]
465    pub(super) fn test_expr_binop() {
466        let e = PythonExpr::BinOp(
467            "+".to_string(),
468            Box::new(PythonExpr::Var("x".to_string())),
469            Box::new(PythonExpr::Lit(PythonLit::Int(1))),
470        );
471        assert_eq!(e.to_string(), "(x + 1)");
472    }
473    #[test]
474    pub(super) fn test_expr_unary_not() {
475        let e = PythonExpr::UnaryOp(
476            "not".to_string(),
477            Box::new(PythonExpr::Var("x".to_string())),
478        );
479        assert_eq!(e.to_string(), "not x");
480    }
481    #[test]
482    pub(super) fn test_expr_unary_neg() {
483        let e = PythonExpr::UnaryOp("-".to_string(), Box::new(PythonExpr::Var("x".to_string())));
484        assert_eq!(e.to_string(), "-x");
485    }
486    #[test]
487    pub(super) fn test_expr_call_no_args() {
488        let e = PythonExpr::Call(Box::new(PythonExpr::Var("foo".to_string())), vec![], vec![]);
489        assert_eq!(e.to_string(), "foo()");
490    }
491    #[test]
492    pub(super) fn test_expr_call_with_args() {
493        let e = PythonExpr::Call(
494            Box::new(PythonExpr::Var("foo".to_string())),
495            vec![
496                PythonExpr::Lit(PythonLit::Int(1)),
497                PythonExpr::Lit(PythonLit::Int(2)),
498            ],
499            vec![],
500        );
501        assert_eq!(e.to_string(), "foo(1, 2)");
502    }
503    #[test]
504    pub(super) fn test_expr_call_with_kwargs() {
505        let e = PythonExpr::Call(
506            Box::new(PythonExpr::Var("print".to_string())),
507            vec![PythonExpr::Lit(PythonLit::Str("hi".to_string()))],
508            vec![(
509                "end".to_string(),
510                PythonExpr::Lit(PythonLit::Str("".to_string())),
511            )],
512        );
513        let s = e.to_string();
514        assert!(s.contains("end=\"\""));
515    }
516    #[test]
517    pub(super) fn test_expr_attr() {
518        let e = PythonExpr::Attr(
519            Box::new(PythonExpr::Var("obj".to_string())),
520            "field".to_string(),
521        );
522        assert_eq!(e.to_string(), "obj.field");
523    }
524    #[test]
525    pub(super) fn test_expr_subscript() {
526        let e = PythonExpr::Subscript(
527            Box::new(PythonExpr::Var("lst".to_string())),
528            Box::new(PythonExpr::Lit(PythonLit::Int(0))),
529        );
530        assert_eq!(e.to_string(), "lst[0]");
531    }
532    #[test]
533    pub(super) fn test_expr_lambda() {
534        let e = PythonExpr::Lambda(
535            vec!["x".to_string(), "y".to_string()],
536            Box::new(PythonExpr::BinOp(
537                "+".to_string(),
538                Box::new(PythonExpr::Var("x".to_string())),
539                Box::new(PythonExpr::Var("y".to_string())),
540            )),
541        );
542        assert_eq!(e.to_string(), "lambda x, y: (x + y)");
543    }
544    #[test]
545    pub(super) fn test_expr_if_expr() {
546        let e = PythonExpr::IfExpr(
547            Box::new(PythonExpr::Lit(PythonLit::Int(1))),
548            Box::new(PythonExpr::Var("cond".to_string())),
549            Box::new(PythonExpr::Lit(PythonLit::Int(0))),
550        );
551        assert_eq!(e.to_string(), "1 if cond else 0");
552    }
553    #[test]
554    pub(super) fn test_expr_list_comp() {
555        let e = PythonExpr::ListComp(
556            Box::new(PythonExpr::BinOp(
557                "*".to_string(),
558                Box::new(PythonExpr::Var("x".to_string())),
559                Box::new(PythonExpr::Lit(PythonLit::Int(2))),
560            )),
561            "x".to_string(),
562            Box::new(PythonExpr::Var("lst".to_string())),
563            None,
564        );
565        assert_eq!(e.to_string(), "[(x * 2) for x in lst]");
566    }
567    #[test]
568    pub(super) fn test_expr_list_comp_with_filter() {
569        let e = PythonExpr::ListComp(
570            Box::new(PythonExpr::Var("x".to_string())),
571            "x".to_string(),
572            Box::new(PythonExpr::Var("lst".to_string())),
573            Some(Box::new(PythonExpr::BinOp(
574                ">".to_string(),
575                Box::new(PythonExpr::Var("x".to_string())),
576                Box::new(PythonExpr::Lit(PythonLit::Int(0))),
577            ))),
578        );
579        assert_eq!(e.to_string(), "[x for x in lst if (x > 0)]");
580    }
581    #[test]
582    pub(super) fn test_expr_dict_comp() {
583        let e = PythonExpr::DictComp(
584            Box::new(PythonExpr::Var("k".to_string())),
585            Box::new(PythonExpr::Var("v".to_string())),
586            "k".to_string(),
587            "v".to_string(),
588            Box::new(PythonExpr::Call(
589                Box::new(PythonExpr::Attr(
590                    Box::new(PythonExpr::Var("d".to_string())),
591                    "items".to_string(),
592                )),
593                vec![],
594                vec![],
595            )),
596        );
597        assert_eq!(e.to_string(), "{k: v for k, v in d.items()}");
598    }
599    #[test]
600    pub(super) fn test_expr_tuple_empty() {
601        let e = PythonExpr::Tuple(vec![]);
602        assert_eq!(e.to_string(), "()");
603    }
604    #[test]
605    pub(super) fn test_expr_tuple_single() {
606        let e = PythonExpr::Tuple(vec![PythonExpr::Lit(PythonLit::Int(1))]);
607        assert_eq!(e.to_string(), "(1,)");
608    }
609    #[test]
610    pub(super) fn test_expr_tuple_multi() {
611        let e = PythonExpr::Tuple(vec![
612            PythonExpr::Lit(PythonLit::Int(1)),
613            PythonExpr::Lit(PythonLit::Int(2)),
614        ]);
615        assert_eq!(e.to_string(), "(1, 2)");
616    }
617    #[test]
618    pub(super) fn test_expr_list() {
619        let e = PythonExpr::List(vec![
620            PythonExpr::Lit(PythonLit::Int(1)),
621            PythonExpr::Lit(PythonLit::Int(2)),
622            PythonExpr::Lit(PythonLit::Int(3)),
623        ]);
624        assert_eq!(e.to_string(), "[1, 2, 3]");
625    }
626    #[test]
627    pub(super) fn test_expr_dict() {
628        let e = PythonExpr::Dict(vec![(
629            PythonExpr::Lit(PythonLit::Str("key".to_string())),
630            PythonExpr::Lit(PythonLit::Int(42)),
631        )]);
632        assert_eq!(e.to_string(), "{\"key\": 42}");
633    }
634    #[test]
635    pub(super) fn test_expr_set_empty() {
636        let e = PythonExpr::Set(vec![]);
637        assert_eq!(e.to_string(), "set()");
638    }
639    #[test]
640    pub(super) fn test_expr_set_nonempty() {
641        let e = PythonExpr::Set(vec![
642            PythonExpr::Lit(PythonLit::Int(1)),
643            PythonExpr::Lit(PythonLit::Int(2)),
644        ]);
645        assert_eq!(e.to_string(), "{1, 2}");
646    }
647    #[test]
648    pub(super) fn test_expr_await() {
649        let e = PythonExpr::Await(Box::new(PythonExpr::Var("coro".to_string())));
650        assert_eq!(e.to_string(), "await coro");
651    }
652    #[test]
653    pub(super) fn test_expr_yield() {
654        let e = PythonExpr::Yield(Some(Box::new(PythonExpr::Lit(PythonLit::Int(42)))));
655        assert_eq!(e.to_string(), "yield 42");
656    }
657    #[test]
658    pub(super) fn test_expr_yield_none() {
659        let e = PythonExpr::Yield(None);
660        assert_eq!(e.to_string(), "yield");
661    }
662    #[test]
663    pub(super) fn test_expr_fstring() {
664        let e = PythonExpr::FString(vec![
665            FStringPart::Literal("hello ".to_string()),
666            FStringPart::Expr(PythonExpr::Var("name".to_string())),
667            FStringPart::Literal("!".to_string()),
668        ]);
669        assert_eq!(e.to_string(), "f\"hello {name}!\"");
670    }
671    #[test]
672    pub(super) fn test_expr_fstring_with_format() {
673        let e = PythonExpr::FString(vec![FStringPart::ExprWithFormat(
674            PythonExpr::Var("pi".to_string()),
675            ".2f".to_string(),
676        )]);
677        assert_eq!(e.to_string(), "f\"{pi:.2f}\"");
678    }
679    #[test]
680    pub(super) fn test_expr_walrus() {
681        let e = PythonExpr::Walrus(
682            "n".to_string(),
683            Box::new(PythonExpr::Call(
684                Box::new(PythonExpr::Var("len".to_string())),
685                vec![PythonExpr::Var("lst".to_string())],
686                vec![],
687            )),
688        );
689        assert_eq!(e.to_string(), "(n := len(lst))");
690    }
691    #[test]
692    pub(super) fn test_stmt_pass() {
693        assert_eq!(emit_stmt(&PythonStmt::Pass, 0), "pass");
694    }
695    #[test]
696    pub(super) fn test_stmt_return_none() {
697        assert_eq!(emit_stmt(&PythonStmt::Return(None), 0), "return");
698    }
699    #[test]
700    pub(super) fn test_stmt_return_expr() {
701        let s = PythonStmt::Return(Some(PythonExpr::Lit(PythonLit::Int(42))));
702        assert_eq!(emit_stmt(&s, 0), "return 42");
703    }
704    #[test]
705    pub(super) fn test_stmt_assign() {
706        let s = PythonStmt::Assign(
707            vec![PythonExpr::Var("x".to_string())],
708            PythonExpr::Lit(PythonLit::Int(5)),
709        );
710        assert_eq!(emit_stmt(&s, 0), "x = 5");
711    }
712    #[test]
713    pub(super) fn test_stmt_ann_assign() {
714        let s = PythonStmt::AnnAssign(
715            "x".to_string(),
716            PythonType::Int,
717            Some(PythonExpr::Lit(PythonLit::Int(0))),
718        );
719        assert_eq!(emit_stmt(&s, 0), "x: int = 0");
720    }
721    #[test]
722    pub(super) fn test_stmt_ann_assign_no_value() {
723        let s = PythonStmt::AnnAssign("y".to_string(), PythonType::Str, None);
724        assert_eq!(emit_stmt(&s, 0), "y: str");
725    }
726    #[test]
727    pub(super) fn test_stmt_aug_assign() {
728        let s = PythonStmt::AugAssign(
729            PythonExpr::Var("x".to_string()),
730            "+".to_string(),
731            PythonExpr::Lit(PythonLit::Int(1)),
732        );
733        assert_eq!(emit_stmt(&s, 0), "x += 1");
734    }
735    #[test]
736    pub(super) fn test_stmt_if_simple() {
737        let s = PythonStmt::If(
738            PythonExpr::Var("cond".to_string()),
739            vec![PythonStmt::Pass],
740            vec![],
741            vec![],
742        );
743        let out = emit_stmt(&s, 0);
744        assert!(out.contains("if cond:"));
745        assert!(out.contains("pass"));
746    }
747    #[test]
748    pub(super) fn test_stmt_if_else() {
749        let s = PythonStmt::If(
750            PythonExpr::Var("cond".to_string()),
751            vec![PythonStmt::Return(Some(PythonExpr::Lit(PythonLit::Int(1))))],
752            vec![],
753            vec![PythonStmt::Return(Some(PythonExpr::Lit(PythonLit::Int(0))))],
754        );
755        let out = emit_stmt(&s, 0);
756        assert!(out.contains("if cond:"));
757        assert!(out.contains("else:"));
758        assert!(out.contains("return 1"));
759        assert!(out.contains("return 0"));
760    }
761    #[test]
762    pub(super) fn test_stmt_for() {
763        let s = PythonStmt::For(
764            "x".to_string(),
765            PythonExpr::Var("items".to_string()),
766            vec![PythonStmt::Pass],
767            vec![],
768        );
769        let out = emit_stmt(&s, 0);
770        assert!(out.contains("for x in items:"));
771    }
772    #[test]
773    pub(super) fn test_stmt_while() {
774        let s = PythonStmt::While(
775            PythonExpr::Lit(PythonLit::Bool(true)),
776            vec![PythonStmt::Break],
777            vec![],
778        );
779        let out = emit_stmt(&s, 0);
780        assert!(out.contains("while True:"));
781        assert!(out.contains("break"));
782    }
783    #[test]
784    pub(super) fn test_stmt_with() {
785        let s = PythonStmt::With(
786            vec![(
787                PythonExpr::Call(
788                    Box::new(PythonExpr::Var("open".to_string())),
789                    vec![PythonExpr::Lit(PythonLit::Str("f.txt".to_string()))],
790                    vec![],
791                ),
792                Some("fh".to_string()),
793            )],
794            vec![PythonStmt::Pass],
795        );
796        let out = emit_stmt(&s, 0);
797        assert!(out.contains("with open(\"f.txt\") as fh:"));
798    }
799    #[test]
800    pub(super) fn test_stmt_try_except() {
801        let s = PythonStmt::Try(
802            vec![PythonStmt::Pass],
803            vec![(
804                Some(PythonExpr::Var("ValueError".to_string())),
805                Some("e".to_string()),
806                vec![PythonStmt::Pass],
807            )],
808            vec![],
809            vec![],
810        );
811        let out = emit_stmt(&s, 0);
812        assert!(out.contains("try:"));
813        assert!(out.contains("except ValueError as e:"));
814    }
815    #[test]
816    pub(super) fn test_stmt_raise() {
817        let s = PythonStmt::Raise(Some(PythonExpr::Call(
818            Box::new(PythonExpr::Var("ValueError".to_string())),
819            vec![PythonExpr::Lit(PythonLit::Str("bad".to_string()))],
820            vec![],
821        )));
822        let out = emit_stmt(&s, 0);
823        assert!(out.contains("raise ValueError(\"bad\")"));
824    }
825    #[test]
826    pub(super) fn test_stmt_import() {
827        let s = PythonStmt::Import(vec![("os".to_string(), None)]);
828        assert_eq!(emit_stmt(&s, 0), "import os");
829    }
830    #[test]
831    pub(super) fn test_stmt_import_alias() {
832        let s = PythonStmt::Import(vec![("numpy".to_string(), Some("np".to_string()))]);
833        assert_eq!(emit_stmt(&s, 0), "import numpy as np");
834    }
835    #[test]
836    pub(super) fn test_stmt_from_import() {
837        let s = PythonStmt::From(
838            "os.path".to_string(),
839            vec![("join".to_string(), None), ("exists".to_string(), None)],
840        );
841        let out = emit_stmt(&s, 0);
842        assert!(out.contains("from os.path import"));
843        assert!(out.contains("join"));
844        assert!(out.contains("exists"));
845    }
846    #[test]
847    pub(super) fn test_stmt_delete() {
848        let s = PythonStmt::Del(vec![PythonExpr::Var("x".to_string())]);
849        assert_eq!(emit_stmt(&s, 0), "del x");
850    }
851    #[test]
852    pub(super) fn test_stmt_assert() {
853        let s = PythonStmt::Assert(
854            PythonExpr::BinOp(
855                "==".to_string(),
856                Box::new(PythonExpr::Var("x".to_string())),
857                Box::new(PythonExpr::Lit(PythonLit::Int(1))),
858            ),
859            None,
860        );
861        let out = emit_stmt(&s, 0);
862        assert!(out.contains("assert (x == 1)"));
863    }
864    #[test]
865    pub(super) fn test_stmt_global() {
866        let s = PythonStmt::Global(vec!["x".to_string(), "y".to_string()]);
867        assert_eq!(emit_stmt(&s, 0), "global x, y");
868    }
869    #[test]
870    pub(super) fn test_stmt_nonlocal() {
871        let s = PythonStmt::Nonlocal(vec!["count".to_string()]);
872        assert_eq!(emit_stmt(&s, 0), "nonlocal count");
873    }
874    #[test]
875    pub(super) fn test_stmt_match() {
876        let s = PythonStmt::Match(
877            PythonExpr::Var("cmd".to_string()),
878            vec![
879                MatchArm {
880                    pattern: "\"quit\"".to_string(),
881                    guard: None,
882                    body: vec![PythonStmt::Return(None)],
883                },
884                MatchArm {
885                    pattern: "_".to_string(),
886                    guard: None,
887                    body: vec![PythonStmt::Pass],
888                },
889            ],
890        );
891        let out = emit_stmt(&s, 0);
892        assert!(out.contains("match cmd:"));
893        assert!(out.contains("case \"quit\":"));
894        assert!(out.contains("case _:"));
895    }
896    #[test]
897    pub(super) fn test_stmt_docstring() {
898        let s = PythonStmt::Docstring("This is a docstring.".to_string());
899        let out = emit_stmt(&s, 0);
900        assert!(out.contains("\"\"\"This is a docstring.\"\"\""));
901    }
902    #[test]
903    pub(super) fn test_function_simple() {
904        let mut func = PythonFunction::new("add");
905        func.params = vec![
906            PythonParam::typed("x", PythonType::Int),
907            PythonParam::typed("y", PythonType::Int),
908        ];
909        func.return_type = Some(PythonType::Int);
910        func.body = vec![PythonStmt::Return(Some(PythonExpr::BinOp(
911            "+".to_string(),
912            Box::new(PythonExpr::Var("x".to_string())),
913            Box::new(PythonExpr::Var("y".to_string())),
914        )))];
915        let out = emit_function(&func, 0);
916        assert!(out.contains("def add(x: int, y: int) -> int:"));
917        assert!(out.contains("return (x + y)"));
918    }
919    #[test]
920    pub(super) fn test_function_async() {
921        let mut func = PythonFunction::new("fetch");
922        func.params = vec![PythonParam::typed("url", PythonType::Str)];
923        func.return_type = Some(PythonType::Custom("bytes".to_string()));
924        func.is_async = true;
925        func.body = vec![PythonStmt::Return(Some(PythonExpr::Await(Box::new(
926            PythonExpr::Var("response".to_string()),
927        ))))];
928        let out = emit_function(&func, 0);
929        assert!(out.contains("async def fetch(url: str) -> bytes:"));
930        assert!(out.contains("return await response"));
931    }
932    #[test]
933    pub(super) fn test_function_with_decorator() {
934        let mut func = PythonFunction::new("value");
935        func.params = vec![PythonParam::typed(
936            "self",
937            PythonType::Custom("Self".to_string()),
938        )];
939        func.return_type = Some(PythonType::Int);
940        func.decorators = vec!["property".to_string()];
941        func.body = vec![PythonStmt::Return(Some(PythonExpr::Attr(
942            Box::new(PythonExpr::Var("self".to_string())),
943            "_value".to_string(),
944        )))];
945        let out = emit_function(&func, 0);
946        assert!(out.contains("@property"));
947        assert!(out.contains("def value(self: Self) -> int:"));
948    }
949    #[test]
950    pub(super) fn test_function_empty_body_pass() {
951        let func = PythonFunction::new("noop");
952        let out = emit_function(&func, 0);
953        assert!(out.contains("def noop():"));
954        assert!(out.contains("pass"));
955    }
956    #[test]
957    pub(super) fn test_class_simple() {
958        let cls = PythonClass::new("MyClass");
959        let out = emit_class(&cls, 0);
960        assert!(out.contains("class MyClass:"));
961        assert!(out.contains("pass"));
962    }
963    #[test]
964    pub(super) fn test_class_with_bases() {
965        let mut cls = PythonClass::new("MyError");
966        cls.bases = vec!["Exception".to_string()];
967        let out = emit_class(&cls, 0);
968        assert!(out.contains("class MyError(Exception):"));
969    }
970    #[test]
971    pub(super) fn test_class_dataclass() {
972        let mut cls = PythonClass::new("Point");
973        cls.is_dataclass = true;
974        cls.class_vars = vec![
975            PythonClassVar {
976                name: "x".to_string(),
977                annotation: PythonType::Float,
978                default: None,
979            },
980            PythonClassVar {
981                name: "y".to_string(),
982                annotation: PythonType::Float,
983                default: Some(PythonExpr::Lit(PythonLit::Float(0.0))),
984            },
985        ];
986        let out = emit_class(&cls, 0);
987        assert!(out.contains("@dataclass"));
988        assert!(out.contains("class Point:"));
989        assert!(out.contains("x: float"));
990        assert!(out.contains("y: float = 0.0"));
991    }
992    #[test]
993    pub(super) fn test_class_with_method() {
994        let mut cls = PythonClass::new("Counter");
995        let mut method = PythonFunction::new("increment");
996        method.params = vec![PythonParam::simple("self")];
997        method.return_type = Some(PythonType::None_);
998        method.body = vec![PythonStmt::AugAssign(
999            PythonExpr::Attr(
1000                Box::new(PythonExpr::Var("self".to_string())),
1001                "count".to_string(),
1002            ),
1003            "+".to_string(),
1004            PythonExpr::Lit(PythonLit::Int(1)),
1005        )];
1006        cls.methods.push(method);
1007        let out = emit_class(&cls, 0);
1008        assert!(out.contains("class Counter:"));
1009        assert!(out.contains("def increment(self) -> None:"));
1010    }
1011    #[test]
1012    pub(super) fn test_class_abstract() {
1013        let mut cls = PythonClass::new("Animal");
1014        cls.is_abstract = true;
1015        let out = emit_class(&cls, 0);
1016        assert!(out.contains("class Animal(ABC):"));
1017    }
1018    #[test]
1019    pub(super) fn test_module_empty() {
1020        let module = PythonModule::new();
1021        let out = module.emit();
1022        assert!(out.is_empty() || !out.contains("syntax error"));
1023    }
1024    #[test]
1025    pub(super) fn test_module_with_imports() {
1026        let mut module = PythonModule::new();
1027        module.add_import("os", None);
1028        module.add_import("sys", None);
1029        let out = module.emit();
1030        assert!(out.contains("import os"));
1031        assert!(out.contains("import sys"));
1032    }
1033    #[test]
1034    pub(super) fn test_module_with_from_imports() {
1035        let mut module = PythonModule::new();
1036        module.add_from_import("pathlib", vec![("Path".to_string(), None)]);
1037        let out = module.emit();
1038        assert!(out.contains("from pathlib import Path"));
1039    }
1040    #[test]
1041    pub(super) fn test_module_with_all_exports() {
1042        let mut module = PythonModule::new();
1043        module.all_exports = vec!["MyClass".to_string(), "my_func".to_string()];
1044        let out = module.emit();
1045        assert!(out.contains("__all__"));
1046        assert!(out.contains("\"MyClass\""));
1047        assert!(out.contains("\"my_func\""));
1048    }
1049    #[test]
1050    pub(super) fn test_module_with_docstring() {
1051        let mut module = PythonModule::new();
1052        module.module_docstring = Some("My module documentation.".to_string());
1053        let out = module.emit();
1054        assert!(out.contains("\"\"\"My module documentation.\"\"\""));
1055    }
1056    #[test]
1057    pub(super) fn test_mangle_dots() {
1058        let backend = PythonBackend::new();
1059        assert_eq!(backend.mangle_name("Nat.add"), "Nat_add");
1060    }
1061    #[test]
1062    pub(super) fn test_mangle_keyword() {
1063        let backend = PythonBackend::new();
1064        assert_eq!(backend.mangle_name("class"), "_class");
1065    }
1066    #[test]
1067    pub(super) fn test_mangle_digit_start() {
1068        let backend = PythonBackend::new();
1069        assert_eq!(backend.mangle_name("3d"), "_3d");
1070    }
1071    #[test]
1072    pub(super) fn test_mangle_prime() {
1073        let backend = PythonBackend::new();
1074        assert_eq!(backend.mangle_name("f'"), "f_");
1075    }
1076    #[test]
1077    pub(super) fn test_mangle_empty() {
1078        let backend = PythonBackend::new();
1079        assert_eq!(backend.mangle_name(""), "_anon");
1080    }
1081    #[test]
1082    pub(super) fn test_param_simple() {
1083        let p = PythonParam::simple("x");
1084        assert_eq!(p.to_string(), "x");
1085    }
1086    #[test]
1087    pub(super) fn test_param_typed() {
1088        let p = PythonParam::typed("count", PythonType::Int);
1089        assert_eq!(p.to_string(), "count: int");
1090    }
1091    #[test]
1092    pub(super) fn test_param_with_default() {
1093        let mut p = PythonParam::typed("n", PythonType::Int);
1094        p.default = Some(PythonExpr::Lit(PythonLit::Int(0)));
1095        assert_eq!(p.to_string(), "n: int = 0");
1096    }
1097    #[test]
1098    pub(super) fn test_param_vararg() {
1099        let mut p = PythonParam::simple("args");
1100        p.is_vararg = true;
1101        assert_eq!(p.to_string(), "*args");
1102    }
1103    #[test]
1104    pub(super) fn test_param_kwarg() {
1105        let mut p = PythonParam::simple("kwargs");
1106        p.is_kwarg = true;
1107        assert_eq!(p.to_string(), "**kwargs");
1108    }
1109    #[test]
1110    pub(super) fn test_full_module_with_dataclass_and_function() {
1111        let mut module = PythonModule::new();
1112        module.add_import("dataclasses", None);
1113        module.add_from_import("dataclasses", vec![("dataclass".to_string(), None)]);
1114        let mut cls = PythonClass::new("Point");
1115        cls.is_dataclass = true;
1116        cls.class_vars = vec![
1117            PythonClassVar {
1118                name: "x".to_string(),
1119                annotation: PythonType::Float,
1120                default: None,
1121            },
1122            PythonClassVar {
1123                name: "y".to_string(),
1124                annotation: PythonType::Float,
1125                default: None,
1126            },
1127        ];
1128        module.add_class(cls);
1129        let mut func = PythonFunction::new("distance");
1130        func.params = vec![
1131            PythonParam::typed("p1", PythonType::Custom("Point".to_string())),
1132            PythonParam::typed("p2", PythonType::Custom("Point".to_string())),
1133        ];
1134        func.return_type = Some(PythonType::Float);
1135        func.body = vec![
1136            PythonStmt::AnnAssign(
1137                "dx".to_string(),
1138                PythonType::Float,
1139                Some(PythonExpr::BinOp(
1140                    "-".to_string(),
1141                    Box::new(PythonExpr::Attr(
1142                        Box::new(PythonExpr::Var("p1".to_string())),
1143                        "x".to_string(),
1144                    )),
1145                    Box::new(PythonExpr::Attr(
1146                        Box::new(PythonExpr::Var("p2".to_string())),
1147                        "x".to_string(),
1148                    )),
1149                )),
1150            ),
1151            PythonStmt::Return(Some(PythonExpr::Call(
1152                Box::new(PythonExpr::Attr(
1153                    Box::new(PythonExpr::Var("math".to_string())),
1154                    "sqrt".to_string(),
1155                )),
1156                vec![PythonExpr::BinOp(
1157                    "+".to_string(),
1158                    Box::new(PythonExpr::BinOp(
1159                        "**".to_string(),
1160                        Box::new(PythonExpr::Var("dx".to_string())),
1161                        Box::new(PythonExpr::Lit(PythonLit::Int(2))),
1162                    )),
1163                    Box::new(PythonExpr::Lit(PythonLit::Int(0))),
1164                )],
1165                vec![],
1166            ))),
1167        ];
1168        module.add_function(func);
1169        let out = module.emit();
1170        assert!(out.contains("@dataclass"));
1171        assert!(out.contains("class Point:"));
1172        assert!(out.contains("x: float"));
1173        assert!(out.contains("def distance(p1: Point, p2: Point) -> float:"));
1174        assert!(out.contains("dx: float = (p1.x - p2.x)"));
1175    }
1176    #[test]
1177    pub(super) fn test_match_with_guard() {
1178        let s = PythonStmt::Match(
1179            PythonExpr::Var("point".to_string()),
1180            vec![MatchArm {
1181                pattern: "Point(x, y)".to_string(),
1182                guard: Some(PythonExpr::BinOp(
1183                    ">".to_string(),
1184                    Box::new(PythonExpr::Var("x".to_string())),
1185                    Box::new(PythonExpr::Lit(PythonLit::Int(0))),
1186                )),
1187                body: vec![PythonStmt::Pass],
1188            }],
1189        );
1190        let out = emit_stmt(&s, 0);
1191        assert!(out.contains("match point:"));
1192        assert!(out.contains("case Point(x, y) if (x > 0):"));
1193    }
1194    #[test]
1195    pub(super) fn test_indented_function_in_class() {
1196        let mut cls = PythonClass::new("Foo");
1197        let mut method = PythonFunction::new("bar");
1198        method.params = vec![PythonParam::simple("self")];
1199        method.body = vec![PythonStmt::Return(Some(PythonExpr::Lit(PythonLit::Int(
1200            42,
1201        ))))];
1202        cls.methods.push(method);
1203        let out = emit_class(&cls, 0);
1204        assert!(out.contains("    def bar(self):"));
1205        assert!(out.contains("        return 42"));
1206    }
1207    #[test]
1208    pub(super) fn test_type_set() {
1209        let t = PythonType::Set(Box::new(PythonType::Str));
1210        assert_eq!(t.to_string(), "set[str]");
1211    }
1212    #[test]
1213    pub(super) fn test_type_iterator() {
1214        let t = PythonType::Iterator(Box::new(PythonType::Int));
1215        assert_eq!(t.to_string(), "Iterator[int]");
1216    }
1217    #[test]
1218    pub(super) fn test_type_callable() {
1219        assert_eq!(PythonType::Callable.to_string(), "Callable");
1220    }
1221    #[test]
1222    pub(super) fn test_expr_yield_from() {
1223        let e = PythonExpr::YieldFrom(Box::new(PythonExpr::Var("gen".to_string())));
1224        assert_eq!(e.to_string(), "yield from gen");
1225    }
1226    #[test]
1227    pub(super) fn test_expr_slice() {
1228        let e = PythonExpr::Slice(
1229            Some(Box::new(PythonExpr::Lit(PythonLit::Int(1)))),
1230            Some(Box::new(PythonExpr::Lit(PythonLit::Int(5)))),
1231            None,
1232        );
1233        assert_eq!(e.to_string(), "1:5");
1234    }
1235    #[test]
1236    pub(super) fn test_expr_slice_with_step() {
1237        let e = PythonExpr::Slice(
1238            None,
1239            None,
1240            Some(Box::new(PythonExpr::Lit(PythonLit::Int(2)))),
1241        );
1242        assert_eq!(e.to_string(), "::2");
1243    }
1244    #[test]
1245    pub(super) fn test_expr_set_comp() {
1246        let e = PythonExpr::SetComp(
1247            Box::new(PythonExpr::Var("x".to_string())),
1248            "x".to_string(),
1249            Box::new(PythonExpr::Var("items".to_string())),
1250            None,
1251        );
1252        assert_eq!(e.to_string(), "{x for x in items}");
1253    }
1254    #[test]
1255    pub(super) fn test_expr_gen_expr() {
1256        let e = PythonExpr::GenExpr(
1257            Box::new(PythonExpr::Var("x".to_string())),
1258            "x".to_string(),
1259            Box::new(PythonExpr::Var("nums".to_string())),
1260            Some(Box::new(PythonExpr::BinOp(
1261                ">".to_string(),
1262                Box::new(PythonExpr::Var("x".to_string())),
1263                Box::new(PythonExpr::Lit(PythonLit::Int(0))),
1264            ))),
1265        );
1266        assert_eq!(e.to_string(), "(x for x in nums if (x > 0))");
1267    }
1268    #[test]
1269    pub(super) fn test_stmt_continue_break() {
1270        assert_eq!(emit_stmt(&PythonStmt::Continue, 0), "continue");
1271        assert_eq!(emit_stmt(&PythonStmt::Break, 0), "break");
1272    }
1273    #[test]
1274    pub(super) fn test_stmt_indented() {
1275        let s = PythonStmt::Return(Some(PythonExpr::Lit(PythonLit::Int(1))));
1276        assert_eq!(emit_stmt(&s, 1), "    return 1");
1277        assert_eq!(emit_stmt(&s, 2), "        return 1");
1278    }
1279    #[test]
1280    pub(super) fn test_fresh_var() {
1281        let mut backend = PythonBackend::new();
1282        assert_eq!(backend.fresh_var(), "_t0");
1283        assert_eq!(backend.fresh_var(), "_t1");
1284        assert_eq!(backend.fresh_var(), "_t2");
1285    }
1286    #[test]
1287    pub(super) fn test_module_default() {
1288        let m = PythonModule::default();
1289        assert!(m.imports.is_empty());
1290        assert!(m.functions.is_empty());
1291        assert!(m.classes.is_empty());
1292    }
1293    #[test]
1294    pub(super) fn test_backend_default() {
1295        let b = PythonBackend::default();
1296        assert_eq!(b.fresh_counter, 0);
1297        assert!(b.fn_map.is_empty());
1298    }
1299}