python_ast/ast/tree/
call.rs

1use proc_macro2::TokenStream;
2use pyo3::{Bound, FromPyObject, PyAny, PyResult, prelude::PyAnyMethods};
3use quote::quote;
4use serde::{Deserialize, Serialize};
5
6use crate::{CodeGen, CodeGenContext, ExprType, Keyword, PythonOptions, SymbolTableScopes};
7
8#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
9pub struct Call {
10    pub func: Box<ExprType>,
11    pub args: Vec<ExprType>,
12    pub keywords: Vec<Keyword>,
13}
14
15impl<'a> FromPyObject<'a> for Call {
16    fn extract_bound(ob: &Bound<'a, PyAny>) -> PyResult<Self> {
17        let func = ob.getattr("func").expect("Call.func");
18        let args = ob.getattr("args").expect("Call.args");
19        let keywords = ob.getattr("keywords").expect("Call.keywords");
20        Ok(Call {
21            func: Box::new(func.extract().expect("Call.func")),
22            args: args.extract().expect("Call.args"),
23            keywords: keywords.extract().expect("Call.keywords"),
24        })
25    }
26}
27
28impl<'a> CodeGen for Call {
29    type Context = CodeGenContext;
30    type Options = PythonOptions;
31    type SymbolTable = SymbolTableScopes;
32
33    fn to_rust(
34        self,
35        ctx: Self::Context,
36        options: Self::Options,
37        symbols: Self::SymbolTable,
38    ) -> Result<TokenStream, Box<dyn std::error::Error>> {
39        let name = self.func.to_rust(ctx.clone(), options.clone(), symbols.clone())?;
40        
41        let mut all_args = Vec::new();
42        
43        // Add positional arguments
44        for arg in self.args {
45            let rust_arg = arg.to_rust(ctx.clone(), options.clone(), symbols.clone())?;
46            all_args.push(rust_arg);
47        }
48        
49        // Add keyword arguments
50        for keyword in self.keywords {
51            let rust_kw = keyword.to_rust(ctx.clone(), options.clone(), symbols.clone())?;
52            all_args.push(rust_kw);
53        }
54        
55        Ok(quote!(#name(#(#all_args),*)))
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn test_lookup_of_function() {
65        let options = PythonOptions::default();
66        let result = crate::parse(
67            "def foo(a = 7):
68    pass
69
70foo(b=9)",
71            "test.py",
72        )
73        .unwrap();
74        println!("Python tree: {:#?}", result);
75        let code = result
76            .to_rust(
77                CodeGenContext::Module("test".to_string()),
78                options,
79                SymbolTableScopes::new(),
80            )
81            .unwrap();
82        println!("Rust code: {}", code);
83    }
84}