Markdown/CommonMark 探訪(1):laziness
Markdown パーサを書くにあたってちょっと苦労したのが Laziness という考え方です。
Markdown では、引用ブロック (blockquotes) を書く際、引用符を付けるのは最初の行だけでよいと定められています。
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing.
https://daringfireball.net/projects/markdown/syntax#blockquote
引用符がある行から段落が終わるまでは、すべて引用ブロックの中の段落として扱われます。
たしかにこれは書きやすいだろうし、読めなくはないので、記法として理解できます。
しかし、さまざまな実装の共通項を探る CommonMark では、こんな風に整理されています。
>>> foo > bar >>baz
http://spec.commonmark.org/0.28/#example-214
このテキストを処理系に渡すと、3重にネストされた引用ブロックの中に「foo, bar, baz という 3行の段落」がある、と解釈されます。
えっ。
テキストとしての見た目と、あまりに違う解釈結果ですね。
laziness はリストでも有効
この laziness の考え方はリストでも適用されています。
* Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. * Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse id sem consectetuer libero luctus adipiscing.
印刷物とかでもこういうレイアウトが使われていることもあり、理解はできます。
では、こちらはどうでしょう。
> 1. > Blockquote > continued here.
http://spec.commonmark.org/0.28/#example-256
2行目の「continued here」は内側の引用ブロックの内部の段落の一部です。
えっ。
またですか。
laziness の範囲
徐々に Markdown の世界観がつかめてきましたか? それではこれはどうでしょう。
> - foo - bar
引用ブロックの中に箇条書きが記述されていますね。
さて、これはどう解釈されるのでしょうか。
実はこれは
- 「foo」は引用ブロックの内側のリストとして扱われる
- 「bar」は引用ブロックの外側の (別の) リストとして扱われる
と解釈されます。
というのは、laziness が適用される対象は「段落」だけです。その他の記法には laziness は適用されません。
楽しいですね。
面倒くさい例としては
> lorem ipsum > ---
は引用ブロックの中に <h2> の見出しが記述されると判定されるのに対して
> lorem ipsum ---
は引用ブロックの後ろに区切り線 (themantic break) がある、と解釈されるものがあります。
pycmark ではどうしているのか
段落用のプロセッサーで、次のような処理をしています。
1. 同じインデントレベル (引用符やリストアイテムなどのレベル) の中で読み進める
2. その状態で空行や区切り線などの割り込み要素がきた場合は、段落の処理は終了
3. インデントレベルの最後まで段落が続いた場合は、LazyLineReader という laziness に対応した読み込みモジュールを使って読み進める
4. 割り込み要素が来るまで、段落の一部として解釈を続ける
ということで、pycmark でも無事に laziness な段落は正しく扱えます。
多用すると読みづらくなりそうですが、つかってみてください。