Skip to main content

python_ast/ast/tree/
statement.rs

1use proc_macro2::TokenStream;
2use pyo3::{Borrowed, FromPyObject, PyAny, PyResult, prelude::PyAnyMethods, types::PyTypeMethods};
3use quote::quote;
4
5use crate::{
6    dump, err_from, extraction_failure, Assign, AsyncFor, AsyncWith, AugAssign, Call, ClassDef,
7    CodeGen, CodeGenContext, Expr, ExprType, For, FunctionDef, If, Import, ImportFrom, Node,
8    PythonOptions, Raise, StatementNotYetImplemented, SymbolTableScopes, Try, While, With,
9};
10
11use tracing::debug;
12
13use serde::{Deserialize, Serialize};
14
15/// AST node types that can be used as a statement implement this type.
16pub trait PyStatementTrait: Clone + PartialEq {
17}
18
19#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
20pub struct Statement {
21    pub lineno: Option<usize>,
22    pub col_offset: Option<usize>,
23    pub end_lineno: Option<usize>,
24    pub end_col_offset: Option<usize>,
25    pub statement: StatementType,
26}
27
28impl<'a, 'py> FromPyObject<'a, 'py> for Statement {
29    type Error = pyo3::PyErr;
30    fn extract(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
31        Ok(Self {
32            lineno: ob.lineno(),
33            col_offset: ob.col_offset(),
34            end_lineno: ob.end_lineno(),
35            end_col_offset: ob.end_col_offset(),
36            statement: StatementType::extract(ob)?,
37        })
38    }
39}
40
41impl Node for Statement {
42    fn lineno(&self) -> Option<usize> {
43        self.lineno
44    }
45    fn col_offset(&self) -> Option<usize> {
46        self.col_offset
47    }
48    fn end_lineno(&self) -> Option<usize> {
49        self.end_lineno
50    }
51    fn end_col_offset(&self) -> Option<usize> {
52        self.end_col_offset
53    }
54}
55
56impl CodeGen for Statement {
57    type Context = CodeGenContext;
58    type Options = PythonOptions;
59    type SymbolTable = SymbolTableScopes;
60
61    fn find_symbols(self, symbols: Self::SymbolTable) -> Self::SymbolTable {
62        self.statement.clone().find_symbols(symbols)
63    }
64
65    fn to_rust(
66        self,
67        ctx: Self::Context,
68        options: Self::Options,
69        symbols: Self::SymbolTable,
70    ) -> Result<TokenStream, Box<dyn std::error::Error>> {
71        let (lineno, col_offset) = (self.lineno, self.col_offset);
72        let (end_lineno, end_col_offset) = (self.end_lineno, self.end_col_offset);
73        self.statement
74            .clone()
75            .to_rust(ctx, options, symbols)
76            .map_err(|e| {
77                let location = crate::SourceLocation::with_span(
78                    "<module>",
79                    lineno,
80                    col_offset.map(|c| c + 1),
81                    end_lineno,
82                    end_col_offset,
83                );
84                Box::<dyn std::error::Error>::from(crate::codegen_error(
85                    location,
86                    crate::format_error_chain(e.as_ref()),
87                    "",
88                ))
89            })
90    }
91}
92
93#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
94pub enum StatementType {
95    AsyncFunctionDef(FunctionDef),
96    Assert {
97        test: Box<ExprType>,
98        msg: Option<Box<ExprType>>,
99    },
100    Assign(Assign),
101    AugAssign(AugAssign),
102    Break,
103    Continue,
104    ClassDef(ClassDef),
105    Call(Call),
106    Pass,
107    Return(Option<Expr>),
108    Import(Import),
109    ImportFrom(ImportFrom),
110    Expr(Expr),
111    FunctionDef(FunctionDef),
112    If(If),
113    For(For),
114    While(While),
115    Try(Try),
116    AsyncWith(AsyncWith),
117    AsyncFor(AsyncFor),
118    Raise(Raise),
119    With(With),
120
121    Unimplemented(String),
122}
123
124impl<'a, 'py> FromPyObject<'a, 'py> for StatementType {
125    type Error = pyo3::PyErr;
126    fn extract(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
127        let ob_type = ob
128            .get_type()
129            .name()
130            .map_err(|e| extraction_failure("statement type", &ob, e))?;
131
132        debug!("statement...ob_type: {}...{}", ob_type, dump(&ob, Some(4))?);
133        match ob_type.extract::<String>()?.as_str() {
134            "AsyncFunctionDef" => Ok(StatementType::AsyncFunctionDef(
135                FunctionDef::extract(ob)
136                    .map_err(|e| extraction_failure("async function definition", &ob, e))?,
137            )),
138            "Assign" => {
139                let assignment = Assign::extract(ob)
140                    .map_err(|e| extraction_failure("assignment", &ob, e))?;
141                Ok(StatementType::Assign(assignment))
142            }
143            "AnnAssign" => {
144                // An annotated assignment (`x: int = 5`) is an ordinary
145                // assignment with a type annotation we don't yet consume; a
146                // bare annotation (`x: int`) declares nothing at runtime.
147                let value = ob
148                    .getattr("value")
149                    .map_err(|e| extraction_failure("annotated assignment value", &ob, e))?;
150                if value.is_none() {
151                    return Ok(StatementType::Pass);
152                }
153                let target = ob
154                    .getattr("target")
155                    .map_err(|e| extraction_failure("annotated assignment target", &ob, e))?
156                    .extract()
157                    .map_err(|e| extraction_failure("annotated assignment target", &ob, e))?;
158                let value = value
159                    .extract()
160                    .map_err(|e| extraction_failure("annotated assignment value", &ob, e))?;
161                Ok(StatementType::Assign(Assign {
162                    targets: vec![target],
163                    value,
164                    type_comment: None,
165                }))
166            }
167            "AugAssign" => {
168                let aug_assignment = AugAssign::extract(ob)
169                    .map_err(|e| extraction_failure("augmented assignment", &ob, e))?;
170                Ok(StatementType::AugAssign(aug_assignment))
171            }
172            "Assert" => {
173                let test: ExprType = ob
174                    .getattr("test")
175                    .map_err(|e| extraction_failure("assert condition", &ob, e))?
176                    .extract()
177                    .map_err(|e| extraction_failure("assert condition", &ob, e))?;
178                let msg: Option<Box<ExprType>> = match ob.getattr("msg") {
179                    Ok(m) if !m.is_none() => Some(Box::new(
180                        m.extract()
181                            .map_err(|e| extraction_failure("assert message", &ob, e))?,
182                    )),
183                    _ => None,
184                };
185                Ok(StatementType::Assert {
186                    test: Box::new(test),
187                    msg,
188                })
189            }
190            "Pass" => Ok(StatementType::Pass),
191            "Call" => {
192                let value = ob
193                    .getattr("value")
194                    .map_err(|e| extraction_failure("call statement value", &ob, e))?;
195                let call = Call::extract(value.as_borrowed())
196                    .map_err(|e| extraction_failure("call statement", &ob, e))?;
197                debug!("call: {:?}", call);
198                Ok(StatementType::Call(call))
199            }
200            "ClassDef" => Ok(StatementType::ClassDef(
201                ClassDef::extract(ob)
202                    .map_err(|e| extraction_failure("class definition", &ob, e))?,
203            )),
204            "Continue" => Ok(StatementType::Continue),
205            "Break" => Ok(StatementType::Break),
206            "FunctionDef" => Ok(StatementType::FunctionDef(
207                FunctionDef::extract(ob)
208                    .map_err(|e| extraction_failure("function definition", &ob, e))?,
209            )),
210            "Import" => Ok(StatementType::Import(
211                Import::extract(ob).map_err(|e| extraction_failure("import", &ob, e))?,
212            )),
213            "ImportFrom" => Ok(StatementType::ImportFrom(
214                ImportFrom::extract(ob)
215                    .map_err(|e| extraction_failure("from-import", &ob, e))?,
216            )),
217            "Expr" => {
218                let expr = ob
219                    .extract()
220                    .map_err(|e| extraction_failure("expression statement", &ob, e))?;
221                Ok(StatementType::Expr(expr))
222            }
223            "Return" => {
224                tracing::debug!("return expression: {}", dump(&ob, None)?);
225                // Extract the return value from the Return statement's 'value' field
226                let return_value = if let Ok(value_attr) = ob.getattr("value") {
227                    if value_attr.is_none() {
228                        // Bare 'return' statement - create a NoneType Expr
229                        Some(Expr {
230                            value: crate::tree::ExprType::NoneType(crate::tree::Constant(None)),
231                            ctx: None,
232                            lineno: ob.lineno(),
233                            col_offset: ob.col_offset(),
234                            end_lineno: ob.end_lineno(),
235                            end_col_offset: ob.end_col_offset(),
236                        })
237                    } else {
238                        // Return with actual expression - extract as ExprType then wrap in Expr
239                        let expr_value: crate::tree::ExprType = value_attr
240                            .extract()
241                            .map_err(|e| extraction_failure("return value", &ob, e))?;
242                        Some(Expr {
243                            value: expr_value,
244                            ctx: None,
245                            lineno: ob.lineno(),
246                            col_offset: ob.col_offset(),
247                            end_lineno: ob.end_lineno(),
248                            end_col_offset: ob.end_col_offset(),
249                        })
250                    }
251                } else {
252                    None
253                };
254                Ok(StatementType::Return(return_value))
255            }
256            "If" => {
257                let if_stmt =
258                    If::extract(ob).map_err(|e| extraction_failure("if statement", &ob, e))?;
259                Ok(StatementType::If(if_stmt))
260            }
261            "For" => {
262                let for_stmt =
263                    For::extract(ob).map_err(|e| extraction_failure("for loop", &ob, e))?;
264                Ok(StatementType::For(for_stmt))
265            }
266            "While" => {
267                let while_stmt =
268                    While::extract(ob).map_err(|e| extraction_failure("while loop", &ob, e))?;
269                Ok(StatementType::While(while_stmt))
270            }
271            "Try" => {
272                let try_stmt =
273                    Try::extract(ob).map_err(|e| extraction_failure("try statement", &ob, e))?;
274                Ok(StatementType::Try(try_stmt))
275            }
276            "AsyncWith" => {
277                let async_with_stmt = AsyncWith::extract(ob)
278                    .map_err(|e| extraction_failure("async with statement", &ob, e))?;
279                Ok(StatementType::AsyncWith(async_with_stmt))
280            }
281            "AsyncFor" => {
282                let async_for_stmt = AsyncFor::extract(ob)
283                    .map_err(|e| extraction_failure("async for loop", &ob, e))?;
284                Ok(StatementType::AsyncFor(async_for_stmt))
285            }
286            "Raise" => {
287                let raise_stmt =
288                    Raise::extract(ob).map_err(|e| extraction_failure("raise statement", &ob, e))?;
289                Ok(StatementType::Raise(raise_stmt))
290            }
291            "With" => {
292                let with_stmt =
293                    With::extract(ob).map_err(|e| extraction_failure("with statement", &ob, e))?;
294                Ok(StatementType::With(with_stmt))
295            }
296            other => Err(extraction_failure(
297                "statement",
298                &ob,
299                format!(
300                    "the `{}` statement is not yet supported by rython",
301                    other
302                ),
303            )),
304        }
305    }
306}
307
308/// A Python `return` lowered for the current context: inside a try-block
309/// closure it signals out via PyFlow so the try lowering can run the
310/// finally body and re-return; elsewhere it returns Ok directly.
311fn return_tokens(ctx: &CodeGenContext, value: TokenStream) -> TokenStream {
312    if ctx.in_try_block() {
313        quote!(return Ok(PyFlow::Return(#value)))
314    } else {
315        quote!(return Ok(#value))
316    }
317}
318
319/// Whether a statement list contains a function-level `return` anywhere —
320/// looking through control flow (including nested trys and their handlers)
321/// but not into nested function or class definitions. The try lowering uses
322/// this to pick its closure's carrier type: bodies with returns thread the
323/// returned value out through PyFlow.
324/// Does this statement list contain a `break`/`continue` that targets a
325/// loop OUTSIDE the list? A loop nested *within* the list owns its own
326/// breaks, so its body is not searched — but its `else` clause is, since
327/// a break there targets the enclosing loop, as in Python. Nested
328/// function and class bodies are separate scopes and never searched.
329pub fn body_breaks_outward(body: &[Statement]) -> bool {
330    body.iter().any(|stmt| match &stmt.statement {
331        StatementType::Break | StatementType::Continue => true,
332        StatementType::If(s) => {
333            body_breaks_outward(&s.body) || body_breaks_outward(&s.orelse)
334        }
335        // A loop captures breaks in its BODY; only its else clause can
336        // break outward.
337        StatementType::For(s) => body_breaks_outward(&s.orelse),
338        StatementType::While(s) => body_breaks_outward(&s.orelse),
339        StatementType::AsyncFor(s) => body_breaks_outward(&s.orelse),
340        StatementType::Try(s) => {
341            body_breaks_outward(&s.body)
342                || s.handlers.iter().any(|h| body_breaks_outward(&h.body))
343                || body_breaks_outward(&s.orelse)
344                || body_breaks_outward(&s.finalbody)
345        }
346        StatementType::With(s) => body_breaks_outward(&s.body),
347        StatementType::AsyncWith(s) => body_breaks_outward(&s.body),
348        _ => false,
349    })
350}
351
352pub fn body_contains_function_return(body: &[Statement]) -> bool {
353    body.iter().any(|stmt| match &stmt.statement {
354        StatementType::Return(_) => true,
355        StatementType::If(s) => {
356            body_contains_function_return(&s.body) || body_contains_function_return(&s.orelse)
357        }
358        StatementType::For(s) => {
359            body_contains_function_return(&s.body) || body_contains_function_return(&s.orelse)
360        }
361        StatementType::While(s) => {
362            body_contains_function_return(&s.body) || body_contains_function_return(&s.orelse)
363        }
364        StatementType::AsyncFor(s) => {
365            body_contains_function_return(&s.body) || body_contains_function_return(&s.orelse)
366        }
367        StatementType::Try(s) => {
368            body_contains_function_return(&s.body)
369                || s.handlers
370                    .iter()
371                    .any(|h| body_contains_function_return(&h.body))
372                || body_contains_function_return(&s.orelse)
373                || body_contains_function_return(&s.finalbody)
374        }
375        StatementType::With(s) => body_contains_function_return(&s.body),
376        StatementType::AsyncWith(s) => body_contains_function_return(&s.body),
377        _ => false,
378    })
379}
380
381/// Whether a loop body contains a `break` that belongs to that loop —
382/// looking through `if`/`try`/`with` blocks but not into nested loops
383/// (whose breaks are their own) or nested definitions. Loops with an `else`
384/// clause only need break-tracking machinery when this is true.
385pub fn loop_body_has_direct_break(body: &[Statement]) -> bool {
386    body.iter().any(|stmt| match &stmt.statement {
387        StatementType::Break => true,
388        StatementType::If(s) => {
389            loop_body_has_direct_break(&s.body) || loop_body_has_direct_break(&s.orelse)
390        }
391        StatementType::Try(s) => {
392            loop_body_has_direct_break(&s.body)
393                || s.handlers
394                    .iter()
395                    .any(|h| loop_body_has_direct_break(&h.body))
396                || loop_body_has_direct_break(&s.orelse)
397                || loop_body_has_direct_break(&s.finalbody)
398        }
399        StatementType::With(s) => loop_body_has_direct_break(&s.body),
400        StatementType::AsyncWith(s) => loop_body_has_direct_break(&s.body),
401        _ => false,
402    })
403}
404
405impl CodeGen for StatementType {
406    type Context = CodeGenContext;
407    type Options = PythonOptions;
408    type SymbolTable = SymbolTableScopes;
409
410    fn find_symbols(self, symbols: Self::SymbolTable) -> Self::SymbolTable {
411        match self {
412            StatementType::Assign(a) => a.find_symbols(symbols),
413            StatementType::AugAssign(a) => a.find_symbols(symbols),
414            StatementType::ClassDef(c) => c.find_symbols(symbols),
415            StatementType::FunctionDef(f) => f.find_symbols(symbols),
416            // Async functions register like ordinary ones, so call sites
417            // know they return Result and append `?` (before `.await`).
418            StatementType::AsyncFunctionDef(f) => f.find_symbols(symbols),
419            StatementType::Import(i) => i.find_symbols(symbols),
420            StatementType::ImportFrom(i) => i.find_symbols(symbols),
421            StatementType::Expr(e) => e.find_symbols(symbols),
422            StatementType::If(i) => i.find_symbols(symbols),
423            StatementType::For(f) => f.find_symbols(symbols),
424            StatementType::While(w) => w.find_symbols(symbols),
425            StatementType::Try(t) => t.find_symbols(symbols),
426            StatementType::AsyncWith(aw) => aw.find_symbols(symbols),
427            StatementType::AsyncFor(af) => af.find_symbols(symbols),
428            StatementType::Raise(r) => r.find_symbols(symbols),
429            StatementType::With(w) => w.find_symbols(symbols),
430            _ => symbols,
431        }
432    }
433
434    fn to_rust(
435        self,
436        ctx: Self::Context,
437        options: Self::Options,
438        symbols: Self::SymbolTable,
439    ) -> Result<TokenStream, Box<dyn std::error::Error>> {
440        match self {
441            StatementType::AsyncFunctionDef(s) => {
442                let func_def = s.to_rust(Self::Context::Async(Box::new(ctx)), options, symbols)?;
443                Ok(quote!(#func_def))
444            }
445            StatementType::Assert { test, msg } => {
446                let test_tokens =
447                    crate::condition_to_rust(&test, ctx.clone(), options.clone(), symbols.clone())?;
448                let msg_tokens = match msg {
449                    Some(m) => {
450                        let m = m.to_rust(ctx.clone(), options, symbols)?;
451                        quote!(format!("{}", #m))
452                    }
453                    None => quote!(String::new()),
454                };
455                // A failed assert raises AssertionError. Functions return
456                // Result<T, PyException>, so raising is returning Err: it is
457                // caught by an enclosing try's closure or propagates out of
458                // the function, as in Python.
459                Ok(quote! {
460                    if !(#test_tokens) {
461                        return Err(PyException::new("AssertionError", #msg_tokens));
462                    }
463                })
464            }
465            StatementType::Assign(a) => a.to_rust(ctx, options, symbols),
466            StatementType::AugAssign(a) => a.to_rust(ctx, options, symbols),
467            StatementType::Break => {
468                // A break whose loop lies outside an enclosing try-block
469                // closure cannot be a Rust `break` here — it would escape
470                // the closure. Signal it out instead; the try lowering
471                // replays it after the finally clause, as Python orders it.
472                if ctx.break_crosses_try_closure() {
473                    return Ok(if ctx.break_target_has_else() {
474                        quote! {{ __rython_broke = true; return Ok(PyFlow::Break); }}
475                    } else {
476                        quote! {return Ok(PyFlow::Break);}
477                    });
478                }
479                // Inside a loop that has an `else` clause, breaking must also
480                // record that the loop did not complete normally.
481                if matches!(ctx, Self::Context::Loop { has_else: true, .. }) {
482                    Ok(quote! {{ __rython_broke = true; break; }})
483                } else {
484                    Ok(quote! {break;})
485                }
486            }
487            StatementType::Call(c) => c.to_rust(ctx, options, symbols),
488            StatementType::ClassDef(c) => c.to_rust(ctx, options, symbols),
489            StatementType::Continue => {
490                if ctx.break_crosses_try_closure() {
491                    Ok(quote! {return Ok(PyFlow::Continue);})
492                } else {
493                    Ok(quote! {continue;})
494                }
495            }
496            StatementType::Pass => Ok(quote! {}),
497            StatementType::FunctionDef(s) => s.to_rust(ctx, options, symbols),
498            StatementType::Import(s) => s.to_rust(ctx, options, symbols),
499            StatementType::ImportFrom(s) => s.to_rust(ctx, options, symbols),
500            StatementType::Expr(s) => s.to_rust(ctx, options, symbols),
501            // Functions return Result<T, PyException>; a Python return wraps
502            // its value in Ok (bare return / return None yield Ok(())).
503            // Inside a try block's closure, a return must first break out of
504            // the closure: it becomes Ok(PyFlow::Return(value)), which
505            // the try lowering turns back into a function return — after
506            // running the finally body, as Python requires.
507            StatementType::Return(None) => Ok(return_tokens(&ctx, quote!(()))),
508            StatementType::Return(Some(e)) => {
509                let value = if matches!(e.value, ExprType::NoneType(_)) {
510                    quote!(())
511                } else {
512                    let tokens = e.clone().to_rust(ctx.clone(), options.clone(), symbols)?;
513                    // A `-> str` function returning an attribute chain reads
514                    // a String field through the shared receiver: clone it
515                    // out. Python strings are immutable, so the clone
516                    // reproduces Python's semantics exactly (a bare field
517                    // read would move out of &self and not compile).
518                    if options.clone_str_attribute_returns
519                        && matches!(e.value, ExprType::Attribute(_))
520                    {
521                        quote!((#tokens).clone())
522                    } else {
523                        tokens
524                    }
525                };
526                Ok(return_tokens(&ctx, value))
527            }
528            StatementType::If(i) => i.to_rust(ctx, options, symbols),
529            StatementType::For(f) => f.to_rust(ctx, options, symbols),
530            StatementType::While(w) => w.to_rust(ctx, options, symbols),
531            StatementType::Try(t) => t.to_rust(ctx, options, symbols),
532            StatementType::AsyncWith(aw) => aw.to_rust(ctx, options, symbols),
533            StatementType::AsyncFor(af) => af.to_rust(ctx, options, symbols),
534            StatementType::Raise(r) => r.to_rust(ctx, options, symbols),
535            StatementType::With(w) => w.to_rust(ctx, options, symbols),
536            _ => {
537                let error = err_from(StatementNotYetImplemented(self));
538                Err(error.into())
539            }
540        }
541    }
542}
543
544#[cfg(test)]
545mod tests {
546    use super::*;
547
548    #[test]
549    fn check_pass_statement() {
550        let statement = StatementType::Pass;
551        let options = PythonOptions::default();
552        let tokens = statement.clone().to_rust(
553            CodeGenContext::Module("".to_string()),
554            options,
555            SymbolTableScopes::new(),
556        );
557
558        debug!("statement: {:?}, tokens: {:?}", statement, tokens);
559        assert_eq!(tokens.unwrap().is_empty(), true);
560    }
561
562    #[test]
563    fn check_break_statement() {
564        let statement = StatementType::Break;
565        let options = PythonOptions::default();
566        let tokens = statement.clone().to_rust(
567            CodeGenContext::Module("".to_string()),
568            options,
569            SymbolTableScopes::new(),
570        );
571
572        debug!("statement: {:?}, tokens: {:?}", statement, tokens);
573        assert_eq!(tokens.unwrap().is_empty(), false);
574    }
575
576    #[test]
577    fn check_continue_statement() {
578        let statement = StatementType::Continue;
579        let options = PythonOptions::default();
580        let tokens = statement.clone().to_rust(
581            CodeGenContext::Module("".to_string()),
582            options,
583            SymbolTableScopes::new(),
584        );
585
586        debug!("statement: {:?}, tokens: {:?}", statement, tokens);
587        assert_eq!(tokens.unwrap().is_empty(), false);
588    }
589
590    #[test]
591    fn return_with_nothing() {
592        let tree = crate::parse("return", "<none>").unwrap();
593        assert_eq!(tree.raw.body.len(), 1);
594        assert_eq!(
595            tree.raw.body[0].statement,
596            StatementType::Return(Some(Expr {
597                value: crate::tree::ExprType::NoneType(crate::tree::Constant(None)),
598                lineno: Some(1),
599                col_offset: Some(0),
600                end_lineno: Some(1),
601                end_col_offset: Some(6),
602                ..Default::default()
603            }))
604        );
605    }
606
607    #[test]
608    fn return_with_expr() {
609        let lit = litrs::Literal::Integer(litrs::IntegerLit::parse(String::from("8")).unwrap());
610        let tree = crate::parse("return 8", "<none>").unwrap();
611        assert_eq!(tree.raw.body.len(), 1);
612        assert_eq!(
613            tree.raw.body[0].statement,
614            StatementType::Return(Some(Expr {
615                value: crate::tree::ExprType::Constant(crate::tree::Constant(Some(lit))),
616                lineno: Some(1),
617                col_offset: Some(0),
618                end_lineno: Some(1),
619                end_col_offset: Some(8),
620                ..Default::default()
621            }))
622        );
623    }
624
625    #[test]
626    fn does_module_compile() {
627        let options = PythonOptions::default();
628        let result = crate::parse(
629            "#test comment
630def foo():
631    continue
632    pass
633",
634            "test_case",
635        )
636        .unwrap();
637        tracing::info!("{:?}", result);
638        let code = result.to_rust(
639            CodeGenContext::Module("".to_string()),
640            options,
641            SymbolTableScopes::new(),
642        );
643        tracing::info!("module: {:?}", code);
644    }
645}