Reputation: 2517
I've been tinkering around with Rust's macro system for a while now, and recently got interested in nesting two macros together, like this:
macro_rules! foo {
() => {
macro_rules! bar {
() => {}
}
}
}
Relating to the example, I wanted to dynamically make parameter names in bar!
which were passed into foo!
, to obtain a result like this:
foo!(bar, baz);
// The above call creates a macro, bar!, with the following definition:
macro_rules! bar {
( $bar:literal, $baz:literal ) => {
println!("{}", stringify!( $bar, $baz ));
}
}
To give a better idea of what I'm trying to do, here was my initial thought process on how this would work (this should parse exactly to the definition shown above):
macro_rules! foo {
( $( $attr:ident ), * ) => {
macro_rules! bar {
// the designator $$attr:literal consists of two parts - $attr,
// which should be replaced with the arguments passed into foo!,
// and $__:literal, which creates a literal designator for each of
// the arguments from foo! for bar!
( $( $$attr:literal ), * ) => {
// $( $$attr ), * follows the same logic as above
println!("{}", stringify!( $( $$attr ), * ));
}
}
}
}
This does look very weird, and sure enough, it didn't work, giving an error mentioning meta-variable expressions and this issue, both of which looked unrelated (full error can be seen on the playground).
Does anyone know if it is possible to dynamically create a macro with variables like this, and if so, how to do it?
Upvotes: 3
Views: 933
Reputation: 70840
Yes, however...
You cannot insert the $
sign, as it is reserved for metavariables.
You have two options to tackle that.
On stable, you need to pass $
to the macro. Then it can refer to it using the metavariable.
macro_rules! foo {
( $dollar:tt $( $attr:ident ), * ) => {
macro_rules! bar {
( $( $dollar $attr:literal ), * ) => {
println!("{}", stringify!( $( $dollar $attr ), * ));
}
}
}
}
foo!($ bar, baz);
On nightly, you can escape the dollar sign: this is part of the feature macro_metavar_expr
the compiler mentioned. You do it using $$
:
#![feature(macro_metavar_expr)]
macro_rules! foo {
( $( $attr:ident ), * ) => {
macro_rules! bar {
( $( $$ $attr:literal ), * ) => {
println!("{}", stringify!( $( $$ $attr ), * ));
}
}
}
}
foo!(bar, baz);
Upvotes: 7