Skip to main content

python_ast/
macros.rs

1/// Macros for reducing code duplication in the python-ast library.
2
3/// Macro for generating test functions for AST parsing.
4/// Reduces duplication in test code. Asserts that both parsing and code
5/// generation succeed and that the generated stream is non-empty, so codegen
6/// regressions actually fail the test.
7#[macro_export]
8macro_rules! create_parse_test {
9    ($test_name:ident, $code:literal, $file_name:literal) => {
10        #[test]
11        fn $test_name() {
12            let options = PythonOptions::default();
13            let result = crate::parse($code, $file_name)
14                .unwrap_or_else(|e| panic!("failed to parse {:?}: {}", $code, e));
15            tracing::info!("Python tree: {:?}", result);
16
17            let symbols = result.clone().find_symbols(SymbolTableScopes::new());
18            let code = result
19                .to_rust(
20                    CodeGenContext::Module($file_name.replace(".py", "").to_string()),
21                    options,
22                    symbols,
23                )
24                .unwrap_or_else(|e| panic!("failed to generate code for {:?}: {}", $code, e));
25            tracing::info!("Generated code: {}", code);
26            assert!(
27                !code.to_string().trim().is_empty(),
28                "codegen produced empty output for {:?}",
29                $code
30            );
31        }
32    };
33}
34
35/// Macro for generating Node trait implementations with optional position fields.
36/// This macro automatically implements the Node trait for types that have position fields.
37#[macro_export]
38macro_rules! impl_node_with_positions {
39    ($type_name:ident { $($field:ident),* }) => {
40        impl $crate::Node for $type_name {
41            fn lineno(&self) -> Option<usize> {
42                $(
43                    if stringify!($field) == "lineno" {
44                        return self.$field;
45                    }
46                )*
47                None
48            }
49
50            fn col_offset(&self) -> Option<usize> {
51                $(
52                    if stringify!($field) == "col_offset" {
53                        return self.$field;
54                    }
55                )*
56                None
57            }
58
59            fn end_lineno(&self) -> Option<usize> {
60                $(
61                    if stringify!($field) == "end_lineno" {
62                        return self.$field;
63                    }
64                )*
65                None
66            }
67
68            fn end_col_offset(&self) -> Option<usize> {
69                $(
70                    if stringify!($field) == "end_col_offset" {
71                        return self.$field;
72                    }
73                )*
74                None
75            }
76        }
77    };
78    
79    // Variant for types without position fields
80    ($type_name:ident) => {
81        impl $crate::Node for $type_name {
82            // All methods return None (default implementation)
83        }
84    };
85}
86