为什么另一个宏内的宏调用不会扩展,而是得到“没有规则需要标记`!`”?

lol*_*lad 0 macros compiler-errors rust

我在宏中调用宏,即

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);
}
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

为什么它不扩展?

She*_*ter 5

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

\n
macro_rules! example {\n    ($($x:tt)+) => {\n        $(eprintln!(">{}<", stringify!($x));)*\n    }\n}\n\nfn main() {\n    example!(macro_call!(arg));\n}\n
Run Code Online (Sandbox Code Playgroud)\n
>macro_call<\n>!<\n>(arg)<\n
Run Code Online (Sandbox Code Playgroud)\n

您的宏仅允许单个标记树 ( $args: tt)。这与宏的名称匹配,留下!. 这与任何内容都不匹配,所以你会得到错误。

\n

你可能想要$args: expr

\n
\n

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

\n
\n

据我所知,还没有“更热切”的扩张。它已在各种 RFC 中建议(例如Eager Macro Expansion \xe2\x80\x94 2320)。

\n

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

\n

也可以看看:

\n\n