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
+270
Original file line number
Diff line number
Diff line change
@@ -196,6 +196,276 @@ compiler knows how to expand them properly:
196
196
not have the same number. This requirement applies to every layer of nested
197
197
repetitions.
198
198
199
+
## Metavariable expressions
200
+
201
+
Metavariable expressions live within a special braced syntax `${...}` and are function-like operators used to access "meta" information about how macros get matched and expanded, such as how many items get matched in a repetition group. This information is typically difficult or even
202
+
impossible to otherwise obtain.
203
+
204
+
### count($ident, depth=0)
205
+
206
+
Expands to an unsuffixed integer literal representing the number of times a ***repetition*** repeats in total. That is, this will be the number of times that a repetition would be expanded.
207
+
208
+
The output of `count` depends on where it is placed as well the provided index. If no index is provided, then it will always start at the innermost level.
209
+
210
+
```rust
211
+
macro_rules!count_idents {
212
+
( $( $i:ident ),* ) => {
213
+
${count($i)}
214
+
};
215
+
}
216
+
217
+
fnmain() {
218
+
assert_eq!(count_idents!(a, b, c), 3);
219
+
}
220
+
```
221
+
222
+
If repetitions are nested, then the optional depth parameter can be used to
223
+
count the repetitions of a parent repetition group.
224
+
225
+
Let `M` be the number of repetition groups in the matcher, `T` the depth placement in the transcriber and `C` the written depth in `count`, then it is possible to infer that `M > T + C`.
226
+
227
+
We are counting how often the repetition group `C` up from a metavariable in the matcher occurs inside the current iteration of the `T` outer repetitions in the transcriber, effectively making the metavariable a reference or starting point.
228
+
229
+
```rust
230
+
macro_rules!count_value {
231
+
( $( $name:ident:$( $value:literal ),* );+ ) => {
232
+
// Count the total number of times that the (innermost) group
233
+
// containing `$value` gets matched.
234
+
${count($value)}
235
+
// This is the same as `${count($value, 0)}`
236
+
};
237
+
}
238
+
macro_rules!count_name1 {
239
+
( $( $name:ident:$( $value:literal ),* );+ ) => {
240
+
// This is one way to get the number of times that the group
`count` can not be placed inside the repetition depth of its referenced metavariable, otherwise the output would always be 1.
305
+
306
+
### ignore($ident)
307
+
308
+
Sometimes it is desired to repeat an expansion the same number of times as a metavariable repeats but without actually expanding the metavariable.
309
+
310
+
```rust
311
+
macro_rules!count {
312
+
( $( $i:ident ),* ) => {{
313
+
0$( +1${ignore($i)} )*
314
+
}};
315
+
}
316
+
fnmain() {
317
+
assert_eq!(count!(a, b, c), 3);
318
+
}
319
+
```
320
+
321
+
The `ignore` metavariable acts as if the ident was used for the purposes of repetition, but expands to nothing.
322
+
323
+
### index(depth=0)
324
+
325
+
Expands to an unsuffixed integer literal representing the current iteration index of a ***repetition*** at a given depth.
326
+
327
+
The output of `index` depends on where it is placed as well the provided index. If no index is provided, then it will always start at the innermost level.
Expands to an unsuffixed integer literal representing the sum or length of a ***repetition*** at a given depth.
411
+
412
+
The output of `len` depends on where it is placed as well the provided index. If no index is provided, then it will always start at the innermost level.
413
+
414
+
```rust
415
+
macro_rules!array {
416
+
( $( $i:ident ),* ) => {
417
+
[$( ${len()}, )*]
418
+
};
419
+
}
420
+
421
+
fnmain() {
422
+
assert_eq!(array!(A, B, C), [3, 3, 3]);
423
+
}
424
+
```
425
+
426
+
If repetitions are nested, then the optional depth parameter can be used to
427
+
count the repetitions of a parent repetition group.
428
+
429
+
```rust
430
+
macro_rules!innermost0 {
431
+
( $( $a:ident:$( $b:literal ),* );+ ) => {
432
+
[$( $( ${ignore($b)} ${len()}, )* )+]
433
+
};
434
+
}
435
+
436
+
macro_rules!innermost1 {
437
+
( $( $a:ident:$( $b:literal ),* );+ ) => {
438
+
[$( $( ${ignore($b)} ${len(1)}, )* )+]
439
+
};
440
+
}
441
+
442
+
macro_rules!outermost {
443
+
( $( $a:ident:$( $b:literal ),* );+ ) => {
444
+
[$( ${ignore($a)} ${len()}, )+]
445
+
};
446
+
}
447
+
448
+
fnmain() {
449
+
// 1 2 3 = 3 elements
450
+
// 4 5 = 2 elements
451
+
//
452
+
// 3 and 2 elements repeating 3 and 2 times in the innermost loop
0 commit comments