@@ -90,10 +90,14 @@ pub macro mir {
90
90
(
91
91
$( let $local_decl: ident $( : $local_decl_ty: ty) ? ; ) *
92
92
93
- $entry_block: block
93
+ {
94
+ $( $entry: tt) *
95
+ }
94
96
95
97
$(
96
- $block_name: ident = $block: block
98
+ $block_name: ident = {
99
+ $( $block: tt) *
100
+ }
97
101
) *
98
102
) => { {
99
103
// First, we declare all basic blocks.
@@ -109,15 +113,146 @@ pub macro mir {
109
113
let $local_decl $( : $local_decl_ty) ? ;
110
114
) *
111
115
116
+ :: core:: intrinsics:: mir:: __internal_extract_let!( $( $entry) * ) ;
117
+ $(
118
+ :: core:: intrinsics:: mir:: __internal_extract_let!( $( $block) * ) ;
119
+ ) *
120
+
112
121
{
113
122
// Finally, the contents of the basic blocks
114
- $entry_block;
123
+ :: core:: intrinsics:: mir:: __internal_remove_let!( {
124
+ { }
125
+ { $( $entry) * }
126
+ } ) ;
115
127
$(
116
- $block;
128
+ :: core:: intrinsics:: mir:: __internal_remove_let!( {
129
+ { }
130
+ { $( $block) * }
131
+ } ) ;
117
132
) *
118
133
119
134
RET
120
135
}
121
136
}
122
137
} }
123
138
}
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