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
  }
 ]
}
  1. typeProgramとあるように最初はソースコード全体を示すProgramから始まる
  2. 関数宣言なので、typeFunctionDeclaration
    • Identifierfooがある
  3. 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のソースを読む力が無いので単なる予想だけど、合っているかな?