// 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, length) 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()}, ${length()}) ),*] }; } /// Produce index and length tuples for literals in a 2-dimensional /// macro repetition. macro_rules! enumerate_literals_2 { ( $( [ $( ($l:literal) ),* ] ),* ) => { [ $( $( ( ${index(1)}, ${length(1)}, ${index(0)}, ${length(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, 2, 5, 9, 26), (9, 2, 5, 9)) ); 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); }