GoのreStructuredTextパーサgorstをリリースしました
タイトルどおりですが、GoのreStreucturedText実装を作ってみました。
https://github.com/hhatto/gorst
以前 GoでMarkdown live previewerのftcatってのを作った のですが、 リリースしたあとくらいに reStructuredText でも使いたいよなーって思ってました。
よしGoのreSTパーサ作ろうと思って 10月下旬にGitHubに空のリポジトリだけ作って 、 どこから手をつけたらいいのやらってグダグダ考えてほったらかしになっていたのですが、 2月に入ってちびちびと余暇の時間を使って進めて、やっと公開できるレベルになって公開したのが先日2/18でした。
使い方
現在はreSTからHTMLへの変換のみ対応しています。 現状はHTML以外のフォーマットに対応させる予定はありません。
$ go get github.com/hhatto/gorst
package main import ( "bufio" "os" "github.com/hhatto/gorst" ) func main() { p := rst.NewParser(nil) w := bufio.NewWriter(os.Stdout) p.ReStructuredText(os.Stdin, rst.ToHTML(w)) w.Flush() }
実装までの流れや中身の話
結論から言うと、GoのMarkdown実装であるところの knieriem/markdown をベースにしてreST実装に移植する形にしました。 自分自身がどういう流れでそこに至ったのかを少し書き残しておきます。
まずはPython実装であるところの docutils のソースコードを読んで移植できないか調べていました。 StateMachineというキーワードが見つかったので、 GoのState Machine実装 を参考にできないかさらに調べたのですが、 ちょっと理解するのだけでも時間かかりそうだなってことであきらめました。
次にPython以外の実装も調べてみようということで調べていく中でたどり着いたのが、以下StackOverflowのページ。
http://stackoverflow.com/questions/2746692/restructuredtext-tool-support
Python以外の実装として、 Haskell(Pandoc)/Java/Scala/Perl/Nim(C)があるようなので、 有名なPandocのソースコードと、Cだったらライブラリ経由で使えるかなってことで、Nimの実装を見てみる事にしました。
PandocのText.Pandoc.Readers.RST / Text.Pandoc.Writers.RST は、 結局Haskell読めないので断片的にしか理解できず、そっとブラウザを閉じました。 Nimの実装 も結局読み解くのに時間かかりそうだなってことでそっとブラウザを閉じました。 Cとの連携もぱっと調べただけではとっかかりを掴む事ができなかったのもあり、あきらめました。
ここまでで多分2ヶ月くらい使ってました。
次に考えたのが、GoのMarkdown実装をreSTに対応させる方法でした。 ドキュメントのスペックはほぼ同じような要素を持っているはずなので、 比較的容易に対応させれるのではないかと考えました。
GoのMarkdown実装についてサックリググると以下の2つの実装があります。
ussross/blackfriday は libupskirt ベースで、単純にCからGoへ移植しているようでした。 少し本題とは外れますが、libupskirt 系のライブラリ群は sundown や libsoldout 等派生物が色々あってカオスです。 ( libsoldout と libupskirt はおそらく作者は同じ。) プロジェクト名とか深入りすると時間がいくらあっても足りなさそうなで、サラッと流しておきます...
もう一方の knieriem/markdown は peg-markdown ベースで、 PEG なパーサジェネレータであるところの peg/leg をベースにしています。 peg-markdown も色々と派生物があって、 今の主流は fletcher/MultiMarkdown-4 になってそうなところまでは感じ取りましたが、 深入りすると時間がいくらあって(ry
で、2つのソースを軽く読んでみたのですが、 knieriem/markdown の方が parser.leg に文法定義をある程度 切り出せており見通しがよさそうというのと、 PEG 学ぶと今後色々応用範囲が広がるかなってことで、 knieriem/markdown をベースにすることにしました。 ( knieriem/markdown 自体がsedとかでCからGoにコンバートしてるっぽいので、 CのreSTライブラリとかも今後展開できそうかな、という思惑もあったり。)
というのを決めて実装に取りかかり始めたのが2015年1月末頃。 そこから2週間くらいで形になったので、リリースしました。
PEG (Parsing Expression Grammars)
正直これだ!!っていう説明ができる程理解できていないので、 参考までにPEGに関するリンクを以下に列挙しておきます。
- Parsing Expression Grammar - Wikipedia
- PEG基礎文法最速マスター - kmizuの日記
- Cライブラリpeg/legのmanpage
- PEGはメタ言語界のLLだ - _ - sideport
実装の際には PEG基礎文法最速マスター - kmizuの日記 と Cライブラリpeg/legのmanpage を参考にさせていただきました。
おわりに
markdownライブラリの作者や他のreST実装の作者、 PEG関連の記事をまとめて下さっている方に感謝します。 ありがとうございます。
gorst はまだ生まれたてなので、色々バグや対応できていない箇所ありますが、 バグ報告やPR等々フィードバックをお待ちしております。