1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
//@ run-pass
#![feature(macro_metavar_expr)]
/// Count the number of idents in a macro repetition.
macro_rules! count_idents {
( $( $i:ident ),* ) => {
${count($i)}
};
}
/// Count the number of idents in a 2-dimensional macro repetition.
macro_rules! count_idents_2 {
( $( [ $( $i:ident ),* ] ),* ) => {
${count($i)}
};
}
/// Mostly counts the number of OUTER-MOST repetitions
macro_rules! count_depth_limits {
( $( { $( [ $( $outer:ident : ( $( $inner:ident )* ) )* ] )* } )* ) => {
(
(
${count($inner)},
${count($inner, 0)},
${count($inner, 1)},
${count($inner, 2)},
${count($inner, 3)},
),
(
${count($outer)},
${count($outer, 0)},
${count($outer, 1)},
${count($outer, 2)},
),
)
};
}
/// Produce (index, len) pairs for literals in a macro repetition.
/// The literal is not included in the output, so this macro uses the
/// `ignore` meta-variable expression to create a non-expanding
/// repetition binding.
macro_rules! enumerate_literals {
( $( ($l:stmt) ),* ) => {
[$( ${ignore($l)} (${index()}, ${len()}) ),*]
};
}
/// Produce index and len tuples for literals in a 2-dimensional
/// macro repetition.
macro_rules! enumerate_literals_2 {
( $( [ $( ($l:literal) ),* ] ),* ) => {
[
$(
$(
(
${index(1)},
${len(1)},
${index(0)},
${len(0)},
$l
),
)*
)*
]
};
}
/// Generate macros that count idents and then add a constant number
/// to the count.
///
/// This macro uses dollar escaping to make it unambiguous as to which
/// macro the repetition belongs to.
macro_rules! make_count_adders {
( $( $i:ident, $b:literal );* ) => {
$(
macro_rules! $i {
( $$( $$j:ident ),* ) => {
$b + $${count($j)}
};
}
)*
};
}
make_count_adders! { plus_one, 1; plus_five, 5 }
/// Generate a macro that allows selection of a particular literal
/// from a sequence of inputs by their identifier.
///
/// This macro uses dollar escaping to make it unambiguous as to which
/// macro the repetition belongs to, and to allow expansion of an
/// identifier the name of which is not known in the definition
/// of `make_picker`.
macro_rules! make_picker {
( $m:ident => $( $i:ident ),* ; $p:ident ) => {
macro_rules! $m {
( $( $$ $i:literal ),* ) => {
$$ $p
};
}
};
}
make_picker!(first => a, b; a);
make_picker!(second => a, b; b);
fn main() {
assert_eq!(count_idents!(a, b, c), 3);
assert_eq!(count_idents_2!([a, b, c], [d, e], [f]), 6);
assert_eq!(
count_depth_limits! {
{
[ A: (a b c) D: (d e f) ]
[ G: (g h) I: (i j k l m) ]
[ N: (n) ]
}
{
[ O: (o) P: (p q) R: (r s) ]
[ T: (t u v w x y z) ]
}
},
((26, 26, 9, 5, 2), (9, 9, 5, 2))
);
assert_eq!(enumerate_literals![("foo"), ("bar")], [(0, 2), (1, 2)]);
assert_eq!(
enumerate_literals_2![
[("foo"), ("bar"), ("baz")],
[("qux"), ("quux"), ("quuz"), ("xyzzy")]
],
[
(0, 2, 0, 3, "foo"),
(0, 2, 1, 3, "bar"),
(0, 2, 2, 3, "baz"),
(1, 2, 0, 4, "qux"),
(1, 2, 1, 4, "quux"),
(1, 2, 2, 4, "quuz"),
(1, 2, 3, 4, "xyzzy"),
]
);
assert_eq!(plus_one!(a, b, c), 4);
assert_eq!(plus_five!(a, b), 7);
assert_eq!(first!(1, 2), 1);
assert_eq!(second!(1, 2), 2);
}
|