はやわかり
tree-sitter

Kyoto.* #4 (2018-08-18)

tree-sitterとは

https://github.com/tree-sitter/tree-sitter

  • パーサージェネレーターの一種
  • なるほど?
  • ところでパーサージェネレーターとは…

そのまえにパーサーとは

決まった文法に従って文字列を解釈するやつ

たとえば

  • なんかのソースコード
  • なんかの設定ファイル
  • コマンドライン引数

とかのパーサーを毎日使ってるはず

  • パーサーを手書きするのは大変
    • あっという間にメンテ不能になる
    • 効率のよい実装にするのも大変
  • 文法を渡してあげるとパーサーを生成してくれるもの=パーサージェネレーター
  • bison, ANTLR, tree-sitterなど

tree-sitterとは

  • パーサージェネレーターの一種
  • An incremental parsing system
    • パース→ソースコード編集→再パース
    • 高速に再パースできる

特徴

  • 文法はJSで定義する
    • 独自DSLではない
    • JSならだいたいみんな読める
  • 出力されるパーサーのコードはC言語
    • ポータビリティを重視してるっぽい

利用例

  • Atomで採用されている
    • (Atomのために開発されてる感がある)
    • シンタックスハイライト
    • インデント
    • ブロックを畳む機能などなど
    • Atom 1.2.5 betaからopt-inで使える
    • 詳細は“site:blog.atom.io tree-sitter“で検索

パーサーを作ってみる

はじめの手順

  1. npm init && npm install -D tree-sitter-cli
  2. 適当にgrammar.jsを書く
  3. npx tree-sitter generate(パーサーのコードとかを出力)
  4. npm install(パーサーをビルドするための設定+実際のビルド)
  5. npx tree-sitter parser ./sourceで動作確認

開発手順

  1. grammar.jsを更新する
  2. npx tree-sitter generate && npx node-gyp build
  3. 動作確認
    • npx tree-sitter test
    • npx tree-sitter parser ./source -d

ポイント

  • テストも書ける
    • パースエラーもテストできる
    • エラー回復込みのテストを書く必要があるっぽい
  • generateしてからbuildする必要がある
    • package.jsonとかMakefileとかでコマンド一発でテスト実行できるようにすると楽

パーサーを動かしてみる

  • JavaScript, Rust, Haskell, Rubyとかのバインディングがある
    • JavaScriptのバインディングがいちばん整備されてる
    • READMEのサンプルを10行ぐらいコピペするだけで動かせるのでおすすめ

Atomに組み込んでみる

https://github.com/vzvu3k6k/language-simple-arithmetic

  • Atomではpackageをインストールすると機能を拡張できる。
  • 各言語のシンタックスハイライトとかもpackageとして提供されている。

Atomに組み込んでみる

  • 従来の言語サポートはTextMateのgrammarの仕組みを使っている。
  • tree-sitterを利用する方法は公式のドキュメントには載ってない。
  • Atomにバンドルされているtree-sitterのバージョンに合わせる必要がある。

まとめ

  • エディタ用のパーサーは意外と簡単につくれる
    • JavaScriptのパーサー(tree-sitter-javascript)も1000行未満
    • でも言語処理系で使うのは難しそう
  • Atomがんばってくれ

おすすめのリソース

あわせて読みたい