I'd like to write a macro that defines macros that define enums with attrs, something like this:
macro_rules! define_enum_definer {
{
$($variant: ident => $t: ty,)+
}
=> {
macro_rules! define_enum {
($(#[$attrs:meta])*$name: ident($container: ident)) => {
$(#[$attrs])*
enum $name {
$($variant($container<$t>),)+
}
};
}
};
}
define_enum_definer! { I32 => i32, I64 => i64, }
define_enum!(
#[derive(Clone, Debug)]
#[non_exhaustive]
DynTypedVec(Vec)
);
fn main() {
let x = DynTypedVec::I32(vec![1, 2, 3]);
println!("{:?}", x);
}
But this fails with
error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth
--> src/main.rs:12:9
|
12 | ($(#[$attrs:meta])*$name: ident($container: ident)) => {
| ^^^^^^^^^^^^^^^^
It's trying to repeat the syntax variable in the outer macro, but I need it to repeat for the inner macro. I tried to escape the inner repeats with $dollar
, but that too fails with
error: missing fragment specifier
--> src/main.rs:12:8
|
12 | ($dollar(#[$attrs:meta])*$name: ident($container: ident)) => {
| ^^^^^^^
...
22 | define_inner_macro! { Foo => i32, Bar => i64, }
| ----------------------------------------------- in this macro invocation
Is there a way around this, or is my only recourse to use procedural macros?
You can use the trick here: https://github.com/rust-lang/rust/issues/35853#issuecomment-415993963. I'll just copy their code below; adapting it is simple enough.
macro_rules! with_dollar_sign { ($($body:tt)*) => { macro_rules! __with_dollar_sign { $($body)* } __with_dollar_sign!($); } } macro_rules! make_println { ($name:ident, $fmt:expr) => { with_dollar_sign! { ($d:tt) => { macro_rules! $name { ($d($d args:expr),*) => { // (1) println!($fmt, $d($d args),*); // (2) } } } } }; } make_println!(my_dbg, "{:?}"); fn main() { my_dbg!(42); }