I don't understand this failure while trying to pass the expression received by the higher!
macro to the lower!
macro:
// A low-level macro using only Rust primitives.
macro_rules! lower {
(x, $a:expr) => {
println!("x is {}", $a);
};
(x($b:expr), $a:expr) => {
println!("x({}) is rather {}", $b, $a);
};
}
// A higher-level macro using my own previous macro.
macro_rules! higher {
($xstuff:expr, $a:expr) => {
// Here, I expect transferring the expression $xstuff to lower!.. but it fails.
lower!($xstuff, $a)
};
}
fn main() {
lower!(x, '5'); // x is 5
lower!(x(8), '6'); // x(8) is rather 6
higher!(x(7), '9');
}
error: no rules expected the token `x(7)`
--> src/main.rs:15:16
|
2 | macro_rules! lower {
| ------------------ when calling this macro
...
15 | lower!($xstuff, $a)
| ^^^^^^^ no rules expected this token in macro call
...
23 | higher!(x(7), '9');
| ------------------- in this macro invocation
I would expect this last token to be expected by the rule in lower!
, but the compiler tells me it is unexpected. What am I missing here? How can I transfer the expression received by higher!
as $xstuff
to lower!
?
After the call to higher!
, x(7)
has been parsed as a complete expression held by the macro variable $xstuff
:
($xstuff:expr, $a:expr) => { /* ... */ }
// ^~~~
However, neither of the macro rules for lower!
accept an arbitrary expression as the first argument, they only accept the token x
:
(x, $a:expr) => { /* ... */ }
// ^
(x($b:expr), $a:expr) => { /* ... */ }
// ^
The easiest fix is to place the same restrictions about the x
in the higher macro:
macro_rules! higher {
(x($xstuff:expr), $a:expr) => {
lower!(x($xstuff), $a)
};
}
An alternate solution (that changes the calling syntax) is to not immediately parse x(7)
as an expression, but instead a collection of token trees. You need to add additional grouping at the call site so that the parser knows when to stop though:
macro_rules! higher {
(($($xstuff:tt)*), $a:expr) => {
lower!($($xstuff)*, $a)
};
}
fn main() {
higher!((x(7)), '9');
}
See also: