以下はより大きな文法に基づくテストケースです。目標はUnity3Dアセットファイルで使用されるYAMLのサブセットを解析することです。興味深い機能はキー配列マッチャーです。このマッチャーはループし、data[i]: val
と一致するのは<array-name(index)><indexer-and-value(index, name)>
です。 <array-name>
はオーバーロードされているので、最初に呼び出されると、どの名前にも一致します。後続の反復(インデックスがゼロ以外の場合)は、表示された同じ名前にのみ一致します。このperl6の文法は壊れていますか、またはバグを公開していますか?
インデックスの値が0より大きい場合、は常にである必要があります。これはパラメータとしてマッチャに渡す必要があります。通訳者が次のエラーを出しています。
Cannot resolve caller array-name(Match.new(...): 1, Nil, 1); none of these signatures match:
(Prefab $: Int $ where { ... }, $prevName, Int $indent, *%_)
(Prefab $: Int $idx, Match $ (@ (Any $prevName, *@)), Int $indent, *%_)
(Prefab $: Int $idx, @ (Any $prevName, *@), Int $indent, *%_)
したがってインデックスは1ですが、以前に一致した名前はありませんでした。そのパラメータはNil
ですが、意味がありません。その関数内のコメントアウトされたブロック:#{ }
に注意してください。これがコメントされていない場合、テストケースは失敗します。最も長いマッチ(|
演算子またはproto
マッチャー)に基づいた分岐はありません。したがって、マッチャーに余分なものを追加しても、解析を変更してはいけません。
テスト入力はテストケースに含まれています。ここでは、次のとおりです。
#use Grammar::Tracer;
#use Grammar::Debugger;
grammar Prefab {
token TOP {
<key> ':' <value=hash-multiline(1)> \n
}
token key { \w+ }
token kvpair(Int $indent=0) {
[
|| <key> ':' <hash-multiline($indent+1)>
|| <keyed-array($indent)>
|| <key> ': ' (\w+)
]
}
token keyed-array(Int $indent) {
# Keys are built in to the list:
# look for arrayname[0] first, then match subsequent lines more strictly, based on name[idx]
:my $idx = 0;
[
<array-name($idx, $<array-name>, $indent)>
<indexer-and-value($idx++, $indent)>
#{ } # XXX this fixes it, somehow
] +% \n
}
multi token array-name(0, $prevName, Int $indent) {
# the first element doesn't need to match indentation
\w+
}
multi token array-name(Int $idx, Match $ ([$prevName, *@]), Int $indent) {
<.indent($indent)>
$prevName
}
# todo: Can I remove this overload? In testing, the parameter was sometimes an array, sometimes a Match
multi token array-name(Int $idx, [$prevName, *@], Int $indent) {
<.indent($indent)>
$prevName
}
# arr[2]: foo
# ^^^^^^^^ match this
token indexer-and-value(Int $idx, Int $indent) {
'[' ~ ']' $idx
[
|| ':' <hash-multiline($indent+1)>
|| ': ' \w+
]
}
token hash-multiline(Int $indent=0) {
# Note: the hash does not need a newline if it's over after the first (inline) kv-pair!
# optional first line which is on the same line as the previous text:
[
|| [<kvpair($indent)>] [ \n <.indent($indent)> <kvpair($indent)> ]*
|| [ \n <.indent($indent)> <kvpair($indent)> ]+
]
}
multi token indent(0) {
^^ <?>
}
multi token indent(Int $level) {
^^ ' ' ** {2*$level}
}
}
sub MAIN() {
say so Prefab.parse($*kv-list);
}
my $*kv-list = q:to/END/;
Renderer:
m_Color[0]: red
END