以下是基於一個更大的語法測試案例 - 我們的目標是分析它在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