Next: tree-sitterを用いるメジャーモードの開発, Previous: tree-sitterノードにたいするパターンマッチング, Up: プログラムソースの解析 [Contents][Index]
プログラミング言語のソースの一部に他の言語のソースが含まれているときがあります。一例としてはHTML + CSS + JavaScriptが挙げられます。このような場合には、別の言語によって記述されたテキストセグメントには別のパーサーを割り当てる必要があります。伝統的にこれはナローイングの使用によって達成されてきました。tree-sitterはナローイング(narrowingを参照)とともに機能しますが、推奨される方法はバッファーテキストのリージョン(範囲)にそれを操作するパーサーを指定する方法です。このセクションではパーサーにたいして範囲のセットや取得を行う関数について説明します。
Lispプログラムがバッファーでパーサーを使う前には、treesit-update-ranges
の呼び出しによってパーサーそれぞれにたいする範囲が正しいか確認して、その位置にあるテキストにたいして任を負うパーサーを解決する必要があります。この2つの関数自身は作業を行わず、実際に作業を行うにはメジャーモードがtreesit-language-at-point-function
およびtreesit-language-at-point-function
をセットする必要があります。これらの関数および変数については、このセクションの終わり近くで詳細に説明しましょう。
この関数はrangesにたいして処理を行なうためにparserをセットアップする。parserが読み込むのは指定された範囲のテキストのみ。ranges内の範囲はそれぞれ(beg . end)
という形式のペアーである。
rangesの範囲は、以下の疑似コードのように重複せず順番に並んでいなければならない。
(cl-loop for idx from 1 to (1- (length ranges)) for prev = (nth (1- idx) ranges) for next = (nth idx ranges) should (<= (car prev) (cdr prev) (car next) (cdr next)))
rangesがこの制約に違反したり、何か他の問題が発生した場合には、この関数はtreesit-range-invalid
エラーをシグナルする。シグナルデータには特定のエラーメッセージ、セットを試みた範囲が含まれている。
この関数は範囲を無効にするためにも使うことができる。rangesがnil
の場合には、パーサーはバッファー全体をパースするようにセットされる。
例:
(treesit-parser-set-included-ranges parser '((1 . 9) (16 . 24) (24 . 25)))
この関数はparserにセットされている範囲をリターンする。リターン値はtreesit-parser-included-ranges
のranges引数と同じく(beg . end)
という形式のコンスセルのリスト。parserが範囲を何ももっていなければリターン値はnil
。
(treesit-parser-included-ranges parser) ⇒ ((1 . 9) (16 . 24) (24 . 25))
この関数はsourceをqueryでマッチングしてキャプチャーされたノードをリターンする。リターン値は(beg . end)
という形式のコンスセルのリスト。ここでbegとendはそれぞれテキスト範囲の開始と終了をする。
利便性のためにsourceは言語シンボル、パーサー、あるいはノードでもよい。この関数はそれが言語シンボルならその言語を使用する最初のパーサーのルートノード、パーサーならそのパーサーのルートノード、ノードならそのノードでマッチを行なう。
引数queryはノードのキャプチャーに用いるクエリー(tree-sitterノードにたいするパターンマッチングを参照)。引数begとendがどちらも非nil
なら、それはこの関数がクエリーを行なう範囲を制限する。
他のクエリー関数と同じように、この関数はqueryが不正であればtreesit-query-error
エラーをraiseする。
一般的なLispプログラムにおいて言語が複数ミックスされたプログラムをサポートするには、以下の2つの関数を呼び出すだけで十分です。
この関数はバッファーのパーサーの範囲を更新する。この関数はパーサーの範囲がbegとendの間に正しくセットされているかをtreesit-range-settings
に照らして確認する。省略された場合のデフォルトはbegがバッファー先頭、endがバッファー終端となる。
たとえばフォント表示(fontification)を行なう関数は、リージョン内のノードにクエリーを行う前にこの関数を使用する。
この関数はバッファー位置posにあるテキストの言語をリターンする。その背後ではtreesit-language-at-point-function
を呼び出して、そのリターンされた値をリターンしている。treesit-language-at-point-function
がnil
の場合には、この関数はtreesit-parser-list
のリターン値から最初のパーサーの言語をリターンする。バッファーにパーサーがなければnil
をリターンする。
ミックスされているかもしれない一連の言語では、ホスト言語(host language)と1つ以上の埋め込み言語(embedded languages)が存在することが珍しくありません。Lispプログラムはまずホスト言語のパーサーでドキュメント全体をパースすることで情報を得てから、それを用いて埋め込み言語の範囲をセット、その後に埋め込み言語をパースするのです。
HTML、CSS、それにJavaScriptを含むバッファーを例にとります。LispプログラムはまずHTMLパーサーでバッファー全体をパースして、それからパーサーにCSSとJavaScriptに相当するstyle_element
とscript_element
のノードをクエリーするのです。その後にCSSとJavaScriptそれぞれにたいして、対応するノードが跨がる範囲をセットします。
シンプルなHTMLドキュメントが与えられると:
<html> <script>1 + 2</script> <style>body { color: "blue"; }</style> </html>
LispプログラムはまずHTMLパーサーでパースを行い、それからCSSとJavaScriptそれぞれのパーサーにたいして範囲をセットします:
;; パーサーの作成 (setq html (treesit-parser-create 'html)) (setq css (treesit-parser-create 'css)) (setq js (treesit-parser-create 'javascript))
;; CSSの範囲をセット (setq css-range (treesit-query-range 'html '((style_element (raw_text) @capture)))) (treesit-parser-set-included-ranges css css-range)
;; JavaScriptの範囲をセット (setq js-range (treesit-query-range 'html '((script_element (raw_text) @capture)))) (treesit-parser-set-included-ranges js js-range)
treesit-update-ranges
によってEmacsがこのプロセスを自動化します。treesit-update-ranges
がプロセスを自動化する方法を解決するためには、複数言語のメジャーモードがtreesit-range-settings
をセットする必要があります。treesit-range-settings
に割り当てられる値を生成するためには、メジャーモードがヘルパー関数treesit-range-rules
を使う必要があります。この操作を直接コード化したのが以下のセッティング例になります。
(setq treesit-range-settings (treesit-range-rules :embed 'javascript :host 'html '((script_element (raw_text) @capture))
:embed 'css :host 'html '((style_element (raw_text) @capture))))
この関数はtreesit-range-settings
をセットするために用いる。クエリーのコンパイルやその他の後処理に注意を払い、treesit-range-settings
にセットできるような値を出力する。
この関数は引数として一連のquery-specを受け取る。ここでquery-specとは0個以上のkeyword/valueペアーが前置されたqueryのこと。queryはそれぞれ文字列、S式、コンパイル済みフォーム、あるいは関数のいずれかによるtree-sitterクエリーである。
queryがtree-sitterクエリーなら:keyword/valueのペアーを2つを前置すること(:keywordが:embed
は埋め込み言語、:host
はホスト言語)。
treesit-update-ranges
は埋め込み言語用のパーサーにたいして範囲をセットする方法の解決にqueryを使用する。ホスト言語パーサーにqueryを問い合わせてキャプチャーされたノードが跨ぐ範囲を計算、それらの範囲を埋め込み言語パーサーに適用するのである。
queryが関数の場合にはkeywordとvalueのペアーは必要ない。関数の場合にはstart、endという2つの引数を受け取り、カレントバッファーでstartとendの間にあるリージョンでパーサー用の範囲をセットすること。その関数がstartとendの間のリージョンを包むような広いリージョンに範囲をセットしても問題はない。
これはバッファーでtreesit-update-ranges
がパーサーにたいする範囲を更新する際の助けとなる変数である。settingのリストであり、その正確なフォーマットは内部的な使用を意図している。この変数が保持できる値を生成するにはtreesit-range-rules
を使うこと。
この変数の値はバッファー位置posを単一の引数として受け取り、posにあるテキストの言語をリターンする関数であること。この変数はtreesit-language-at
により使用される。
Next: tree-sitterを用いるメジャーモードの開発, Previous: tree-sitterノードにたいするパターンマッチング, Up: プログラムソースの解析 [Contents][Index]