Почему я получаю "неожиданный токен" при попытке вызвать внутренний макрос с аргументом внешнего макроса?
Я не понимаю эту ошибку при попытке передать выражение, полученное higher!
макрос в lower!
макрос:
// 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
Я ожидаю, что этот последний токен будет ожидаться правилом в lower!
, но компилятор говорит мне, что это неожиданно. Что мне здесь не хватает? Как я могу передать выражение, полученное higher!
как $xstuff
в lower!
?
1 ответ
После звонка higher!
, x(7)
был проанализирован как полное выражение, содержащееся в макросе $xstuff
:
($xstuff:expr, $a:expr) => { /* ... */ }
// ^~~~
Однако ни одно из правил макроса для lower!
принять произвольное выражение в качестве первого аргумента, они принимают только маркер x
:
(x, $a:expr) => { /* ... */ }
// ^
(x($b:expr), $a:expr) => { /* ... */ }
// ^
Самый простой способ - установить те же ограничения на x
в более высоком макросе:
macro_rules! higher {
(x($xstuff:expr), $a:expr) => {
lower!(x($xstuff), $a)
};
}
Альтернативное решение (которое изменяет синтаксис вызова) состоит в том, чтобы не сразу анализировать x(7)
в качестве выражения, но вместо этого - набор токенов. Вам нужно добавить дополнительную группировку на сайте вызовов, чтобы парсер знал, когда остановиться, хотя:
macro_rules! higher {
(($($xstuff:tt)*), $a:expr) => {
lower!($($xstuff)*, $a)
};
}
fn main() {
higher!((x(7)), '9');
}
Смотрите также: