LCOV - code coverage report
Current view: directory - js/src - jsreflect.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1268 711 56.1 %
Date: 2012-06-02 Functions: 137 98 71.5 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=8 sw=4 et tw=99 ft=cpp:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
      18                 :  * June 12, 2009.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  *   the Mozilla Corporation.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Dave Herman <dherman@mozilla.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : /*
      41                 :  * JS reflection package.
      42                 :  */
      43                 : #include <stdlib.h>
      44                 : 
      45                 : #include "mozilla/Util.h"
      46                 : 
      47                 : #include "jspubtd.h"
      48                 : #include "jsatom.h"
      49                 : #include "jsobj.h"
      50                 : #include "jsreflect.h"
      51                 : #include "jsprf.h"
      52                 : #include "jsiter.h"
      53                 : #include "jsbool.h"
      54                 : #include "jsval.h"
      55                 : #include "jsinferinlines.h"
      56                 : #include "jsobjinlines.h"
      57                 : #include "jsarray.h"
      58                 : #include "jsnum.h"
      59                 : 
      60                 : #include "frontend/BytecodeEmitter.h"
      61                 : #include "frontend/Parser.h"
      62                 : #include "frontend/TokenStream.h"
      63                 : #include "vm/RegExpObject.h"
      64                 : 
      65                 : #include "jsscriptinlines.h"
      66                 : 
      67                 : using namespace mozilla;
      68                 : using namespace js;
      69                 : 
      70                 : namespace js {
      71                 : 
      72                 : char const *aopNames[] = {
      73                 :     "=",    /* AOP_ASSIGN */
      74                 :     "+=",   /* AOP_PLUS */
      75                 :     "-=",   /* AOP_MINUS */
      76                 :     "*=",   /* AOP_STAR */
      77                 :     "/=",   /* AOP_DIV */
      78                 :     "%=",   /* AOP_MOD */
      79                 :     "<<=",  /* AOP_LSH */
      80                 :     ">>=",  /* AOP_RSH */
      81                 :     ">>>=", /* AOP_URSH */
      82                 :     "|=",   /* AOP_BITOR */
      83                 :     "^=",   /* AOP_BITXOR */
      84                 :     "&="    /* AOP_BITAND */
      85                 : };
      86                 : 
      87                 : char const *binopNames[] = {
      88                 :     "==",         /* BINOP_EQ */
      89                 :     "!=",         /* BINOP_NE */
      90                 :     "===",        /* BINOP_STRICTEQ */
      91                 :     "!==",        /* BINOP_STRICTNE */
      92                 :     "<",          /* BINOP_LT */
      93                 :     "<=",         /* BINOP_LE */
      94                 :     ">",          /* BINOP_GT */
      95                 :     ">=",         /* BINOP_GE */
      96                 :     "<<",         /* BINOP_LSH */
      97                 :     ">>",         /* BINOP_RSH */
      98                 :     ">>>",        /* BINOP_URSH */
      99                 :     "+",          /* BINOP_PLUS */
     100                 :     "-",          /* BINOP_MINUS */
     101                 :     "*",          /* BINOP_STAR */
     102                 :     "/",          /* BINOP_DIV */
     103                 :     "%",          /* BINOP_MOD */
     104                 :     "|",          /* BINOP_BITOR */
     105                 :     "^",          /* BINOP_BITXOR */
     106                 :     "&",          /* BINOP_BITAND */
     107                 :     "in",         /* BINOP_IN */
     108                 :     "instanceof", /* BINOP_INSTANCEOF */
     109                 :     "..",         /* BINOP_DBLDOT */
     110                 : };
     111                 : 
     112                 : char const *unopNames[] = {
     113                 :     "delete",  /* UNOP_DELETE */
     114                 :     "-",       /* UNOP_NEG */
     115                 :     "+",       /* UNOP_POS */
     116                 :     "!",       /* UNOP_NOT */
     117                 :     "~",       /* UNOP_BITNOT */
     118                 :     "typeof",  /* UNOP_TYPEOF */
     119                 :     "void"     /* UNOP_VOID */
     120                 : };
     121                 : 
     122                 : char const *nodeTypeNames[] = {
     123                 : #define ASTDEF(ast, str, method) str,
     124                 : #include "jsast.tbl"
     125                 : #undef ASTDEF
     126                 :     NULL
     127                 : };
     128                 : 
     129                 : char const *callbackNames[] = {
     130                 : #define ASTDEF(ast, str, method) method,
     131                 : #include "jsast.tbl"
     132                 : #undef ASTDEF
     133                 :     NULL
     134                 : };
     135                 : 
     136                 : typedef AutoValueVector NodeVector;
     137                 : 
     138                 : /*
     139                 :  * ParseNode is a somewhat intricate data structure, and its invariants have
     140                 :  * evolved, making it more likely that there could be a disconnect between the
     141                 :  * parser and the AST serializer. We use these macros to check invariants on a
     142                 :  * parse node and raise a dynamic error on failure.
     143                 :  */
     144                 : #define LOCAL_ASSERT(expr)                                                             \
     145                 :     JS_BEGIN_MACRO                                                                     \
     146                 :         JS_ASSERT(expr);                                                               \
     147                 :         if (!(expr)) {                                                                 \
     148                 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PARSE_NODE);  \
     149                 :             return false;                                                              \
     150                 :         }                                                                              \
     151                 :     JS_END_MACRO
     152                 : 
     153                 : #define LOCAL_NOT_REACHED(expr)                                                        \
     154                 :     JS_BEGIN_MACRO                                                                     \
     155                 :         JS_NOT_REACHED(expr);                                                          \
     156                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PARSE_NODE);      \
     157                 :         return false;                                                                  \
     158                 :     JS_END_MACRO
     159                 : 
     160                 : 
     161                 : /*
     162                 :  * Builder class that constructs JavaScript AST node objects. See:
     163                 :  *
     164                 :  *     https://developer.mozilla.org/en/SpiderMonkey/Parser_API
     165                 :  *
     166                 :  * Bug 569487: generalize builder interface
     167                 :  */
     168                 : class NodeBuilder
     169                 : {
     170                 :     JSContext   *cx;
     171                 :     bool        saveLoc;               /* save source location information?     */
     172                 :     char const  *src;                  /* source filename or null               */
     173                 :     Value       srcval;                /* source filename JS value or null      */
     174                 :     Value       callbacks[AST_LIMIT];  /* user-specified callbacks              */
     175                 :     Value       userv;                 /* user-specified builder object or null */
     176                 : 
     177                 :   public:
     178            2278 :     NodeBuilder(JSContext *c, bool l, char const *s)
     179            2278 :         : cx(c), saveLoc(l), src(s) {
     180            2278 :     }
     181                 : 
     182            2278 :     bool init(JSObject *userobj = NULL) {
     183            2278 :         if (src) {
     184               0 :             if (!atomValue(src, &srcval))
     185               0 :                 return false;
     186                 :         } else {
     187            2278 :             srcval.setNull();
     188                 :         }
     189                 : 
     190            2278 :         if (!userobj) {
     191            2278 :             userv.setNull();
     192          159460 :             for (unsigned i = 0; i < AST_LIMIT; i++) {
     193          157182 :                 callbacks[i].setNull();
     194                 :             }
     195            2278 :             return true;
     196                 :         }
     197                 : 
     198               0 :         userv.setObject(*userobj);
     199                 : 
     200               0 :         for (unsigned i = 0; i < AST_LIMIT; i++) {
     201                 :             Value funv;
     202                 : 
     203               0 :             const char *name = callbackNames[i];
     204               0 :             JSAtom *atom = js_Atomize(cx, name, strlen(name));
     205               0 :             if (!atom || !GetPropertyDefault(cx, userobj, ATOM_TO_JSID(atom), NullValue(), &funv))
     206               0 :                 return false;
     207                 : 
     208               0 :             if (funv.isNullOrUndefined()) {
     209               0 :                 callbacks[i].setNull();
     210               0 :                 continue;
     211                 :             }
     212                 : 
     213               0 :             if (!funv.isObject() || !funv.toObject().isFunction()) {
     214                 :                 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NOT_FUNCTION,
     215               0 :                                          JSDVG_SEARCH_STACK, funv, NULL, NULL, NULL);
     216               0 :                 return false;
     217                 :             }
     218                 : 
     219               0 :             callbacks[i] = funv;
     220                 :         }
     221                 : 
     222               0 :         return true;
     223                 :     }
     224                 : 
     225                 :   private:
     226               0 :     bool callback(Value fun, TokenPos *pos, Value *dst) {
     227               0 :         if (saveLoc) {
     228                 :             Value loc;
     229               0 :             if (!newNodeLoc(pos, &loc))
     230               0 :                 return false;
     231               0 :             Value argv[] = { loc };
     232               0 :             return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
     233                 :         }
     234                 : 
     235               0 :         Value argv[] = { NullValue() }; /* no zero-length arrays allowed! */
     236               0 :         return Invoke(cx, userv, fun, 0, argv, dst);
     237                 :     }
     238                 : 
     239               0 :     bool callback(Value fun, Value v1, TokenPos *pos, Value *dst) {
     240               0 :         if (saveLoc) {
     241                 :             Value loc;
     242               0 :             if (!newNodeLoc(pos, &loc))
     243               0 :                 return false;
     244               0 :             Value argv[] = { v1, loc };
     245               0 :             return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
     246                 :         }
     247                 : 
     248               0 :         Value argv[] = { v1 };
     249               0 :         return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
     250                 :     }
     251                 : 
     252               0 :     bool callback(Value fun, Value v1, Value v2, TokenPos *pos, Value *dst) {
     253               0 :         if (saveLoc) {
     254                 :             Value loc;
     255               0 :             if (!newNodeLoc(pos, &loc))
     256               0 :                 return false;
     257               0 :             Value argv[] = { v1, v2, loc };
     258               0 :             return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
     259                 :         }
     260                 : 
     261               0 :         Value argv[] = { v1, v2 };
     262               0 :         return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
     263                 :     }
     264                 : 
     265               0 :     bool callback(Value fun, Value v1, Value v2, Value v3, TokenPos *pos, Value *dst) {
     266               0 :         if (saveLoc) {
     267                 :             Value loc;
     268               0 :             if (!newNodeLoc(pos, &loc))
     269               0 :                 return false;
     270               0 :             Value argv[] = { v1, v2, v3, loc };
     271               0 :             return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
     272                 :         }
     273                 : 
     274               0 :         Value argv[] = { v1, v2, v3 };
     275               0 :         return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
     276                 :     }
     277                 : 
     278               0 :     bool callback(Value fun, Value v1, Value v2, Value v3, Value v4, TokenPos *pos, Value *dst) {
     279               0 :         if (saveLoc) {
     280                 :             Value loc;
     281               0 :             if (!newNodeLoc(pos, &loc))
     282               0 :                 return false;
     283               0 :             Value argv[] = { v1, v2, v3, v4, loc };
     284               0 :             return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
     285                 :         }
     286                 : 
     287               0 :         Value argv[] = { v1, v2, v3, v4 };
     288               0 :         return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
     289                 :     }
     290                 : 
     291               0 :     bool callback(Value fun, Value v1, Value v2, Value v3, Value v4, Value v5,
     292                 :                   TokenPos *pos, Value *dst) {
     293               0 :         if (saveLoc) {
     294                 :             Value loc;
     295               0 :             if (!newNodeLoc(pos, &loc))
     296               0 :                 return false;
     297               0 :             Value argv[] = { v1, v2, v3, v4, v5, loc };
     298               0 :             return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
     299                 :         }
     300                 : 
     301               0 :         Value argv[] = { v1, v2, v3, v4, v5 };
     302               0 :         return Invoke(cx, userv, fun, ArrayLength(argv), argv, dst);
     303                 :     }
     304                 : 
     305               0 :     Value opt(Value v) {
     306               0 :         JS_ASSERT_IF(v.isMagic(), v.whyMagic() == JS_SERIALIZE_NO_NODE);
     307               0 :         return v.isMagic(JS_SERIALIZE_NO_NODE) ? UndefinedValue() : v;
     308                 :     }
     309                 : 
     310           48585 :     bool atomValue(const char *s, Value *dst) {
     311                 :         /*
     312                 :          * Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
     313                 :          */
     314           48585 :         JSAtom *atom = js_Atomize(cx, s, strlen(s));
     315           48585 :         if (!atom)
     316               0 :             return false;
     317                 : 
     318           48585 :         dst->setString(atom);
     319           48585 :         return true;
     320                 :     }
     321                 : 
     322          127665 :     bool newObject(JSObject **dst) {
     323          127665 :         JSObject *nobj = NewBuiltinClassInstance(cx, &ObjectClass);
     324          127665 :         if (!nobj)
     325               0 :             return false;
     326                 : 
     327          127665 :         *dst = nobj;
     328          127665 :         return true;
     329                 :     }
     330                 : 
     331                 :     bool newArray(NodeVector &elts, Value *dst);
     332                 : 
     333                 :     bool newNode(ASTType type, TokenPos *pos, JSObject **dst);
     334                 : 
     335              63 :     bool newNode(ASTType type, TokenPos *pos, Value *dst) {
     336                 :         JSObject *node;
     337              63 :         return newNode(type, pos, &node) &&
     338              63 :                setResult(node, dst);
     339                 :     }
     340                 : 
     341           32232 :     bool newNode(ASTType type, TokenPos *pos, const char *childName, Value child, Value *dst) {
     342                 :         JSObject *node;
     343           32232 :         return newNode(type, pos, &node) &&
     344           32232 :                setProperty(node, childName, child) &&
     345           64464 :                setResult(node, dst);
     346                 :     }
     347                 : 
     348            6615 :     bool newNode(ASTType type, TokenPos *pos,
     349                 :                  const char *childName1, Value child1,
     350                 :                  const char *childName2, Value child2,
     351                 :                  Value *dst) {
     352                 :         JSObject *node;
     353            6615 :         return newNode(type, pos, &node) &&
     354            6615 :                setProperty(node, childName1, child1) &&
     355            6615 :                setProperty(node, childName2, child2) &&
     356           19845 :                setResult(node, dst);
     357                 :     }
     358                 : 
     359            3231 :     bool newNode(ASTType type, TokenPos *pos,
     360                 :                  const char *childName1, Value child1,
     361                 :                  const char *childName2, Value child2,
     362                 :                  const char *childName3, Value child3,
     363                 :                  Value *dst) {
     364                 :         JSObject *node;
     365            3231 :         return newNode(type, pos, &node) &&
     366            3231 :                setProperty(node, childName1, child1) &&
     367            3231 :                setProperty(node, childName2, child2) &&
     368            3231 :                setProperty(node, childName3, child3) &&
     369           12924 :                setResult(node, dst);
     370                 :     }
     371                 : 
     372             558 :     bool newNode(ASTType type, TokenPos *pos,
     373                 :                  const char *childName1, Value child1,
     374                 :                  const char *childName2, Value child2,
     375                 :                  const char *childName3, Value child3,
     376                 :                  const char *childName4, Value child4,
     377                 :                  Value *dst) {
     378                 :         JSObject *node;
     379             558 :         return newNode(type, pos, &node) &&
     380             558 :                setProperty(node, childName1, child1) &&
     381             558 :                setProperty(node, childName2, child2) &&
     382             558 :                setProperty(node, childName3, child3) &&
     383             558 :                setProperty(node, childName4, child4) &&
     384            2790 :                setResult(node, dst);
     385                 :     }
     386                 : 
     387            2313 :     bool newNode(ASTType type, TokenPos *pos,
     388                 :                  const char *childName1, Value child1,
     389                 :                  const char *childName2, Value child2,
     390                 :                  const char *childName3, Value child3,
     391                 :                  const char *childName4, Value child4,
     392                 :                  const char *childName5, Value child5,
     393                 :                  Value *dst) {
     394                 :         JSObject *node;
     395            2313 :         return newNode(type, pos, &node) &&
     396            2313 :                setProperty(node, childName1, child1) &&
     397            2313 :                setProperty(node, childName2, child2) &&
     398            2313 :                setProperty(node, childName3, child3) &&
     399            2313 :                setProperty(node, childName4, child4) &&
     400            2313 :                setProperty(node, childName5, child5) &&
     401           13878 :                setResult(node, dst);
     402                 :     }
     403                 : 
     404            9892 :     bool listNode(ASTType type, const char *propName, NodeVector &elts, TokenPos *pos, Value *dst) {
     405                 :         Value array;
     406            9892 :         if (!newArray(elts, &array))
     407               0 :             return false;
     408                 : 
     409            9892 :         Value cb = callbacks[type];
     410            9892 :         if (!cb.isNull())
     411               0 :             return callback(cb, array, pos, dst);
     412                 : 
     413            9892 :         return newNode(type, pos, propName, array, dst);
     414                 :     }
     415                 : 
     416          456861 :     bool setProperty(JSObject *obj, const char *name, Value val) {
     417          456861 :         JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
     418                 : 
     419                 :         /* Represent "no node" as null and ensure users are not exposed to magic values. */
     420          456861 :         if (val.isMagic(JS_SERIALIZE_NO_NODE))
     421            1602 :             val.setNull();
     422                 : 
     423                 :         /*
     424                 :          * Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
     425                 :          */
     426          456861 :         JSAtom *atom = js_Atomize(cx, name, strlen(name));
     427          456861 :         if (!atom)
     428               0 :             return false;
     429                 : 
     430          456861 :         return obj->defineProperty(cx, atom->asPropertyName(), val);
     431                 :     }
     432                 : 
     433                 :     bool newNodeLoc(TokenPos *pos, Value *dst);
     434                 : 
     435                 :     bool setNodeLoc(JSObject *obj, TokenPos *pos);
     436                 : 
     437           45012 :     bool setResult(JSObject *obj, Value *dst) {
     438           45012 :         JS_ASSERT(obj);
     439           45012 :         dst->setObject(*obj);
     440           45012 :         return true;
     441                 :     }
     442                 : 
     443                 :   public:
     444                 :     /*
     445                 :      * All of the public builder methods take as their last two
     446                 :      * arguments a nullable token position and a non-nullable, rooted
     447                 :      * outparam.
     448                 :      *
     449                 :      * All Value arguments are rooted. Any Value arguments representing
     450                 :      * optional subnodes may be a JS_SERIALIZE_NO_NODE magic value.
     451                 :      */
     452                 : 
     453                 :     /*
     454                 :      * misc nodes
     455                 :      */
     456                 : 
     457                 :     bool program(NodeVector &elts, TokenPos *pos, Value *dst);
     458                 : 
     459                 :     bool literal(Value val, TokenPos *pos, Value *dst);
     460                 : 
     461                 :     bool identifier(Value name, TokenPos *pos, Value *dst);
     462                 : 
     463                 :     bool function(ASTType type, TokenPos *pos,
     464                 :                   Value id, NodeVector &args, Value body,
     465                 :                   bool isGenerator, bool isExpression, Value *dst);
     466                 : 
     467                 :     bool variableDeclarator(Value id, Value init, TokenPos *pos, Value *dst);
     468                 : 
     469                 :     bool switchCase(Value expr, NodeVector &elts, TokenPos *pos, Value *dst);
     470                 : 
     471                 :     bool catchClause(Value var, Value guard, Value body, TokenPos *pos, Value *dst);
     472                 : 
     473                 :     bool propertyInitializer(Value key, Value val, PropKind kind, TokenPos *pos, Value *dst);
     474                 : 
     475                 : 
     476                 :     /*
     477                 :      * statements
     478                 :      */
     479                 : 
     480                 :     bool blockStatement(NodeVector &elts, TokenPos *pos, Value *dst);
     481                 : 
     482                 :     bool expressionStatement(Value expr, TokenPos *pos, Value *dst);
     483                 : 
     484                 :     bool emptyStatement(TokenPos *pos, Value *dst);
     485                 : 
     486                 :     bool ifStatement(Value test, Value cons, Value alt, TokenPos *pos, Value *dst);
     487                 : 
     488                 :     bool breakStatement(Value label, TokenPos *pos, Value *dst);
     489                 : 
     490                 :     bool continueStatement(Value label, TokenPos *pos, Value *dst);
     491                 : 
     492                 :     bool labeledStatement(Value label, Value stmt, TokenPos *pos, Value *dst);
     493                 : 
     494                 :     bool throwStatement(Value arg, TokenPos *pos, Value *dst);
     495                 : 
     496                 :     bool returnStatement(Value arg, TokenPos *pos, Value *dst);
     497                 : 
     498                 :     bool forStatement(Value init, Value test, Value update, Value stmt,
     499                 :                       TokenPos *pos, Value *dst);
     500                 : 
     501                 :     bool forInStatement(Value var, Value expr, Value stmt,
     502                 :                         bool isForEach, TokenPos *pos, Value *dst);
     503                 : 
     504                 :     bool withStatement(Value expr, Value stmt, TokenPos *pos, Value *dst);
     505                 : 
     506                 :     bool whileStatement(Value test, Value stmt, TokenPos *pos, Value *dst);
     507                 : 
     508                 :     bool doWhileStatement(Value stmt, Value test, TokenPos *pos, Value *dst);
     509                 : 
     510                 :     bool switchStatement(Value disc, NodeVector &elts, bool lexical, TokenPos *pos, Value *dst);
     511                 : 
     512                 :     bool tryStatement(Value body, NodeVector &catches, Value finally, TokenPos *pos, Value *dst);
     513                 : 
     514                 :     bool debuggerStatement(TokenPos *pos, Value *dst);
     515                 : 
     516                 :     bool letStatement(NodeVector &head, Value stmt, TokenPos *pos, Value *dst);
     517                 : 
     518                 :     /*
     519                 :      * expressions
     520                 :      */
     521                 : 
     522                 :     bool binaryExpression(BinaryOperator op, Value left, Value right, TokenPos *pos, Value *dst);
     523                 : 
     524                 :     bool unaryExpression(UnaryOperator op, Value expr, TokenPos *pos, Value *dst);
     525                 : 
     526                 :     bool assignmentExpression(AssignmentOperator op, Value lhs, Value rhs,
     527                 :                               TokenPos *pos, Value *dst);
     528                 : 
     529                 :     bool updateExpression(Value expr, bool incr, bool prefix, TokenPos *pos, Value *dst);
     530                 : 
     531                 :     bool logicalExpression(bool lor, Value left, Value right, TokenPos *pos, Value *dst);
     532                 : 
     533                 :     bool conditionalExpression(Value test, Value cons, Value alt, TokenPos *pos, Value *dst);
     534                 : 
     535                 :     bool sequenceExpression(NodeVector &elts, TokenPos *pos, Value *dst);
     536                 : 
     537                 :     bool newExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst);
     538                 : 
     539                 :     bool callExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst);
     540                 : 
     541                 :     bool memberExpression(bool computed, Value expr, Value member, TokenPos *pos, Value *dst);
     542                 : 
     543                 :     bool arrayExpression(NodeVector &elts, TokenPos *pos, Value *dst);
     544                 : 
     545                 :     bool objectExpression(NodeVector &elts, TokenPos *pos, Value *dst);
     546                 : 
     547                 :     bool thisExpression(TokenPos *pos, Value *dst);
     548                 : 
     549                 :     bool yieldExpression(Value arg, TokenPos *pos, Value *dst);
     550                 : 
     551                 :     bool comprehensionBlock(Value patt, Value src, bool isForEach, TokenPos *pos, Value *dst);
     552                 : 
     553                 :     bool comprehensionExpression(Value body, NodeVector &blocks, Value filter,
     554                 :                                  TokenPos *pos, Value *dst);
     555                 : 
     556                 :     bool generatorExpression(Value body, NodeVector &blocks, Value filter,
     557                 :                              TokenPos *pos, Value *dst);
     558                 : 
     559                 :     bool letExpression(NodeVector &head, Value expr, TokenPos *pos, Value *dst);
     560                 : 
     561                 :     /*
     562                 :      * declarations
     563                 :      */
     564                 : 
     565                 :     bool variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos, Value *dst);
     566                 : 
     567                 :     /*
     568                 :      * patterns
     569                 :      */
     570                 : 
     571                 :     bool arrayPattern(NodeVector &elts, TokenPos *pos, Value *dst);
     572                 : 
     573                 :     bool objectPattern(NodeVector &elts, TokenPos *pos, Value *dst);
     574                 : 
     575                 :     bool propertyPattern(Value key, Value patt, TokenPos *pos, Value *dst);
     576                 : 
     577                 :     /*
     578                 :      * xml
     579                 :      */
     580                 : 
     581                 :     bool xmlAnyName(TokenPos *pos, Value *dst);
     582                 : 
     583                 :     bool xmlEscapeExpression(Value expr, TokenPos *pos, Value *dst);
     584                 : 
     585                 :     bool xmlDefaultNamespace(Value ns, TokenPos *pos, Value *dst);
     586                 : 
     587                 :     bool xmlFilterExpression(Value left, Value right, TokenPos *pos, Value *dst);
     588                 : 
     589                 :     bool xmlAttributeSelector(Value expr, bool computed, TokenPos *pos, Value *dst);
     590                 : 
     591                 :     bool xmlQualifiedIdentifier(Value left, Value right, bool computed, TokenPos *pos, Value *dst);
     592                 : 
     593                 :     bool xmlFunctionQualifiedIdentifier(Value right, bool computed, TokenPos *pos, Value *dst);
     594                 : 
     595                 :     bool xmlElement(NodeVector &elts, TokenPos *pos, Value *dst);
     596                 : 
     597                 :     bool xmlText(Value text, TokenPos *pos, Value *dst);
     598                 : 
     599                 :     bool xmlList(NodeVector &elts, TokenPos *pos, Value *dst);
     600                 : 
     601                 :     bool xmlStartTag(NodeVector &elts, TokenPos *pos, Value *dst);
     602                 : 
     603                 :     bool xmlEndTag(NodeVector &elts, TokenPos *pos, Value *dst);
     604                 : 
     605                 :     bool xmlPointTag(NodeVector &elts, TokenPos *pos, Value *dst);
     606                 : 
     607                 :     bool xmlName(Value text, TokenPos *pos, Value *dst);
     608                 : 
     609                 :     bool xmlName(NodeVector &elts, TokenPos *pos, Value *dst);
     610                 : 
     611                 :     bool xmlAttribute(Value text, TokenPos *pos, Value *dst);
     612                 : 
     613                 :     bool xmlCdata(Value text, TokenPos *pos, Value *dst);
     614                 : 
     615                 :     bool xmlComment(Value text, TokenPos *pos, Value *dst);
     616                 : 
     617                 :     bool xmlPI(Value target, Value content, TokenPos *pos, Value *dst);
     618                 : };
     619                 : 
     620                 : bool
     621           45012 : NodeBuilder::newNode(ASTType type, TokenPos *pos, JSObject **dst)
     622                 : {
     623           45012 :     JS_ASSERT(type > AST_ERROR && type < AST_LIMIT);
     624                 : 
     625                 :     Value tv;
     626                 : 
     627           45012 :     JSObject *node = NewBuiltinClassInstance(cx, &ObjectClass);
     628          180048 :     if (!node ||
     629           45012 :         !setNodeLoc(node, pos) ||
     630           45012 :         !atomValue(nodeTypeNames[type], &tv) ||
     631           45012 :         !setProperty(node, "type", tv)) {
     632               0 :         return false;
     633                 :     }
     634                 : 
     635           45012 :     *dst = node;
     636           45012 :     return true;
     637                 : }
     638                 : 
     639                 : bool
     640           15940 : NodeBuilder::newArray(NodeVector &elts, Value *dst)
     641                 : {
     642           15940 :     const size_t len = elts.length();
     643                 :     if (len > UINT32_MAX) {
     644                 :         js_ReportAllocationOverflow(cx);
     645                 :         return false;
     646                 :     }
     647           15940 :     JSObject *array = NewDenseAllocatedArray(cx, uint32_t(len));
     648           15940 :     if (!array)
     649               0 :         return false;
     650                 : 
     651           34031 :     for (size_t i = 0; i < len; i++) {
     652           18091 :         Value val = elts[i];
     653                 : 
     654           18091 :         JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
     655                 : 
     656                 :         /* Represent "no node" as an array hole by not adding the value. */
     657           18091 :         if (val.isMagic(JS_SERIALIZE_NO_NODE))
     658             342 :             continue;
     659                 : 
     660           17749 :         if (!array->setElement(cx, i, &val, false))
     661               0 :             return false;
     662                 :     }
     663                 : 
     664           15940 :     dst->setObject(*array);
     665           15940 :     return true;
     666                 : }
     667                 : 
     668                 : bool
     669           45012 : NodeBuilder::newNodeLoc(TokenPos *pos, Value *dst)
     670                 : {
     671           45012 :     if (!pos) {
     672            2457 :         dst->setNull();
     673            2457 :         return true;
     674                 :     }
     675                 :  
     676                 :     JSObject *loc, *to;
     677                 :     Value tv;
     678                 : 
     679           42555 :     if (!newObject(&loc))
     680               0 :         return false;
     681                 : 
     682           42555 :     dst->setObject(*loc);
     683                 : 
     684           42555 :     return newObject(&to) &&
     685           42555 :            setProperty(loc, "start", ObjectValue(*to)) &&
     686           42555 :            (tv.setNumber(pos->begin.lineno), true) &&
     687           42555 :            setProperty(to, "line", tv) &&
     688           42555 :            (tv.setNumber(pos->begin.index), true) &&
     689           42555 :            setProperty(to, "column", tv) &&
     690                 : 
     691           42555 :            newObject(&to) &&
     692           42555 :            setProperty(loc, "end", ObjectValue(*to)) &&
     693           42555 :            (tv.setNumber(pos->end.lineno), true) &&
     694           42555 :            setProperty(to, "line", tv) &&
     695           42555 :            (tv.setNumber(pos->end.index), true) &&
     696           42555 :            setProperty(to, "column", tv) &&
     697                 : 
     698          510660 :            setProperty(loc, "source", srcval);
     699                 : }
     700                 : 
     701                 : bool
     702           45012 : NodeBuilder::setNodeLoc(JSObject *node, TokenPos *pos)
     703                 : {
     704           45012 :     if (!saveLoc) {
     705               0 :         setProperty(node, "loc", NullValue());
     706               0 :         return true;
     707                 :     }
     708                 : 
     709                 :     Value loc;
     710           45012 :     return newNodeLoc(pos, &loc) &&
     711           45012 :            setProperty(node, "loc", loc);
     712                 : }
     713                 : 
     714                 : bool
     715            2278 : NodeBuilder::program(NodeVector &elts, TokenPos *pos, Value *dst)
     716                 : {
     717            2278 :     return listNode(AST_PROGRAM, "body", elts, pos, dst);
     718                 : }
     719                 : 
     720                 : bool
     721            4095 : NodeBuilder::blockStatement(NodeVector &elts, TokenPos *pos, Value *dst)
     722                 : {
     723            4095 :     return listNode(AST_BLOCK_STMT, "body", elts, pos, dst);
     724                 : }
     725                 : 
     726                 : bool
     727            2656 : NodeBuilder::expressionStatement(Value expr, TokenPos *pos, Value *dst)
     728                 : {
     729            2656 :     Value cb = callbacks[AST_EXPR_STMT];
     730            2656 :     if (!cb.isNull())
     731               0 :         return callback(cb, expr, pos, dst);
     732                 : 
     733            2656 :     return newNode(AST_EXPR_STMT, pos, "expression", expr, dst);
     734                 : }
     735                 : 
     736                 : bool
     737               9 : NodeBuilder::emptyStatement(TokenPos *pos, Value *dst)
     738                 : {
     739               9 :     Value cb = callbacks[AST_EMPTY_STMT];
     740               9 :     if (!cb.isNull())
     741               0 :         return callback(cb, pos, dst);
     742                 : 
     743               9 :     return newNode(AST_EMPTY_STMT, pos, dst);
     744                 : }
     745                 : 
     746                 : bool
     747             423 : NodeBuilder::ifStatement(Value test, Value cons, Value alt, TokenPos *pos, Value *dst)
     748                 : {
     749             423 :     Value cb = callbacks[AST_IF_STMT];
     750             423 :     if (!cb.isNull())
     751               0 :         return callback(cb, test, cons, opt(alt), pos, dst);
     752                 : 
     753                 :     return newNode(AST_IF_STMT, pos,
     754                 :                    "test", test,
     755                 :                    "consequent", cons,
     756                 :                    "alternate", alt,
     757             423 :                    dst);
     758                 : }
     759                 : 
     760                 : bool
     761              72 : NodeBuilder::breakStatement(Value label, TokenPos *pos, Value *dst)
     762                 : {
     763              72 :     Value cb = callbacks[AST_BREAK_STMT];
     764              72 :     if (!cb.isNull())
     765               0 :         return callback(cb, opt(label), pos, dst);
     766                 : 
     767              72 :     return newNode(AST_BREAK_STMT, pos, "label", label, dst);
     768                 : }
     769                 : 
     770                 : bool
     771               0 : NodeBuilder::continueStatement(Value label, TokenPos *pos, Value *dst)
     772                 : {
     773               0 :     Value cb = callbacks[AST_CONTINUE_STMT];
     774               0 :     if (!cb.isNull())
     775               0 :         return callback(cb, opt(label), pos, dst);
     776                 : 
     777               0 :     return newNode(AST_CONTINUE_STMT, pos, "label", label, dst);
     778                 : }
     779                 : 
     780                 : bool
     781              18 : NodeBuilder::labeledStatement(Value label, Value stmt, TokenPos *pos, Value *dst)
     782                 : {
     783              18 :     Value cb = callbacks[AST_LAB_STMT];
     784              18 :     if (!cb.isNull())
     785               0 :         return callback(cb, label, stmt, pos, dst);
     786                 : 
     787                 :     return newNode(AST_LAB_STMT, pos,
     788                 :                    "label", label,
     789                 :                    "body", stmt,
     790              18 :                    dst);
     791                 : }
     792                 : 
     793                 : bool
     794              27 : NodeBuilder::throwStatement(Value arg, TokenPos *pos, Value *dst)
     795                 : {
     796              27 :     Value cb = callbacks[AST_THROW_STMT];
     797              27 :     if (!cb.isNull())
     798               0 :         return callback(cb, arg, pos, dst);
     799                 : 
     800              27 :     return newNode(AST_THROW_STMT, pos, "argument", arg, dst);
     801                 : }
     802                 : 
     803                 : bool
     804            2358 : NodeBuilder::returnStatement(Value arg, TokenPos *pos, Value *dst)
     805                 : {
     806            2358 :     Value cb = callbacks[AST_RETURN_STMT];
     807            2358 :     if (!cb.isNull())
     808               0 :         return callback(cb, opt(arg), pos, dst);
     809                 : 
     810            2358 :     return newNode(AST_RETURN_STMT, pos, "argument", arg, dst);
     811                 : }
     812                 : 
     813                 : bool
     814             315 : NodeBuilder::forStatement(Value init, Value test, Value update, Value stmt,
     815                 :                           TokenPos *pos, Value *dst)
     816                 : {
     817             315 :     Value cb = callbacks[AST_FOR_STMT];
     818             315 :     if (!cb.isNull())
     819               0 :         return callback(cb, opt(init), opt(test), opt(update), stmt, pos, dst);
     820                 : 
     821                 :     return newNode(AST_FOR_STMT, pos,
     822                 :                    "init", init,
     823                 :                    "test", test,
     824                 :                    "update", update,
     825                 :                    "body", stmt,
     826             315 :                    dst);
     827                 : }
     828                 : 
     829                 : bool
     830             243 : NodeBuilder::forInStatement(Value var, Value expr, Value stmt, bool isForEach,
     831                 :                             TokenPos *pos, Value *dst)
     832                 : {
     833             243 :     Value cb = callbacks[AST_FOR_IN_STMT];
     834             243 :     if (!cb.isNull())
     835               0 :         return callback(cb, var, expr, stmt, BooleanValue(isForEach), pos, dst);
     836                 : 
     837                 :     return newNode(AST_FOR_IN_STMT, pos,
     838                 :                    "left", var,
     839                 :                    "right", expr,
     840                 :                    "body", stmt,
     841             243 :                    "each", BooleanValue(isForEach),
     842             243 :                    dst);
     843                 : }
     844                 : 
     845                 : bool
     846               0 : NodeBuilder::withStatement(Value expr, Value stmt, TokenPos *pos, Value *dst)
     847                 : {
     848               0 :     Value cb = callbacks[AST_WITH_STMT];
     849               0 :     if (!cb.isNull())
     850               0 :         return callback(cb, expr, stmt, pos, dst);
     851                 : 
     852                 :     return newNode(AST_WITH_STMT, pos,
     853                 :                    "object", expr,
     854                 :                    "body", stmt,
     855               0 :                    dst);
     856                 : }
     857                 : 
     858                 : bool
     859               0 : NodeBuilder::whileStatement(Value test, Value stmt, TokenPos *pos, Value *dst)
     860                 : {
     861               0 :     Value cb = callbacks[AST_WHILE_STMT];
     862               0 :     if (!cb.isNull())
     863               0 :         return callback(cb, test, stmt, pos, dst);
     864                 : 
     865                 :     return newNode(AST_WHILE_STMT, pos,
     866                 :                    "test", test,
     867                 :                    "body", stmt,
     868               0 :                    dst);
     869                 : }
     870                 : 
     871                 : bool
     872               0 : NodeBuilder::doWhileStatement(Value stmt, Value test, TokenPos *pos, Value *dst)
     873                 : {
     874               0 :     Value cb = callbacks[AST_DO_STMT];
     875               0 :     if (!cb.isNull())
     876               0 :         return callback(cb, stmt, test, pos, dst);
     877                 : 
     878                 :     return newNode(AST_DO_STMT, pos,
     879                 :                    "body", stmt,
     880                 :                    "test", test,
     881               0 :                    dst);
     882                 : }
     883                 : 
     884                 : bool
     885              36 : NodeBuilder::switchStatement(Value disc, NodeVector &elts, bool lexical, TokenPos *pos, Value *dst)
     886                 : {
     887                 :     Value array;
     888              36 :     if (!newArray(elts, &array))
     889               0 :         return false;
     890                 : 
     891              36 :     Value cb = callbacks[AST_SWITCH_STMT];
     892              36 :     if (!cb.isNull())
     893               0 :         return callback(cb, disc, array, BooleanValue(lexical), pos, dst);
     894                 : 
     895                 :     return newNode(AST_SWITCH_STMT, pos,
     896                 :                    "discriminant", disc,
     897                 :                    "cases", array,
     898              36 :                    "lexical", BooleanValue(lexical),
     899              36 :                    dst);
     900                 : }
     901                 : 
     902                 : bool
     903             135 : NodeBuilder::tryStatement(Value body, NodeVector &catches, Value finally,
     904                 :                           TokenPos *pos, Value *dst)
     905                 : {
     906                 :     Value handlers;
     907                 : 
     908             135 :     Value cb = callbacks[AST_TRY_STMT];
     909             135 :     if (!cb.isNull()) {
     910               0 :         return newArray(catches, &handlers) &&
     911               0 :                callback(cb, body, handlers, opt(finally), pos, dst);
     912                 :     }
     913                 : 
     914             135 :     if (!newArray(catches, &handlers))
     915               0 :         return false;
     916                 : 
     917                 :     return newNode(AST_TRY_STMT, pos,
     918                 :                    "block", body,
     919                 :                    "handlers", handlers,
     920                 :                    "finalizer", finally,
     921             135 :                    dst);
     922                 : }
     923                 : 
     924                 : bool
     925               0 : NodeBuilder::debuggerStatement(TokenPos *pos, Value *dst)
     926                 : {
     927               0 :     Value cb = callbacks[AST_DEBUGGER_STMT];
     928               0 :     if (!cb.isNull())
     929               0 :         return callback(cb, pos, dst);
     930                 : 
     931               0 :     return newNode(AST_DEBUGGER_STMT, pos, dst);
     932                 : }
     933                 : 
     934                 : bool
     935             999 : NodeBuilder::binaryExpression(BinaryOperator op, Value left, Value right, TokenPos *pos, Value *dst)
     936                 : {
     937             999 :     JS_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
     938                 : 
     939                 :     Value opName;
     940             999 :     if (!atomValue(binopNames[op], &opName))
     941               0 :         return false;
     942                 : 
     943             999 :     Value cb = callbacks[AST_BINARY_EXPR];
     944             999 :     if (!cb.isNull())
     945               0 :         return callback(cb, opName, left, right, pos, dst);
     946                 : 
     947                 :     return newNode(AST_BINARY_EXPR, pos,
     948                 :                    "operator", opName,
     949                 :                    "left", left,
     950                 :                    "right", right,
     951             999 :                    dst);
     952                 : }
     953                 : 
     954                 : bool
     955               0 : NodeBuilder::unaryExpression(UnaryOperator unop, Value expr, TokenPos *pos, Value *dst)
     956                 : {
     957               0 :     JS_ASSERT(unop > UNOP_ERR && unop < UNOP_LIMIT);
     958                 : 
     959                 :     Value opName;
     960               0 :     if (!atomValue(unopNames[unop], &opName))
     961               0 :         return false;
     962                 : 
     963               0 :     Value cb = callbacks[AST_UNARY_EXPR];
     964               0 :     if (!cb.isNull())
     965               0 :         return callback(cb, opName, expr, pos, dst);
     966                 : 
     967                 :     return newNode(AST_UNARY_EXPR, pos,
     968                 :                    "operator", opName,
     969                 :                    "argument", expr,
     970                 :                    "prefix", BooleanValue(true),
     971               0 :                    dst);
     972                 : }
     973                 : 
     974                 : bool
     975             270 : NodeBuilder::assignmentExpression(AssignmentOperator aop, Value lhs, Value rhs,
     976                 :                                   TokenPos *pos, Value *dst)
     977                 : {
     978             270 :     JS_ASSERT(aop > AOP_ERR && aop < AOP_LIMIT);
     979                 : 
     980                 :     Value opName;
     981             270 :     if (!atomValue(aopNames[aop], &opName))
     982               0 :         return false;
     983                 : 
     984             270 :     Value cb = callbacks[AST_ASSIGN_EXPR];
     985             270 :     if (!cb.isNull())
     986               0 :         return callback(cb, opName, lhs, rhs, pos, dst);
     987                 : 
     988                 :     return newNode(AST_ASSIGN_EXPR, pos,
     989                 :                    "operator", opName,
     990                 :                    "left", lhs,
     991                 :                    "right", rhs,
     992             270 :                    dst);
     993                 : }
     994                 : 
     995                 : bool
     996             198 : NodeBuilder::updateExpression(Value expr, bool incr, bool prefix, TokenPos *pos, Value *dst)
     997                 : {
     998                 :     Value opName;
     999             198 :     if (!atomValue(incr ? "++" : "--", &opName))
    1000               0 :         return false;
    1001                 : 
    1002             198 :     Value cb = callbacks[AST_UPDATE_EXPR];
    1003             198 :     if (!cb.isNull())
    1004               0 :         return callback(cb, expr, opName, BooleanValue(prefix), pos, dst);
    1005                 : 
    1006                 :     return newNode(AST_UPDATE_EXPR, pos,
    1007                 :                    "operator", opName,
    1008                 :                    "argument", expr,
    1009             198 :                    "prefix", BooleanValue(prefix),
    1010             198 :                    dst);
    1011                 : }
    1012                 : 
    1013                 : bool
    1014               0 : NodeBuilder::logicalExpression(bool lor, Value left, Value right, TokenPos *pos, Value *dst)
    1015                 : {
    1016                 :     Value opName;
    1017               0 :     if (!atomValue(lor ? "||" : "&&", &opName))
    1018               0 :         return false;
    1019                 : 
    1020               0 :     Value cb = callbacks[AST_LOGICAL_EXPR];
    1021               0 :     if (!cb.isNull())
    1022               0 :         return callback(cb, opName, left, right, pos, dst);
    1023                 : 
    1024                 :     return newNode(AST_LOGICAL_EXPR, pos,
    1025                 :                    "operator", opName,
    1026                 :                    "left", left,
    1027                 :                    "right", right,
    1028               0 :                    dst);
    1029                 : }
    1030                 : 
    1031                 : bool
    1032               0 : NodeBuilder::conditionalExpression(Value test, Value cons, Value alt, TokenPos *pos, Value *dst)
    1033                 : {
    1034               0 :     Value cb = callbacks[AST_COND_EXPR];
    1035               0 :     if (!cb.isNull())
    1036               0 :         return callback(cb, test, cons, alt, pos, dst);
    1037                 : 
    1038                 :     return newNode(AST_COND_EXPR, pos,
    1039                 :                    "test", test,
    1040                 :                    "consequent", cons,
    1041                 :                    "alternate", alt,
    1042               0 :                    dst);
    1043                 : }
    1044                 : 
    1045                 : bool
    1046              54 : NodeBuilder::sequenceExpression(NodeVector &elts, TokenPos *pos, Value *dst)
    1047                 : {
    1048              54 :     return listNode(AST_LIST_EXPR, "expressions", elts, pos, dst);
    1049                 : }
    1050                 : 
    1051                 : bool
    1052             738 : NodeBuilder::callExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst)
    1053                 : {
    1054                 :     Value array;
    1055             738 :     if (!newArray(args, &array))
    1056               0 :         return false;
    1057                 : 
    1058             738 :     Value cb = callbacks[AST_CALL_EXPR];
    1059             738 :     if (!cb.isNull())
    1060               0 :         return callback(cb, callee, array, pos, dst);
    1061                 : 
    1062                 :     return newNode(AST_CALL_EXPR, pos,
    1063                 :                    "callee", callee,
    1064                 :                    "arguments", array,
    1065             738 :                    dst);
    1066                 : }
    1067                 : 
    1068                 : bool
    1069               0 : NodeBuilder::newExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst)
    1070                 : {
    1071                 :     Value array;
    1072               0 :     if (!newArray(args, &array))
    1073               0 :         return false;
    1074                 : 
    1075               0 :     Value cb = callbacks[AST_NEW_EXPR];
    1076               0 :     if (!cb.isNull())
    1077               0 :         return callback(cb, callee, array, pos, dst);
    1078                 : 
    1079                 :     return newNode(AST_NEW_EXPR, pos,
    1080                 :                    "callee", callee,
    1081                 :                    "arguments", array,
    1082               0 :                    dst);
    1083                 : }
    1084                 : 
    1085                 : bool
    1086             216 : NodeBuilder::memberExpression(bool computed, Value expr, Value member, TokenPos *pos, Value *dst)
    1087                 : {
    1088             216 :     Value cb = callbacks[AST_MEMBER_EXPR];
    1089             216 :     if (!cb.isNull())
    1090               0 :         return callback(cb, BooleanValue(computed), expr, member, pos, dst);
    1091                 : 
    1092                 :     return newNode(AST_MEMBER_EXPR, pos,
    1093                 :                    "object", expr,
    1094                 :                    "property", member,
    1095             216 :                    "computed", BooleanValue(computed),
    1096             216 :                    dst);
    1097                 : }
    1098                 : 
    1099                 : bool
    1100             540 : NodeBuilder::arrayExpression(NodeVector &elts, TokenPos *pos, Value *dst)
    1101                 : {
    1102             540 :     return listNode(AST_ARRAY_EXPR, "elements", elts, pos, dst);
    1103                 : }
    1104                 : 
    1105                 : bool
    1106             576 : NodeBuilder::propertyPattern(Value key, Value patt, TokenPos *pos, Value *dst)
    1107                 : {
    1108                 :     Value kindName;
    1109             576 :     if (!atomValue("init", &kindName))
    1110               0 :         return false;
    1111                 : 
    1112             576 :     Value cb = callbacks[AST_PROP_PATT];
    1113             576 :     if (!cb.isNull())
    1114               0 :         return callback(cb, key, patt, pos, dst);
    1115                 : 
    1116                 :     return newNode(AST_PROP_PATT, pos,
    1117                 :                    "key", key,
    1118                 :                    "value", patt,
    1119                 :                    "kind", kindName,
    1120             576 :                    dst);
    1121                 : }
    1122                 : 
    1123                 : bool
    1124              99 : NodeBuilder::propertyInitializer(Value key, Value val, PropKind kind, TokenPos *pos, Value *dst)
    1125                 : {
    1126                 :     Value kindName;
    1127              99 :     if (!atomValue(kind == PROP_INIT
    1128                 :                    ? "init"
    1129                 :                    : kind == PROP_GETTER
    1130                 :                    ? "get"
    1131              99 :                    : "set", &kindName)) {
    1132               0 :         return false;
    1133                 :     }
    1134                 : 
    1135              99 :     Value cb = callbacks[AST_PROPERTY];
    1136              99 :     if (!cb.isNull())
    1137               0 :         return callback(cb, kindName, key, val, pos, dst);
    1138                 : 
    1139                 :     return newNode(AST_PROPERTY, pos,
    1140                 :                    "key", key,
    1141                 :                    "value", val,
    1142                 :                    "kind", kindName,
    1143              99 :                    dst);
    1144                 : }
    1145                 : 
    1146                 : bool
    1147             126 : NodeBuilder::objectExpression(NodeVector &elts, TokenPos *pos, Value *dst)
    1148                 : {
    1149             126 :     return listNode(AST_OBJECT_EXPR, "properties", elts, pos, dst);
    1150                 : }
    1151                 : 
    1152                 : bool
    1153              54 : NodeBuilder::thisExpression(TokenPos *pos, Value *dst)
    1154                 : {
    1155              54 :     Value cb = callbacks[AST_THIS_EXPR];
    1156              54 :     if (!cb.isNull())
    1157               0 :         return callback(cb, pos, dst);
    1158                 : 
    1159              54 :     return newNode(AST_THIS_EXPR, pos, dst);
    1160                 : }
    1161                 : 
    1162                 : bool
    1163               0 : NodeBuilder::yieldExpression(Value arg, TokenPos *pos, Value *dst)
    1164                 : {
    1165               0 :     Value cb = callbacks[AST_YIELD_EXPR];
    1166               0 :     if (!cb.isNull())
    1167               0 :         return callback(cb, opt(arg), pos, dst);
    1168                 : 
    1169               0 :     return newNode(AST_YIELD_EXPR, pos, "argument", arg, dst);
    1170                 : }
    1171                 : 
    1172                 : bool
    1173              72 : NodeBuilder::comprehensionBlock(Value patt, Value src, bool isForEach, TokenPos *pos, Value *dst)
    1174                 : {
    1175              72 :     Value cb = callbacks[AST_COMP_BLOCK];
    1176              72 :     if (!cb.isNull())
    1177               0 :         return callback(cb, patt, src, BooleanValue(isForEach), pos, dst);
    1178                 : 
    1179                 :     return newNode(AST_COMP_BLOCK, pos,
    1180                 :                    "left", patt,
    1181                 :                    "right", src,
    1182              72 :                    "each", BooleanValue(isForEach),
    1183              72 :                    dst);
    1184                 : }
    1185                 : 
    1186                 : bool
    1187              36 : NodeBuilder::comprehensionExpression(Value body, NodeVector &blocks, Value filter,
    1188                 :                                      TokenPos *pos, Value *dst)
    1189                 : {
    1190                 :     Value array;
    1191              36 :     if (!newArray(blocks, &array))
    1192               0 :         return false;
    1193                 : 
    1194              36 :     Value cb = callbacks[AST_COMP_EXPR];
    1195              36 :     if (!cb.isNull())
    1196               0 :         return callback(cb, body, array, opt(filter), pos, dst);
    1197                 : 
    1198                 :     return newNode(AST_COMP_EXPR, pos,
    1199                 :                    "body", body,
    1200                 :                    "blocks", array,
    1201                 :                    "filter", filter,
    1202              36 :                    dst);
    1203                 : }
    1204                 : 
    1205                 : bool
    1206              36 : NodeBuilder::generatorExpression(Value body, NodeVector &blocks, Value filter, TokenPos *pos, Value *dst)
    1207                 : {
    1208                 :     Value array;
    1209              36 :     if (!newArray(blocks, &array))
    1210               0 :         return false;
    1211                 : 
    1212              36 :     Value cb = callbacks[AST_GENERATOR_EXPR];
    1213              36 :     if (!cb.isNull())
    1214               0 :         return callback(cb, body, array, opt(filter), pos, dst);
    1215                 : 
    1216                 :     return newNode(AST_GENERATOR_EXPR, pos,
    1217                 :                    "body", body,
    1218                 :                    "blocks", array,
    1219                 :                    "filter", filter,
    1220              36 :                    dst);
    1221                 : }
    1222                 : 
    1223                 : bool
    1224             540 : NodeBuilder::letExpression(NodeVector &head, Value expr, TokenPos *pos, Value *dst)
    1225                 : {
    1226                 :     Value array;
    1227             540 :     if (!newArray(head, &array))
    1228               0 :         return false;
    1229                 : 
    1230             540 :     Value cb = callbacks[AST_LET_EXPR];
    1231             540 :     if (!cb.isNull())
    1232               0 :         return callback(cb, array, expr, pos, dst);
    1233                 : 
    1234                 :     return newNode(AST_LET_EXPR, pos,
    1235                 :                    "head", array,
    1236                 :                    "body", expr,
    1237             540 :                    dst);
    1238                 : }
    1239                 : 
    1240                 : bool
    1241             702 : NodeBuilder::letStatement(NodeVector &head, Value stmt, TokenPos *pos, Value *dst)
    1242                 : {
    1243                 :     Value array;
    1244             702 :     if (!newArray(head, &array))
    1245               0 :         return false;
    1246                 : 
    1247             702 :     Value cb = callbacks[AST_LET_STMT];
    1248             702 :     if (!cb.isNull())
    1249               0 :         return callback(cb, array, stmt, pos, dst);
    1250                 : 
    1251                 :     return newNode(AST_LET_STMT, pos,
    1252                 :                    "head", array,
    1253                 :                    "body", stmt,
    1254             702 :                    dst);
    1255                 : }
    1256                 : 
    1257                 : bool
    1258            1431 : NodeBuilder::variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos, Value *dst)
    1259                 : {
    1260            1431 :     JS_ASSERT(kind > VARDECL_ERR && kind < VARDECL_LIMIT);
    1261                 : 
    1262                 :     Value array, kindName;
    1263            2862 :     if (!newArray(elts, &array) ||
    1264                 :         !atomValue(kind == VARDECL_CONST
    1265                 :                    ? "const"
    1266                 :                    : kind == VARDECL_LET
    1267                 :                    ? "let"
    1268            1431 :                    : "var", &kindName)) {
    1269               0 :         return false;
    1270                 :     }
    1271                 : 
    1272            1431 :     Value cb = callbacks[AST_VAR_DECL];
    1273            1431 :     if (!cb.isNull())
    1274               0 :         return callback(cb, kindName, array, pos, dst);
    1275                 : 
    1276                 :     return newNode(AST_VAR_DECL, pos,
    1277                 :                    "kind", kindName,
    1278                 :                    "declarations", array,
    1279            1431 :                    dst);
    1280                 : }
    1281                 : 
    1282                 : bool
    1283            3105 : NodeBuilder::variableDeclarator(Value id, Value init, TokenPos *pos, Value *dst)
    1284                 : {
    1285            3105 :     Value cb = callbacks[AST_VAR_DTOR];
    1286            3105 :     if (!cb.isNull())
    1287               0 :         return callback(cb, id, opt(init), pos, dst);
    1288                 : 
    1289            3105 :     return newNode(AST_VAR_DTOR, pos, "id", id, "init", init, dst);
    1290                 : }
    1291                 : 
    1292                 : bool
    1293              81 : NodeBuilder::switchCase(Value expr, NodeVector &elts, TokenPos *pos, Value *dst)
    1294                 : {
    1295                 :     Value array;
    1296              81 :     if (!newArray(elts, &array))
    1297               0 :         return false;
    1298                 : 
    1299              81 :     Value cb = callbacks[AST_CASE];
    1300              81 :     if (!cb.isNull())
    1301               0 :         return callback(cb, opt(expr), array, pos, dst);
    1302                 : 
    1303                 :     return newNode(AST_CASE, pos,
    1304                 :                    "test", expr,
    1305                 :                    "consequent", array,
    1306              81 :                    dst);
    1307                 : }
    1308                 : 
    1309                 : bool
    1310             135 : NodeBuilder::catchClause(Value var, Value guard, Value body, TokenPos *pos, Value *dst)
    1311                 : {
    1312             135 :     Value cb = callbacks[AST_CATCH];
    1313             135 :     if (!cb.isNull())
    1314               0 :         return callback(cb, var, opt(guard), body, pos, dst);
    1315                 : 
    1316                 :     return newNode(AST_CATCH, pos,
    1317                 :                    "param", var,
    1318                 :                    "guard", guard,
    1319                 :                    "body", body,
    1320             135 :                    dst);
    1321                 : }
    1322                 : 
    1323                 : bool
    1324            2143 : NodeBuilder::literal(Value val, TokenPos *pos, Value *dst)
    1325                 : {
    1326            2143 :     Value cb = callbacks[AST_LITERAL];
    1327            2143 :     if (!cb.isNull())
    1328               0 :         return callback(cb, val, pos, dst);
    1329                 : 
    1330            2143 :     return newNode(AST_LITERAL, pos, "value", val, dst);
    1331                 : }
    1332                 : 
    1333                 : bool
    1334           15084 : NodeBuilder::identifier(Value name, TokenPos *pos, Value *dst)
    1335                 : {
    1336           15084 :     Value cb = callbacks[AST_IDENTIFIER];
    1337           15084 :     if (!cb.isNull())
    1338               0 :         return callback(cb, name, pos, dst);
    1339                 : 
    1340           15084 :     return newNode(AST_IDENTIFIER, pos, "name", name, dst);
    1341                 : }
    1342                 : 
    1343                 : bool
    1344             441 : NodeBuilder::objectPattern(NodeVector &elts, TokenPos *pos, Value *dst)
    1345                 : {
    1346             441 :     return listNode(AST_OBJECT_PATT, "properties", elts, pos, dst);
    1347                 : }
    1348                 : 
    1349                 : bool
    1350            2358 : NodeBuilder::arrayPattern(NodeVector &elts, TokenPos *pos, Value *dst)
    1351                 : {
    1352            2358 :     return listNode(AST_ARRAY_PATT, "elements", elts, pos, dst);
    1353                 : }
    1354                 : 
    1355                 : bool
    1356            2313 : NodeBuilder::function(ASTType type, TokenPos *pos,
    1357                 :                       Value id, NodeVector &args, Value body,
    1358                 :                       bool isGenerator, bool isExpression,
    1359                 :                       Value *dst)
    1360                 : {
    1361                 :     Value array;
    1362            2313 :     if (!newArray(args, &array))
    1363               0 :         return false;
    1364                 : 
    1365            2313 :     Value cb = callbacks[type];
    1366            2313 :     if (!cb.isNull()) {
    1367               0 :         return callback(cb, opt(id), array, body, BooleanValue(isGenerator),
    1368               0 :                         BooleanValue(isExpression), pos, dst);
    1369                 :     }
    1370                 : 
    1371                 :     return newNode(type, pos,
    1372                 :                    "id", id,
    1373                 :                    "params", array,
    1374                 :                    "body", body,
    1375            2313 :                    "generator", BooleanValue(isGenerator),
    1376            2313 :                    "expression", BooleanValue(isExpression),
    1377            4626 :                    dst);
    1378                 : }
    1379                 : 
    1380                 : bool
    1381               0 : NodeBuilder::xmlAnyName(TokenPos *pos, Value *dst)
    1382                 : {
    1383               0 :     Value cb = callbacks[AST_XMLANYNAME];
    1384               0 :     if (!cb.isNull())
    1385               0 :         return callback(cb, pos, dst);
    1386                 : 
    1387               0 :     return newNode(AST_XMLANYNAME, pos, dst);
    1388                 : }
    1389                 : 
    1390                 : bool
    1391               0 : NodeBuilder::xmlEscapeExpression(Value expr, TokenPos *pos, Value *dst)
    1392                 : {
    1393               0 :     Value cb = callbacks[AST_XMLESCAPE];
    1394               0 :     if (!cb.isNull())
    1395               0 :         return callback(cb, expr, pos, dst);
    1396                 : 
    1397               0 :     return newNode(AST_XMLESCAPE, pos, "expression", expr, dst);
    1398                 : }
    1399                 : 
    1400                 : bool
    1401               0 : NodeBuilder::xmlFilterExpression(Value left, Value right, TokenPos *pos, Value *dst)
    1402                 : {
    1403               0 :     Value cb = callbacks[AST_XMLFILTER];
    1404               0 :     if (!cb.isNull())
    1405               0 :         return callback(cb, left, right, pos, dst);
    1406                 : 
    1407               0 :     return newNode(AST_XMLFILTER, pos, "left", left, "right", right, dst);
    1408                 : }
    1409                 : 
    1410                 : bool
    1411               0 : NodeBuilder::xmlDefaultNamespace(Value ns, TokenPos *pos, Value *dst)
    1412                 : {
    1413               0 :     Value cb = callbacks[AST_XMLDEFAULT];
    1414               0 :     if (!cb.isNull())
    1415               0 :         return callback(cb, ns, pos, dst);
    1416                 : 
    1417               0 :     return newNode(AST_XMLDEFAULT, pos, "namespace", ns, dst);
    1418                 : }
    1419                 : 
    1420                 : bool
    1421               0 : NodeBuilder::xmlAttributeSelector(Value expr, bool computed, TokenPos *pos, Value *dst)
    1422                 : {
    1423               0 :     Value cb = callbacks[AST_XMLATTR_SEL];
    1424               0 :     if (!cb.isNull())
    1425               0 :         return callback(cb, expr, BooleanValue(computed), pos, dst);
    1426                 : 
    1427                 :     return newNode(AST_XMLATTR_SEL, pos,
    1428                 :                    "attribute", expr,
    1429               0 :                    "computed", BooleanValue(computed),
    1430               0 :                    dst);
    1431                 : }
    1432                 : 
    1433                 : bool
    1434               0 : NodeBuilder::xmlFunctionQualifiedIdentifier(Value right, bool computed, TokenPos *pos, Value *dst)
    1435                 : {
    1436               0 :     Value cb = callbacks[AST_XMLFUNCQUAL];
    1437               0 :     if (!cb.isNull())
    1438               0 :         return callback(cb, right, BooleanValue(computed), pos, dst);
    1439                 : 
    1440                 :     return newNode(AST_XMLFUNCQUAL, pos,
    1441                 :                    "right", right,
    1442               0 :                    "computed", BooleanValue(computed),
    1443               0 :                    dst);
    1444                 : }
    1445                 : 
    1446                 : bool
    1447               0 : NodeBuilder::xmlQualifiedIdentifier(Value left, Value right, bool computed,
    1448                 :                                     TokenPos *pos, Value *dst)
    1449                 : {
    1450               0 :     Value cb = callbacks[AST_XMLQUAL];
    1451               0 :     if (!cb.isNull())
    1452               0 :         return callback(cb, left, right, BooleanValue(computed), pos, dst);
    1453                 : 
    1454                 :     return newNode(AST_XMLQUAL, pos,
    1455                 :                    "left", left,
    1456                 :                    "right", right,
    1457               0 :                    "computed", BooleanValue(computed),
    1458               0 :                    dst);
    1459                 : }
    1460                 : 
    1461                 : bool
    1462               0 : NodeBuilder::xmlElement(NodeVector &elts, TokenPos *pos, Value *dst)
    1463                 : {
    1464               0 :     return listNode(AST_XMLELEM, "contents", elts, pos, dst);
    1465                 : }
    1466                 : 
    1467                 : bool
    1468               0 : NodeBuilder::xmlText(Value text, TokenPos *pos, Value *dst)
    1469                 : {
    1470               0 :     Value cb = callbacks[AST_XMLTEXT];
    1471               0 :     if (!cb.isNull())
    1472               0 :         return callback(cb, text, pos, dst);
    1473                 : 
    1474               0 :     return newNode(AST_XMLTEXT, pos, "text", text, dst);
    1475                 : }
    1476                 : 
    1477                 : bool
    1478               0 : NodeBuilder::xmlList(NodeVector &elts, TokenPos *pos, Value *dst)
    1479                 : {
    1480               0 :     return listNode(AST_XMLLIST, "contents", elts, pos, dst);
    1481                 : }
    1482                 : 
    1483                 : bool
    1484               0 : NodeBuilder::xmlStartTag(NodeVector &elts, TokenPos *pos, Value *dst)
    1485                 : {
    1486               0 :     return listNode(AST_XMLSTART, "contents", elts, pos, dst);
    1487                 : }
    1488                 : 
    1489                 : bool
    1490               0 : NodeBuilder::xmlEndTag(NodeVector &elts, TokenPos *pos, Value *dst)
    1491                 : {
    1492               0 :     return listNode(AST_XMLEND, "contents", elts, pos, dst);
    1493                 : }
    1494                 : 
    1495                 : bool
    1496               0 : NodeBuilder::xmlPointTag(NodeVector &elts, TokenPos *pos, Value *dst)
    1497                 : {
    1498               0 :     return listNode(AST_XMLPOINT, "contents", elts, pos, dst);
    1499                 : }
    1500                 : 
    1501                 : bool
    1502               0 : NodeBuilder::xmlName(Value text, TokenPos *pos, Value *dst)
    1503                 : {
    1504               0 :     Value cb = callbacks[AST_XMLNAME];
    1505               0 :     if (!cb.isNull())
    1506               0 :         return callback(cb, text, pos, dst);
    1507                 : 
    1508               0 :     return newNode(AST_XMLNAME, pos, "contents", text, dst);
    1509                 : }
    1510                 : 
    1511                 : bool
    1512               0 : NodeBuilder::xmlName(NodeVector &elts, TokenPos *pos, Value *dst)
    1513                 : {
    1514               0 :     return listNode(AST_XMLNAME, "contents", elts, pos ,dst);
    1515                 : }
    1516                 : 
    1517                 : bool
    1518               0 : NodeBuilder::xmlAttribute(Value text, TokenPos *pos, Value *dst)
    1519                 : {
    1520               0 :     Value cb = callbacks[AST_XMLATTR];
    1521               0 :     if (!cb.isNull())
    1522               0 :         return callback(cb, text, pos, dst);
    1523                 : 
    1524               0 :     return newNode(AST_XMLATTR, pos, "value", text, dst);
    1525                 : }
    1526                 : 
    1527                 : bool
    1528               0 : NodeBuilder::xmlCdata(Value text, TokenPos *pos, Value *dst)
    1529                 : {
    1530               0 :     Value cb = callbacks[AST_XMLCDATA];
    1531               0 :     if (!cb.isNull())
    1532               0 :         return callback(cb, text, pos, dst);
    1533                 : 
    1534               0 :     return newNode(AST_XMLCDATA, pos, "contents", text, dst);
    1535                 : }
    1536                 : 
    1537                 : bool
    1538               0 : NodeBuilder::xmlComment(Value text, TokenPos *pos, Value *dst)
    1539                 : {
    1540               0 :     Value cb = callbacks[AST_XMLCOMMENT];
    1541               0 :     if (!cb.isNull())
    1542               0 :         return callback(cb, text, pos, dst);
    1543                 : 
    1544               0 :     return newNode(AST_XMLCOMMENT, pos, "contents", text, dst);
    1545                 : }
    1546                 : 
    1547                 : bool
    1548               0 : NodeBuilder::xmlPI(Value target, Value contents, TokenPos *pos, Value *dst)
    1549                 : {
    1550               0 :     Value cb = callbacks[AST_XMLPI];
    1551               0 :     if (!cb.isNull())
    1552               0 :         return callback(cb, target, contents, pos, dst);
    1553                 : 
    1554                 :     return newNode(AST_XMLPI, pos,
    1555                 :                    "target", target,
    1556                 :                    "contents", contents,
    1557               0 :                    dst);
    1558                 : }
    1559                 : 
    1560                 : 
    1561                 : /*
    1562                 :  * Serialization of parse nodes to JavaScript objects.
    1563                 :  *
    1564                 :  * All serialization methods take a non-nullable ParseNode pointer.
    1565                 :  */
    1566                 : 
    1567                 : class ASTSerializer
    1568                 : {
    1569                 :     JSContext     *cx;
    1570                 :     Parser        *parser;
    1571                 :     NodeBuilder   builder;
    1572                 :     uint32_t      lineno;
    1573                 : 
    1574           15084 :     Value atomContents(JSAtom *atom) {
    1575           15084 :         return StringValue(atom ? atom : cx->runtime->atomState.emptyAtom);
    1576                 :     }
    1577                 : 
    1578                 :     BinaryOperator binop(ParseNodeKind kind, JSOp op);
    1579                 :     UnaryOperator unop(ParseNodeKind kind, JSOp op);
    1580                 :     AssignmentOperator aop(JSOp op);
    1581                 : 
    1582                 :     bool statements(ParseNode *pn, NodeVector &elts);
    1583                 :     bool expressions(ParseNode *pn, NodeVector &elts);
    1584                 :     bool xmls(ParseNode *pn, NodeVector &elts);
    1585                 :     bool leftAssociate(ParseNode *pn, Value *dst);
    1586                 :     bool functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct, ParseNode *pnbody,
    1587                 :                       NodeVector &args);
    1588                 : 
    1589                 :     bool sourceElement(ParseNode *pn, Value *dst);
    1590                 : 
    1591                 :     bool declaration(ParseNode *pn, Value *dst);
    1592                 :     bool variableDeclaration(ParseNode *pn, bool let, Value *dst);
    1593                 :     bool variableDeclarator(ParseNode *pn, VarDeclKind *pkind, Value *dst);
    1594                 :     bool let(ParseNode *pn, bool expr, Value *dst);
    1595                 : 
    1596             558 :     bool optStatement(ParseNode *pn, Value *dst) {
    1597             558 :         if (!pn) {
    1598             558 :             dst->setMagic(JS_SERIALIZE_NO_NODE);
    1599             558 :             return true;
    1600                 :         }
    1601               0 :         return statement(pn, dst);
    1602                 :     }
    1603                 : 
    1604                 :     bool forInit(ParseNode *pn, Value *dst);
    1605                 :     bool statement(ParseNode *pn, Value *dst);
    1606                 :     bool blockStatement(ParseNode *pn, Value *dst);
    1607                 :     bool switchStatement(ParseNode *pn, Value *dst);
    1608                 :     bool switchCase(ParseNode *pn, Value *dst);
    1609                 :     bool tryStatement(ParseNode *pn, Value *dst);
    1610                 :     bool catchClause(ParseNode *pn, Value *dst);
    1611                 : 
    1612            6102 :     bool optExpression(ParseNode *pn, Value *dst) {
    1613            6102 :         if (!pn) {
    1614             693 :             dst->setMagic(JS_SERIALIZE_NO_NODE);
    1615             693 :             return true;
    1616                 :         }
    1617            5409 :         return expression(pn, dst);
    1618                 :     }
    1619                 : 
    1620                 :     bool expression(ParseNode *pn, Value *dst);
    1621                 : 
    1622                 :     bool propertyName(ParseNode *pn, Value *dst);
    1623                 :     bool property(ParseNode *pn, Value *dst);
    1624                 : 
    1625            2385 :     bool optIdentifier(JSAtom *atom, TokenPos *pos, Value *dst) {
    1626            2385 :         if (!atom) {
    1627              90 :             dst->setMagic(JS_SERIALIZE_NO_NODE);
    1628              90 :             return true;
    1629                 :         }
    1630            2295 :         return identifier(atom, pos, dst);
    1631                 :     }
    1632                 : 
    1633                 :     bool identifier(JSAtom *atom, TokenPos *pos, Value *dst);
    1634                 :     bool identifier(ParseNode *pn, Value *dst);
    1635                 :     bool literal(ParseNode *pn, Value *dst);
    1636                 : 
    1637                 :     bool pattern(ParseNode *pn, VarDeclKind *pkind, Value *dst);
    1638                 :     bool arrayPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst);
    1639                 :     bool objectPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst);
    1640                 : 
    1641                 :     bool function(ParseNode *pn, ASTType type, Value *dst);
    1642                 :     bool functionArgsAndBody(ParseNode *pn, NodeVector &args, Value *body);
    1643                 :     bool functionBody(ParseNode *pn, TokenPos *pos, Value *dst);
    1644                 : 
    1645                 :     bool comprehensionBlock(ParseNode *pn, Value *dst);
    1646                 :     bool comprehension(ParseNode *pn, Value *dst);
    1647                 :     bool generatorExpression(ParseNode *pn, Value *dst);
    1648                 : 
    1649                 :     bool xml(ParseNode *pn, Value *dst);
    1650                 : 
    1651                 :   public:
    1652            2278 :     ASTSerializer(JSContext *c, bool l, char const *src, uint32_t ln)
    1653            2278 :         : cx(c), builder(c, l, src), lineno(ln) {
    1654            2278 :     }
    1655                 : 
    1656            2278 :     bool init(JSObject *userobj) {
    1657            2278 :         return builder.init(userobj);
    1658                 :     }
    1659                 : 
    1660            2278 :     void setParser(Parser *p) {
    1661            2278 :         parser = p;
    1662            2278 :     }
    1663                 : 
    1664                 :     bool program(ParseNode *pn, Value *dst);
    1665                 : };
    1666                 : 
    1667                 : AssignmentOperator
    1668             270 : ASTSerializer::aop(JSOp op)
    1669                 : {
    1670             270 :     switch (op) {
    1671                 :       case JSOP_NOP:
    1672             117 :         return AOP_ASSIGN;
    1673                 :       case JSOP_ADD:
    1674             153 :         return AOP_PLUS;
    1675                 :       case JSOP_SUB:
    1676               0 :         return AOP_MINUS;
    1677                 :       case JSOP_MUL:
    1678               0 :         return AOP_STAR;
    1679                 :       case JSOP_DIV:
    1680               0 :         return AOP_DIV;
    1681                 :       case JSOP_MOD:
    1682               0 :         return AOP_MOD;
    1683                 :       case JSOP_LSH:
    1684               0 :         return AOP_LSH;
    1685                 :       case JSOP_RSH:
    1686               0 :         return AOP_RSH;
    1687                 :       case JSOP_URSH:
    1688               0 :         return AOP_URSH;
    1689                 :       case JSOP_BITOR:
    1690               0 :         return AOP_BITOR;
    1691                 :       case JSOP_BITXOR:
    1692               0 :         return AOP_BITXOR;
    1693                 :       case JSOP_BITAND:
    1694               0 :         return AOP_BITAND;
    1695                 :       default:
    1696               0 :         return AOP_ERR;
    1697                 :     }
    1698                 : }
    1699                 : 
    1700                 : UnaryOperator
    1701               0 : ASTSerializer::unop(ParseNodeKind kind, JSOp op)
    1702                 : {
    1703               0 :     if (kind == PNK_DELETE)
    1704               0 :         return UNOP_DELETE;
    1705                 : 
    1706               0 :     switch (op) {
    1707                 :       case JSOP_NEG:
    1708               0 :         return UNOP_NEG;
    1709                 :       case JSOP_POS:
    1710               0 :         return UNOP_POS;
    1711                 :       case JSOP_NOT:
    1712               0 :         return UNOP_NOT;
    1713                 :       case JSOP_BITNOT:
    1714               0 :         return UNOP_BITNOT;
    1715                 :       case JSOP_TYPEOF:
    1716                 :       case JSOP_TYPEOFEXPR:
    1717               0 :         return UNOP_TYPEOF;
    1718                 :       case JSOP_VOID:
    1719               0 :         return UNOP_VOID;
    1720                 :       default:
    1721               0 :         return UNOP_ERR;
    1722                 :     }
    1723                 : }
    1724                 : 
    1725                 : BinaryOperator
    1726             999 : ASTSerializer::binop(ParseNodeKind kind, JSOp op)
    1727                 : {
    1728             999 :     switch (kind) {
    1729                 :       case PNK_LSH:
    1730               0 :         return BINOP_LSH;
    1731                 :       case PNK_RSH:
    1732               0 :         return BINOP_RSH;
    1733                 :       case PNK_URSH:
    1734               0 :         return BINOP_URSH;
    1735                 :       case PNK_LT:
    1736             126 :         return BINOP_LT;
    1737                 :       case PNK_LE:
    1738               0 :         return BINOP_LE;
    1739                 :       case PNK_GT:
    1740               0 :         return BINOP_GT;
    1741                 :       case PNK_GE:
    1742               0 :         return BINOP_GE;
    1743                 :       case PNK_EQ:
    1744               9 :         return BINOP_EQ;
    1745                 :       case PNK_NE:
    1746              18 :         return BINOP_NE;
    1747                 :       case PNK_STRICTEQ:
    1748               9 :         return BINOP_STRICTEQ;
    1749                 :       case PNK_STRICTNE:
    1750               0 :         return BINOP_STRICTNE;
    1751                 :       case PNK_ADD:
    1752             828 :         return BINOP_ADD;
    1753                 :       case PNK_SUB:
    1754               0 :         return BINOP_SUB;
    1755                 :       case PNK_STAR:
    1756               0 :         return BINOP_STAR;
    1757                 :       case PNK_DIV:
    1758               0 :         return BINOP_DIV;
    1759                 :       case PNK_MOD:
    1760               9 :         return BINOP_MOD;
    1761                 :       case PNK_BITOR:
    1762               0 :         return BINOP_BITOR;
    1763                 :       case PNK_BITXOR:
    1764               0 :         return BINOP_BITXOR;
    1765                 :       case PNK_BITAND:
    1766               0 :         return BINOP_BITAND;
    1767                 :       case PNK_IN:
    1768               0 :         return BINOP_IN;
    1769                 :       case PNK_INSTANCEOF:
    1770               0 :         return BINOP_INSTANCEOF;
    1771                 :       case PNK_DBLDOT:
    1772               0 :         return BINOP_DBLDOT;
    1773                 :       default:
    1774               0 :         return BINOP_ERR;
    1775                 :     }
    1776                 : }
    1777                 : 
    1778                 : bool
    1779            4141 : ASTSerializer::statements(ParseNode *pn, NodeVector &elts)
    1780                 : {
    1781            4141 :     JS_ASSERT(pn->isKind(PNK_STATEMENTLIST));
    1782            4141 :     JS_ASSERT(pn->isArity(PN_LIST));
    1783                 : 
    1784            4141 :     if (!elts.reserve(pn->pn_count))
    1785               0 :         return false;
    1786                 : 
    1787            8948 :     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
    1788                 :         Value elt;
    1789            4807 :         if (!sourceElement(next, &elt))
    1790               0 :             return false;
    1791            4807 :         elts.infallibleAppend(elt);
    1792                 :     }
    1793                 : 
    1794            4141 :     return true;
    1795                 : }
    1796                 : 
    1797                 : bool
    1798              54 : ASTSerializer::expressions(ParseNode *pn, NodeVector &elts)
    1799                 : {
    1800              54 :     if (!elts.reserve(pn->pn_count))
    1801               0 :         return false;
    1802                 : 
    1803             162 :     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
    1804                 :         Value elt;
    1805             108 :         if (!expression(next, &elt))
    1806               0 :             return false;
    1807             108 :         elts.infallibleAppend(elt);
    1808                 :     }
    1809                 : 
    1810              54 :     return true;
    1811                 : }
    1812                 : 
    1813                 : bool
    1814               0 : ASTSerializer::xmls(ParseNode *pn, NodeVector &elts)
    1815                 : {
    1816               0 :     if (!elts.reserve(pn->pn_count))
    1817               0 :         return false;
    1818                 : 
    1819               0 :     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
    1820                 :         Value elt;
    1821               0 :         if (!xml(next, &elt))
    1822               0 :             return false;
    1823               0 :         elts.infallibleAppend(elt);
    1824                 :     }
    1825                 : 
    1826               0 :     return true;
    1827                 : }
    1828                 : 
    1829                 : bool
    1830            1782 : ASTSerializer::blockStatement(ParseNode *pn, Value *dst)
    1831                 : {
    1832            1782 :     JS_ASSERT(pn->isKind(PNK_STATEMENTLIST));
    1833                 : 
    1834            3564 :     NodeVector stmts(cx);
    1835            1782 :     return statements(pn, stmts) &&
    1836            1782 :            builder.blockStatement(stmts, &pn->pn_pos, dst);
    1837                 : }
    1838                 : 
    1839                 : bool
    1840            2278 : ASTSerializer::program(ParseNode *pn, Value *dst)
    1841                 : {
    1842            2278 :     JS_ASSERT(pn->pn_pos.begin.lineno == lineno);
    1843                 : 
    1844            4556 :     NodeVector stmts(cx);
    1845            2278 :     return statements(pn, stmts) &&
    1846            2278 :            builder.program(stmts, &pn->pn_pos, dst);
    1847                 : }
    1848                 : 
    1849                 : bool
    1850            7912 : ASTSerializer::sourceElement(ParseNode *pn, Value *dst)
    1851                 : {
    1852                 :     /* SpiderMonkey allows declarations even in pure statement contexts. */
    1853            7912 :     return statement(pn, dst);
    1854                 : }
    1855                 : 
    1856                 : bool
    1857            1107 : ASTSerializer::declaration(ParseNode *pn, Value *dst)
    1858                 : {
    1859            2781 :     JS_ASSERT(pn->isKind(PNK_FUNCTION) ||
    1860                 :               pn->isKind(PNK_VAR) ||
    1861                 :               pn->isKind(PNK_LET) ||
    1862            2781 :               pn->isKind(PNK_CONST));
    1863                 : 
    1864            1107 :     switch (pn->getKind()) {
    1865                 :       case PNK_FUNCTION:
    1866              18 :         return function(pn, AST_FUNC_DECL, dst);
    1867                 : 
    1868                 :       case PNK_VAR:
    1869                 :       case PNK_CONST:
    1870             504 :         return variableDeclaration(pn, false, dst);
    1871                 : 
    1872                 :       default:
    1873             585 :         JS_ASSERT(pn->isKind(PNK_LET));
    1874             585 :         return variableDeclaration(pn, true, dst);
    1875                 :     }
    1876                 : }
    1877                 : 
    1878                 : bool
    1879            1431 : ASTSerializer::variableDeclaration(ParseNode *pn, bool let, Value *dst)
    1880                 : {
    1881            1431 :     JS_ASSERT(let ? pn->isKind(PNK_LET) : (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST)));
    1882                 : 
    1883                 :     /* Later updated to VARDECL_CONST if we find a PND_CONST declarator. */
    1884            1431 :     VarDeclKind kind = let ? VARDECL_LET : VARDECL_VAR;
    1885                 : 
    1886            2862 :     NodeVector dtors(cx);
    1887                 : 
    1888                 :     /* In a for-in context, variable declarations contain just a single pattern. */
    1889            1431 :     if (pn->pn_xflags & PNX_FORINVAR) {
    1890                 :         Value patt, child;
    1891             234 :         return pattern(pn->pn_head, &kind, &patt) &&
    1892             234 :                builder.variableDeclarator(patt, NullValue(), &pn->pn_head->pn_pos, &child) &&
    1893             234 :                dtors.append(child) &&
    1894             702 :                builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
    1895                 :     }
    1896                 : 
    1897            1197 :     if (!dtors.reserve(pn->pn_count))
    1898               0 :         return false;
    1899            2628 :     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
    1900                 :         Value child;
    1901            1431 :         if (!variableDeclarator(next, &kind, &child))
    1902               0 :             return false;
    1903            1431 :         dtors.infallibleAppend(child);
    1904                 :     }
    1905                 : 
    1906            1197 :     return builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
    1907                 : }
    1908                 : 
    1909                 : bool
    1910            2871 : ASTSerializer::variableDeclarator(ParseNode *pn, VarDeclKind *pkind, Value *dst)
    1911                 : {
    1912                 :     /* A destructuring declarator is always a PNK_ASSIGN. */
    1913            2871 :     JS_ASSERT(pn->isKind(PNK_NAME) || pn->isKind(PNK_ASSIGN));
    1914                 : 
    1915                 :     ParseNode *pnleft;
    1916                 :     ParseNode *pnright;
    1917                 : 
    1918            2871 :     if (pn->isKind(PNK_NAME)) {
    1919            1647 :         pnleft = pn;
    1920            1647 :         pnright = pn->isUsed() ? NULL : pn->pn_expr;
    1921                 :     } else {
    1922            1224 :         JS_ASSERT(pn->isKind(PNK_ASSIGN));
    1923            1224 :         pnleft = pn->pn_left;
    1924            1224 :         pnright = pn->pn_right;
    1925                 :     }
    1926                 : 
    1927                 :     Value left, right;
    1928            2871 :     return pattern(pnleft, pkind, &left) &&
    1929            2871 :            optExpression(pnright, &right) &&
    1930            5742 :            builder.variableDeclarator(left, right, &pn->pn_pos, dst);
    1931                 : }
    1932                 : 
    1933                 : bool
    1934            1242 : ASTSerializer::let(ParseNode *pn, bool expr, Value *dst)
    1935                 : {
    1936            1242 :     ParseNode *letHead = pn->pn_left;
    1937            1242 :     LOCAL_ASSERT(letHead->isArity(PN_LIST));
    1938                 : 
    1939            1242 :     ParseNode *letBody = pn->pn_right;
    1940            1242 :     LOCAL_ASSERT(letBody->isKind(PNK_LEXICALSCOPE));
    1941                 : 
    1942            2484 :     NodeVector dtors(cx);
    1943            1242 :     if (!dtors.reserve(letHead->pn_count))
    1944               0 :         return false;
    1945                 : 
    1946            1242 :     VarDeclKind kind = VARDECL_LET_HEAD;
    1947                 : 
    1948            2682 :     for (ParseNode *next = letHead->pn_head; next; next = next->pn_next) {
    1949                 :         Value child;
    1950                 :         /*
    1951                 :          * Unlike in |variableDeclaration|, this does not update |kind|; since let-heads do
    1952                 :          * not contain const declarations, declarators should never have PND_CONST set.
    1953                 :          */
    1954            1440 :         if (!variableDeclarator(next, &kind, &child))
    1955               0 :             return false;
    1956            1440 :         dtors.infallibleAppend(child);
    1957                 :     }
    1958                 : 
    1959                 :     Value v;
    1960                 :     return expr
    1961             540 :            ? expression(letBody->pn_expr, &v) &&
    1962             540 :              builder.letExpression(dtors, v, &pn->pn_pos, dst)
    1963             702 :            : statement(letBody->pn_expr, &v) &&
    1964            3024 :              builder.letStatement(dtors, v, &pn->pn_pos, dst);
    1965                 : }
    1966                 : 
    1967                 : bool
    1968              81 : ASTSerializer::switchCase(ParseNode *pn, Value *dst)
    1969                 : {
    1970             162 :     NodeVector stmts(cx);
    1971                 : 
    1972                 :     Value expr;
    1973                 : 
    1974              81 :     return optExpression(pn->pn_left, &expr) &&
    1975              81 :            statements(pn->pn_right, stmts) &&
    1976             162 :            builder.switchCase(expr, stmts, &pn->pn_pos, dst);
    1977                 : }
    1978                 : 
    1979                 : bool
    1980              36 : ASTSerializer::switchStatement(ParseNode *pn, Value *dst)
    1981                 : {
    1982                 :     Value disc;
    1983                 : 
    1984              36 :     if (!expression(pn->pn_left, &disc))
    1985               0 :         return false;
    1986                 : 
    1987                 :     ParseNode *listNode;
    1988                 :     bool lexical;
    1989                 : 
    1990              36 :     if (pn->pn_right->isKind(PNK_LEXICALSCOPE)) {
    1991              36 :         listNode = pn->pn_right->pn_expr;
    1992              36 :         lexical = true;
    1993                 :     } else {
    1994               0 :         listNode = pn->pn_right;
    1995               0 :         lexical = false;
    1996                 :     }
    1997                 : 
    1998              72 :     NodeVector cases(cx);
    1999              36 :     if (!cases.reserve(listNode->pn_count))
    2000               0 :         return false;
    2001                 : 
    2002             117 :     for (ParseNode *next = listNode->pn_head; next; next = next->pn_next) {
    2003                 :         Value child;
    2004                 : #ifdef __GNUC__ /* quell GCC overwarning */
    2005              81 :         child = UndefinedValue();
    2006                 : #endif
    2007              81 :         if (!switchCase(next, &child))
    2008               0 :             return false;
    2009              81 :         cases.infallibleAppend(child);
    2010                 :     }
    2011                 : 
    2012              36 :     return builder.switchStatement(disc, cases, lexical, &pn->pn_pos, dst);
    2013                 : }
    2014                 : 
    2015                 : bool
    2016             135 : ASTSerializer::catchClause(ParseNode *pn, Value *dst)
    2017                 : {
    2018                 :     Value var, guard, body;
    2019                 : 
    2020             135 :     return pattern(pn->pn_kid1, NULL, &var) &&
    2021             135 :            optExpression(pn->pn_kid2, &guard) &&
    2022             135 :            statement(pn->pn_kid3, &body) &&
    2023             405 :            builder.catchClause(var, guard, body, &pn->pn_pos, dst);
    2024                 : }
    2025                 : 
    2026                 : bool
    2027             135 : ASTSerializer::tryStatement(ParseNode *pn, Value *dst)
    2028                 : {
    2029                 :     Value body;
    2030             135 :     if (!statement(pn->pn_kid1, &body))
    2031               0 :         return false;
    2032                 : 
    2033             270 :     NodeVector clauses(cx);
    2034             135 :     if (pn->pn_kid2) {
    2035             135 :         if (!clauses.reserve(pn->pn_kid2->pn_count))
    2036               0 :             return false;
    2037                 : 
    2038             270 :         for (ParseNode *next = pn->pn_kid2->pn_head; next; next = next->pn_next) {
    2039                 :             Value clause;
    2040             135 :             if (!catchClause(next->pn_expr, &clause))
    2041               0 :                 return false;
    2042             135 :             clauses.infallibleAppend(clause);
    2043                 :         }
    2044                 :     }
    2045                 : 
    2046                 :     Value finally;
    2047             135 :     return optStatement(pn->pn_kid3, &finally) &&
    2048             135 :            builder.tryStatement(body, clauses, finally, &pn->pn_pos, dst);
    2049                 : }
    2050                 : 
    2051                 : bool
    2052             315 : ASTSerializer::forInit(ParseNode *pn, Value *dst)
    2053                 : {
    2054             315 :     if (!pn) {
    2055             189 :         dst->setMagic(JS_SERIALIZE_NO_NODE);
    2056             189 :         return true;
    2057                 :     }
    2058                 : 
    2059             144 :     return (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST))
    2060                 :            ? variableDeclaration(pn, false, dst)
    2061             144 :            : expression(pn, dst);
    2062                 : }
    2063                 : 
    2064                 : bool
    2065            9883 : ASTSerializer::statement(ParseNode *pn, Value *dst)
    2066                 : {
    2067            9883 :     JS_CHECK_RECURSION(cx, return false);
    2068            9883 :     switch (pn->getKind()) {
    2069                 :       case PNK_FUNCTION:
    2070                 :       case PNK_VAR:
    2071                 :       case PNK_CONST:
    2072             522 :         return declaration(pn, dst);
    2073                 : 
    2074                 :       case PNK_LET:
    2075            1287 :         return pn->isArity(PN_BINARY)
    2076                 :                ? let(pn, false, dst)
    2077            1287 :                : declaration(pn, dst);
    2078                 : 
    2079                 :       case PNK_NAME:
    2080               0 :         LOCAL_ASSERT(pn->isUsed());
    2081               0 :         return statement(pn->pn_lexdef, dst);
    2082                 : 
    2083                 :       case PNK_SEMI:
    2084            2665 :         if (pn->pn_kid) {
    2085                 :             Value expr;
    2086            2656 :             return expression(pn->pn_kid, &expr) &&
    2087            2656 :                    builder.expressionStatement(expr, &pn->pn_pos, dst);
    2088                 :         }
    2089               9 :         return builder.emptyStatement(&pn->pn_pos, dst);
    2090                 : 
    2091                 :       case PNK_LEXICALSCOPE:
    2092             486 :         pn = pn->pn_expr;
    2093             486 :         if (!pn->isKind(PNK_STATEMENTLIST))
    2094               0 :             return statement(pn, dst);
    2095                 :         /* FALL THROUGH */
    2096                 : 
    2097                 :       case PNK_STATEMENTLIST:
    2098            1782 :         return blockStatement(pn, dst);
    2099                 : 
    2100                 :       case PNK_IF:
    2101                 :       {
    2102                 :         Value test, cons, alt;
    2103                 : 
    2104             423 :         return expression(pn->pn_kid1, &test) &&
    2105             423 :                statement(pn->pn_kid2, &cons) &&
    2106             423 :                optStatement(pn->pn_kid3, &alt) &&
    2107            1269 :                builder.ifStatement(test, cons, alt, &pn->pn_pos, dst);
    2108                 :       }
    2109                 : 
    2110                 :       case PNK_SWITCH:
    2111              36 :         return switchStatement(pn, dst);
    2112                 : 
    2113                 :       case PNK_TRY:
    2114             135 :         return tryStatement(pn, dst);
    2115                 : 
    2116                 :       case PNK_WITH:
    2117                 :       case PNK_WHILE:
    2118                 :       {
    2119                 :         Value expr, stmt;
    2120                 : 
    2121               0 :         return expression(pn->pn_left, &expr) &&
    2122               0 :                statement(pn->pn_right, &stmt) &&
    2123               0 :                (pn->isKind(PNK_WITH)
    2124               0 :                 ? builder.withStatement(expr, stmt, &pn->pn_pos, dst)
    2125               0 :                 : builder.whileStatement(expr, stmt, &pn->pn_pos, dst));
    2126                 :       }
    2127                 : 
    2128                 :       case PNK_DOWHILE:
    2129                 :       {
    2130                 :         Value stmt, test;
    2131                 : 
    2132               0 :         return statement(pn->pn_left, &stmt) &&
    2133               0 :                expression(pn->pn_right, &test) &&
    2134               0 :                builder.doWhileStatement(stmt, test, &pn->pn_pos, dst);
    2135                 :       }
    2136                 : 
    2137                 :       case PNK_FOR:
    2138                 :       {
    2139             558 :         ParseNode *head = pn->pn_left;
    2140                 : 
    2141                 :         Value stmt;
    2142             558 :         if (!statement(pn->pn_right, &stmt))
    2143               0 :             return false;
    2144                 : 
    2145             558 :         bool isForEach = pn->pn_iflags & JSITER_FOREACH;
    2146                 : 
    2147             558 :         if (head->isKind(PNK_FORIN)) {
    2148                 :             Value var, expr;
    2149                 : 
    2150             243 :             return (!head->pn_kid1
    2151               9 :                     ? pattern(head->pn_kid2, NULL, &var)
    2152             234 :                     : head->pn_kid1->isKind(PNK_LEXICALSCOPE)
    2153             225 :                       ? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
    2154               9 :                       : variableDeclaration(head->pn_kid1, false, &var)) &&
    2155             243 :                    expression(head->pn_kid3, &expr) &&
    2156             963 :                    builder.forInStatement(var, expr, stmt, isForEach, &pn->pn_pos, dst);
    2157                 :         }
    2158                 : 
    2159                 :         Value init, test, update;
    2160                 : 
    2161             315 :         return forInit(head->pn_kid1, &init) &&
    2162             315 :                optExpression(head->pn_kid2, &test) &&
    2163             315 :                optExpression(head->pn_kid3, &update) &&
    2164             945 :                builder.forStatement(init, test, update, stmt, &pn->pn_pos, dst);
    2165                 :       }
    2166                 : 
    2167                 :       /* Synthesized by the parser when a for-in loop contains a variable initializer. */
    2168                 :       case PNK_SEQ:
    2169                 :       {
    2170               0 :         LOCAL_ASSERT(pn->pn_count == 2);
    2171                 : 
    2172               0 :         ParseNode *prelude = pn->pn_head;
    2173               0 :         ParseNode *loop = prelude->pn_next;
    2174                 : 
    2175               0 :         LOCAL_ASSERT(prelude->isKind(PNK_VAR) && loop->isKind(PNK_FOR));
    2176                 : 
    2177                 :         Value var;
    2178               0 :         if (!variableDeclaration(prelude, false, &var))
    2179               0 :             return false;
    2180                 : 
    2181               0 :         ParseNode *head = loop->pn_left;
    2182               0 :         JS_ASSERT(head->isKind(PNK_FORIN));
    2183                 : 
    2184               0 :         bool isForEach = loop->pn_iflags & JSITER_FOREACH;
    2185                 : 
    2186                 :         Value expr, stmt;
    2187                 : 
    2188               0 :         return expression(head->pn_kid3, &expr) &&
    2189               0 :                statement(loop->pn_right, &stmt) &&
    2190               0 :                builder.forInStatement(var, expr, stmt, isForEach, &pn->pn_pos, dst);
    2191                 :       }
    2192                 : 
    2193                 :       case PNK_BREAK:
    2194                 :       case PNK_CONTINUE:
    2195                 :       {
    2196                 :         Value label;
    2197                 : 
    2198              72 :         return optIdentifier(pn->pn_atom, NULL, &label) &&
    2199              72 :                (pn->isKind(PNK_BREAK)
    2200              72 :                 ? builder.breakStatement(label, &pn->pn_pos, dst)
    2201             216 :                 : builder.continueStatement(label, &pn->pn_pos, dst));
    2202                 :       }
    2203                 : 
    2204                 :       case PNK_COLON:
    2205                 :       {
    2206                 :         Value label, stmt;
    2207                 : 
    2208              18 :         return identifier(pn->pn_atom, NULL, &label) &&
    2209              18 :                statement(pn->pn_expr, &stmt) &&
    2210              36 :                builder.labeledStatement(label, stmt, &pn->pn_pos, dst);
    2211                 :       }
    2212                 : 
    2213                 :       case PNK_THROW:
    2214                 :       case PNK_RETURN:
    2215                 :       {
    2216                 :         Value arg;
    2217                 : 
    2218            2385 :         return optExpression(pn->pn_kid, &arg) &&
    2219            2385 :                (pn->isKind(PNK_THROW)
    2220              27 :                 ? builder.throwStatement(arg, &pn->pn_pos, dst)
    2221            4797 :                 : builder.returnStatement(arg, &pn->pn_pos, dst));
    2222                 :       }
    2223                 : 
    2224                 :       case PNK_DEBUGGER:
    2225               0 :         return builder.debuggerStatement(&pn->pn_pos, dst);
    2226                 : 
    2227                 : #if JS_HAS_XML_SUPPORT
    2228                 :       case PNK_DEFXMLNS:
    2229                 :       {
    2230               0 :         LOCAL_ASSERT(pn->isArity(PN_UNARY));
    2231                 : 
    2232                 :         Value ns;
    2233                 : 
    2234               0 :         return expression(pn->pn_kid, &ns) &&
    2235               0 :                builder.xmlDefaultNamespace(ns, &pn->pn_pos, dst);
    2236                 :       }
    2237                 : #endif
    2238                 : 
    2239                 :       default:
    2240               0 :         LOCAL_NOT_REACHED("unexpected statement type");
    2241                 :     }
    2242                 : }
    2243                 : 
    2244                 : bool
    2245              45 : ASTSerializer::leftAssociate(ParseNode *pn, Value *dst)
    2246                 : {
    2247              45 :     JS_ASSERT(pn->isArity(PN_LIST));
    2248              45 :     JS_ASSERT(pn->pn_count >= 1);
    2249                 : 
    2250              45 :     ParseNodeKind kind = pn->getKind();
    2251              45 :     bool lor = kind == PNK_OR;
    2252              45 :     bool logop = lor || (kind == PNK_AND);
    2253                 : 
    2254              45 :     ParseNode *head = pn->pn_head;
    2255                 :     Value left;
    2256              45 :     if (!expression(head, &left))
    2257               0 :         return false;
    2258             135 :     for (ParseNode *next = head->pn_next; next; next = next->pn_next) {
    2259                 :         Value right;
    2260              90 :         if (!expression(next, &right))
    2261               0 :             return false;
    2262                 : 
    2263              90 :         TokenPos subpos = {pn->pn_pos.begin, next->pn_pos.end};
    2264                 : 
    2265              90 :         if (logop) {
    2266               0 :             if (!builder.logicalExpression(lor, left, right, &subpos, &left))
    2267               0 :                 return false;
    2268                 :         } else {
    2269              90 :             BinaryOperator op = binop(pn->getKind(), pn->getOp());
    2270              90 :             LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
    2271                 : 
    2272              90 :             if (!builder.binaryExpression(op, left, right, &subpos, &left))
    2273               0 :                 return false;
    2274                 :         }
    2275                 :     }
    2276                 : 
    2277              45 :     *dst = left;
    2278              45 :     return true;
    2279                 : }
    2280                 : 
    2281                 : bool
    2282              72 : ASTSerializer::comprehensionBlock(ParseNode *pn, Value *dst)
    2283                 : {
    2284              72 :     LOCAL_ASSERT(pn->isArity(PN_BINARY));
    2285                 : 
    2286              72 :     ParseNode *in = pn->pn_left;
    2287                 : 
    2288              72 :     LOCAL_ASSERT(in && in->isKind(PNK_FORIN));
    2289                 : 
    2290              72 :     bool isForEach = pn->pn_iflags & JSITER_FOREACH;
    2291                 : 
    2292                 :     Value patt, src;
    2293              72 :     return pattern(in->pn_kid2, NULL, &patt) &&
    2294              72 :            expression(in->pn_kid3, &src) &&
    2295             144 :            builder.comprehensionBlock(patt, src, isForEach, &in->pn_pos, dst);
    2296                 : }
    2297                 : 
    2298                 : bool
    2299              36 : ASTSerializer::comprehension(ParseNode *pn, Value *dst)
    2300                 : {
    2301              36 :     LOCAL_ASSERT(pn->isKind(PNK_FOR));
    2302                 : 
    2303              72 :     NodeVector blocks(cx);
    2304                 : 
    2305              36 :     ParseNode *next = pn;
    2306             108 :     while (next->isKind(PNK_FOR)) {
    2307                 :         Value block;
    2308              36 :         if (!comprehensionBlock(next, &block) || !blocks.append(block))
    2309               0 :             return false;
    2310              36 :         next = next->pn_right;
    2311                 :     }
    2312                 : 
    2313              36 :     Value filter = MagicValue(JS_SERIALIZE_NO_NODE);
    2314                 : 
    2315              36 :     if (next->isKind(PNK_IF)) {
    2316               0 :         if (!optExpression(next->pn_kid1, &filter))
    2317               0 :             return false;
    2318               0 :         next = next->pn_kid2;
    2319              36 :     } else if (next->isKind(PNK_STATEMENTLIST) && next->pn_count == 0) {
    2320                 :         /* FoldConstants optimized away the push. */
    2321               0 :         NodeVector empty(cx);
    2322               0 :         return builder.arrayExpression(empty, &pn->pn_pos, dst);
    2323                 :     }
    2324                 : 
    2325              36 :     LOCAL_ASSERT(next->isKind(PNK_ARRAYPUSH));
    2326                 : 
    2327                 :     Value body;
    2328                 : 
    2329              36 :     return expression(next->pn_kid, &body) &&
    2330              36 :            builder.comprehensionExpression(body, blocks, filter, &pn->pn_pos, dst);
    2331                 : }
    2332                 : 
    2333                 : bool
    2334              36 : ASTSerializer::generatorExpression(ParseNode *pn, Value *dst)
    2335                 : {
    2336              36 :     LOCAL_ASSERT(pn->isKind(PNK_FOR));
    2337                 : 
    2338              72 :     NodeVector blocks(cx);
    2339                 : 
    2340              36 :     ParseNode *next = pn;
    2341             108 :     while (next->isKind(PNK_FOR)) {
    2342                 :         Value block;
    2343              36 :         if (!comprehensionBlock(next, &block) || !blocks.append(block))
    2344               0 :             return false;
    2345              36 :         next = next->pn_right;
    2346                 :     }
    2347                 : 
    2348              36 :     Value filter = MagicValue(JS_SERIALIZE_NO_NODE);
    2349                 : 
    2350              36 :     if (next->isKind(PNK_IF)) {
    2351               0 :         if (!optExpression(next->pn_kid1, &filter))
    2352               0 :             return false;
    2353               0 :         next = next->pn_kid2;
    2354                 :     }
    2355                 : 
    2356              36 :     LOCAL_ASSERT(next->isKind(PNK_SEMI) &&
    2357                 :                  next->pn_kid->isKind(PNK_YIELD) &&
    2358                 :                  next->pn_kid->pn_kid);
    2359                 : 
    2360                 :     Value body;
    2361                 : 
    2362              36 :     return expression(next->pn_kid->pn_kid, &body) &&
    2363              36 :            builder.generatorExpression(body, blocks, filter, &pn->pn_pos, dst);
    2364                 : }
    2365                 : 
    2366                 : bool
    2367           17893 : ASTSerializer::expression(ParseNode *pn, Value *dst)
    2368                 : {
    2369           17893 :     JS_CHECK_RECURSION(cx, return false);
    2370           17893 :     switch (pn->getKind()) {
    2371                 :       case PNK_FUNCTION:
    2372            2295 :         return function(pn, AST_FUNC_EXPR, dst);
    2373                 : 
    2374                 :       case PNK_COMMA:
    2375                 :       {
    2376             108 :         NodeVector exprs(cx);
    2377              54 :         return expressions(pn, exprs) &&
    2378              54 :                builder.sequenceExpression(exprs, &pn->pn_pos, dst);
    2379                 :       }
    2380                 : 
    2381                 :       case PNK_CONDITIONAL:
    2382                 :       {
    2383                 :         Value test, cons, alt;
    2384                 : 
    2385               0 :         return expression(pn->pn_kid1, &test) &&
    2386               0 :                expression(pn->pn_kid2, &cons) &&
    2387               0 :                expression(pn->pn_kid3, &alt) &&
    2388               0 :                builder.conditionalExpression(test, cons, alt, &pn->pn_pos, dst);
    2389                 :       }
    2390                 : 
    2391                 :       case PNK_OR:
    2392                 :       case PNK_AND:
    2393                 :       {
    2394               0 :         if (pn->isArity(PN_BINARY)) {
    2395                 :             Value left, right;
    2396               0 :             return expression(pn->pn_left, &left) &&
    2397               0 :                    expression(pn->pn_right, &right) &&
    2398               0 :                    builder.logicalExpression(pn->isKind(PNK_OR), left, right, &pn->pn_pos, dst);
    2399                 :         }
    2400               0 :         return leftAssociate(pn, dst);
    2401                 :       }
    2402                 : 
    2403                 :       case PNK_PREINCREMENT:
    2404                 :       case PNK_PREDECREMENT:
    2405                 :       {
    2406             180 :         bool inc = pn->isKind(PNK_PREINCREMENT);
    2407                 :         Value expr;
    2408             180 :         return expression(pn->pn_kid, &expr) &&
    2409             180 :                builder.updateExpression(expr, inc, true, &pn->pn_pos, dst);
    2410                 :       }
    2411                 : 
    2412                 :       case PNK_POSTINCREMENT:
    2413                 :       case PNK_POSTDECREMENT:
    2414                 :       {
    2415              18 :         bool inc = pn->isKind(PNK_POSTINCREMENT);
    2416                 :         Value expr;
    2417              18 :         return expression(pn->pn_kid, &expr) &&
    2418              18 :                builder.updateExpression(expr, inc, false, &pn->pn_pos, dst);
    2419                 :       }
    2420                 : 
    2421                 :       case PNK_ASSIGN:
    2422                 :       case PNK_ADDASSIGN:
    2423                 :       case PNK_SUBASSIGN:
    2424                 :       case PNK_BITORASSIGN:
    2425                 :       case PNK_BITXORASSIGN:
    2426                 :       case PNK_BITANDASSIGN:
    2427                 :       case PNK_LSHASSIGN:
    2428                 :       case PNK_RSHASSIGN:
    2429                 :       case PNK_URSHASSIGN:
    2430                 :       case PNK_MULASSIGN:
    2431                 :       case PNK_DIVASSIGN:
    2432                 :       case PNK_MODASSIGN:
    2433                 :       {
    2434             270 :         AssignmentOperator op = aop(pn->getOp());
    2435             270 :         LOCAL_ASSERT(op > AOP_ERR && op < AOP_LIMIT);
    2436                 : 
    2437                 :         Value lhs, rhs;
    2438             270 :         return pattern(pn->pn_left, NULL, &lhs) &&
    2439             270 :                expression(pn->pn_right, &rhs) &&
    2440             540 :                builder.assignmentExpression(op, lhs, rhs, &pn->pn_pos, dst);
    2441                 :       }
    2442                 : 
    2443                 :       case PNK_ADD:
    2444                 :       case PNK_SUB:
    2445                 :       case PNK_STRICTEQ:
    2446                 :       case PNK_EQ:
    2447                 :       case PNK_STRICTNE:
    2448                 :       case PNK_NE:
    2449                 :       case PNK_LT:
    2450                 :       case PNK_LE:
    2451                 :       case PNK_GT:
    2452                 :       case PNK_GE:
    2453                 :       case PNK_LSH:
    2454                 :       case PNK_RSH:
    2455                 :       case PNK_URSH:
    2456                 :       case PNK_STAR:
    2457                 :       case PNK_DIV:
    2458                 :       case PNK_MOD:
    2459                 :       case PNK_BITOR:
    2460                 :       case PNK_BITXOR:
    2461                 :       case PNK_BITAND:
    2462                 :       case PNK_IN:
    2463                 :       case PNK_INSTANCEOF:
    2464                 :       case PNK_DBLDOT:
    2465             954 :         if (pn->isArity(PN_BINARY)) {
    2466             909 :             BinaryOperator op = binop(pn->getKind(), pn->getOp());
    2467             909 :             LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
    2468                 : 
    2469                 :             Value left, right;
    2470             909 :             return expression(pn->pn_left, &left) &&
    2471             909 :                    expression(pn->pn_right, &right) &&
    2472            1818 :                    builder.binaryExpression(op, left, right, &pn->pn_pos, dst);
    2473                 :         }
    2474              45 :         return leftAssociate(pn, dst);
    2475                 : 
    2476                 :       case PNK_DELETE:
    2477                 :       case PNK_TYPEOF:
    2478                 :       case PNK_VOID:
    2479                 :       case PNK_NOT:
    2480                 :       case PNK_BITNOT:
    2481                 :       case PNK_POS:
    2482                 :       case PNK_NEG: {
    2483               0 :         UnaryOperator op = unop(pn->getKind(), pn->getOp());
    2484               0 :         LOCAL_ASSERT(op > UNOP_ERR && op < UNOP_LIMIT);
    2485                 : 
    2486                 :         Value expr;
    2487               0 :         return expression(pn->pn_kid, &expr) &&
    2488               0 :                builder.unaryExpression(op, expr, &pn->pn_pos, dst);
    2489                 :       }
    2490                 : 
    2491                 :       case PNK_NEW:
    2492                 :       case PNK_LP:
    2493                 :       {
    2494                 : #ifdef JS_HAS_GENERATOR_EXPRS
    2495             774 :         if (pn->isGeneratorExpr())
    2496              36 :             return generatorExpression(pn->generatorExpr(), dst);
    2497                 : #endif
    2498                 : 
    2499             738 :         ParseNode *next = pn->pn_head;
    2500                 : 
    2501                 :         Value callee;
    2502             738 :         if (!expression(next, &callee))
    2503               0 :             return false;
    2504                 : 
    2505            1476 :         NodeVector args(cx);
    2506             738 :         if (!args.reserve(pn->pn_count - 1))
    2507               0 :             return false;
    2508                 : 
    2509            1368 :         for (next = next->pn_next; next; next = next->pn_next) {
    2510                 :             Value arg;
    2511             630 :             if (!expression(next, &arg))
    2512               0 :                 return false;
    2513             630 :             args.infallibleAppend(arg);
    2514                 :         }
    2515                 : 
    2516             738 :         return pn->isKind(PNK_NEW)
    2517               0 :                ? builder.newExpression(callee, args, &pn->pn_pos, dst)
    2518             738 :                : builder.callExpression(callee, args, &pn->pn_pos, dst);
    2519                 :       }
    2520                 : 
    2521                 :       case PNK_DOT:
    2522                 :       {
    2523                 :         Value expr, id;
    2524             144 :         return expression(pn->pn_expr, &expr) &&
    2525             144 :                identifier(pn->pn_atom, NULL, &id) &&
    2526             288 :                builder.memberExpression(false, expr, id, &pn->pn_pos, dst);
    2527                 :       }
    2528                 : 
    2529                 :       case PNK_LB:
    2530                 :       {
    2531                 :         Value left, right;
    2532              72 :         return expression(pn->pn_left, &left) &&
    2533              72 :                expression(pn->pn_right, &right) &&
    2534             144 :                builder.memberExpression(true, left, right, &pn->pn_pos, dst);
    2535                 :       }
    2536                 : 
    2537                 :       case PNK_RB:
    2538                 :       {
    2539            1080 :         NodeVector elts(cx);
    2540             540 :         if (!elts.reserve(pn->pn_count))
    2541               0 :             return false;
    2542                 : 
    2543            1260 :         for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
    2544             720 :             if (next->isKind(PNK_COMMA)) {
    2545               0 :                 elts.infallibleAppend(MagicValue(JS_SERIALIZE_NO_NODE));
    2546                 :             } else {
    2547                 :                 Value expr;
    2548             720 :                 if (!expression(next, &expr))
    2549               0 :                     return false;
    2550             720 :                 elts.infallibleAppend(expr);
    2551                 :             }
    2552                 :         }
    2553                 : 
    2554             540 :         return builder.arrayExpression(elts, &pn->pn_pos, dst);
    2555                 :       }
    2556                 : 
    2557                 :       case PNK_RC:
    2558                 :       {
    2559                 :         /* The parser notes any uninitialized properties by setting the PNX_DESTRUCT flag. */
    2560             126 :         if (pn->pn_xflags & PNX_DESTRUCT) {
    2561               0 :             parser->reportErrorNumber(pn, JSREPORT_ERROR, JSMSG_BAD_OBJECT_INIT);
    2562               0 :             return false;
    2563                 :         }
    2564             252 :         NodeVector elts(cx);
    2565             126 :         if (!elts.reserve(pn->pn_count))
    2566               0 :             return false;
    2567                 : 
    2568             225 :         for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
    2569                 :             Value prop;
    2570              99 :             if (!property(next, &prop))
    2571               0 :                 return false;
    2572              99 :             elts.infallibleAppend(prop);
    2573                 :         }
    2574                 : 
    2575             126 :         return builder.objectExpression(elts, &pn->pn_pos, dst);
    2576                 :       }
    2577                 : 
    2578                 :       case PNK_NAME:
    2579            9765 :         return identifier(pn, dst);
    2580                 : 
    2581                 :       case PNK_THIS:
    2582              54 :         return builder.thisExpression(&pn->pn_pos, dst);
    2583                 : 
    2584                 :       case PNK_STRING:
    2585                 :       case PNK_REGEXP:
    2586                 :       case PNK_NUMBER:
    2587                 :       case PNK_TRUE:
    2588                 :       case PNK_FALSE:
    2589                 :       case PNK_NULL:
    2590            2071 :         return literal(pn, dst);
    2591                 : 
    2592                 :       case PNK_YIELD:
    2593                 :       {
    2594                 :         Value arg;
    2595               0 :         return optExpression(pn->pn_kid, &arg) &&
    2596               0 :                builder.yieldExpression(arg, &pn->pn_pos, dst);
    2597                 :       }
    2598                 : 
    2599                 :       case PNK_ARRAYCOMP:
    2600                 :         /* NB: it's no longer the case that pn_count could be 2. */
    2601              36 :         LOCAL_ASSERT(pn->pn_count == 1);
    2602              36 :         LOCAL_ASSERT(pn->pn_head->isKind(PNK_LEXICALSCOPE));
    2603                 : 
    2604              36 :         return comprehension(pn->pn_head->pn_expr, dst);
    2605                 : 
    2606                 :       case PNK_LET:
    2607             540 :         return let(pn, true, dst);
    2608                 : 
    2609                 : #ifdef JS_HAS_XML_SUPPORT
    2610                 :       case PNK_XMLUNARY:
    2611               0 :         JS_ASSERT(pn->isOp(JSOP_XMLNAME) ||
    2612                 :                   pn->isOp(JSOP_SETXMLNAME) ||
    2613               0 :                   pn->isOp(JSOP_BINDXMLNAME));
    2614               0 :         return expression(pn->pn_kid, dst);
    2615                 : 
    2616                 :       case PNK_ANYNAME:
    2617               0 :         return builder.xmlAnyName(&pn->pn_pos, dst);
    2618                 : 
    2619                 :       case PNK_DBLCOLON:
    2620                 :       {
    2621                 :         Value right;
    2622                 : 
    2623               0 :         LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_BINARY));
    2624                 : 
    2625                 :         ParseNode *pnleft;
    2626                 :         bool computed;
    2627                 : 
    2628               0 :         if (pn->isArity(PN_BINARY)) {
    2629               0 :             computed = true;
    2630               0 :             pnleft = pn->pn_left;
    2631               0 :             if (!expression(pn->pn_right, &right))
    2632               0 :                 return false;
    2633                 :         } else {
    2634               0 :             JS_ASSERT(pn->isArity(PN_NAME));
    2635               0 :             computed = false;
    2636               0 :             pnleft = pn->pn_expr;
    2637               0 :             if (!identifier(pn->pn_atom, NULL, &right))
    2638               0 :                 return false;
    2639                 :         }
    2640                 : 
    2641               0 :         if (pnleft->isKind(PNK_FUNCTION))
    2642               0 :             return builder.xmlFunctionQualifiedIdentifier(right, computed, &pn->pn_pos, dst);
    2643                 : 
    2644                 :         Value left;
    2645               0 :         return expression(pnleft, &left) &&
    2646               0 :                builder.xmlQualifiedIdentifier(left, right, computed, &pn->pn_pos, dst);
    2647                 :       }
    2648                 : 
    2649                 :       case PNK_AT:
    2650                 :       {
    2651                 :         Value expr;
    2652               0 :         ParseNode *kid = pn->pn_kid;
    2653               0 :         bool computed = ((!kid->isKind(PNK_NAME) || !kid->isOp(JSOP_QNAMEPART)) &&
    2654               0 :                          !kid->isKind(PNK_DBLCOLON) &&
    2655               0 :                          !kid->isKind(PNK_ANYNAME));
    2656               0 :         return expression(kid, &expr) &&
    2657               0 :             builder.xmlAttributeSelector(expr, computed, &pn->pn_pos, dst);
    2658                 :       }
    2659                 : 
    2660                 :       case PNK_FILTER:
    2661                 :       {
    2662                 :         Value left, right;
    2663               0 :         return expression(pn->pn_left, &left) &&
    2664               0 :                expression(pn->pn_right, &right) &&
    2665               0 :                builder.xmlFilterExpression(left, right, &pn->pn_pos, dst);
    2666                 :       }
    2667                 : 
    2668                 :       default:
    2669               0 :         return xml(pn, dst);
    2670                 : 
    2671                 : #else
    2672                 :       default:
    2673                 :         LOCAL_NOT_REACHED("unexpected expression type");
    2674                 : #endif
    2675                 :     }
    2676                 : }
    2677                 : 
    2678                 : bool
    2679               0 : ASTSerializer::xml(ParseNode *pn, Value *dst)
    2680                 : {
    2681               0 :     JS_CHECK_RECURSION(cx, return false);
    2682               0 :     switch (pn->getKind()) {
    2683                 : #ifdef JS_HAS_XML_SUPPORT
    2684                 :       case PNK_XMLCURLYEXPR:
    2685                 :       {
    2686                 :         Value expr;
    2687               0 :         return expression(pn->pn_kid, &expr) &&
    2688               0 :                builder.xmlEscapeExpression(expr, &pn->pn_pos, dst);
    2689                 :       }
    2690                 : 
    2691                 :       case PNK_XMLELEM:
    2692                 :       {
    2693               0 :         NodeVector elts(cx);
    2694               0 :         if (!xmls(pn, elts))
    2695               0 :             return false;
    2696               0 :         return builder.xmlElement(elts, &pn->pn_pos, dst);
    2697                 :       }
    2698                 : 
    2699                 :       case PNK_XMLLIST:
    2700                 :       {
    2701               0 :         NodeVector elts(cx);
    2702               0 :         if (!xmls(pn, elts))
    2703               0 :             return false;
    2704               0 :         return builder.xmlList(elts, &pn->pn_pos, dst);
    2705                 :       }
    2706                 : 
    2707                 :       case PNK_XMLSTAGO:
    2708                 :       {
    2709               0 :         NodeVector elts(cx);
    2710               0 :         if (!xmls(pn, elts))
    2711               0 :             return false;
    2712               0 :         return builder.xmlStartTag(elts, &pn->pn_pos, dst);
    2713                 :       }
    2714                 : 
    2715                 :       case PNK_XMLETAGO:
    2716                 :       {
    2717               0 :         NodeVector elts(cx);
    2718               0 :         if (!xmls(pn, elts))
    2719               0 :             return false;
    2720               0 :         return builder.xmlEndTag(elts, &pn->pn_pos, dst);
    2721                 :       }
    2722                 : 
    2723                 :       case PNK_XMLPTAGC:
    2724                 :       {
    2725               0 :         NodeVector elts(cx);
    2726               0 :         if (!xmls(pn, elts))
    2727               0 :             return false;
    2728               0 :         return builder.xmlPointTag(elts, &pn->pn_pos, dst);
    2729                 :       }
    2730                 : 
    2731                 :       case PNK_XMLTEXT:
    2732                 :       case PNK_XMLSPACE:
    2733               0 :         return builder.xmlText(atomContents(pn->pn_atom), &pn->pn_pos, dst);
    2734                 : 
    2735                 :       case PNK_XMLNAME:
    2736               0 :         if (pn->isArity(PN_NULLARY))
    2737               0 :             return builder.xmlName(atomContents(pn->pn_atom), &pn->pn_pos, dst);
    2738                 : 
    2739               0 :         LOCAL_ASSERT(pn->isArity(PN_LIST));
    2740                 : 
    2741                 :         {
    2742               0 :             NodeVector elts(cx);
    2743               0 :             return xmls(pn, elts) &&
    2744               0 :                    builder.xmlName(elts, &pn->pn_pos, dst);
    2745                 :         }
    2746                 : 
    2747                 :       case PNK_XMLATTR:
    2748               0 :         return builder.xmlAttribute(atomContents(pn->pn_atom), &pn->pn_pos, dst);
    2749                 : 
    2750                 :       case PNK_XMLCDATA:
    2751               0 :         return builder.xmlCdata(atomContents(pn->pn_atom), &pn->pn_pos, dst);
    2752                 : 
    2753                 :       case PNK_XMLCOMMENT:
    2754               0 :         return builder.xmlComment(atomContents(pn->pn_atom), &pn->pn_pos, dst);
    2755                 : 
    2756                 :       case PNK_XMLPI: {
    2757               0 :         XMLProcessingInstruction &pi = pn->asXMLProcessingInstruction();
    2758               0 :         return builder.xmlPI(atomContents(pi.target()),
    2759               0 :                              atomContents(pi.data()),
    2760                 :                              &pi.pn_pos,
    2761               0 :                              dst);
    2762                 :       }
    2763                 : #endif
    2764                 : 
    2765                 :       default:
    2766               0 :         LOCAL_NOT_REACHED("unexpected XML node type");
    2767                 :     }
    2768                 : }
    2769                 : 
    2770                 : bool
    2771             675 : ASTSerializer::propertyName(ParseNode *pn, Value *dst)
    2772                 : {
    2773             675 :     if (pn->isKind(PNK_NAME))
    2774             603 :         return identifier(pn, dst);
    2775                 : 
    2776              72 :     LOCAL_ASSERT(pn->isKind(PNK_STRING) || pn->isKind(PNK_NUMBER));
    2777                 : 
    2778              72 :     return literal(pn, dst);
    2779                 : }
    2780                 : 
    2781                 : bool
    2782              99 : ASTSerializer::property(ParseNode *pn, Value *dst)
    2783                 : {
    2784                 :     PropKind kind;
    2785              99 :     switch (pn->getOp()) {
    2786                 :       case JSOP_INITPROP:
    2787              99 :         kind = PROP_INIT;
    2788              99 :         break;
    2789                 : 
    2790                 :       case JSOP_GETTER:
    2791               0 :         kind = PROP_GETTER;
    2792               0 :         break;
    2793                 : 
    2794                 :       case JSOP_SETTER:
    2795               0 :         kind = PROP_SETTER;
    2796               0 :         break;
    2797                 : 
    2798                 :       default:
    2799               0 :         LOCAL_NOT_REACHED("unexpected object-literal property");
    2800                 :     }
    2801                 : 
    2802                 :     Value key, val;
    2803              99 :     return propertyName(pn->pn_left, &key) &&
    2804              99 :            expression(pn->pn_right, &val) &&
    2805             198 :            builder.propertyInitializer(key, val, kind, &pn->pn_pos, dst);
    2806                 : }
    2807                 : 
    2808                 : bool
    2809            2143 : ASTSerializer::literal(ParseNode *pn, Value *dst)
    2810                 : {
    2811                 :     Value val;
    2812            2143 :     switch (pn->getKind()) {
    2813                 :       case PNK_STRING:
    2814             901 :         val.setString(pn->pn_atom);
    2815             901 :         break;
    2816                 : 
    2817                 :       case PNK_REGEXP:
    2818                 :       {
    2819               0 :         JSObject *re1 = pn->pn_objbox ? pn->pn_objbox->object : NULL;
    2820               0 :         LOCAL_ASSERT(re1 && re1->isRegExp());
    2821                 : 
    2822                 :         JSObject *proto;
    2823               0 :         if (!js_GetClassPrototype(cx, &cx->fp()->scopeChain(), JSProto_RegExp, &proto))
    2824               0 :             return false;
    2825                 : 
    2826               0 :         JSObject *re2 = CloneRegExpObject(cx, re1, proto);
    2827               0 :         if (!re2)
    2828               0 :             return false;
    2829                 : 
    2830               0 :         val.setObject(*re2);
    2831               0 :         break;
    2832                 :       }
    2833                 : 
    2834                 :       case PNK_NUMBER:
    2835            1233 :         val.setNumber(pn->pn_dval);
    2836            1233 :         break;
    2837                 : 
    2838                 :       case PNK_NULL:
    2839               0 :         val.setNull();
    2840               0 :         break;
    2841                 : 
    2842                 :       case PNK_TRUE:
    2843               9 :         val.setBoolean(true);
    2844               9 :         break;
    2845                 : 
    2846                 :       case PNK_FALSE:
    2847               0 :         val.setBoolean(false);
    2848               0 :         break;
    2849                 : 
    2850                 :       default:
    2851               0 :         LOCAL_NOT_REACHED("unexpected literal type");
    2852                 :     }
    2853                 : 
    2854            2143 :     return builder.literal(val, &pn->pn_pos, dst);
    2855                 : }
    2856                 : 
    2857                 : bool
    2858            2358 : ASTSerializer::arrayPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst)
    2859                 : {
    2860            2358 :     JS_ASSERT(pn->isKind(PNK_RB));
    2861                 : 
    2862            4716 :     NodeVector elts(cx);
    2863            2358 :     if (!elts.reserve(pn->pn_count))
    2864               0 :         return false;
    2865                 : 
    2866            4752 :     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
    2867            2394 :         if (next->isKind(PNK_COMMA)) {
    2868             342 :             elts.infallibleAppend(MagicValue(JS_SERIALIZE_NO_NODE));
    2869                 :         } else {
    2870                 :             Value patt;
    2871            2052 :             if (!pattern(next, pkind, &patt))
    2872               0 :                 return false;
    2873            2052 :             elts.infallibleAppend(patt);
    2874                 :         }
    2875                 :     }
    2876                 : 
    2877            2358 :     return builder.arrayPattern(elts, &pn->pn_pos, dst);
    2878                 : }
    2879                 : 
    2880                 : bool
    2881             441 : ASTSerializer::objectPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst)
    2882                 : {
    2883             441 :     JS_ASSERT(pn->isKind(PNK_RC));
    2884                 : 
    2885             882 :     NodeVector elts(cx);
    2886             441 :     if (!elts.reserve(pn->pn_count))
    2887               0 :         return false;
    2888                 : 
    2889            1017 :     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
    2890             576 :         LOCAL_ASSERT(next->isOp(JSOP_INITPROP));
    2891                 : 
    2892                 :         Value key, patt, prop;
    2893            1728 :         if (!propertyName(next->pn_left, &key) ||
    2894             576 :             !pattern(next->pn_right, pkind, &patt) ||
    2895             576 :             !builder.propertyPattern(key, patt, &next->pn_pos, &prop)) {
    2896               0 :             return false;
    2897                 :         }
    2898                 : 
    2899             576 :         elts.infallibleAppend(prop);
    2900                 :     }
    2901                 : 
    2902             441 :     return builder.objectPattern(elts, &pn->pn_pos, dst);
    2903                 : }
    2904                 : 
    2905                 : bool
    2906            6219 : ASTSerializer::pattern(ParseNode *pn, VarDeclKind *pkind, Value *dst)
    2907                 : {
    2908            6219 :     JS_CHECK_RECURSION(cx, return false);
    2909            6219 :     switch (pn->getKind()) {
    2910                 :       case PNK_RC:
    2911             441 :         return objectPattern(pn, pkind, dst);
    2912                 : 
    2913                 :       case PNK_RB:
    2914            2358 :         return arrayPattern(pn, pkind, dst);
    2915                 : 
    2916                 :       case PNK_NAME:
    2917            3384 :         if (pkind && (pn->pn_dflags & PND_CONST))
    2918               0 :             *pkind = VARDECL_CONST;
    2919                 :         /* FALL THROUGH */
    2920                 : 
    2921                 :       default:
    2922            3420 :         return expression(pn, dst);
    2923                 :     }
    2924                 : }
    2925                 : 
    2926                 : bool
    2927           15084 : ASTSerializer::identifier(JSAtom *atom, TokenPos *pos, Value *dst)
    2928                 : {
    2929           15084 :     return builder.identifier(atomContents(atom), pos, dst);
    2930                 : }
    2931                 : 
    2932                 : bool
    2933           12627 : ASTSerializer::identifier(ParseNode *pn, Value *dst)
    2934                 : {
    2935           12627 :     LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_NULLARY));
    2936           12627 :     LOCAL_ASSERT(pn->pn_atom);
    2937                 : 
    2938           12627 :     return identifier(pn->pn_atom, &pn->pn_pos, dst);
    2939                 : }
    2940                 : 
    2941                 : bool
    2942            2313 : ASTSerializer::function(ParseNode *pn, ASTType type, Value *dst)
    2943                 : {
    2944            2313 :     JSFunction *func = (JSFunction *)pn->pn_funbox->object;
    2945                 : 
    2946                 :     bool isGenerator =
    2947                 : #ifdef JS_HAS_GENERATORS
    2948            2313 :         pn->pn_funbox->tcflags & TCF_FUN_IS_GENERATOR;
    2949                 : #else
    2950                 :         false;
    2951                 : #endif
    2952                 : 
    2953                 :     bool isExpression =
    2954                 : #ifdef JS_HAS_EXPR_CLOSURES
    2955            2313 :         func->flags & JSFUN_EXPR_CLOSURE;
    2956                 : #else
    2957                 :         false;
    2958                 : #endif
    2959                 : 
    2960                 :     Value id;
    2961            2313 :     if (!optIdentifier(func->atom, NULL, &id))
    2962               0 :         return false;
    2963                 : 
    2964            4626 :     NodeVector args(cx);
    2965                 : 
    2966            2313 :     ParseNode *argsAndBody = pn->pn_body->isKind(PNK_UPVARS)
    2967                 :                              ? pn->pn_body->pn_tree
    2968            2313 :                              : pn->pn_body;
    2969                 : 
    2970                 :     Value body;
    2971            2313 :     return functionArgsAndBody(argsAndBody, args, &body) &&
    2972            2313 :            builder.function(type, &pn->pn_pos, id, args, body, isGenerator, isExpression, dst);
    2973                 : }
    2974                 : 
    2975                 : bool
    2976            2313 : ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, Value *body)
    2977                 : {
    2978                 :     ParseNode *pnargs;
    2979                 :     ParseNode *pnbody;
    2980                 : 
    2981                 :     /* Extract the args and body separately. */
    2982            2313 :     if (pn->isKind(PNK_ARGSBODY)) {
    2983            2259 :         pnargs = pn;
    2984            2259 :         pnbody = pn->last();
    2985                 :     } else {
    2986              54 :         pnargs = NULL;
    2987              54 :         pnbody = pn;
    2988                 :     }
    2989                 : 
    2990                 :     ParseNode *pndestruct;
    2991                 : 
    2992                 :     /* Extract the destructuring assignments. */
    2993            2313 :     if (pnbody->isArity(PN_LIST) && (pnbody->pn_xflags & PNX_DESTRUCT)) {
    2994               0 :         ParseNode *head = pnbody->pn_head;
    2995               0 :         LOCAL_ASSERT(head && head->isKind(PNK_SEMI));
    2996                 : 
    2997               0 :         pndestruct = head->pn_kid;
    2998               0 :         LOCAL_ASSERT(pndestruct);
    2999               0 :         LOCAL_ASSERT(pndestruct->isKind(PNK_VAR));
    3000                 :     } else {
    3001            2313 :         pndestruct = NULL;
    3002                 :     }
    3003                 : 
    3004                 :     /* Serialize the arguments and body. */
    3005            2313 :     switch (pnbody->getKind()) {
    3006                 :       case PNK_RETURN: /* expression closure, no destructured args */
    3007               0 :         return functionArgs(pn, pnargs, NULL, pnbody, args) &&
    3008               0 :                expression(pnbody->pn_kid, body);
    3009                 : 
    3010                 :       case PNK_SEQ:    /* expression closure with destructured args */
    3011                 :       {
    3012               0 :         ParseNode *pnstart = pnbody->pn_head->pn_next;
    3013               0 :         LOCAL_ASSERT(pnstart && pnstart->isKind(PNK_RETURN));
    3014                 : 
    3015               0 :         return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
    3016               0 :                expression(pnstart->pn_kid, body);
    3017                 :       }
    3018                 : 
    3019                 :       case PNK_STATEMENTLIST:     /* statement closure */
    3020                 :       {
    3021                 :         ParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT)
    3022                 :                                ? pnbody->pn_head->pn_next
    3023            2313 :                                : pnbody->pn_head;
    3024                 : 
    3025            2313 :         return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
    3026            2313 :                functionBody(pnstart, &pnbody->pn_pos, body);
    3027                 :       }
    3028                 : 
    3029                 :       default:
    3030               0 :         LOCAL_NOT_REACHED("unexpected function contents");
    3031                 :     }
    3032                 : }
    3033                 : 
    3034                 : bool
    3035            2313 : ASTSerializer::functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct,
    3036                 :                             ParseNode *pnbody, NodeVector &args)
    3037                 : {
    3038            2313 :     uint32_t i = 0;
    3039            2313 :     ParseNode *arg = pnargs ? pnargs->pn_head : NULL;
    3040            2313 :     ParseNode *destruct = pndestruct ? pndestruct->pn_head : NULL;
    3041                 :     Value node;
    3042                 : 
    3043                 :     /*
    3044                 :      * Arguments are found in potentially two different places: 1) the
    3045                 :      * argsbody sequence (which ends with the body node), or 2) a
    3046                 :      * destructuring initialization at the beginning of the body. Loop
    3047                 :      * |arg| through the argsbody and |destruct| through the initial
    3048                 :      * destructuring assignments, stopping only when we've exhausted
    3049                 :      * both.
    3050                 :      */
    3051            6885 :     while ((arg && arg != pnbody) || destruct) {
    3052            2259 :         if (destruct && destruct->pn_right->frameSlot() == i) {
    3053               0 :             if (!pattern(destruct->pn_left, NULL, &node) || !args.append(node))
    3054               0 :                 return false;
    3055               0 :             destruct = destruct->pn_next;
    3056            2259 :         } else if (arg && arg != pnbody) {
    3057                 :             /*
    3058                 :              * We don't check that arg->frameSlot() == i since we
    3059                 :              * can't call that method if the arg def has been turned
    3060                 :              * into a use, e.g.:
    3061                 :              *
    3062                 :              *     function(a) { function a() { } }
    3063                 :              *
    3064                 :              * There's no other way to ask a non-destructuring arg its
    3065                 :              * index in the formals list, so we rely on the ability to
    3066                 :              * ask destructuring args their index above.
    3067                 :              */
    3068            2259 :             if (!identifier(arg, &node) || !args.append(node))
    3069               0 :                 return false;
    3070            2259 :             arg = arg->pn_next;
    3071                 :         } else {
    3072               0 :             LOCAL_NOT_REACHED("missing function argument");
    3073                 :         }
    3074            2259 :         ++i;
    3075                 :     }
    3076                 : 
    3077            2313 :     return true;
    3078                 : }
    3079                 : 
    3080                 : bool
    3081            2313 : ASTSerializer::functionBody(ParseNode *pn, TokenPos *pos, Value *dst)
    3082                 : {
    3083            4626 :     NodeVector elts(cx);
    3084                 : 
    3085                 :     /* We aren't sure how many elements there are up front, so we'll check each append. */
    3086            5418 :     for (ParseNode *next = pn; next; next = next->pn_next) {
    3087                 :         Value child;
    3088            3105 :         if (!sourceElement(next, &child) || !elts.append(child))
    3089               0 :             return false;
    3090                 :     }
    3091                 : 
    3092            2313 :     return builder.blockStatement(elts, pos, dst);
    3093                 : }
    3094                 : 
    3095                 : } /* namespace js */
    3096                 : 
    3097                 : static JSBool
    3098            2278 : reflect_parse(JSContext *cx, uint32_t argc, jsval *vp)
    3099                 : {
    3100            2278 :     if (argc < 1) {
    3101                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
    3102               0 :                              "Reflect.parse", "0", "s");
    3103               0 :         return JS_FALSE;
    3104                 :     }
    3105                 : 
    3106            2278 :     JSString *src = ToString(cx, JS_ARGV(cx, vp)[0]);
    3107            2278 :     if (!src)
    3108               0 :         return JS_FALSE;
    3109                 : 
    3110            2278 :     char *filename = NULL;
    3111            4556 :     AutoReleaseNullablePtr filenamep(cx, filename);
    3112            2278 :     uint32_t lineno = 1;
    3113            2278 :     bool loc = true;
    3114                 : 
    3115            2278 :     JSObject *builder = NULL;
    3116                 : 
    3117            2278 :     Value arg = argc > 1 ? JS_ARGV(cx, vp)[1] : UndefinedValue();
    3118                 : 
    3119            2278 :     if (!arg.isNullOrUndefined()) {
    3120               0 :         if (!arg.isObject()) {
    3121                 :             js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
    3122               0 :                                      JSDVG_SEARCH_STACK, arg, NULL, "not an object", NULL);
    3123               0 :             return JS_FALSE;
    3124                 :         }
    3125                 : 
    3126               0 :         JSObject *config = &arg.toObject();
    3127                 : 
    3128                 :         Value prop;
    3129                 : 
    3130                 :         /* config.loc */
    3131               0 :         if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.locAtom),
    3132               0 :                                 BooleanValue(true), &prop)) {
    3133               0 :             return JS_FALSE;
    3134                 :         }
    3135                 : 
    3136               0 :         loc = js_ValueToBoolean(prop);
    3137                 : 
    3138               0 :         if (loc) {
    3139                 :             /* config.source */
    3140               0 :             if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.sourceAtom),
    3141               0 :                                     NullValue(), &prop)) {
    3142               0 :                 return JS_FALSE;
    3143                 :             }
    3144                 : 
    3145               0 :             if (!prop.isNullOrUndefined()) {
    3146               0 :                 JSString *str = ToString(cx, prop);
    3147               0 :                 if (!str)
    3148               0 :                     return JS_FALSE;
    3149                 : 
    3150               0 :                 size_t length = str->length();
    3151               0 :                 const jschar *chars = str->getChars(cx);
    3152               0 :                 if (!chars)
    3153               0 :                     return JS_FALSE;
    3154                 : 
    3155               0 :                 filename = DeflateString(cx, chars, length);
    3156               0 :                 if (!filename)
    3157               0 :                     return JS_FALSE;
    3158               0 :                 filenamep.reset(filename);
    3159                 :             }
    3160                 : 
    3161                 :             /* config.line */
    3162               0 :             if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.lineAtom),
    3163               0 :                                     Int32Value(1), &prop) ||
    3164               0 :                 !ToUint32(cx, prop, &lineno)) {
    3165               0 :                 return JS_FALSE;
    3166                 :             }
    3167                 :         }
    3168                 : 
    3169                 :         /* config.builder */
    3170               0 :         if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.builderAtom),
    3171               0 :                                 NullValue(), &prop)) {
    3172               0 :             return JS_FALSE;
    3173                 :         }
    3174                 : 
    3175               0 :         if (!prop.isNullOrUndefined()) {
    3176               0 :             if (!prop.isObject()) {
    3177                 :                 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
    3178               0 :                                          JSDVG_SEARCH_STACK, prop, NULL, "not an object", NULL);
    3179               0 :                 return JS_FALSE;
    3180                 :             }
    3181               0 :             builder = &prop.toObject();
    3182                 :         }
    3183                 :     }
    3184                 : 
    3185                 :     /* Extract the builder methods first to report errors before parsing. */
    3186            2278 :     ASTSerializer serialize(cx, loc, filename, lineno);
    3187            2278 :     if (!serialize.init(builder))
    3188               0 :         return JS_FALSE;
    3189                 : 
    3190            2278 :     size_t length = src->length();
    3191            2278 :     const jschar *chars = src->getChars(cx);
    3192            2278 :     if (!chars)
    3193               0 :         return JS_FALSE;
    3194                 : 
    3195            4556 :     Parser parser(cx, NULL, NULL, NULL, false);
    3196                 : 
    3197            2278 :     if (!parser.init(chars, length, filename, lineno, cx->findVersion()))
    3198               0 :         return JS_FALSE;
    3199                 : 
    3200            2278 :     serialize.setParser(&parser);
    3201                 : 
    3202            2278 :     ParseNode *pn = parser.parse(NULL);
    3203            2278 :     if (!pn)
    3204               0 :         return JS_FALSE;
    3205                 : 
    3206                 :     Value val;
    3207            2278 :     if (!serialize.program(pn, &val)) {
    3208               0 :         JS_SET_RVAL(cx, vp, JSVAL_NULL);
    3209               0 :         return JS_FALSE;
    3210                 :     }
    3211                 : 
    3212            2278 :     JS_SET_RVAL(cx, vp, val);
    3213            2278 :     return JS_TRUE;
    3214                 : }
    3215                 : 
    3216                 : static JSFunctionSpec static_methods[] = {
    3217                 :     JS_FN("parse", reflect_parse, 1, 0),
    3218                 :     JS_FS_END
    3219                 : };
    3220                 : 
    3221                 : 
    3222                 : JS_BEGIN_EXTERN_C
    3223                 : 
    3224                 : JS_PUBLIC_API(JSObject *)
    3225           24211 : JS_InitReflect(JSContext *cx, JSObject *obj)
    3226                 : {
    3227           48422 :     RootObject root(cx, &obj);
    3228           48422 :     RootedVarObject Reflect(cx);
    3229                 : 
    3230           24211 :     Reflect = NewObjectWithClassProto(cx, &ObjectClass, NULL, obj);
    3231           24211 :     if (!Reflect || !Reflect->setSingletonType(cx))
    3232               0 :         return NULL;
    3233                 : 
    3234           48422 :     if (!JS_DefineProperty(cx, obj, "Reflect", OBJECT_TO_JSVAL(Reflect),
    3235           24211 :                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
    3236               0 :         return NULL;
    3237                 :     }
    3238                 : 
    3239           24211 :     if (!JS_DefineFunctions(cx, Reflect, static_methods))
    3240               0 :         return NULL;
    3241                 : 
    3242           24211 :     return Reflect;
    3243                 : }
    3244                 : 
    3245                 : JS_END_EXTERN_C

Generated by: LCOV version 1.7