rust 在macro_rules中递归处理逗号分隔的标记时,如何解决局部二义性错误?

e5nszbig  于 2023-05-07  发布在  Mac
关注(0)|答案(1)|浏览(282)

在试图创建一个宏来简化代码的阅读时,我发现宏中存在“局部歧义”。我真的不明白这是如何模糊的:在我的括号的每个分支中,我解析的值前面都有一个唯一的前缀。

macro_rules! test {
    (rule_a=$value: expr $(, $($rest: tt)*),*) => {
        println!("Rule A: {}", stringify!($value));
        test!($($($rest)*),*)
    };
    (rule_b=$value: ident $(, $($rest: tt)*),*) => {
        println!("Rule B: {}", stringify!($value));
        test!($($($rest)*),*)
    };
    (rule_c=$value: ident $(, $($rest: tt)*),*) => {
        println!("Rule C: {}", stringify!($value));
        test!($($($rest)*),*)
    };
    () => {
        println!("End");
    };
}

fn main() {
    // Working
    test!(rule_a="Great test", rule_b=i32);
    // Working
    test!(rule_a="Great test", rule_c=i64);
    // "Local ambiguity"
    test!(rule_a="Great test", rule_b=i32, rule_c=i64);
}
error: local ambiguity when calling macro `test`: multiple parsing options: built-in NTs tt ('rest') or 1 other option.
  --> src/main.rs:25:42
   |
25 |     test!(rule_a="Great test", rule_b=i32, rule_c=i64);
   |                                          ^

Rust Playground
我该怎么解决这个问题?我试着四处寻找,但并没有真正找到任何有用的资源来帮助解决这个问题...

kmb7vmvb

kmb7vmvb1#

,是一个有效的令牌,因此它同时匹配$rest:tt),*中的,。您需要使第一个,成为可选的,然后使任何其他,成为$rest的一部分。

macro_rules! test {
    (rule_a = $value:expr $(, $($rest:tt)* )?) => {
        println!("Rule A: {}", stringify!($value));
        test!($($($rest)*),*)
    };
    (rule_b = $value:ident $(, $($rest:tt)* )?) => {
        println!("Rule B: {}", stringify!($value));
        test!($($($rest)*),*)
    };
    (rule_c = $value:ident $(, $($rest:tt)* )?) => {
        println!("Rule C: {}", stringify!($value));
        test!($($($rest)*)?)
    };
    () => {
        println!("End");
    };
}

相关问题