为什么 Rust 的 macro_rules! 模式不能跟随 "<" 符号?

3
在L-System符号化表示法中,一个模式看起来会像这样:
A(a)<A(x)>B(b, c) if a+b+c < 10 => B(a+b, a+c)A(x+a+b+c)

我正在尝试编写Rust宏来扩展它们。因此,我有以下内容:
macro_rules! test {
    ($lc:pat < $a:pat > $rc:pat) => { ... };
}

但是我不能这样做。它显示的信息是:
error: `$a:pat` is followed by `>`, which is not allowed for `pat` fragments
 --> src/main.rs:7:23
  |
7 |     ($lc:pat < $a:pat > $rc:pat) => { log_syntax!($lc); log_syntax!($a); log_syntax!($rc); };
  |                       ^ not allowed after `pat` fragments
  |
  = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`

为什么这些在模式类型之后不允许?我可以匹配什么来得到这个结果?

我不能使用 tt,因为括号在其中不被允许。


这里的 A(a), A(x), 和 B(b, c) 是否代表 Rust 模式中可能出现的任意模式,就像在 matchif let 表达式中一样?还是它们实际上是一些更受限制的语法,只是恰好是 pat 可以匹配的子集?如果是后者,您可以编写一个 TT-muncher,通过 <> 将输入拆分,然后一次性匹配这些部分。 - trent
1个回答

5
被传递给`macro_rules`宏的标记已经由Rust词法分析器发出;该词法分析器是Rust解析器的一部分。词法分析器允许许多非有效的Rust标记序列,但在解析正常的Rust代码时,将被下游的语法规则捕获。然而,词法分析器有一定程度的上下文意识,例如它可以根据处理类型还是表达式来区分像<<(左移操作符)和<<(嵌套类型参数的开始)这样的东西。
在许多情况下,宏可以匹配不是有效的Rust的标记流,但是实现会以谨慎为原则禁止许多词法分析器可能会发出的组合。原因是为了允许语言开发人员具有一些灵活性,如添加新的语法而不破坏现有宏。这条界限似乎相当任意,并且部分是由于历史 - 语言的发展以及早期发布的宏代码 - 但是必须划定界限。
我们保证在输入有效的Rust代码(以及许多输入无效Rust代码的宏)的宏中具有前向兼容性的代价是禁止许多创造性的应用程序。随着语言和编译器变得越来越稳定,规则可能会逐渐放宽,但我认为这将缓慢而且可能不会发生。
您的宏匹配了不是有效Rust的输入:模式永远不会出现在<>之间。不幸的是,在宏中也不允许使用它,您可能需要选择其他语法。
过程宏有较少限制,也可以是一个选择。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接