如何将 Raku Grammar 标记固定为仅在字符串末尾时匹配

p6s*_*eve 8 grammar raku

我已经写了这个 - 效果很好:

use Grammar::Tracer;

my grammar Lambda {
    token  TOP       { <signature> <body> ' as ' <r-type> }
    rule  signature { '|' <a-sig> [',' <b-sig>]? '|' }
    rule  a-sig     { 'a:' <a-type> }
    rule  b-sig     { 'b:' <b-type> }
    token body      { '(' <expr> ')' <?before ' as '> }
    token expr      { <-[()]>* }
    token a-type    { @types }
    token b-type    { @types }
    token r-type    { @types }
}

Lambda.parse("|a: i32, b: i32| (a + b) as i32");
Run Code Online (Sandbox Code Playgroud)

给出我需要的:

TOP
|  signature
|  |  a-sig
|  |  |  a-type
|  |  |  * MATCH "i32"
|  |  * MATCH "a: i32"
|  |  b-sig
|  |  |  b-type
|  |  |  * MATCH "i32"
|  |  * MATCH "b: i32"
|  * MATCH "|a: i32, b: i32| "
|  body
|  |  expr
|  |  * MATCH "a + b"
|  * MATCH "(a + b)"
|  r-type
|  * MATCH "i32"
* MATCH "|a: i32, b: i32| (a + b) as i32"
Run Code Online (Sandbox Code Playgroud)

但我想做这个字符串(和类似的): |a: str, b: i32| (a.len() as i32 + b) as i32

  • 这失败了,因为它退出了 len() 括号上的主体匹配
  • 即使我修复它在第一个作为 i32 退出

我想找到某种方法将匹配“固定”为字符串末尾之前“as type”的最后一个有效匹配

以及如何匹配但不只捕获其他括号。

p6s*_*eve 7

经过一番尝试和错误后,我设法解决了这个问题(Grammar::Tracer 太有帮助了!)

这是工作语法

my @types  = <bool i32 i64 u32 u64 f32 f64 str>;

my grammar Lambda {
    rule  TOP       { <signature> <body> <as-type> }
    rule  signature { '|' <a-sig> [',' <b-sig>]? '|' }
    rule  a-sig     { 'a:' <a-type> }
    rule  b-sig     { 'b:' <b-type> }
    rule  as-type   { 'as' <r-type> }
    rule  body      { '(' <expr> ')' <?before <as-type>> }
    rule  expr      { .* <?before ')'> }
    token a-type    { @types }
    token b-type    { @types }
    token r-type    { @types }
}
Run Code Online (Sandbox Code Playgroud)

我所做的改变是:

  • 将一堆标记交换为规则(忽略空格的最佳方法)
  • <as-type>将返回类型捆绑为 TOP 中的单个匹配器,以便它始终在末尾匹配
  • <body>有一个前瞻断言,所以总是在<as-type>
  • <expr>有一个先行断言,所以总是在 ')' 之前
  • 但在其他方面对 .* 贪婪,以便它吸住整个 expr 并且不会在第一个 ')' 处停止