Firefox Aurora(8.0a2) の Parser API で関数をパースしてみた結果からの予想
主に拡張機能での話しだが、Firefox 8 くらいから Parser API というものが導入されている。
何かって言うと、JavaScriptソースコードを構文解析するものである。詳しくは上記リンク先を。
基本的にはSpiderMonkey上から実行するのだが、Firefoxから実行するには以下の様にモジュールをロードする。
// グローバル上に Reflect なるオブジェクトがエクスポートされる。 Components.utils.import("resource://gre/modules/reflect.jsm");
ちょい思い立って関数宣言のコードを解析させてみた。
var res = Reflect.parse(<><![CDATA[ function foo(){ return 1; } ]]></>.toString(), { loc: false }); JSON.stringify(res, null, " ");
ソースコードの位置情報を収めるlocはちょっと邪魔なのでfalse
でなくしている。
結果。
{ "loc": null, "type": "Program", "body": [ { "loc": null, "type": "FunctionDeclaration", "id": { "loc": null, "type": "Identifier", "name": "foo" }, "params": [], "body": { "loc": null, "type": "BlockStatement", "body": [ { "loc": null, "type": "ReturnStatement", "argument": { "loc": null, "type": "Literal", "value": 1 } } ] }, "generator": false, "expression": false } ] }
- typeが
Program
とあるように最初はソースコード全体を示すProgramから始まる - 関数宣言なので、typeが
FunctionDeclaration
Identifier
にfoo
がある
- bodyプロパティにFunctionBodyとなるものが格納される
BlockStatement
があり、その中に、ReternStatement
がある
とまあこんな感じで解析結果がオブジェクトとなって返ってくるわけだ。
が、おや? と思うことが。
ECMAScriptでは関数宣言の構文は以下の様になる。
FunctionDeclaration: function Identifier ( FormalParameterListopt ) { FunctionBody }
関数宣言としてブロックの{}
は既に組み込まれているわけで、正しくECMAScriptとして解析されているならば、結果中のBlockStatement
は不要なのではないか? というわけだ。
ここで思い当たるのが、Mozilla JavaScriptでは以下の様な書き方が許されている点。
function foo() 1; /* ↓と同じ function foo() { return 1; } */
一つの式(Expression)を返すのならば、ブロックとreturn句を省略しても良いという構文だ。
よってSpiderMonkeyでは関数宣言の周りの構文としては
Statement: Block ... FunctionDeclaration FunctionDeclaration: function Identifier ( FormalParameterListopt ) FunctionBody FunctionBody: Block Expression
となっているのではないか。と思う。
SpiderMonkeyのソースを読む力が無いので単なる予想だけど、合っているかな?