(I'm fairly new to macros.) My patterns will contain optional flags that shall trigger additional code generation. I fail to find a way to query the presence of such a flag. Matching on any identifier is no problem as it has a name bound to it but the flag doesn't have a name. Due to the error message, I feel it would work as expected if it was possible to bind a syntax variable to the flag:
error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth
struct NodeA(Vec<u32>);
struct NodeB(u8);
struct NodeC(String);
trait Container {}
#[macro_export]
macro_rules! nodes {
($($Type:ty, $Variant:ident $(container)?;)*) => {
pub enum AnyNode {
$($Variant($Type),)*
}
$(
// this was meant to iterate 0 or 1 times depending on the presence of `container`
$(
impl Container for $Type {}
)*
)*
};
}
nodes!(
NodeA, A container;
NodeB, B;
NodeC, C container;
);
I could imagine that breaking this up into multiple patterns (one per entry, one with/out flag, …) could help, but so far It didn't manage to find one - and I was wondering if there's a more straight-forward solution.
pub struct NodeA(Vec<u32>);
pub struct NodeB(u8);
pub struct NodeC(String);
trait Container {}
#[macro_export]
macro_rules! nodes {
($($Type:ty, $Variant:ident $($flags:ident)?;)*) => {
pub enum AnyNode {
$($Variant($Type),)*
}
$(
// this was meant to iterate 0 or 1 times depending on the presence of `container`
nodes! { @if container in [$($flags)*] => {
impl Container for $Type {}
}}
)*
};
// Output nothing if list is empty
(@if container in [] => $tail:tt) => {};
// Output tail if list starts with `container`
(@if container in [container $($flags:tt)*] => {$($tail:tt)*}) => { $($tail)* };
// Recurse if list is non-empty, but doesn't start with `container`
(@if container in [$head:tt $($flags:tt)*] => $tail:tt) => {
nodes! { @if container in [$($flags)*] => $tail }
};
}
nodes!(
NodeA, A container;
NodeB, B;
NodeC, C container;
);
fn main() {
}
(Also had to fix a few unrelated things to get it to compile.)
Edit: should mention: you cannot do a repetition substitution based on something you matched but did not capture. There must be a capture involved in any repetition substitution.
Ok, wow - that solution wasn't exactly obvious to me
re your comment: I somehow expected it to be possible to add a capture to the constant (something like $my_constant:(constant)) without having to introduce an identifier (resulting in all those sub-patterns).
There are a lot of new patterns in your example that will help me on other occasions as well. Thank you!