先週のありえるえりあミニ勉強会#4 ~ Google Closure Libraryにて@teppeisさんに発表していただいたfixclosureをRhinoのパーサーで書き直してみました。
https://github.com/tuchida/fixclosure-rhino
Eclipseプラグインを作ったりClosure Compilerに組み込んだりしやすくなったのではないでしょうか。まあRhinoパーサー使いたかっただけなので用途を考えてないのですが。
以下脱線してRhinoの話をします。(rhino1_7R4時点)
まずRhinoは
- 実装がJavaで作られている
- Rhinoで実行するJavaScriptからJavaを呼べる
ということはつまりRhinoで実行するJavaScriptからJavaScriptエンジンを十全に使えるということを意味します。ただの「JVM上で動くJavaScript環境」ではなく「JavaScriptのメタプログラミング環境」として使うことができます。(他のJVM上で動く言語ではどうなんでしょう?)
具体的にどんなことができるかというと
Rhinoパーサーが使える
fixclosure-rhinoで使ったやつです。
1 2 3 4 5 6 7 8 9 10 11 12 |
var ast = org.mozilla.javascript.Parser().parse('console.log("hoge");', '', 0); ast.visit(function(node) { print(org.mozilla.javascript.Token.typeToName(node) + ' => ' + node.toSource()); return true; }); // SCRIPT => console.log("hoge"); // EXPR_RESULT => console.log("hoge"); // CALL => console.log("hoge") // GETPROP => console.log // NAME => console // NAME => log // STRING => "hoge" |
本来はNodeVisitorを実装したものをParser#visitに渡すのですが、実装するメソッドが一個の場合、かつ呼び出すメソッドが一意に決まる(オーバーロードしてない)場合はjsの関数を渡すだけで済みます。今回esprimaと比較しながら使ってみてわかったのですが、astのノードの親がたどれなかったり、lexer(TokenStream.java)とparser(Parser.java)で定数(Token.java)を使いまわしているので意味が分かりにくいものがあったり(Token.COMMAって何)して、esprimaが少し羨ましいと感じました。
Proxy API
JavaオブジェクトをJSオブジェクトにラップするためのScriptableを実装することでES.nextのProxy APIのようなことができます。
1 2 3 4 5 6 |
var p = JavaAdapter(org.mozilla.javascript.Scriptable, { get: function(name, start) { return name + '|' + name; } }); p.hoge // hoge|hoge |
これを利用して社内アプリ用のSQLを書くライブラリなんてのも作りました。まあキモいので誰も使ってませんが。
スコープを汚さずにeval
例えばrequire/exportsをこんな風に実装できます。
1 2 3 4 5 6 7 |
function require(path) { var cx = org.mozilla.javascript.Context.enter(); var scope = cx.initStandardObjects(); var exports = scope['exports'] = {}; cx.evaluateString(scope, readFile(path), '<cmd>', 1, null); return exports; } |
「新しいJavaScript」
JavaScript1.8に対応してます。ES5外の機能として特に条件付きcatchとIteratorはJavaと相性がいいので押さえておくべきでしょう。あと(まだ)E4Xが使えます。
Nashornの話題なんかのときに「Rhinoは古い」と言われますが、個人的にはなかなか面白いJavaScriptエンジンだと思うんですけどね。
最近のコメント