You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/macros-by-example.md
+70
Original file line number
Diff line number
Diff line change
@@ -193,6 +193,76 @@ compiler knows how to expand them properly:
193
193
not have the same number. This requirement applies to every layer of nested
194
194
repetitions.
195
195
196
+
## Metavariable expressions
197
+
198
+
Metavariable expressions in declarative macros provide expansions for information about metavariables that are otherwise not easily obtainable.
199
+
200
+
| Expression | Meaning |
201
+
|----------------------------|------------|
202
+
|`${ignore(ident)}`| Binds `$ident` for repetition, but expands to nothing. |
203
+
|`$$`| Expands to a single `$`, for removing ambiguity in recursive macro definitions. |
204
+
205
+
### Ignore
206
+
207
+
`${ignore(ident)}` repeats an expansion the same number of times a metavariable repeats without actually expanding the metavariable.
208
+
209
+
```rust
210
+
macro_rules!count {
211
+
( $( $ignored_identifier:ident ),* ) => {{
212
+
0$( +1${ignore(ignored_identifier)} )*
213
+
}};
214
+
}
215
+
216
+
fnmain() {
217
+
assert_eq!(count!(T, T, T), 3);
218
+
}
219
+
```
220
+
221
+
The above snippet will expand to a sequence of numbers respecting the number of times that `ignored_identifier` repeats, resulting in a final `0 + 1 + 1 + 1` output.
222
+
223
+
### Dollar-dollar ($$)
224
+
225
+
`$$` expands to a single `$`.
226
+
227
+
Since metavariable expressions always apply during the expansion of a macro, they cannot be used in recursive macro definitions and this is where `$$` expressions comes into play, i.e., `$$` can se used to resolve ambiguities in nested macros.
228
+
229
+
```rust
230
+
#![feature(macro_metavar_expr)]
231
+
232
+
macro_rules!foo_error {
233
+
() => {
234
+
macro_rules!bar_error {
235
+
( $( $any:tt )* ) => { $( $any )* };
236
+
// ^^^^^^^^^^^ error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth
237
+
}
238
+
};
239
+
}
240
+
241
+
macro_rules!foo_ok {
242
+
() => {
243
+
macro_rules!bar_ok {
244
+
( $$( $any:tt )* ) => { $$( $any )* };
245
+
}
246
+
};
247
+
}
248
+
249
+
fnmain() {
250
+
foo!();
251
+
}
252
+
```
253
+
254
+
One consequence of such expansion is that deeper nested levels make dollar-dollar declarations grown linearly, starting at `$$`, then `$$$$`, then `$$$$$` and so on. This is also necessary to be fully featured so that it is possible to specify names of metavariables using other metavariables at each nesting level.
255
+
256
+
```
257
+
$foo => bar => bar // Evaluate foo at level 1
258
+
$$foo => $foo => bar // Evaluate foo at level 2
259
+
$$$foo => $bar => baz // Evaluate foo at level 1, and use that as a name at level 2
0 commit comments