このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

言語処理サーバーとそのプロトコル

随分と前にErlangをいじっていたとき、Distelというツールを使っていました。DistelはEmacs上のErlang開発環境なのですが、関数に対するソースの場所を実行中のErlang処理系に問い合わせます。現在のErlangソースコード群に対して一番確実な知識を持っているのはErlang処理系自身なので、その処理系に聞きにいくわけです。

TypeScriptでも同じ発想のツールがあります。tss(TSServer、https://github.com/clausreinke/typescript-tools)とtss.el(https://github.com/aki2o/emacs-tss)です。tssは、TypeScriptコンパイラの能力と知識を、対話的コマンドラインツールとして提供するものです。人間が使うものではなくて、他の開発ツールがコンパイラ機能(主に構文解析)を利用したいときに使います。tss.elは、tssサーバーと標準入出力を介して通信して、コード補完機能などを実現しています。

tssには標準入出力経由でアクセスするので、人間でも使えます。手でtssと会話してみます。黄色い部分が僕が手で入れた入力です。サンプルは昨日の記事のやつ、シェルはPowerShellです。([追記]prettyJSON使うように修正[/追記]


gulptest > tss .
"loaded c:/Users/hiyama/Work/JsDev/gulptest, TSS listening.."
help
^signature (\d+) (\d+) (.*)$
^(type|quickInfo) (\d+) (\d+) (.*)$
^definition (\d+) (\d+) (.*)$
^(references|occurrences) (\d+) (\d+) (.*)$
^navigationBarItems (.*)$
^navigateToItems (.*)$
^completions(-brief)?( true| false)? (\d+) (\d+) (.*)$
^update( nocheck)? (\d+)( (\d+)-(\d+))? (.*)$
^showErrors$
^files$
^lastError(Dump)?$
^dump (\S+) (.*)$
^reload$
^quit$
^prettyJSON (true|false)$
^help$
prettyJSON true
"pretty JSON: true"
files
[
"C:/Installed/nodist-master/bin/node_modules/typescript-tools/node_modules/typescript/bin/lib.d.ts",
"c:/Users/hiyama/Work/JsDev/gulptest"
]
type 8 10 greeter.ts
{
"kind": "function",
"kindModifiers": "export",
"textSpan": {
"start": 125,
"length": 5
},
"documentation": [
{
"text": "This function greets to someone.",
"kind": "text"
}
],
"type": "function greet(greeting: string, toWhom: string): void",
"docComment": "This function greets to someone."
}
quit
"TSS closing"

[hiyama@TP-X220-HIYAMA ~\JsDev\gulptest]
gulptest >

これ以上手で使う気はありませんが、面白いですよね。VimやEclipsのTypeScriptプラグインもtssをバックエンドに使っているらしいです。

さて、昨日の記事「最近のビルドツールって何なの?」で次のように述べました。

  • リソース間の依存関係の把握は、ビルドツールがいくら頑張っても無理。個々のファイルに関する知識を持っている依存関係スキャナーが必要。例えば、gcc -M 。
  • 使える依存関係スキャナーがない。コンパイラやトランスパイラ自身は依存関係を認識できるが、それなら当のツールを起動してコンパイル/トランスパイルしてしまったほうが単純明快。

ここのポイントは、依存関係を含めソースコードに関して一番よく知っているのは言語処理系だということです。プログラムの意図やセマンティクスに関しては人間しか知らないので、「一番」は語弊があるかも知れませんが、構文解析で得られる情報を把握しているのは言語処理系です。

しかし今までのコンパイラでは、構文解析情報を内部的に消費するだけで、その情報を他のツールから利用することが出来ませんでした。せいぜい、オプションでなにやらマップファイルの類を吐き出すくらい。インタプリタであっても、構文解析情報を提供してるとは限りません。もったいない!

言語処理系が、バッチコンパイルや対話的シェルの機能を提供するだけではなくて、サーバーとしてリクエストに応えて、自分の能力・知識を惜しげなくあまねく利用可能とすれば、けっこうみんなハッピーになれるんじゃないのかな。プロトコルは、tssがそうであるようにJSONベースが良さそう。

真逆の実例として、Emacsjs2-modeがあります。JavaScript構文解析Emacs Lispのみでまるまる再実装しています。「凄いなー」と感心しますが、頑張り過ぎな印象もあります。JavaScriptの言語仕様が変われば、エディタ内部の構文解析系も書き換えなくてはなりません。

こんなことになるのも、コンパイラインタプリタが言語処理能力を他人に提供する気がないからで、あっちこっちでブランドコピー品みたいな実装がされています。js2-modeは、それ自身で価値があるスーパーコピーといったところでしょうが。

それで結局、言語処理系は、プログラミング言語のメタオブジェクトを抱えた状態で待ち受けるサーバーとして(も)実装すべきだろうと思うわけです。やり取りのプロトコルもある程度は標準化されるのが望ましいですね。