I tried to do something like this where an outer macro takes comma separate expressions and an inner macro takes different behaviour depending on whether it is a literal or not. I also wanted to handle array literals and it doesn't work. I'm assuming this is a limitation of macros, but is there a workaround?
Playground
macro_rules! example {
($($e:expr),+) => {
$(inner!($e)),+
};
}
macro_rules! inner {
($e:literal) => {
// logic for literals
};
([$($e:literal),+]) => { // <-- added this branch
// logic for array literals
};
($e:expr) => {
// otherwise
}
}
fn main() {
example!(123); // works
example!([123]); // doesn't work, goes into $e:expr branch
}
Yes it is a limitation of macros which is documented by the tool which would be the direct solution for your problem:
Otherwise, the way people usually work around the problem is by mixing both macros into a single-expression muncher:
macro_rules! example {( $($input:tt)* ) => (
muncher! {
out: { /* this will be filled as we recurse */ }
$($input)*
}
)}
macro_rules! muncher {
(
out: { $($out:tt)* }
// CASE:
$e:literal
$(, $($rest:tt)*)?
) => (muncher! {
out: { $($out)*
/* inline here the logic for literals */ ,
}
$($($rest)*)?
});
(
out: { $($out:tt)* }
// CASE:
[$($e:literal),+ $(,)?]
$(, $($rest:tt)*)?
) => (muncher! {
out: { $($out)*
/* inline here the logic for array literals */ ,
}
$($($rest)*)?
});
(
out: { $($out:tt)* }
// CASE:
$e:expr
$(, $($rest:tt)*)?
) => (muncher! {
out: { $($out)*
/* otherwise */ ,
}
$($($rest)*)?
});
(
out: {
/* the shape of your output, _e.g._, */
$($out:expr ,)*
}
// CASE:
/* nothing left, end of recursion */
) => (
// your actual combined output, _e.g._, */
[ $($out),* ]
);
}
1 Like
system
Closed
April 1, 2023, 12:49pm
3
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.