在 Nearley 中使用嵌套宏嵌套数据结果

Using nested macros in Nearley nests the data result

问题

乍一看,如果没有一些严重的错误,宏就无法正确嵌套。

主要问题是从数据对象中检索宏的值会将此值嵌套到列表中:

a[X] -> $X {% id %}
main -> a["test"] {% id %}

Parse results:
[ [ 'test' ] ]

预期结果将是 [ 'test' ]

一个快速修复方法是 return data[0][0],但这还不够,因为结果将嵌套每一层宏:

a[X] -> b[$X] {% id %}
b[X] -> $X {% id %}
main -> a["test"] {% id %}

Parse results:
[ [ [ 'x' ] ] ]

要修复错误,我们可以对每个宏使用 data => data[0][0]。然而,这绝对是丑陋的。

真正的解决方法是使用动态范围。由于我们不能(据我所知)创建一个没有参数的宏,让我们使用一个无用的参数:

a[X] -> b["_"] {% id %}
b[_] -> $X {% id %}
main -> a["test"] {% id %}

Parse results:
[ [ 'test' ] ]

这停止了之前发生的嵌套地狱 - 我们可以通过 500 个子宏并仍然得到相同的结果。但是我们仍然需要为最终的子宏 b 放置 data[0][0],这使我们无法单独使用 b 宏 - 我们必须使用 a 让它工作。

我们正在寻找一种解决方案: - 允许单独使用最后一个宏 - 避免使用数据 => 数据[0][0]

解决方案

为避免此问题,最佳解决方案如下:

a[X] -> b[$X] {% id %}
b[X] -> c[$X] {% id %}
c[X] -> $X {% data => data[0].join('') %}

main -> a["test"] {% id %}

Parse results:
[ 'test' ]

说明

问题是,当最后一个子宏得到结果的时候,由于nearley默认把所有的东西都看成一个数组,结果嵌套到一个数组中,然后每一层都做同样的事情。在数组上使用 join 方法使其成为字符串 - 每个宏都会停止将其放入数组中。

您必须考虑哪个宏或非终端负责结构化数据和展平数组,以及它适用于哪些地方。

就个人而言,我喜欢将与宏相关的常规后处理保留在宏内部,并且我在链的上游进行结构化(如展平数组),在负责执行此操作的非终端(或宏)内。

例子

withCurlyBrackets[X] -> "{" $X "}" {% d => d[1] %}
withSquareBrackets[X] -> "[" $X "]" {% d => d[1] %}
withRoundBrackets[X] -> "(" $X ")" {% d => d[1] %}

test -> withRoundBrackets[withSquareBrackets[withCurlyBrackets["test"]]] {% id => ({ value: id.flat(Infinity).join('') }) %}

// Parse results for '([{test}])': [ { value: 'test' } ]