@@ -90,10 +90,14 @@ pub macro mir {
9090 (
9191 $( let $local_decl: ident $( : $local_decl_ty: ty) ? ; ) *
9292
93- $entry_block: block
93+ {
94+ $( $entry: tt) *
95+ }
9496
9597 $(
96- $block_name: ident = $block: block
98+ $block_name: ident = {
99+ $( $block: tt) *
100+ }
97101 ) *
98102 ) => { {
99103 // First, we declare all basic blocks.
@@ -109,15 +113,146 @@ pub macro mir {
109113 let $local_decl $( : $local_decl_ty) ? ;
110114 ) *
111115
116+ :: core:: intrinsics:: mir:: __internal_extract_let!( $( $entry) * ) ;
117+ $(
118+ :: core:: intrinsics:: mir:: __internal_extract_let!( $( $block) * ) ;
119+ ) *
120+
112121 {
113122 // Finally, the contents of the basic blocks
114- $entry_block;
123+ :: core:: intrinsics:: mir:: __internal_remove_let!( {
124+ { }
125+ { $( $entry) * }
126+ } ) ;
115127 $(
116- $block;
128+ :: core:: intrinsics:: mir:: __internal_remove_let!( {
129+ { }
130+ { $( $block) * }
131+ } ) ;
117132 ) *
118133
119134 RET
120135 }
121136 }
122137 } }
123138}
139+
140+ /// Helper macro that extracts the `let` declarations out of a bunch of statements.
141+ ///
142+ /// This macro is written using the "statement muncher" strategy. Each invocation parses the first
143+ /// statement out of the input, does the appropriate thing with it, and then recursively calls the
144+ /// same macro on the remainder of the input.
145+ #[ doc ( hidden) ]
146+ pub macro __internal_extract_let {
147+ // If it's a `let` like statement, keep the `let`
148+ (
149+ let $var: ident $( : $ty: ty) ? = $expr: expr; $( $rest: tt) *
150+ ) => {
151+ let $var $( : $ty) ?;
152+ :: core:: intrinsics:: mir:: __internal_extract_let!( $( $rest) * ) ;
153+ } ,
154+ // Otherwise, output nothing
155+ (
156+ $stmt: stmt; $( $rest: tt) *
157+ ) => {
158+ :: core:: intrinsics:: mir:: __internal_extract_let!( $( $rest) * ) ;
159+ } ,
160+ (
161+ $expr: expr
162+ ) => { }
163+ }
164+
165+ /// Helper macro that removes the `let` declarations from a bunch of statements.
166+ ///
167+ /// Because expression position macros cannot expand to statements + expressions, we need to be
168+ /// slightly creative here. The general strategy is also statement munching as above , but the output
169+ /// of the macro is "stored" in the subsequent macro invocation. Easiest understood via example:
170+ /// ```text
171+ /// invoke!(
172+ /// {
173+ /// {
174+ /// x = 5;
175+ /// }
176+ /// {
177+ /// let d = e;
178+ /// Call()
179+ /// }
180+ /// }
181+ /// )
182+ /// ```
183+ /// becomes
184+ /// ```text
185+ /// invoke!(
186+ /// {
187+ /// {
188+ /// x = 5;
189+ /// d = e;
190+ /// }
191+ /// {
192+ /// Call()
193+ /// }
194+ /// }
195+ /// )
196+ /// ```
197+ #[ doc ( hidden) ]
198+ pub macro __internal_remove_let {
199+ // If it's a `let` like statement, remove the `let`
200+ (
201+ {
202+ {
203+ $( $already_parsed: tt) *
204+ }
205+ {
206+ let $var: ident $( : $ty: ty ) ? = $expr: expr;
207+ $( $rest: tt) *
208+ }
209+ }
210+ ) => { :: core:: intrinsics:: mir:: __internal_remove_let!(
211+ {
212+ {
213+ $( $already_parsed) *
214+ $var = $expr;
215+ }
216+ {
217+ $( $rest) *
218+ }
219+ }
220+ ) } ,
221+ // Otherwise, keep going
222+ (
223+ {
224+ {
225+ $( $already_parsed: tt) *
226+ }
227+ {
228+ $stmt: stmt;
229+ $( $rest: tt) *
230+ }
231+ }
232+ ) => { :: core:: intrinsics:: mir:: __internal_remove_let!(
233+ {
234+ {
235+ $( $already_parsed) *
236+ $stmt;
237+ }
238+ {
239+ $( $rest) *
240+ }
241+ }
242+ ) } ,
243+ (
244+ {
245+ {
246+ $( $already_parsed: tt) *
247+ }
248+ {
249+ $expr: expr
250+ }
251+ }
252+ ) => {
253+ {
254+ $( $already_parsed) *
255+ $expr
256+ }
257+ } ,
258+ }
0 commit comments