Perl6:将匹配对象转换为可序列化为JSON的哈希表

4

我目前在使用Perl6进行一些操作。具体来说,我正在尝试基于语法(Fortran::Grammar模块)编写Fortran解析器。

为了测试,我想将一个Match对象转换为可JSON序列化的Hash

谷歌 / 官方Perl6文档没有帮助。如果我错过了什么,请原谅。

到目前为止,我的尝试:

  • 我知道可以通过$m.hashMatch $m转换为Hash。但是这会保留嵌套的Match对象。
  • 由于这个问题显然可以通过递归解决,我尝试了一下,但最终放弃了,并寻求是否有更简单/现成的解决方案。
  • 处理Match对象的内容最好是通过make/made完成。我希望提供一个超级简单的Actions对象,以便将其传递给.parse,并为所有匹配项提供一个默认方法,该方法基本上只是执行make $/.hash或类似的操作。但我不知道如何指定默认方法。
2个回答

5
这是我在Perl 6项目中的一个动作类方法,实现了你所描述的功能。它几乎与Christoph发布的内容相同,但写得更冗长(我添加了大量注释以便更易理解):
#| Fallback action method that produces a Hash tree from named captures.
method FALLBACK ($name, $/) {

    # Unless an embedded { } block in the grammar already called make()...
    unless $/.made.defined {

        # If the Match has named captures, produce a hash with one entry
        # per capture:
        if $/.hash -> %captures {
            make hash do for %captures.kv -> $k, $v {

                # The key of the hash entry is the capture's name.
                $k => $v ~~ Array 

                    # If the capture was repeated by a quantifier, the
                    # value becomes a list of what each repetition of the
                    # sub-rule produced:
                    ?? $v.map(*.made).cache 

                    # If the capture wasn't quantified, the value becomes
                    # what the sub-rule produced:
                    !! $v.made
            }
        }

        # If the Match has no named captures, produce the string it matched:
        else { make ~$/ }
    }
}

注意:

  • 此代码完全忽略位置捕获(即在语法内部使用( )进行的捕获)- 仅使用命名捕获(例如<foo><foo=bar>)构建哈希树。可以根据需要修改它以处理它们。请记住:
    • $/.hash 给出命名捕获,作为Map
    • $/.list 给出位置捕获,作为List
    • $/.caps(或$/.pairs)给出命名和位置捕获,作为name=>submatch和/或index=>submatch对的序列。
  • 它允许您覆盖特定规则的AST生成,方法是在语法中的规则内添加一个{ make ... }块(假设您从未有意地想要make一个未定义的值),或者通过将该规则名称的方法添加到操作类中。

2
仅供完整性,.caps.pairs 之间的区别在于前者将对应于相同键的子匹配列为不同的项,而后者不重复键,必要时将子匹配放入数组中。 - Christoph

4

我不知道如何指定默认方法。

方法名FALLBACK被保留用于此目的。

可以添加类似以下内容:

method FALLBACK($name, $/) {
    make $/.pairs.map(-> (:key($k), :value($v)) {
        $k => $v ~~ Match ?? $v.made !! $v>>.made
    }).hash || ~$/;
}

您的操作类应该起作用。

对于每个没有显式动作方法的命名规则,它将生成一个包含其子规则(命名的或位置捕获的)的哈希表,或者如果该规则是“原子”的且没有这样的子规则,则匹配字符串。


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