2017-09-09 4 views
7

以下はより大きな文法に基づくテストケースです。目標は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 

答えて

7

timotimoはマッチ変数($/$0$1、および名前の一致)がグローバルではありませんIRC-上の問題を説明しました。マッチャーが始まると、マッチ変数にはすでに値が設定されています。パフォーマンスの問題のため、ほとんどは*マッチャー本体の残りの部分では更新されません。しかし、コードブロックが見られると(空のブロックさえも)、一致変数が更新されます。つまり、バグの回避策は実際には有効な解決策です。空のブロックを含めて、マッチ変数の更新を強制します。

* $0はすぐに更新され、利用可能と思われます。おそらく他の番号の一致も同様です。

UPDATE:唯一の時刻一致変数がすぐに利用できないように見えるのは、ブロックを使用せずにコードライクなコンテキストでそれらを使用する場合です(別のマッチャーへの引数リストなど)。あなたが更新されるという名前の一致変数を強制的にブロックを追加しない限り

my regex repeated($x) { [$x]+ }; 
say 'ooxoo' ~~/^ <repeated('o')> . <repeated($<repeated>)> $/

my regex word { \w+ }; 
say 'hellohello' ~~ /<word> $<word>/ 

しかし、パラメータが失敗したとして使用されるこの例:ここでは、マッチ変数は、前の試合後すぐに利用可能です:

my regex repeated($x) { [$x]+ }; 
say 'ooxoo' ~~/^ <repeated('o')> . {} <repeated($<repeated>)> $/
関連する問題