LCOV - app.info - js/src/jsreflect.cpp

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-04-07 | 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            2367 :     NodeBuilder(JSContext *c, bool l, char const *s)
         179            2367 :         : cx(c), saveLoc(l), src(s) {
         180            2367 :     }
         181                 :
         182            2367 :     bool init(JSObject *userobj = NULL) {
         183            2367 :         if (src) {
         184               0 :             if (!atomValue(src, &srcval))
         185               0 :                 return false;
         186                 :         } else {
         187            2367 :             srcval.setNull();
         188                 :         }
         189                 :
         190            2367 :         if (!userobj) {
         191            2367 :             userv.setNull();
         192          165690 :             for (unsigned i = 0; i < AST_LIMIT; i++) {
         193          163323 :                 callbacks[i].setNull();
         194                 :             }
         195            2367 :             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           50211 :     bool atomValue(const char *s, Value *dst) {
         311                 :         /*
         312                 :          * Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
         313                 :          */
         314           50211 :         JSAtom *atom = js_Atomize(cx, s, strlen(s));
         315           50211 :         if (!atom)
         316               0 :             return false;
         317                 :
         318           50211 :         dst->setString(atom);
         319           50211 :         return true;
         320                 :     }
         321                 :
         322          132165 :     bool newObject(JSObject **dst) {
         323          132165 :         JSObject *nobj = NewBuiltinClassInstance(cx, &ObjectClass);
         324          132165 :         if (!nobj)
         325               0 :             return false;
         326                 :
         327          132165 :         *dst = nobj;
         328          132165 :         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           33516 :     bool newNode(ASTType type, TokenPos *pos, const char *childName, Value child, Value *dst) {
         342                 :         JSObject *node;
         343           33516 :         return newNode(type, pos, &node) &&
         344           33516 :                setProperty(node, childName, child) &&
         345           67032 :                setResult(node, dst);
         346                 :     }
         347                 :
         348            6795 :     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            6795 :         return newNode(type, pos, &node) &&
         354            6795 :                setProperty(node, childName1, child1) &&
         355            6795 :                setProperty(node, childName2, child2) &&
         356           20385 :                setResult(node, dst);
         357                 :     }
         358                 :
         359            3249 :     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            3249 :         return newNode(type, pos, &node) &&
         366            3249 :                setProperty(node, childName1, child1) &&
         367            3249 :                setProperty(node, childName2, child2) &&
         368            3249 :                setProperty(node, childName3, child3) &&
         369           12996 :                setResult(node, dst);
         370                 :     }
         371                 :
         372             576 :     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             576 :         return newNode(type, pos, &node) &&
         380             576 :                setProperty(node, childName1, child1) &&
         381             576 :                setProperty(node, childName2, child2) &&
         382             576 :                setProperty(node, childName3, child3) &&
         383             576 :                setProperty(node, childName4, child4) &&
         384            2880 :                setResult(node, dst);
         385                 :     }
         386                 :
         387            2403 :     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            2403 :         return newNode(type, pos, &node) &&
         396            2403 :                setProperty(node, childName1, child1) &&
         397            2403 :                setProperty(node, childName2, child2) &&
         398            2403 :                setProperty(node, childName3, child3) &&
         399            2403 :                setProperty(node, childName4, child4) &&
         400            2403 :                setProperty(node, childName5, child5) &&
         401           14418 :                setResult(node, dst);
         402                 :     }
         403                 :
         404           10350 :     bool listNode(ASTType type, const char *propName, NodeVector &elts, TokenPos *pos, Value *dst) {
         405                 :         Value array;
         406           10350 :         if (!newArray(elts, &array))
         407               0 :             return false;
         408                 :
         409           10350 :         Value cb = callbacks[type];
         410           10350 :         if (!cb.isNull())
         411               0 :             return callback(cb, array, pos, dst);
         412                 :
         413           10350 :         return newNode(type, pos, propName, array, dst);
         414                 :     }
         415                 :
         416          472761 :     bool setProperty(JSObject *obj, const char *name, Value val) {
         417          472761 :         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          472761 :         if (val.isMagic(JS_SERIALIZE_NO_NODE))
         421            1674 :             val.setNull();
         422                 :
         423                 :         /*
         424                 :          * Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
         425                 :          */
         426          472761 :         JSAtom *atom = js_Atomize(cx, name, strlen(name));
         427          472761 :         if (!atom)
         428               0 :             return false;
         429                 :
         430          472761 :         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           46602 :     bool setResult(JSObject *obj, Value *dst) {
         438           46602 :         JS_ASSERT(obj);
         439           46602 :         dst->setObject(*obj);
         440           46602 :         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           46602 : NodeBuilder::newNode(ASTType type, TokenPos *pos, JSObject **dst)
         622                 : {
         623           46602 :     JS_ASSERT(type > AST_ERROR && type < AST_LIMIT);
         624                 :
         625                 :     Value tv;
         626                 :
         627           46602 :     JSObject *node = NewBuiltinClassInstance(cx, &ObjectClass);
         628          186408 :     if (!node ||
         629           46602 :         !setNodeLoc(node, pos) ||
         630           46602 :         !atomValue(nodeTypeNames[type], &tv) ||
         631           46602 :         !setProperty(node, "type", tv)) {
         632               0 :         return false;
         633                 :     }
         634                 :
         635           46602 :     *dst = node;
         636           46602 :     return true;
         637                 : }
         638                 :
         639                 : bool
         640           16578 : NodeBuilder::newArray(NodeVector &elts, Value *dst)
         641                 : {
         642           16578 :     const size_t len = elts.length();
         643                 :     if (len > UINT32_MAX) {
         644                 :         js_ReportAllocationOverflow(cx);
         645                 :         return false;
         646                 :     }
         647           16578 :     JSObject *array = NewDenseAllocatedArray(cx, uint32_t(len));
         648           16578 :     if (!array)
         649               0 :         return false;
         650                 :
         651           35523 :     for (size_t i = 0; i < len; i++) {
         652           18945 :         Value val = elts[i];
         653                 :
         654           18945 :         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           18945 :         if (val.isMagic(JS_SERIALIZE_NO_NODE))
         658             342 :             continue;
         659                 :
         660           18603 :         if (!array->setElement(cx, i, &val, false))
         661               0 :             return false;
         662                 :     }
         663                 :
         664           16578 :     dst->setObject(*array);
         665           16578 :     return true;
         666                 : }
         667                 :
         668                 : bool
         669           46602 : NodeBuilder::newNodeLoc(TokenPos *pos, Value *dst)
         670                 : {
         671           46602 :     if (!pos) {
         672            2547 :         dst->setNull();
         673            2547 :         return true;
         674                 :     }
         675                 :
         676                 :     JSObject *loc, *to;
         677                 :     Value tv;
         678                 :
         679           44055 :     if (!newObject(&loc))
         680               0 :         return false;
         681                 :
         682           44055 :     dst->setObject(*loc);
         683                 :
         684           44055 :     return newObject(&to) &&
         685           44055 :            setProperty(loc, "start", ObjectValue(*to)) &&
         686           44055 :            (tv.setNumber(pos->begin.lineno), true) &&
         687           44055 :            setProperty(to, "line", tv) &&
         688           44055 :            (tv.setNumber(pos->begin.index), true) &&
         689           44055 :            setProperty(to, "column", tv) &&
         690                 :
         691           44055 :            newObject(&to) &&
         692           44055 :            setProperty(loc, "end", ObjectValue(*to)) &&
         693           44055 :            (tv.setNumber(pos->end.lineno), true) &&
         694           44055 :            setProperty(to, "line", tv) &&
         695           44055 :            (tv.setNumber(pos->end.index), true) &&
         696           44055 :            setProperty(to, "column", tv) &&
         697                 :
         698          528660 :            setProperty(loc, "source", srcval);
         699                 : }
         700                 :
         701                 : bool
         702           46602 : NodeBuilder::setNodeLoc(JSObject *node, TokenPos *pos)
         703                 : {
         704           46602 :     if (!saveLoc) {
         705               0 :         setProperty(node, "loc", NullValue());
         706               0 :         return true;
         707                 :     }
         708                 :
         709                 :     Value loc;
         710           46602 :     return newNodeLoc(pos, &loc) &&
         711           46602 :            setProperty(node, "loc", loc);
         712                 : }
         713                 :
         714                 : bool
         715            2367 : NodeBuilder::program(NodeVector &elts, TokenPos *pos, Value *dst)
         716                 : {
         717            2367 :     return listNode(AST_PROGRAM, "body", elts, pos, dst);
         718                 : }
         719                 :
         720                 : bool
         721            4239 : NodeBuilder::blockStatement(NodeVector &elts, TokenPos *pos, Value *dst)
         722                 : {
         723            4239 :     return listNode(AST_BLOCK_STMT, "body", elts, pos, dst);
         724                 : }
         725                 :
         726                 : bool
         727            2745 : NodeBuilder::expressionStatement(Value expr, TokenPos *pos, Value *dst)
         728                 : {
         729            2745 :     Value cb = callbacks[AST_EXPR_STMT];
         730            2745 :     if (!cb.isNull())
         731               0 :         return callback(cb, expr, pos, dst);
         732                 :
         733            2745 :     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             441 : NodeBuilder::ifStatement(Value test, Value cons, Value alt, TokenPos *pos, Value *dst)
         748                 : {
         749             441 :     Value cb = callbacks[AST_IF_STMT];
         750             441 :     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             441 :                    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            2448 : NodeBuilder::returnStatement(Value arg, TokenPos *pos, Value *dst)
         805                 : {
         806            2448 :     Value cb = callbacks[AST_RETURN_STMT];
         807            2448 :     if (!cb.isNull())
         808               0 :         return callback(cb, opt(arg), pos, dst);
         809                 :
         810            2448 :     return newNode(AST_RETURN_STMT, pos, "argument", arg, dst);
         811                 : }
         812                 :
         813                 : bool
         814             333 : NodeBuilder::forStatement(Value init, Value test, Value update, Value stmt,
         815                 :                           TokenPos *pos, Value *dst)
         816                 : {
         817             333 :     Value cb = callbacks[AST_FOR_STMT];
         818             333 :     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             333 :                    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             144 : NodeBuilder::sequenceExpression(NodeVector &elts, TokenPos *pos, Value *dst)
        1047                 : {
        1048             144 :     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             585 : NodeBuilder::arrayExpression(NodeVector &elts, TokenPos *pos, Value *dst)
        1101                 : {
        1102             585 :     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             558 : NodeBuilder::letExpression(NodeVector &head, Value expr, TokenPos *pos, Value *dst)
        1225                 : {
        1226                 :     Value array;
        1227             558 :     if (!newArray(head, &array))
        1228               0 :         return false;
        1229                 :
        1230             558 :     Value cb = callbacks[AST_LET_EXPR];
        1231             558 :     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             558 :                    dst);
        1238                 : }
        1239                 :
        1240                 : bool
        1241             738 : NodeBuilder::letStatement(NodeVector &head, Value stmt, TokenPos *pos, Value *dst)
        1242                 : {
        1243                 :     Value array;
        1244             738 :     if (!newArray(head, &array))
        1245               0 :         return false;
        1246                 :
        1247             738 :     Value cb = callbacks[AST_LET_STMT];
        1248             738 :     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             738 :                    dst);
        1255                 : }
        1256                 :
        1257                 : bool
        1258            1467 : NodeBuilder::variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos, Value *dst)
        1259                 : {
        1260            1467 :     JS_ASSERT(kind > VARDECL_ERR && kind < VARDECL_LIMIT);
        1261                 :
        1262                 :     Value array, kindName;
        1263            2934 :     if (!newArray(elts, &array) ||
        1264                 :         !atomValue(kind == VARDECL_CONST
        1265                 :                    ? "const"
        1266                 :                    : kind == VARDECL_LET
        1267                 :                    ? "let"
        1268            1467 :                    : "var", &kindName)) {
        1269               0 :         return false;
        1270                 :     }
        1271                 :
        1272            1467 :     Value cb = callbacks[AST_VAR_DECL];
        1273            1467 :     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            1467 :                    dst);
        1280                 : }
        1281                 :
        1282                 : bool
        1283            3195 : NodeBuilder::variableDeclarator(Value id, Value init, TokenPos *pos, Value *dst)
        1284                 : {
        1285            3195 :     Value cb = callbacks[AST_VAR_DTOR];
        1286            3195 :     if (!cb.isNull())
        1287               0 :         return callback(cb, id, opt(init), pos, dst);
        1288                 :
        1289            3195 :     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            2277 : NodeBuilder::literal(Value val, TokenPos *pos, Value *dst)
        1325                 : {
        1326            2277 :     Value cb = callbacks[AST_LITERAL];
        1327            2277 :     if (!cb.isNull())
        1328               0 :         return callback(cb, val, pos, dst);
        1329                 :
        1330            2277 :     return newNode(AST_LITERAL, pos, "value", val, dst);
        1331                 : }
        1332                 :
        1333                 : bool
        1334           15597 : NodeBuilder::identifier(Value name, TokenPos *pos, Value *dst)
        1335                 : {
        1336           15597 :     Value cb = callbacks[AST_IDENTIFIER];
        1337           15597 :     if (!cb.isNull())
        1338               0 :         return callback(cb, name, pos, dst);
        1339                 :
        1340           15597 :     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            2448 : NodeBuilder::arrayPattern(NodeVector &elts, TokenPos *pos, Value *dst)
        1351                 : {
        1352            2448 :     return listNode(AST_ARRAY_PATT, "elements", elts, pos, dst);
        1353                 : }
        1354                 :
        1355                 : bool
        1356            2403 : 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            2403 :     if (!newArray(args, &array))
        1363               0 :         return false;
        1364                 :
        1365            2403 :     Value cb = callbacks[type];
        1366            2403 :     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            2403 :                    "generator", BooleanValue(isGenerator),
        1376            2403 :                    "expression", BooleanValue(isExpression),
        1377            4806 :                    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           15597 :     Value atomContents(JSAtom *atom) {
        1575           15597 :         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             576 :     bool optStatement(ParseNode *pn, Value *dst) {
        1597             576 :         if (!pn) {
        1598             576 :             dst->setMagic(JS_SERIALIZE_NO_NODE);
        1599             576 :             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            6318 :     bool optExpression(ParseNode *pn, Value *dst) {
        1613            6318 :         if (!pn) {
        1614             729 :             dst->setMagic(JS_SERIALIZE_NO_NODE);
        1615             729 :             return true;
        1616                 :         }
        1617            5589 :         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            2475 :     bool optIdentifier(JSAtom *atom, TokenPos *pos, Value *dst) {
        1626            2475 :         if (!atom) {
        1627              90 :             dst->setMagic(JS_SERIALIZE_NO_NODE);
        1628              90 :             return true;
        1629                 :         }
        1630            2385 :         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            2367 :     ASTSerializer(JSContext *c, bool l, char const *src, uint32_t ln)
        1653            2367 :         : cx(c), builder(c, l, src), lineno(ln) {
        1654            2367 :     }
        1655                 :
        1656            2367 :     bool init(JSObject *userobj) {
        1657            2367 :         return builder.init(userobj);
        1658                 :     }
        1659                 :
        1660            2367 :     void setParser(Parser *p) {
        1661            2367 :         parser = p;
        1662            2367 :     }
        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            4284 : ASTSerializer::statements(ParseNode *pn, NodeVector &elts)
        1780                 : {
        1781            4284 :     JS_ASSERT(pn->isKind(PNK_STATEMENTLIST));
        1782            4284 :     JS_ASSERT(pn->isArity(PN_LIST));
        1783                 :
        1784            4284 :     if (!elts.reserve(pn->pn_count))
        1785               0 :         return false;
        1786                 :
        1787            9252 :     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
        1788                 :         Value elt;
        1789            4968 :         if (!sourceElement(next, &elt))
        1790               0 :             return false;
        1791            4968 :         elts.infallibleAppend(elt);
        1792                 :     }
        1793                 :
        1794            4284 :     return true;
        1795                 : }
        1796                 :
        1797                 : bool
        1798             144 : ASTSerializer::expressions(ParseNode *pn, NodeVector &elts)
        1799                 : {
        1800             144 :     if (!elts.reserve(pn->pn_count))
        1801               0 :         return false;
        1802                 :
        1803             522 :     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
        1804                 :         Value elt;
        1805             378 :         if (!expression(next, &elt))
        1806               0 :             return false;
        1807             378 :         elts.infallibleAppend(elt);
        1808                 :     }
        1809                 :
        1810             144 :     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            1836 : ASTSerializer::blockStatement(ParseNode *pn, Value *dst)
        1831                 : {
        1832            1836 :     JS_ASSERT(pn->isKind(PNK_STATEMENTLIST));
        1833                 :
        1834            3672 :     NodeVector stmts(cx);
        1835            1836 :     return statements(pn, stmts) &&
        1836            1836 :            builder.blockStatement(stmts, &pn->pn_pos, dst);
        1837                 : }
        1838                 :
        1839                 : bool
        1840            2367 : ASTSerializer::program(ParseNode *pn, Value *dst)
        1841                 : {
        1842            2367 :     JS_ASSERT(pn->pn_pos.begin.lineno == lineno);
        1843                 :
        1844            4734 :     NodeVector stmts(cx);
        1845            2367 :     return statements(pn, stmts) &&
        1846            2367 :            builder.program(stmts, &pn->pn_pos, dst);
        1847                 : }
        1848                 :
        1849                 : bool
        1850            8181 : ASTSerializer::sourceElement(ParseNode *pn, Value *dst)
        1851                 : {
        1852                 :     /* SpiderMonkey allows declarations even in pure statement contexts. */
        1853            8181 :     return statement(pn, dst);
        1854                 : }
        1855                 :
        1856                 : bool
        1857            1143 : ASTSerializer::declaration(ParseNode *pn, Value *dst)
        1858                 : {
        1859            2871 :     JS_ASSERT(pn->isKind(PNK_FUNCTION) ||
        1860                 :               pn->isKind(PNK_VAR) ||
        1861                 :               pn->isKind(PNK_LET) ||
        1862            2871 :               pn->isKind(PNK_CONST));
        1863                 :
        1864            1143 :     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             522 :         return variableDeclaration(pn, false, dst);
        1871                 :
        1872                 :       default:
        1873             603 :         JS_ASSERT(pn->isKind(PNK_LET));
        1874             603 :         return variableDeclaration(pn, true, dst);
        1875                 :     }
        1876                 : }
        1877                 :
        1878                 : bool
        1879            1467 : ASTSerializer::variableDeclaration(ParseNode *pn, bool let, Value *dst)
        1880                 : {
        1881            1467 :     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            1467 :     VarDeclKind kind = let ? VARDECL_LET : VARDECL_VAR;
        1885                 :
        1886            2934 :     NodeVector dtors(cx);
        1887                 :
        1888                 :     /* In a for-in context, variable declarations contain just a single pattern. */
        1889            1467 :     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            1233 :     if (!dtors.reserve(pn->pn_count))
        1898               0 :         return false;
        1899            2700 :     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
        1900                 :         Value child;
        1901            1467 :         if (!variableDeclarator(next, &kind, &child))
        1902               0 :             return false;
        1903            1467 :         dtors.infallibleAppend(child);
        1904                 :     }
        1905                 :
        1906            1233 :     return builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
        1907                 : }
        1908                 :
        1909                 : bool
        1910            2961 : ASTSerializer::variableDeclarator(ParseNode *pn, VarDeclKind *pkind, Value *dst)
        1911                 : {
        1912                 :     /* A destructuring declarator is always a PNK_ASSIGN. */
        1913            2961 :     JS_ASSERT(pn->isKind(PNK_NAME) || pn->isKind(PNK_ASSIGN));
        1914                 :
        1915                 :     ParseNode *pnleft;
        1916                 :     ParseNode *pnright;
        1917                 :
        1918            2961 :     if (pn->isKind(PNK_NAME)) {
        1919            1647 :         pnleft = pn;
        1920            1647 :         pnright = pn->isUsed() ? NULL : pn->pn_expr;
        1921                 :     } else {
        1922            1314 :         JS_ASSERT(pn->isKind(PNK_ASSIGN));
        1923            1314 :         pnleft = pn->pn_left;
        1924            1314 :         pnright = pn->pn_right;
        1925                 :     }
        1926                 :
        1927                 :     Value left, right;
        1928            2961 :     return pattern(pnleft, pkind, &left) &&
        1929            2961 :            optExpression(pnright, &right) &&
        1930            5922 :            builder.variableDeclarator(left, right, &pn->pn_pos, dst);
        1931                 : }
        1932                 :
        1933                 : bool
        1934            1296 : ASTSerializer::let(ParseNode *pn, bool expr, Value *dst)
        1935                 : {
        1936            1296 :     ParseNode *letHead = pn->pn_left;
        1937            1296 :     LOCAL_ASSERT(letHead->isArity(PN_LIST));
        1938                 :
        1939            1296 :     ParseNode *letBody = pn->pn_right;
        1940            1296 :     LOCAL_ASSERT(letBody->isKind(PNK_LEXICALSCOPE));
        1941                 :
        1942            2592 :     NodeVector dtors(cx);
        1943            1296 :     if (!dtors.reserve(letHead->pn_count))
        1944               0 :         return false;
        1945                 :
        1946            1296 :     VarDeclKind kind = VARDECL_LET_HEAD;
        1947                 :
        1948            2790 :     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            1494 :         if (!variableDeclarator(next, &kind, &child))
        1955               0 :             return false;
        1956            1494 :         dtors.infallibleAppend(child);
        1957                 :     }
        1958                 :
        1959                 :     Value v;
        1960                 :     return expr
        1961             558 :            ? expression(letBody->pn_expr, &v) &&
        1962             558 :              builder.letExpression(dtors, v, &pn->pn_pos, dst)
        1963             738 :            : statement(letBody->pn_expr, &v) &&
        1964            3150 :              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             333 : ASTSerializer::forInit(ParseNode *pn, Value *dst)
        2053                 : {
        2054             333 :     if (!pn) {
        2055             207 :         dst->setMagic(JS_SERIALIZE_NO_NODE);
        2056             207 :         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           10224 : ASTSerializer::statement(ParseNode *pn, Value *dst)
        2066                 : {
        2067           10224 :     JS_CHECK_RECURSION(cx, return false);
        2068           10224 :     switch (pn->getKind()) {
        2069                 :       case PNK_FUNCTION:
        2070                 :       case PNK_VAR:
        2071                 :       case PNK_CONST:
        2072             540 :         return declaration(pn, dst);
        2073                 :
        2074                 :       case PNK_LET:
        2075            1341 :         return pn->isArity(PN_BINARY)
        2076                 :                ? let(pn, false, dst)
        2077            1341 :                : 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            2754 :         if (pn->pn_kid) {
        2085                 :             Value expr;
        2086            2745 :             return expression(pn->pn_kid, &expr) &&
        2087            2745 :                    builder.expressionStatement(expr, &pn->pn_pos, dst);
        2088                 :         }
        2089               9 :         return builder.emptyStatement(&pn->pn_pos, dst);
        2090                 :
        2091                 :       case PNK_LEXICALSCOPE:
        2092             504 :         pn = pn->pn_expr;
        2093             504 :         if (!pn->isKind(PNK_STATEMENTLIST))
        2094               0 :             return statement(pn, dst);
        2095                 :         /* FALL THROUGH */
        2096                 :
        2097                 :       case PNK_STATEMENTLIST:
        2098            1836 :         return blockStatement(pn, dst);
        2099                 :
        2100                 :       case PNK_IF:
        2101                 :       {
        2102                 :         Value test, cons, alt;
        2103                 :
        2104             441 :         return expression(pn->pn_kid1, &test) &&
        2105             441 :                statement(pn->pn_kid2, &cons) &&
        2106             441 :                optStatement(pn->pn_kid3, &alt) &&
        2107            1323 :                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             576 :         ParseNode *head = pn->pn_left;
        2140                 :
        2141                 :         Value stmt;
        2142             576 :         if (!statement(pn->pn_right, &stmt))
        2143               0 :             return false;
        2144                 :
        2145             576 :         bool isForEach = pn->pn_iflags & JSITER_FOREACH;
        2146                 :
        2147             576 :         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             333 :         return forInit(head->pn_kid1, &init) &&
        2162             333 :                optExpression(head->pn_kid2, &test) &&
        2163             333 :                optExpression(head->pn_kid3, &update) &&
        2164             999 :                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            2475 :         return optExpression(pn->pn_kid, &arg) &&
        2219            2475 :                (pn->isKind(PNK_THROW)
        2220              27 :                 ? builder.throwStatement(arg, &pn->pn_pos, dst)
        2221            4977 :                 : 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           18603 : ASTSerializer::expression(ParseNode *pn, Value *dst)
        2368                 : {
        2369           18603 :     JS_CHECK_RECURSION(cx, return false);
        2370           18603 :     switch (pn->getKind()) {
        2371                 :       case PNK_FUNCTION:
        2372            2385 :         return function(pn, AST_FUNC_EXPR, dst);
        2373                 :
        2374                 :       case PNK_COMMA:
        2375                 :       {
        2376             288 :         NodeVector exprs(cx);
        2377             144 :         return expressions(pn, exprs) &&
        2378             144 :                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            1170 :         NodeVector elts(cx);
        2540             585 :         if (!elts.reserve(pn->pn_count))
        2541               0 :             return false;
        2542                 :
        2543            1350 :         for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
        2544             765 :             if (next->isKind(PNK_COMMA)) {
        2545               0 :                 elts.infallibleAppend(MagicValue(JS_SERIALIZE_NO_NODE));
        2546                 :             } else {
        2547                 :                 Value expr;
        2548             765 :                 if (!expression(next, &expr))
        2549               0 :                     return false;
        2550             765 :                 elts.infallibleAppend(expr);
        2551                 :             }
        2552                 :         }
        2553                 :
        2554             585 :         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           10098 :         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            2205 :         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             558 :         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            2277 : ASTSerializer::literal(ParseNode *pn, Value *dst)
        2810                 : {
        2811                 :     Value val;
        2812            2277 :     switch (pn->getKind()) {
        2813                 :       case PNK_STRING:
        2814             900 :         val.setString(pn->pn_atom);
        2815             900 :         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            1368 :         val.setNumber(pn->pn_dval);
        2836            1368 :         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            2277 :     return builder.literal(val, &pn->pn_pos, dst);
        2855                 : }
        2856                 :
        2857                 : bool
        2858            2448 : ASTSerializer::arrayPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst)
        2859                 : {
        2860            2448 :     JS_ASSERT(pn->isKind(PNK_RB));
        2861                 :
        2862            4896 :     NodeVector elts(cx);
        2863            2448 :     if (!elts.reserve(pn->pn_count))
        2864               0 :         return false;
        2865                 :
        2866            4932 :     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
        2867            2484 :         if (next->isKind(PNK_COMMA)) {
        2868             342 :             elts.infallibleAppend(MagicValue(JS_SERIALIZE_NO_NODE));
        2869                 :         } else {
        2870                 :             Value patt;
        2871            2142 :             if (!pattern(next, pkind, &patt))
        2872               0 :                 return false;
        2873            2142 :             elts.infallibleAppend(patt);
        2874                 :         }
        2875                 :     }
        2876                 :
        2877            2448 :     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            6399 : ASTSerializer::pattern(ParseNode *pn, VarDeclKind *pkind, Value *dst)
        2907                 : {
        2908            6399 :     JS_CHECK_RECURSION(cx, return false);
        2909            6399 :     switch (pn->getKind()) {
        2910                 :       case PNK_RC:
        2911             441 :         return objectPattern(pn, pkind, dst);
        2912                 :
        2913                 :       case PNK_RB:
        2914            2448 :         return arrayPattern(pn, pkind, dst);
        2915                 :
        2916                 :       case PNK_NAME:
        2917            3474 :         if (pkind && (pn->pn_dflags & PND_CONST))
        2918               0 :             *pkind = VARDECL_CONST;
        2919                 :         /* FALL THROUGH */
        2920                 :
        2921                 :       default:
        2922            3510 :         return expression(pn, dst);
        2923                 :     }
        2924                 : }
        2925                 :
        2926                 : bool
        2927           15597 : ASTSerializer::identifier(JSAtom *atom, TokenPos *pos, Value *dst)
        2928                 : {
        2929           15597 :     return builder.identifier(atomContents(atom), pos, dst);
        2930                 : }
        2931                 :
        2932                 : bool
        2933           13050 : ASTSerializer::identifier(ParseNode *pn, Value *dst)
        2934                 : {
        2935           13050 :     LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_NULLARY));
        2936           13050 :     LOCAL_ASSERT(pn->pn_atom);
        2937                 :
        2938           13050 :     return identifier(pn->pn_atom, &pn->pn_pos, dst);
        2939                 : }
        2940                 :
        2941                 : bool
        2942            2403 : ASTSerializer::function(ParseNode *pn, ASTType type, Value *dst)
        2943                 : {
        2944            2403 :     JSFunction *func = (JSFunction *)pn->pn_funbox->object;
        2945                 :
        2946                 :     bool isGenerator =
        2947                 : #ifdef JS_HAS_GENERATORS
        2948            2403 :         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            2403 :         func->flags & JSFUN_EXPR_CLOSURE;
        2956                 : #else
        2957                 :         false;
        2958                 : #endif
        2959                 :
        2960                 :     Value id;
        2961            2403 :     if (!optIdentifier(func->atom, NULL, &id))
        2962               0 :         return false;
        2963                 :
        2964            4806 :     NodeVector args(cx);
        2965                 :
        2966            2403 :     ParseNode *argsAndBody = pn->pn_body->isKind(PNK_UPVARS)
        2967                 :                              ? pn->pn_body->pn_tree
        2968            2403 :                              : pn->pn_body;
        2969                 :
        2970                 :     Value body;
        2971            2403 :     return functionArgsAndBody(argsAndBody, args, &body) &&
        2972            2403 :            builder.function(type, &pn->pn_pos, id, args, body, isGenerator, isExpression, dst);
        2973                 : }
        2974                 :
        2975                 : bool
        2976            2403 : ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, Value *body)
        2977                 : {
        2978                 :     ParseNode *pnargs;
        2979                 :     ParseNode *pnbody;
        2980                 :
        2981                 :     /* Extract the args and body separately. */
        2982            2403 :     if (pn->isKind(PNK_ARGSBODY)) {
        2983            2349 :         pnargs = pn;
        2984            2349 :         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            2403 :     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            2403 :         pndestruct = NULL;
        3002                 :     }
        3003                 :
        3004                 :     /* Serialize the arguments and body. */
        3005            2403 :     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            2403 :                                : pnbody->pn_head;
        3024                 :
        3025            2403 :         return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
        3026            2403 :                functionBody(pnstart, &pnbody->pn_pos, body);
        3027                 :       }
        3028                 :
        3029                 :       default:
        3030               0 :         LOCAL_NOT_REACHED("unexpected function contents");
        3031                 :     }
        3032                 : }
        3033                 :
        3034                 : bool
        3035            2403 : ASTSerializer::functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct,
        3036                 :                             ParseNode *pnbody, NodeVector &args)
        3037                 : {
        3038            2403 :     uint32_t i = 0;
        3039            2403 :     ParseNode *arg = pnargs ? pnargs->pn_head : NULL;
        3040            2403 :     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            7155 :     while ((arg && arg != pnbody) || destruct) {
        3052            2349 :         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            2349 :         } 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            2349 :             if (!identifier(arg, &node) || !args.append(node))
        3069               0 :                 return false;
        3070            2349 :             arg = arg->pn_next;
        3071                 :         } else {
        3072               0 :             LOCAL_NOT_REACHED("missing function argument");
        3073                 :         }
        3074            2349 :         ++i;
        3075                 :     }
        3076                 :
        3077            2403 :     return true;
        3078                 : }
        3079                 :
        3080                 : bool
        3081            2403 : ASTSerializer::functionBody(ParseNode *pn, TokenPos *pos, Value *dst)
        3082                 : {
        3083            4806 :     NodeVector elts(cx);
        3084                 :
        3085                 :     /* We aren't sure how many elements there are up front, so we'll check each append. */
        3086            5616 :     for (ParseNode *next = pn; next; next = next->pn_next) {
        3087                 :         Value child;
        3088            3213 :         if (!sourceElement(next, &child) || !elts.append(child))
        3089               0 :             return false;
        3090                 :     }
        3091                 :
        3092            2403 :     return builder.blockStatement(elts, pos, dst);
        3093                 : }
        3094                 :
        3095                 : } /* namespace js */
        3096                 :
        3097                 : static JSBool
        3098            2367 : reflect_parse(JSContext *cx, uint32_t argc, jsval *vp)
        3099                 : {
        3100            2367 :     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            2367 :     JSString *src = ToString(cx, JS_ARGV(cx, vp)[0]);
        3107            2367 :     if (!src)
        3108               0 :         return JS_FALSE;
        3109                 :
        3110            2367 :     char *filename = NULL;
        3111            4734 :     AutoReleaseNullablePtr filenamep(cx, filename);
        3112            2367 :     uint32_t lineno = 1;
        3113            2367 :     bool loc = true;
        3114                 :
        3115            2367 :     JSObject *builder = NULL;
        3116                 :
        3117            2367 :     Value arg = argc > 1 ? JS_ARGV(cx, vp)[1] : UndefinedValue();
        3118                 :
        3119            2367 :     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            2367 :     ASTSerializer serialize(cx, loc, filename, lineno);
        3187            2367 :     if (!serialize.init(builder))
        3188               0 :         return JS_FALSE;
        3189                 :
        3190            2367 :     size_t length = src->length();
        3191            2367 :     const jschar *chars = src->getChars(cx);
        3192            2367 :     if (!chars)
        3193               0 :         return JS_FALSE;
        3194                 :
        3195            4734 :     Parser parser(cx, NULL, NULL, NULL, false);
        3196                 :
        3197            2367 :     if (!parser.init(chars, length, filename, lineno, cx->findVersion()))
        3198               0 :         return JS_FALSE;
        3199                 :
        3200            2367 :     serialize.setParser(&parser);
        3201                 :
        3202            2367 :     ParseNode *pn = parser.parse(NULL);
        3203            2367 :     if (!pn)
        3204               0 :         return JS_FALSE;
        3205                 :
        3206                 :     Value val;
        3207            2367 :     if (!serialize.program(pn, &val)) {
        3208               0 :         JS_SET_RVAL(cx, vp, JSVAL_NULL);
        3209               0 :         return JS_FALSE;
        3210                 :     }
        3211                 :
        3212            2367 :     JS_SET_RVAL(cx, vp, val);
        3213            2367 :     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           23328 : JS_InitReflect(JSContext *cx, JSObject *obj)
        3226                 : {
        3227           46656 :     RootObject root(cx, &obj);
        3228           46656 :     RootedVarObject Reflect(cx);
        3229                 :
        3230           23328 :     Reflect = NewObjectWithClassProto(cx, &ObjectClass, NULL, obj);
        3231           23328 :     if (!Reflect || !Reflect->setSingletonType(cx))
        3232               0 :         return NULL;
        3233                 :
        3234           46656 :     if (!JS_DefineProperty(cx, obj, "Reflect", OBJECT_TO_JSVAL(Reflect),
        3235           23328 :                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
        3236               0 :         return NULL;
        3237                 :     }
        3238                 :
        3239           23328 :     if (!JS_DefineFunctions(cx, Reflect, static_methods))
        3240               0 :         return NULL;
        3241                 :
        3242           23328 :     return Reflect;
        3243                 : }
        3244                 :
        3245                 : JS_END_EXTERN_C

Generated by: LCOV version 1.7