Perl6:将Match对象转换为JSON可序列化Hash

时间:2017-02-03 14:47:16

标签: json testing perl6 regexp-grammars

我目前正在接触一些Perl6。具体来说,我正在尝试编写基于语法的Fortran解析器(Fortran::Grammar模块)

出于测试目的,我希望有可能将Match对象转换为JSON可序列化Hash

谷歌搜索/ official Perl6 documentation没有帮助。如果我忽略了某些事情,我很抱歉。

到目前为止我的尝试:

  • 我知道可以通过Match $mHash转换为$m.hash。但这会保留嵌套的Match个对象。
  • 由于 可以通过递归解决,我试过但是放弃了先请求更简单/现有的解决方案
  • 处理Match个对象的内容显然最好通过make / made完成。我希望有一个超级简单的Actions对象可以用{strong>默认方法传递给.parse,所有匹配基本上只需要make $/.hash或类似的东西。我根本不知道如何指定默认方法。

2 个答案:

答案 0 :(得分: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>)来构建哈希树。它可以修改为处理它们,具体取决于你想用它们做什么。请记住:
    • $/.hashMap
    • 的形式提供指定的捕获
    • $/.list提供位置捕获,为List
    • $/.caps(或$/.pairs)同时提供命名和位置捕获,作为name=>submatch和/或index=>submatch对的序列。
  • 它允许您通过在语法规则中添加{ make ... }块来覆盖特定规则的AST生成(假设您从未故意想要make未定义的值),或者通过向操作类添加带有规则名称的方法。

答案 1 :(得分:3)

  

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

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

添加类似这样的内容

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

你的行动课应该有效。

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