I apparently don't understand how scoping works with regards to macros. I'm trying to write a macro using the TT muncher pattern. I think I need to have an initial matching arm which declares a variable, then munching arms which build it as they consume sequences of tokens.
Here's an oversimplified thing that works, following the general pattern:
macro_rules! simple_muncher {
(__recursive) => {};
(__recursive $l : literal $($tail:tt)*) => {
{
println!("I see {}", $l);
simple_muncher!(__recursive $($tail)*);
}
};
($($tail:tt)*) => {
{
println!("Starting off!");
simple_muncher!(__recursive $($tail)*)
}
}
}
And here's one that doesn't work, because it doesn't see v
as being in scope:
macro_rules! scoped_muncher {
(__recursive) => {};
(__recursive $l : literal $($tail:tt)*) => {
{
v.push(stringify!($l));
simple_muncher!(__recursive $($tail)*);
}
};
($($tail:tt)*) => {
{
println!("Starting off!");
let mut v : Vec<&str> = Vec::<&str>::new();
scoped_muncher!(__recursive $($tail)*);
println!("Vector contains: {:?}", v)
}
}
}
But why doesn't it? For a simple call (scoped_muncher!(1)
, say) shouldn't it be outputting something like:
{
println!("Starting off!");
let mut v : Vec<&str> = Vec::<&str>::new();
{
v.push(stringify!(1));
}
println!("Vector contains: {:?}", v)
}
which is perfectly legal. Why is the macro saying that there's no v
in scope?
What's the rhyme or reason to what macros can or can't see?
Bonus question: even in the working version, it looks like I'll be generating a lot of nested scopes. Is there any way around that? There seem to be unclear rules of when you need the extra {}
block within the RHS of a macro arm, and when you don't.