出現性とマッチングのキャンセル
抽出式は、マッチングに失敗してもnullまたは[]を戻す。エラーや例外はない。これだと、特定の要素や属性の出現を必須(required)とすることができない。
必須の出現性を表すために '!' を導入したが、'!' を付けても抽出に関して特に何の変化もない。抽出とは別にcheckというコマンドを準備して、checkで出現性を解釈する方針とした。
だが、やはり、抽出時に出現性のチェックも行いたい。そこで、'!'の解釈を変え、それに伴うメカニズムも変更する。いったん成功したパターンマッチングを後からキャンセルする方法を導入する。これは、パターンの内容評価に入ってからでもマッチングの失敗を引き起こせることである。
概念の説明(実装方式の説明ではない)のため、式はundefined値を持てるとして、undefinedを例外の代わりに使う。
パターンマッチングの成功失敗を次のように定義する。
- カレントノードがセレクターにマッチしないなら失敗。
- カレントノードがセレクターにマッチしたら、カレントノードをコンテキストノードにする。
- 新しいコンテキストノードのもとで、条件式を評価する。
- 条件式がひとつでも偽(false, null, [], {})を返したら失敗。
- 内容に含まれるすべての式をextractで評価する。
- そのなかで一つでもundefinedを返したなら、評価を中止してパターンマッチングが失敗とみなす。
evalは「パターンマッチング失敗」の目印(例外の代わり)にundefinedを返すが、extractはundefinedを返すことはなかった。したがって、今までは、内容に含まれる式の値がundefinedとなることはなかった。
ここで、'!'を「偽をundefinedに変換する演算子」と考える。'!'を前置した式がnullまたは[]を返すと、undefinedが発生して、パターンマッチングの失敗を引き起こす(例外と似ている)。
<div> "id": !$id, "title": ! ><h2, h3>$:text</> </>
この式で、id属性と子であるh2またはh3要素が存在しないときは、パターンマッチングが失敗する。次と同じとなる。
<div[id]> and ><h2, h3>$:text</> "id": $id, "title": ><h2, h3>$:text</> </>
これだと、><h2, h3>$:text</> の評価が二度行われてうれしくない。また冗長で可読性も悪い。'!'を「出現必須」と読めば、直感的である。
[追記]二度評価は $:cond という配列変数で回避できる。[/追記]