js/src/jsreflect.cpp

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /* JS reflection package. */
     9 #include "jsreflect.h"
    11 #include "mozilla/ArrayUtils.h"
    12 #include "mozilla/DebugOnly.h"
    14 #include <stdlib.h>
    16 #include "jsarray.h"
    17 #include "jsatom.h"
    18 #include "jsobj.h"
    19 #include "jspubtd.h"
    21 #include "frontend/Parser.h"
    22 #include "frontend/TokenStream.h"
    23 #include "js/CharacterEncoding.h"
    24 #include "vm/RegExpObject.h"
    26 #include "jsobjinlines.h"
    28 #include "frontend/ParseNode-inl.h"
    30 using namespace js;
    31 using namespace js::frontend;
    33 using JS::AutoValueArray;
    34 using mozilla::ArrayLength;
    35 using mozilla::DebugOnly;
    37 char const * const js::aopNames[] = {
    38     "=",    /* AOP_ASSIGN */
    39     "+=",   /* AOP_PLUS */
    40     "-=",   /* AOP_MINUS */
    41     "*=",   /* AOP_STAR */
    42     "/=",   /* AOP_DIV */
    43     "%=",   /* AOP_MOD */
    44     "<<=",  /* AOP_LSH */
    45     ">>=",  /* AOP_RSH */
    46     ">>>=", /* AOP_URSH */
    47     "|=",   /* AOP_BITOR */
    48     "^=",   /* AOP_BITXOR */
    49     "&="    /* AOP_BITAND */
    50 };
    52 char const * const js::binopNames[] = {
    53     "==",         /* BINOP_EQ */
    54     "!=",         /* BINOP_NE */
    55     "===",        /* BINOP_STRICTEQ */
    56     "!==",        /* BINOP_STRICTNE */
    57     "<",          /* BINOP_LT */
    58     "<=",         /* BINOP_LE */
    59     ">",          /* BINOP_GT */
    60     ">=",         /* BINOP_GE */
    61     "<<",         /* BINOP_LSH */
    62     ">>",         /* BINOP_RSH */
    63     ">>>",        /* BINOP_URSH */
    64     "+",          /* BINOP_PLUS */
    65     "-",          /* BINOP_MINUS */
    66     "*",          /* BINOP_STAR */
    67     "/",          /* BINOP_DIV */
    68     "%",          /* BINOP_MOD */
    69     "|",          /* BINOP_BITOR */
    70     "^",          /* BINOP_BITXOR */
    71     "&",          /* BINOP_BITAND */
    72     "in",         /* BINOP_IN */
    73     "instanceof", /* BINOP_INSTANCEOF */
    74 };
    76 char const * const js::unopNames[] = {
    77     "delete",  /* UNOP_DELETE */
    78     "-",       /* UNOP_NEG */
    79     "+",       /* UNOP_POS */
    80     "!",       /* UNOP_NOT */
    81     "~",       /* UNOP_BITNOT */
    82     "typeof",  /* UNOP_TYPEOF */
    83     "void"     /* UNOP_VOID */
    84 };
    86 char const * const js::nodeTypeNames[] = {
    87 #define ASTDEF(ast, str, method) str,
    88 #include "jsast.tbl"
    89 #undef ASTDEF
    90     nullptr
    91 };
    93 static char const * const callbackNames[] = {
    94 #define ASTDEF(ast, str, method) method,
    95 #include "jsast.tbl"
    96 #undef ASTDEF
    97     nullptr
    98 };
   100 enum YieldKind { Delegating, NotDelegating };
   102 typedef AutoValueVector NodeVector;
   104 /*
   105  * ParseNode is a somewhat intricate data structure, and its invariants have
   106  * evolved, making it more likely that there could be a disconnect between the
   107  * parser and the AST serializer. We use these macros to check invariants on a
   108  * parse node and raise a dynamic error on failure.
   109  */
   110 #define LOCAL_ASSERT(expr)                                                                \
   111     JS_BEGIN_MACRO                                                                        \
   112         JS_ASSERT(expr);                                                                  \
   113         if (!(expr)) {                                                                    \
   114             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_PARSE_NODE);  \
   115             return false;                                                                 \
   116         }                                                                                 \
   117     JS_END_MACRO
   119 #define LOCAL_NOT_REACHED(expr)                                                           \
   120     JS_BEGIN_MACRO                                                                        \
   121         MOZ_ASSERT(false);                                                                \
   122         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_PARSE_NODE);      \
   123         return false;                                                                     \
   124     JS_END_MACRO
   126 namespace {
   128 /* Set 'result' to obj[id] if any such property exists, else defaultValue. */
   129 static bool
   130 GetPropertyDefault(JSContext *cx, HandleObject obj, HandleId id, HandleValue defaultValue,
   131                    MutableHandleValue result)
   132 {
   133     bool found;
   134     if (!JSObject::hasProperty(cx, obj, id, &found))
   135         return false;
   136     if (!found) {
   137         result.set(defaultValue);
   138         return true;
   139     }
   140     return JSObject::getGeneric(cx, obj, obj, id, result);
   141 }
   143 /*
   144  * Builder class that constructs JavaScript AST node objects. See:
   145  *
   146  *     https://developer.mozilla.org/en/SpiderMonkey/Parser_API
   147  *
   148  * Bug 569487: generalize builder interface
   149  */
   150 class NodeBuilder
   151 {
   152     typedef AutoValueArray<AST_LIMIT> CallbackArray;
   154     JSContext   *cx;
   155     TokenStream *tokenStream;
   156     bool        saveLoc;               /* save source location information?     */
   157     char const  *src;                  /* source filename or null               */
   158     RootedValue srcval;                /* source filename JS value or null      */
   159     CallbackArray callbacks;           /* user-specified callbacks              */
   160     RootedValue userv;                 /* user-specified builder object or null */
   162   public:
   163     NodeBuilder(JSContext *c, bool l, char const *s)
   164       : cx(c), tokenStream(nullptr), saveLoc(l), src(s), srcval(c), callbacks(cx),
   165           userv(c)
   166     {}
   168     bool init(HandleObject userobj = js::NullPtr()) {
   169         if (src) {
   170             if (!atomValue(src, &srcval))
   171                 return false;
   172         } else {
   173             srcval.setNull();
   174         }
   176         if (!userobj) {
   177             userv.setNull();
   178             for (unsigned i = 0; i < AST_LIMIT; i++) {
   179                 callbacks[i].setNull();
   180             }
   181             return true;
   182         }
   184         userv.setObject(*userobj);
   186         RootedValue nullVal(cx, NullValue());
   187         RootedValue funv(cx);
   188         for (unsigned i = 0; i < AST_LIMIT; i++) {
   189             const char *name = callbackNames[i];
   190             RootedAtom atom(cx, Atomize(cx, name, strlen(name)));
   191             if (!atom)
   192                 return false;
   193             RootedId id(cx, AtomToId(atom));
   194             if (!GetPropertyDefault(cx, userobj, id, nullVal, &funv))
   195                 return false;
   197             if (funv.isNullOrUndefined()) {
   198                 callbacks[i].setNull();
   199                 continue;
   200             }
   202             if (!funv.isObject() || !funv.toObject().is<JSFunction>()) {
   203                 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NOT_FUNCTION,
   204                                          JSDVG_SEARCH_STACK, funv, js::NullPtr(), nullptr, nullptr);
   205                 return false;
   206             }
   208             callbacks[i].set(funv);
   209         }
   211         return true;
   212     }
   214     void setTokenStream(TokenStream *ts) {
   215         tokenStream = ts;
   216     }
   218   private:
   219     bool callback(HandleValue fun, TokenPos *pos, MutableHandleValue dst) {
   220         if (saveLoc) {
   221             RootedValue loc(cx);
   222             if (!newNodeLoc(pos, &loc))
   223                 return false;
   224             AutoValueArray<1> argv(cx);
   225             argv[0].set(loc);
   226             return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
   227         }
   229         AutoValueArray<1> argv(cx);
   230         argv[0].setNull(); /* no zero-length arrays allowed! */
   231         return Invoke(cx, userv, fun, 0, argv.begin(), dst);
   232     }
   234     bool callback(HandleValue fun, HandleValue v1, TokenPos *pos, MutableHandleValue dst) {
   235         if (saveLoc) {
   236             RootedValue loc(cx);
   237             if (!newNodeLoc(pos, &loc))
   238                 return false;
   239             AutoValueArray<2> argv(cx);
   240             argv[0].set(v1);
   241             argv[1].set(loc);
   242             return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
   243         }
   245         AutoValueArray<1> argv(cx);
   246         argv[0].set(v1);
   247         return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
   248     }
   250     bool callback(HandleValue fun, HandleValue v1, HandleValue v2, TokenPos *pos,
   251                   MutableHandleValue dst) {
   252         if (saveLoc) {
   253             RootedValue loc(cx);
   254             if (!newNodeLoc(pos, &loc))
   255                 return false;
   256             AutoValueArray<3> argv(cx);
   257             argv[0].set(v1);
   258             argv[1].set(v2);
   259             argv[2].set(loc);
   260             return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
   261         }
   263         AutoValueArray<2> argv(cx);
   264         argv[0].set(v1);
   265         argv[1].set(v2);
   266         return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
   267     }
   269     bool callback(HandleValue fun, HandleValue v1, HandleValue v2, HandleValue v3, TokenPos *pos,
   270                   MutableHandleValue dst) {
   271         if (saveLoc) {
   272             RootedValue loc(cx);
   273             if (!newNodeLoc(pos, &loc))
   274                 return false;
   275             AutoValueArray<4> argv(cx);
   276             argv[0].set(v1);
   277             argv[1].set(v2);
   278             argv[2].set(v3);
   279             argv[3].set(loc);
   280             return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
   281         }
   283         AutoValueArray<3> argv(cx);
   284         argv[0].set(v1);
   285         argv[1].set(v2);
   286         argv[2].set(v3);
   287         return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
   288     }
   290     bool callback(HandleValue fun, HandleValue v1, HandleValue v2, HandleValue v3, HandleValue v4,
   291                   TokenPos *pos, MutableHandleValue dst) {
   292         if (saveLoc) {
   293             RootedValue loc(cx);
   294             if (!newNodeLoc(pos, &loc))
   295                 return false;
   296             AutoValueArray<5> argv(cx);
   297             argv[0].set(v1);
   298             argv[1].set(v2);
   299             argv[2].set(v3);
   300             argv[3].set(v4);
   301             argv[4].set(loc);
   302             return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
   303         }
   305         AutoValueArray<4> argv(cx);
   306         argv[0].set(v1);
   307         argv[1].set(v2);
   308         argv[2].set(v3);
   309         argv[3].set(v4);
   310         return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
   311     }
   313     bool callback(HandleValue fun, HandleValue v1, HandleValue v2, HandleValue v3, HandleValue v4,
   314                   HandleValue v5, TokenPos *pos, MutableHandleValue dst) {
   315         if (saveLoc) {
   316             RootedValue loc(cx);
   317             if (!newNodeLoc(pos, &loc))
   318                 return false;
   319             AutoValueArray<6> argv(cx);
   320             argv[0].set(v1);
   321             argv[1].set(v2);
   322             argv[2].set(v3);
   323             argv[3].set(v4);
   324             argv[4].set(v5);
   325             argv[5].set(loc);
   326             return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
   327         }
   329         AutoValueArray<5> argv(cx);
   330         argv[0].set(v1);
   331         argv[1].set(v2);
   332         argv[2].set(v3);
   333         argv[3].set(v4);
   334         argv[4].set(v5);
   335         return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
   336     }
   338     // WARNING: Returning a Handle is non-standard, but it works in this case
   339     // because both |v| and |UndefinedHandleValue| are definitely rooted on a
   340     // previous stack frame (i.e. we're just choosing between two
   341     // already-rooted values).
   342     HandleValue opt(HandleValue v) {
   343         JS_ASSERT_IF(v.isMagic(), v.whyMagic() == JS_SERIALIZE_NO_NODE);
   344         return v.isMagic(JS_SERIALIZE_NO_NODE) ? JS::UndefinedHandleValue : v;
   345     }
   347     bool atomValue(const char *s, MutableHandleValue dst) {
   348         /*
   349          * Bug 575416: instead of Atomize, lookup constant atoms in tbl file
   350          */
   351         RootedAtom atom(cx, Atomize(cx, s, strlen(s)));
   352         if (!atom)
   353             return false;
   355         dst.setString(atom);
   356         return true;
   357     }
   359     bool newObject(MutableHandleObject dst) {
   360         RootedObject nobj(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
   361         if (!nobj)
   362             return false;
   364         dst.set(nobj);
   365         return true;
   366     }
   368     bool newArray(NodeVector &elts, MutableHandleValue dst);
   370     bool newNode(ASTType type, TokenPos *pos, MutableHandleObject dst);
   372     bool newNode(ASTType type, TokenPos *pos, MutableHandleValue dst) {
   373         RootedObject node(cx);
   374         return newNode(type, pos, &node) &&
   375                setResult(node, dst);
   376     }
   378     bool newNode(ASTType type, TokenPos *pos,
   379                  const char *childName, HandleValue child,
   380                  MutableHandleValue dst) {
   381         RootedObject node(cx);
   382         return newNode(type, pos, &node) &&
   383                setProperty(node, childName, child) &&
   384                setResult(node, dst);
   385     }
   387     bool newNode(ASTType type, TokenPos *pos,
   388                  const char *childName1, HandleValue child1,
   389                  const char *childName2, HandleValue child2,
   390                  MutableHandleValue dst) {
   391         RootedObject node(cx);
   392         return newNode(type, pos, &node) &&
   393                setProperty(node, childName1, child1) &&
   394                setProperty(node, childName2, child2) &&
   395                setResult(node, dst);
   396     }
   398     bool newNode(ASTType type, TokenPos *pos,
   399                  const char *childName1, HandleValue child1,
   400                  const char *childName2, HandleValue child2,
   401                  const char *childName3, HandleValue child3,
   402                  MutableHandleValue dst) {
   403         RootedObject node(cx);
   404         return newNode(type, pos, &node) &&
   405                setProperty(node, childName1, child1) &&
   406                setProperty(node, childName2, child2) &&
   407                setProperty(node, childName3, child3) &&
   408                setResult(node, dst);
   409     }
   411     bool newNode(ASTType type, TokenPos *pos,
   412                  const char *childName1, HandleValue child1,
   413                  const char *childName2, HandleValue child2,
   414                  const char *childName3, HandleValue child3,
   415                  const char *childName4, HandleValue child4,
   416                  MutableHandleValue dst) {
   417         RootedObject node(cx);
   418         return newNode(type, pos, &node) &&
   419                setProperty(node, childName1, child1) &&
   420                setProperty(node, childName2, child2) &&
   421                setProperty(node, childName3, child3) &&
   422                setProperty(node, childName4, child4) &&
   423                setResult(node, dst);
   424     }
   426     bool newNode(ASTType type, TokenPos *pos,
   427                  const char *childName1, HandleValue child1,
   428                  const char *childName2, HandleValue child2,
   429                  const char *childName3, HandleValue child3,
   430                  const char *childName4, HandleValue child4,
   431                  const char *childName5, HandleValue child5,
   432                  MutableHandleValue dst) {
   433         RootedObject node(cx);
   434         return newNode(type, pos, &node) &&
   435                setProperty(node, childName1, child1) &&
   436                setProperty(node, childName2, child2) &&
   437                setProperty(node, childName3, child3) &&
   438                setProperty(node, childName4, child4) &&
   439                setProperty(node, childName5, child5) &&
   440                setResult(node, dst);
   441     }
   443     bool newNode(ASTType type, TokenPos *pos,
   444                  const char *childName1, HandleValue child1,
   445                  const char *childName2, HandleValue child2,
   446                  const char *childName3, HandleValue child3,
   447                  const char *childName4, HandleValue child4,
   448                  const char *childName5, HandleValue child5,
   449                  const char *childName6, HandleValue child6,
   450                  const char *childName7, HandleValue child7,
   451                  MutableHandleValue dst) {
   452         RootedObject node(cx);
   453         return newNode(type, pos, &node) &&
   454                setProperty(node, childName1, child1) &&
   455                setProperty(node, childName2, child2) &&
   456                setProperty(node, childName3, child3) &&
   457                setProperty(node, childName4, child4) &&
   458                setProperty(node, childName5, child5) &&
   459                setProperty(node, childName6, child6) &&
   460                setProperty(node, childName7, child7) &&
   461                setResult(node, dst);
   462     }
   464     bool listNode(ASTType type, const char *propName, NodeVector &elts, TokenPos *pos,
   465                   MutableHandleValue dst) {
   466         RootedValue array(cx);
   467         if (!newArray(elts, &array))
   468             return false;
   470         RootedValue cb(cx, callbacks[type]);
   471         if (!cb.isNull())
   472             return callback(cb, array, pos, dst);
   474         return newNode(type, pos, propName, array, dst);
   475     }
   477     bool setProperty(HandleObject obj, const char *name, HandleValue val) {
   478         JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
   480         /*
   481          * Bug 575416: instead of Atomize, lookup constant atoms in tbl file
   482          */
   483         RootedAtom atom(cx, Atomize(cx, name, strlen(name)));
   484         if (!atom)
   485             return false;
   487         /* Represent "no node" as null and ensure users are not exposed to magic values. */
   488         RootedValue optVal(cx, val.isMagic(JS_SERIALIZE_NO_NODE) ? NullValue() : val);
   489         return JSObject::defineProperty(cx, obj, atom->asPropertyName(), optVal);
   490     }
   492     bool newNodeLoc(TokenPos *pos, MutableHandleValue dst);
   494     bool setNodeLoc(HandleObject node, TokenPos *pos);
   496     bool setResult(HandleObject obj, MutableHandleValue dst) {
   497         JS_ASSERT(obj);
   498         dst.setObject(*obj);
   499         return true;
   500     }
   502   public:
   503     /*
   504      * All of the public builder methods take as their last two
   505      * arguments a nullable token position and a non-nullable, rooted
   506      * outparam.
   507      *
   508      * Any Value arguments representing optional subnodes may be a
   509      * JS_SERIALIZE_NO_NODE magic value.
   510      */
   512     /*
   513      * misc nodes
   514      */
   516     bool program(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
   518     bool literal(HandleValue val, TokenPos *pos, MutableHandleValue dst);
   520     bool identifier(HandleValue name, TokenPos *pos, MutableHandleValue dst);
   522     bool function(ASTType type, TokenPos *pos,
   523                   HandleValue id, NodeVector &args, NodeVector &defaults,
   524                   HandleValue body, HandleValue rest, bool isGenerator, bool isExpression,
   525                   MutableHandleValue dst);
   527     bool variableDeclarator(HandleValue id, HandleValue init, TokenPos *pos,
   528                             MutableHandleValue dst);
   530     bool switchCase(HandleValue expr, NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
   532     bool catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos *pos,
   533                      MutableHandleValue dst);
   535     bool propertyInitializer(HandleValue key, HandleValue val, PropKind kind, TokenPos *pos,
   536                              MutableHandleValue dst);
   539     /*
   540      * statements
   541      */
   543     bool blockStatement(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
   545     bool expressionStatement(HandleValue expr, TokenPos *pos, MutableHandleValue dst);
   547     bool emptyStatement(TokenPos *pos, MutableHandleValue dst);
   549     bool ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos *pos,
   550                      MutableHandleValue dst);
   552     bool breakStatement(HandleValue label, TokenPos *pos, MutableHandleValue dst);
   554     bool continueStatement(HandleValue label, TokenPos *pos, MutableHandleValue dst);
   556     bool labeledStatement(HandleValue label, HandleValue stmt, TokenPos *pos,
   557                           MutableHandleValue dst);
   559     bool throwStatement(HandleValue arg, TokenPos *pos, MutableHandleValue dst);
   561     bool returnStatement(HandleValue arg, TokenPos *pos, MutableHandleValue dst);
   563     bool forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt,
   564                       TokenPos *pos, MutableHandleValue dst);
   566     bool forInStatement(HandleValue var, HandleValue expr, HandleValue stmt,
   567                         bool isForEach, TokenPos *pos, MutableHandleValue dst);
   569     bool forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos *pos,
   570                         MutableHandleValue dst);
   572     bool withStatement(HandleValue expr, HandleValue stmt, TokenPos *pos, MutableHandleValue dst);
   574     bool whileStatement(HandleValue test, HandleValue stmt, TokenPos *pos, MutableHandleValue dst);
   576     bool doWhileStatement(HandleValue stmt, HandleValue test, TokenPos *pos,
   577                           MutableHandleValue dst);
   579     bool switchStatement(HandleValue disc, NodeVector &elts, bool lexical, TokenPos *pos,
   580                          MutableHandleValue dst);
   582     bool tryStatement(HandleValue body, NodeVector &guarded, HandleValue unguarded,
   583                       HandleValue finally, TokenPos *pos, MutableHandleValue dst);
   585     bool debuggerStatement(TokenPos *pos, MutableHandleValue dst);
   587     bool letStatement(NodeVector &head, HandleValue stmt, TokenPos *pos, MutableHandleValue dst);
   589     bool importDeclaration(NodeVector &elts, HandleValue moduleSpec, TokenPos *pos, MutableHandleValue dst);
   591     bool importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos *pos, MutableHandleValue dst);
   593     bool exportDeclaration(HandleValue decl, NodeVector &elts, HandleValue moduleSpec, TokenPos *pos, MutableHandleValue dst);
   595     bool exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos *pos, MutableHandleValue dst);
   597     bool exportBatchSpecifier(TokenPos *pos, MutableHandleValue dst);
   599     /*
   600      * expressions
   601      */
   603     bool binaryExpression(BinaryOperator op, HandleValue left, HandleValue right, TokenPos *pos,
   604                           MutableHandleValue dst);
   606     bool unaryExpression(UnaryOperator op, HandleValue expr, TokenPos *pos, MutableHandleValue dst);
   608     bool assignmentExpression(AssignmentOperator op, HandleValue lhs, HandleValue rhs,
   609                               TokenPos *pos, MutableHandleValue dst);
   611     bool updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos *pos,
   612                           MutableHandleValue dst);
   614     bool logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos *pos,
   615                            MutableHandleValue dst);
   617     bool conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt, TokenPos *pos,
   618                                MutableHandleValue dst);
   620     bool sequenceExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
   622     bool newExpression(HandleValue callee, NodeVector &args, TokenPos *pos, MutableHandleValue dst);
   624     bool callExpression(HandleValue callee, NodeVector &args, TokenPos *pos,
   625                         MutableHandleValue dst);
   627     bool memberExpression(bool computed, HandleValue expr, HandleValue member, TokenPos *pos,
   628                           MutableHandleValue dst);
   630     bool arrayExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
   632     bool spreadExpression(HandleValue expr, TokenPos *pos, MutableHandleValue dst);
   634     bool objectExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
   636     bool thisExpression(TokenPos *pos, MutableHandleValue dst);
   638     bool yieldExpression(HandleValue arg, YieldKind kind, TokenPos *pos, MutableHandleValue dst);
   640     bool comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach, bool isForOf, TokenPos *pos,
   641                             MutableHandleValue dst);
   643     bool comprehensionExpression(HandleValue body, NodeVector &blocks, HandleValue filter,
   644                                  TokenPos *pos, MutableHandleValue dst);
   646     bool generatorExpression(HandleValue body, NodeVector &blocks, HandleValue filter,
   647                              TokenPos *pos, MutableHandleValue dst);
   649     bool letExpression(NodeVector &head, HandleValue expr, TokenPos *pos, MutableHandleValue dst);
   651     /*
   652      * declarations
   653      */
   655     bool variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos,
   656                              MutableHandleValue dst);
   658     /*
   659      * patterns
   660      */
   662     bool arrayPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
   664     bool objectPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
   666     bool propertyPattern(HandleValue key, HandleValue patt, TokenPos *pos, MutableHandleValue dst);
   667 };
   669 } /* anonymous namespace */
   671 bool
   672 NodeBuilder::newNode(ASTType type, TokenPos *pos, MutableHandleObject dst)
   673 {
   674     JS_ASSERT(type > AST_ERROR && type < AST_LIMIT);
   676     RootedValue tv(cx);
   677     RootedObject node(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
   678     if (!node ||
   679         !setNodeLoc(node, pos) ||
   680         !atomValue(nodeTypeNames[type], &tv) ||
   681         !setProperty(node, "type", tv)) {
   682         return false;
   683     }
   685     dst.set(node);
   686     return true;
   687 }
   689 bool
   690 NodeBuilder::newArray(NodeVector &elts, MutableHandleValue dst)
   691 {
   692     const size_t len = elts.length();
   693     if (len > UINT32_MAX) {
   694         js_ReportAllocationOverflow(cx);
   695         return false;
   696     }
   697     RootedObject array(cx, NewDenseAllocatedArray(cx, uint32_t(len)));
   698     if (!array)
   699         return false;
   701     for (size_t i = 0; i < len; i++) {
   702         RootedValue val(cx, elts[i]);
   704         JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
   706         /* Represent "no node" as an array hole by not adding the value. */
   707         if (val.isMagic(JS_SERIALIZE_NO_NODE))
   708             continue;
   710         if (!JSObject::setElement(cx, array, array, i, &val, false))
   711             return false;
   712     }
   714     dst.setObject(*array);
   715     return true;
   716 }
   718 bool
   719 NodeBuilder::newNodeLoc(TokenPos *pos, MutableHandleValue dst)
   720 {
   721     if (!pos) {
   722         dst.setNull();
   723         return true;
   724     }
   726     RootedObject loc(cx);
   727     RootedObject to(cx);
   728     RootedValue val(cx);
   730     if (!newObject(&loc))
   731         return false;
   733     dst.setObject(*loc);
   735     uint32_t startLineNum, startColumnIndex;
   736     uint32_t endLineNum, endColumnIndex;
   737     tokenStream->srcCoords.lineNumAndColumnIndex(pos->begin, &startLineNum, &startColumnIndex);
   738     tokenStream->srcCoords.lineNumAndColumnIndex(pos->end, &endLineNum, &endColumnIndex);
   740     if (!newObject(&to))
   741         return false;
   742     val.setObject(*to);
   743     if (!setProperty(loc, "start", val))
   744         return false;
   745     val.setNumber(startLineNum);
   746     if (!setProperty(to, "line", val))
   747         return false;
   748     val.setNumber(startColumnIndex);
   749     if (!setProperty(to, "column", val))
   750         return false;
   752     if (!newObject(&to))
   753         return false;
   754     val.setObject(*to);
   755     if (!setProperty(loc, "end", val))
   756         return false;
   757     val.setNumber(endLineNum);
   758     if (!setProperty(to, "line", val))
   759         return false;
   760     val.setNumber(endColumnIndex);
   761     if (!setProperty(to, "column", val))
   762         return false;
   764     if (!setProperty(loc, "source", srcval))
   765         return false;
   767     return true;
   768 }
   770 bool
   771 NodeBuilder::setNodeLoc(HandleObject node, TokenPos *pos)
   772 {
   773     if (!saveLoc) {
   774         RootedValue nullVal(cx, NullValue());
   775         setProperty(node, "loc", nullVal);
   776         return true;
   777     }
   779     RootedValue loc(cx);
   780     return newNodeLoc(pos, &loc) &&
   781            setProperty(node, "loc", loc);
   782 }
   784 bool
   785 NodeBuilder::program(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
   786 {
   787     return listNode(AST_PROGRAM, "body", elts, pos, dst);
   788 }
   790 bool
   791 NodeBuilder::blockStatement(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
   792 {
   793     return listNode(AST_BLOCK_STMT, "body", elts, pos, dst);
   794 }
   796 bool
   797 NodeBuilder::expressionStatement(HandleValue expr, TokenPos *pos, MutableHandleValue dst)
   798 {
   799     RootedValue cb(cx, callbacks[AST_EXPR_STMT]);
   800     if (!cb.isNull())
   801         return callback(cb, expr, pos, dst);
   803     return newNode(AST_EXPR_STMT, pos, "expression", expr, dst);
   804 }
   806 bool
   807 NodeBuilder::emptyStatement(TokenPos *pos, MutableHandleValue dst)
   808 {
   809     RootedValue cb(cx, callbacks[AST_EMPTY_STMT]);
   810     if (!cb.isNull())
   811         return callback(cb, pos, dst);
   813     return newNode(AST_EMPTY_STMT, pos, dst);
   814 }
   816 bool
   817 NodeBuilder::ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos *pos,
   818                          MutableHandleValue dst)
   819 {
   820     RootedValue cb(cx, callbacks[AST_IF_STMT]);
   821     if (!cb.isNull())
   822         return callback(cb, test, cons, opt(alt), pos, dst);
   824     return newNode(AST_IF_STMT, pos,
   825                    "test", test,
   826                    "consequent", cons,
   827                    "alternate", alt,
   828                    dst);
   829 }
   831 bool
   832 NodeBuilder::breakStatement(HandleValue label, TokenPos *pos, MutableHandleValue dst)
   833 {
   834     RootedValue cb(cx, callbacks[AST_BREAK_STMT]);
   835     if (!cb.isNull())
   836         return callback(cb, opt(label), pos, dst);
   838     return newNode(AST_BREAK_STMT, pos, "label", label, dst);
   839 }
   841 bool
   842 NodeBuilder::continueStatement(HandleValue label, TokenPos *pos, MutableHandleValue dst)
   843 {
   844     RootedValue cb(cx, callbacks[AST_CONTINUE_STMT]);
   845     if (!cb.isNull())
   846         return callback(cb, opt(label), pos, dst);
   848     return newNode(AST_CONTINUE_STMT, pos, "label", label, dst);
   849 }
   851 bool
   852 NodeBuilder::labeledStatement(HandleValue label, HandleValue stmt, TokenPos *pos,
   853                               MutableHandleValue dst)
   854 {
   855     RootedValue cb(cx, callbacks[AST_LAB_STMT]);
   856     if (!cb.isNull())
   857         return callback(cb, label, stmt, pos, dst);
   859     return newNode(AST_LAB_STMT, pos,
   860                    "label", label,
   861                    "body", stmt,
   862                    dst);
   863 }
   865 bool
   866 NodeBuilder::throwStatement(HandleValue arg, TokenPos *pos, MutableHandleValue dst)
   867 {
   868     RootedValue cb(cx, callbacks[AST_THROW_STMT]);
   869     if (!cb.isNull())
   870         return callback(cb, arg, pos, dst);
   872     return newNode(AST_THROW_STMT, pos, "argument", arg, dst);
   873 }
   875 bool
   876 NodeBuilder::returnStatement(HandleValue arg, TokenPos *pos, MutableHandleValue dst)
   877 {
   878     RootedValue cb(cx, callbacks[AST_RETURN_STMT]);
   879     if (!cb.isNull())
   880         return callback(cb, opt(arg), pos, dst);
   882     return newNode(AST_RETURN_STMT, pos, "argument", arg, dst);
   883 }
   885 bool
   886 NodeBuilder::forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt,
   887                           TokenPos *pos, MutableHandleValue dst)
   888 {
   889     RootedValue cb(cx, callbacks[AST_FOR_STMT]);
   890     if (!cb.isNull())
   891         return callback(cb, opt(init), opt(test), opt(update), stmt, pos, dst);
   893     return newNode(AST_FOR_STMT, pos,
   894                    "init", init,
   895                    "test", test,
   896                    "update", update,
   897                    "body", stmt,
   898                    dst);
   899 }
   901 bool
   902 NodeBuilder::forInStatement(HandleValue var, HandleValue expr, HandleValue stmt, bool isForEach,
   903                             TokenPos *pos, MutableHandleValue dst)
   904 {
   905     RootedValue isForEachVal(cx, BooleanValue(isForEach));
   907     RootedValue cb(cx, callbacks[AST_FOR_IN_STMT]);
   908     if (!cb.isNull())
   909         return callback(cb, var, expr, stmt, isForEachVal, pos, dst);
   911     return newNode(AST_FOR_IN_STMT, pos,
   912                    "left", var,
   913                    "right", expr,
   914                    "body", stmt,
   915                    "each", isForEachVal,
   916                    dst);
   917 }
   919 bool
   920 NodeBuilder::forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos *pos,
   921                             MutableHandleValue dst)
   922 {
   923     RootedValue cb(cx, callbacks[AST_FOR_OF_STMT]);
   924     if (!cb.isNull())
   925         return callback(cb, var, expr, stmt, pos, dst);
   927     return newNode(AST_FOR_OF_STMT, pos,
   928                    "left", var,
   929                    "right", expr,
   930                    "body", stmt,
   931                    dst);
   932 }
   934 bool
   935 NodeBuilder::withStatement(HandleValue expr, HandleValue stmt, TokenPos *pos,
   936                            MutableHandleValue dst)
   937 {
   938     RootedValue cb(cx, callbacks[AST_WITH_STMT]);
   939     if (!cb.isNull())
   940         return callback(cb, expr, stmt, pos, dst);
   942     return newNode(AST_WITH_STMT, pos,
   943                    "object", expr,
   944                    "body", stmt,
   945                    dst);
   946 }
   948 bool
   949 NodeBuilder::whileStatement(HandleValue test, HandleValue stmt, TokenPos *pos,
   950                             MutableHandleValue dst)
   951 {
   952     RootedValue cb(cx, callbacks[AST_WHILE_STMT]);
   953     if (!cb.isNull())
   954         return callback(cb, test, stmt, pos, dst);
   956     return newNode(AST_WHILE_STMT, pos,
   957                    "test", test,
   958                    "body", stmt,
   959                    dst);
   960 }
   962 bool
   963 NodeBuilder::doWhileStatement(HandleValue stmt, HandleValue test, TokenPos *pos,
   964                               MutableHandleValue dst)
   965 {
   966     RootedValue cb(cx, callbacks[AST_DO_STMT]);
   967     if (!cb.isNull())
   968         return callback(cb, stmt, test, pos, dst);
   970     return newNode(AST_DO_STMT, pos,
   971                    "body", stmt,
   972                    "test", test,
   973                    dst);
   974 }
   976 bool
   977 NodeBuilder::switchStatement(HandleValue disc, NodeVector &elts, bool lexical, TokenPos *pos,
   978                              MutableHandleValue dst)
   979 {
   980     RootedValue array(cx);
   981     if (!newArray(elts, &array))
   982         return false;
   984     RootedValue lexicalVal(cx, BooleanValue(lexical));
   986     RootedValue cb(cx, callbacks[AST_SWITCH_STMT]);
   987     if (!cb.isNull())
   988         return callback(cb, disc, array, lexicalVal, pos, dst);
   990     return newNode(AST_SWITCH_STMT, pos,
   991                    "discriminant", disc,
   992                    "cases", array,
   993                    "lexical", lexicalVal,
   994                    dst);
   995 }
   997 bool
   998 NodeBuilder::tryStatement(HandleValue body, NodeVector &guarded, HandleValue unguarded,
   999                           HandleValue finally, TokenPos *pos, MutableHandleValue dst)
  1001     RootedValue guardedHandlers(cx);
  1002     if (!newArray(guarded, &guardedHandlers))
  1003         return false;
  1005     RootedValue cb(cx, callbacks[AST_TRY_STMT]);
  1006     if (!cb.isNull())
  1007         return callback(cb, body, guardedHandlers, unguarded, opt(finally), pos, dst);
  1009     return newNode(AST_TRY_STMT, pos,
  1010                    "block", body,
  1011                    "guardedHandlers", guardedHandlers,
  1012                    "handler", unguarded,
  1013                    "finalizer", finally,
  1014                    dst);
  1017 bool
  1018 NodeBuilder::debuggerStatement(TokenPos *pos, MutableHandleValue dst)
  1020     RootedValue cb(cx, callbacks[AST_DEBUGGER_STMT]);
  1021     if (!cb.isNull())
  1022         return callback(cb, pos, dst);
  1024     return newNode(AST_DEBUGGER_STMT, pos, dst);
  1027 bool
  1028 NodeBuilder::binaryExpression(BinaryOperator op, HandleValue left, HandleValue right, TokenPos *pos,
  1029                               MutableHandleValue dst)
  1031     JS_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
  1033     RootedValue opName(cx);
  1034     if (!atomValue(binopNames[op], &opName))
  1035         return false;
  1037     RootedValue cb(cx, callbacks[AST_BINARY_EXPR]);
  1038     if (!cb.isNull())
  1039         return callback(cb, opName, left, right, pos, dst);
  1041     return newNode(AST_BINARY_EXPR, pos,
  1042                    "operator", opName,
  1043                    "left", left,
  1044                    "right", right,
  1045                    dst);
  1048 bool
  1049 NodeBuilder::unaryExpression(UnaryOperator unop, HandleValue expr, TokenPos *pos,
  1050                              MutableHandleValue dst)
  1052     JS_ASSERT(unop > UNOP_ERR && unop < UNOP_LIMIT);
  1054     RootedValue opName(cx);
  1055     if (!atomValue(unopNames[unop], &opName))
  1056         return false;
  1058     RootedValue cb(cx, callbacks[AST_UNARY_EXPR]);
  1059     if (!cb.isNull())
  1060         return callback(cb, opName, expr, pos, dst);
  1062     RootedValue trueVal(cx, BooleanValue(true));
  1063     return newNode(AST_UNARY_EXPR, pos,
  1064                    "operator", opName,
  1065                    "argument", expr,
  1066                    "prefix", trueVal,
  1067                    dst);
  1070 bool
  1071 NodeBuilder::assignmentExpression(AssignmentOperator aop, HandleValue lhs, HandleValue rhs,
  1072                                   TokenPos *pos, MutableHandleValue dst)
  1074     JS_ASSERT(aop > AOP_ERR && aop < AOP_LIMIT);
  1076     RootedValue opName(cx);
  1077     if (!atomValue(aopNames[aop], &opName))
  1078         return false;
  1080     RootedValue cb(cx, callbacks[AST_ASSIGN_EXPR]);
  1081     if (!cb.isNull())
  1082         return callback(cb, opName, lhs, rhs, pos, dst);
  1084     return newNode(AST_ASSIGN_EXPR, pos,
  1085                    "operator", opName,
  1086                    "left", lhs,
  1087                    "right", rhs,
  1088                    dst);
  1091 bool
  1092 NodeBuilder::updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos *pos,
  1093                               MutableHandleValue dst)
  1095     RootedValue opName(cx);
  1096     if (!atomValue(incr ? "++" : "--", &opName))
  1097         return false;
  1099     RootedValue prefixVal(cx, BooleanValue(prefix));
  1101     RootedValue cb(cx, callbacks[AST_UPDATE_EXPR]);
  1102     if (!cb.isNull())
  1103         return callback(cb, expr, opName, prefixVal, pos, dst);
  1105     return newNode(AST_UPDATE_EXPR, pos,
  1106                    "operator", opName,
  1107                    "argument", expr,
  1108                    "prefix", prefixVal,
  1109                    dst);
  1112 bool
  1113 NodeBuilder::logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos *pos,
  1114                                MutableHandleValue dst)
  1116     RootedValue opName(cx);
  1117     if (!atomValue(lor ? "||" : "&&", &opName))
  1118         return false;
  1120     RootedValue cb(cx, callbacks[AST_LOGICAL_EXPR]);
  1121     if (!cb.isNull())
  1122         return callback(cb, opName, left, right, pos, dst);
  1124     return newNode(AST_LOGICAL_EXPR, pos,
  1125                    "operator", opName,
  1126                    "left", left,
  1127                    "right", right,
  1128                    dst);
  1131 bool
  1132 NodeBuilder::conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt,
  1133                                    TokenPos *pos, MutableHandleValue dst)
  1135     RootedValue cb(cx, callbacks[AST_COND_EXPR]);
  1136     if (!cb.isNull())
  1137         return callback(cb, test, cons, alt, pos, dst);
  1139     return newNode(AST_COND_EXPR, pos,
  1140                    "test", test,
  1141                    "consequent", cons,
  1142                    "alternate", alt,
  1143                    dst);
  1146 bool
  1147 NodeBuilder::sequenceExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
  1149     return listNode(AST_LIST_EXPR, "expressions", elts, pos, dst);
  1152 bool
  1153 NodeBuilder::callExpression(HandleValue callee, NodeVector &args, TokenPos *pos,
  1154                             MutableHandleValue dst)
  1156     RootedValue array(cx);
  1157     if (!newArray(args, &array))
  1158         return false;
  1160     RootedValue cb(cx, callbacks[AST_CALL_EXPR]);
  1161     if (!cb.isNull())
  1162         return callback(cb, callee, array, pos, dst);
  1164     return newNode(AST_CALL_EXPR, pos,
  1165                    "callee", callee,
  1166                    "arguments", array,
  1167                    dst);
  1170 bool
  1171 NodeBuilder::newExpression(HandleValue callee, NodeVector &args, TokenPos *pos,
  1172                            MutableHandleValue dst)
  1174     RootedValue array(cx);
  1175     if (!newArray(args, &array))
  1176         return false;
  1178     RootedValue cb(cx, callbacks[AST_NEW_EXPR]);
  1179     if (!cb.isNull())
  1180         return callback(cb, callee, array, pos, dst);
  1182     return newNode(AST_NEW_EXPR, pos,
  1183                    "callee", callee,
  1184                    "arguments", array,
  1185                    dst);
  1188 bool
  1189 NodeBuilder::memberExpression(bool computed, HandleValue expr, HandleValue member, TokenPos *pos,
  1190                               MutableHandleValue dst)
  1192     RootedValue computedVal(cx, BooleanValue(computed));
  1194     RootedValue cb(cx, callbacks[AST_MEMBER_EXPR]);
  1195     if (!cb.isNull())
  1196         return callback(cb, computedVal, expr, member, pos, dst);
  1198     return newNode(AST_MEMBER_EXPR, pos,
  1199                    "object", expr,
  1200                    "property", member,
  1201                    "computed", computedVal,
  1202                    dst);
  1205 bool
  1206 NodeBuilder::arrayExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
  1208     return listNode(AST_ARRAY_EXPR, "elements", elts, pos, dst);
  1211 bool
  1212 NodeBuilder::spreadExpression(HandleValue expr, TokenPos *pos, MutableHandleValue dst)
  1214     return newNode(AST_SPREAD_EXPR, pos,
  1215                    "expression", expr,
  1216                    dst);
  1219 bool
  1220 NodeBuilder::propertyPattern(HandleValue key, HandleValue patt, TokenPos *pos,
  1221                              MutableHandleValue dst)
  1223     RootedValue kindName(cx);
  1224     if (!atomValue("init", &kindName))
  1225         return false;
  1227     RootedValue cb(cx, callbacks[AST_PROP_PATT]);
  1228     if (!cb.isNull())
  1229         return callback(cb, key, patt, pos, dst);
  1231     return newNode(AST_PROP_PATT, pos,
  1232                    "key", key,
  1233                    "value", patt,
  1234                    "kind", kindName,
  1235                    dst);
  1238 bool
  1239 NodeBuilder::propertyInitializer(HandleValue key, HandleValue val, PropKind kind, TokenPos *pos,
  1240                                  MutableHandleValue dst)
  1242     RootedValue kindName(cx);
  1243     if (!atomValue(kind == PROP_INIT
  1244                    ? "init"
  1245                    : kind == PROP_GETTER
  1246                    ? "get"
  1247                    : "set", &kindName)) {
  1248         return false;
  1251     RootedValue cb(cx, callbacks[AST_PROPERTY]);
  1252     if (!cb.isNull())
  1253         return callback(cb, kindName, key, val, pos, dst);
  1255     return newNode(AST_PROPERTY, pos,
  1256                    "key", key,
  1257                    "value", val,
  1258                    "kind", kindName,
  1259                    dst);
  1262 bool
  1263 NodeBuilder::objectExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
  1265     return listNode(AST_OBJECT_EXPR, "properties", elts, pos, dst);
  1268 bool
  1269 NodeBuilder::thisExpression(TokenPos *pos, MutableHandleValue dst)
  1271     RootedValue cb(cx, callbacks[AST_THIS_EXPR]);
  1272     if (!cb.isNull())
  1273         return callback(cb, pos, dst);
  1275     return newNode(AST_THIS_EXPR, pos, dst);
  1278 bool
  1279 NodeBuilder::yieldExpression(HandleValue arg, YieldKind kind, TokenPos *pos, MutableHandleValue dst)
  1281     RootedValue cb(cx, callbacks[AST_YIELD_EXPR]);
  1282     RootedValue delegateVal(cx);
  1284     switch (kind) {
  1285       case Delegating:
  1286         delegateVal = BooleanValue(true);
  1287         break;
  1288       case NotDelegating:
  1289         delegateVal = BooleanValue(false);
  1290         break;
  1293     if (!cb.isNull())
  1294         return callback(cb, opt(arg), delegateVal, pos, dst);
  1295     return newNode(AST_YIELD_EXPR, pos, "argument", arg, "delegate", delegateVal, dst);
  1298 bool
  1299 NodeBuilder::comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach, bool isForOf, TokenPos *pos,
  1300                                 MutableHandleValue dst)
  1302     RootedValue isForEachVal(cx, BooleanValue(isForEach));
  1303     RootedValue isForOfVal(cx, BooleanValue(isForOf));
  1305     RootedValue cb(cx, callbacks[AST_COMP_BLOCK]);
  1306     if (!cb.isNull())
  1307         return callback(cb, patt, src, isForEachVal, isForOfVal, pos, dst);
  1309     return newNode(AST_COMP_BLOCK, pos,
  1310                    "left", patt,
  1311                    "right", src,
  1312                    "each", isForEachVal,
  1313                    "of", isForOfVal,
  1314                    dst);
  1317 bool
  1318 NodeBuilder::comprehensionExpression(HandleValue body, NodeVector &blocks, HandleValue filter,
  1319                                      TokenPos *pos, MutableHandleValue dst)
  1321     RootedValue array(cx);
  1322     if (!newArray(blocks, &array))
  1323         return false;
  1325     RootedValue cb(cx, callbacks[AST_COMP_EXPR]);
  1326     if (!cb.isNull())
  1327         return callback(cb, body, array, opt(filter), pos, dst);
  1329     return newNode(AST_COMP_EXPR, pos,
  1330                    "body", body,
  1331                    "blocks", array,
  1332                    "filter", filter,
  1333                    dst);
  1336 bool
  1337 NodeBuilder::generatorExpression(HandleValue body, NodeVector &blocks, HandleValue filter,
  1338                                  TokenPos *pos, MutableHandleValue dst)
  1340     RootedValue array(cx);
  1341     if (!newArray(blocks, &array))
  1342         return false;
  1344     RootedValue cb(cx, callbacks[AST_GENERATOR_EXPR]);
  1345     if (!cb.isNull())
  1346         return callback(cb, body, array, opt(filter), pos, dst);
  1348     return newNode(AST_GENERATOR_EXPR, pos,
  1349                    "body", body,
  1350                    "blocks", array,
  1351                    "filter", filter,
  1352                    dst);
  1355 bool
  1356 NodeBuilder::letExpression(NodeVector &head, HandleValue expr, TokenPos *pos,
  1357                            MutableHandleValue dst)
  1359     RootedValue array(cx);
  1360     if (!newArray(head, &array))
  1361         return false;
  1363     RootedValue cb(cx, callbacks[AST_LET_EXPR]);
  1364     if (!cb.isNull())
  1365         return callback(cb, array, expr, pos, dst);
  1367     return newNode(AST_LET_EXPR, pos,
  1368                    "head", array,
  1369                    "body", expr,
  1370                    dst);
  1373 bool
  1374 NodeBuilder::letStatement(NodeVector &head, HandleValue stmt, TokenPos *pos, MutableHandleValue dst)
  1376     RootedValue array(cx);
  1377     if (!newArray(head, &array))
  1378         return false;
  1380     RootedValue cb(cx, callbacks[AST_LET_STMT]);
  1381     if (!cb.isNull())
  1382         return callback(cb, array, stmt, pos, dst);
  1384     return newNode(AST_LET_STMT, pos,
  1385                    "head", array,
  1386                    "body", stmt,
  1387                    dst);
  1390 bool
  1391 NodeBuilder::importDeclaration(NodeVector &elts, HandleValue moduleSpec, TokenPos *pos,
  1392                                MutableHandleValue dst)
  1394     RootedValue array(cx);
  1395     if (!newArray(elts, &array))
  1396         return false;
  1398     RootedValue cb(cx, callbacks[AST_IMPORT_DECL]);
  1399     if (!cb.isNull())
  1400         return callback(cb, array, moduleSpec, pos, dst);
  1402     return newNode(AST_IMPORT_DECL, pos,
  1403                    "specifiers", array,
  1404                    "source", moduleSpec,
  1405                    dst);
  1408 bool
  1409 NodeBuilder::importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos *pos,
  1410                              MutableHandleValue dst)
  1412     RootedValue cb(cx, callbacks[AST_IMPORT_SPEC]);
  1413     if (!cb.isNull())
  1414         return callback(cb, importName, bindingName, pos, dst);
  1416     return newNode(AST_IMPORT_SPEC, pos,
  1417                    "id", importName,
  1418                    "name", bindingName,
  1419                    dst);
  1422 bool
  1423 NodeBuilder::exportDeclaration(HandleValue decl, NodeVector &elts, HandleValue moduleSpec,
  1424                                TokenPos *pos, MutableHandleValue dst)
  1426     RootedValue array(cx, NullValue());
  1427     if (decl.isNull() && !newArray(elts, &array))
  1428         return false;
  1430     RootedValue cb(cx, callbacks[AST_IMPORT_DECL]);
  1432     if (!cb.isNull())
  1433         return callback(cb, decl, array, moduleSpec, pos, dst);
  1435     return newNode(AST_EXPORT_DECL, pos,
  1436                    "declaration", decl,
  1437                    "specifiers", array,
  1438                    "source", moduleSpec,
  1439                    dst);
  1442 bool
  1443 NodeBuilder::exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos *pos,
  1444                              MutableHandleValue dst)
  1446     RootedValue cb(cx, callbacks[AST_EXPORT_SPEC]);
  1447     if (!cb.isNull())
  1448         return callback(cb, bindingName, exportName, pos, dst);
  1450     return newNode(AST_EXPORT_SPEC, pos,
  1451                    "id", bindingName,
  1452                    "name", exportName,
  1453                    dst);
  1456 bool
  1457 NodeBuilder::exportBatchSpecifier(TokenPos *pos, MutableHandleValue dst)
  1459     RootedValue cb(cx, callbacks[AST_EXPORT_BATCH_SPEC]);
  1460     if (!cb.isNull())
  1461         return callback(cb, pos, dst);
  1463     return newNode(AST_EXPORT_BATCH_SPEC, pos, dst);
  1466 bool
  1467 NodeBuilder::variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos,
  1468                                  MutableHandleValue dst)
  1470     JS_ASSERT(kind > VARDECL_ERR && kind < VARDECL_LIMIT);
  1472     RootedValue array(cx), kindName(cx);
  1473     if (!newArray(elts, &array) ||
  1474         !atomValue(kind == VARDECL_CONST
  1475                    ? "const"
  1476                    : kind == VARDECL_LET
  1477                    ? "let"
  1478                    : "var", &kindName)) {
  1479         return false;
  1482     RootedValue cb(cx, callbacks[AST_VAR_DECL]);
  1483     if (!cb.isNull())
  1484         return callback(cb, kindName, array, pos, dst);
  1486     return newNode(AST_VAR_DECL, pos,
  1487                    "kind", kindName,
  1488                    "declarations", array,
  1489                    dst);
  1492 bool
  1493 NodeBuilder::variableDeclarator(HandleValue id, HandleValue init, TokenPos *pos,
  1494                                 MutableHandleValue dst)
  1496     RootedValue cb(cx, callbacks[AST_VAR_DTOR]);
  1497     if (!cb.isNull())
  1498         return callback(cb, id, opt(init), pos, dst);
  1500     return newNode(AST_VAR_DTOR, pos, "id", id, "init", init, dst);
  1503 bool
  1504 NodeBuilder::switchCase(HandleValue expr, NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
  1506     RootedValue array(cx);
  1507     if (!newArray(elts, &array))
  1508         return false;
  1510     RootedValue cb(cx, callbacks[AST_CASE]);
  1511     if (!cb.isNull())
  1512         return callback(cb, opt(expr), array, pos, dst);
  1514     return newNode(AST_CASE, pos,
  1515                    "test", expr,
  1516                    "consequent", array,
  1517                    dst);
  1520 bool
  1521 NodeBuilder::catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos *pos,
  1522                          MutableHandleValue dst)
  1524     RootedValue cb(cx, callbacks[AST_CATCH]);
  1525     if (!cb.isNull())
  1526         return callback(cb, var, opt(guard), body, pos, dst);
  1528     return newNode(AST_CATCH, pos,
  1529                    "param", var,
  1530                    "guard", guard,
  1531                    "body", body,
  1532                    dst);
  1535 bool
  1536 NodeBuilder::literal(HandleValue val, TokenPos *pos, MutableHandleValue dst)
  1538     RootedValue cb(cx, callbacks[AST_LITERAL]);
  1539     if (!cb.isNull())
  1540         return callback(cb, val, pos, dst);
  1542     return newNode(AST_LITERAL, pos, "value", val, dst);
  1545 bool
  1546 NodeBuilder::identifier(HandleValue name, TokenPos *pos, MutableHandleValue dst)
  1548     RootedValue cb(cx, callbacks[AST_IDENTIFIER]);
  1549     if (!cb.isNull())
  1550         return callback(cb, name, pos, dst);
  1552     return newNode(AST_IDENTIFIER, pos, "name", name, dst);
  1555 bool
  1556 NodeBuilder::objectPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
  1558     return listNode(AST_OBJECT_PATT, "properties", elts, pos, dst);
  1561 bool
  1562 NodeBuilder::arrayPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
  1564     return listNode(AST_ARRAY_PATT, "elements", elts, pos, dst);
  1567 bool
  1568 NodeBuilder::function(ASTType type, TokenPos *pos,
  1569                       HandleValue id, NodeVector &args, NodeVector &defaults,
  1570                       HandleValue body, HandleValue rest,
  1571                       bool isGenerator, bool isExpression,
  1572                       MutableHandleValue dst)
  1574     RootedValue array(cx), defarray(cx);
  1575     if (!newArray(args, &array))
  1576         return false;
  1577     if (!newArray(defaults, &defarray))
  1578         return false;
  1580     RootedValue isGeneratorVal(cx, BooleanValue(isGenerator));
  1581     RootedValue isExpressionVal(cx, BooleanValue(isExpression));
  1583     RootedValue cb(cx, callbacks[type]);
  1584     if (!cb.isNull()) {
  1585         return callback(cb, opt(id), array, body, isGeneratorVal, isExpressionVal, pos, dst);
  1588     return newNode(type, pos,
  1589                    "id", id,
  1590                    "params", array,
  1591                    "defaults", defarray,
  1592                    "body", body,
  1593                    "rest", rest,
  1594                    "generator", isGeneratorVal,
  1595                    "expression", isExpressionVal,
  1596                    dst);
  1599 namespace {
  1601 /*
  1602  * Serialization of parse nodes to JavaScript objects.
  1604  * All serialization methods take a non-nullable ParseNode pointer.
  1605  */
  1606 class ASTSerializer
  1608     JSContext           *cx;
  1609     Parser<FullParseHandler> *parser;
  1610     NodeBuilder         builder;
  1611     DebugOnly<uint32_t> lineno;
  1613     Value unrootedAtomContents(JSAtom *atom) {
  1614         return StringValue(atom ? atom : cx->names().empty);
  1617     BinaryOperator binop(ParseNodeKind kind, JSOp op);
  1618     UnaryOperator unop(ParseNodeKind kind, JSOp op);
  1619     AssignmentOperator aop(JSOp op);
  1621     bool statements(ParseNode *pn, NodeVector &elts);
  1622     bool expressions(ParseNode *pn, NodeVector &elts);
  1623     bool leftAssociate(ParseNode *pn, MutableHandleValue dst);
  1624     bool functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct, ParseNode *pnbody,
  1625                       NodeVector &args, NodeVector &defaults, MutableHandleValue rest);
  1627     bool sourceElement(ParseNode *pn, MutableHandleValue dst);
  1629     bool declaration(ParseNode *pn, MutableHandleValue dst);
  1630     bool variableDeclaration(ParseNode *pn, bool let, MutableHandleValue dst);
  1631     bool variableDeclarator(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst);
  1632     bool let(ParseNode *pn, bool expr, MutableHandleValue dst);
  1633     bool importDeclaration(ParseNode *pn, MutableHandleValue dst);
  1634     bool importSpecifier(ParseNode *pn, MutableHandleValue dst);
  1635     bool exportDeclaration(ParseNode *pn, MutableHandleValue dst);
  1636     bool exportSpecifier(ParseNode *pn, MutableHandleValue dst);
  1638     bool optStatement(ParseNode *pn, MutableHandleValue dst) {
  1639         if (!pn) {
  1640             dst.setMagic(JS_SERIALIZE_NO_NODE);
  1641             return true;
  1643         return statement(pn, dst);
  1646     bool forInit(ParseNode *pn, MutableHandleValue dst);
  1647     bool forIn(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
  1648                MutableHandleValue dst);
  1649     bool forOf(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
  1650                MutableHandleValue dst);
  1651     bool statement(ParseNode *pn, MutableHandleValue dst);
  1652     bool blockStatement(ParseNode *pn, MutableHandleValue dst);
  1653     bool switchStatement(ParseNode *pn, MutableHandleValue dst);
  1654     bool switchCase(ParseNode *pn, MutableHandleValue dst);
  1655     bool tryStatement(ParseNode *pn, MutableHandleValue dst);
  1656     bool catchClause(ParseNode *pn, bool *isGuarded, MutableHandleValue dst);
  1658     bool optExpression(ParseNode *pn, MutableHandleValue dst) {
  1659         if (!pn) {
  1660             dst.setMagic(JS_SERIALIZE_NO_NODE);
  1661             return true;
  1663         return expression(pn, dst);
  1666     bool expression(ParseNode *pn, MutableHandleValue dst);
  1668     bool propertyName(ParseNode *pn, MutableHandleValue dst);
  1669     bool property(ParseNode *pn, MutableHandleValue dst);
  1671     bool optIdentifier(HandleAtom atom, TokenPos *pos, MutableHandleValue dst) {
  1672         if (!atom) {
  1673             dst.setMagic(JS_SERIALIZE_NO_NODE);
  1674             return true;
  1676         return identifier(atom, pos, dst);
  1679     bool identifier(HandleAtom atom, TokenPos *pos, MutableHandleValue dst);
  1680     bool identifier(ParseNode *pn, MutableHandleValue dst);
  1681     bool literal(ParseNode *pn, MutableHandleValue dst);
  1683     bool pattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst);
  1684     bool arrayPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst);
  1685     bool objectPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst);
  1687     bool function(ParseNode *pn, ASTType type, MutableHandleValue dst);
  1688     bool functionArgsAndBody(ParseNode *pn, NodeVector &args, NodeVector &defaults,
  1689                              MutableHandleValue body, MutableHandleValue rest);
  1690     bool functionBody(ParseNode *pn, TokenPos *pos, MutableHandleValue dst);
  1692     bool comprehensionBlock(ParseNode *pn, MutableHandleValue dst);
  1693     bool comprehension(ParseNode *pn, MutableHandleValue dst);
  1694     bool generatorExpression(ParseNode *pn, MutableHandleValue dst);
  1696   public:
  1697     ASTSerializer(JSContext *c, bool l, char const *src, uint32_t ln)
  1698         : cx(c)
  1699         , builder(c, l, src)
  1700 #ifdef DEBUG
  1701         , lineno(ln)
  1702 #endif
  1703     {}
  1705     bool init(HandleObject userobj) {
  1706         return builder.init(userobj);
  1709     void setParser(Parser<FullParseHandler> *p) {
  1710         parser = p;
  1711         builder.setTokenStream(&p->tokenStream);
  1714     bool program(ParseNode *pn, MutableHandleValue dst);
  1715 };
  1717 } /* anonymous namespace */
  1719 AssignmentOperator
  1720 ASTSerializer::aop(JSOp op)
  1722     switch (op) {
  1723       case JSOP_NOP:
  1724         return AOP_ASSIGN;
  1725       case JSOP_ADD:
  1726         return AOP_PLUS;
  1727       case JSOP_SUB:
  1728         return AOP_MINUS;
  1729       case JSOP_MUL:
  1730         return AOP_STAR;
  1731       case JSOP_DIV:
  1732         return AOP_DIV;
  1733       case JSOP_MOD:
  1734         return AOP_MOD;
  1735       case JSOP_LSH:
  1736         return AOP_LSH;
  1737       case JSOP_RSH:
  1738         return AOP_RSH;
  1739       case JSOP_URSH:
  1740         return AOP_URSH;
  1741       case JSOP_BITOR:
  1742         return AOP_BITOR;
  1743       case JSOP_BITXOR:
  1744         return AOP_BITXOR;
  1745       case JSOP_BITAND:
  1746         return AOP_BITAND;
  1747       default:
  1748         return AOP_ERR;
  1752 UnaryOperator
  1753 ASTSerializer::unop(ParseNodeKind kind, JSOp op)
  1755     if (kind == PNK_DELETE)
  1756         return UNOP_DELETE;
  1758     switch (op) {
  1759       case JSOP_NEG:
  1760         return UNOP_NEG;
  1761       case JSOP_POS:
  1762         return UNOP_POS;
  1763       case JSOP_NOT:
  1764         return UNOP_NOT;
  1765       case JSOP_BITNOT:
  1766         return UNOP_BITNOT;
  1767       case JSOP_TYPEOF:
  1768       case JSOP_TYPEOFEXPR:
  1769         return UNOP_TYPEOF;
  1770       case JSOP_VOID:
  1771         return UNOP_VOID;
  1772       default:
  1773         return UNOP_ERR;
  1777 BinaryOperator
  1778 ASTSerializer::binop(ParseNodeKind kind, JSOp op)
  1780     switch (kind) {
  1781       case PNK_LSH:
  1782         return BINOP_LSH;
  1783       case PNK_RSH:
  1784         return BINOP_RSH;
  1785       case PNK_URSH:
  1786         return BINOP_URSH;
  1787       case PNK_LT:
  1788         return BINOP_LT;
  1789       case PNK_LE:
  1790         return BINOP_LE;
  1791       case PNK_GT:
  1792         return BINOP_GT;
  1793       case PNK_GE:
  1794         return BINOP_GE;
  1795       case PNK_EQ:
  1796         return BINOP_EQ;
  1797       case PNK_NE:
  1798         return BINOP_NE;
  1799       case PNK_STRICTEQ:
  1800         return BINOP_STRICTEQ;
  1801       case PNK_STRICTNE:
  1802         return BINOP_STRICTNE;
  1803       case PNK_ADD:
  1804         return BINOP_ADD;
  1805       case PNK_SUB:
  1806         return BINOP_SUB;
  1807       case PNK_STAR:
  1808         return BINOP_STAR;
  1809       case PNK_DIV:
  1810         return BINOP_DIV;
  1811       case PNK_MOD:
  1812         return BINOP_MOD;
  1813       case PNK_BITOR:
  1814         return BINOP_BITOR;
  1815       case PNK_BITXOR:
  1816         return BINOP_BITXOR;
  1817       case PNK_BITAND:
  1818         return BINOP_BITAND;
  1819       case PNK_IN:
  1820         return BINOP_IN;
  1821       case PNK_INSTANCEOF:
  1822         return BINOP_INSTANCEOF;
  1823       default:
  1824         return BINOP_ERR;
  1828 bool
  1829 ASTSerializer::statements(ParseNode *pn, NodeVector &elts)
  1831     JS_ASSERT(pn->isKind(PNK_STATEMENTLIST));
  1832     JS_ASSERT(pn->isArity(PN_LIST));
  1834     if (!elts.reserve(pn->pn_count))
  1835         return false;
  1837     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
  1838         JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
  1840         RootedValue elt(cx);
  1841         if (!sourceElement(next, &elt))
  1842             return false;
  1843         elts.infallibleAppend(elt);
  1846     return true;
  1849 bool
  1850 ASTSerializer::expressions(ParseNode *pn, NodeVector &elts)
  1852     if (!elts.reserve(pn->pn_count))
  1853         return false;
  1855     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
  1856         JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
  1858         RootedValue elt(cx);
  1859         if (!expression(next, &elt))
  1860             return false;
  1861         elts.infallibleAppend(elt);
  1864     return true;
  1867 bool
  1868 ASTSerializer::blockStatement(ParseNode *pn, MutableHandleValue dst)
  1870     JS_ASSERT(pn->isKind(PNK_STATEMENTLIST));
  1872     NodeVector stmts(cx);
  1873     return statements(pn, stmts) &&
  1874            builder.blockStatement(stmts, &pn->pn_pos, dst);
  1877 bool
  1878 ASTSerializer::program(ParseNode *pn, MutableHandleValue dst)
  1880     JS_ASSERT(parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin) == lineno);
  1882     NodeVector stmts(cx);
  1883     return statements(pn, stmts) &&
  1884            builder.program(stmts, &pn->pn_pos, dst);
  1887 bool
  1888 ASTSerializer::sourceElement(ParseNode *pn, MutableHandleValue dst)
  1890     /* SpiderMonkey allows declarations even in pure statement contexts. */
  1891     return statement(pn, dst);
  1894 bool
  1895 ASTSerializer::declaration(ParseNode *pn, MutableHandleValue dst)
  1897     JS_ASSERT(pn->isKind(PNK_FUNCTION) ||
  1898               pn->isKind(PNK_VAR) ||
  1899               pn->isKind(PNK_LET) ||
  1900               pn->isKind(PNK_CONST));
  1902     switch (pn->getKind()) {
  1903       case PNK_FUNCTION:
  1904         return function(pn, AST_FUNC_DECL, dst);
  1906       case PNK_VAR:
  1907       case PNK_CONST:
  1908         return variableDeclaration(pn, false, dst);
  1910       default:
  1911         JS_ASSERT(pn->isKind(PNK_LET));
  1912         return variableDeclaration(pn, true, dst);
  1916 bool
  1917 ASTSerializer::variableDeclaration(ParseNode *pn, bool let, MutableHandleValue dst)
  1919     JS_ASSERT(let ? pn->isKind(PNK_LET) : (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST)));
  1921     /* Later updated to VARDECL_CONST if we find a PND_CONST declarator. */
  1922     VarDeclKind kind = let ? VARDECL_LET : VARDECL_VAR;
  1924     NodeVector dtors(cx);
  1925     if (!dtors.reserve(pn->pn_count))
  1926         return false;
  1927     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
  1928         RootedValue child(cx);
  1929         if (!variableDeclarator(next, &kind, &child))
  1930             return false;
  1931         dtors.infallibleAppend(child);
  1933     return builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
  1936 bool
  1937 ASTSerializer::variableDeclarator(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst)
  1939     ParseNode *pnleft;
  1940     ParseNode *pnright;
  1942     if (pn->isKind(PNK_NAME)) {
  1943         pnleft = pn;
  1944         pnright = pn->isUsed() ? nullptr : pn->pn_expr;
  1945         JS_ASSERT_IF(pnright, pn->pn_pos.encloses(pnright->pn_pos));
  1946     } else if (pn->isKind(PNK_ASSIGN)) {
  1947         pnleft = pn->pn_left;
  1948         pnright = pn->pn_right;
  1949         JS_ASSERT(pn->pn_pos.encloses(pnleft->pn_pos));
  1950         JS_ASSERT(pn->pn_pos.encloses(pnright->pn_pos));
  1951     } else {
  1952         /* This happens for a destructuring declarator in a for-in/of loop. */
  1953         pnleft = pn;
  1954         pnright = nullptr;
  1957     RootedValue left(cx), right(cx);
  1958     return pattern(pnleft, pkind, &left) &&
  1959            optExpression(pnright, &right) &&
  1960            builder.variableDeclarator(left, right, &pn->pn_pos, dst);
  1963 bool
  1964 ASTSerializer::let(ParseNode *pn, bool expr, MutableHandleValue dst)
  1966     JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
  1967     JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
  1969     ParseNode *letHead = pn->pn_left;
  1970     LOCAL_ASSERT(letHead->isArity(PN_LIST));
  1972     ParseNode *letBody = pn->pn_right;
  1973     LOCAL_ASSERT(letBody->isKind(PNK_LEXICALSCOPE));
  1975     NodeVector dtors(cx);
  1976     if (!dtors.reserve(letHead->pn_count))
  1977         return false;
  1979     VarDeclKind kind = VARDECL_LET_HEAD;
  1981     for (ParseNode *next = letHead->pn_head; next; next = next->pn_next) {
  1982         RootedValue child(cx);
  1983         /*
  1984          * Unlike in |variableDeclaration|, this does not update |kind|; since let-heads do
  1985          * not contain const declarations, declarators should never have PND_CONST set.
  1986          */
  1987         if (!variableDeclarator(next, &kind, &child))
  1988             return false;
  1989         dtors.infallibleAppend(child);
  1992     RootedValue v(cx);
  1993     return expr
  1994            ? expression(letBody->pn_expr, &v) &&
  1995              builder.letExpression(dtors, v, &pn->pn_pos, dst)
  1996            : statement(letBody->pn_expr, &v) &&
  1997              builder.letStatement(dtors, v, &pn->pn_pos, dst);
  2000 bool
  2001 ASTSerializer::importDeclaration(ParseNode *pn, MutableHandleValue dst)
  2003     JS_ASSERT(pn->isKind(PNK_IMPORT));
  2004     JS_ASSERT(pn->pn_left->isKind(PNK_IMPORT_SPEC_LIST));
  2005     JS_ASSERT(pn->pn_right->isKind(PNK_STRING));
  2007     NodeVector elts(cx);
  2008     if (!elts.reserve(pn->pn_count))
  2009         return false;
  2011     for (ParseNode *next = pn->pn_left->pn_head; next; next = next->pn_next) {
  2012         RootedValue elt(cx);
  2013         if (!importSpecifier(next, &elt))
  2014             return false;
  2015         elts.infallibleAppend(elt);
  2018     RootedValue moduleSpec(cx);
  2019     return literal(pn->pn_right, &moduleSpec) &&
  2020            builder.importDeclaration(elts, moduleSpec, &pn->pn_pos, dst);
  2023 bool
  2024 ASTSerializer::importSpecifier(ParseNode *pn, MutableHandleValue dst)
  2026     JS_ASSERT(pn->isKind(PNK_IMPORT_SPEC));
  2028     RootedValue importName(cx);
  2029     RootedValue bindingName(cx);
  2030     return identifier(pn->pn_left, &importName) &&
  2031            identifier(pn->pn_right, &bindingName) &&
  2032            builder.importSpecifier(importName, bindingName, &pn->pn_pos, dst);
  2035 bool
  2036 ASTSerializer::exportDeclaration(ParseNode *pn, MutableHandleValue dst)
  2038     JS_ASSERT(pn->isKind(PNK_EXPORT) || pn->isKind(PNK_EXPORT_FROM));
  2039     JS_ASSERT_IF(pn->isKind(PNK_EXPORT_FROM), pn->pn_right->isKind(PNK_STRING));
  2041     RootedValue decl(cx, NullValue());
  2042     NodeVector elts(cx);
  2044     ParseNode *kid = pn->isKind(PNK_EXPORT) ? pn->pn_kid : pn->pn_left;
  2045     switch (ParseNodeKind kind = kid->getKind()) {
  2046       case PNK_EXPORT_SPEC_LIST:
  2047         if (!elts.reserve(pn->pn_count))
  2048             return false;
  2050         for (ParseNode *next = pn->pn_left->pn_head; next; next = next->pn_next) {
  2051             RootedValue elt(cx);
  2052             if (next->isKind(PNK_EXPORT_SPEC)) {
  2053                 if (!exportSpecifier(next, &elt))
  2054                     return false;
  2055             } else {
  2056                 if (!builder.exportBatchSpecifier(&pn->pn_pos, &elt))
  2057                     return false;
  2059             elts.infallibleAppend(elt);
  2061         break;
  2063       case PNK_FUNCTION:
  2064         if (!function(kid, AST_FUNC_DECL, &decl))
  2065             return false;
  2066         break;
  2068       case PNK_VAR:
  2069       case PNK_CONST:
  2070       case PNK_LET:
  2071         if (!variableDeclaration(kid, kind == PNK_LET, &decl))
  2072             return false;
  2073         break;
  2075       default:
  2076         LOCAL_NOT_REACHED("unexpected statement type");
  2079     RootedValue moduleSpec(cx, NullValue());
  2080     if (pn->isKind(PNK_EXPORT_FROM) && !literal(pn->pn_right, &moduleSpec))
  2081         return false;
  2083     return builder.exportDeclaration(decl, elts, moduleSpec, &pn->pn_pos, dst);
  2086 bool
  2087 ASTSerializer::exportSpecifier(ParseNode *pn, MutableHandleValue dst)
  2089     JS_ASSERT(pn->isKind(PNK_EXPORT_SPEC));
  2091     RootedValue bindingName(cx);
  2092     RootedValue exportName(cx);
  2093     return identifier(pn->pn_left, &bindingName) &&
  2094            identifier(pn->pn_right, &exportName) &&
  2095            builder.exportSpecifier(bindingName, exportName, &pn->pn_pos, dst);
  2098 bool
  2099 ASTSerializer::switchCase(ParseNode *pn, MutableHandleValue dst)
  2101     JS_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos));
  2102     JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
  2104     NodeVector stmts(cx);
  2106     RootedValue expr(cx);
  2108     return optExpression(pn->pn_left, &expr) &&
  2109            statements(pn->pn_right, stmts) &&
  2110            builder.switchCase(expr, stmts, &pn->pn_pos, dst);
  2113 bool
  2114 ASTSerializer::switchStatement(ParseNode *pn, MutableHandleValue dst)
  2116     JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
  2117     JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
  2119     RootedValue disc(cx);
  2121     if (!expression(pn->pn_left, &disc))
  2122         return false;
  2124     ParseNode *listNode;
  2125     bool lexical;
  2127     if (pn->pn_right->isKind(PNK_LEXICALSCOPE)) {
  2128         listNode = pn->pn_right->pn_expr;
  2129         lexical = true;
  2130     } else {
  2131         listNode = pn->pn_right;
  2132         lexical = false;
  2135     NodeVector cases(cx);
  2136     if (!cases.reserve(listNode->pn_count))
  2137         return false;
  2139     for (ParseNode *next = listNode->pn_head; next; next = next->pn_next) {
  2140         RootedValue child(cx);
  2141         if (!switchCase(next, &child))
  2142             return false;
  2143         cases.infallibleAppend(child);
  2146     return builder.switchStatement(disc, cases, lexical, &pn->pn_pos, dst);
  2149 bool
  2150 ASTSerializer::catchClause(ParseNode *pn, bool *isGuarded, MutableHandleValue dst)
  2152     JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
  2153     JS_ASSERT_IF(pn->pn_kid2, pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
  2154     JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
  2156     RootedValue var(cx), guard(cx), body(cx);
  2158     if (!pattern(pn->pn_kid1, nullptr, &var) ||
  2159         !optExpression(pn->pn_kid2, &guard)) {
  2160         return false;
  2163     *isGuarded = !guard.isMagic(JS_SERIALIZE_NO_NODE);
  2165     return statement(pn->pn_kid3, &body) &&
  2166            builder.catchClause(var, guard, body, &pn->pn_pos, dst);
  2169 bool
  2170 ASTSerializer::tryStatement(ParseNode *pn, MutableHandleValue dst)
  2172     JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
  2173     JS_ASSERT_IF(pn->pn_kid2, pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
  2174     JS_ASSERT_IF(pn->pn_kid3, pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
  2176     RootedValue body(cx);
  2177     if (!statement(pn->pn_kid1, &body))
  2178         return false;
  2180     NodeVector guarded(cx);
  2181     RootedValue unguarded(cx, NullValue());
  2183     if (pn->pn_kid2) {
  2184         if (!guarded.reserve(pn->pn_kid2->pn_count))
  2185             return false;
  2187         for (ParseNode *next = pn->pn_kid2->pn_head; next; next = next->pn_next) {
  2188             RootedValue clause(cx);
  2189             bool isGuarded;
  2190             if (!catchClause(next->pn_expr, &isGuarded, &clause))
  2191                 return false;
  2192             if (isGuarded)
  2193                 guarded.infallibleAppend(clause);
  2194             else
  2195                 unguarded = clause;
  2199     RootedValue finally(cx);
  2200     return optStatement(pn->pn_kid3, &finally) &&
  2201            builder.tryStatement(body, guarded, unguarded, finally, &pn->pn_pos, dst);
  2204 bool
  2205 ASTSerializer::forInit(ParseNode *pn, MutableHandleValue dst)
  2207     if (!pn) {
  2208         dst.setMagic(JS_SERIALIZE_NO_NODE);
  2209         return true;
  2212     return (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST))
  2213            ? variableDeclaration(pn, false, dst)
  2214            : expression(pn, dst);
  2217 bool
  2218 ASTSerializer::forOf(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
  2219                          MutableHandleValue dst)
  2221     RootedValue expr(cx);
  2223     return expression(head->pn_kid3, &expr) &&
  2224         builder.forOfStatement(var, expr, stmt, &loop->pn_pos, dst);
  2227 bool
  2228 ASTSerializer::forIn(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
  2229                          MutableHandleValue dst)
  2231     RootedValue expr(cx);
  2232     bool isForEach = loop->pn_iflags & JSITER_FOREACH;
  2234     return expression(head->pn_kid3, &expr) &&
  2235         builder.forInStatement(var, expr, stmt, isForEach, &loop->pn_pos, dst);
  2238 bool
  2239 ASTSerializer::statement(ParseNode *pn, MutableHandleValue dst)
  2241     JS_CHECK_RECURSION(cx, return false);
  2242     switch (pn->getKind()) {
  2243       case PNK_FUNCTION:
  2244       case PNK_VAR:
  2245       case PNK_CONST:
  2246         return declaration(pn, dst);
  2248       case PNK_LET:
  2249         return pn->isArity(PN_BINARY)
  2250                ? let(pn, false, dst)
  2251                : declaration(pn, dst);
  2253       case PNK_IMPORT:
  2254         return importDeclaration(pn, dst);
  2256       case PNK_EXPORT:
  2257       case PNK_EXPORT_FROM:
  2258         return exportDeclaration(pn, dst);
  2260       case PNK_NAME:
  2261         LOCAL_ASSERT(pn->isUsed());
  2262         return statement(pn->pn_lexdef, dst);
  2264       case PNK_SEMI:
  2265         if (pn->pn_kid) {
  2266             RootedValue expr(cx);
  2267             return expression(pn->pn_kid, &expr) &&
  2268                    builder.expressionStatement(expr, &pn->pn_pos, dst);
  2270         return builder.emptyStatement(&pn->pn_pos, dst);
  2272       case PNK_LEXICALSCOPE:
  2273         pn = pn->pn_expr;
  2274         if (!pn->isKind(PNK_STATEMENTLIST))
  2275             return statement(pn, dst);
  2276         /* FALL THROUGH */
  2278       case PNK_STATEMENTLIST:
  2279         return blockStatement(pn, dst);
  2281       case PNK_IF:
  2283         JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
  2284         JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
  2285         JS_ASSERT_IF(pn->pn_kid3, pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
  2287         RootedValue test(cx), cons(cx), alt(cx);
  2289         return expression(pn->pn_kid1, &test) &&
  2290                statement(pn->pn_kid2, &cons) &&
  2291                optStatement(pn->pn_kid3, &alt) &&
  2292                builder.ifStatement(test, cons, alt, &pn->pn_pos, dst);
  2295       case PNK_SWITCH:
  2296         return switchStatement(pn, dst);
  2298       case PNK_TRY:
  2299         return tryStatement(pn, dst);
  2301       case PNK_WITH:
  2302       case PNK_WHILE:
  2304         JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
  2305         JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
  2307         RootedValue expr(cx), stmt(cx);
  2309         return expression(pn->pn_left, &expr) &&
  2310                statement(pn->pn_right, &stmt) &&
  2311                (pn->isKind(PNK_WITH)
  2312                 ? builder.withStatement(expr, stmt, &pn->pn_pos, dst)
  2313                 : builder.whileStatement(expr, stmt, &pn->pn_pos, dst));
  2316       case PNK_DOWHILE:
  2318         JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
  2319         JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
  2321         RootedValue stmt(cx), test(cx);
  2323         return statement(pn->pn_left, &stmt) &&
  2324                expression(pn->pn_right, &test) &&
  2325                builder.doWhileStatement(stmt, test, &pn->pn_pos, dst);
  2328       case PNK_FOR:
  2330         JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
  2331         JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
  2333         ParseNode *head = pn->pn_left;
  2335         JS_ASSERT_IF(head->pn_kid1, head->pn_pos.encloses(head->pn_kid1->pn_pos));
  2336         JS_ASSERT_IF(head->pn_kid2, head->pn_pos.encloses(head->pn_kid2->pn_pos));
  2337         JS_ASSERT_IF(head->pn_kid3, head->pn_pos.encloses(head->pn_kid3->pn_pos));
  2339         RootedValue stmt(cx);
  2340         if (!statement(pn->pn_right, &stmt))
  2341             return false;
  2343         if (head->isKind(PNK_FORIN)) {
  2344             RootedValue var(cx);
  2345             return (!head->pn_kid1
  2346                     ? pattern(head->pn_kid2, nullptr, &var)
  2347                     : head->pn_kid1->isKind(PNK_LEXICALSCOPE)
  2348                     ? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
  2349                     : variableDeclaration(head->pn_kid1, false, &var)) &&
  2350                 forIn(pn, head, var, stmt, dst);
  2353         if (head->isKind(PNK_FOROF)) {
  2354             RootedValue var(cx);
  2355             return (!head->pn_kid1
  2356                     ? pattern(head->pn_kid2, nullptr, &var)
  2357                     : head->pn_kid1->isKind(PNK_LEXICALSCOPE)
  2358                     ? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
  2359                     : variableDeclaration(head->pn_kid1, false, &var)) &&
  2360                 forOf(pn, head, var, stmt, dst);
  2363         RootedValue init(cx), test(cx), update(cx);
  2365         return forInit(head->pn_kid1, &init) &&
  2366                optExpression(head->pn_kid2, &test) &&
  2367                optExpression(head->pn_kid3, &update) &&
  2368                builder.forStatement(init, test, update, stmt, &pn->pn_pos, dst);
  2371       /* Synthesized by the parser when a for-in loop contains a variable initializer. */
  2372       case PNK_SEQ:
  2374         LOCAL_ASSERT(pn->pn_count == 2);
  2376         ParseNode *prelude = pn->pn_head;
  2377         ParseNode *loop = prelude->pn_next;
  2379         LOCAL_ASSERT(prelude->isKind(PNK_VAR) && loop->isKind(PNK_FOR));
  2381         RootedValue var(cx);
  2382         if (!variableDeclaration(prelude, false, &var))
  2383             return false;
  2385         ParseNode *head = loop->pn_left;
  2386         JS_ASSERT(head->isKind(PNK_FORIN));
  2388         RootedValue stmt(cx);
  2390         return statement(loop->pn_right, &stmt) && forIn(loop, head, var, stmt, dst);
  2393       case PNK_BREAK:
  2394       case PNK_CONTINUE:
  2396         RootedValue label(cx);
  2397         RootedAtom pnAtom(cx, pn->pn_atom);
  2398         return optIdentifier(pnAtom, nullptr, &label) &&
  2399                (pn->isKind(PNK_BREAK)
  2400                 ? builder.breakStatement(label, &pn->pn_pos, dst)
  2401                 : builder.continueStatement(label, &pn->pn_pos, dst));
  2404       case PNK_LABEL:
  2406         JS_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
  2408         RootedValue label(cx), stmt(cx);
  2409         RootedAtom pnAtom(cx, pn->as<LabeledStatement>().label());
  2410         return identifier(pnAtom, nullptr, &label) &&
  2411                statement(pn->pn_expr, &stmt) &&
  2412                builder.labeledStatement(label, stmt, &pn->pn_pos, dst);
  2415       case PNK_THROW:
  2416       case PNK_RETURN:
  2418         JS_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
  2420         RootedValue arg(cx);
  2422         return optExpression(pn->pn_kid, &arg) &&
  2423                (pn->isKind(PNK_THROW)
  2424                 ? builder.throwStatement(arg, &pn->pn_pos, dst)
  2425                 : builder.returnStatement(arg, &pn->pn_pos, dst));
  2428       case PNK_DEBUGGER:
  2429         return builder.debuggerStatement(&pn->pn_pos, dst);
  2431       case PNK_NOP:
  2432         return builder.emptyStatement(&pn->pn_pos, dst);
  2434       default:
  2435         LOCAL_NOT_REACHED("unexpected statement type");
  2439 bool
  2440 ASTSerializer::leftAssociate(ParseNode *pn, MutableHandleValue dst)
  2442     JS_ASSERT(pn->isArity(PN_LIST));
  2443     JS_ASSERT(pn->pn_count >= 1);
  2445     ParseNodeKind kind = pn->getKind();
  2446     bool lor = kind == PNK_OR;
  2447     bool logop = lor || (kind == PNK_AND);
  2449     ParseNode *head = pn->pn_head;
  2450     RootedValue left(cx);
  2451     if (!expression(head, &left))
  2452         return false;
  2453     for (ParseNode *next = head->pn_next; next; next = next->pn_next) {
  2454         RootedValue right(cx);
  2455         if (!expression(next, &right))
  2456             return false;
  2458         TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end);
  2460         if (logop) {
  2461             if (!builder.logicalExpression(lor, left, right, &subpos, &left))
  2462                 return false;
  2463         } else {
  2464             BinaryOperator op = binop(pn->getKind(), pn->getOp());
  2465             LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
  2467             if (!builder.binaryExpression(op, left, right, &subpos, &left))
  2468                 return false;
  2472     dst.set(left);
  2473     return true;
  2476 bool
  2477 ASTSerializer::comprehensionBlock(ParseNode *pn, MutableHandleValue dst)
  2479     LOCAL_ASSERT(pn->isArity(PN_BINARY));
  2481     ParseNode *in = pn->pn_left;
  2483     LOCAL_ASSERT(in && (in->isKind(PNK_FORIN) || in->isKind(PNK_FOROF)));
  2485     bool isForEach = pn->pn_iflags & JSITER_FOREACH;
  2486     bool isForOf = in->isKind(PNK_FOROF);
  2488     RootedValue patt(cx), src(cx);
  2489     return pattern(in->pn_kid2, nullptr, &patt) &&
  2490            expression(in->pn_kid3, &src) &&
  2491            builder.comprehensionBlock(patt, src, isForEach, isForOf, &in->pn_pos, dst);
  2494 bool
  2495 ASTSerializer::comprehension(ParseNode *pn, MutableHandleValue dst)
  2497     LOCAL_ASSERT(pn->isKind(PNK_FOR));
  2499     NodeVector blocks(cx);
  2501     ParseNode *next = pn;
  2502     while (next->isKind(PNK_FOR)) {
  2503         RootedValue block(cx);
  2504         if (!comprehensionBlock(next, &block) || !blocks.append(block))
  2505             return false;
  2506         next = next->pn_right;
  2509     RootedValue filter(cx, MagicValue(JS_SERIALIZE_NO_NODE));
  2511     if (next->isKind(PNK_IF)) {
  2512         if (!optExpression(next->pn_kid1, &filter))
  2513             return false;
  2514         next = next->pn_kid2;
  2515     } else if (next->isKind(PNK_STATEMENTLIST) && next->pn_count == 0) {
  2516         /* FoldConstants optimized away the push. */
  2517         NodeVector empty(cx);
  2518         return builder.arrayExpression(empty, &pn->pn_pos, dst);
  2521     LOCAL_ASSERT(next->isKind(PNK_ARRAYPUSH));
  2523     RootedValue body(cx);
  2525     return expression(next->pn_kid, &body) &&
  2526            builder.comprehensionExpression(body, blocks, filter, &pn->pn_pos, dst);
  2529 bool
  2530 ASTSerializer::generatorExpression(ParseNode *pn, MutableHandleValue dst)
  2532     LOCAL_ASSERT(pn->isKind(PNK_FOR));
  2534     NodeVector blocks(cx);
  2536     ParseNode *next = pn;
  2537     while (next->isKind(PNK_FOR)) {
  2538         RootedValue block(cx);
  2539         if (!comprehensionBlock(next, &block) || !blocks.append(block))
  2540             return false;
  2541         next = next->pn_right;
  2544     RootedValue filter(cx, MagicValue(JS_SERIALIZE_NO_NODE));
  2546     if (next->isKind(PNK_IF)) {
  2547         if (!optExpression(next->pn_kid1, &filter))
  2548             return false;
  2549         next = next->pn_kid2;
  2552     LOCAL_ASSERT(next->isKind(PNK_SEMI) &&
  2553                  next->pn_kid->isKind(PNK_YIELD) &&
  2554                  next->pn_kid->pn_kid);
  2556     RootedValue body(cx);
  2558     return expression(next->pn_kid->pn_kid, &body) &&
  2559            builder.generatorExpression(body, blocks, filter, &pn->pn_pos, dst);
  2562 bool
  2563 ASTSerializer::expression(ParseNode *pn, MutableHandleValue dst)
  2565     JS_CHECK_RECURSION(cx, return false);
  2566     switch (pn->getKind()) {
  2567       case PNK_FUNCTION:
  2569         ASTType type = pn->pn_funbox->function()->isArrow() ? AST_ARROW_EXPR : AST_FUNC_EXPR;
  2570         return function(pn, type, dst);
  2573       case PNK_COMMA:
  2575         NodeVector exprs(cx);
  2576         return expressions(pn, exprs) &&
  2577                builder.sequenceExpression(exprs, &pn->pn_pos, dst);
  2580       case PNK_CONDITIONAL:
  2582         JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
  2583         JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
  2584         JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
  2586         RootedValue test(cx), cons(cx), alt(cx);
  2588         return expression(pn->pn_kid1, &test) &&
  2589                expression(pn->pn_kid2, &cons) &&
  2590                expression(pn->pn_kid3, &alt) &&
  2591                builder.conditionalExpression(test, cons, alt, &pn->pn_pos, dst);
  2594       case PNK_OR:
  2595       case PNK_AND:
  2597         if (pn->isArity(PN_BINARY)) {
  2598             JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
  2599             JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
  2601             RootedValue left(cx), right(cx);
  2602             return expression(pn->pn_left, &left) &&
  2603                    expression(pn->pn_right, &right) &&
  2604                    builder.logicalExpression(pn->isKind(PNK_OR), left, right, &pn->pn_pos, dst);
  2606         return leftAssociate(pn, dst);
  2609       case PNK_PREINCREMENT:
  2610       case PNK_PREDECREMENT:
  2612         JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
  2614         bool inc = pn->isKind(PNK_PREINCREMENT);
  2615         RootedValue expr(cx);
  2616         return expression(pn->pn_kid, &expr) &&
  2617                builder.updateExpression(expr, inc, true, &pn->pn_pos, dst);
  2620       case PNK_POSTINCREMENT:
  2621       case PNK_POSTDECREMENT:
  2623         JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
  2625         bool inc = pn->isKind(PNK_POSTINCREMENT);
  2626         RootedValue expr(cx);
  2627         return expression(pn->pn_kid, &expr) &&
  2628                builder.updateExpression(expr, inc, false, &pn->pn_pos, dst);
  2631       case PNK_ASSIGN:
  2632       case PNK_ADDASSIGN:
  2633       case PNK_SUBASSIGN:
  2634       case PNK_BITORASSIGN:
  2635       case PNK_BITXORASSIGN:
  2636       case PNK_BITANDASSIGN:
  2637       case PNK_LSHASSIGN:
  2638       case PNK_RSHASSIGN:
  2639       case PNK_URSHASSIGN:
  2640       case PNK_MULASSIGN:
  2641       case PNK_DIVASSIGN:
  2642       case PNK_MODASSIGN:
  2644         JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
  2645         JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
  2647         AssignmentOperator op = aop(pn->getOp());
  2648         LOCAL_ASSERT(op > AOP_ERR && op < AOP_LIMIT);
  2650         RootedValue lhs(cx), rhs(cx);
  2651         return pattern(pn->pn_left, nullptr, &lhs) &&
  2652                expression(pn->pn_right, &rhs) &&
  2653                builder.assignmentExpression(op, lhs, rhs, &pn->pn_pos, dst);
  2656       case PNK_ADD:
  2657       case PNK_SUB:
  2658       case PNK_STRICTEQ:
  2659       case PNK_EQ:
  2660       case PNK_STRICTNE:
  2661       case PNK_NE:
  2662       case PNK_LT:
  2663       case PNK_LE:
  2664       case PNK_GT:
  2665       case PNK_GE:
  2666       case PNK_LSH:
  2667       case PNK_RSH:
  2668       case PNK_URSH:
  2669       case PNK_STAR:
  2670       case PNK_DIV:
  2671       case PNK_MOD:
  2672       case PNK_BITOR:
  2673       case PNK_BITXOR:
  2674       case PNK_BITAND:
  2675       case PNK_IN:
  2676       case PNK_INSTANCEOF:
  2677         if (pn->isArity(PN_BINARY)) {
  2678             JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
  2679             JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
  2681             BinaryOperator op = binop(pn->getKind(), pn->getOp());
  2682             LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
  2684             RootedValue left(cx), right(cx);
  2685             return expression(pn->pn_left, &left) &&
  2686                    expression(pn->pn_right, &right) &&
  2687                    builder.binaryExpression(op, left, right, &pn->pn_pos, dst);
  2689         return leftAssociate(pn, dst);
  2691       case PNK_DELETE:
  2692       case PNK_TYPEOF:
  2693       case PNK_VOID:
  2694       case PNK_NOT:
  2695       case PNK_BITNOT:
  2696       case PNK_POS:
  2697       case PNK_NEG: {
  2698         JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
  2700         UnaryOperator op = unop(pn->getKind(), pn->getOp());
  2701         LOCAL_ASSERT(op > UNOP_ERR && op < UNOP_LIMIT);
  2703         RootedValue expr(cx);
  2704         return expression(pn->pn_kid, &expr) &&
  2705                builder.unaryExpression(op, expr, &pn->pn_pos, dst);
  2708 #if JS_HAS_GENERATOR_EXPRS
  2709       case PNK_GENEXP:
  2710         return generatorExpression(pn->generatorExpr(), dst);
  2711 #endif
  2713       case PNK_NEW:
  2714       case PNK_CALL:
  2716         ParseNode *next = pn->pn_head;
  2717         JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
  2719         RootedValue callee(cx);
  2720         if (!expression(next, &callee))
  2721             return false;
  2723         NodeVector args(cx);
  2724         if (!args.reserve(pn->pn_count - 1))
  2725             return false;
  2727         for (next = next->pn_next; next; next = next->pn_next) {
  2728             JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
  2730             RootedValue arg(cx);
  2731             if (!expression(next, &arg))
  2732                 return false;
  2733             args.infallibleAppend(arg);
  2736         return pn->isKind(PNK_NEW)
  2737                ? builder.newExpression(callee, args, &pn->pn_pos, dst)
  2739             : builder.callExpression(callee, args, &pn->pn_pos, dst);
  2742       case PNK_DOT:
  2744         JS_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
  2746         RootedValue expr(cx), id(cx);
  2747         RootedAtom pnAtom(cx, pn->pn_atom);
  2748         return expression(pn->pn_expr, &expr) &&
  2749                identifier(pnAtom, nullptr, &id) &&
  2750                builder.memberExpression(false, expr, id, &pn->pn_pos, dst);
  2753       case PNK_ELEM:
  2755         JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
  2756         JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
  2758         RootedValue left(cx), right(cx);
  2759         return expression(pn->pn_left, &left) &&
  2760                expression(pn->pn_right, &right) &&
  2761                builder.memberExpression(true, left, right, &pn->pn_pos, dst);
  2764       case PNK_ARRAY:
  2766         NodeVector elts(cx);
  2767         if (!elts.reserve(pn->pn_count))
  2768             return false;
  2770         for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
  2771             JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
  2773             if (next->isKind(PNK_ELISION)) {
  2774                 elts.infallibleAppend(NullValue());
  2775             } else {
  2776                 RootedValue expr(cx);
  2777                 if (!expression(next, &expr))
  2778                     return false;
  2779                 elts.infallibleAppend(expr);
  2783         return builder.arrayExpression(elts, &pn->pn_pos, dst);
  2786       case PNK_SPREAD:
  2788           RootedValue expr(cx);
  2789           return expression(pn->pn_kid, &expr) &&
  2790                  builder.spreadExpression(expr, &pn->pn_pos, dst);
  2793       case PNK_OBJECT:
  2795         /* The parser notes any uninitialized properties by setting the PNX_DESTRUCT flag. */
  2796         if (pn->pn_xflags & PNX_DESTRUCT) {
  2797             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_OBJECT_INIT);
  2798             return false;
  2800         NodeVector elts(cx);
  2801         if (!elts.reserve(pn->pn_count))
  2802             return false;
  2804         for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
  2805             JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
  2807             RootedValue prop(cx);
  2808             if (!property(next, &prop))
  2809                 return false;
  2810             elts.infallibleAppend(prop);
  2813         return builder.objectExpression(elts, &pn->pn_pos, dst);
  2816       case PNK_NAME:
  2817         return identifier(pn, dst);
  2819       case PNK_THIS:
  2820         return builder.thisExpression(&pn->pn_pos, dst);
  2822       case PNK_STRING:
  2823       case PNK_REGEXP:
  2824       case PNK_NUMBER:
  2825       case PNK_TRUE:
  2826       case PNK_FALSE:
  2827       case PNK_NULL:
  2828         return literal(pn, dst);
  2830       case PNK_YIELD_STAR:
  2832         JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
  2834         RootedValue arg(cx);
  2835         return expression(pn->pn_kid, &arg) &&
  2836                builder.yieldExpression(arg, Delegating, &pn->pn_pos, dst);
  2839       case PNK_YIELD:
  2841         JS_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
  2843         RootedValue arg(cx);
  2844         return optExpression(pn->pn_kid, &arg) &&
  2845                builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst);
  2848       case PNK_ARRAYCOMP:
  2849         JS_ASSERT(pn->pn_pos.encloses(pn->pn_head->pn_pos));
  2851         /* NB: it's no longer the case that pn_count could be 2. */
  2852         LOCAL_ASSERT(pn->pn_count == 1);
  2853         LOCAL_ASSERT(pn->pn_head->isKind(PNK_LEXICALSCOPE));
  2855         return comprehension(pn->pn_head->pn_expr, dst);
  2857       case PNK_LET:
  2858         return let(pn, true, dst);
  2860       default:
  2861         LOCAL_NOT_REACHED("unexpected expression type");
  2865 bool
  2866 ASTSerializer::propertyName(ParseNode *pn, MutableHandleValue dst)
  2868     if (pn->isKind(PNK_NAME))
  2869         return identifier(pn, dst);
  2871     LOCAL_ASSERT(pn->isKind(PNK_STRING) || pn->isKind(PNK_NUMBER));
  2873     return literal(pn, dst);
  2876 bool
  2877 ASTSerializer::property(ParseNode *pn, MutableHandleValue dst)
  2879     PropKind kind;
  2880     switch (pn->getOp()) {
  2881       case JSOP_INITPROP:
  2882         kind = PROP_INIT;
  2883         break;
  2885       case JSOP_INITPROP_GETTER:
  2886         kind = PROP_GETTER;
  2887         break;
  2889       case JSOP_INITPROP_SETTER:
  2890         kind = PROP_SETTER;
  2891         break;
  2893       default:
  2894         LOCAL_NOT_REACHED("unexpected object-literal property");
  2897     RootedValue key(cx), val(cx);
  2898     return propertyName(pn->pn_left, &key) &&
  2899            expression(pn->pn_right, &val) &&
  2900            builder.propertyInitializer(key, val, kind, &pn->pn_pos, dst);
  2903 bool
  2904 ASTSerializer::literal(ParseNode *pn, MutableHandleValue dst)
  2906     RootedValue val(cx);
  2907     switch (pn->getKind()) {
  2908       case PNK_STRING:
  2909         val.setString(pn->pn_atom);
  2910         break;
  2912       case PNK_REGEXP:
  2914         RootedObject re1(cx, pn->as<RegExpLiteral>().objbox()->object);
  2915         LOCAL_ASSERT(re1 && re1->is<RegExpObject>());
  2917         RootedObject re2(cx, CloneRegExpObject(cx, re1));
  2918         if (!re2)
  2919             return false;
  2921         val.setObject(*re2);
  2922         break;
  2925       case PNK_NUMBER:
  2926         val.setNumber(pn->pn_dval);
  2927         break;
  2929       case PNK_NULL:
  2930         val.setNull();
  2931         break;
  2933       case PNK_TRUE:
  2934         val.setBoolean(true);
  2935         break;
  2937       case PNK_FALSE:
  2938         val.setBoolean(false);
  2939         break;
  2941       default:
  2942         LOCAL_NOT_REACHED("unexpected literal type");
  2945     return builder.literal(val, &pn->pn_pos, dst);
  2948 bool
  2949 ASTSerializer::arrayPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst)
  2951     JS_ASSERT(pn->isKind(PNK_ARRAY));
  2953     NodeVector elts(cx);
  2954     if (!elts.reserve(pn->pn_count))
  2955         return false;
  2957     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
  2958         if (next->isKind(PNK_ELISION)) {
  2959             elts.infallibleAppend(NullValue());
  2960         } else {
  2961             RootedValue patt(cx);
  2962             if (!pattern(next, pkind, &patt))
  2963                 return false;
  2964             elts.infallibleAppend(patt);
  2968     return builder.arrayPattern(elts, &pn->pn_pos, dst);
  2971 bool
  2972 ASTSerializer::objectPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst)
  2974     JS_ASSERT(pn->isKind(PNK_OBJECT));
  2976     NodeVector elts(cx);
  2977     if (!elts.reserve(pn->pn_count))
  2978         return false;
  2980     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
  2981         LOCAL_ASSERT(next->isOp(JSOP_INITPROP));
  2983         RootedValue key(cx), patt(cx), prop(cx);
  2984         if (!propertyName(next->pn_left, &key) ||
  2985             !pattern(next->pn_right, pkind, &patt) ||
  2986             !builder.propertyPattern(key, patt, &next->pn_pos, &prop)) {
  2987             return false;
  2990         elts.infallibleAppend(prop);
  2993     return builder.objectPattern(elts, &pn->pn_pos, dst);
  2996 bool
  2997 ASTSerializer::pattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst)
  2999     JS_CHECK_RECURSION(cx, return false);
  3000     switch (pn->getKind()) {
  3001       case PNK_OBJECT:
  3002         return objectPattern(pn, pkind, dst);
  3004       case PNK_ARRAY:
  3005         return arrayPattern(pn, pkind, dst);
  3007       case PNK_NAME:
  3008         if (pkind && (pn->pn_dflags & PND_CONST))
  3009             *pkind = VARDECL_CONST;
  3010         /* FALL THROUGH */
  3012       default:
  3013         return expression(pn, dst);
  3017 bool
  3018 ASTSerializer::identifier(HandleAtom atom, TokenPos *pos, MutableHandleValue dst)
  3020     RootedValue atomContentsVal(cx, unrootedAtomContents(atom));
  3021     return builder.identifier(atomContentsVal, pos, dst);
  3024 bool
  3025 ASTSerializer::identifier(ParseNode *pn, MutableHandleValue dst)
  3027     LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_NULLARY));
  3028     LOCAL_ASSERT(pn->pn_atom);
  3030     RootedAtom pnAtom(cx, pn->pn_atom);
  3031     return identifier(pnAtom, &pn->pn_pos, dst);
  3034 bool
  3035 ASTSerializer::function(ParseNode *pn, ASTType type, MutableHandleValue dst)
  3037     RootedFunction func(cx, pn->pn_funbox->function());
  3039     // FIXME: Provide more information (legacy generator vs star generator).
  3040     bool isGenerator = pn->pn_funbox->isGenerator();
  3042     bool isExpression =
  3043 #if JS_HAS_EXPR_CLOSURES
  3044         func->isExprClosure();
  3045 #else
  3046         false;
  3047 #endif
  3049     RootedValue id(cx);
  3050     RootedAtom funcAtom(cx, func->atom());
  3051     if (!optIdentifier(funcAtom, nullptr, &id))
  3052         return false;
  3054     NodeVector args(cx);
  3055     NodeVector defaults(cx);
  3057     RootedValue body(cx), rest(cx);
  3058     if (func->hasRest())
  3059         rest.setUndefined();
  3060     else
  3061         rest.setNull();
  3062     return functionArgsAndBody(pn->pn_body, args, defaults, &body, &rest) &&
  3063         builder.function(type, &pn->pn_pos, id, args, defaults, body,
  3064                          rest, isGenerator, isExpression, dst);
  3067 bool
  3068 ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, NodeVector &defaults,
  3069                                    MutableHandleValue body, MutableHandleValue rest)
  3071     ParseNode *pnargs;
  3072     ParseNode *pnbody;
  3074     /* Extract the args and body separately. */
  3075     if (pn->isKind(PNK_ARGSBODY)) {
  3076         pnargs = pn;
  3077         pnbody = pn->last();
  3078     } else {
  3079         pnargs = nullptr;
  3080         pnbody = pn;
  3083     ParseNode *pndestruct;
  3085     /* Extract the destructuring assignments. */
  3086     if (pnbody->isArity(PN_LIST) && (pnbody->pn_xflags & PNX_DESTRUCT)) {
  3087         ParseNode *head = pnbody->pn_head;
  3088         LOCAL_ASSERT(head && head->isKind(PNK_SEMI));
  3090         pndestruct = head->pn_kid;
  3091         LOCAL_ASSERT(pndestruct);
  3092         LOCAL_ASSERT(pndestruct->isKind(PNK_VAR));
  3093     } else {
  3094         pndestruct = nullptr;
  3097     /* Serialize the arguments and body. */
  3098     switch (pnbody->getKind()) {
  3099       case PNK_RETURN: /* expression closure, no destructured args */
  3100         return functionArgs(pn, pnargs, nullptr, pnbody, args, defaults, rest) &&
  3101                expression(pnbody->pn_kid, body);
  3103       case PNK_SEQ:    /* expression closure with destructured args */
  3105         ParseNode *pnstart = pnbody->pn_head->pn_next;
  3106         LOCAL_ASSERT(pnstart && pnstart->isKind(PNK_RETURN));
  3108         return functionArgs(pn, pnargs, pndestruct, pnbody, args, defaults, rest) &&
  3109                expression(pnstart->pn_kid, body);
  3112       case PNK_STATEMENTLIST:     /* statement closure */
  3114         ParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT)
  3115                                ? pnbody->pn_head->pn_next
  3116                                : pnbody->pn_head;
  3118         return functionArgs(pn, pnargs, pndestruct, pnbody, args, defaults, rest) &&
  3119                functionBody(pnstart, &pnbody->pn_pos, body);
  3122       default:
  3123         LOCAL_NOT_REACHED("unexpected function contents");
  3127 bool
  3128 ASTSerializer::functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct,
  3129                             ParseNode *pnbody, NodeVector &args, NodeVector &defaults,
  3130                             MutableHandleValue rest)
  3132     uint32_t i = 0;
  3133     ParseNode *arg = pnargs ? pnargs->pn_head : nullptr;
  3134     ParseNode *destruct = pndestruct ? pndestruct->pn_head : nullptr;
  3135     RootedValue node(cx);
  3137     /*
  3138      * Arguments are found in potentially two different places: 1) the
  3139      * argsbody sequence (which ends with the body node), or 2) a
  3140      * destructuring initialization at the beginning of the body. Loop
  3141      * |arg| through the argsbody and |destruct| through the initial
  3142      * destructuring assignments, stopping only when we've exhausted
  3143      * both.
  3144      */
  3145     while ((arg && arg != pnbody) || destruct) {
  3146         if (destruct && destruct->pn_right->frameSlot() == i) {
  3147             if (!pattern(destruct->pn_left, nullptr, &node) || !args.append(node))
  3148                 return false;
  3149             destruct = destruct->pn_next;
  3150         } else if (arg && arg != pnbody) {
  3151             /*
  3152              * We don't check that arg->frameSlot() == i since we
  3153              * can't call that method if the arg def has been turned
  3154              * into a use, e.g.:
  3156              *     function(a) { function a() { } }
  3158              * There's no other way to ask a non-destructuring arg its
  3159              * index in the formals list, so we rely on the ability to
  3160              * ask destructuring args their index above.
  3161              */
  3162             JS_ASSERT(arg->isKind(PNK_NAME) || arg->isKind(PNK_ASSIGN));
  3163             ParseNode *argName = arg->isKind(PNK_NAME) ? arg : arg->pn_left;
  3164             if (!identifier(argName, &node))
  3165                 return false;
  3166             if (rest.isUndefined() && arg->pn_next == pnbody)
  3167                 rest.setObject(node.toObject());
  3168             else if (!args.append(node))
  3169                 return false;
  3170             if (arg->pn_dflags & PND_DEFAULT) {
  3171                 ParseNode *expr = arg->isDefn() ? arg->expr() : arg->pn_kid->pn_right;
  3172                 RootedValue def(cx);
  3173                 if (!expression(expr, &def) || !defaults.append(def))
  3174                     return false;
  3176             arg = arg->pn_next;
  3177         } else {
  3178             LOCAL_NOT_REACHED("missing function argument");
  3180         ++i;
  3182     JS_ASSERT(!rest.isUndefined());
  3184     return true;
  3187 bool
  3188 ASTSerializer::functionBody(ParseNode *pn, TokenPos *pos, MutableHandleValue dst)
  3190     NodeVector elts(cx);
  3192     /* We aren't sure how many elements there are up front, so we'll check each append. */
  3193     for (ParseNode *next = pn; next; next = next->pn_next) {
  3194         RootedValue child(cx);
  3195         if (!sourceElement(next, &child) || !elts.append(child))
  3196             return false;
  3199     return builder.blockStatement(elts, pos, dst);
  3202 static bool
  3203 reflect_parse(JSContext *cx, uint32_t argc, jsval *vp)
  3205     CallArgs args = CallArgsFromVp(argc, vp);
  3207     if (args.length() < 1) {
  3208         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
  3209                              "Reflect.parse", "0", "s");
  3210         return false;
  3213     RootedString src(cx, ToString<CanGC>(cx, args[0]));
  3214     if (!src)
  3215         return false;
  3217     ScopedJSFreePtr<char> filename;
  3218     uint32_t lineno = 1;
  3219     bool loc = true;
  3221     RootedObject builder(cx);
  3223     RootedValue arg(cx, args.get(1));
  3225     if (!arg.isNullOrUndefined()) {
  3226         if (!arg.isObject()) {
  3227             js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
  3228                                      JSDVG_SEARCH_STACK, arg, js::NullPtr(),
  3229                                      "not an object", nullptr);
  3230             return false;
  3233         RootedObject config(cx, &arg.toObject());
  3235         RootedValue prop(cx);
  3237         /* config.loc */
  3238         RootedId locId(cx, NameToId(cx->names().loc));
  3239         RootedValue trueVal(cx, BooleanValue(true));
  3240         if (!GetPropertyDefault(cx, config, locId, trueVal, &prop))
  3241             return false;
  3243         loc = ToBoolean(prop);
  3245         if (loc) {
  3246             /* config.source */
  3247             RootedId sourceId(cx, NameToId(cx->names().source));
  3248             RootedValue nullVal(cx, NullValue());
  3249             if (!GetPropertyDefault(cx, config, sourceId, nullVal, &prop))
  3250                 return false;
  3252             if (!prop.isNullOrUndefined()) {
  3253                 RootedString str(cx, ToString<CanGC>(cx, prop));
  3254                 if (!str)
  3255                     return false;
  3257                 size_t length = str->length();
  3258                 const jschar *chars = str->getChars(cx);
  3259                 if (!chars)
  3260                     return false;
  3262                 TwoByteChars tbchars(chars, length);
  3263                 filename = LossyTwoByteCharsToNewLatin1CharsZ(cx, tbchars).c_str();
  3264                 if (!filename)
  3265                     return false;
  3268             /* config.line */
  3269             RootedId lineId(cx, NameToId(cx->names().line));
  3270             RootedValue oneValue(cx, Int32Value(1));
  3271             if (!GetPropertyDefault(cx, config, lineId, oneValue, &prop) ||
  3272                 !ToUint32(cx, prop, &lineno)) {
  3273                 return false;
  3277         /* config.builder */
  3278         RootedId builderId(cx, NameToId(cx->names().builder));
  3279         RootedValue nullVal(cx, NullValue());
  3280         if (!GetPropertyDefault(cx, config, builderId, nullVal, &prop))
  3281             return false;
  3283         if (!prop.isNullOrUndefined()) {
  3284             if (!prop.isObject()) {
  3285                 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
  3286                                          JSDVG_SEARCH_STACK, prop, js::NullPtr(),
  3287                                          "not an object", nullptr);
  3288                 return false;
  3290             builder = &prop.toObject();
  3294     /* Extract the builder methods first to report errors before parsing. */
  3295     ASTSerializer serialize(cx, loc, filename, lineno);
  3296     if (!serialize.init(builder))
  3297         return false;
  3299     JSFlatString *flat = src->ensureFlat(cx);
  3300     if (!flat)
  3301         return false;
  3303     CompileOptions options(cx);
  3304     options.setFileAndLine(filename, lineno);
  3305     options.setCanLazilyParse(false);
  3306     Parser<FullParseHandler> parser(cx, &cx->tempLifoAlloc(), options, flat->chars(),
  3307                                     flat->length(), /* foldConstants = */ false, nullptr, nullptr);
  3309     serialize.setParser(&parser);
  3311     ParseNode *pn = parser.parse(nullptr);
  3312     if (!pn)
  3313         return false;
  3315     RootedValue val(cx);
  3316     if (!serialize.program(pn, &val)) {
  3317         args.rval().setNull();
  3318         return false;
  3321     args.rval().set(val);
  3322     return true;
  3325 JS_PUBLIC_API(JSObject *)
  3326 JS_InitReflect(JSContext *cx, HandleObject obj)
  3328     static const JSFunctionSpec static_methods[] = {
  3329         JS_FN("parse", reflect_parse, 1, 0),
  3330         JS_FS_END
  3331     };
  3333     RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx));
  3334     if (!proto)
  3335         return nullptr;
  3336     RootedObject Reflect(cx, NewObjectWithGivenProto(cx, &JSObject::class_, proto,
  3337                                                      obj, SingletonObject));
  3338     if (!Reflect)
  3339         return nullptr;
  3341     if (!JS_DefineProperty(cx, obj, "Reflect", Reflect, 0,
  3342                            JS_PropertyStub, JS_StrictPropertyStub)) {
  3343         return nullptr;
  3346     if (!JS_DefineFunctions(cx, Reflect, static_methods))
  3347         return nullptr;
  3349     return Reflect;

mercurial