@@ -33,18 +33,37 @@ To add a new compiler pass, you need to update this file and create the test dir
33331. Add a new entry to the `compiler_passes!` table:
3434
3535```rust
36- (runner_name, PassStruct, ( input), run_type_checking )
36+ (runner_name, [( PassStruct, input), ...] )
3737```
3838
3939- `runner_name` – the function name for this pass runner (snake_case).
40- - `PassStruct` – the compiler pass struct you are testing.
41- - `input` – the argument to the pass (`()` if none, or a struct literal like `(SsaFormingInput { rename_defs: true })`).
42- - `run_prelude` - whether to run setup passes such as type checking before this pass, you most likely want this to be true
40+ - `[(PassStruct, input), ...]` – a list of passes to run sequentially. Each entry is a tuple of `(pass_struct, input)`.
41+ - `input` – the argument to the pass. Can be `()` if none, or a struct literal like `(SsaFormingInput { rename_defs: true })`.
4342
44- Example :
43+ Examples :
4544
4645```rust
47- (new_pass_runner, NewPass, (NewPassInput { option: true }), true),
46+ // Single pass with typical prelude
47+ (new_pass_runner, [
48+ (PathResolution, ()),
49+ (SymbolTableCreation, ()),
50+ (TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
51+ (NewPass, (NewPassInput { option: true }))
52+ ]),
53+
54+ // Multiple passes run sequentially
55+ (multi_pass_runner, [
56+ (PathResolution, ()),
57+ (SymbolTableCreation, ()),
58+ (TypeChecking, (TypeCheckingInput::new(NetworkName::TestnetV0))),
59+ (FirstPass, ()),
60+ (SecondPass, (SecondPassInput { value: NetworkName::TestnetV0 }))
61+ ]),
62+
63+ // Pass without prelude (if prelude not needed)
64+ (no_prelude_runner, [
65+ (SomePass, ())
66+ ]),
4867```
4968
50692. No other code needs to change — macros automatically generate:
@@ -88,38 +107,102 @@ use leo_span::{create_session_if_not_set_then, source_map::FileName, with_sessio
88107use serial_test:: serial;
89108
90109/// Table of all compiler passes and their runner names.
91- /// Each entry is a tuple of `(runner_name, pass_struct, input)`
92- /// - `input` is the argument to the pass, can be `()` or a struct literal.
110+ /// Each entry is a tuple of `(runner_name, [(pass_struct, input), ...])`
111+ /// - `runner_name` – the function name for this pass runner (snake_case).
112+ /// - `[(pass_struct, input), ...]` – a list of passes to run sequentially. Each entry is a tuple of `(pass_struct, input)`.
113+ /// Include the prelude passes (PathResolution, SymbolTableCreation, TypeChecking) at the beginning if needed.
114+ /// - `input` – the argument to the pass. Can be `()` if none, or a struct literal like `(SsaFormingInput { rename_defs: true })`.
93115macro_rules! compiler_passes {
94116 ( $macro: ident) => {
95117 $macro! {
96- ( common_subexpression_elimination_runner, CommonSubexpressionEliminating , ( ) , true ) ,
97- ( const_prop_unroll_and_morphing_runner, ConstPropUnrollAndMorphing , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) , true ) ,
98- ( destructuring_runner, Destructuring , ( ) , true ) ,
99- ( dead_code_elimination_runner, DeadCodeEliminating , ( ) , true ) ,
100- ( flattening_runner, Flattening , ( ) , true ) ,
101- ( function_inlining_runner, FunctionInlining , ( ) , true ) ,
102- ( option_lowering_runner, OptionLowering , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) , true ) ,
103- ( processing_async_runner, ProcessingAsync , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) , true ) ,
104- ( processing_script_runner, ProcessingScript , ( ) , true ) ,
105- ( ssa_forming_runner, SsaForming , ( SsaFormingInput { rename_defs: true } ) , true ) ,
106- ( storage_lowering_runner, StorageLowering , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) , true ) ,
107- ( write_transforming_runner, WriteTransforming , ( ) , true ) ,
108- ( remove_unreachable, RemoveUnreachable , ( ) , false )
118+ ( common_subexpression_elimination_runner, [
119+ ( PathResolution , ( ) ) ,
120+ ( SymbolTableCreation , ( ) ) ,
121+ ( TypeChecking , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) ) ,
122+ ( CommonSubexpressionEliminating , ( ) )
123+ ] ) ,
124+ ( const_prop_unroll_and_morphing_runner, [
125+ ( PathResolution , ( ) ) ,
126+ ( SymbolTableCreation , ( ) ) ,
127+ ( TypeChecking , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) ) ,
128+ ( ConstPropUnrollAndMorphing , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) )
129+ ] ) ,
130+ ( destructuring_runner, [
131+ ( PathResolution , ( ) ) ,
132+ ( SymbolTableCreation , ( ) ) ,
133+ ( TypeChecking , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) ) ,
134+ ( Destructuring , ( ) )
135+ ] ) ,
136+ ( dead_code_elimination_runner, [
137+ ( PathResolution , ( ) ) ,
138+ ( SymbolTableCreation , ( ) ) ,
139+ ( TypeChecking , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) ) ,
140+ ( DeadCodeEliminating , ( ) )
141+ ] ) ,
142+ ( flattening_runner, [
143+ ( PathResolution , ( ) ) ,
144+ ( SymbolTableCreation , ( ) ) ,
145+ ( TypeChecking , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) ) ,
146+ ( Flattening , ( ) )
147+ ] ) ,
148+ ( function_inlining_runner, [
149+ ( PathResolution , ( ) ) ,
150+ ( SymbolTableCreation , ( ) ) ,
151+ ( TypeChecking , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) ) ,
152+ ( FunctionInlining , ( ) )
153+ ] ) ,
154+ ( option_lowering_runner, [
155+ ( PathResolution , ( ) ) ,
156+ ( SymbolTableCreation , ( ) ) ,
157+ ( TypeChecking , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) ) ,
158+ ( OptionLowering , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) )
159+ ] ) ,
160+ ( processing_async_runner, [
161+ ( PathResolution , ( ) ) ,
162+ ( SymbolTableCreation , ( ) ) ,
163+ ( TypeChecking , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) ) ,
164+ ( ProcessingAsync , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) )
165+ ] ) ,
166+ ( processing_script_runner, [
167+ ( PathResolution , ( ) ) ,
168+ ( SymbolTableCreation , ( ) ) ,
169+ ( TypeChecking , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) ) ,
170+ ( ProcessingScript , ( ) )
171+ ] ) ,
172+ ( ssa_forming_runner, [
173+ ( PathResolution , ( ) ) ,
174+ ( SymbolTableCreation , ( ) ) ,
175+ ( TypeChecking , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) ) ,
176+ ( SsaForming , ( SsaFormingInput { rename_defs: true } ) )
177+ ] ) ,
178+ ( storage_lowering_runner, [
179+ ( PathResolution , ( ) ) ,
180+ ( SymbolTableCreation , ( ) ) ,
181+ ( TypeChecking , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) ) ,
182+ ( StorageLowering , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) )
183+ ] ) ,
184+ ( write_transforming_runner, [
185+ ( PathResolution , ( ) ) ,
186+ ( SymbolTableCreation , ( ) ) ,
187+ ( TypeChecking , ( TypeCheckingInput :: new( NetworkName :: TestnetV0 ) ) ) ,
188+ ( WriteTransforming , ( ) )
189+ ] ) ,
190+ ( remove_unreachable, [
191+ ( RemoveUnreachable , ( ) )
192+ ] )
109193 }
110194 } ;
111195}
112196
113- /// Macro to generate a single runner function for a compiler pass .
197+ /// Macro to generate a single runner function for compiler passes .
114198///
115199/// Each runner:
116200/// - Sets up a BufferEmitter and Handler for error/warning reporting.
117201/// - Parse the test into an AST.
118- /// - Runs the first three fixed passes: PathResolution, SymbolTableCreation, TypeChecking.
119- /// - Runs the specified compiler pass.
202+ /// - Runs the specified list of compiler passes sequentially.
120203/// - Returns the resulting AST or formatted errors/warnings.
121204macro_rules! make_runner {
122- ( $runner_name: ident, $ pass: ident, $input: expr, $run_prelude : expr ) => {
205+ ( $runner_name: ident, [ $ ( ( $ pass: ident, $input: expr) ) , * $ ( , ) ? ] ) => {
123206 fn $runner_name( source: & str ) -> String {
124207 let buf = BufferEmitter :: new( ) ;
125208 let handler = Handler :: new( buf. clone( ) ) ;
@@ -138,28 +221,12 @@ macro_rules! make_runner {
138221 Err ( ( ) ) => return format!( "{}{}" , buf. extract_errs( ) , buf. extract_warnings( ) ) ,
139222 } ;
140223
141- // Run these three passes before the tested pass; they populate symbol & type tables,
142- // which are required for the following compiler pass to function correctly.
143- // Type checking may be disabled by argument
144- if $run_prelude {
145- if handler. extend_if_error( PathResolution :: do_pass( ( ) , & mut state) ) . is_err( ) {
224+ // Run the specified passes sequentially
225+ $(
226+ if handler. extend_if_error( $pass:: do_pass( $input, & mut state) ) . is_err( ) {
146227 return format!( "{}{}" , buf. extract_errs( ) , buf. extract_warnings( ) ) ;
147228 }
148- if handler. extend_if_error( SymbolTableCreation :: do_pass( ( ) , & mut state) ) . is_err( ) {
149- return format!( "{}{}" , buf. extract_errs( ) , buf. extract_warnings( ) ) ;
150- }
151- if handler
152- . extend_if_error( TypeChecking :: do_pass( TypeCheckingInput :: new( state. network) , & mut state) )
153- . is_err( )
154- {
155- return format!( "{}{}" , buf. extract_errs( ) , buf. extract_warnings( ) ) ;
156- }
157- }
158-
159- // Run the specific pass
160- if handler. extend_if_error( $pass:: do_pass( $input, & mut state) ) . is_err( ) {
161- return format!( "{}{}" , buf. extract_errs( ) , buf. extract_warnings( ) ) ;
162- }
229+ ) *
163230
164231 // Success: return AST with any warnings
165232 format!( "{}{}" , buf. extract_warnings( ) , state. ast. ast)
@@ -170,9 +237,9 @@ macro_rules! make_runner {
170237
171238/// Macro to generate all runners from the compiler_passes table.
172239macro_rules! make_all_runners {
173- ( $( ( $runner: ident, $pass : ident , $input : tt , $run_prelude : tt) ) ,* $( , ) ?) => {
240+ ( $( ( $runner: ident, $passes : tt) ) ,* $( , ) ?) => {
174241 $(
175- make_runner!( $runner, $pass , $input , $run_prelude ) ;
242+ make_runner!( $runner, $passes ) ;
176243 ) *
177244 } ;
178245}
@@ -182,23 +249,37 @@ compiler_passes!(make_all_runners);
182249///
183250/// Each test function:
184251/// - Uses the runner function generated above.
185- /// - Uses `leo_test_framework::run_tests` with a path derived from the pass struct name.
252+ /// - Uses `leo_test_framework::run_tests` with a path derived from the last pass struct name (the actual pass being tested) .
186253/// - Uses `paste::paste!` to safely concatenate identifiers.
187254macro_rules! make_all_tests {
188- ( $( ( $runner: ident, $ pass: ident, $input: tt, $run_prelude : tt ) ) ,* $( , ) ?) => {
255+ ( $( ( $runner: ident, [ $ ( ( $ pass: ident, $input: tt) ) , * $ ( , ) ? ] ) ) ,* $( , ) ?) => {
189256 $(
190257 paste:: paste! {
191258 #[ test]
192259 #[ serial]
193260 fn [ <$runner _test>] ( ) {
194- // Automatically derive the snake_case directory name from the pass name
195- leo_test_framework:: run_tests(
196- concat!( "passes/" , stringify!( [ <$pass: snake>] ) ) ,
197- $runner,
198- ) ;
261+ // Automatically derive the snake_case directory name from the last pass name (the actual pass being tested)
262+ // We need to extract the last pass from the list
263+ make_all_tests_inner!( $runner, [ $( ( $pass, $input) ) ,* ] ) ;
199264 }
200265 }
201266 ) *
202267 } ;
203268}
269+
270+ /// Helper macro to extract the last pass name from the list.
271+ macro_rules! make_all_tests_inner {
272+ ( $runner: ident, [ ( $pass: ident, $input: tt) ] ) => {
273+ paste:: paste! {
274+ leo_test_framework:: run_tests(
275+ concat!( "passes/" , stringify!( [ <$pass: snake>] ) ) ,
276+ $runner,
277+ ) ;
278+ }
279+ } ;
280+ ( $runner: ident, [ ( $pass: ident, $input: tt) , $( ( $rest_pass: ident, $rest_input: tt) ) ,+ $( , ) ?] ) => {
281+ make_all_tests_inner!( $runner, [ $( ( $rest_pass, $rest_input) ) ,+] ) ;
282+ } ;
283+ }
284+
204285compiler_passes ! ( make_all_tests) ;
0 commit comments