esprimaのパーサを試してみる
2つ前の記事で紹介したJavaScript Source Transformation: Non-Destructive vs Regenerativeのコメント欄にて、esprimaというパーサがあることを知った。
さっそくnpm installして試そう・・・と思ったのだが、なんと公式サイト上で試せてしまった。
http://esprima.org/demo/parse.html
結果をみると大変分かりやすく、コメントをいれるのがうざいくらいなので、今回は貼るだけ。
この結果では、行番号などの実行時に不要な情報は抜け落ちているが、オプションをつけて色々出来るようだ。
パースする文
var g = function(x) { return 3 * x; };
結果(構文解析木)
{ type: 'Program', body: [ { type: 'VariableDeclaration', kind: 'var', declarations: [ { type: 'VariableDeclarator', id: { type: 'Identifier', name: 'g' }, init: { type: 'FunctionExpression', id: null, params: [ { type: 'Identifier', name: 'x' } ], defaults: [], body: { type: 'BlockStatement', body: [ { type: 'ReturnStatement', argument: { type: 'BinaryExpression', operator: '*', left: { type: 'Literal', value: 3, raw: '3' }, right: { type: 'Identifier', name: 'x' } } } ] }, rest: null, generator: false, expression: false } } ] } ] }
速さとかは計測してみなければ分からないけれども、趣味で使う分にはこっちだろうなー。
ところで、UglifyJSもEsprimaもJSで書かれている。これはつまり、例えばとあるコードをEsprimaでパースしようとして、それをNode.js上で動かしたとすると、EsprimaのコードはV8エンジンがパースするわけで、2度パースすることになる。(なおV8エンジンのパーサはC++で書かれている模様。)
目的が新しいコードを得ることではなく、実行時にコードを一部変更してそのまま実行させる、というような場合だったら、
V8がEsprimaのソースをパース → V8上で動いてるEsprimaがあるコードをパース → コードの構文解析木を変更 → 一旦JSの文字列として書き出す → V8がそれをパースして実行
となるわけで、なんかちょっと無駄感ある。
なのでV8のパーサを直接利用して・・・的なことは出来ないのかな?と思ったところ、
それはできないらしい。
https://groups.google.com/forum/#!topic/v8-users/_WracRX9BTQ
V8のパーサはV8の内部実装に密接に関係してるし、しょっちゅう実装変わるし、とにかく外から呼ばれるように作ってない、とのことです。