Using a simple recursive macro like the example below, its common to take the first argument, then glob the rest.
macro_rules! count_tts {
() => {0usize};
($_head:tt $($tail:tt)*) => {1usize + count_tts!($($tail)*)};
}
Is there a way to recursively take the last argument?
This makes it possible to:
- Handle the arguments in reverse.
- Take all the previous arguments into account (count them for example, see related question)
Something like ($($head:tt)* $tail:tt)
... but this doesn't work.
There is no "backtracking" in the macro parser, so no you can't do this directly with $($head:tt)* $tail:tt
. But you can do it by reversing it yourself.
macro_rules! concat_reverse {
([] $($reversed:tt)*) => {
concat!($(stringify!($reversed)),*) // base case
};
([$first:tt $($rest:tt)*] $($reversed:tt)*) => {
concat_reverse!([$($rest)*] $first $($reversed)*) // recursion
};
}
fn main() {
println!("{}", concat_reverse!([e d c b a]))
// output: abcde
}
The macro trace looks like:
concat_reverse!([e d c b a])
== concat_reverse!([d c b a] e)
== concat_reverse!([c b a] d e)
== concat_reverse!([b a] c d e)
== concat_reverse!([a] b c d e)
== concat_reverse!([] a b c d e)
== concat!(stringify!(a), stringify!(b), stringify!(c), stringify!(d), stringify!(e))
You could do some "map" and "reduce" operation (e.g. for counting) in the recursion phase.
Note that this method will eat your recursion depth, you may need to raise your #![recursion_limit="..."]
.