1#[macro_export]
6macro_rules! impl_from_py_object_for_op_enum {
7 ($enum_name:ident, $error_msg:literal) => {
8 impl<'a> FromPyObject<'a> for $enum_name {
9 fn extract_bound(ob: &Bound<'a, PyAny>) -> PyResult<Self> {
10 let err_msg = format!($error_msg, dump(ob, None)?);
11 Err(pyo3::exceptions::PyValueError::new_err(
12 ob.error_message("<unknown>", err_msg),
13 ))
14 }
15 }
16 };
17}
18
19#[macro_export]
22macro_rules! impl_standard_codegen {
23 ($type_name:ident) => {
24 impl CodeGen for $type_name {
25 type Context = CodeGenContext;
26 type Options = PythonOptions;
27 type SymbolTable = SymbolTableScopes;
28
29 fn to_rust(
30 self,
31 ctx: Self::Context,
32 options: Self::Options,
33 symbols: Self::SymbolTable,
34 ) -> Result<proc_macro2::TokenStream, Box<dyn std::error::Error>> {
35 self.generate_rust_code(ctx, options, symbols)
36 }
37 }
38 };
39}
40
41#[macro_export]
43macro_rules! impl_codegen_with_custom {
44 ($type_name:ident, $generate_fn:expr) => {
45 impl CodeGen for $type_name {
46 type Context = CodeGenContext;
47 type Options = PythonOptions;
48 type SymbolTable = SymbolTableScopes;
49
50 fn to_rust(
51 self,
52 ctx: Self::Context,
53 options: Self::Options,
54 symbols: Self::SymbolTable,
55 ) -> Result<proc_macro2::TokenStream, Box<dyn std::error::Error>> {
56 $generate_fn(self, ctx, options, symbols)
57 }
58 }
59 };
60}
61
62#[macro_export]
64macro_rules! extract_py_attr {
65 ($obj:expr, $attr:literal, $error_context:literal) => {
66 $obj.getattr($attr).expect(
67 $obj.error_message("<unknown>", concat!("error getting ", $error_context))
68 .as_str(),
69 )
70 };
71}
72
73#[macro_export]
75macro_rules! extract_py_type_name {
76 ($obj:expr, $context:literal) => {
77 $obj.get_type().name().expect(
78 $obj.error_message(
79 "<unknown>",
80 format!("extracting type name for {}", $context),
81 )
82 .as_str(),
83 )
84 };
85}
86
87#[macro_export]
90macro_rules! impl_binary_op_from_py {
91 ($struct_name:ident, $enum_name:ident, $op_variants:tt) => {
92 impl<'a> FromPyObject<'a> for $struct_name {
93 fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<Self> {
94 log::debug!("ob: {}", dump(ob, None)?);
95
96 let op = extract_py_attr!(ob, "op", "operator");
97 let op_type = extract_py_type_name!(op, "binary operator")?;
98
99 let left = extract_py_attr!(ob, "left", "binary operand");
100 let right = extract_py_attr!(ob, "right", "binary operand");
101
102 log::debug!("left: {}, right: {}", dump(&left, None)?, dump(&right, None)?);
103
104 let op_type_str: String = op_type.extract()?;
105 let op = match op_type_str.as_ref() {
106 $op_variants,
107 _ => {
108 log::debug!("Found unknown {} {:?}", stringify!($enum_name), op);
109 $enum_name::Unknown
110 }
111 };
112
113 let left = left.extract().expect("getting binary operator operand");
114 let right = right.extract().expect("getting binary operator operand");
115
116 Ok($struct_name {
117 op,
118 left: Box::new(left),
119 right: Box::new(right),
120 })
121 }
122 }
123 };
124}
125
126#[macro_export]
129macro_rules! create_parse_test {
130 ($test_name:ident, $code:literal, $file_name:literal) => {
131 #[test]
132 fn $test_name() {
133 let options = PythonOptions::default();
134 let result = crate::parse($code, $file_name).unwrap();
135 log::info!("Python tree: {:?}", result);
136
137 let code = result.to_rust(
138 CodeGenContext::Module($file_name.replace(".py", "").to_string()),
139 options,
140 SymbolTableScopes::new(),
141 );
142 log::info!("Generated code: {:?}", code);
143 }
144 };
145}
146
147#[macro_export]
150macro_rules! impl_node_with_positions {
151 ($type_name:ident { $($field:ident),* }) => {
152 impl $crate::Node for $type_name {
153 fn lineno(&self) -> Option<usize> {
154 $(
155 if stringify!($field) == "lineno" {
156 return self.$field;
157 }
158 )*
159 None
160 }
161
162 fn col_offset(&self) -> Option<usize> {
163 $(
164 if stringify!($field) == "col_offset" {
165 return self.$field;
166 }
167 )*
168 None
169 }
170
171 fn end_lineno(&self) -> Option<usize> {
172 $(
173 if stringify!($field) == "end_lineno" {
174 return self.$field;
175 }
176 )*
177 None
178 }
179
180 fn end_col_offset(&self) -> Option<usize> {
181 $(
182 if stringify!($field) == "end_col_offset" {
183 return self.$field;
184 }
185 )*
186 None
187 }
188 }
189 };
190
191 ($type_name:ident) => {
193 impl $crate::Node for $type_name {
194 }
196 };
197}
198
199#[macro_export]
201macro_rules! extract_with_context {
202 ($obj:expr, $attr:literal) => {
203 $obj.getattr($attr).map_err(|e| {
204 pyo3::exceptions::PyAttributeError::new_err(format!(
205 "Failed to extract '{}': {}",
206 $attr, e
207 ))
208 })?
209 };
210}
211
212#[macro_export]
214macro_rules! operator_match_arms {
215 ($($variant:ident => $string:literal),* $(,)?) => {
216 $(
217 $string => Self::$variant,
218 )*
219 };
220}
221
222#[macro_export]
224macro_rules! symbol_table_test {
225 ($test_name:ident, $setup:block, $assertion:block) => {
226 #[test]
227 fn $test_name() {
228 $setup
229 $assertion
230 }
231 };
232}