< 返回版块

ugdbg 发表于 2020-08-04 18:35

Tags:macro


macro_rules! example {
    // A
    ($x:literal) => {
        concat!("a", $x)
    };
    // B
    (foo($x:literal)) => {
        concat!("b", $x)
    };
    // C
    (foo($x:literal),$($e:expr),*) => {
        concat!("c", ".foo(", $x, ")", example!{$($e),*})
    };
    // D
    ($x:literal,$($e:expr),*) => {
        concat!("d", ".foo(", $x, ")", example!{$($e),*})
    };
}

fn main() {
    // 进入规则A,正常输出bbar
    println!(
        "{}",
        example! {
            foo("bar")
        }
    );
    // 进入规则D,报错 error: no rules expected the token `foo("1")`
    println!(
        "{}",
        example! {
            foo("0"),
            "a",
            foo("1")
        }
    );
}

Playground

为啥第一次可以正确执行,第二次却不行?

评论区

写评论
gwy15 2020-08-04 20:26

(token stream) foo(0), 1, foo(2)

第一次展开匹配到了 (foo($x:literal),$($e:expr),*),递归展开接下来的部分

(AST expr) 1, (AST expr) foo(2)

由于 expr 1 是一个 AST literal 项,因此匹配到 ($x:literal,$($e:expr),*) 规则,递归展开匹配

(AST expr) foo(2)

这里无法继续匹配,不能匹配到 (foo($x:literal)),这个只能匹配到 token stream,而传来的是一个 AST Expression tree。

如果添加一个项 ($e:expr) => {concat!("AST expr:", stringify!($e))} 就可以继续匹配了。

1 共 1 条评论, 1 页