【问题标题】:Why does a macro call inside another macro not expand, but instead I get "no rules expected the token `!`"?为什么另一个宏内部的宏调用没有扩展,而是我得到“没有规则需要令牌`!`”?
【发布时间】:2020-12-08 17:52:10
【问题描述】:

我在宏中调用宏,即

macro_rules! foo {
    (yes) => {
        true
    };
    () => {
        false
    };
}

macro_rules! baz {
    () => {
        [(); 0]
    };
    ($args: tt) => {
        $args
    };
}

macro_rules! parse_rule {
    ($rule: tt, $args: tt, $newline: expr) => {
        println!("The rule is {}, with args {:?}", $rule, $args);
        if $newline {
            println!()
        }
    };
}

macro_rules! bar {
    ($($rule: tt  $([$($args: tt),*])? $($flag: ident)?);+) => {
        $(parse_rule!($rule, baz!($([$($args),*])?), foo!($($flag)?)));+
    }
}

fn main() {
    bar!("hi" yes; "there" ["are", "some", "args"]; "no" yes);
}

编译器抱怨我在 parse_rule 调用中调用 baz

error: no rules expected the token `!`
  --> src/main.rs:30:33
   |
19 | macro_rules! parse_rule {
   | ----------------------- when calling this macro
...
30 |         $(parse_rule!($rule, baz!($([$($args),*])?), foo!($($flag)?)));+
   |                                 ^ no rules expected this token in macro call
...
35 |     bar!("hi" yes; "there" ["are", "some", "args"]; "no" yes);
   |     ---------------------------------------------------------- in this macro invocation
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

为什么不展开?

【问题讨论】:

    标签: rust compiler-errors macros


    【解决方案1】:

    宏是通过其未扩展的参数调用的。 macro_call!(arg)三个令牌树,而不是一个:

    macro_rules! example {
        ($($x:tt)+) => {
            $(eprintln!(">{}<", stringify!($x));)*
        }
    }
    
    fn main() {
        example!(macro_call!(arg));
    }
    
    >macro_call<
    >!<
    >(arg)<
    

    您的宏只允许单个令牌树 ($args: tt)。这与宏的名称相匹配,留下!。那没有任何东西匹配,所以你得到了你的错误。

    你可能想要$args: expr

    以前有没有办法扩展它?我想手动解析数组的一些元素

    据我所知,没有“更急切”的扩展。它已在各种 RFC 中提出(例如 Eager Macro Expansion — 2320)。

    我建议重排您的代码,以便 parse_rule 调用 foo / bar 本身,或者将 foo / bar 的逻辑直接烘焙到 parse_rule 中。内部规则对此很常见。

    另见:

    【讨论】:

    • 谢谢,那之前有没有办法扩展呢?我想手动解析数组的一些元素。
    • @lolad 没有“更急切”的扩展,没有。也许重排你的代码,使parse_rule 调用foo / bar 会起作用,或者将该逻辑直接烘焙到parse_rule 中。内部规则对此很常见 (What does an @ symbol mean in a Rust declarative macro?)。
    猜你喜欢
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多