新しい構造化Wiki記法パーサーの設計案

プラグインの記述

プラグイン=要素の記述。要素はRubyのクラス。このクラスが持つクラス変数(か定数):

  • 開始マーク
  • 終了マーク(省略可)
  • XMLを生成するプログラム(メソッド)
  • 包含可能な要素またはグループ(無ければ省略)
  • 所属するグループ(無ければ省略可)
  • どこにも含められなかったときに補完する親要素(無ければ省略可)

「見出し」とか基本的な要素は開始マークと包含可能要素だけ書けばいいので簡単。「段落」要素とかその他一切を@contentsグループとかに属させておいて、「見出し」の包含可能な要素には:@contentsと書いておく。
「太字」とかインライン要素は、開始マークと終了マークを書いて、@inlineグループに属しておく。包含可能要素は@inline - [self]としておく。良くあるパターンだから、ちょっと宣言が書いてあったら全自動でやってしまえばいい。
ちょぃと小粋なことがやりたくなったら、ブロック要素で終了マークを使ってみたり、親要素とか使う。

パースと自動構造化

文脈(その文脈で利用できる要素の集合)の中から開始マークを探す。どの要素にもマッチしなかったら:text要素。
マッチしたら、その要素をスタックに積む。そして:

  • その要素に終了マークが定義されていたら、文脈を、その要素が包含可能な要素のセットに切り替える
    • 文脈はスタック。この要素がpopされたら文脈も元に戻る
    • 「太字」の中で「見出し」にマッチしたり、「整形済みテキスト」の中で「太字」にマッチしたりするのを防げる


文脈の中から開始マークか、スタックのトップの要素の終了マークを探す(←コレ文章が終わるまでループ)
開始マークにマッチしたら、その要素=Tをスタックに積む。このとき自動構造化:

  • スタックのトップの要素=Aが包含可能な要素のセットの中にTが含まれていたら、TをAの子要素とし、Tをスタックに積む
  • 含まれていなかったら、Aをpopしてスタックの次の要素Bについて繰り返す
    • popするとき文脈もpopする
    • popする要素に終了マークが定義されていたらエラー。終了マークが定義されている要素は終了マークによってのみpopされなければならない
  • スタックが空になったら:
    • Tに親要素が定義されていたら、スタックをpopを始める前の状態に戻し、Tの親要素を生成して補完する。T_pending.push(T); T = T.parent.new
    • Tに親要素が定義されていなかったら、エラー

開始マークではなくスタックのトップの要素の終了マークにマッチしたら、単にスタックをpopする。


開始要素を探すのはStringScannerで。文脈は、開始マークのセットとスタックのトップの要素の終了マークをRegexp#unionしてキャッシュ。一度使った正規表現は使い回す。速度は鬼車に依存!


要注目: