python_ast/ast/tree/
keyword.rs

1use proc_macro2::TokenStream;
2use pyo3::{Bound, FromPyObject, PyAny, PyResult, prelude::PyAnyMethods};
3// Keyword arguments are now handled by just passing values
4use serde::{Deserialize, Serialize};
5
6use crate::{CodeGen, CodeGenContext, ExprType, PythonOptions, SymbolTableScopes, Node};
7
8/// A keyword argument in a function call.
9#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
10pub struct Keyword {
11    /// Keyword name (None for **kwargs unpacking)
12    pub arg: Option<String>,
13    /// Argument value
14    pub value: ExprType,
15    /// Position information
16    pub lineno: Option<usize>,
17    pub col_offset: Option<usize>,
18    pub end_lineno: Option<usize>,
19    pub end_col_offset: Option<usize>,
20}
21
22impl<'a> FromPyObject<'a> for Keyword {
23    fn extract_bound(ob: &Bound<'a, PyAny>) -> PyResult<Self> {
24        let arg = if let Ok(arg_attr) = ob.getattr("arg") {
25            if arg_attr.is_none() {
26                None
27            } else {
28                Some(arg_attr.extract()?)
29            }
30        } else {
31            None
32        };
33        
34        let value: ExprType = ob.getattr("value")?.extract()?;
35        
36        Ok(Self {
37            arg,
38            value,
39            lineno: ob.lineno(),
40            col_offset: ob.col_offset(),
41            end_lineno: ob.end_lineno(),
42            end_col_offset: ob.end_col_offset(),
43        })
44    }
45}
46
47impl CodeGen for Keyword {
48    type Context = CodeGenContext;
49    type Options = PythonOptions;
50    type SymbolTable = SymbolTableScopes;
51
52    fn to_rust(
53        self,
54        ctx: Self::Context,
55        options: Self::Options,
56        symbols: Self::SymbolTable,
57    ) -> Result<TokenStream, Box<dyn std::error::Error>> {
58        let value = self.value.to_rust(ctx, options, symbols)?;
59        
60        if let Some(_keyword) = self.arg {
61            // Named keyword argument: In Python this is keyword=value,
62            // but in Rust we typically pass just the value
63            // For now, just pass the value - this could be enhanced to handle
64            // struct initialization syntax or builder patterns in the future
65            Ok(value)
66        } else {
67            // **kwargs unpacking: **dict_expr
68            // This is complex in Rust and would need special handling
69            // For now, just pass the value
70            Ok(value)
71        }
72    }
73}
74
75impl Node for Keyword {
76    fn lineno(&self) -> Option<usize> { self.lineno }
77    fn col_offset(&self) -> Option<usize> { self.col_offset }
78    fn end_lineno(&self) -> Option<usize> { self.end_lineno }
79    fn end_col_offset(&self) -> Option<usize> { self.end_col_offset }
80}