新 ReVIEWパーサ
・
について
  ReVIEW開発者カンファレンス 2014/03/08
株式会社達人出版会
高橋征義
自己紹介
• 高橋征義 (@takahashim), ReVIEWコミッタ
• 古参Rubyist (1997年くらいから)
• ∼2010年 Web制作会社のプログラマ
• @kdmsnrの同僚
• 2010年∼ 電子書籍の制作と販売
(今日はこの話じゃなくて、実装の話)
本日のあらすじ
• パーサを書き換え中
• いろいろスッキリした(はず)
• わりと動いている(はず)
• そもそもの仕様を決めないとダメ
• すごく内部実装の技術的な話ですみません…
本発表の話題
• パーサ (Parser)
パーサとは

• 構文解析をするひと
• どこがブロックで、どこがインラインで…と
いうのを解析する

• ReVIEWではReVIEW::Compiler
• lib/review/compiler.rb
• …だけではなく、実はBuilderの中でも構文解析
しているのが問題だったり
== foo
XXXYYY
ZZZ
//list[foo1][foo2]{
AAA@<b>{BBB}CCC
DDD@<raw>{EEE{FFF}GGG}
IIIJJJ
//}
@<ruby>{KKK,LLL}
MMMNNN
== foo
Headline
XXXYYY
Paragraph
ZZZ
//list[foo1][foo2]{
BlockElement
AAA@<b>{BBB}CCC
DDD@<raw>{EEE{FFF}GGG}
IIIJJJ
//}
@<ruby>{KKK,LLL}
Paragraph
LLLMMM
== foo
XXXYYY
ZZZ
//list[foo1][foo2]{
AAA@<b>{BBB}CCC
DDD@<raw>{EEE{FFF}GGG}
IIIJJJ
//}
@<ruby>{KKK,LLL}
LLLMMM
※細かい要素に分割するだけ
→各要素をどう扱うかは
 パーサではなくBuilderが
 担当する

== foo
XXXYYY
ZZZ
//list[foo1][foo2]{
AAA@<b>{BBB}CCC
DDD@<raw>{EEE{FFF}GGG}
IIIJJJ
//}
@<ruby>{KKK,LLL}
LLLMMM
なぜ新パーサなのか
• 現状のパーサがいろいろつらい
• 拡張しづらい
• 「ブロックのネストをさせたい」etc
• 修正しづらい
• Builder/インラインごとにエンバグetc
• パーサから仕様がリバースできない
• (他に仕様があればいいんですが…)
• ReVIEW.jsみたいなのを作るにもつらそうな予感
つらい点
R::Compiler
<div class="emlist-code">
+
//emlist{
R::Builder <pre class="emlist">def foo(a)
def foo(a)
if a&gt;1
☆escape
if a>1
bar(a)
bar(a)
end
end
end</pre>
end
</div>
//}
つらい点
☆インラインを入れたい→escapeした文字列の連結
//emlist{
def foo(a)

if @<b>{a>1}
bar(a)
end
end
//}

<div class="emlist-code">
<pre class="emlist">def foo(a)
if <b>a&gt;1</b>
bar(a)
end
end</pre>
</div>
つらい点
☆ソースハイライトもしたい→unescape??
//emlist{
def foo(a)

if a>1
bar(a)
end
end
//}

<div class="emlist-code">
<pre class="emlist">def foo(a)
if a&gt;1
bar(a)
end
end</pre>
</div>

???
現パーサの問題点
• 正規表現で頑張っている
• パーサがReVIEW::Compilerと
ReVIEW::BuilderとReVIEW::*Builderに分割さ
れている

• 各Builderでの解析方法が統一されていない
(ような気がする)
新パーサの方針
• 基本的には書き直し
• ad hocな書き方をせず、ちゃんとパーサを実

装する(既存パーサライブラリor自作パーサ)

• ネストは実現できるようにしたい
• APIはあまり非互換にしない(変えすぎるとい
ろいろつらい)

• ReVIEW文法の再定義(明確化)も狙いたい
新パーサの現状
• kpegブランチで開発中(Github Issues #235)
• それなりに動くが、完璧ではない
新パーサの特徴
• パーサジェネレータ(PEG)を使って書き直し
• 実装としてはkpegを採用
• Ruby 1.8∼2.1まで対応(してるといいな…)
• 外部gemへの依存なしで動く
• 現状はUTF-8のみだが、それ以外の文字コード
にも対応可能かも

• 現状のAPIに合わせている(kpegとしては不自
然かもしれないが、互換性は高いはず)
新パーサの実装
• lib/review/review.kpegで定義
• 生成されたパーサはlib/review/compiler.rb
になる(現状と同名のファイル)

• いったんAST(抽象構文木)を作成したあと、
それを元に各nodeに対する処理を呼び出す

• 処理内容は現状同様*Builderに書かれている
• *BuilderのAPIは一部非互換(inline_*)
== foo
XXXYYY
ZZZ
//list[foo1][foo2]{
AAA@<b>{BBB}CCC
DDD@<raw>{EEE{FFF}GGG}
IIIJJJ
//}
@<ruby>{KKK,LLL}
LLLMMM
root
Headline
level
2

Paragraph

Text

Text

Paragraph

Text
Text

InlineElement
foo

XXXYYY

ZZZ

name

contents
LLLMMM

ruby

Text
KKK

BlockElement

☆escapeは
ツリーを作った
後で行える

name
list

args
foo1

contents

Text
LLL

foo2

SinglelineContent

SinglelineContent

Text

InlineElement

Text

Text

AAA

BBB

CCC

DDD

SinglelineContent

Raw
EEE{FFF}GGG

Text
IIIJJJ
新パーサの課題

• パーサより文法が決まっていないのが課題
• 複雑なケースに対する処理がこれで正しいのか
どうかよく分からない

• //list[t1][@<b>{}] 
• highlightingとかの制御方法・具体的なルール
• インライン+ハイライトは死ぬ
• ReVIEWドキュメントの互換性は完璧ではない
(むしろ非互換にしたい)

• ReVIEW.jsとのマージ
リリーススケジュール
• 未定
• 今日の流れ次第で
• 2.0で?
• 1.xにはしない方が良さそう(互換性の問題
もあるし)
まとめ
• パーサを書き換え中
• いろいろスッキリした(はず)
• わりと動いている(はず)
• そもそもの仕様を決めないとダメ
• 良い機会なので整理したい

新・ReVIEWパーサについて