LCOV - code coverage report
Current view: top level - js/src/builtin - ReflectParse.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1658 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 263 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : /* JS reflection package. */
       8             : 
       9             : #include "mozilla/ArrayUtils.h"
      10             : #include "mozilla/DebugOnly.h"
      11             : #include "mozilla/Move.h"
      12             : 
      13             : #include <stdlib.h>
      14             : 
      15             : #include "jsarray.h"
      16             : #include "jsatom.h"
      17             : #include "jsobj.h"
      18             : #include "jspubtd.h"
      19             : 
      20             : #include "builtin/Reflect.h"
      21             : #include "frontend/Parser.h"
      22             : #include "frontend/TokenStream.h"
      23             : #include "js/CharacterEncoding.h"
      24             : #include "vm/RegExpObject.h"
      25             : 
      26             : #include "jsobjinlines.h"
      27             : 
      28             : #include "frontend/ParseNode-inl.h"
      29             : 
      30             : using namespace js;
      31             : using namespace js::frontend;
      32             : 
      33             : using JS::AutoValueArray;
      34             : using mozilla::ArrayLength;
      35             : using mozilla::DebugOnly;
      36             : using mozilla::Forward;
      37             : 
      38             : enum class ParseTarget
      39             : {
      40             :     Script,
      41             :     Module
      42             : };
      43             : 
      44             : enum ASTType {
      45             :     AST_ERROR = -1,
      46             : #define ASTDEF(ast, str, method) ast,
      47             : #include "jsast.tbl"
      48             : #undef ASTDEF
      49             :     AST_LIMIT
      50             : };
      51             : 
      52             : enum AssignmentOperator {
      53             :     AOP_ERR = -1,
      54             : 
      55             :     /* assign */
      56             :     AOP_ASSIGN = 0,
      57             :     /* operator-assign */
      58             :     AOP_PLUS, AOP_MINUS, AOP_STAR, AOP_DIV, AOP_MOD, AOP_POW,
      59             :     /* shift-assign */
      60             :     AOP_LSH, AOP_RSH, AOP_URSH,
      61             :     /* binary */
      62             :     AOP_BITOR, AOP_BITXOR, AOP_BITAND,
      63             : 
      64             :     AOP_LIMIT
      65             : };
      66             : 
      67             : enum BinaryOperator {
      68             :     BINOP_ERR = -1,
      69             : 
      70             :     /* eq */
      71             :     BINOP_EQ = 0, BINOP_NE, BINOP_STRICTEQ, BINOP_STRICTNE,
      72             :     /* rel */
      73             :     BINOP_LT, BINOP_LE, BINOP_GT, BINOP_GE,
      74             :     /* shift */
      75             :     BINOP_LSH, BINOP_RSH, BINOP_URSH,
      76             :     /* arithmetic */
      77             :     BINOP_ADD, BINOP_SUB, BINOP_STAR, BINOP_DIV, BINOP_MOD, BINOP_POW,
      78             :     /* binary */
      79             :     BINOP_BITOR, BINOP_BITXOR, BINOP_BITAND,
      80             :     /* misc */
      81             :     BINOP_IN, BINOP_INSTANCEOF,
      82             : 
      83             :     BINOP_LIMIT
      84             : };
      85             : 
      86             : enum UnaryOperator {
      87             :     UNOP_ERR = -1,
      88             : 
      89             :     UNOP_DELETE = 0,
      90             :     UNOP_NEG,
      91             :     UNOP_POS,
      92             :     UNOP_NOT,
      93             :     UNOP_BITNOT,
      94             :     UNOP_TYPEOF,
      95             :     UNOP_VOID,
      96             :     UNOP_AWAIT,
      97             : 
      98             :     UNOP_LIMIT
      99             : };
     100             : 
     101             : enum VarDeclKind {
     102             :     VARDECL_ERR = -1,
     103             :     VARDECL_VAR = 0,
     104             :     VARDECL_CONST,
     105             :     VARDECL_LET,
     106             :     VARDECL_LIMIT
     107             : };
     108             : 
     109             : enum PropKind {
     110             :     PROP_ERR = -1,
     111             :     PROP_INIT = 0,
     112             :     PROP_GETTER,
     113             :     PROP_SETTER,
     114             :     PROP_MUTATEPROTO,
     115             :     PROP_LIMIT
     116             : };
     117             : 
     118             : static const char* const aopNames[] = {
     119             :     "=",    /* AOP_ASSIGN */
     120             :     "+=",   /* AOP_PLUS */
     121             :     "-=",   /* AOP_MINUS */
     122             :     "*=",   /* AOP_STAR */
     123             :     "/=",   /* AOP_DIV */
     124             :     "%=",   /* AOP_MOD */
     125             :     "**=",  /* AOP_POW */
     126             :     "<<=",  /* AOP_LSH */
     127             :     ">>=",  /* AOP_RSH */
     128             :     ">>>=", /* AOP_URSH */
     129             :     "|=",   /* AOP_BITOR */
     130             :     "^=",   /* AOP_BITXOR */
     131             :     "&="    /* AOP_BITAND */
     132             : };
     133             : 
     134             : static const char* const binopNames[] = {
     135             :     "==",         /* BINOP_EQ */
     136             :     "!=",         /* BINOP_NE */
     137             :     "===",        /* BINOP_STRICTEQ */
     138             :     "!==",        /* BINOP_STRICTNE */
     139             :     "<",          /* BINOP_LT */
     140             :     "<=",         /* BINOP_LE */
     141             :     ">",          /* BINOP_GT */
     142             :     ">=",         /* BINOP_GE */
     143             :     "<<",         /* BINOP_LSH */
     144             :     ">>",         /* BINOP_RSH */
     145             :     ">>>",        /* BINOP_URSH */
     146             :     "+",          /* BINOP_PLUS */
     147             :     "-",          /* BINOP_MINUS */
     148             :     "*",          /* BINOP_STAR */
     149             :     "/",          /* BINOP_DIV */
     150             :     "%",          /* BINOP_MOD */
     151             :     "**",         /* BINOP_POW */
     152             :     "|",          /* BINOP_BITOR */
     153             :     "^",          /* BINOP_BITXOR */
     154             :     "&",          /* BINOP_BITAND */
     155             :     "in",         /* BINOP_IN */
     156             :     "instanceof", /* BINOP_INSTANCEOF */
     157             : };
     158             : 
     159             : static const char* const unopNames[] = {
     160             :     "delete",  /* UNOP_DELETE */
     161             :     "-",       /* UNOP_NEG */
     162             :     "+",       /* UNOP_POS */
     163             :     "!",       /* UNOP_NOT */
     164             :     "~",       /* UNOP_BITNOT */
     165             :     "typeof",  /* UNOP_TYPEOF */
     166             :     "void",    /* UNOP_VOID */
     167             :     "await"    /* UNOP_AWAIT */
     168             : };
     169             : 
     170             : static const char* const nodeTypeNames[] = {
     171             : #define ASTDEF(ast, str, method) str,
     172             : #include "jsast.tbl"
     173             : #undef ASTDEF
     174             :     nullptr
     175             : };
     176             : 
     177             : static const char* const callbackNames[] = {
     178             : #define ASTDEF(ast, str, method) method,
     179             : #include "jsast.tbl"
     180             : #undef ASTDEF
     181             :     nullptr
     182             : };
     183             : 
     184             : enum YieldKind { Delegating, NotDelegating };
     185             : 
     186             : typedef AutoValueVector NodeVector;
     187             : 
     188             : /*
     189             :  * ParseNode is a somewhat intricate data structure, and its invariants have
     190             :  * evolved, making it more likely that there could be a disconnect between the
     191             :  * parser and the AST serializer. We use these macros to check invariants on a
     192             :  * parse node and raise a dynamic error on failure.
     193             :  */
     194             : #define LOCAL_ASSERT(expr)                                                                \
     195             :     JS_BEGIN_MACRO                                                                        \
     196             :         MOZ_ASSERT(expr);                                                                 \
     197             :         if (!(expr)) {                                                                    \
     198             :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_PARSE_NODE);\
     199             :             return false;                                                                 \
     200             :         }                                                                                 \
     201             :     JS_END_MACRO
     202             : 
     203             : #define LOCAL_NOT_REACHED(expr)                                                           \
     204             :     JS_BEGIN_MACRO                                                                        \
     205             :         MOZ_ASSERT(false);                                                                \
     206             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_PARSE_NODE);    \
     207             :         return false;                                                                     \
     208             :     JS_END_MACRO
     209             : 
     210             : namespace {
     211             : 
     212             : /* Set 'result' to obj[id] if any such property exists, else defaultValue. */
     213             : static bool
     214           0 : GetPropertyDefault(JSContext* cx, HandleObject obj, HandleId id, HandleValue defaultValue,
     215             :                    MutableHandleValue result)
     216             : {
     217             :     bool found;
     218           0 :     if (!HasProperty(cx, obj, id, &found))
     219           0 :         return false;
     220           0 :     if (!found) {
     221           0 :         result.set(defaultValue);
     222           0 :         return true;
     223             :     }
     224           0 :     return GetProperty(cx, obj, obj, id, result);
     225             : }
     226             : 
     227             : enum class GeneratorStyle
     228             : {
     229             :     None,
     230             :     Legacy,
     231             :     ES6
     232             : };
     233             : 
     234             : /*
     235             :  * Builder class that constructs JavaScript AST node objects. See:
     236             :  *
     237             :  *     https://developer.mozilla.org/en/SpiderMonkey/Parser_API
     238             :  *
     239             :  * Bug 569487: generalize builder interface
     240             :  */
     241           0 : class NodeBuilder
     242             : {
     243             :     typedef AutoValueArray<AST_LIMIT> CallbackArray;
     244             : 
     245             :     JSContext*  cx;
     246             :     TokenStreamAnyChars* tokenStream;
     247             :     bool        saveLoc;               /* save source location information?     */
     248             :     char const* src;                  /* source filename or null               */
     249             :     RootedValue srcval;                /* source filename JS value or null      */
     250             :     CallbackArray callbacks;           /* user-specified callbacks              */
     251             :     RootedValue userv;                 /* user-specified builder object or null */
     252             : 
     253             :   public:
     254           0 :     NodeBuilder(JSContext* c, bool l, char const* s)
     255           0 :       : cx(c), tokenStream(nullptr), saveLoc(l), src(s), srcval(c), callbacks(cx),
     256           0 :           userv(c)
     257           0 :     {}
     258             : 
     259           0 :     MOZ_MUST_USE bool init(HandleObject userobj = nullptr) {
     260           0 :         if (src) {
     261           0 :             if (!atomValue(src, &srcval))
     262           0 :                 return false;
     263             :         } else {
     264           0 :             srcval.setNull();
     265             :         }
     266             : 
     267           0 :         if (!userobj) {
     268           0 :             userv.setNull();
     269           0 :             for (unsigned i = 0; i < AST_LIMIT; i++) {
     270           0 :                 callbacks[i].setNull();
     271             :             }
     272           0 :             return true;
     273             :         }
     274             : 
     275           0 :         userv.setObject(*userobj);
     276             : 
     277           0 :         RootedValue nullVal(cx, NullValue());
     278           0 :         RootedValue funv(cx);
     279           0 :         for (unsigned i = 0; i < AST_LIMIT; i++) {
     280           0 :             const char* name = callbackNames[i];
     281           0 :             RootedAtom atom(cx, Atomize(cx, name, strlen(name)));
     282           0 :             if (!atom)
     283           0 :                 return false;
     284           0 :             RootedId id(cx, AtomToId(atom));
     285           0 :             if (!GetPropertyDefault(cx, userobj, id, nullVal, &funv))
     286           0 :                 return false;
     287             : 
     288           0 :             if (funv.isNullOrUndefined()) {
     289           0 :                 callbacks[i].setNull();
     290           0 :                 continue;
     291             :             }
     292             : 
     293           0 :             if (!funv.isObject() || !funv.toObject().is<JSFunction>()) {
     294           0 :                 ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NOT_FUNCTION,
     295           0 :                                       JSDVG_SEARCH_STACK, funv, nullptr, nullptr, nullptr);
     296           0 :                 return false;
     297             :             }
     298             : 
     299           0 :             callbacks[i].set(funv);
     300             :         }
     301             : 
     302           0 :         return true;
     303             :     }
     304             : 
     305           0 :     void setTokenStream(TokenStreamAnyChars* ts) {
     306           0 :         tokenStream = ts;
     307           0 :     }
     308             : 
     309             :   private:
     310           0 :     MOZ_MUST_USE bool callbackHelper(HandleValue fun, const InvokeArgs& args, size_t i,
     311             :                                      TokenPos* pos, MutableHandleValue dst)
     312             :     {
     313             :         // The end of the implementation of callback(). All arguments except
     314             :         // loc have already been stored in range [0, i).
     315           0 :         if (saveLoc) {
     316           0 :             if (!newNodeLoc(pos, args[i]))
     317           0 :                 return false;
     318             :         }
     319             : 
     320           0 :         return js::Call(cx, fun, userv, args, dst);
     321             :     }
     322             : 
     323             :     // Helper function for callback(). Note that all Arguments must be types
     324             :     // that convert to HandleValue, so this isn't as template-y as it seems,
     325             :     // just variadic.
     326             :     template <typename... Arguments>
     327           0 :     MOZ_MUST_USE bool callbackHelper(HandleValue fun, const InvokeArgs& args, size_t i,
     328             :                                      HandleValue head, Arguments&&... tail)
     329             :     {
     330             :         // Recursive loop to store the arguments into args. This eventually
     331             :         // bottoms out in a call to the non-template callbackHelper() above.
     332           0 :         args[i].set(head);
     333           0 :         return callbackHelper(fun, args, i + 1, Forward<Arguments>(tail)...);
     334             :     }
     335             : 
     336             :     // Invoke a user-defined callback. The actual signature is:
     337             :     //
     338             :     //     bool callback(HandleValue fun, HandleValue... args, TokenPos* pos,
     339             :     //                   MutableHandleValue dst);
     340             :     template <typename... Arguments>
     341           0 :     MOZ_MUST_USE bool callback(HandleValue fun, Arguments&&... args) {
     342           0 :         InvokeArgs iargs(cx);
     343           0 :         if (!iargs.init(cx, sizeof...(args) - 2 + size_t(saveLoc)))
     344           0 :             return false;
     345             : 
     346           0 :         return callbackHelper(fun, iargs, 0, Forward<Arguments>(args)...);
     347             :     }
     348             : 
     349             :     // WARNING: Returning a Handle is non-standard, but it works in this case
     350             :     // because both |v| and |UndefinedHandleValue| are definitely rooted on a
     351             :     // previous stack frame (i.e. we're just choosing between two
     352             :     // already-rooted values).
     353           0 :     HandleValue opt(HandleValue v) {
     354           0 :         MOZ_ASSERT_IF(v.isMagic(), v.whyMagic() == JS_SERIALIZE_NO_NODE);
     355           0 :         return v.isMagic(JS_SERIALIZE_NO_NODE) ? JS::UndefinedHandleValue : v;
     356             :     }
     357             : 
     358           0 :     MOZ_MUST_USE bool atomValue(const char* s, MutableHandleValue dst) {
     359             :         /*
     360             :          * Bug 575416: instead of Atomize, lookup constant atoms in tbl file
     361             :          */
     362           0 :         RootedAtom atom(cx, Atomize(cx, s, strlen(s)));
     363           0 :         if (!atom)
     364           0 :             return false;
     365             : 
     366           0 :         dst.setString(atom);
     367           0 :         return true;
     368             :     }
     369             : 
     370           0 :     MOZ_MUST_USE bool newObject(MutableHandleObject dst) {
     371           0 :         RootedPlainObject nobj(cx, NewBuiltinClassInstance<PlainObject>(cx));
     372           0 :         if (!nobj)
     373           0 :             return false;
     374             : 
     375           0 :         dst.set(nobj);
     376           0 :         return true;
     377             :     }
     378             : 
     379             :     MOZ_MUST_USE bool newArray(NodeVector& elts, MutableHandleValue dst);
     380             : 
     381             :     MOZ_MUST_USE bool createNode(ASTType type, TokenPos* pos, MutableHandleObject dst);
     382             : 
     383           0 :     MOZ_MUST_USE bool newNodeHelper(HandleObject obj, MutableHandleValue dst) {
     384             :         // The end of the implementation of newNode().
     385           0 :         MOZ_ASSERT(obj);
     386           0 :         dst.setObject(*obj);
     387           0 :         return true;
     388             :     }
     389             : 
     390             :     template <typename... Arguments>
     391           0 :     MOZ_MUST_USE bool newNodeHelper(HandleObject obj, const char *name, HandleValue value,
     392             :                                     Arguments&&... rest)
     393             :     {
     394             :         // Recursive loop to define properties. Note that the newNodeHelper()
     395             :         // call below passes two fewer arguments than we received, as we omit
     396             :         // `name` and `value`. This eventually bottoms out in a call to the
     397             :         // non-template newNodeHelper() above.
     398           0 :         return defineProperty(obj, name, value)
     399           0 :                && newNodeHelper(obj, Forward<Arguments>(rest)...);
     400             :     }
     401             : 
     402             :     // Create a node object with "type" and "loc" properties, as well as zero
     403             :     // or more properties passed in as arguments. The signature is really more
     404             :     // like:
     405             :     //
     406             :     //     bool newNode(ASTType type, TokenPos* pos,
     407             :     //                  {const char *name0, HandleValue value0,}...
     408             :     //                  MutableHandleValue dst);
     409             :     template <typename... Arguments>
     410           0 :     MOZ_MUST_USE bool newNode(ASTType type, TokenPos* pos, Arguments&&... args) {
     411           0 :         RootedObject node(cx);
     412           0 :         return createNode(type, pos, &node) &&
     413           0 :                newNodeHelper(node, Forward<Arguments>(args)...);
     414             :     }
     415             : 
     416           0 :     MOZ_MUST_USE bool listNode(ASTType type, const char* propName, NodeVector& elts, TokenPos* pos,
     417             :                                MutableHandleValue dst) {
     418           0 :         RootedValue array(cx);
     419           0 :         if (!newArray(elts, &array))
     420           0 :             return false;
     421             : 
     422           0 :         RootedValue cb(cx, callbacks[type]);
     423           0 :         if (!cb.isNull())
     424           0 :             return callback(cb, array, pos, dst);
     425             : 
     426           0 :         return newNode(type, pos, propName, array, dst);
     427             :     }
     428             : 
     429           0 :     MOZ_MUST_USE bool defineProperty(HandleObject obj, const char* name, HandleValue val) {
     430           0 :         MOZ_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
     431             : 
     432             :         /*
     433             :          * Bug 575416: instead of Atomize, lookup constant atoms in tbl file
     434             :          */
     435           0 :         RootedAtom atom(cx, Atomize(cx, name, strlen(name)));
     436           0 :         if (!atom)
     437           0 :             return false;
     438             : 
     439             :         /* Represent "no node" as null and ensure users are not exposed to magic values. */
     440           0 :         RootedValue optVal(cx, val.isMagic(JS_SERIALIZE_NO_NODE) ? NullValue() : val);
     441           0 :         return DefineProperty(cx, obj, atom->asPropertyName(), optVal);
     442             :     }
     443             : 
     444             :     MOZ_MUST_USE bool newNodeLoc(TokenPos* pos, MutableHandleValue dst);
     445             : 
     446             :     MOZ_MUST_USE bool setNodeLoc(HandleObject node, TokenPos* pos);
     447             : 
     448             :   public:
     449             :     /*
     450             :      * All of the public builder methods take as their last two
     451             :      * arguments a nullable token position and a non-nullable, rooted
     452             :      * outparam.
     453             :      *
     454             :      * Any Value arguments representing optional subnodes may be a
     455             :      * JS_SERIALIZE_NO_NODE magic value.
     456             :      */
     457             : 
     458             :     /*
     459             :      * misc nodes
     460             :      */
     461             : 
     462             :     MOZ_MUST_USE bool program(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
     463             : 
     464             :     MOZ_MUST_USE bool literal(HandleValue val, TokenPos* pos, MutableHandleValue dst);
     465             : 
     466             :     MOZ_MUST_USE bool identifier(HandleValue name, TokenPos* pos, MutableHandleValue dst);
     467             : 
     468             :     MOZ_MUST_USE bool function(ASTType type, TokenPos* pos,
     469             :                                HandleValue id, NodeVector& args, NodeVector& defaults,
     470             :                                HandleValue body, HandleValue rest, GeneratorStyle generatorStyle,
     471             :                                bool isAsync, bool isExpression, MutableHandleValue dst);
     472             : 
     473             :     MOZ_MUST_USE bool variableDeclarator(HandleValue id, HandleValue init, TokenPos* pos,
     474             :                                          MutableHandleValue dst);
     475             : 
     476             :     MOZ_MUST_USE bool switchCase(HandleValue expr, NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
     477             : 
     478             :     MOZ_MUST_USE bool catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos* pos,
     479             :                                   MutableHandleValue dst);
     480             : 
     481             :     MOZ_MUST_USE bool prototypeMutation(HandleValue val, TokenPos* pos, MutableHandleValue dst);
     482             :     MOZ_MUST_USE bool propertyInitializer(HandleValue key, HandleValue val, PropKind kind,
     483             :                                           bool isShorthand, bool isMethod, TokenPos* pos,
     484             :                                           MutableHandleValue dst);
     485             : 
     486             : 
     487             :     /*
     488             :      * statements
     489             :      */
     490             : 
     491             :     MOZ_MUST_USE bool blockStatement(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
     492             : 
     493             :     MOZ_MUST_USE bool expressionStatement(HandleValue expr, TokenPos* pos, MutableHandleValue dst);
     494             : 
     495             :     MOZ_MUST_USE bool emptyStatement(TokenPos* pos, MutableHandleValue dst);
     496             : 
     497             :     MOZ_MUST_USE bool ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos* pos,
     498             :                      MutableHandleValue dst);
     499             : 
     500             :     MOZ_MUST_USE bool breakStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst);
     501             : 
     502             :     MOZ_MUST_USE bool continueStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst);
     503             : 
     504             :     MOZ_MUST_USE bool labeledStatement(HandleValue label, HandleValue stmt, TokenPos* pos,
     505             :                           MutableHandleValue dst);
     506             : 
     507             :     MOZ_MUST_USE bool throwStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst);
     508             : 
     509             :     MOZ_MUST_USE bool returnStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst);
     510             : 
     511             :     MOZ_MUST_USE bool forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt,
     512             :                       TokenPos* pos, MutableHandleValue dst);
     513             : 
     514             :     MOZ_MUST_USE bool forInStatement(HandleValue var, HandleValue expr, HandleValue stmt,
     515             :                                      bool isForEach, TokenPos* pos, MutableHandleValue dst);
     516             : 
     517             :     MOZ_MUST_USE bool forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos* pos,
     518             :                                      MutableHandleValue dst);
     519             : 
     520             :     MOZ_MUST_USE bool withStatement(HandleValue expr, HandleValue stmt, TokenPos* pos, MutableHandleValue dst);
     521             : 
     522             :     MOZ_MUST_USE bool whileStatement(HandleValue test, HandleValue stmt, TokenPos* pos, MutableHandleValue dst);
     523             : 
     524             :     MOZ_MUST_USE bool doWhileStatement(HandleValue stmt, HandleValue test, TokenPos* pos,
     525             :                                        MutableHandleValue dst);
     526             : 
     527             :     MOZ_MUST_USE bool switchStatement(HandleValue disc, NodeVector& elts, bool lexical, TokenPos* pos,
     528             :                                       MutableHandleValue dst);
     529             : 
     530             :     MOZ_MUST_USE bool tryStatement(HandleValue body, NodeVector& guarded, HandleValue unguarded,
     531             :                                    HandleValue finally, TokenPos* pos, MutableHandleValue dst);
     532             : 
     533             :     MOZ_MUST_USE bool debuggerStatement(TokenPos* pos, MutableHandleValue dst);
     534             : 
     535             :     MOZ_MUST_USE bool importDeclaration(NodeVector& elts, HandleValue moduleSpec, TokenPos* pos, MutableHandleValue dst);
     536             : 
     537             :     MOZ_MUST_USE bool importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos* pos, MutableHandleValue dst);
     538             : 
     539             :     MOZ_MUST_USE bool exportDeclaration(HandleValue decl, NodeVector& elts, HandleValue moduleSpec,
     540             :                                         HandleValue isDefault, TokenPos* pos, MutableHandleValue dst);
     541             : 
     542             :     MOZ_MUST_USE bool exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos* pos, MutableHandleValue dst);
     543             : 
     544             :     MOZ_MUST_USE bool exportBatchSpecifier(TokenPos* pos, MutableHandleValue dst);
     545             : 
     546             :     MOZ_MUST_USE bool classDefinition(bool expr, HandleValue name, HandleValue heritage,
     547             :                                       HandleValue block, TokenPos* pos, MutableHandleValue dst);
     548             :     MOZ_MUST_USE bool classMethods(NodeVector& methods, MutableHandleValue dst);
     549             :     MOZ_MUST_USE bool classMethod(HandleValue name, HandleValue body, PropKind kind, bool isStatic,
     550             :                                   TokenPos* pos, MutableHandleValue dst);
     551             : 
     552             :     /*
     553             :      * expressions
     554             :      */
     555             : 
     556             :     MOZ_MUST_USE bool binaryExpression(BinaryOperator op, HandleValue left, HandleValue right,
     557             :                                        TokenPos* pos, MutableHandleValue dst);
     558             : 
     559             :     MOZ_MUST_USE bool unaryExpression(UnaryOperator op, HandleValue expr, TokenPos* pos,
     560             :                                       MutableHandleValue dst);
     561             : 
     562             :     MOZ_MUST_USE bool assignmentExpression(AssignmentOperator op, HandleValue lhs, HandleValue rhs,
     563             :                                            TokenPos* pos, MutableHandleValue dst);
     564             : 
     565             :     MOZ_MUST_USE bool updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos* pos,
     566             :                                        MutableHandleValue dst);
     567             : 
     568             :     MOZ_MUST_USE bool logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos* pos,
     569             :                                         MutableHandleValue dst);
     570             : 
     571             :     MOZ_MUST_USE bool conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt,
     572             :                                             TokenPos* pos, MutableHandleValue dst);
     573             : 
     574             :     MOZ_MUST_USE bool sequenceExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
     575             : 
     576             :     MOZ_MUST_USE bool newExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
     577             :                                     MutableHandleValue dst);
     578             : 
     579             :     MOZ_MUST_USE bool callExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
     580             :                                      MutableHandleValue dst);
     581             : 
     582             :     MOZ_MUST_USE bool memberExpression(bool computed, HandleValue expr, HandleValue member,
     583             :                                        TokenPos* pos, MutableHandleValue dst);
     584             : 
     585             :     MOZ_MUST_USE bool arrayExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
     586             : 
     587             :     MOZ_MUST_USE bool templateLiteral(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
     588             : 
     589             :     MOZ_MUST_USE bool taggedTemplate(HandleValue callee, NodeVector& args, TokenPos* pos,
     590             :                                      MutableHandleValue dst);
     591             : 
     592             :     MOZ_MUST_USE bool callSiteObj(NodeVector& raw, NodeVector& cooked, TokenPos* pos,
     593             :                                   MutableHandleValue dst);
     594             : 
     595             :     MOZ_MUST_USE bool spreadExpression(HandleValue expr, TokenPos* pos, MutableHandleValue dst);
     596             : 
     597             :     MOZ_MUST_USE bool computedName(HandleValue name, TokenPos* pos, MutableHandleValue dst);
     598             : 
     599             :     MOZ_MUST_USE bool objectExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
     600             : 
     601             :     MOZ_MUST_USE bool thisExpression(TokenPos* pos, MutableHandleValue dst);
     602             : 
     603             :     MOZ_MUST_USE bool yieldExpression(HandleValue arg, YieldKind kind, TokenPos* pos,
     604             :                                       MutableHandleValue dst);
     605             : 
     606             :     MOZ_MUST_USE bool comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach,
     607             :                                          bool isForOf, TokenPos* pos, MutableHandleValue dst);
     608             :     MOZ_MUST_USE bool comprehensionIf(HandleValue test, TokenPos* pos, MutableHandleValue dst);
     609             : 
     610             :     MOZ_MUST_USE bool comprehensionExpression(HandleValue body, NodeVector& blocks,
     611             :                                               HandleValue filter, bool isLegacy, TokenPos* pos,
     612             :                                               MutableHandleValue dst);
     613             : 
     614             :     MOZ_MUST_USE bool generatorExpression(HandleValue body, NodeVector& blocks, HandleValue filter,
     615             :                                           bool isLegacy, TokenPos* pos, MutableHandleValue dst);
     616             : 
     617             :     MOZ_MUST_USE bool metaProperty(HandleValue meta, HandleValue property, TokenPos* pos,
     618             :                                    MutableHandleValue dst);
     619             : 
     620             :     MOZ_MUST_USE bool super(TokenPos* pos, MutableHandleValue dst);
     621             : 
     622             :     /*
     623             :      * declarations
     624             :      */
     625             : 
     626             :     MOZ_MUST_USE bool variableDeclaration(NodeVector& elts, VarDeclKind kind, TokenPos* pos,
     627             :                                           MutableHandleValue dst);
     628             : 
     629             :     /*
     630             :      * patterns
     631             :      */
     632             : 
     633             :     MOZ_MUST_USE bool arrayPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
     634             : 
     635             :     MOZ_MUST_USE bool objectPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
     636             : 
     637             :     MOZ_MUST_USE bool propertyPattern(HandleValue key, HandleValue patt, bool isShorthand,
     638             :                                       TokenPos* pos, MutableHandleValue dst);
     639             : };
     640             : 
     641             : } /* anonymous namespace */
     642             : 
     643             : bool
     644           0 : NodeBuilder::createNode(ASTType type, TokenPos* pos, MutableHandleObject dst)
     645             : {
     646           0 :     MOZ_ASSERT(type > AST_ERROR && type < AST_LIMIT);
     647             : 
     648           0 :     RootedValue tv(cx);
     649           0 :     RootedPlainObject node(cx, NewBuiltinClassInstance<PlainObject>(cx));
     650           0 :     if (!node ||
     651           0 :         !setNodeLoc(node, pos) ||
     652           0 :         !atomValue(nodeTypeNames[type], &tv) ||
     653           0 :         !defineProperty(node, "type", tv)) {
     654           0 :         return false;
     655             :     }
     656             : 
     657           0 :     dst.set(node);
     658           0 :     return true;
     659             : }
     660             : 
     661             : bool
     662           0 : NodeBuilder::newArray(NodeVector& elts, MutableHandleValue dst)
     663             : {
     664           0 :     const size_t len = elts.length();
     665           0 :     if (len > UINT32_MAX) {
     666           0 :         ReportAllocationOverflow(cx);
     667           0 :         return false;
     668             :     }
     669           0 :     RootedObject array(cx, NewDenseFullyAllocatedArray(cx, uint32_t(len)));
     670           0 :     if (!array)
     671           0 :         return false;
     672             : 
     673           0 :     for (size_t i = 0; i < len; i++) {
     674           0 :         RootedValue val(cx, elts[i]);
     675             : 
     676           0 :         MOZ_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
     677             : 
     678             :         /* Represent "no node" as an array hole by not adding the value. */
     679           0 :         if (val.isMagic(JS_SERIALIZE_NO_NODE))
     680           0 :             continue;
     681             : 
     682           0 :         if (!DefineElement(cx, array, i, val))
     683           0 :             return false;
     684             :     }
     685             : 
     686           0 :     dst.setObject(*array);
     687           0 :     return true;
     688             : }
     689             : 
     690             : bool
     691           0 : NodeBuilder::newNodeLoc(TokenPos* pos, MutableHandleValue dst)
     692             : {
     693           0 :     if (!pos) {
     694           0 :         dst.setNull();
     695           0 :         return true;
     696             :     }
     697             : 
     698           0 :     RootedObject loc(cx);
     699           0 :     RootedObject to(cx);
     700           0 :     RootedValue val(cx);
     701             : 
     702           0 :     if (!newObject(&loc))
     703           0 :         return false;
     704             : 
     705           0 :     dst.setObject(*loc);
     706             : 
     707             :     uint32_t startLineNum, startColumnIndex;
     708             :     uint32_t endLineNum, endColumnIndex;
     709           0 :     tokenStream->srcCoords.lineNumAndColumnIndex(pos->begin, &startLineNum, &startColumnIndex);
     710           0 :     tokenStream->srcCoords.lineNumAndColumnIndex(pos->end, &endLineNum, &endColumnIndex);
     711             : 
     712           0 :     if (!newObject(&to))
     713           0 :         return false;
     714           0 :     val.setObject(*to);
     715           0 :     if (!defineProperty(loc, "start", val))
     716           0 :         return false;
     717           0 :     val.setNumber(startLineNum);
     718           0 :     if (!defineProperty(to, "line", val))
     719           0 :         return false;
     720           0 :     val.setNumber(startColumnIndex);
     721           0 :     if (!defineProperty(to, "column", val))
     722           0 :         return false;
     723             : 
     724           0 :     if (!newObject(&to))
     725           0 :         return false;
     726           0 :     val.setObject(*to);
     727           0 :     if (!defineProperty(loc, "end", val))
     728           0 :         return false;
     729           0 :     val.setNumber(endLineNum);
     730           0 :     if (!defineProperty(to, "line", val))
     731           0 :         return false;
     732           0 :     val.setNumber(endColumnIndex);
     733           0 :     if (!defineProperty(to, "column", val))
     734           0 :         return false;
     735             : 
     736           0 :     if (!defineProperty(loc, "source", srcval))
     737           0 :         return false;
     738             : 
     739           0 :     return true;
     740             : }
     741             : 
     742             : bool
     743           0 : NodeBuilder::setNodeLoc(HandleObject node, TokenPos* pos)
     744             : {
     745           0 :     if (!saveLoc) {
     746           0 :         RootedValue nullVal(cx, NullValue());
     747           0 :         return defineProperty(node, "loc", nullVal);
     748             :     }
     749             : 
     750           0 :     RootedValue loc(cx);
     751           0 :     return newNodeLoc(pos, &loc) &&
     752           0 :            defineProperty(node, "loc", loc);
     753             : }
     754             : 
     755             : bool
     756           0 : NodeBuilder::program(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
     757             : {
     758           0 :     return listNode(AST_PROGRAM, "body", elts, pos, dst);
     759             : }
     760             : 
     761             : bool
     762           0 : NodeBuilder::blockStatement(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
     763             : {
     764           0 :     return listNode(AST_BLOCK_STMT, "body", elts, pos, dst);
     765             : }
     766             : 
     767             : bool
     768           0 : NodeBuilder::expressionStatement(HandleValue expr, TokenPos* pos, MutableHandleValue dst)
     769             : {
     770           0 :     RootedValue cb(cx, callbacks[AST_EXPR_STMT]);
     771           0 :     if (!cb.isNull())
     772           0 :         return callback(cb, expr, pos, dst);
     773             : 
     774           0 :     return newNode(AST_EXPR_STMT, pos, "expression", expr, dst);
     775             : }
     776             : 
     777             : bool
     778           0 : NodeBuilder::emptyStatement(TokenPos* pos, MutableHandleValue dst)
     779             : {
     780           0 :     RootedValue cb(cx, callbacks[AST_EMPTY_STMT]);
     781           0 :     if (!cb.isNull())
     782           0 :         return callback(cb, pos, dst);
     783             : 
     784           0 :     return newNode(AST_EMPTY_STMT, pos, dst);
     785             : }
     786             : 
     787             : bool
     788           0 : NodeBuilder::ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos* pos,
     789             :                          MutableHandleValue dst)
     790             : {
     791           0 :     RootedValue cb(cx, callbacks[AST_IF_STMT]);
     792           0 :     if (!cb.isNull())
     793           0 :         return callback(cb, test, cons, opt(alt), pos, dst);
     794             : 
     795           0 :     return newNode(AST_IF_STMT, pos,
     796             :                    "test", test,
     797             :                    "consequent", cons,
     798             :                    "alternate", alt,
     799           0 :                    dst);
     800             : }
     801             : 
     802             : bool
     803           0 : NodeBuilder::breakStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst)
     804             : {
     805           0 :     RootedValue cb(cx, callbacks[AST_BREAK_STMT]);
     806           0 :     if (!cb.isNull())
     807           0 :         return callback(cb, opt(label), pos, dst);
     808             : 
     809           0 :     return newNode(AST_BREAK_STMT, pos, "label", label, dst);
     810             : }
     811             : 
     812             : bool
     813           0 : NodeBuilder::continueStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst)
     814             : {
     815           0 :     RootedValue cb(cx, callbacks[AST_CONTINUE_STMT]);
     816           0 :     if (!cb.isNull())
     817           0 :         return callback(cb, opt(label), pos, dst);
     818             : 
     819           0 :     return newNode(AST_CONTINUE_STMT, pos, "label", label, dst);
     820             : }
     821             : 
     822             : bool
     823           0 : NodeBuilder::labeledStatement(HandleValue label, HandleValue stmt, TokenPos* pos,
     824             :                               MutableHandleValue dst)
     825             : {
     826           0 :     RootedValue cb(cx, callbacks[AST_LAB_STMT]);
     827           0 :     if (!cb.isNull())
     828           0 :         return callback(cb, label, stmt, pos, dst);
     829             : 
     830           0 :     return newNode(AST_LAB_STMT, pos,
     831             :                    "label", label,
     832             :                    "body", stmt,
     833           0 :                    dst);
     834             : }
     835             : 
     836             : bool
     837           0 : NodeBuilder::throwStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst)
     838             : {
     839           0 :     RootedValue cb(cx, callbacks[AST_THROW_STMT]);
     840           0 :     if (!cb.isNull())
     841           0 :         return callback(cb, arg, pos, dst);
     842             : 
     843           0 :     return newNode(AST_THROW_STMT, pos, "argument", arg, dst);
     844             : }
     845             : 
     846             : bool
     847           0 : NodeBuilder::returnStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst)
     848             : {
     849           0 :     RootedValue cb(cx, callbacks[AST_RETURN_STMT]);
     850           0 :     if (!cb.isNull())
     851           0 :         return callback(cb, opt(arg), pos, dst);
     852             : 
     853           0 :     return newNode(AST_RETURN_STMT, pos, "argument", arg, dst);
     854             : }
     855             : 
     856             : bool
     857           0 : NodeBuilder::forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt,
     858             :                           TokenPos* pos, MutableHandleValue dst)
     859             : {
     860           0 :     RootedValue cb(cx, callbacks[AST_FOR_STMT]);
     861           0 :     if (!cb.isNull())
     862           0 :         return callback(cb, opt(init), opt(test), opt(update), stmt, pos, dst);
     863             : 
     864           0 :     return newNode(AST_FOR_STMT, pos,
     865             :                    "init", init,
     866             :                    "test", test,
     867             :                    "update", update,
     868             :                    "body", stmt,
     869           0 :                    dst);
     870             : }
     871             : 
     872             : bool
     873           0 : NodeBuilder::forInStatement(HandleValue var, HandleValue expr, HandleValue stmt, bool isForEach,
     874             :                             TokenPos* pos, MutableHandleValue dst)
     875             : {
     876           0 :     RootedValue isForEachVal(cx, BooleanValue(isForEach));
     877             : 
     878           0 :     RootedValue cb(cx, callbacks[AST_FOR_IN_STMT]);
     879           0 :     if (!cb.isNull())
     880           0 :         return callback(cb, var, expr, stmt, isForEachVal, pos, dst);
     881             : 
     882           0 :     return newNode(AST_FOR_IN_STMT, pos,
     883             :                    "left", var,
     884             :                    "right", expr,
     885             :                    "body", stmt,
     886             :                    "each", isForEachVal,
     887           0 :                    dst);
     888             : }
     889             : 
     890             : bool
     891           0 : NodeBuilder::forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos* pos,
     892             :                             MutableHandleValue dst)
     893             : {
     894           0 :     RootedValue cb(cx, callbacks[AST_FOR_OF_STMT]);
     895           0 :     if (!cb.isNull())
     896           0 :         return callback(cb, var, expr, stmt, pos, dst);
     897             : 
     898           0 :     return newNode(AST_FOR_OF_STMT, pos,
     899             :                    "left", var,
     900             :                    "right", expr,
     901             :                    "body", stmt,
     902           0 :                    dst);
     903             : }
     904             : 
     905             : bool
     906           0 : NodeBuilder::withStatement(HandleValue expr, HandleValue stmt, TokenPos* pos,
     907             :                            MutableHandleValue dst)
     908             : {
     909           0 :     RootedValue cb(cx, callbacks[AST_WITH_STMT]);
     910           0 :     if (!cb.isNull())
     911           0 :         return callback(cb, expr, stmt, pos, dst);
     912             : 
     913           0 :     return newNode(AST_WITH_STMT, pos,
     914             :                    "object", expr,
     915             :                    "body", stmt,
     916           0 :                    dst);
     917             : }
     918             : 
     919             : bool
     920           0 : NodeBuilder::whileStatement(HandleValue test, HandleValue stmt, TokenPos* pos,
     921             :                             MutableHandleValue dst)
     922             : {
     923           0 :     RootedValue cb(cx, callbacks[AST_WHILE_STMT]);
     924           0 :     if (!cb.isNull())
     925           0 :         return callback(cb, test, stmt, pos, dst);
     926             : 
     927           0 :     return newNode(AST_WHILE_STMT, pos,
     928             :                    "test", test,
     929             :                    "body", stmt,
     930           0 :                    dst);
     931             : }
     932             : 
     933             : bool
     934           0 : NodeBuilder::doWhileStatement(HandleValue stmt, HandleValue test, TokenPos* pos,
     935             :                               MutableHandleValue dst)
     936             : {
     937           0 :     RootedValue cb(cx, callbacks[AST_DO_STMT]);
     938           0 :     if (!cb.isNull())
     939           0 :         return callback(cb, stmt, test, pos, dst);
     940             : 
     941           0 :     return newNode(AST_DO_STMT, pos,
     942             :                    "body", stmt,
     943             :                    "test", test,
     944           0 :                    dst);
     945             : }
     946             : 
     947             : bool
     948           0 : NodeBuilder::switchStatement(HandleValue disc, NodeVector& elts, bool lexical, TokenPos* pos,
     949             :                              MutableHandleValue dst)
     950             : {
     951           0 :     RootedValue array(cx);
     952           0 :     if (!newArray(elts, &array))
     953           0 :         return false;
     954             : 
     955           0 :     RootedValue lexicalVal(cx, BooleanValue(lexical));
     956             : 
     957           0 :     RootedValue cb(cx, callbacks[AST_SWITCH_STMT]);
     958           0 :     if (!cb.isNull())
     959           0 :         return callback(cb, disc, array, lexicalVal, pos, dst);
     960             : 
     961           0 :     return newNode(AST_SWITCH_STMT, pos,
     962             :                    "discriminant", disc,
     963             :                    "cases", array,
     964             :                    "lexical", lexicalVal,
     965           0 :                    dst);
     966             : }
     967             : 
     968             : bool
     969           0 : NodeBuilder::tryStatement(HandleValue body, NodeVector& guarded, HandleValue unguarded,
     970             :                           HandleValue finally, TokenPos* pos, MutableHandleValue dst)
     971             : {
     972           0 :     RootedValue guardedHandlers(cx);
     973           0 :     if (!newArray(guarded, &guardedHandlers))
     974           0 :         return false;
     975             : 
     976           0 :     RootedValue cb(cx, callbacks[AST_TRY_STMT]);
     977           0 :     if (!cb.isNull())
     978           0 :         return callback(cb, body, guardedHandlers, unguarded, opt(finally), pos, dst);
     979             : 
     980           0 :     return newNode(AST_TRY_STMT, pos,
     981             :                    "block", body,
     982             :                    "guardedHandlers", guardedHandlers,
     983             :                    "handler", unguarded,
     984             :                    "finalizer", finally,
     985           0 :                    dst);
     986             : }
     987             : 
     988             : bool
     989           0 : NodeBuilder::debuggerStatement(TokenPos* pos, MutableHandleValue dst)
     990             : {
     991           0 :     RootedValue cb(cx, callbacks[AST_DEBUGGER_STMT]);
     992           0 :     if (!cb.isNull())
     993           0 :         return callback(cb, pos, dst);
     994             : 
     995           0 :     return newNode(AST_DEBUGGER_STMT, pos, dst);
     996             : }
     997             : 
     998             : bool
     999           0 : NodeBuilder::binaryExpression(BinaryOperator op, HandleValue left, HandleValue right, TokenPos* pos,
    1000             :                               MutableHandleValue dst)
    1001             : {
    1002           0 :     MOZ_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
    1003             : 
    1004           0 :     RootedValue opName(cx);
    1005           0 :     if (!atomValue(binopNames[op], &opName))
    1006           0 :         return false;
    1007             : 
    1008           0 :     RootedValue cb(cx, callbacks[AST_BINARY_EXPR]);
    1009           0 :     if (!cb.isNull())
    1010           0 :         return callback(cb, opName, left, right, pos, dst);
    1011             : 
    1012           0 :     return newNode(AST_BINARY_EXPR, pos,
    1013             :                    "operator", opName,
    1014             :                    "left", left,
    1015             :                    "right", right,
    1016           0 :                    dst);
    1017             : }
    1018             : 
    1019             : bool
    1020           0 : NodeBuilder::unaryExpression(UnaryOperator unop, HandleValue expr, TokenPos* pos,
    1021             :                              MutableHandleValue dst)
    1022             : {
    1023           0 :     MOZ_ASSERT(unop > UNOP_ERR && unop < UNOP_LIMIT);
    1024             : 
    1025           0 :     RootedValue opName(cx);
    1026           0 :     if (!atomValue(unopNames[unop], &opName))
    1027           0 :         return false;
    1028             : 
    1029           0 :     RootedValue cb(cx, callbacks[AST_UNARY_EXPR]);
    1030           0 :     if (!cb.isNull())
    1031           0 :         return callback(cb, opName, expr, pos, dst);
    1032             : 
    1033           0 :     RootedValue trueVal(cx, BooleanValue(true));
    1034           0 :     return newNode(AST_UNARY_EXPR, pos,
    1035             :                    "operator", opName,
    1036             :                    "argument", expr,
    1037             :                    "prefix", trueVal,
    1038           0 :                    dst);
    1039             : }
    1040             : 
    1041             : bool
    1042           0 : NodeBuilder::assignmentExpression(AssignmentOperator aop, HandleValue lhs, HandleValue rhs,
    1043             :                                   TokenPos* pos, MutableHandleValue dst)
    1044             : {
    1045           0 :     MOZ_ASSERT(aop > AOP_ERR && aop < AOP_LIMIT);
    1046             : 
    1047           0 :     RootedValue opName(cx);
    1048           0 :     if (!atomValue(aopNames[aop], &opName))
    1049           0 :         return false;
    1050             : 
    1051           0 :     RootedValue cb(cx, callbacks[AST_ASSIGN_EXPR]);
    1052           0 :     if (!cb.isNull())
    1053           0 :         return callback(cb, opName, lhs, rhs, pos, dst);
    1054             : 
    1055           0 :     return newNode(AST_ASSIGN_EXPR, pos,
    1056             :                    "operator", opName,
    1057             :                    "left", lhs,
    1058             :                    "right", rhs,
    1059           0 :                    dst);
    1060             : }
    1061             : 
    1062             : bool
    1063           0 : NodeBuilder::updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos* pos,
    1064             :                               MutableHandleValue dst)
    1065             : {
    1066           0 :     RootedValue opName(cx);
    1067           0 :     if (!atomValue(incr ? "++" : "--", &opName))
    1068           0 :         return false;
    1069             : 
    1070           0 :     RootedValue prefixVal(cx, BooleanValue(prefix));
    1071             : 
    1072           0 :     RootedValue cb(cx, callbacks[AST_UPDATE_EXPR]);
    1073           0 :     if (!cb.isNull())
    1074           0 :         return callback(cb, expr, opName, prefixVal, pos, dst);
    1075             : 
    1076           0 :     return newNode(AST_UPDATE_EXPR, pos,
    1077             :                    "operator", opName,
    1078             :                    "argument", expr,
    1079             :                    "prefix", prefixVal,
    1080           0 :                    dst);
    1081             : }
    1082             : 
    1083             : bool
    1084           0 : NodeBuilder::logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos* pos,
    1085             :                                MutableHandleValue dst)
    1086             : {
    1087           0 :     RootedValue opName(cx);
    1088           0 :     if (!atomValue(lor ? "||" : "&&", &opName))
    1089           0 :         return false;
    1090             : 
    1091           0 :     RootedValue cb(cx, callbacks[AST_LOGICAL_EXPR]);
    1092           0 :     if (!cb.isNull())
    1093           0 :         return callback(cb, opName, left, right, pos, dst);
    1094             : 
    1095           0 :     return newNode(AST_LOGICAL_EXPR, pos,
    1096             :                    "operator", opName,
    1097             :                    "left", left,
    1098             :                    "right", right,
    1099           0 :                    dst);
    1100             : }
    1101             : 
    1102             : bool
    1103           0 : NodeBuilder::conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt,
    1104             :                                    TokenPos* pos, MutableHandleValue dst)
    1105             : {
    1106           0 :     RootedValue cb(cx, callbacks[AST_COND_EXPR]);
    1107           0 :     if (!cb.isNull())
    1108           0 :         return callback(cb, test, cons, alt, pos, dst);
    1109             : 
    1110           0 :     return newNode(AST_COND_EXPR, pos,
    1111             :                    "test", test,
    1112             :                    "consequent", cons,
    1113             :                    "alternate", alt,
    1114           0 :                    dst);
    1115             : }
    1116             : 
    1117             : bool
    1118           0 : NodeBuilder::sequenceExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
    1119             : {
    1120           0 :     return listNode(AST_LIST_EXPR, "expressions", elts, pos, dst);
    1121             : }
    1122             : 
    1123             : bool
    1124           0 : NodeBuilder::callExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
    1125             :                             MutableHandleValue dst)
    1126             : {
    1127           0 :     RootedValue array(cx);
    1128           0 :     if (!newArray(args, &array))
    1129           0 :         return false;
    1130             : 
    1131           0 :     RootedValue cb(cx, callbacks[AST_CALL_EXPR]);
    1132           0 :     if (!cb.isNull())
    1133           0 :         return callback(cb, callee, array, pos, dst);
    1134             : 
    1135           0 :     return newNode(AST_CALL_EXPR, pos,
    1136             :                    "callee", callee,
    1137             :                    "arguments", array,
    1138           0 :                    dst);
    1139             : }
    1140             : 
    1141             : bool
    1142           0 : NodeBuilder::newExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
    1143             :                            MutableHandleValue dst)
    1144             : {
    1145           0 :     RootedValue array(cx);
    1146           0 :     if (!newArray(args, &array))
    1147           0 :         return false;
    1148             : 
    1149           0 :     RootedValue cb(cx, callbacks[AST_NEW_EXPR]);
    1150           0 :     if (!cb.isNull())
    1151           0 :         return callback(cb, callee, array, pos, dst);
    1152             : 
    1153           0 :     return newNode(AST_NEW_EXPR, pos,
    1154             :                    "callee", callee,
    1155             :                    "arguments", array,
    1156           0 :                    dst);
    1157             : }
    1158             : 
    1159             : bool
    1160           0 : NodeBuilder::memberExpression(bool computed, HandleValue expr, HandleValue member, TokenPos* pos,
    1161             :                               MutableHandleValue dst)
    1162             : {
    1163           0 :     RootedValue computedVal(cx, BooleanValue(computed));
    1164             : 
    1165           0 :     RootedValue cb(cx, callbacks[AST_MEMBER_EXPR]);
    1166           0 :     if (!cb.isNull())
    1167           0 :         return callback(cb, computedVal, expr, member, pos, dst);
    1168             : 
    1169           0 :     return newNode(AST_MEMBER_EXPR, pos,
    1170             :                    "object", expr,
    1171             :                    "property", member,
    1172             :                    "computed", computedVal,
    1173           0 :                    dst);
    1174             : }
    1175             : 
    1176             : bool
    1177           0 : NodeBuilder::arrayExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
    1178             : {
    1179           0 :     return listNode(AST_ARRAY_EXPR, "elements", elts, pos, dst);
    1180             : }
    1181             : 
    1182             : bool
    1183           0 : NodeBuilder::callSiteObj(NodeVector& raw, NodeVector& cooked, TokenPos* pos, MutableHandleValue dst)
    1184             : {
    1185           0 :     RootedValue rawVal(cx);
    1186           0 :     if (!newArray(raw, &rawVal))
    1187           0 :         return false;
    1188             : 
    1189           0 :     RootedValue cookedVal(cx);
    1190           0 :     if (!newArray(cooked, &cookedVal))
    1191           0 :         return false;
    1192             : 
    1193             :     return newNode(AST_CALL_SITE_OBJ, pos,
    1194             :                    "raw", rawVal,
    1195             :                    "cooked", cookedVal,
    1196           0 :                     dst);
    1197             : }
    1198             : 
    1199             : bool
    1200           0 : NodeBuilder::taggedTemplate(HandleValue callee, NodeVector& args, TokenPos* pos,
    1201             :                             MutableHandleValue dst)
    1202             : {
    1203           0 :     RootedValue array(cx);
    1204           0 :     if (!newArray(args, &array))
    1205           0 :         return false;
    1206             : 
    1207             :     return newNode(AST_TAGGED_TEMPLATE, pos,
    1208             :                    "callee", callee,
    1209             :                    "arguments", array,
    1210           0 :                    dst);
    1211             : }
    1212             : 
    1213             : bool
    1214           0 : NodeBuilder::templateLiteral(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
    1215             : {
    1216           0 :     return listNode(AST_TEMPLATE_LITERAL, "elements", elts, pos, dst);
    1217             : }
    1218             : 
    1219             : bool
    1220           0 : NodeBuilder::computedName(HandleValue name, TokenPos* pos, MutableHandleValue dst)
    1221             : {
    1222             :     return newNode(AST_COMPUTED_NAME, pos,
    1223             :                    "name", name,
    1224           0 :                    dst);
    1225             : }
    1226             : 
    1227             : bool
    1228           0 : NodeBuilder::spreadExpression(HandleValue expr, TokenPos* pos, MutableHandleValue dst)
    1229             : {
    1230             :     return newNode(AST_SPREAD_EXPR, pos,
    1231             :                    "expression", expr,
    1232           0 :                    dst);
    1233             : }
    1234             : 
    1235             : bool
    1236           0 : NodeBuilder::propertyPattern(HandleValue key, HandleValue patt, bool isShorthand, TokenPos* pos,
    1237             :                              MutableHandleValue dst)
    1238             : {
    1239           0 :     RootedValue kindName(cx);
    1240           0 :     if (!atomValue("init", &kindName))
    1241           0 :         return false;
    1242             : 
    1243           0 :     RootedValue isShorthandVal(cx, BooleanValue(isShorthand));
    1244             : 
    1245           0 :     RootedValue cb(cx, callbacks[AST_PROP_PATT]);
    1246           0 :     if (!cb.isNull())
    1247           0 :         return callback(cb, key, patt, pos, dst);
    1248             : 
    1249           0 :     return newNode(AST_PROP_PATT, pos,
    1250             :                    "key", key,
    1251             :                    "value", patt,
    1252             :                    "kind", kindName,
    1253             :                    "shorthand", isShorthandVal,
    1254           0 :                    dst);
    1255             : }
    1256             : 
    1257             : bool
    1258           0 : NodeBuilder::prototypeMutation(HandleValue val, TokenPos* pos, MutableHandleValue dst)
    1259             : {
    1260           0 :     RootedValue cb(cx, callbacks[AST_PROTOTYPEMUTATION]);
    1261           0 :     if (!cb.isNull())
    1262           0 :         return callback(cb, val, pos, dst);
    1263             : 
    1264           0 :     return newNode(AST_PROTOTYPEMUTATION, pos,
    1265             :                    "value", val,
    1266           0 :                    dst);
    1267             : }
    1268             : 
    1269             : bool
    1270           0 : NodeBuilder::propertyInitializer(HandleValue key, HandleValue val, PropKind kind, bool isShorthand,
    1271             :                                  bool isMethod, TokenPos* pos, MutableHandleValue dst)
    1272             : {
    1273           0 :     RootedValue kindName(cx);
    1274           0 :     if (!atomValue(kind == PROP_INIT
    1275             :                    ? "init"
    1276             :                    : kind == PROP_GETTER
    1277             :                    ? "get"
    1278             :                    : "set", &kindName)) {
    1279           0 :         return false;
    1280             :     }
    1281             : 
    1282           0 :     RootedValue isShorthandVal(cx, BooleanValue(isShorthand));
    1283           0 :     RootedValue isMethodVal(cx, BooleanValue(isMethod));
    1284             : 
    1285           0 :     RootedValue cb(cx, callbacks[AST_PROPERTY]);
    1286           0 :     if (!cb.isNull())
    1287           0 :         return callback(cb, kindName, key, val, pos, dst);
    1288             : 
    1289           0 :     return newNode(AST_PROPERTY, pos,
    1290             :                    "key", key,
    1291             :                    "value", val,
    1292             :                    "kind", kindName,
    1293             :                    "method", isMethodVal,
    1294             :                    "shorthand", isShorthandVal,
    1295           0 :                    dst);
    1296             : }
    1297             : 
    1298             : bool
    1299           0 : NodeBuilder::objectExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
    1300             : {
    1301           0 :     return listNode(AST_OBJECT_EXPR, "properties", elts, pos, dst);
    1302             : }
    1303             : 
    1304             : bool
    1305           0 : NodeBuilder::thisExpression(TokenPos* pos, MutableHandleValue dst)
    1306             : {
    1307           0 :     RootedValue cb(cx, callbacks[AST_THIS_EXPR]);
    1308           0 :     if (!cb.isNull())
    1309           0 :         return callback(cb, pos, dst);
    1310             : 
    1311           0 :     return newNode(AST_THIS_EXPR, pos, dst);
    1312             : }
    1313             : 
    1314             : bool
    1315           0 : NodeBuilder::yieldExpression(HandleValue arg, YieldKind kind, TokenPos* pos, MutableHandleValue dst)
    1316             : {
    1317           0 :     RootedValue cb(cx, callbacks[AST_YIELD_EXPR]);
    1318           0 :     RootedValue delegateVal(cx);
    1319             : 
    1320           0 :     switch (kind) {
    1321             :       case Delegating:
    1322           0 :         delegateVal = BooleanValue(true);
    1323           0 :         break;
    1324             :       case NotDelegating:
    1325           0 :         delegateVal = BooleanValue(false);
    1326           0 :         break;
    1327             :     }
    1328             : 
    1329           0 :     if (!cb.isNull())
    1330           0 :         return callback(cb, opt(arg), delegateVal, pos, dst);
    1331           0 :     return newNode(AST_YIELD_EXPR, pos, "argument", arg, "delegate", delegateVal, dst);
    1332             : }
    1333             : 
    1334             : bool
    1335           0 : NodeBuilder::comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach, bool isForOf, TokenPos* pos,
    1336             :                                 MutableHandleValue dst)
    1337             : {
    1338           0 :     RootedValue isForEachVal(cx, BooleanValue(isForEach));
    1339           0 :     RootedValue isForOfVal(cx, BooleanValue(isForOf));
    1340             : 
    1341           0 :     RootedValue cb(cx, callbacks[AST_COMP_BLOCK]);
    1342           0 :     if (!cb.isNull())
    1343           0 :         return callback(cb, patt, src, isForEachVal, isForOfVal, pos, dst);
    1344             : 
    1345           0 :     return newNode(AST_COMP_BLOCK, pos,
    1346             :                    "left", patt,
    1347             :                    "right", src,
    1348             :                    "each", isForEachVal,
    1349             :                    "of", isForOfVal,
    1350           0 :                    dst);
    1351             : }
    1352             : 
    1353             : bool
    1354           0 : NodeBuilder::comprehensionIf(HandleValue test, TokenPos* pos, MutableHandleValue dst)
    1355             : {
    1356           0 :     RootedValue cb(cx, callbacks[AST_COMP_IF]);
    1357           0 :     if (!cb.isNull())
    1358           0 :         return callback(cb, test, pos, dst);
    1359             : 
    1360           0 :     return newNode(AST_COMP_IF, pos,
    1361             :                    "test", test,
    1362           0 :                    dst);
    1363             : }
    1364             : 
    1365             : bool
    1366           0 : NodeBuilder::comprehensionExpression(HandleValue body, NodeVector& blocks, HandleValue filter,
    1367             :                                      bool isLegacy, TokenPos* pos, MutableHandleValue dst)
    1368             : {
    1369           0 :     RootedValue array(cx);
    1370           0 :     if (!newArray(blocks, &array))
    1371           0 :         return false;
    1372             : 
    1373           0 :     RootedValue style(cx);
    1374           0 :     if (!atomValue(isLegacy ? "legacy" : "modern", &style))
    1375           0 :         return false;
    1376             : 
    1377           0 :     RootedValue cb(cx, callbacks[AST_COMP_EXPR]);
    1378           0 :     if (!cb.isNull())
    1379           0 :         return callback(cb, body, array, opt(filter), style, pos, dst);
    1380             : 
    1381           0 :     return newNode(AST_COMP_EXPR, pos,
    1382             :                    "body", body,
    1383             :                    "blocks", array,
    1384             :                    "filter", filter,
    1385             :                    "style", style,
    1386           0 :                    dst);
    1387             : }
    1388             : 
    1389             : bool
    1390           0 : NodeBuilder::generatorExpression(HandleValue body, NodeVector& blocks, HandleValue filter,
    1391             :                                  bool isLegacy, TokenPos* pos, MutableHandleValue dst)
    1392             : {
    1393           0 :     RootedValue array(cx);
    1394           0 :     if (!newArray(blocks, &array))
    1395           0 :         return false;
    1396             : 
    1397           0 :     RootedValue style(cx);
    1398           0 :     if (!atomValue(isLegacy ? "legacy" : "modern", &style))
    1399           0 :         return false;
    1400             : 
    1401           0 :     RootedValue cb(cx, callbacks[AST_GENERATOR_EXPR]);
    1402           0 :     if (!cb.isNull())
    1403           0 :         return callback(cb, body, array, opt(filter), style, pos, dst);
    1404             : 
    1405           0 :     return newNode(AST_GENERATOR_EXPR, pos,
    1406             :                    "body", body,
    1407             :                    "blocks", array,
    1408             :                    "filter", filter,
    1409             :                    "style", style,
    1410           0 :                    dst);
    1411             : }
    1412             : 
    1413             : bool
    1414           0 : NodeBuilder::importDeclaration(NodeVector& elts, HandleValue moduleSpec, TokenPos* pos,
    1415             :                                MutableHandleValue dst)
    1416             : {
    1417           0 :     RootedValue array(cx);
    1418           0 :     if (!newArray(elts, &array))
    1419           0 :         return false;
    1420             : 
    1421           0 :     RootedValue cb(cx, callbacks[AST_IMPORT_DECL]);
    1422           0 :     if (!cb.isNull())
    1423           0 :         return callback(cb, array, moduleSpec, pos, dst);
    1424             : 
    1425           0 :     return newNode(AST_IMPORT_DECL, pos,
    1426             :                    "specifiers", array,
    1427             :                    "source", moduleSpec,
    1428           0 :                    dst);
    1429             : }
    1430             : 
    1431             : bool
    1432           0 : NodeBuilder::importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos* pos,
    1433             :                              MutableHandleValue dst)
    1434             : {
    1435           0 :     RootedValue cb(cx, callbacks[AST_IMPORT_SPEC]);
    1436           0 :     if (!cb.isNull())
    1437           0 :         return callback(cb, importName, bindingName, pos, dst);
    1438             : 
    1439           0 :     return newNode(AST_IMPORT_SPEC, pos,
    1440             :                    "id", importName,
    1441             :                    "name", bindingName,
    1442           0 :                    dst);
    1443             : }
    1444             : 
    1445             : bool
    1446           0 : NodeBuilder::exportDeclaration(HandleValue decl, NodeVector& elts, HandleValue moduleSpec,
    1447             :                                HandleValue isDefault, TokenPos* pos, MutableHandleValue dst)
    1448             : {
    1449           0 :     RootedValue array(cx, NullValue());
    1450           0 :     if (decl.isNull() && !newArray(elts, &array))
    1451           0 :         return false;
    1452             : 
    1453           0 :     RootedValue cb(cx, callbacks[AST_EXPORT_DECL]);
    1454             : 
    1455           0 :     if (!cb.isNull())
    1456           0 :         return callback(cb, decl, array, moduleSpec, pos, dst);
    1457             : 
    1458           0 :     return newNode(AST_EXPORT_DECL, pos,
    1459             :                    "declaration", decl,
    1460             :                    "specifiers", array,
    1461             :                    "source", moduleSpec,
    1462             :                    "isDefault", isDefault,
    1463           0 :                    dst);
    1464             : }
    1465             : 
    1466             : bool
    1467           0 : NodeBuilder::exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos* pos,
    1468             :                              MutableHandleValue dst)
    1469             : {
    1470           0 :     RootedValue cb(cx, callbacks[AST_EXPORT_SPEC]);
    1471           0 :     if (!cb.isNull())
    1472           0 :         return callback(cb, bindingName, exportName, pos, dst);
    1473             : 
    1474           0 :     return newNode(AST_EXPORT_SPEC, pos,
    1475             :                    "id", bindingName,
    1476             :                    "name", exportName,
    1477           0 :                    dst);
    1478             : }
    1479             : 
    1480             : bool
    1481           0 : NodeBuilder::exportBatchSpecifier(TokenPos* pos, MutableHandleValue dst)
    1482             : {
    1483           0 :     RootedValue cb(cx, callbacks[AST_EXPORT_BATCH_SPEC]);
    1484           0 :     if (!cb.isNull())
    1485           0 :         return callback(cb, pos, dst);
    1486             : 
    1487           0 :     return newNode(AST_EXPORT_BATCH_SPEC, pos, dst);
    1488             : }
    1489             : 
    1490             : bool
    1491           0 : NodeBuilder::variableDeclaration(NodeVector& elts, VarDeclKind kind, TokenPos* pos,
    1492             :                                  MutableHandleValue dst)
    1493             : {
    1494           0 :     MOZ_ASSERT(kind > VARDECL_ERR && kind < VARDECL_LIMIT);
    1495             : 
    1496           0 :     RootedValue array(cx), kindName(cx);
    1497           0 :     if (!newArray(elts, &array) ||
    1498           0 :         !atomValue(kind == VARDECL_CONST
    1499             :                    ? "const"
    1500             :                    : kind == VARDECL_LET
    1501             :                    ? "let"
    1502             :                    : "var", &kindName)) {
    1503           0 :         return false;
    1504             :     }
    1505             : 
    1506           0 :     RootedValue cb(cx, callbacks[AST_VAR_DECL]);
    1507           0 :     if (!cb.isNull())
    1508           0 :         return callback(cb, kindName, array, pos, dst);
    1509             : 
    1510           0 :     return newNode(AST_VAR_DECL, pos,
    1511             :                    "kind", kindName,
    1512             :                    "declarations", array,
    1513           0 :                    dst);
    1514             : }
    1515             : 
    1516             : bool
    1517           0 : NodeBuilder::variableDeclarator(HandleValue id, HandleValue init, TokenPos* pos,
    1518             :                                 MutableHandleValue dst)
    1519             : {
    1520           0 :     RootedValue cb(cx, callbacks[AST_VAR_DTOR]);
    1521           0 :     if (!cb.isNull())
    1522           0 :         return callback(cb, id, opt(init), pos, dst);
    1523             : 
    1524           0 :     return newNode(AST_VAR_DTOR, pos, "id", id, "init", init, dst);
    1525             : }
    1526             : 
    1527             : bool
    1528           0 : NodeBuilder::switchCase(HandleValue expr, NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
    1529             : {
    1530           0 :     RootedValue array(cx);
    1531           0 :     if (!newArray(elts, &array))
    1532           0 :         return false;
    1533             : 
    1534           0 :     RootedValue cb(cx, callbacks[AST_CASE]);
    1535           0 :     if (!cb.isNull())
    1536           0 :         return callback(cb, opt(expr), array, pos, dst);
    1537             : 
    1538           0 :     return newNode(AST_CASE, pos,
    1539             :                    "test", expr,
    1540             :                    "consequent", array,
    1541           0 :                    dst);
    1542             : }
    1543             : 
    1544             : bool
    1545           0 : NodeBuilder::catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos* pos,
    1546             :                          MutableHandleValue dst)
    1547             : {
    1548           0 :     RootedValue cb(cx, callbacks[AST_CATCH]);
    1549           0 :     if (!cb.isNull())
    1550           0 :         return callback(cb, var, opt(guard), body, pos, dst);
    1551             : 
    1552           0 :     return newNode(AST_CATCH, pos,
    1553             :                    "param", var,
    1554             :                    "guard", guard,
    1555             :                    "body", body,
    1556           0 :                    dst);
    1557             : }
    1558             : 
    1559             : bool
    1560           0 : NodeBuilder::literal(HandleValue val, TokenPos* pos, MutableHandleValue dst)
    1561             : {
    1562           0 :     RootedValue cb(cx, callbacks[AST_LITERAL]);
    1563           0 :     if (!cb.isNull())
    1564           0 :         return callback(cb, val, pos, dst);
    1565             : 
    1566           0 :     return newNode(AST_LITERAL, pos, "value", val, dst);
    1567             : }
    1568             : 
    1569             : bool
    1570           0 : NodeBuilder::identifier(HandleValue name, TokenPos* pos, MutableHandleValue dst)
    1571             : {
    1572           0 :     RootedValue cb(cx, callbacks[AST_IDENTIFIER]);
    1573           0 :     if (!cb.isNull())
    1574           0 :         return callback(cb, name, pos, dst);
    1575             : 
    1576           0 :     return newNode(AST_IDENTIFIER, pos, "name", name, dst);
    1577             : }
    1578             : 
    1579             : bool
    1580           0 : NodeBuilder::objectPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
    1581             : {
    1582           0 :     return listNode(AST_OBJECT_PATT, "properties", elts, pos, dst);
    1583             : }
    1584             : 
    1585             : bool
    1586           0 : NodeBuilder::arrayPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
    1587             : {
    1588           0 :     return listNode(AST_ARRAY_PATT, "elements", elts, pos, dst);
    1589             : }
    1590             : 
    1591             : bool
    1592           0 : NodeBuilder::function(ASTType type, TokenPos* pos,
    1593             :                       HandleValue id, NodeVector& args, NodeVector& defaults,
    1594             :                       HandleValue body, HandleValue rest,
    1595             :                       GeneratorStyle generatorStyle, bool isAsync, bool isExpression,
    1596             :                       MutableHandleValue dst)
    1597             : {
    1598           0 :     RootedValue array(cx), defarray(cx);
    1599           0 :     if (!newArray(args, &array))
    1600           0 :         return false;
    1601           0 :     if (!newArray(defaults, &defarray))
    1602           0 :         return false;
    1603             : 
    1604           0 :     bool isGenerator = generatorStyle != GeneratorStyle::None;
    1605           0 :     RootedValue isGeneratorVal(cx, BooleanValue(isGenerator));
    1606           0 :     RootedValue isAsyncVal(cx, BooleanValue(isAsync));
    1607           0 :     RootedValue isExpressionVal(cx, BooleanValue(isExpression));
    1608             : 
    1609           0 :     RootedValue cb(cx, callbacks[type]);
    1610           0 :     if (!cb.isNull()) {
    1611           0 :         return callback(cb, opt(id), array, body, isGeneratorVal, isExpressionVal, pos, dst);
    1612             :     }
    1613             : 
    1614           0 :     if (isGenerator) {
    1615             :         // Distinguish ES6 generators from legacy generators.
    1616           0 :         RootedValue styleVal(cx);
    1617             :         JSAtom* styleStr = generatorStyle == GeneratorStyle::ES6
    1618           0 :                            ? Atomize(cx, "es6", 3)
    1619           0 :                            : Atomize(cx, "legacy", 6);
    1620           0 :         if (!styleStr)
    1621           0 :             return false;
    1622           0 :         styleVal.setString(styleStr);
    1623           0 :         return newNode(type, pos,
    1624             :                        "id", id,
    1625             :                        "params", array,
    1626             :                        "defaults", defarray,
    1627             :                        "body", body,
    1628             :                        "rest", rest,
    1629             :                        "generator", isGeneratorVal,
    1630             :                        "async", isAsyncVal,
    1631             :                        "style", styleVal,
    1632             :                        "expression", isExpressionVal,
    1633           0 :                        dst);
    1634             :     }
    1635             : 
    1636           0 :     return newNode(type, pos,
    1637             :                    "id", id,
    1638             :                    "params", array,
    1639             :                    "defaults", defarray,
    1640             :                    "body", body,
    1641             :                    "rest", rest,
    1642             :                    "generator", isGeneratorVal,
    1643             :                    "async", isAsyncVal,
    1644             :                    "expression", isExpressionVal,
    1645           0 :                    dst);
    1646             : }
    1647             : 
    1648             : bool
    1649           0 : NodeBuilder::classMethod(HandleValue name, HandleValue body, PropKind kind, bool isStatic,
    1650             :                          TokenPos* pos, MutableHandleValue dst)
    1651             : {
    1652           0 :     RootedValue kindName(cx);
    1653           0 :     if (!atomValue(kind == PROP_INIT
    1654             :                    ? "method"
    1655             :                    : kind == PROP_GETTER
    1656             :                    ? "get"
    1657             :                    : "set", &kindName)) {
    1658           0 :         return false;
    1659             :     }
    1660             : 
    1661           0 :     RootedValue isStaticVal(cx, BooleanValue(isStatic));
    1662           0 :     RootedValue cb(cx, callbacks[AST_CLASS_METHOD]);
    1663           0 :     if (!cb.isNull())
    1664           0 :         return callback(cb, kindName, name, body, isStaticVal, pos, dst);
    1665             : 
    1666           0 :     return newNode(AST_CLASS_METHOD, pos,
    1667             :                    "name", name,
    1668             :                    "body", body,
    1669             :                    "kind", kindName,
    1670             :                    "static", isStaticVal,
    1671           0 :                    dst);
    1672             : }
    1673             : 
    1674             : bool
    1675           0 : NodeBuilder::classMethods(NodeVector& methods, MutableHandleValue dst)
    1676             : {
    1677           0 :     return newArray(methods, dst);
    1678             : }
    1679             : 
    1680             : bool
    1681           0 : NodeBuilder::classDefinition(bool expr, HandleValue name, HandleValue heritage, HandleValue block,
    1682             :                              TokenPos* pos, MutableHandleValue dst)
    1683             : {
    1684           0 :     ASTType type = expr ? AST_CLASS_EXPR : AST_CLASS_STMT;
    1685           0 :     RootedValue cb(cx, callbacks[type]);
    1686           0 :     if (!cb.isNull())
    1687           0 :         return callback(cb, name, heritage, block, pos, dst);
    1688             : 
    1689           0 :     return newNode(type, pos,
    1690             :                    "id", name,
    1691             :                    "superClass", heritage,
    1692             :                    "body", block,
    1693           0 :                    dst);
    1694             : }
    1695             : 
    1696             : bool
    1697           0 : NodeBuilder::metaProperty(HandleValue meta, HandleValue property, TokenPos* pos, MutableHandleValue dst)
    1698             : {
    1699           0 :     RootedValue cb(cx, callbacks[AST_METAPROPERTY]);
    1700           0 :     if (!cb.isNull())
    1701           0 :         return callback(cb, meta, property, pos, dst);
    1702             : 
    1703           0 :     return newNode(AST_METAPROPERTY, pos,
    1704             :                    "meta", meta,
    1705             :                    "property", property,
    1706           0 :                    dst);
    1707             : }
    1708             : 
    1709             : bool
    1710           0 : NodeBuilder::super(TokenPos* pos, MutableHandleValue dst)
    1711             : {
    1712           0 :     RootedValue cb(cx, callbacks[AST_SUPER]);
    1713           0 :     if (!cb.isNull())
    1714           0 :         return callback(cb, pos, dst);
    1715             : 
    1716           0 :     return newNode(AST_SUPER, pos, dst);
    1717             : }
    1718             : 
    1719             : namespace {
    1720             : 
    1721             : /*
    1722             :  * Serialization of parse nodes to JavaScript objects.
    1723             :  *
    1724             :  * All serialization methods take a non-nullable ParseNode pointer.
    1725             :  */
    1726           0 : class ASTSerializer
    1727             : {
    1728             :     JSContext*          cx;
    1729             :     Parser<FullParseHandler, char16_t>* parser;
    1730             :     NodeBuilder         builder;
    1731             :     DebugOnly<uint32_t> lineno;
    1732             : 
    1733           0 :     Value unrootedAtomContents(JSAtom* atom) {
    1734           0 :         return StringValue(atom ? atom : cx->names().empty);
    1735             :     }
    1736             : 
    1737             :     BinaryOperator binop(ParseNodeKind kind, JSOp op);
    1738             :     UnaryOperator unop(ParseNodeKind kind, JSOp op);
    1739             :     AssignmentOperator aop(JSOp op);
    1740             : 
    1741             :     bool statements(ParseNode* pn, NodeVector& elts);
    1742             :     bool expressions(ParseNode* pn, NodeVector& elts);
    1743             :     bool leftAssociate(ParseNode* pn, MutableHandleValue dst);
    1744             :     bool rightAssociate(ParseNode* pn, MutableHandleValue dst);
    1745             :     bool functionArgs(ParseNode* pn, ParseNode* pnargs,
    1746             :                       NodeVector& args, NodeVector& defaults, MutableHandleValue rest);
    1747             : 
    1748             :     bool sourceElement(ParseNode* pn, MutableHandleValue dst);
    1749             : 
    1750             :     bool declaration(ParseNode* pn, MutableHandleValue dst);
    1751             :     bool variableDeclaration(ParseNode* pn, bool lexical, MutableHandleValue dst);
    1752             :     bool variableDeclarator(ParseNode* pn, MutableHandleValue dst);
    1753             :     bool importDeclaration(ParseNode* pn, MutableHandleValue dst);
    1754             :     bool importSpecifier(ParseNode* pn, MutableHandleValue dst);
    1755             :     bool exportDeclaration(ParseNode* pn, MutableHandleValue dst);
    1756             :     bool exportSpecifier(ParseNode* pn, MutableHandleValue dst);
    1757             :     bool classDefinition(ParseNode* pn, bool expr, MutableHandleValue dst);
    1758             : 
    1759           0 :     bool optStatement(ParseNode* pn, MutableHandleValue dst) {
    1760           0 :         if (!pn) {
    1761           0 :             dst.setMagic(JS_SERIALIZE_NO_NODE);
    1762           0 :             return true;
    1763             :         }
    1764           0 :         return statement(pn, dst);
    1765             :     }
    1766             : 
    1767             :     bool forInit(ParseNode* pn, MutableHandleValue dst);
    1768             :     bool forIn(ParseNode* loop, ParseNode* head, HandleValue var, HandleValue stmt,
    1769             :                MutableHandleValue dst);
    1770             :     bool forOf(ParseNode* loop, ParseNode* head, HandleValue var, HandleValue stmt,
    1771             :                MutableHandleValue dst);
    1772             :     bool statement(ParseNode* pn, MutableHandleValue dst);
    1773             :     bool blockStatement(ParseNode* pn, MutableHandleValue dst);
    1774             :     bool switchStatement(ParseNode* pn, MutableHandleValue dst);
    1775             :     bool switchCase(ParseNode* pn, MutableHandleValue dst);
    1776             :     bool tryStatement(ParseNode* pn, MutableHandleValue dst);
    1777             :     bool catchClause(ParseNode* pn, bool* isGuarded, MutableHandleValue dst);
    1778             : 
    1779           0 :     bool optExpression(ParseNode* pn, MutableHandleValue dst) {
    1780           0 :         if (!pn) {
    1781           0 :             dst.setMagic(JS_SERIALIZE_NO_NODE);
    1782           0 :             return true;
    1783             :         }
    1784           0 :         return expression(pn, dst);
    1785             :     }
    1786             : 
    1787             :     bool expression(ParseNode* pn, MutableHandleValue dst);
    1788             : 
    1789             :     bool propertyName(ParseNode* pn, MutableHandleValue dst);
    1790             :     bool property(ParseNode* pn, MutableHandleValue dst);
    1791             : 
    1792             :     bool classMethod(ParseNode* pn, MutableHandleValue dst);
    1793             : 
    1794           0 :     bool optIdentifier(HandleAtom atom, TokenPos* pos, MutableHandleValue dst) {
    1795           0 :         if (!atom) {
    1796           0 :             dst.setMagic(JS_SERIALIZE_NO_NODE);
    1797           0 :             return true;
    1798             :         }
    1799           0 :         return identifier(atom, pos, dst);
    1800             :     }
    1801             : 
    1802             :     bool identifier(HandleAtom atom, TokenPos* pos, MutableHandleValue dst);
    1803             :     bool identifier(ParseNode* pn, MutableHandleValue dst);
    1804             :     bool literal(ParseNode* pn, MutableHandleValue dst);
    1805             : 
    1806             :     bool pattern(ParseNode* pn, MutableHandleValue dst);
    1807             :     bool arrayPattern(ParseNode* pn, MutableHandleValue dst);
    1808             :     bool objectPattern(ParseNode* pn, MutableHandleValue dst);
    1809             : 
    1810             :     bool function(ParseNode* pn, ASTType type, MutableHandleValue dst);
    1811             :     bool functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector& defaults,
    1812             :                              bool isAsync, bool isExpression,
    1813             :                              MutableHandleValue body, MutableHandleValue rest);
    1814             :     bool functionBody(ParseNode* pn, TokenPos* pos, MutableHandleValue dst);
    1815             : 
    1816             :     bool comprehensionBlock(ParseNode* pn, MutableHandleValue dst);
    1817             :     bool comprehensionIf(ParseNode* pn, MutableHandleValue dst);
    1818             :     bool comprehension(ParseNode* pn, MutableHandleValue dst);
    1819             :     bool generatorExpression(ParseNode* pn, MutableHandleValue dst);
    1820             : 
    1821             :   public:
    1822           0 :     ASTSerializer(JSContext* c, bool l, char const* src, uint32_t ln)
    1823           0 :         : cx(c)
    1824             :         , parser(nullptr)
    1825             :         , builder(c, l, src)
    1826             : #ifdef DEBUG
    1827           0 :         , lineno(ln)
    1828             : #endif
    1829           0 :     {}
    1830             : 
    1831           0 :     bool init(HandleObject userobj) {
    1832           0 :         return builder.init(userobj);
    1833             :     }
    1834             : 
    1835           0 :     void setParser(Parser<FullParseHandler, char16_t>* p) {
    1836           0 :         parser = p;
    1837           0 :         builder.setTokenStream(&p->tokenStream);
    1838           0 :     }
    1839             : 
    1840             :     bool program(ParseNode* pn, MutableHandleValue dst);
    1841             : };
    1842             : 
    1843             : } /* anonymous namespace */
    1844             : 
    1845             : AssignmentOperator
    1846           0 : ASTSerializer::aop(JSOp op)
    1847             : {
    1848           0 :     switch (op) {
    1849             :       case JSOP_NOP:
    1850           0 :         return AOP_ASSIGN;
    1851             :       case JSOP_ADD:
    1852           0 :         return AOP_PLUS;
    1853             :       case JSOP_SUB:
    1854           0 :         return AOP_MINUS;
    1855             :       case JSOP_MUL:
    1856           0 :         return AOP_STAR;
    1857             :       case JSOP_DIV:
    1858           0 :         return AOP_DIV;
    1859             :       case JSOP_MOD:
    1860           0 :         return AOP_MOD;
    1861             :       case JSOP_POW:
    1862           0 :         return AOP_POW;
    1863             :       case JSOP_LSH:
    1864           0 :         return AOP_LSH;
    1865             :       case JSOP_RSH:
    1866           0 :         return AOP_RSH;
    1867             :       case JSOP_URSH:
    1868           0 :         return AOP_URSH;
    1869             :       case JSOP_BITOR:
    1870           0 :         return AOP_BITOR;
    1871             :       case JSOP_BITXOR:
    1872           0 :         return AOP_BITXOR;
    1873             :       case JSOP_BITAND:
    1874           0 :         return AOP_BITAND;
    1875             :       default:
    1876           0 :         return AOP_ERR;
    1877             :     }
    1878             : }
    1879             : 
    1880             : UnaryOperator
    1881           0 : ASTSerializer::unop(ParseNodeKind kind, JSOp op)
    1882             : {
    1883           0 :     if (IsDeleteKind(kind))
    1884           0 :         return UNOP_DELETE;
    1885             : 
    1886           0 :     if (IsTypeofKind(kind))
    1887           0 :         return UNOP_TYPEOF;
    1888             : 
    1889           0 :     if (kind == PNK_AWAIT)
    1890           0 :         return UNOP_AWAIT;
    1891             : 
    1892           0 :     switch (op) {
    1893             :       case JSOP_NEG:
    1894           0 :         return UNOP_NEG;
    1895             :       case JSOP_POS:
    1896           0 :         return UNOP_POS;
    1897             :       case JSOP_NOT:
    1898           0 :         return UNOP_NOT;
    1899             :       case JSOP_BITNOT:
    1900           0 :         return UNOP_BITNOT;
    1901             :       case JSOP_VOID:
    1902           0 :         return UNOP_VOID;
    1903             :       default:
    1904           0 :         return UNOP_ERR;
    1905             :     }
    1906             : }
    1907             : 
    1908             : BinaryOperator
    1909           0 : ASTSerializer::binop(ParseNodeKind kind, JSOp op)
    1910             : {
    1911           0 :     switch (kind) {
    1912             :       case PNK_LSH:
    1913           0 :         return BINOP_LSH;
    1914             :       case PNK_RSH:
    1915           0 :         return BINOP_RSH;
    1916             :       case PNK_URSH:
    1917           0 :         return BINOP_URSH;
    1918             :       case PNK_LT:
    1919           0 :         return BINOP_LT;
    1920             :       case PNK_LE:
    1921           0 :         return BINOP_LE;
    1922             :       case PNK_GT:
    1923           0 :         return BINOP_GT;
    1924             :       case PNK_GE:
    1925           0 :         return BINOP_GE;
    1926             :       case PNK_EQ:
    1927           0 :         return BINOP_EQ;
    1928             :       case PNK_NE:
    1929           0 :         return BINOP_NE;
    1930             :       case PNK_STRICTEQ:
    1931           0 :         return BINOP_STRICTEQ;
    1932             :       case PNK_STRICTNE:
    1933           0 :         return BINOP_STRICTNE;
    1934             :       case PNK_ADD:
    1935           0 :         return BINOP_ADD;
    1936             :       case PNK_SUB:
    1937           0 :         return BINOP_SUB;
    1938             :       case PNK_STAR:
    1939           0 :         return BINOP_STAR;
    1940             :       case PNK_DIV:
    1941           0 :         return BINOP_DIV;
    1942             :       case PNK_MOD:
    1943           0 :         return BINOP_MOD;
    1944             :       case PNK_POW:
    1945           0 :         return BINOP_POW;
    1946             :       case PNK_BITOR:
    1947           0 :         return BINOP_BITOR;
    1948             :       case PNK_BITXOR:
    1949           0 :         return BINOP_BITXOR;
    1950             :       case PNK_BITAND:
    1951           0 :         return BINOP_BITAND;
    1952             :       case PNK_IN:
    1953           0 :         return BINOP_IN;
    1954             :       case PNK_INSTANCEOF:
    1955           0 :         return BINOP_INSTANCEOF;
    1956             :       default:
    1957           0 :         return BINOP_ERR;
    1958             :     }
    1959             : }
    1960             : 
    1961             : bool
    1962           0 : ASTSerializer::statements(ParseNode* pn, NodeVector& elts)
    1963             : {
    1964           0 :     MOZ_ASSERT(pn->isKind(PNK_STATEMENTLIST));
    1965           0 :     MOZ_ASSERT(pn->isArity(PN_LIST));
    1966             : 
    1967           0 :     if (!elts.reserve(pn->pn_count))
    1968           0 :         return false;
    1969             : 
    1970           0 :     for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
    1971           0 :         MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
    1972             : 
    1973           0 :         RootedValue elt(cx);
    1974           0 :         if (!sourceElement(next, &elt))
    1975           0 :             return false;
    1976           0 :         elts.infallibleAppend(elt);
    1977             :     }
    1978             : 
    1979           0 :     return true;
    1980             : }
    1981             : 
    1982             : bool
    1983           0 : ASTSerializer::expressions(ParseNode* pn, NodeVector& elts)
    1984             : {
    1985           0 :     if (!elts.reserve(pn->pn_count))
    1986           0 :         return false;
    1987             : 
    1988           0 :     for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
    1989           0 :         MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
    1990             : 
    1991           0 :         RootedValue elt(cx);
    1992           0 :         if (!expression(next, &elt))
    1993           0 :             return false;
    1994           0 :         elts.infallibleAppend(elt);
    1995             :     }
    1996             : 
    1997           0 :     return true;
    1998             : }
    1999             : 
    2000             : bool
    2001           0 : ASTSerializer::blockStatement(ParseNode* pn, MutableHandleValue dst)
    2002             : {
    2003           0 :     MOZ_ASSERT(pn->isKind(PNK_STATEMENTLIST));
    2004             : 
    2005           0 :     NodeVector stmts(cx);
    2006           0 :     return statements(pn, stmts) &&
    2007           0 :            builder.blockStatement(stmts, &pn->pn_pos, dst);
    2008             : }
    2009             : 
    2010             : bool
    2011           0 : ASTSerializer::program(ParseNode* pn, MutableHandleValue dst)
    2012             : {
    2013           0 :     MOZ_ASSERT(parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin) == lineno);
    2014             : 
    2015           0 :     NodeVector stmts(cx);
    2016           0 :     return statements(pn, stmts) &&
    2017           0 :            builder.program(stmts, &pn->pn_pos, dst);
    2018             : }
    2019             : 
    2020             : bool
    2021           0 : ASTSerializer::sourceElement(ParseNode* pn, MutableHandleValue dst)
    2022             : {
    2023             :     /* SpiderMonkey allows declarations even in pure statement contexts. */
    2024           0 :     return statement(pn, dst);
    2025             : }
    2026             : 
    2027             : bool
    2028           0 : ASTSerializer::declaration(ParseNode* pn, MutableHandleValue dst)
    2029             : {
    2030           0 :     MOZ_ASSERT(pn->isKind(PNK_FUNCTION) ||
    2031             :                pn->isKind(PNK_VAR) ||
    2032             :                pn->isKind(PNK_LET) ||
    2033             :                pn->isKind(PNK_CONST));
    2034             : 
    2035           0 :     switch (pn->getKind()) {
    2036             :       case PNK_FUNCTION:
    2037           0 :         return function(pn, AST_FUNC_DECL, dst);
    2038             : 
    2039             :       case PNK_VAR:
    2040           0 :         return variableDeclaration(pn, false, dst);
    2041             : 
    2042             :       default:
    2043           0 :         MOZ_ASSERT(pn->isKind(PNK_LET) || pn->isKind(PNK_CONST));
    2044           0 :         return variableDeclaration(pn, true, dst);
    2045             :     }
    2046             : }
    2047             : 
    2048             : bool
    2049           0 : ASTSerializer::variableDeclaration(ParseNode* pn, bool lexical, MutableHandleValue dst)
    2050             : {
    2051           0 :     MOZ_ASSERT_IF(lexical, pn->isKind(PNK_LET) || pn->isKind(PNK_CONST));
    2052           0 :     MOZ_ASSERT_IF(!lexical, pn->isKind(PNK_VAR));
    2053             : 
    2054           0 :     VarDeclKind kind = VARDECL_ERR;
    2055             :     // Treat both the toplevel const binding (secretly var-like) and the lexical const
    2056             :     // the same way
    2057           0 :     if (lexical)
    2058           0 :         kind = pn->isKind(PNK_LET) ? VARDECL_LET : VARDECL_CONST;
    2059             :     else
    2060           0 :         kind = pn->isKind(PNK_VAR) ? VARDECL_VAR : VARDECL_CONST;
    2061             : 
    2062           0 :     NodeVector dtors(cx);
    2063           0 :     if (!dtors.reserve(pn->pn_count))
    2064           0 :         return false;
    2065           0 :     for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
    2066           0 :         RootedValue child(cx);
    2067           0 :         if (!variableDeclarator(next, &child))
    2068           0 :             return false;
    2069           0 :         dtors.infallibleAppend(child);
    2070             :     }
    2071           0 :     return builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
    2072             : }
    2073             : 
    2074             : bool
    2075           0 : ASTSerializer::variableDeclarator(ParseNode* pn, MutableHandleValue dst)
    2076             : {
    2077             :     ParseNode* pnleft;
    2078             :     ParseNode* pnright;
    2079             : 
    2080           0 :     if (pn->isKind(PNK_NAME)) {
    2081           0 :         pnleft = pn;
    2082           0 :         pnright = pn->pn_expr;
    2083           0 :         MOZ_ASSERT_IF(pnright, pn->pn_pos.encloses(pnright->pn_pos));
    2084           0 :     } else if (pn->isKind(PNK_ASSIGN)) {
    2085           0 :         pnleft = pn->pn_left;
    2086           0 :         pnright = pn->pn_right;
    2087           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pnleft->pn_pos));
    2088           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pnright->pn_pos));
    2089             :     } else {
    2090             :         /* This happens for a destructuring declarator in a for-in/of loop. */
    2091           0 :         pnleft = pn;
    2092           0 :         pnright = nullptr;
    2093             :     }
    2094             : 
    2095           0 :     RootedValue left(cx), right(cx);
    2096           0 :     return pattern(pnleft, &left) &&
    2097           0 :            optExpression(pnright, &right) &&
    2098           0 :            builder.variableDeclarator(left, right, &pn->pn_pos, dst);
    2099             : }
    2100             : 
    2101             : bool
    2102           0 : ASTSerializer::importDeclaration(ParseNode* pn, MutableHandleValue dst)
    2103             : {
    2104           0 :     MOZ_ASSERT(pn->isKind(PNK_IMPORT));
    2105           0 :     MOZ_ASSERT(pn->isArity(PN_BINARY));
    2106           0 :     MOZ_ASSERT(pn->pn_left->isKind(PNK_IMPORT_SPEC_LIST));
    2107           0 :     MOZ_ASSERT(pn->pn_right->isKind(PNK_STRING));
    2108             : 
    2109           0 :     NodeVector elts(cx);
    2110           0 :     if (!elts.reserve(pn->pn_left->pn_count))
    2111           0 :         return false;
    2112             : 
    2113           0 :     for (ParseNode* next = pn->pn_left->pn_head; next; next = next->pn_next) {
    2114           0 :         RootedValue elt(cx);
    2115           0 :         if (!importSpecifier(next, &elt))
    2116           0 :             return false;
    2117           0 :         elts.infallibleAppend(elt);
    2118             :     }
    2119             : 
    2120           0 :     RootedValue moduleSpec(cx);
    2121           0 :     return literal(pn->pn_right, &moduleSpec) &&
    2122           0 :            builder.importDeclaration(elts, moduleSpec, &pn->pn_pos, dst);
    2123             : }
    2124             : 
    2125             : bool
    2126           0 : ASTSerializer::importSpecifier(ParseNode* pn, MutableHandleValue dst)
    2127             : {
    2128           0 :     MOZ_ASSERT(pn->isKind(PNK_IMPORT_SPEC));
    2129             : 
    2130           0 :     RootedValue importName(cx);
    2131           0 :     RootedValue bindingName(cx);
    2132           0 :     return identifier(pn->pn_left, &importName) &&
    2133           0 :            identifier(pn->pn_right, &bindingName) &&
    2134           0 :            builder.importSpecifier(importName, bindingName, &pn->pn_pos, dst);
    2135             : }
    2136             : 
    2137             : bool
    2138           0 : ASTSerializer::exportDeclaration(ParseNode* pn, MutableHandleValue dst)
    2139             : {
    2140           0 :     MOZ_ASSERT(pn->isKind(PNK_EXPORT) ||
    2141             :                pn->isKind(PNK_EXPORT_FROM) ||
    2142             :                pn->isKind(PNK_EXPORT_DEFAULT));
    2143           0 :     MOZ_ASSERT(pn->getArity() == (pn->isKind(PNK_EXPORT) ? PN_UNARY : PN_BINARY));
    2144           0 :     MOZ_ASSERT_IF(pn->isKind(PNK_EXPORT_FROM), pn->pn_right->isKind(PNK_STRING));
    2145             : 
    2146           0 :     RootedValue decl(cx, NullValue());
    2147           0 :     NodeVector elts(cx);
    2148             : 
    2149           0 :     ParseNode* kid = pn->isKind(PNK_EXPORT) ? pn->pn_kid : pn->pn_left;
    2150           0 :     switch (ParseNodeKind kind = kid->getKind()) {
    2151             :       case PNK_EXPORT_SPEC_LIST:
    2152           0 :         if (!elts.reserve(pn->pn_left->pn_count))
    2153           0 :             return false;
    2154             : 
    2155           0 :         for (ParseNode* next = pn->pn_left->pn_head; next; next = next->pn_next) {
    2156           0 :             RootedValue elt(cx);
    2157           0 :             if (next->isKind(PNK_EXPORT_SPEC)) {
    2158           0 :                 if (!exportSpecifier(next, &elt))
    2159           0 :                     return false;
    2160             :             } else {
    2161           0 :                 if (!builder.exportBatchSpecifier(&pn->pn_pos, &elt))
    2162           0 :                     return false;
    2163             :             }
    2164           0 :             elts.infallibleAppend(elt);
    2165             :         }
    2166           0 :         break;
    2167             : 
    2168             :       case PNK_FUNCTION:
    2169           0 :         if (!function(kid, AST_FUNC_DECL, &decl))
    2170           0 :             return false;
    2171           0 :         break;
    2172             : 
    2173             :       case PNK_CLASS:
    2174           0 :         if (!classDefinition(kid, false, &decl))
    2175           0 :             return false;
    2176           0 :         break;
    2177             : 
    2178             :       case PNK_VAR:
    2179             :       case PNK_CONST:
    2180             :       case PNK_LET:
    2181           0 :         if (!variableDeclaration(kid, kind != PNK_VAR, &decl))
    2182           0 :             return false;
    2183           0 :         break;
    2184             : 
    2185             :       default:
    2186           0 :           if (!expression(kid, &decl))
    2187           0 :               return false;
    2188           0 :           break;
    2189             :     }
    2190             : 
    2191           0 :     RootedValue moduleSpec(cx, NullValue());
    2192           0 :     if (pn->isKind(PNK_EXPORT_FROM) && !literal(pn->pn_right, &moduleSpec))
    2193           0 :         return false;
    2194             : 
    2195           0 :     RootedValue isDefault(cx, BooleanValue(false));
    2196           0 :     if (pn->isKind(PNK_EXPORT_DEFAULT))
    2197           0 :         isDefault.setBoolean(true);
    2198             : 
    2199           0 :     return builder.exportDeclaration(decl, elts, moduleSpec, isDefault, &pn->pn_pos, dst);
    2200             : }
    2201             : 
    2202             : bool
    2203           0 : ASTSerializer::exportSpecifier(ParseNode* pn, MutableHandleValue dst)
    2204             : {
    2205           0 :     MOZ_ASSERT(pn->isKind(PNK_EXPORT_SPEC));
    2206             : 
    2207           0 :     RootedValue bindingName(cx);
    2208           0 :     RootedValue exportName(cx);
    2209           0 :     return identifier(pn->pn_left, &bindingName) &&
    2210           0 :            identifier(pn->pn_right, &exportName) &&
    2211           0 :            builder.exportSpecifier(bindingName, exportName, &pn->pn_pos, dst);
    2212             : }
    2213             : 
    2214             : bool
    2215           0 : ASTSerializer::switchCase(ParseNode* pn, MutableHandleValue dst)
    2216             : {
    2217           0 :     MOZ_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos));
    2218           0 :     MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
    2219             : 
    2220           0 :     NodeVector stmts(cx);
    2221             : 
    2222           0 :     RootedValue expr(cx);
    2223             : 
    2224           0 :     return optExpression(pn->as<CaseClause>().caseExpression(), &expr) &&
    2225           0 :            statements(pn->as<CaseClause>().statementList(), stmts) &&
    2226           0 :            builder.switchCase(expr, stmts, &pn->pn_pos, dst);
    2227             : }
    2228             : 
    2229             : bool
    2230           0 : ASTSerializer::switchStatement(ParseNode* pn, MutableHandleValue dst)
    2231             : {
    2232           0 :     MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
    2233           0 :     MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
    2234             : 
    2235           0 :     RootedValue disc(cx);
    2236             : 
    2237           0 :     if (!expression(pn->pn_left, &disc))
    2238           0 :         return false;
    2239             : 
    2240             :     ParseNode* listNode;
    2241             :     bool lexical;
    2242             : 
    2243           0 :     if (pn->pn_right->isKind(PNK_LEXICALSCOPE)) {
    2244           0 :         listNode = pn->pn_right->pn_expr;
    2245           0 :         lexical = true;
    2246             :     } else {
    2247           0 :         listNode = pn->pn_right;
    2248           0 :         lexical = false;
    2249             :     }
    2250             : 
    2251           0 :     NodeVector cases(cx);
    2252           0 :     if (!cases.reserve(listNode->pn_count))
    2253           0 :         return false;
    2254             : 
    2255           0 :     for (ParseNode* next = listNode->pn_head; next; next = next->pn_next) {
    2256           0 :         RootedValue child(cx);
    2257           0 :         if (!switchCase(next, &child))
    2258           0 :             return false;
    2259           0 :         cases.infallibleAppend(child);
    2260             :     }
    2261             : 
    2262           0 :     return builder.switchStatement(disc, cases, lexical, &pn->pn_pos, dst);
    2263             : }
    2264             : 
    2265             : bool
    2266           0 : ASTSerializer::catchClause(ParseNode* pn, bool* isGuarded, MutableHandleValue dst)
    2267             : {
    2268           0 :     MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
    2269           0 :     MOZ_ASSERT_IF(pn->pn_kid2, pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
    2270           0 :     MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
    2271             : 
    2272           0 :     RootedValue var(cx), guard(cx), body(cx);
    2273             : 
    2274           0 :     if (!pattern(pn->pn_kid1, &var) ||
    2275           0 :         !optExpression(pn->pn_kid2, &guard)) {
    2276           0 :         return false;
    2277             :     }
    2278             : 
    2279           0 :     *isGuarded = !guard.isMagic(JS_SERIALIZE_NO_NODE);
    2280             : 
    2281           0 :     return statement(pn->pn_kid3, &body) &&
    2282           0 :            builder.catchClause(var, guard, body, &pn->pn_pos, dst);
    2283             : }
    2284             : 
    2285             : bool
    2286           0 : ASTSerializer::tryStatement(ParseNode* pn, MutableHandleValue dst)
    2287             : {
    2288           0 :     MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
    2289           0 :     MOZ_ASSERT_IF(pn->pn_kid2, pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
    2290           0 :     MOZ_ASSERT_IF(pn->pn_kid3, pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
    2291             : 
    2292           0 :     RootedValue body(cx);
    2293           0 :     if (!statement(pn->pn_kid1, &body))
    2294           0 :         return false;
    2295             : 
    2296           0 :     NodeVector guarded(cx);
    2297           0 :     RootedValue unguarded(cx, NullValue());
    2298             : 
    2299           0 :     if (ParseNode* catchList = pn->pn_kid2) {
    2300           0 :         if (!guarded.reserve(catchList->pn_count))
    2301           0 :             return false;
    2302             : 
    2303           0 :         for (ParseNode* next = catchList->pn_head; next; next = next->pn_next) {
    2304           0 :             RootedValue clause(cx);
    2305             :             bool isGuarded;
    2306           0 :             if (!catchClause(next->pn_expr, &isGuarded, &clause))
    2307           0 :                 return false;
    2308           0 :             if (isGuarded)
    2309           0 :                 guarded.infallibleAppend(clause);
    2310             :             else
    2311           0 :                 unguarded = clause;
    2312             :         }
    2313             :     }
    2314             : 
    2315           0 :     RootedValue finally(cx);
    2316           0 :     return optStatement(pn->pn_kid3, &finally) &&
    2317           0 :            builder.tryStatement(body, guarded, unguarded, finally, &pn->pn_pos, dst);
    2318             : }
    2319             : 
    2320             : bool
    2321           0 : ASTSerializer::forInit(ParseNode* pn, MutableHandleValue dst)
    2322             : {
    2323           0 :     if (!pn) {
    2324           0 :         dst.setMagic(JS_SERIALIZE_NO_NODE);
    2325           0 :         return true;
    2326             :     }
    2327             : 
    2328           0 :     bool lexical = pn->isKind(PNK_LET) || pn->isKind(PNK_CONST);
    2329           0 :     return (lexical || pn->isKind(PNK_VAR))
    2330           0 :            ? variableDeclaration(pn, lexical, dst)
    2331           0 :            : expression(pn, dst);
    2332             : }
    2333             : 
    2334             : bool
    2335           0 : ASTSerializer::forOf(ParseNode* loop, ParseNode* head, HandleValue var, HandleValue stmt,
    2336             :                          MutableHandleValue dst)
    2337             : {
    2338           0 :     RootedValue expr(cx);
    2339             : 
    2340           0 :     return expression(head->pn_kid3, &expr) &&
    2341           0 :         builder.forOfStatement(var, expr, stmt, &loop->pn_pos, dst);
    2342             : }
    2343             : 
    2344             : bool
    2345           0 : ASTSerializer::forIn(ParseNode* loop, ParseNode* head, HandleValue var, HandleValue stmt,
    2346             :                          MutableHandleValue dst)
    2347             : {
    2348           0 :     RootedValue expr(cx);
    2349           0 :     bool isForEach = loop->pn_iflags & JSITER_FOREACH;
    2350             : 
    2351           0 :     return expression(head->pn_kid3, &expr) &&
    2352           0 :         builder.forInStatement(var, expr, stmt, isForEach, &loop->pn_pos, dst);
    2353             : }
    2354             : 
    2355             : bool
    2356           0 : ASTSerializer::classDefinition(ParseNode* pn, bool expr, MutableHandleValue dst)
    2357             : {
    2358           0 :     RootedValue className(cx, MagicValue(JS_SERIALIZE_NO_NODE));
    2359           0 :     RootedValue heritage(cx);
    2360           0 :     RootedValue classBody(cx);
    2361             : 
    2362           0 :     if (pn->pn_kid1) {
    2363           0 :         if (!identifier(pn->pn_kid1->as<ClassNames>().innerBinding(), &className))
    2364           0 :             return false;
    2365             :     }
    2366             : 
    2367           0 :     return optExpression(pn->pn_kid2, &heritage) &&
    2368           0 :            statement(pn->pn_kid3, &classBody) &&
    2369           0 :            builder.classDefinition(expr, className, heritage, classBody, &pn->pn_pos, dst);
    2370             : }
    2371             : 
    2372             : bool
    2373           0 : ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
    2374             : {
    2375           0 :     if (!CheckRecursionLimit(cx))
    2376           0 :         return false;
    2377             : 
    2378           0 :     switch (pn->getKind()) {
    2379             :       case PNK_FUNCTION:
    2380             :       case PNK_VAR:
    2381           0 :         return declaration(pn, dst);
    2382             : 
    2383             :       case PNK_LET:
    2384             :       case PNK_CONST:
    2385           0 :         return declaration(pn, dst);
    2386             : 
    2387             :       case PNK_IMPORT:
    2388           0 :         return importDeclaration(pn, dst);
    2389             : 
    2390             :       case PNK_EXPORT:
    2391             :       case PNK_EXPORT_DEFAULT:
    2392             :       case PNK_EXPORT_FROM:
    2393           0 :         return exportDeclaration(pn, dst);
    2394             : 
    2395             :       case PNK_SEMI:
    2396           0 :         if (pn->pn_kid) {
    2397           0 :             RootedValue expr(cx);
    2398           0 :             return expression(pn->pn_kid, &expr) &&
    2399           0 :                    builder.expressionStatement(expr, &pn->pn_pos, dst);
    2400             :         }
    2401           0 :         return builder.emptyStatement(&pn->pn_pos, dst);
    2402             : 
    2403             :       case PNK_LEXICALSCOPE:
    2404           0 :         pn = pn->pn_expr;
    2405           0 :         if (!pn->isKind(PNK_STATEMENTLIST))
    2406           0 :             return statement(pn, dst);
    2407             :         MOZ_FALLTHROUGH;
    2408             : 
    2409             :       case PNK_STATEMENTLIST:
    2410           0 :         return blockStatement(pn, dst);
    2411             : 
    2412             :       case PNK_IF:
    2413             :       {
    2414           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
    2415           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
    2416           0 :         MOZ_ASSERT_IF(pn->pn_kid3, pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
    2417             : 
    2418           0 :         RootedValue test(cx), cons(cx), alt(cx);
    2419             : 
    2420           0 :         return expression(pn->pn_kid1, &test) &&
    2421           0 :                statement(pn->pn_kid2, &cons) &&
    2422           0 :                optStatement(pn->pn_kid3, &alt) &&
    2423           0 :                builder.ifStatement(test, cons, alt, &pn->pn_pos, dst);
    2424             :       }
    2425             : 
    2426             :       case PNK_SWITCH:
    2427           0 :         return switchStatement(pn, dst);
    2428             : 
    2429             :       case PNK_TRY:
    2430           0 :         return tryStatement(pn, dst);
    2431             : 
    2432             :       case PNK_WITH:
    2433             :       case PNK_WHILE:
    2434             :       {
    2435           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
    2436           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
    2437             : 
    2438           0 :         RootedValue expr(cx), stmt(cx);
    2439             : 
    2440           0 :         return expression(pn->pn_left, &expr) &&
    2441           0 :                statement(pn->pn_right, &stmt) &&
    2442           0 :                (pn->isKind(PNK_WITH)
    2443           0 :                 ? builder.withStatement(expr, stmt, &pn->pn_pos, dst)
    2444           0 :                 : builder.whileStatement(expr, stmt, &pn->pn_pos, dst));
    2445             :       }
    2446             : 
    2447             :       case PNK_DOWHILE:
    2448             :       {
    2449           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
    2450           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
    2451             : 
    2452           0 :         RootedValue stmt(cx), test(cx);
    2453             : 
    2454           0 :         return statement(pn->pn_left, &stmt) &&
    2455           0 :                expression(pn->pn_right, &test) &&
    2456           0 :                builder.doWhileStatement(stmt, test, &pn->pn_pos, dst);
    2457             :       }
    2458             : 
    2459             :       case PNK_FOR:
    2460             :       case PNK_COMPREHENSIONFOR:
    2461             :       {
    2462           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
    2463           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
    2464             : 
    2465           0 :         ParseNode* head = pn->pn_left;
    2466             : 
    2467           0 :         MOZ_ASSERT_IF(head->pn_kid1, head->pn_pos.encloses(head->pn_kid1->pn_pos));
    2468           0 :         MOZ_ASSERT_IF(head->pn_kid2, head->pn_pos.encloses(head->pn_kid2->pn_pos));
    2469           0 :         MOZ_ASSERT_IF(head->pn_kid3, head->pn_pos.encloses(head->pn_kid3->pn_pos));
    2470             : 
    2471           0 :         RootedValue stmt(cx);
    2472           0 :         if (!statement(pn->pn_right, &stmt))
    2473           0 :             return false;
    2474             : 
    2475           0 :         if (head->isKind(PNK_FORIN) || head->isKind(PNK_FOROF)) {
    2476           0 :             RootedValue var(cx);
    2477           0 :             if (head->pn_kid1->isKind(PNK_LEXICALSCOPE)) {
    2478           0 :                 if (!variableDeclaration(head->pn_kid1->pn_expr, true, &var))
    2479           0 :                     return false;
    2480           0 :             } else if (!head->pn_kid1->isKind(PNK_VAR) &&
    2481           0 :                        !head->pn_kid1->isKind(PNK_LET) &&
    2482           0 :                        !head->pn_kid1->isKind(PNK_CONST))
    2483             :             {
    2484           0 :                 if (!pattern(head->pn_kid1, &var))
    2485           0 :                     return false;
    2486             :             } else {
    2487           0 :                 if (!variableDeclaration(head->pn_kid1,
    2488           0 :                                          head->pn_kid1->isKind(PNK_LET) ||
    2489           0 :                                          head->pn_kid1->isKind(PNK_CONST),
    2490             :                                          &var))
    2491             :                 {
    2492           0 :                     return false;
    2493             :                 }
    2494             :             }
    2495           0 :             if (head->isKind(PNK_FORIN))
    2496           0 :                 return forIn(pn, head, var, stmt, dst);
    2497           0 :             return forOf(pn, head, var, stmt, dst);
    2498             :         }
    2499             : 
    2500           0 :         RootedValue init(cx), test(cx), update(cx);
    2501             : 
    2502           0 :         return forInit(head->pn_kid1, &init) &&
    2503           0 :                optExpression(head->pn_kid2, &test) &&
    2504           0 :                optExpression(head->pn_kid3, &update) &&
    2505           0 :                builder.forStatement(init, test, update, stmt, &pn->pn_pos, dst);
    2506             :       }
    2507             : 
    2508             :       case PNK_BREAK:
    2509             :       case PNK_CONTINUE:
    2510             :       {
    2511           0 :         RootedValue label(cx);
    2512           0 :         RootedAtom pnAtom(cx, pn->pn_atom);
    2513           0 :         return optIdentifier(pnAtom, nullptr, &label) &&
    2514           0 :                (pn->isKind(PNK_BREAK)
    2515           0 :                 ? builder.breakStatement(label, &pn->pn_pos, dst)
    2516           0 :                 : builder.continueStatement(label, &pn->pn_pos, dst));
    2517             :       }
    2518             : 
    2519             :       case PNK_LABEL:
    2520             :       {
    2521           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
    2522             : 
    2523           0 :         RootedValue label(cx), stmt(cx);
    2524           0 :         RootedAtom pnAtom(cx, pn->as<LabeledStatement>().label());
    2525           0 :         return identifier(pnAtom, nullptr, &label) &&
    2526           0 :                statement(pn->pn_expr, &stmt) &&
    2527           0 :                builder.labeledStatement(label, stmt, &pn->pn_pos, dst);
    2528             :       }
    2529             : 
    2530             :       case PNK_THROW:
    2531             :       {
    2532           0 :         MOZ_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
    2533             : 
    2534           0 :         RootedValue arg(cx);
    2535             : 
    2536           0 :         return optExpression(pn->pn_kid, &arg) &&
    2537           0 :                builder.throwStatement(arg, &pn->pn_pos, dst);
    2538             :       }
    2539             : 
    2540             :       case PNK_RETURN:
    2541             :       {
    2542           0 :         MOZ_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
    2543             : 
    2544           0 :         RootedValue arg(cx);
    2545             : 
    2546           0 :         return optExpression(pn->pn_kid, &arg) &&
    2547           0 :                builder.returnStatement(arg, &pn->pn_pos, dst);
    2548             :       }
    2549             : 
    2550             :       case PNK_DEBUGGER:
    2551           0 :         return builder.debuggerStatement(&pn->pn_pos, dst);
    2552             : 
    2553             :       case PNK_CLASS:
    2554           0 :         return classDefinition(pn, false, dst);
    2555             : 
    2556             :       case PNK_CLASSMETHODLIST:
    2557             :       {
    2558           0 :         NodeVector methods(cx);
    2559           0 :         if (!methods.reserve(pn->pn_count))
    2560           0 :             return false;
    2561             : 
    2562           0 :         for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
    2563           0 :             MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
    2564             : 
    2565           0 :             RootedValue prop(cx);
    2566           0 :             if (!classMethod(next, &prop))
    2567           0 :                 return false;
    2568           0 :             methods.infallibleAppend(prop);
    2569             :         }
    2570             : 
    2571           0 :         return builder.classMethods(methods, dst);
    2572             :       }
    2573             : 
    2574             :       case PNK_NOP:
    2575           0 :         return builder.emptyStatement(&pn->pn_pos, dst);
    2576             : 
    2577             :       default:
    2578           0 :         LOCAL_NOT_REACHED("unexpected statement type");
    2579             :     }
    2580             : }
    2581             : 
    2582             : bool
    2583           0 : ASTSerializer::classMethod(ParseNode* pn, MutableHandleValue dst)
    2584             : {
    2585             :     PropKind kind;
    2586           0 :     switch (pn->getOp()) {
    2587             :       case JSOP_INITPROP:
    2588           0 :         kind = PROP_INIT;
    2589           0 :         break;
    2590             : 
    2591             :       case JSOP_INITPROP_GETTER:
    2592           0 :         kind = PROP_GETTER;
    2593           0 :         break;
    2594             : 
    2595             :       case JSOP_INITPROP_SETTER:
    2596           0 :         kind = PROP_SETTER;
    2597           0 :         break;
    2598             : 
    2599             :       default:
    2600           0 :         LOCAL_NOT_REACHED("unexpected object-literal property");
    2601             :     }
    2602             : 
    2603           0 :     RootedValue key(cx), val(cx);
    2604           0 :     bool isStatic = pn->as<ClassMethod>().isStatic();
    2605           0 :     return propertyName(pn->pn_left, &key) &&
    2606           0 :            expression(pn->pn_right, &val) &&
    2607           0 :            builder.classMethod(key, val, kind, isStatic, &pn->pn_pos, dst);
    2608             : }
    2609             : 
    2610             : bool
    2611           0 : ASTSerializer::leftAssociate(ParseNode* pn, MutableHandleValue dst)
    2612             : {
    2613           0 :     MOZ_ASSERT(pn->isArity(PN_LIST));
    2614           0 :     MOZ_ASSERT(pn->pn_count >= 1);
    2615             : 
    2616           0 :     ParseNodeKind kind = pn->getKind();
    2617           0 :     bool lor = kind == PNK_OR;
    2618           0 :     bool logop = lor || (kind == PNK_AND);
    2619             : 
    2620           0 :     ParseNode* head = pn->pn_head;
    2621           0 :     RootedValue left(cx);
    2622           0 :     if (!expression(head, &left))
    2623           0 :         return false;
    2624           0 :     for (ParseNode* next = head->pn_next; next; next = next->pn_next) {
    2625           0 :         RootedValue right(cx);
    2626           0 :         if (!expression(next, &right))
    2627           0 :             return false;
    2628             : 
    2629           0 :         TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end);
    2630             : 
    2631           0 :         if (logop) {
    2632           0 :             if (!builder.logicalExpression(lor, left, right, &subpos, &left))
    2633           0 :                 return false;
    2634             :         } else {
    2635           0 :             BinaryOperator op = binop(pn->getKind(), pn->getOp());
    2636           0 :             LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
    2637             : 
    2638           0 :             if (!builder.binaryExpression(op, left, right, &subpos, &left))
    2639           0 :                 return false;
    2640             :         }
    2641             :     }
    2642             : 
    2643           0 :     dst.set(left);
    2644           0 :     return true;
    2645             : }
    2646             : 
    2647             : bool
    2648           0 : ASTSerializer::rightAssociate(ParseNode* pn, MutableHandleValue dst)
    2649             : {
    2650           0 :     MOZ_ASSERT(pn->isArity(PN_LIST));
    2651           0 :     MOZ_ASSERT(pn->pn_count >= 1);
    2652             : 
    2653             :     // First, we need to reverse the list, so that we can traverse it in the right order.
    2654             :     // It's OK to destructively reverse the list, because there are no other consumers.
    2655             : 
    2656           0 :     ParseNode* head = pn->pn_head;
    2657           0 :     ParseNode* prev = nullptr;
    2658           0 :     ParseNode* current = head;
    2659             :     ParseNode* next;
    2660           0 :     while (current != nullptr) {
    2661           0 :         next = current->pn_next;
    2662           0 :         current->pn_next = prev;
    2663           0 :         prev = current;
    2664           0 :         current = next;
    2665             :     }
    2666             : 
    2667           0 :     head = prev;
    2668             : 
    2669           0 :     RootedValue right(cx);
    2670           0 :     if (!expression(head, &right))
    2671           0 :         return false;
    2672           0 :     for (ParseNode* next = head->pn_next; next; next = next->pn_next) {
    2673           0 :         RootedValue left(cx);
    2674           0 :         if (!expression(next, &left))
    2675           0 :             return false;
    2676             : 
    2677           0 :         TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end);
    2678             : 
    2679           0 :         BinaryOperator op = binop(pn->getKind(), pn->getOp());
    2680           0 :         LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
    2681             : 
    2682           0 :         if (!builder.binaryExpression(op, left, right, &subpos, &right))
    2683           0 :             return false;
    2684             :     }
    2685             : 
    2686           0 :     dst.set(right);
    2687           0 :     return true;
    2688             : }
    2689             : 
    2690             : bool
    2691           0 : ASTSerializer::comprehensionBlock(ParseNode* pn, MutableHandleValue dst)
    2692             : {
    2693           0 :     LOCAL_ASSERT(pn->isArity(PN_BINARY));
    2694             : 
    2695           0 :     ParseNode* in = pn->pn_left;
    2696             : 
    2697           0 :     LOCAL_ASSERT(in && (in->isKind(PNK_FORIN) || in->isKind(PNK_FOROF)));
    2698             : 
    2699           0 :     bool isForEach = in->isKind(PNK_FORIN) && (pn->pn_iflags & JSITER_FOREACH);
    2700           0 :     bool isForOf = in->isKind(PNK_FOROF);
    2701             : 
    2702           0 :     ParseNode* decl = in->pn_kid1;
    2703           0 :     if (decl->isKind(PNK_LEXICALSCOPE))
    2704           0 :         decl = decl->pn_expr;
    2705           0 :     MOZ_ASSERT(decl->pn_count == 1);
    2706             : 
    2707           0 :     RootedValue patt(cx), src(cx);
    2708           0 :     return pattern(decl->pn_head, &patt) &&
    2709           0 :            expression(in->pn_kid3, &src) &&
    2710           0 :            builder.comprehensionBlock(patt, src, isForEach, isForOf, &in->pn_pos, dst);
    2711             : }
    2712             : 
    2713             : bool
    2714           0 : ASTSerializer::comprehensionIf(ParseNode* pn, MutableHandleValue dst)
    2715             : {
    2716           0 :     LOCAL_ASSERT(pn->isKind(PNK_IF));
    2717           0 :     LOCAL_ASSERT(!pn->pn_kid3);
    2718             : 
    2719           0 :     RootedValue patt(cx);
    2720           0 :     return pattern(pn->pn_kid1, &patt) &&
    2721           0 :            builder.comprehensionIf(patt, &pn->pn_pos, dst);
    2722             : }
    2723             : 
    2724             : bool
    2725           0 : ASTSerializer::comprehension(ParseNode* pn, MutableHandleValue dst)
    2726             : {
    2727             :     // There are two array comprehension flavors.
    2728             :     // 1. The kind that was in ES4 for a while: [z for (x in y)]
    2729             :     // 2. The kind that was in ES6 for a while: [for (x of y) z]
    2730             :     // They have slightly different parse trees and scoping.
    2731           0 :     bool isLegacy = pn->isKind(PNK_LEXICALSCOPE);
    2732           0 :     ParseNode* next = isLegacy ? pn->pn_expr : pn;
    2733           0 :     LOCAL_ASSERT(next->isKind(PNK_COMPREHENSIONFOR));
    2734             : 
    2735           0 :     NodeVector blocks(cx);
    2736           0 :     RootedValue filter(cx, MagicValue(JS_SERIALIZE_NO_NODE));
    2737             :     while (true) {
    2738           0 :         if (next->isKind(PNK_COMPREHENSIONFOR)) {
    2739           0 :             RootedValue block(cx);
    2740           0 :             if (!comprehensionBlock(next, &block) || !blocks.append(block))
    2741           0 :                 return false;
    2742           0 :             next = next->pn_right;
    2743           0 :         } else if (next->isKind(PNK_IF)) {
    2744           0 :             if (isLegacy) {
    2745           0 :                 MOZ_ASSERT(filter.isMagic(JS_SERIALIZE_NO_NODE));
    2746           0 :                 if (!optExpression(next->pn_kid1, &filter))
    2747           0 :                     return false;
    2748             :             } else {
    2749             :                 // ES7 comprehension can contain multiple ComprehensionIfs.
    2750           0 :                 RootedValue compif(cx);
    2751           0 :                 if (!comprehensionIf(next, &compif) || !blocks.append(compif))
    2752           0 :                     return false;
    2753             :             }
    2754           0 :             next = next->pn_kid2;
    2755             :         } else {
    2756           0 :             break;
    2757             :         }
    2758           0 :     }
    2759             : 
    2760           0 :     LOCAL_ASSERT(next->isKind(PNK_ARRAYPUSH));
    2761             : 
    2762           0 :     RootedValue body(cx);
    2763             : 
    2764           0 :     return expression(next->pn_kid, &body) &&
    2765           0 :            builder.comprehensionExpression(body, blocks, filter, isLegacy, &pn->pn_pos, dst);
    2766             : }
    2767             : 
    2768             : bool
    2769           0 : ASTSerializer::generatorExpression(ParseNode* pn, MutableHandleValue dst)
    2770             : {
    2771             :     // Just as there are two kinds of array comprehension (see
    2772             :     // ASTSerializer::comprehension), there are legacy and modern generator
    2773             :     // expression.
    2774           0 :     bool isLegacy = pn->isKind(PNK_LEXICALSCOPE);
    2775           0 :     ParseNode* next = isLegacy ? pn->pn_expr : pn;
    2776           0 :     LOCAL_ASSERT(next->isKind(PNK_COMPREHENSIONFOR));
    2777             : 
    2778           0 :     NodeVector blocks(cx);
    2779           0 :     RootedValue filter(cx, MagicValue(JS_SERIALIZE_NO_NODE));
    2780             :     while (true) {
    2781           0 :         if (next->isKind(PNK_COMPREHENSIONFOR)) {
    2782           0 :             RootedValue block(cx);
    2783           0 :             if (!comprehensionBlock(next, &block) || !blocks.append(block))
    2784           0 :                 return false;
    2785           0 :             next = next->pn_right;
    2786           0 :         } else if (next->isKind(PNK_IF)) {
    2787           0 :             if (isLegacy) {
    2788           0 :                 MOZ_ASSERT(filter.isMagic(JS_SERIALIZE_NO_NODE));
    2789           0 :                 if (!optExpression(next->pn_kid1, &filter))
    2790           0 :                     return false;
    2791             :             } else {
    2792             :                 // ES7 comprehension can contain multiple ComprehensionIfs.
    2793           0 :                 RootedValue compif(cx);
    2794           0 :                 if (!comprehensionIf(next, &compif) || !blocks.append(compif))
    2795           0 :                     return false;
    2796             :             }
    2797           0 :             next = next->pn_kid2;
    2798             :         } else {
    2799           0 :             break;
    2800             :         }
    2801           0 :     }
    2802             : 
    2803           0 :     LOCAL_ASSERT(next->isKind(PNK_SEMI) &&
    2804             :                  next->pn_kid->isKind(PNK_YIELD) &&
    2805             :                  next->pn_kid->pn_kid);
    2806             : 
    2807           0 :     RootedValue body(cx);
    2808             : 
    2809           0 :     return expression(next->pn_kid->pn_kid, &body) &&
    2810           0 :            builder.generatorExpression(body, blocks, filter, isLegacy, &pn->pn_pos, dst);
    2811             : }
    2812             : 
    2813             : bool
    2814           0 : ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
    2815             : {
    2816           0 :     if (!CheckRecursionLimit(cx))
    2817           0 :         return false;
    2818             : 
    2819           0 :     switch (pn->getKind()) {
    2820             :       case PNK_FUNCTION:
    2821             :       {
    2822           0 :         ASTType type = pn->pn_funbox->function()->isArrow() ? AST_ARROW_EXPR : AST_FUNC_EXPR;
    2823           0 :         return function(pn, type, dst);
    2824             :       }
    2825             : 
    2826             :       case PNK_COMMA:
    2827             :       {
    2828           0 :         NodeVector exprs(cx);
    2829           0 :         return expressions(pn, exprs) &&
    2830           0 :                builder.sequenceExpression(exprs, &pn->pn_pos, dst);
    2831             :       }
    2832             : 
    2833             :       case PNK_CONDITIONAL:
    2834             :       {
    2835           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
    2836           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
    2837           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
    2838             : 
    2839           0 :         RootedValue test(cx), cons(cx), alt(cx);
    2840             : 
    2841           0 :         return expression(pn->pn_kid1, &test) &&
    2842           0 :                expression(pn->pn_kid2, &cons) &&
    2843           0 :                expression(pn->pn_kid3, &alt) &&
    2844           0 :                builder.conditionalExpression(test, cons, alt, &pn->pn_pos, dst);
    2845             :       }
    2846             : 
    2847             :       case PNK_OR:
    2848             :       case PNK_AND:
    2849           0 :         return leftAssociate(pn, dst);
    2850             : 
    2851             :       case PNK_PREINCREMENT:
    2852             :       case PNK_PREDECREMENT:
    2853             :       {
    2854           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
    2855             : 
    2856           0 :         bool inc = pn->isKind(PNK_PREINCREMENT);
    2857           0 :         RootedValue expr(cx);
    2858           0 :         return expression(pn->pn_kid, &expr) &&
    2859           0 :                builder.updateExpression(expr, inc, true, &pn->pn_pos, dst);
    2860             :       }
    2861             : 
    2862             :       case PNK_POSTINCREMENT:
    2863             :       case PNK_POSTDECREMENT:
    2864             :       {
    2865           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
    2866             : 
    2867           0 :         bool inc = pn->isKind(PNK_POSTINCREMENT);
    2868           0 :         RootedValue expr(cx);
    2869           0 :         return expression(pn->pn_kid, &expr) &&
    2870           0 :                builder.updateExpression(expr, inc, false, &pn->pn_pos, dst);
    2871             :       }
    2872             : 
    2873             :       case PNK_ASSIGN:
    2874             :       case PNK_ADDASSIGN:
    2875             :       case PNK_SUBASSIGN:
    2876             :       case PNK_BITORASSIGN:
    2877             :       case PNK_BITXORASSIGN:
    2878             :       case PNK_BITANDASSIGN:
    2879             :       case PNK_LSHASSIGN:
    2880             :       case PNK_RSHASSIGN:
    2881             :       case PNK_URSHASSIGN:
    2882             :       case PNK_MULASSIGN:
    2883             :       case PNK_DIVASSIGN:
    2884             :       case PNK_MODASSIGN:
    2885             :       case PNK_POWASSIGN:
    2886             :       {
    2887           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
    2888           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
    2889             : 
    2890           0 :         AssignmentOperator op = aop(pn->getOp());
    2891           0 :         LOCAL_ASSERT(op > AOP_ERR && op < AOP_LIMIT);
    2892             : 
    2893           0 :         RootedValue lhs(cx), rhs(cx);
    2894           0 :         return pattern(pn->pn_left, &lhs) &&
    2895           0 :                expression(pn->pn_right, &rhs) &&
    2896           0 :                builder.assignmentExpression(op, lhs, rhs, &pn->pn_pos, dst);
    2897             :       }
    2898             : 
    2899             :       case PNK_ADD:
    2900             :       case PNK_SUB:
    2901             :       case PNK_STRICTEQ:
    2902             :       case PNK_EQ:
    2903             :       case PNK_STRICTNE:
    2904             :       case PNK_NE:
    2905             :       case PNK_LT:
    2906             :       case PNK_LE:
    2907             :       case PNK_GT:
    2908             :       case PNK_GE:
    2909             :       case PNK_LSH:
    2910             :       case PNK_RSH:
    2911             :       case PNK_URSH:
    2912             :       case PNK_STAR:
    2913             :       case PNK_DIV:
    2914             :       case PNK_MOD:
    2915             :       case PNK_BITOR:
    2916             :       case PNK_BITXOR:
    2917             :       case PNK_BITAND:
    2918             :       case PNK_IN:
    2919             :       case PNK_INSTANCEOF:
    2920           0 :         return leftAssociate(pn, dst);
    2921             : 
    2922             :       case PNK_POW:
    2923           0 :         return rightAssociate(pn, dst);
    2924             : 
    2925             :       case PNK_DELETENAME:
    2926             :       case PNK_DELETEPROP:
    2927             :       case PNK_DELETEELEM:
    2928             :       case PNK_DELETEEXPR:
    2929             :       case PNK_TYPEOFNAME:
    2930             :       case PNK_TYPEOFEXPR:
    2931             :       case PNK_VOID:
    2932             :       case PNK_NOT:
    2933             :       case PNK_BITNOT:
    2934             :       case PNK_POS:
    2935             :       case PNK_AWAIT:
    2936             :       case PNK_NEG: {
    2937           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
    2938             : 
    2939           0 :         UnaryOperator op = unop(pn->getKind(), pn->getOp());
    2940           0 :         LOCAL_ASSERT(op > UNOP_ERR && op < UNOP_LIMIT);
    2941             : 
    2942           0 :         RootedValue expr(cx);
    2943           0 :         return expression(pn->pn_kid, &expr) &&
    2944           0 :                builder.unaryExpression(op, expr, &pn->pn_pos, dst);
    2945             :       }
    2946             : 
    2947             :       case PNK_GENEXP:
    2948           0 :         return generatorExpression(pn->generatorExpr(), dst);
    2949             : 
    2950             :       case PNK_NEW:
    2951             :       case PNK_TAGGED_TEMPLATE:
    2952             :       case PNK_CALL:
    2953             :       case PNK_SUPERCALL:
    2954             :       {
    2955           0 :         ParseNode* next = pn->pn_head;
    2956           0 :         MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
    2957             : 
    2958           0 :         RootedValue callee(cx);
    2959           0 :         if (pn->isKind(PNK_SUPERCALL)) {
    2960           0 :             MOZ_ASSERT(next->isKind(PNK_SUPERBASE));
    2961           0 :             if (!builder.super(&next->pn_pos, &callee))
    2962           0 :                 return false;
    2963             :         } else {
    2964           0 :             if (!expression(next, &callee))
    2965           0 :                 return false;
    2966             :         }
    2967             : 
    2968           0 :         NodeVector args(cx);
    2969           0 :         if (!args.reserve(pn->pn_count - 1))
    2970           0 :             return false;
    2971             : 
    2972           0 :         for (next = next->pn_next; next; next = next->pn_next) {
    2973           0 :             MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
    2974             : 
    2975           0 :             RootedValue arg(cx);
    2976           0 :             if (!expression(next, &arg))
    2977           0 :                 return false;
    2978           0 :             args.infallibleAppend(arg);
    2979             :         }
    2980             : 
    2981           0 :         if (pn->getKind() == PNK_TAGGED_TEMPLATE)
    2982           0 :             return builder.taggedTemplate(callee, args, &pn->pn_pos, dst);
    2983             : 
    2984             :         // SUPERCALL is Call(super, args)
    2985           0 :         return pn->isKind(PNK_NEW)
    2986           0 :                ? builder.newExpression(callee, args, &pn->pn_pos, dst)
    2987             : 
    2988           0 :             : builder.callExpression(callee, args, &pn->pn_pos, dst);
    2989             :       }
    2990             : 
    2991             :       case PNK_DOT:
    2992             :       {
    2993           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
    2994             : 
    2995           0 :         RootedValue expr(cx);
    2996           0 :         RootedValue propname(cx);
    2997           0 :         RootedAtom pnAtom(cx, pn->pn_atom);
    2998             : 
    2999           0 :         if (pn->as<PropertyAccess>().isSuper()) {
    3000           0 :             if (!builder.super(&pn->pn_expr->pn_pos, &expr))
    3001           0 :                 return false;
    3002             :         } else {
    3003           0 :             if (!expression(pn->pn_expr, &expr))
    3004           0 :                 return false;
    3005             :         }
    3006             : 
    3007           0 :         return identifier(pnAtom, nullptr, &propname) &&
    3008           0 :                builder.memberExpression(false, expr, propname, &pn->pn_pos, dst);
    3009             :       }
    3010             : 
    3011             :       case PNK_ELEM:
    3012             :       {
    3013           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
    3014           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
    3015             : 
    3016           0 :         RootedValue left(cx), right(cx);
    3017             : 
    3018           0 :         if (pn->as<PropertyByValue>().isSuper()) {
    3019           0 :             if (!builder.super(&pn->pn_left->pn_pos, &left))
    3020           0 :                 return false;
    3021             :         } else {
    3022           0 :             if (!expression(pn->pn_left, &left))
    3023           0 :                 return false;
    3024             :         }
    3025             : 
    3026           0 :         return expression(pn->pn_right, &right) &&
    3027           0 :                builder.memberExpression(true, left, right, &pn->pn_pos, dst);
    3028             :       }
    3029             : 
    3030             :       case PNK_CALLSITEOBJ:
    3031             :       {
    3032           0 :         NodeVector raw(cx);
    3033           0 :         if (!raw.reserve(pn->pn_head->pn_count))
    3034           0 :             return false;
    3035           0 :         for (ParseNode* next = pn->pn_head->pn_head; next; next = next->pn_next) {
    3036           0 :             MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
    3037             : 
    3038           0 :             RootedValue expr(cx);
    3039           0 :             expr.setString(next->pn_atom);
    3040           0 :             raw.infallibleAppend(expr);
    3041             :         }
    3042             : 
    3043           0 :         NodeVector cooked(cx);
    3044           0 :         if (!cooked.reserve(pn->pn_count - 1))
    3045           0 :             return false;
    3046             : 
    3047           0 :         for (ParseNode* next = pn->pn_head->pn_next; next; next = next->pn_next) {
    3048           0 :             MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
    3049             : 
    3050           0 :             RootedValue expr(cx);
    3051           0 :             if (next->isKind(PNK_RAW_UNDEFINED)) {
    3052           0 :                 expr.setUndefined();
    3053             :             } else {
    3054           0 :                 MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING));
    3055           0 :                 expr.setString(next->pn_atom);
    3056             :             }
    3057           0 :             cooked.infallibleAppend(expr);
    3058             :         }
    3059             : 
    3060           0 :         return builder.callSiteObj(raw, cooked, &pn->pn_pos, dst);
    3061             :       }
    3062             : 
    3063             :       case PNK_ARRAY:
    3064             :       {
    3065           0 :         NodeVector elts(cx);
    3066           0 :         if (!elts.reserve(pn->pn_count))
    3067           0 :             return false;
    3068             : 
    3069           0 :         for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
    3070           0 :             MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
    3071             : 
    3072           0 :             if (next->isKind(PNK_ELISION)) {
    3073           0 :                 elts.infallibleAppend(NullValue());
    3074             :             } else {
    3075           0 :                 RootedValue expr(cx);
    3076           0 :                 if (!expression(next, &expr))
    3077           0 :                     return false;
    3078           0 :                 elts.infallibleAppend(expr);
    3079             :             }
    3080             :         }
    3081             : 
    3082           0 :         return builder.arrayExpression(elts, &pn->pn_pos, dst);
    3083             :       }
    3084             : 
    3085             :       case PNK_SPREAD:
    3086             :       {
    3087           0 :           RootedValue expr(cx);
    3088           0 :           return expression(pn->pn_kid, &expr) &&
    3089           0 :                  builder.spreadExpression(expr, &pn->pn_pos, dst);
    3090             :       }
    3091             : 
    3092             :       case PNK_COMPUTED_NAME:
    3093             :       {
    3094           0 :          RootedValue name(cx);
    3095           0 :          return expression(pn->pn_kid, &name) &&
    3096           0 :                 builder.computedName(name, &pn->pn_pos, dst);
    3097             :       }
    3098             : 
    3099             :       case PNK_OBJECT:
    3100             :       {
    3101           0 :         NodeVector elts(cx);
    3102           0 :         if (!elts.reserve(pn->pn_count))
    3103           0 :             return false;
    3104             : 
    3105           0 :         for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
    3106           0 :             MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
    3107             : 
    3108           0 :             RootedValue prop(cx);
    3109           0 :             if (!property(next, &prop))
    3110           0 :                 return false;
    3111           0 :             elts.infallibleAppend(prop);
    3112             :         }
    3113             : 
    3114           0 :         return builder.objectExpression(elts, &pn->pn_pos, dst);
    3115             :       }
    3116             : 
    3117             :       case PNK_NAME:
    3118           0 :         return identifier(pn, dst);
    3119             : 
    3120             :       case PNK_THIS:
    3121           0 :         return builder.thisExpression(&pn->pn_pos, dst);
    3122             : 
    3123             :       case PNK_TEMPLATE_STRING_LIST:
    3124             :       {
    3125           0 :         NodeVector elts(cx);
    3126           0 :         if (!elts.reserve(pn->pn_count))
    3127           0 :             return false;
    3128             : 
    3129           0 :         for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
    3130           0 :             MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
    3131             : 
    3132           0 :             RootedValue expr(cx);
    3133           0 :             if (!expression(next, &expr))
    3134           0 :                 return false;
    3135           0 :             elts.infallibleAppend(expr);
    3136             :         }
    3137             : 
    3138           0 :         return builder.templateLiteral(elts, &pn->pn_pos, dst);
    3139             :       }
    3140             : 
    3141             :       case PNK_TEMPLATE_STRING:
    3142             :       case PNK_STRING:
    3143             :       case PNK_REGEXP:
    3144             :       case PNK_NUMBER:
    3145             :       case PNK_TRUE:
    3146             :       case PNK_FALSE:
    3147             :       case PNK_NULL:
    3148             :       case PNK_RAW_UNDEFINED:
    3149           0 :         return literal(pn, dst);
    3150             : 
    3151             :       case PNK_YIELD_STAR:
    3152             :       {
    3153           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
    3154             : 
    3155           0 :         RootedValue arg(cx);
    3156           0 :         return expression(pn->pn_kid, &arg) &&
    3157           0 :                builder.yieldExpression(arg, Delegating, &pn->pn_pos, dst);
    3158             :       }
    3159             : 
    3160             :       case PNK_YIELD:
    3161             :       {
    3162           0 :         MOZ_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
    3163             : 
    3164           0 :         RootedValue arg(cx);
    3165           0 :         return optExpression(pn->pn_kid, &arg) &&
    3166           0 :                builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst);
    3167             :       }
    3168             : 
    3169             :       case PNK_ARRAYCOMP:
    3170           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_head->pn_pos));
    3171             : 
    3172             :         /* NB: it's no longer the case that pn_count could be 2. */
    3173           0 :         LOCAL_ASSERT(pn->pn_count == 1);
    3174           0 :         return comprehension(pn->pn_head, dst);
    3175             : 
    3176             :       case PNK_CLASS:
    3177           0 :         return classDefinition(pn, true, dst);
    3178             : 
    3179             :       case PNK_NEWTARGET:
    3180             :       {
    3181           0 :         MOZ_ASSERT(pn->pn_left->isKind(PNK_POSHOLDER));
    3182           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
    3183           0 :         MOZ_ASSERT(pn->pn_right->isKind(PNK_POSHOLDER));
    3184           0 :         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
    3185             : 
    3186           0 :         RootedValue newIdent(cx);
    3187           0 :         RootedValue targetIdent(cx);
    3188             : 
    3189           0 :         RootedAtom newStr(cx, cx->names().new_);
    3190           0 :         RootedAtom targetStr(cx, cx->names().target);
    3191             : 
    3192           0 :         return identifier(newStr, &pn->pn_left->pn_pos, &newIdent) &&
    3193           0 :                identifier(targetStr, &pn->pn_right->pn_pos, &targetIdent) &&
    3194           0 :                builder.metaProperty(newIdent, targetIdent, &pn->pn_pos, dst);
    3195             :       }
    3196             : 
    3197             :       case PNK_SETTHIS:
    3198             :         // SETTHIS is used to assign the result of a super() call to |this|.
    3199             :         // It's not part of the original AST, so just forward to the call.
    3200           0 :         MOZ_ASSERT(pn->pn_left->isKind(PNK_NAME));
    3201           0 :         return expression(pn->pn_right, dst);
    3202             : 
    3203             :       default:
    3204           0 :         LOCAL_NOT_REACHED("unexpected expression type");
    3205             :     }
    3206             : }
    3207             : 
    3208             : bool
    3209           0 : ASTSerializer::propertyName(ParseNode* pn, MutableHandleValue dst)
    3210             : {
    3211           0 :     if (pn->isKind(PNK_COMPUTED_NAME))
    3212           0 :         return expression(pn, dst);
    3213           0 :     if (pn->isKind(PNK_OBJECT_PROPERTY_NAME))
    3214           0 :         return identifier(pn, dst);
    3215             : 
    3216           0 :     LOCAL_ASSERT(pn->isKind(PNK_STRING) || pn->isKind(PNK_NUMBER));
    3217             : 
    3218           0 :     return literal(pn, dst);
    3219             : }
    3220             : 
    3221             : bool
    3222           0 : ASTSerializer::property(ParseNode* pn, MutableHandleValue dst)
    3223             : {
    3224           0 :     if (pn->isKind(PNK_MUTATEPROTO)) {
    3225           0 :         RootedValue val(cx);
    3226           0 :         return expression(pn->pn_kid, &val) &&
    3227           0 :                builder.prototypeMutation(val, &pn->pn_pos, dst);
    3228             :     }
    3229           0 :     if (pn->isKind(PNK_SPREAD))
    3230           0 :         return expression(pn, dst);
    3231             : 
    3232             :     PropKind kind;
    3233           0 :     switch (pn->getOp()) {
    3234             :       case JSOP_INITPROP:
    3235           0 :         kind = PROP_INIT;
    3236           0 :         break;
    3237             : 
    3238             :       case JSOP_INITPROP_GETTER:
    3239           0 :         kind = PROP_GETTER;
    3240           0 :         break;
    3241             : 
    3242             :       case JSOP_INITPROP_SETTER:
    3243           0 :         kind = PROP_SETTER;
    3244           0 :         break;
    3245             : 
    3246             :       default:
    3247           0 :         LOCAL_NOT_REACHED("unexpected object-literal property");
    3248             :     }
    3249             : 
    3250           0 :     bool isShorthand = pn->isKind(PNK_SHORTHAND);
    3251             :     bool isMethod =
    3252           0 :         pn->pn_right->isKind(PNK_FUNCTION) &&
    3253           0 :         pn->pn_right->pn_funbox->function()->kind() == JSFunction::Method;
    3254           0 :     RootedValue key(cx), val(cx);
    3255           0 :     return propertyName(pn->pn_left, &key) &&
    3256           0 :            expression(pn->pn_right, &val) &&
    3257           0 :            builder.propertyInitializer(key, val, kind, isShorthand, isMethod, &pn->pn_pos, dst);
    3258             : }
    3259             : 
    3260             : bool
    3261           0 : ASTSerializer::literal(ParseNode* pn, MutableHandleValue dst)
    3262             : {
    3263           0 :     RootedValue val(cx);
    3264           0 :     switch (pn->getKind()) {
    3265             :       case PNK_TEMPLATE_STRING:
    3266             :       case PNK_STRING:
    3267           0 :         val.setString(pn->pn_atom);
    3268           0 :         break;
    3269             : 
    3270             :       case PNK_REGEXP:
    3271             :       {
    3272           0 :         RootedObject re1(cx, pn->as<RegExpLiteral>().objbox()->object);
    3273           0 :         LOCAL_ASSERT(re1 && re1->is<RegExpObject>());
    3274             : 
    3275           0 :         RootedObject re2(cx, CloneRegExpObject(cx, re1.as<RegExpObject>()));
    3276           0 :         if (!re2)
    3277           0 :             return false;
    3278             : 
    3279           0 :         val.setObject(*re2);
    3280           0 :         break;
    3281             :       }
    3282             : 
    3283             :       case PNK_NUMBER:
    3284           0 :         val.setNumber(pn->pn_dval);
    3285           0 :         break;
    3286             : 
    3287             :       case PNK_NULL:
    3288           0 :         val.setNull();
    3289           0 :         break;
    3290             : 
    3291             :       case PNK_RAW_UNDEFINED:
    3292           0 :         val.setUndefined();
    3293           0 :         break;
    3294             : 
    3295             :       case PNK_TRUE:
    3296           0 :         val.setBoolean(true);
    3297           0 :         break;
    3298             : 
    3299             :       case PNK_FALSE:
    3300           0 :         val.setBoolean(false);
    3301           0 :         break;
    3302             : 
    3303             :       default:
    3304           0 :         LOCAL_NOT_REACHED("unexpected literal type");
    3305             :     }
    3306             : 
    3307           0 :     return builder.literal(val, &pn->pn_pos, dst);
    3308             : }
    3309             : 
    3310             : bool
    3311           0 : ASTSerializer::arrayPattern(ParseNode* pn, MutableHandleValue dst)
    3312             : {
    3313           0 :     MOZ_ASSERT(pn->isKind(PNK_ARRAY));
    3314             : 
    3315           0 :     NodeVector elts(cx);
    3316           0 :     if (!elts.reserve(pn->pn_count))
    3317           0 :         return false;
    3318             : 
    3319           0 :     for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
    3320           0 :         if (next->isKind(PNK_ELISION)) {
    3321           0 :             elts.infallibleAppend(NullValue());
    3322           0 :         } else if (next->isKind(PNK_SPREAD)) {
    3323           0 :             RootedValue target(cx);
    3324           0 :             RootedValue spread(cx);
    3325           0 :             if (!pattern(next->pn_kid, &target))
    3326           0 :                 return false;
    3327           0 :             if(!builder.spreadExpression(target, &next->pn_pos, &spread))
    3328           0 :                 return false;
    3329           0 :             elts.infallibleAppend(spread);
    3330             :         } else {
    3331           0 :             RootedValue patt(cx);
    3332           0 :             if (!pattern(next, &patt))
    3333           0 :                 return false;
    3334           0 :             elts.infallibleAppend(patt);
    3335             :         }
    3336             :     }
    3337             : 
    3338           0 :     return builder.arrayPattern(elts, &pn->pn_pos, dst);
    3339             : }
    3340             : 
    3341             : bool
    3342           0 : ASTSerializer::objectPattern(ParseNode* pn, MutableHandleValue dst)
    3343             : {
    3344           0 :     MOZ_ASSERT(pn->isKind(PNK_OBJECT));
    3345             : 
    3346           0 :     NodeVector elts(cx);
    3347           0 :     if (!elts.reserve(pn->pn_count))
    3348           0 :         return false;
    3349             : 
    3350           0 :     for (ParseNode* propdef = pn->pn_head; propdef; propdef = propdef->pn_next) {
    3351           0 :         if (propdef->isKind(PNK_SPREAD)) {
    3352           0 :             RootedValue target(cx);
    3353           0 :             RootedValue spread(cx);
    3354           0 :             if (!pattern(propdef->pn_kid, &target))
    3355           0 :                 return false;
    3356           0 :             if(!builder.spreadExpression(target, &propdef->pn_pos, &spread))
    3357           0 :                 return false;
    3358           0 :             elts.infallibleAppend(spread);
    3359           0 :             continue;
    3360             :         }
    3361           0 :         LOCAL_ASSERT(propdef->isKind(PNK_MUTATEPROTO) != propdef->isOp(JSOP_INITPROP));
    3362             : 
    3363           0 :         RootedValue key(cx);
    3364             :         ParseNode* target;
    3365           0 :         if (propdef->isKind(PNK_MUTATEPROTO)) {
    3366           0 :             RootedValue pname(cx, StringValue(cx->names().proto));
    3367           0 :             if (!builder.literal(pname, &propdef->pn_pos, &key))
    3368           0 :                 return false;
    3369           0 :             target = propdef->pn_kid;
    3370             :         } else {
    3371           0 :             if (!propertyName(propdef->pn_left, &key))
    3372           0 :                 return false;
    3373           0 :             target = propdef->pn_right;
    3374             :         }
    3375             : 
    3376           0 :         RootedValue patt(cx), prop(cx);
    3377           0 :         if (!pattern(target, &patt) ||
    3378           0 :             !builder.propertyPattern(key, patt, propdef->isKind(PNK_SHORTHAND), &propdef->pn_pos,
    3379             :                                      &prop))
    3380             :         {
    3381           0 :             return false;
    3382             :         }
    3383             : 
    3384           0 :         elts.infallibleAppend(prop);
    3385             :     }
    3386             : 
    3387           0 :     return builder.objectPattern(elts, &pn->pn_pos, dst);
    3388             : }
    3389             : 
    3390             : bool
    3391           0 : ASTSerializer::pattern(ParseNode* pn, MutableHandleValue dst)
    3392             : {
    3393           0 :     if (!CheckRecursionLimit(cx))
    3394           0 :         return false;
    3395             : 
    3396           0 :     switch (pn->getKind()) {
    3397             :       case PNK_OBJECT:
    3398           0 :         return objectPattern(pn, dst);
    3399             : 
    3400             :       case PNK_ARRAY:
    3401           0 :         return arrayPattern(pn, dst);
    3402             : 
    3403             :       default:
    3404           0 :         return expression(pn, dst);
    3405             :     }
    3406             : }
    3407             : 
    3408             : bool
    3409           0 : ASTSerializer::identifier(HandleAtom atom, TokenPos* pos, MutableHandleValue dst)
    3410             : {
    3411           0 :     RootedValue atomContentsVal(cx, unrootedAtomContents(atom));
    3412           0 :     return builder.identifier(atomContentsVal, pos, dst);
    3413             : }
    3414             : 
    3415             : bool
    3416           0 : ASTSerializer::identifier(ParseNode* pn, MutableHandleValue dst)
    3417             : {
    3418           0 :     LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_NULLARY));
    3419           0 :     LOCAL_ASSERT(pn->pn_atom);
    3420             : 
    3421           0 :     RootedAtom pnAtom(cx, pn->pn_atom);
    3422           0 :     return identifier(pnAtom, &pn->pn_pos, dst);
    3423             : }
    3424             : 
    3425             : bool
    3426           0 : ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
    3427             : {
    3428           0 :     RootedFunction func(cx, pn->pn_funbox->function());
    3429             : 
    3430             :     GeneratorStyle generatorStyle =
    3431           0 :         pn->pn_funbox->isStarGenerator()
    3432           0 :         ? GeneratorStyle::ES6
    3433           0 :         : pn->pn_funbox->isLegacyGenerator()
    3434           0 :         ? GeneratorStyle::Legacy
    3435           0 :         : GeneratorStyle::None;
    3436             : 
    3437           0 :     bool isAsync = pn->pn_funbox->isAsync();
    3438           0 :     bool isExpression = pn->pn_funbox->isExprBody();
    3439             : 
    3440           0 :     RootedValue id(cx);
    3441           0 :     RootedAtom funcAtom(cx, func->explicitName());
    3442           0 :     if (!optIdentifier(funcAtom, nullptr, &id))
    3443           0 :         return false;
    3444             : 
    3445           0 :     NodeVector args(cx);
    3446           0 :     NodeVector defaults(cx);
    3447             : 
    3448           0 :     RootedValue body(cx), rest(cx);
    3449           0 :     if (pn->pn_funbox->hasRest())
    3450           0 :         rest.setUndefined();
    3451             :     else
    3452           0 :         rest.setNull();
    3453           0 :     return functionArgsAndBody(pn->pn_body, args, defaults, isAsync, isExpression, &body, &rest) &&
    3454           0 :            builder.function(type, &pn->pn_pos, id, args, defaults, body,
    3455           0 :                             rest, generatorStyle, isAsync, isExpression, dst);
    3456             : }
    3457             : 
    3458             : bool
    3459           0 : ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector& defaults,
    3460             :                                    bool isAsync, bool isExpression,
    3461             :                                    MutableHandleValue body, MutableHandleValue rest)
    3462             : {
    3463             :     ParseNode* pnargs;
    3464             :     ParseNode* pnbody;
    3465             : 
    3466             :     /* Extract the args and body separately. */
    3467           0 :     if (pn->isKind(PNK_PARAMSBODY)) {
    3468           0 :         pnargs = pn;
    3469           0 :         pnbody = pn->last();
    3470             :     } else {
    3471           0 :         pnargs = nullptr;
    3472           0 :         pnbody = pn;
    3473             :     }
    3474             : 
    3475           0 :     if (pnbody->isKind(PNK_LEXICALSCOPE))
    3476           0 :         pnbody = pnbody->scopeBody();
    3477             : 
    3478             :     /* Serialize the arguments and body. */
    3479           0 :     switch (pnbody->getKind()) {
    3480             :       case PNK_RETURN: /* expression closure, no destructured args */
    3481           0 :         return functionArgs(pn, pnargs, args, defaults, rest) &&
    3482           0 :                expression(pnbody->pn_kid, body);
    3483             : 
    3484             :       case PNK_STATEMENTLIST:     /* statement closure */
    3485             :       {
    3486           0 :         ParseNode* pnstart = pnbody->pn_head;
    3487             : 
    3488             :         // Skip over initial yield in generator.
    3489           0 :         if (pnstart && pnstart->isKind(PNK_INITIALYIELD)) {
    3490           0 :             MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD);
    3491           0 :             pnstart = pnstart->pn_next;
    3492             :         }
    3493             : 
    3494             :         // Async arrow with expression body is converted into STATEMENTLIST
    3495             :         // to insert initial yield.
    3496           0 :         if (isAsync && isExpression) {
    3497           0 :             MOZ_ASSERT(pnstart->getKind() == PNK_RETURN);
    3498           0 :             return functionArgs(pn, pnargs, args, defaults, rest) &&
    3499           0 :                    expression(pnstart->pn_kid, body);
    3500             :         }
    3501             : 
    3502           0 :         return functionArgs(pn, pnargs, args, defaults, rest) &&
    3503           0 :                functionBody(pnstart, &pnbody->pn_pos, body);
    3504             :       }
    3505             : 
    3506             :       default:
    3507           0 :         LOCAL_NOT_REACHED("unexpected function contents");
    3508             :     }
    3509             : }
    3510             : 
    3511             : bool
    3512           0 : ASTSerializer::functionArgs(ParseNode* pn, ParseNode* pnargs,
    3513             :                             NodeVector& args, NodeVector& defaults,
    3514             :                             MutableHandleValue rest)
    3515             : {
    3516           0 :     if (!pnargs)
    3517           0 :         return true;
    3518             : 
    3519           0 :     RootedValue node(cx);
    3520           0 :     bool defaultsNull = true;
    3521           0 :     MOZ_ASSERT(defaults.empty(),
    3522             :                "must be initially empty for it to be proper to clear this "
    3523             :                "when there are no defaults");
    3524             : 
    3525           0 :     for (ParseNode* arg = pnargs->pn_head; arg && arg != pnargs->last(); arg = arg->pn_next) {
    3526             :         ParseNode* pat;
    3527             :         ParseNode* defNode;
    3528           0 :         if (arg->isKind(PNK_NAME) || arg->isKind(PNK_ARRAY) || arg->isKind(PNK_OBJECT)) {
    3529           0 :             pat = arg;
    3530           0 :             defNode = nullptr;
    3531             :         } else {
    3532           0 :             MOZ_ASSERT(arg->isKind(PNK_ASSIGN));
    3533           0 :             pat = arg->pn_left;
    3534           0 :             defNode = arg->pn_right;
    3535             :         }
    3536             : 
    3537             :         // Process the name or pattern.
    3538           0 :         MOZ_ASSERT(pat->isKind(PNK_NAME) || pat->isKind(PNK_ARRAY) || pat->isKind(PNK_OBJECT));
    3539           0 :         if (!pattern(pat, &node))
    3540           0 :             return false;
    3541           0 :         if (rest.isUndefined() && arg->pn_next == pnargs->last()) {
    3542           0 :             rest.setObject(node.toObject());
    3543             :         } else {
    3544           0 :             if (!args.append(node))
    3545           0 :                 return false;
    3546             :         }
    3547             : 
    3548             :         // Process its default (or lack thereof).
    3549           0 :         if (defNode) {
    3550           0 :             defaultsNull = false;
    3551           0 :             RootedValue def(cx);
    3552           0 :             if (!expression(defNode, &def) || !defaults.append(def))
    3553           0 :                 return false;
    3554             :         } else {
    3555           0 :             if (!defaults.append(NullValue()))
    3556           0 :                 return false;
    3557             :         }
    3558             :     }
    3559           0 :     MOZ_ASSERT(!rest.isUndefined(),
    3560             :                "if a rest argument was present (signified by "
    3561             :                "|rest.isUndefined()| initially), the rest node was properly "
    3562             :                "recorded");
    3563             : 
    3564           0 :     if (defaultsNull)
    3565           0 :         defaults.clear();
    3566             : 
    3567           0 :     return true;
    3568             : }
    3569             : 
    3570             : bool
    3571           0 : ASTSerializer::functionBody(ParseNode* pn, TokenPos* pos, MutableHandleValue dst)
    3572             : {
    3573           0 :     NodeVector elts(cx);
    3574             : 
    3575             :     /* We aren't sure how many elements there are up front, so we'll check each append. */
    3576           0 :     for (ParseNode* next = pn; next; next = next->pn_next) {
    3577           0 :         RootedValue child(cx);
    3578           0 :         if (!sourceElement(next, &child) || !elts.append(child))
    3579           0 :             return false;
    3580             :     }
    3581             : 
    3582           0 :     return builder.blockStatement(elts, pos, dst);
    3583             : }
    3584             : 
    3585             : static bool
    3586           0 : reflect_parse(JSContext* cx, uint32_t argc, Value* vp)
    3587             : {
    3588           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    3589             : 
    3590           0 :     if (args.length() < 1) {
    3591             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
    3592           0 :                                   "Reflect.parse", "0", "s");
    3593           0 :         return false;
    3594             :     }
    3595             : 
    3596           0 :     RootedString src(cx, ToString<CanGC>(cx, args[0]));
    3597           0 :     if (!src)
    3598           0 :         return false;
    3599             : 
    3600           0 :     ScopedJSFreePtr<char> filename;
    3601           0 :     uint32_t lineno = 1;
    3602           0 :     bool loc = true;
    3603           0 :     RootedObject builder(cx);
    3604           0 :     ParseTarget target = ParseTarget::Script;
    3605             : 
    3606           0 :     RootedValue arg(cx, args.get(1));
    3607             : 
    3608           0 :     if (!arg.isNullOrUndefined()) {
    3609           0 :         if (!arg.isObject()) {
    3610           0 :             ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
    3611             :                                   JSDVG_SEARCH_STACK, arg, nullptr,
    3612           0 :                                   "not an object", nullptr);
    3613           0 :             return false;
    3614             :         }
    3615             : 
    3616           0 :         RootedObject config(cx, &arg.toObject());
    3617             : 
    3618           0 :         RootedValue prop(cx);
    3619             : 
    3620             :         /* config.loc */
    3621           0 :         RootedId locId(cx, NameToId(cx->names().loc));
    3622           0 :         RootedValue trueVal(cx, BooleanValue(true));
    3623           0 :         if (!GetPropertyDefault(cx, config, locId, trueVal, &prop))
    3624           0 :             return false;
    3625             : 
    3626           0 :         loc = ToBoolean(prop);
    3627             : 
    3628           0 :         if (loc) {
    3629             :             /* config.source */
    3630           0 :             RootedId sourceId(cx, NameToId(cx->names().source));
    3631           0 :             RootedValue nullVal(cx, NullValue());
    3632           0 :             if (!GetPropertyDefault(cx, config, sourceId, nullVal, &prop))
    3633           0 :                 return false;
    3634             : 
    3635           0 :             if (!prop.isNullOrUndefined()) {
    3636           0 :                 RootedString str(cx, ToString<CanGC>(cx, prop));
    3637           0 :                 if (!str)
    3638           0 :                     return false;
    3639             : 
    3640           0 :                 filename = JS_EncodeString(cx, str);
    3641           0 :                 if (!filename)
    3642           0 :                     return false;
    3643             :             }
    3644             : 
    3645             :             /* config.line */
    3646           0 :             RootedId lineId(cx, NameToId(cx->names().line));
    3647           0 :             RootedValue oneValue(cx, Int32Value(1));
    3648           0 :             if (!GetPropertyDefault(cx, config, lineId, oneValue, &prop) ||
    3649           0 :                 !ToUint32(cx, prop, &lineno)) {
    3650           0 :                 return false;
    3651             :             }
    3652             :         }
    3653             : 
    3654             :         /* config.builder */
    3655           0 :         RootedId builderId(cx, NameToId(cx->names().builder));
    3656           0 :         RootedValue nullVal(cx, NullValue());
    3657           0 :         if (!GetPropertyDefault(cx, config, builderId, nullVal, &prop))
    3658           0 :             return false;
    3659             : 
    3660           0 :         if (!prop.isNullOrUndefined()) {
    3661           0 :             if (!prop.isObject()) {
    3662           0 :                 ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
    3663             :                                       JSDVG_SEARCH_STACK, prop, nullptr,
    3664           0 :                                       "not an object", nullptr);
    3665           0 :                 return false;
    3666             :             }
    3667           0 :             builder = &prop.toObject();
    3668             :         }
    3669             : 
    3670             :         /* config.target */
    3671           0 :         RootedId targetId(cx, NameToId(cx->names().target));
    3672           0 :         RootedValue scriptVal(cx, StringValue(cx->names().script));
    3673           0 :         if (!GetPropertyDefault(cx, config, targetId, scriptVal, &prop))
    3674           0 :             return false;
    3675             : 
    3676           0 :         if (!prop.isString()) {
    3677           0 :             ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE, JSDVG_SEARCH_STACK,
    3678           0 :                                   prop, nullptr, "not 'script' or 'module'", nullptr);
    3679           0 :             return false;
    3680             :         }
    3681             : 
    3682           0 :         RootedString stringProp(cx, prop.toString());
    3683           0 :         bool isScript = false;
    3684           0 :         bool isModule = false;
    3685           0 :         if (!EqualStrings(cx, stringProp, cx->names().script, &isScript))
    3686           0 :             return false;
    3687             : 
    3688           0 :         if (!EqualStrings(cx, stringProp, cx->names().module, &isModule))
    3689           0 :             return false;
    3690             : 
    3691           0 :         if (isScript) {
    3692           0 :             target = ParseTarget::Script;
    3693           0 :         } else if (isModule) {
    3694           0 :             target = ParseTarget::Module;
    3695             :         } else {
    3696           0 :             JS_ReportErrorASCII(cx, "Bad target value, expected 'script' or 'module'");
    3697           0 :             return false;
    3698             :         }
    3699             :     }
    3700             : 
    3701             :     /* Extract the builder methods first to report errors before parsing. */
    3702           0 :     ASTSerializer serialize(cx, loc, filename, lineno);
    3703           0 :     if (!serialize.init(builder))
    3704           0 :         return false;
    3705             : 
    3706           0 :     JSLinearString* linear = src->ensureLinear(cx);
    3707           0 :     if (!linear)
    3708           0 :         return false;
    3709             : 
    3710           0 :     AutoStableStringChars linearChars(cx);
    3711           0 :     if (!linearChars.initTwoByte(cx, linear))
    3712           0 :         return false;
    3713             : 
    3714           0 :     CompileOptions options(cx);
    3715           0 :     options.setFileAndLine(filename, lineno);
    3716           0 :     options.setCanLazilyParse(false);
    3717           0 :     options.allowHTMLComments = target == ParseTarget::Script;
    3718           0 :     mozilla::Range<const char16_t> chars = linearChars.twoByteRange();
    3719           0 :     UsedNameTracker usedNames(cx);
    3720           0 :     if (!usedNames.init())
    3721           0 :         return false;
    3722             :     Parser<FullParseHandler, char16_t> parser(cx, cx->tempLifoAlloc(), options,
    3723           0 :                                               chars.begin().get(), chars.length(),
    3724             :                                               /* foldConstants = */ false, usedNames, nullptr,
    3725           0 :                                               nullptr);
    3726           0 :     if (!parser.checkOptions())
    3727           0 :         return false;
    3728             : 
    3729           0 :     serialize.setParser(&parser);
    3730             : 
    3731             :     ParseNode* pn;
    3732           0 :     if (target == ParseTarget::Script) {
    3733           0 :         pn = parser.parse();
    3734           0 :         if (!pn)
    3735           0 :             return false;
    3736             :     } else {
    3737           0 :         if (!GlobalObject::ensureModulePrototypesCreated(cx, cx->global()))
    3738           0 :             return false;
    3739             : 
    3740           0 :         Rooted<ModuleObject*> module(cx, ModuleObject::create(cx));
    3741           0 :         if (!module)
    3742           0 :             return false;
    3743             : 
    3744           0 :         ModuleBuilder builder(cx, module);
    3745           0 :         ModuleSharedContext modulesc(cx, module, &cx->global()->emptyGlobalScope(), builder);
    3746           0 :         pn = parser.moduleBody(&modulesc);
    3747           0 :         if (!pn)
    3748           0 :             return false;
    3749             : 
    3750           0 :         MOZ_ASSERT(pn->getKind() == PNK_MODULE);
    3751           0 :         pn = pn->pn_body;
    3752             :     }
    3753             : 
    3754           0 :     RootedValue val(cx);
    3755           0 :     if (!serialize.program(pn, &val)) {
    3756           0 :         args.rval().setNull();
    3757           0 :         return false;
    3758             :     }
    3759             : 
    3760           0 :     args.rval().set(val);
    3761           0 :     return true;
    3762             : }
    3763             : 
    3764             : JS_PUBLIC_API(bool)
    3765           0 : JS_InitReflectParse(JSContext* cx, HandleObject global)
    3766             : {
    3767           0 :     RootedValue reflectVal(cx);
    3768           0 :     if (!GetProperty(cx, global, global, cx->names().Reflect, &reflectVal))
    3769           0 :         return false;
    3770           0 :     if (!reflectVal.isObject()) {
    3771           0 :         JS_ReportErrorASCII(cx, "JS_InitReflectParse must be called during global initialization");
    3772           0 :         return false;
    3773             :     }
    3774             : 
    3775           0 :     RootedObject reflectObj(cx, &reflectVal.toObject());
    3776           0 :     return JS_DefineFunction(cx, reflectObj, "parse", reflect_parse, 1, 0);
    3777             : }

Generated by: LCOV version 1.13