js/src/frontend/Parser.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/frontend/Parser.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,7499 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/*
    1.11 + * JS parser.
    1.12 + *
    1.13 + * This is a recursive-descent parser for the JavaScript language specified by
    1.14 + * "The JavaScript 1.5 Language Specification".  It uses lexical and semantic
    1.15 + * feedback to disambiguate non-LL(1) structures.  It generates trees of nodes
    1.16 + * induced by the recursive parsing (not precise syntax trees, see Parser.h).
    1.17 + * After tree construction, it rewrites trees to fold constants and evaluate
    1.18 + * compile-time expressions.
    1.19 + *
    1.20 + * This parser attempts no error recovery.
    1.21 + */
    1.22 +
    1.23 +#include "frontend/Parser-inl.h"
    1.24 +
    1.25 +#include "jsapi.h"
    1.26 +#include "jsatom.h"
    1.27 +#include "jscntxt.h"
    1.28 +#include "jsfun.h"
    1.29 +#include "jsobj.h"
    1.30 +#include "jsopcode.h"
    1.31 +#include "jsscript.h"
    1.32 +#include "jstypes.h"
    1.33 +
    1.34 +#include "frontend/BytecodeCompiler.h"
    1.35 +#include "frontend/FoldConstants.h"
    1.36 +#include "frontend/ParseMaps.h"
    1.37 +#include "frontend/TokenStream.h"
    1.38 +#include "jit/AsmJS.h"
    1.39 +#include "vm/Shape.h"
    1.40 +
    1.41 +#include "jsatominlines.h"
    1.42 +#include "jsscriptinlines.h"
    1.43 +
    1.44 +#include "frontend/ParseNode-inl.h"
    1.45 +
    1.46 +using namespace js;
    1.47 +using namespace js::gc;
    1.48 +using mozilla::Maybe;
    1.49 +
    1.50 +namespace js {
    1.51 +namespace frontend {
    1.52 +
    1.53 +typedef Rooted<StaticBlockObject*> RootedStaticBlockObject;
    1.54 +typedef Handle<StaticBlockObject*> HandleStaticBlockObject;
    1.55 +typedef Rooted<NestedScopeObject*> RootedNestedScopeObject;
    1.56 +typedef Handle<NestedScopeObject*> HandleNestedScopeObject;
    1.57 +
    1.58 +
    1.59 +/*
    1.60 + * Insist that the next token be of type tt, or report errno and return null.
    1.61 + * NB: this macro uses cx and ts from its lexical environment.
    1.62 + */
    1.63 +#define MUST_MATCH_TOKEN(tt, errno)                                                         \
    1.64 +    JS_BEGIN_MACRO                                                                          \
    1.65 +        if (tokenStream.getToken() != tt) {                                                 \
    1.66 +            report(ParseError, false, null(), errno);                                       \
    1.67 +            return null();                                                                  \
    1.68 +        }                                                                                   \
    1.69 +    JS_END_MACRO
    1.70 +
    1.71 +static const unsigned BlockIdLimit = 1 << ParseNode::NumBlockIdBits;
    1.72 +
    1.73 +template <typename ParseHandler>
    1.74 +bool
    1.75 +GenerateBlockId(TokenStream &ts, ParseContext<ParseHandler> *pc, uint32_t &blockid)
    1.76 +{
    1.77 +    if (pc->blockidGen == BlockIdLimit) {
    1.78 +        ts.reportError(JSMSG_NEED_DIET, "program");
    1.79 +        return false;
    1.80 +    }
    1.81 +    JS_ASSERT(pc->blockidGen < BlockIdLimit);
    1.82 +    blockid = pc->blockidGen++;
    1.83 +    return true;
    1.84 +}
    1.85 +
    1.86 +template bool
    1.87 +GenerateBlockId(TokenStream &ts, ParseContext<SyntaxParseHandler> *pc, uint32_t &blockid);
    1.88 +
    1.89 +template bool
    1.90 +GenerateBlockId(TokenStream &ts, ParseContext<FullParseHandler> *pc, uint32_t &blockid);
    1.91 +
    1.92 +template <typename ParseHandler>
    1.93 +static void
    1.94 +PushStatementPC(ParseContext<ParseHandler> *pc, StmtInfoPC *stmt, StmtType type)
    1.95 +{
    1.96 +    stmt->blockid = pc->blockid();
    1.97 +    PushStatement(pc, stmt, type);
    1.98 +}
    1.99 +
   1.100 +// See comment on member function declaration.
   1.101 +template <>
   1.102 +bool
   1.103 +ParseContext<FullParseHandler>::define(TokenStream &ts,
   1.104 +                                       HandlePropertyName name, ParseNode *pn, Definition::Kind kind)
   1.105 +{
   1.106 +    JS_ASSERT(!pn->isUsed());
   1.107 +    JS_ASSERT_IF(pn->isDefn(), pn->isPlaceholder());
   1.108 +
   1.109 +    Definition *prevDef = nullptr;
   1.110 +    if (kind == Definition::LET)
   1.111 +        prevDef = decls_.lookupFirst(name);
   1.112 +    else
   1.113 +        JS_ASSERT(!decls_.lookupFirst(name));
   1.114 +
   1.115 +    if (!prevDef)
   1.116 +        prevDef = lexdeps.lookupDefn<FullParseHandler>(name);
   1.117 +
   1.118 +    if (prevDef) {
   1.119 +        ParseNode **pnup = &prevDef->dn_uses;
   1.120 +        ParseNode *pnu;
   1.121 +        unsigned start = (kind == Definition::LET) ? pn->pn_blockid : bodyid;
   1.122 +
   1.123 +        while ((pnu = *pnup) != nullptr && pnu->pn_blockid >= start) {
   1.124 +            JS_ASSERT(pnu->pn_blockid >= bodyid);
   1.125 +            JS_ASSERT(pnu->isUsed());
   1.126 +            pnu->pn_lexdef = (Definition *) pn;
   1.127 +            pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
   1.128 +            pnup = &pnu->pn_link;
   1.129 +        }
   1.130 +
   1.131 +        if (!pnu || pnu != prevDef->dn_uses) {
   1.132 +            *pnup = pn->dn_uses;
   1.133 +            pn->dn_uses = prevDef->dn_uses;
   1.134 +            prevDef->dn_uses = pnu;
   1.135 +
   1.136 +            if (!pnu && prevDef->isPlaceholder())
   1.137 +                lexdeps->remove(name);
   1.138 +        }
   1.139 +
   1.140 +        pn->pn_dflags |= prevDef->pn_dflags & PND_CLOSED;
   1.141 +    }
   1.142 +
   1.143 +    JS_ASSERT_IF(kind != Definition::LET, !lexdeps->lookup(name));
   1.144 +    pn->setDefn(true);
   1.145 +    pn->pn_dflags &= ~PND_PLACEHOLDER;
   1.146 +    if (kind == Definition::CONST)
   1.147 +        pn->pn_dflags |= PND_CONST;
   1.148 +
   1.149 +    Definition *dn = (Definition *)pn;
   1.150 +    switch (kind) {
   1.151 +      case Definition::ARG:
   1.152 +        JS_ASSERT(sc->isFunctionBox());
   1.153 +        dn->setOp(JSOP_GETARG);
   1.154 +        dn->pn_dflags |= PND_BOUND;
   1.155 +        if (!dn->pn_cookie.set(ts, staticLevel, args_.length()))
   1.156 +            return false;
   1.157 +        if (!args_.append(dn))
   1.158 +            return false;
   1.159 +        if (args_.length() >= ARGNO_LIMIT) {
   1.160 +            ts.reportError(JSMSG_TOO_MANY_FUN_ARGS);
   1.161 +            return false;
   1.162 +        }
   1.163 +        if (name == ts.names().empty)
   1.164 +            break;
   1.165 +        if (!decls_.addUnique(name, dn))
   1.166 +            return false;
   1.167 +        break;
   1.168 +
   1.169 +      case Definition::CONST:
   1.170 +      case Definition::VAR:
   1.171 +        if (sc->isFunctionBox()) {
   1.172 +            dn->setOp(JSOP_GETLOCAL);
   1.173 +            dn->pn_dflags |= PND_BOUND;
   1.174 +            if (!dn->pn_cookie.set(ts, staticLevel, vars_.length()))
   1.175 +                return false;
   1.176 +            if (!vars_.append(dn))
   1.177 +                return false;
   1.178 +            if (vars_.length() >= LOCALNO_LIMIT) {
   1.179 +                ts.reportError(JSMSG_TOO_MANY_LOCALS);
   1.180 +                return false;
   1.181 +            }
   1.182 +        }
   1.183 +        if (!decls_.addUnique(name, dn))
   1.184 +            return false;
   1.185 +        break;
   1.186 +
   1.187 +      case Definition::LET:
   1.188 +        dn->setOp(JSOP_GETLOCAL);
   1.189 +        dn->pn_dflags |= (PND_LET | PND_BOUND);
   1.190 +        JS_ASSERT(dn->pn_cookie.level() == staticLevel); /* see bindLet */
   1.191 +        if (!decls_.addShadow(name, dn))
   1.192 +            return false;
   1.193 +        break;
   1.194 +
   1.195 +      default:
   1.196 +        MOZ_ASSUME_UNREACHABLE("unexpected kind");
   1.197 +    }
   1.198 +
   1.199 +    return true;
   1.200 +}
   1.201 +
   1.202 +template <>
   1.203 +bool
   1.204 +ParseContext<SyntaxParseHandler>::define(TokenStream &ts, HandlePropertyName name, Node pn,
   1.205 +                                         Definition::Kind kind)
   1.206 +{
   1.207 +    JS_ASSERT(!decls_.lookupFirst(name));
   1.208 +
   1.209 +    if (lexdeps.lookupDefn<SyntaxParseHandler>(name))
   1.210 +        lexdeps->remove(name);
   1.211 +
   1.212 +    // Keep track of the number of arguments in args_, for fun->nargs.
   1.213 +    if (kind == Definition::ARG) {
   1.214 +        if (!args_.append((Definition *) nullptr))
   1.215 +            return false;
   1.216 +        if (args_.length() >= ARGNO_LIMIT) {
   1.217 +            ts.reportError(JSMSG_TOO_MANY_FUN_ARGS);
   1.218 +            return false;
   1.219 +        }
   1.220 +    }
   1.221 +
   1.222 +    return decls_.addUnique(name, kind);
   1.223 +}
   1.224 +
   1.225 +template <typename ParseHandler>
   1.226 +void
   1.227 +ParseContext<ParseHandler>::prepareToAddDuplicateArg(HandlePropertyName name, DefinitionNode prevDecl)
   1.228 +{
   1.229 +    JS_ASSERT(decls_.lookupFirst(name) == prevDecl);
   1.230 +    decls_.remove(name);
   1.231 +}
   1.232 +
   1.233 +template <typename ParseHandler>
   1.234 +void
   1.235 +ParseContext<ParseHandler>::updateDecl(JSAtom *atom, Node pn)
   1.236 +{
   1.237 +    Definition *oldDecl = decls_.lookupFirst(atom);
   1.238 +
   1.239 +    pn->setDefn(true);
   1.240 +    Definition *newDecl = (Definition *)pn;
   1.241 +    decls_.updateFirst(atom, newDecl);
   1.242 +
   1.243 +    if (!sc->isFunctionBox()) {
   1.244 +        JS_ASSERT(newDecl->isFreeVar());
   1.245 +        return;
   1.246 +    }
   1.247 +
   1.248 +    JS_ASSERT(oldDecl->isBound());
   1.249 +    JS_ASSERT(!oldDecl->pn_cookie.isFree());
   1.250 +    newDecl->pn_cookie = oldDecl->pn_cookie;
   1.251 +    newDecl->pn_dflags |= PND_BOUND;
   1.252 +    if (IsArgOp(oldDecl->getOp())) {
   1.253 +        newDecl->setOp(JSOP_GETARG);
   1.254 +        JS_ASSERT(args_[oldDecl->pn_cookie.slot()] == oldDecl);
   1.255 +        args_[oldDecl->pn_cookie.slot()] = newDecl;
   1.256 +    } else {
   1.257 +        JS_ASSERT(IsLocalOp(oldDecl->getOp()));
   1.258 +        newDecl->setOp(JSOP_GETLOCAL);
   1.259 +        JS_ASSERT(vars_[oldDecl->pn_cookie.slot()] == oldDecl);
   1.260 +        vars_[oldDecl->pn_cookie.slot()] = newDecl;
   1.261 +    }
   1.262 +}
   1.263 +
   1.264 +template <typename ParseHandler>
   1.265 +void
   1.266 +ParseContext<ParseHandler>::popLetDecl(JSAtom *atom)
   1.267 +{
   1.268 +    JS_ASSERT(ParseHandler::getDefinitionKind(decls_.lookupFirst(atom)) == Definition::LET);
   1.269 +    decls_.remove(atom);
   1.270 +}
   1.271 +
   1.272 +template <typename ParseHandler>
   1.273 +static void
   1.274 +AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec, Binding *dst)
   1.275 +{
   1.276 +    for (size_t i = 0; i < vec.length(); ++i, ++dst) {
   1.277 +        Definition *dn = vec[i];
   1.278 +        PropertyName *name = dn->name();
   1.279 +
   1.280 +        Binding::Kind kind;
   1.281 +        switch (dn->kind()) {
   1.282 +          case Definition::VAR:
   1.283 +            kind = Binding::VARIABLE;
   1.284 +            break;
   1.285 +          case Definition::CONST:
   1.286 +            kind = Binding::CONSTANT;
   1.287 +            break;
   1.288 +          case Definition::ARG:
   1.289 +            kind = Binding::ARGUMENT;
   1.290 +            break;
   1.291 +          default:
   1.292 +            MOZ_ASSUME_UNREACHABLE("unexpected dn->kind");
   1.293 +        }
   1.294 +
   1.295 +        /*
   1.296 +         * Bindings::init does not check for duplicates so we must ensure that
   1.297 +         * only one binding with a given name is marked aliased. pc->decls
   1.298 +         * maintains the canonical definition for each name, so use that.
   1.299 +         */
   1.300 +        JS_ASSERT_IF(dn->isClosed(), pc->decls().lookupFirst(name) == dn);
   1.301 +        bool aliased = dn->isClosed() ||
   1.302 +                       (pc->sc->allLocalsAliased() &&
   1.303 +                        pc->decls().lookupFirst(name) == dn);
   1.304 +
   1.305 +        *dst = Binding(name, kind, aliased);
   1.306 +    }
   1.307 +}
   1.308 +
   1.309 +template <typename ParseHandler>
   1.310 +bool
   1.311 +ParseContext<ParseHandler>::generateFunctionBindings(ExclusiveContext *cx, TokenStream &ts,
   1.312 +                                                     LifoAlloc &alloc,
   1.313 +                                                     InternalHandle<Bindings*> bindings) const
   1.314 +{
   1.315 +    JS_ASSERT(sc->isFunctionBox());
   1.316 +    JS_ASSERT(args_.length() < ARGNO_LIMIT);
   1.317 +    JS_ASSERT(vars_.length() < LOCALNO_LIMIT);
   1.318 +
   1.319 +    /*
   1.320 +     * Avoid pathological edge cases by explicitly limiting the total number of
   1.321 +     * bindings to what will fit in a uint32_t.
   1.322 +     */
   1.323 +    if (UINT32_MAX - args_.length() <= vars_.length())
   1.324 +        return ts.reportError(JSMSG_TOO_MANY_LOCALS);
   1.325 +
   1.326 +    uint32_t count = args_.length() + vars_.length();
   1.327 +    Binding *packedBindings = alloc.newArrayUninitialized<Binding>(count);
   1.328 +    if (!packedBindings) {
   1.329 +        js_ReportOutOfMemory(cx);
   1.330 +        return false;
   1.331 +    }
   1.332 +
   1.333 +    AppendPackedBindings(this, args_, packedBindings);
   1.334 +    AppendPackedBindings(this, vars_, packedBindings + args_.length());
   1.335 +
   1.336 +    return Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(),
   1.337 +                                              packedBindings, blockScopeDepth);
   1.338 +}
   1.339 +
   1.340 +template <typename ParseHandler>
   1.341 +bool
   1.342 +Parser<ParseHandler>::reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
   1.343 +                                   unsigned errorNumber, va_list args)
   1.344 +{
   1.345 +    bool result = false;
   1.346 +    switch (kind) {
   1.347 +      case ParseError:
   1.348 +        result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args);
   1.349 +        break;
   1.350 +      case ParseWarning:
   1.351 +        result =
   1.352 +            tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args);
   1.353 +        break;
   1.354 +      case ParseExtraWarning:
   1.355 +        result = tokenStream.reportStrictWarningErrorNumberVA(offset, errorNumber, args);
   1.356 +        break;
   1.357 +      case ParseStrictError:
   1.358 +        result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args);
   1.359 +        break;
   1.360 +    }
   1.361 +    return result;
   1.362 +}
   1.363 +
   1.364 +template <typename ParseHandler>
   1.365 +bool
   1.366 +Parser<ParseHandler>::report(ParseReportKind kind, bool strict, Node pn, unsigned errorNumber, ...)
   1.367 +{
   1.368 +    uint32_t offset = (pn ? handler.getPosition(pn) : pos()).begin;
   1.369 +
   1.370 +    va_list args;
   1.371 +    va_start(args, errorNumber);
   1.372 +    bool result = reportHelper(kind, strict, offset, errorNumber, args);
   1.373 +    va_end(args);
   1.374 +    return result;
   1.375 +}
   1.376 +
   1.377 +template <typename ParseHandler>
   1.378 +bool
   1.379 +Parser<ParseHandler>::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...)
   1.380 +{
   1.381 +    va_list args;
   1.382 +    va_start(args, errorNumber);
   1.383 +    bool result = reportHelper(kind, strict, TokenStream::NoOffset, errorNumber, args);
   1.384 +    va_end(args);
   1.385 +    return result;
   1.386 +}
   1.387 +
   1.388 +template <typename ParseHandler>
   1.389 +bool
   1.390 +Parser<ParseHandler>::reportWithOffset(ParseReportKind kind, bool strict, uint32_t offset,
   1.391 +                                       unsigned errorNumber, ...)
   1.392 +{
   1.393 +    va_list args;
   1.394 +    va_start(args, errorNumber);
   1.395 +    bool result = reportHelper(kind, strict, offset, errorNumber, args);
   1.396 +    va_end(args);
   1.397 +    return result;
   1.398 +}
   1.399 +
   1.400 +template <>
   1.401 +bool
   1.402 +Parser<FullParseHandler>::abortIfSyntaxParser()
   1.403 +{
   1.404 +    handler.disableSyntaxParser();
   1.405 +    return true;
   1.406 +}
   1.407 +
   1.408 +template <>
   1.409 +bool
   1.410 +Parser<SyntaxParseHandler>::abortIfSyntaxParser()
   1.411 +{
   1.412 +    abortedSyntaxParse = true;
   1.413 +    return false;
   1.414 +}
   1.415 +
   1.416 +template <typename ParseHandler>
   1.417 +Parser<ParseHandler>::Parser(ExclusiveContext *cx, LifoAlloc *alloc,
   1.418 +                             const ReadOnlyCompileOptions &options,
   1.419 +                             const jschar *chars, size_t length, bool foldConstants,
   1.420 +                             Parser<SyntaxParseHandler> *syntaxParser,
   1.421 +                             LazyScript *lazyOuterFunction)
   1.422 +  : AutoGCRooter(cx, PARSER),
   1.423 +    context(cx),
   1.424 +    alloc(*alloc),
   1.425 +    tokenStream(cx, options, chars, length, thisForCtor()),
   1.426 +    traceListHead(nullptr),
   1.427 +    pc(nullptr),
   1.428 +    sct(nullptr),
   1.429 +    ss(nullptr),
   1.430 +    keepAtoms(cx->perThreadData),
   1.431 +    foldConstants(foldConstants),
   1.432 +    abortedSyntaxParse(false),
   1.433 +    isUnexpectedEOF_(false),
   1.434 +    handler(cx, *alloc, tokenStream, foldConstants, syntaxParser, lazyOuterFunction)
   1.435 +{
   1.436 +    {
   1.437 +        AutoLockForExclusiveAccess lock(cx);
   1.438 +        cx->perThreadData->addActiveCompilation();
   1.439 +    }
   1.440 +
   1.441 +    // The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings
   1.442 +    // which are not generated if functions are parsed lazily. Note that the
   1.443 +    // standard "use strict" does not inhibit lazy parsing.
   1.444 +    if (options.extraWarningsOption)
   1.445 +        handler.disableSyntaxParser();
   1.446 +
   1.447 +    tempPoolMark = alloc->mark();
   1.448 +}
   1.449 +
   1.450 +template <typename ParseHandler>
   1.451 +Parser<ParseHandler>::~Parser()
   1.452 +{
   1.453 +    alloc.release(tempPoolMark);
   1.454 +
   1.455 +    /*
   1.456 +     * The parser can allocate enormous amounts of memory for large functions.
   1.457 +     * Eagerly free the memory now (which otherwise won't be freed until the
   1.458 +     * next GC) to avoid unnecessary OOMs.
   1.459 +     */
   1.460 +    alloc.freeAllIfHugeAndUnused();
   1.461 +
   1.462 +    {
   1.463 +        AutoLockForExclusiveAccess lock(context);
   1.464 +        context->perThreadData->removeActiveCompilation();
   1.465 +    }
   1.466 +}
   1.467 +
   1.468 +template <typename ParseHandler>
   1.469 +ObjectBox *
   1.470 +Parser<ParseHandler>::newObjectBox(JSObject *obj)
   1.471 +{
   1.472 +    JS_ASSERT(obj && !IsPoisonedPtr(obj));
   1.473 +
   1.474 +    /*
   1.475 +     * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
   1.476 +     * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
   1.477 +     * arenas containing the entries must be alive until we are done with
   1.478 +     * scanning, parsing and code generation for the whole script or top-level
   1.479 +     * function.
   1.480 +     */
   1.481 +
   1.482 +    ObjectBox *objbox = alloc.new_<ObjectBox>(obj, traceListHead);
   1.483 +    if (!objbox) {
   1.484 +        js_ReportOutOfMemory(context);
   1.485 +        return nullptr;
   1.486 +    }
   1.487 +
   1.488 +    traceListHead = objbox;
   1.489 +
   1.490 +    return objbox;
   1.491 +}
   1.492 +
   1.493 +template <typename ParseHandler>
   1.494 +FunctionBox::FunctionBox(ExclusiveContext *cx, ObjectBox* traceListHead, JSFunction *fun,
   1.495 +                         ParseContext<ParseHandler> *outerpc, Directives directives,
   1.496 +                         bool extraWarnings, GeneratorKind generatorKind)
   1.497 +  : ObjectBox(fun, traceListHead),
   1.498 +    SharedContext(cx, directives, extraWarnings),
   1.499 +    bindings(),
   1.500 +    bufStart(0),
   1.501 +    bufEnd(0),
   1.502 +    length(0),
   1.503 +    generatorKindBits_(GeneratorKindAsBits(generatorKind)),
   1.504 +    inWith(false),                  // initialized below
   1.505 +    inGenexpLambda(false),
   1.506 +    hasDestructuringArgs(false),
   1.507 +    useAsm(directives.asmJS()),
   1.508 +    insideUseAsm(outerpc && outerpc->useAsmOrInsideUseAsm()),
   1.509 +    usesArguments(false),
   1.510 +    usesApply(false),
   1.511 +    funCxFlags()
   1.512 +{
   1.513 +    // Functions created at parse time may be set singleton after parsing and
   1.514 +    // baked into JIT code, so they must be allocated tenured. They are held by
   1.515 +    // the JSScript so cannot be collected during a minor GC anyway.
   1.516 +    JS_ASSERT(fun->isTenured());
   1.517 +
   1.518 +    if (!outerpc) {
   1.519 +        inWith = false;
   1.520 +
   1.521 +    } else if (outerpc->parsingWith) {
   1.522 +        // This covers cases that don't involve eval().  For example:
   1.523 +        //
   1.524 +        //   with (o) { (function() { g(); })(); }
   1.525 +        //
   1.526 +        // In this case, |outerpc| corresponds to global code, and
   1.527 +        // outerpc->parsingWith is true.
   1.528 +        inWith = true;
   1.529 +
   1.530 +    } else if (outerpc->sc->isGlobalSharedContext()) {
   1.531 +        // This covers the case where a function is nested within an eval()
   1.532 +        // within a |with| statement.
   1.533 +        //
   1.534 +        //   with (o) { eval("(function() { g(); })();"); }
   1.535 +        //
   1.536 +        // In this case, |outerpc| corresponds to the eval(),
   1.537 +        // outerpc->parsingWith is false because the eval() breaks the
   1.538 +        // ParseContext chain, and |parent| is nullptr (again because of the
   1.539 +        // eval(), so we have to look at |outerpc|'s scopeChain.
   1.540 +        //
   1.541 +        JSObject *scope = outerpc->sc->asGlobalSharedContext()->scopeChain();
   1.542 +        while (scope) {
   1.543 +            if (scope->is<DynamicWithObject>())
   1.544 +                inWith = true;
   1.545 +            scope = scope->enclosingScope();
   1.546 +        }
   1.547 +    } else if (outerpc->sc->isFunctionBox()) {
   1.548 +        // This is like the above case, but for more deeply nested functions.
   1.549 +        // For example:
   1.550 +        //
   1.551 +        //   with (o) { eval("(function() { (function() { g(); })(); })();"); } }
   1.552 +        //
   1.553 +        // In this case, the inner anonymous function needs to inherit the
   1.554 +        // setting of |inWith| from the outer one.
   1.555 +        FunctionBox *parent = outerpc->sc->asFunctionBox();
   1.556 +        if (parent && parent->inWith)
   1.557 +            inWith = true;
   1.558 +    }
   1.559 +}
   1.560 +
   1.561 +template <typename ParseHandler>
   1.562 +FunctionBox *
   1.563 +Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction *fun, ParseContext<ParseHandler> *outerpc,
   1.564 +                                     Directives inheritedDirectives, GeneratorKind generatorKind)
   1.565 +{
   1.566 +    JS_ASSERT(fun && !IsPoisonedPtr(fun));
   1.567 +
   1.568 +    /*
   1.569 +     * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
   1.570 +     * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
   1.571 +     * arenas containing the entries must be alive until we are done with
   1.572 +     * scanning, parsing and code generation for the whole script or top-level
   1.573 +     * function.
   1.574 +     */
   1.575 +    FunctionBox *funbox =
   1.576 +        alloc.new_<FunctionBox>(context, traceListHead, fun, outerpc,
   1.577 +                                inheritedDirectives, options().extraWarningsOption,
   1.578 +                                generatorKind);
   1.579 +    if (!funbox) {
   1.580 +        js_ReportOutOfMemory(context);
   1.581 +        return nullptr;
   1.582 +    }
   1.583 +
   1.584 +    traceListHead = funbox;
   1.585 +    if (fn)
   1.586 +        handler.setFunctionBox(fn, funbox);
   1.587 +
   1.588 +    return funbox;
   1.589 +}
   1.590 +
   1.591 +template <typename ParseHandler>
   1.592 +void
   1.593 +Parser<ParseHandler>::trace(JSTracer *trc)
   1.594 +{
   1.595 +    traceListHead->trace(trc);
   1.596 +}
   1.597 +
   1.598 +void
   1.599 +MarkParser(JSTracer *trc, AutoGCRooter *parser)
   1.600 +{
   1.601 +    static_cast<Parser<FullParseHandler> *>(parser)->trace(trc);
   1.602 +}
   1.603 +
   1.604 +/*
   1.605 + * Parse a top-level JS script.
   1.606 + */
   1.607 +template <typename ParseHandler>
   1.608 +typename ParseHandler::Node
   1.609 +Parser<ParseHandler>::parse(JSObject *chain)
   1.610 +{
   1.611 +    /*
   1.612 +     * Protect atoms from being collected by a GC activation, which might
   1.613 +     * - nest on this thread due to out of memory (the so-called "last ditch"
   1.614 +     *   GC attempted within js_NewGCThing), or
   1.615 +     * - run for any reason on another thread if this thread is suspended on
   1.616 +     *   an object lock before it finishes generating bytecode into a script
   1.617 +     *   protected from the GC by a root or a stack frame reference.
   1.618 +     */
   1.619 +    Directives directives(options().strictOption);
   1.620 +    GlobalSharedContext globalsc(context, chain, directives, options().extraWarningsOption);
   1.621 +    ParseContext<ParseHandler> globalpc(this, /* parent = */ nullptr, ParseHandler::null(),
   1.622 +                                        &globalsc, /* newDirectives = */ nullptr,
   1.623 +                                        /* staticLevel = */ 0, /* bodyid = */ 0,
   1.624 +                                        /* blockScopeDepth = */ 0);
   1.625 +    if (!globalpc.init(tokenStream))
   1.626 +        return null();
   1.627 +
   1.628 +    Node pn = statements();
   1.629 +    if (pn) {
   1.630 +        if (!tokenStream.matchToken(TOK_EOF)) {
   1.631 +            report(ParseError, false, null(), JSMSG_SYNTAX_ERROR);
   1.632 +            return null();
   1.633 +        }
   1.634 +        if (foldConstants) {
   1.635 +            if (!FoldConstants(context, &pn, this))
   1.636 +                return null();
   1.637 +        }
   1.638 +    }
   1.639 +    return pn;
   1.640 +}
   1.641 +
   1.642 +/*
   1.643 + * Insist on a final return before control flows out of pn.  Try to be a bit
   1.644 + * smart about loops: do {...; return e2;} while(0) at the end of a function
   1.645 + * that contains an early return e1 will get a strict warning.  Similarly for
   1.646 + * iloops: while (true){...} is treated as though ... returns.
   1.647 + */
   1.648 +enum {
   1.649 +    ENDS_IN_OTHER = 0,
   1.650 +    ENDS_IN_RETURN = 1,
   1.651 +    ENDS_IN_BREAK = 2
   1.652 +};
   1.653 +
   1.654 +static int
   1.655 +HasFinalReturn(ParseNode *pn)
   1.656 +{
   1.657 +    ParseNode *pn2, *pn3;
   1.658 +    unsigned rv, rv2, hasDefault;
   1.659 +
   1.660 +    switch (pn->getKind()) {
   1.661 +      case PNK_STATEMENTLIST:
   1.662 +        if (!pn->pn_head)
   1.663 +            return ENDS_IN_OTHER;
   1.664 +        return HasFinalReturn(pn->last());
   1.665 +
   1.666 +      case PNK_IF:
   1.667 +        if (!pn->pn_kid3)
   1.668 +            return ENDS_IN_OTHER;
   1.669 +        return HasFinalReturn(pn->pn_kid2) & HasFinalReturn(pn->pn_kid3);
   1.670 +
   1.671 +      case PNK_WHILE:
   1.672 +        pn2 = pn->pn_left;
   1.673 +        if (pn2->isKind(PNK_TRUE))
   1.674 +            return ENDS_IN_RETURN;
   1.675 +        if (pn2->isKind(PNK_NUMBER) && pn2->pn_dval)
   1.676 +            return ENDS_IN_RETURN;
   1.677 +        return ENDS_IN_OTHER;
   1.678 +
   1.679 +      case PNK_DOWHILE:
   1.680 +        pn2 = pn->pn_right;
   1.681 +        if (pn2->isKind(PNK_FALSE))
   1.682 +            return HasFinalReturn(pn->pn_left);
   1.683 +        if (pn2->isKind(PNK_TRUE))
   1.684 +            return ENDS_IN_RETURN;
   1.685 +        if (pn2->isKind(PNK_NUMBER)) {
   1.686 +            if (pn2->pn_dval == 0)
   1.687 +                return HasFinalReturn(pn->pn_left);
   1.688 +            return ENDS_IN_RETURN;
   1.689 +        }
   1.690 +        return ENDS_IN_OTHER;
   1.691 +
   1.692 +      case PNK_FOR:
   1.693 +        pn2 = pn->pn_left;
   1.694 +        if (pn2->isArity(PN_TERNARY) && !pn2->pn_kid2)
   1.695 +            return ENDS_IN_RETURN;
   1.696 +        return ENDS_IN_OTHER;
   1.697 +
   1.698 +      case PNK_SWITCH:
   1.699 +        rv = ENDS_IN_RETURN;
   1.700 +        hasDefault = ENDS_IN_OTHER;
   1.701 +        pn2 = pn->pn_right;
   1.702 +        if (pn2->isKind(PNK_LEXICALSCOPE))
   1.703 +            pn2 = pn2->expr();
   1.704 +        for (pn2 = pn2->pn_head; rv && pn2; pn2 = pn2->pn_next) {
   1.705 +            if (pn2->isKind(PNK_DEFAULT))
   1.706 +                hasDefault = ENDS_IN_RETURN;
   1.707 +            pn3 = pn2->pn_right;
   1.708 +            JS_ASSERT(pn3->isKind(PNK_STATEMENTLIST));
   1.709 +            if (pn3->pn_head) {
   1.710 +                rv2 = HasFinalReturn(pn3->last());
   1.711 +                if (rv2 == ENDS_IN_OTHER && pn2->pn_next)
   1.712 +                    /* Falling through to next case or default. */;
   1.713 +                else
   1.714 +                    rv &= rv2;
   1.715 +            }
   1.716 +        }
   1.717 +        /* If a final switch has no default case, we judge it harshly. */
   1.718 +        rv &= hasDefault;
   1.719 +        return rv;
   1.720 +
   1.721 +      case PNK_BREAK:
   1.722 +        return ENDS_IN_BREAK;
   1.723 +
   1.724 +      case PNK_WITH:
   1.725 +        return HasFinalReturn(pn->pn_right);
   1.726 +
   1.727 +      case PNK_RETURN:
   1.728 +        return ENDS_IN_RETURN;
   1.729 +
   1.730 +      case PNK_COLON:
   1.731 +      case PNK_LEXICALSCOPE:
   1.732 +        return HasFinalReturn(pn->expr());
   1.733 +
   1.734 +      case PNK_THROW:
   1.735 +        return ENDS_IN_RETURN;
   1.736 +
   1.737 +      case PNK_TRY:
   1.738 +        /* If we have a finally block that returns, we are done. */
   1.739 +        if (pn->pn_kid3) {
   1.740 +            rv = HasFinalReturn(pn->pn_kid3);
   1.741 +            if (rv == ENDS_IN_RETURN)
   1.742 +                return rv;
   1.743 +        }
   1.744 +
   1.745 +        /* Else check the try block and any and all catch statements. */
   1.746 +        rv = HasFinalReturn(pn->pn_kid1);
   1.747 +        if (pn->pn_kid2) {
   1.748 +            JS_ASSERT(pn->pn_kid2->isArity(PN_LIST));
   1.749 +            for (pn2 = pn->pn_kid2->pn_head; pn2; pn2 = pn2->pn_next)
   1.750 +                rv &= HasFinalReturn(pn2);
   1.751 +        }
   1.752 +        return rv;
   1.753 +
   1.754 +      case PNK_CATCH:
   1.755 +        /* Check this catch block's body. */
   1.756 +        return HasFinalReturn(pn->pn_kid3);
   1.757 +
   1.758 +      case PNK_LET:
   1.759 +        /* Non-binary let statements are let declarations. */
   1.760 +        if (!pn->isArity(PN_BINARY))
   1.761 +            return ENDS_IN_OTHER;
   1.762 +        return HasFinalReturn(pn->pn_right);
   1.763 +
   1.764 +      default:
   1.765 +        return ENDS_IN_OTHER;
   1.766 +    }
   1.767 +}
   1.768 +
   1.769 +static int
   1.770 +HasFinalReturn(SyntaxParseHandler::Node pn)
   1.771 +{
   1.772 +    return ENDS_IN_RETURN;
   1.773 +}
   1.774 +
   1.775 +template <typename ParseHandler>
   1.776 +bool
   1.777 +Parser<ParseHandler>::reportBadReturn(Node pn, ParseReportKind kind,
   1.778 +                                      unsigned errnum, unsigned anonerrnum)
   1.779 +{
   1.780 +    JSAutoByteString name;
   1.781 +    JSAtom *atom = pc->sc->asFunctionBox()->function()->atom();
   1.782 +    if (atom) {
   1.783 +        if (!AtomToPrintableString(context, atom, &name))
   1.784 +            return false;
   1.785 +    } else {
   1.786 +        errnum = anonerrnum;
   1.787 +    }
   1.788 +    return report(kind, pc->sc->strict, pn, errnum, name.ptr());
   1.789 +}
   1.790 +
   1.791 +template <typename ParseHandler>
   1.792 +bool
   1.793 +Parser<ParseHandler>::checkFinalReturn(Node pn)
   1.794 +{
   1.795 +    JS_ASSERT(pc->sc->isFunctionBox());
   1.796 +    return HasFinalReturn(pn) == ENDS_IN_RETURN ||
   1.797 +           reportBadReturn(pn, ParseExtraWarning,
   1.798 +                           JSMSG_NO_RETURN_VALUE, JSMSG_ANON_NO_RETURN_VALUE);
   1.799 +}
   1.800 +
   1.801 +/*
   1.802 + * Check that assigning to lhs is permitted.  Assigning to 'eval' or
   1.803 + * 'arguments' is banned in strict mode and in destructuring assignment.
   1.804 + */
   1.805 +template <typename ParseHandler>
   1.806 +bool
   1.807 +Parser<ParseHandler>::checkStrictAssignment(Node lhs, AssignmentFlavor flavor)
   1.808 +{
   1.809 +    if (!pc->sc->needStrictChecks() && flavor != KeyedDestructuringAssignment)
   1.810 +        return true;
   1.811 +
   1.812 +    JSAtom *atom = handler.isName(lhs);
   1.813 +    if (!atom)
   1.814 +        return true;
   1.815 +
   1.816 +    if (atom == context->names().eval || atom == context->names().arguments) {
   1.817 +        JSAutoByteString name;
   1.818 +        if (!AtomToPrintableString(context, atom, &name))
   1.819 +            return false;
   1.820 +
   1.821 +        ParseReportKind kind;
   1.822 +        unsigned errnum;
   1.823 +        if (pc->sc->strict || flavor != KeyedDestructuringAssignment) {
   1.824 +            kind = ParseStrictError;
   1.825 +            errnum = JSMSG_BAD_STRICT_ASSIGN;
   1.826 +        } else {
   1.827 +            kind = ParseError;
   1.828 +            errnum = JSMSG_BAD_DESTRUCT_ASSIGN;
   1.829 +        }
   1.830 +        if (!report(kind, pc->sc->strict, lhs, errnum, name.ptr()))
   1.831 +            return false;
   1.832 +    }
   1.833 +    return true;
   1.834 +}
   1.835 +
   1.836 +/*
   1.837 + * Check that it is permitted to introduce a binding for atom.  Strict mode
   1.838 + * forbids introducing new definitions for 'eval', 'arguments', or for any
   1.839 + * strict mode reserved keyword.  Use pn for reporting error locations, or use
   1.840 + * pc's token stream if pn is nullptr.
   1.841 + */
   1.842 +template <typename ParseHandler>
   1.843 +bool
   1.844 +Parser<ParseHandler>::checkStrictBinding(PropertyName *name, Node pn)
   1.845 +{
   1.846 +    if (!pc->sc->needStrictChecks())
   1.847 +        return true;
   1.848 +
   1.849 +    if (name == context->names().eval || name == context->names().arguments || IsKeyword(name)) {
   1.850 +        JSAutoByteString bytes;
   1.851 +        if (!AtomToPrintableString(context, name, &bytes))
   1.852 +            return false;
   1.853 +        return report(ParseStrictError, pc->sc->strict, pn,
   1.854 +                      JSMSG_BAD_BINDING, bytes.ptr());
   1.855 +    }
   1.856 +
   1.857 +    return true;
   1.858 +}
   1.859 +
   1.860 +template <>
   1.861 +ParseNode *
   1.862 +Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals,
   1.863 +                                                 GeneratorKind generatorKind,
   1.864 +                                                 Directives inheritedDirectives,
   1.865 +                                                 Directives *newDirectives)
   1.866 +{
   1.867 +    Node fn = handler.newFunctionDefinition();
   1.868 +    if (!fn)
   1.869 +        return null();
   1.870 +
   1.871 +    ParseNode *argsbody = ListNode::create(PNK_ARGSBODY, &handler);
   1.872 +    if (!argsbody)
   1.873 +        return null();
   1.874 +    argsbody->setOp(JSOP_NOP);
   1.875 +    argsbody->makeEmpty();
   1.876 +    fn->pn_body = argsbody;
   1.877 +
   1.878 +    FunctionBox *funbox = newFunctionBox(fn, fun, /* outerpc = */ nullptr, inheritedDirectives,
   1.879 +                                         generatorKind);
   1.880 +    if (!funbox)
   1.881 +        return null();
   1.882 +    funbox->length = fun->nargs() - fun->hasRest();
   1.883 +    handler.setFunctionBox(fn, funbox);
   1.884 +
   1.885 +    ParseContext<FullParseHandler> funpc(this, pc, fn, funbox, newDirectives,
   1.886 +                                         /* staticLevel = */ 0, /* bodyid = */ 0,
   1.887 +                                         /* blockScopeDepth = */ 0);
   1.888 +    if (!funpc.init(tokenStream))
   1.889 +        return null();
   1.890 +
   1.891 +    for (unsigned i = 0; i < formals.length(); i++) {
   1.892 +        if (!defineArg(fn, formals[i]))
   1.893 +            return null();
   1.894 +    }
   1.895 +
   1.896 +    ParseNode *pn = functionBody(Statement, StatementListBody);
   1.897 +    if (!pn)
   1.898 +        return null();
   1.899 +
   1.900 +    if (!tokenStream.matchToken(TOK_EOF)) {
   1.901 +        report(ParseError, false, null(), JSMSG_SYNTAX_ERROR);
   1.902 +        return null();
   1.903 +    }
   1.904 +
   1.905 +    if (!FoldConstants(context, &pn, this))
   1.906 +        return null();
   1.907 +
   1.908 +    InternalHandle<Bindings*> funboxBindings =
   1.909 +        InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings);
   1.910 +    if (!funpc.generateFunctionBindings(context, tokenStream, alloc, funboxBindings))
   1.911 +        return null();
   1.912 +
   1.913 +    JS_ASSERT(fn->pn_body->isKind(PNK_ARGSBODY));
   1.914 +    fn->pn_body->append(pn);
   1.915 +    fn->pn_body->pn_pos = pn->pn_pos;
   1.916 +    return fn;
   1.917 +}
   1.918 +
   1.919 +template <>
   1.920 +bool
   1.921 +Parser<FullParseHandler>::checkFunctionArguments()
   1.922 +{
   1.923 +    /*
   1.924 +     * Non-top-level functions use JSOP_DEFFUN which is a dynamic scope
   1.925 +     * operation which means it aliases any bindings with the same name.
   1.926 +     */
   1.927 +    if (FuncStmtSet *set = pc->funcStmts) {
   1.928 +        for (FuncStmtSet::Range r = set->all(); !r.empty(); r.popFront()) {
   1.929 +            PropertyName *name = r.front()->asPropertyName();
   1.930 +            if (Definition *dn = pc->decls().lookupFirst(name))
   1.931 +                dn->pn_dflags |= PND_CLOSED;
   1.932 +        }
   1.933 +    }
   1.934 +
   1.935 +    /* Time to implement the odd semantics of 'arguments'. */
   1.936 +    HandlePropertyName arguments = context->names().arguments;
   1.937 +
   1.938 +    /*
   1.939 +     * As explained by the ContextFlags::funArgumentsHasLocalBinding comment,
   1.940 +     * create a declaration for 'arguments' if there are any unbound uses in
   1.941 +     * the function body.
   1.942 +     */
   1.943 +    for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) {
   1.944 +        if (r.front().key() == arguments) {
   1.945 +            Definition *dn = r.front().value().get<FullParseHandler>();
   1.946 +            pc->lexdeps->remove(arguments);
   1.947 +            dn->pn_dflags |= PND_IMPLICITARGUMENTS;
   1.948 +            if (!pc->define(tokenStream, arguments, dn, Definition::VAR))
   1.949 +                return false;
   1.950 +            pc->sc->asFunctionBox()->usesArguments = true;
   1.951 +            break;
   1.952 +        }
   1.953 +    }
   1.954 +
   1.955 +    /*
   1.956 +     * Report error if both rest parameters and 'arguments' are used. Do this
   1.957 +     * check before adding artificial 'arguments' below.
   1.958 +     */
   1.959 +    Definition *maybeArgDef = pc->decls().lookupFirst(arguments);
   1.960 +    bool argumentsHasBinding = !!maybeArgDef;
   1.961 +    bool argumentsHasLocalBinding = maybeArgDef && maybeArgDef->kind() != Definition::ARG;
   1.962 +    bool hasRest = pc->sc->asFunctionBox()->function()->hasRest();
   1.963 +    if (hasRest && argumentsHasLocalBinding) {
   1.964 +        report(ParseError, false, nullptr, JSMSG_ARGUMENTS_AND_REST);
   1.965 +        return false;
   1.966 +    }
   1.967 +
   1.968 +    /*
   1.969 +     * Even if 'arguments' isn't explicitly mentioned, dynamic name lookup
   1.970 +     * forces an 'arguments' binding. The exception is that functions with rest
   1.971 +     * parameters are free from 'arguments'.
   1.972 +     */
   1.973 +    if (!argumentsHasBinding && pc->sc->bindingsAccessedDynamically() && !hasRest) {
   1.974 +        ParseNode *pn = newName(arguments);
   1.975 +        if (!pn)
   1.976 +            return false;
   1.977 +        if (!pc->define(tokenStream, arguments, pn, Definition::VAR))
   1.978 +            return false;
   1.979 +        argumentsHasBinding = true;
   1.980 +        argumentsHasLocalBinding = true;
   1.981 +    }
   1.982 +
   1.983 +    /*
   1.984 +     * Now that all possible 'arguments' bindings have been added, note whether
   1.985 +     * 'arguments' has a local binding and whether it unconditionally needs an
   1.986 +     * arguments object. (Also see the flags' comments in ContextFlags.)
   1.987 +     */
   1.988 +    if (argumentsHasLocalBinding) {
   1.989 +        FunctionBox *funbox = pc->sc->asFunctionBox();
   1.990 +        funbox->setArgumentsHasLocalBinding();
   1.991 +
   1.992 +        /*
   1.993 +         * If a script has both explicit mentions of 'arguments' and dynamic
   1.994 +         * name lookups which could access the arguments, an arguments object
   1.995 +         * must be created eagerly. The SSA analysis used for lazy arguments
   1.996 +         * cannot cope with dynamic name accesses, so any 'arguments' accessed
   1.997 +         * via a NAME opcode must force construction of the arguments object.
   1.998 +         */
   1.999 +        if (pc->sc->bindingsAccessedDynamically() && maybeArgDef)
  1.1000 +            funbox->setDefinitelyNeedsArgsObj();
  1.1001 +
  1.1002 +        /*
  1.1003 +         * If a script contains the debugger statement either directly or
  1.1004 +         * within an inner function, the arguments object must be created
  1.1005 +         * eagerly. The debugger can walk the scope chain and observe any
  1.1006 +         * values along it.
  1.1007 +         */
  1.1008 +        if (pc->sc->hasDebuggerStatement())
  1.1009 +            funbox->setDefinitelyNeedsArgsObj();
  1.1010 +
  1.1011 +        /*
  1.1012 +         * Check whether any parameters have been assigned within this
  1.1013 +         * function. In strict mode parameters do not alias arguments[i], and
  1.1014 +         * to make the arguments object reflect initial parameter values prior
  1.1015 +         * to any mutation we create it eagerly whenever parameters are (or
  1.1016 +         * might, in the case of calls to eval) be assigned.
  1.1017 +         */
  1.1018 +        if (pc->sc->needStrictChecks()) {
  1.1019 +            for (AtomDefnListMap::Range r = pc->decls().all(); !r.empty(); r.popFront()) {
  1.1020 +                DefinitionList &dlist = r.front().value();
  1.1021 +                for (DefinitionList::Range dr = dlist.all(); !dr.empty(); dr.popFront()) {
  1.1022 +                    Definition *dn = dr.front<FullParseHandler>();
  1.1023 +                    if (dn->kind() == Definition::ARG && dn->isAssigned())
  1.1024 +                        funbox->setDefinitelyNeedsArgsObj();
  1.1025 +                }
  1.1026 +            }
  1.1027 +            /* Watch for mutation of arguments through e.g. eval(). */
  1.1028 +            if (pc->sc->bindingsAccessedDynamically())
  1.1029 +                funbox->setDefinitelyNeedsArgsObj();
  1.1030 +        }
  1.1031 +    }
  1.1032 +
  1.1033 +    return true;
  1.1034 +}
  1.1035 +
  1.1036 +template <>
  1.1037 +bool
  1.1038 +Parser<SyntaxParseHandler>::checkFunctionArguments()
  1.1039 +{
  1.1040 +    bool hasRest = pc->sc->asFunctionBox()->function()->hasRest();
  1.1041 +
  1.1042 +    if (pc->lexdeps->lookup(context->names().arguments)) {
  1.1043 +        pc->sc->asFunctionBox()->usesArguments = true;
  1.1044 +        if (hasRest) {
  1.1045 +            report(ParseError, false, null(), JSMSG_ARGUMENTS_AND_REST);
  1.1046 +            return false;
  1.1047 +        }
  1.1048 +    } else if (hasRest) {
  1.1049 +        DefinitionNode maybeArgDef = pc->decls().lookupFirst(context->names().arguments);
  1.1050 +        if (maybeArgDef && handler.getDefinitionKind(maybeArgDef) != Definition::ARG) {
  1.1051 +            report(ParseError, false, null(), JSMSG_ARGUMENTS_AND_REST);
  1.1052 +            return false;
  1.1053 +        }
  1.1054 +    }
  1.1055 +
  1.1056 +    return true;
  1.1057 +}
  1.1058 +
  1.1059 +template <typename ParseHandler>
  1.1060 +typename ParseHandler::Node
  1.1061 +Parser<ParseHandler>::functionBody(FunctionSyntaxKind kind, FunctionBodyType type)
  1.1062 +{
  1.1063 +    JS_ASSERT(pc->sc->isFunctionBox());
  1.1064 +    JS_ASSERT(!pc->funHasReturnExpr && !pc->funHasReturnVoid);
  1.1065 +
  1.1066 +#ifdef DEBUG
  1.1067 +    uint32_t startYieldOffset = pc->lastYieldOffset;
  1.1068 +#endif
  1.1069 +
  1.1070 +    Node pn;
  1.1071 +    if (type == StatementListBody) {
  1.1072 +        pn = statements();
  1.1073 +        if (!pn)
  1.1074 +            return null();
  1.1075 +    } else {
  1.1076 +        JS_ASSERT(type == ExpressionBody);
  1.1077 +        JS_ASSERT(JS_HAS_EXPR_CLOSURES);
  1.1078 +
  1.1079 +        Node kid = assignExpr();
  1.1080 +        if (!kid)
  1.1081 +            return null();
  1.1082 +
  1.1083 +        pn = handler.newReturnStatement(kid, handler.getPosition(kid));
  1.1084 +        if (!pn)
  1.1085 +            return null();
  1.1086 +    }
  1.1087 +
  1.1088 +    switch (pc->generatorKind()) {
  1.1089 +      case NotGenerator:
  1.1090 +        JS_ASSERT(pc->lastYieldOffset == startYieldOffset);
  1.1091 +        break;
  1.1092 +
  1.1093 +      case LegacyGenerator:
  1.1094 +        // FIXME: Catch these errors eagerly, in yieldExpression().
  1.1095 +        JS_ASSERT(pc->lastYieldOffset != startYieldOffset);
  1.1096 +        if (kind == Arrow) {
  1.1097 +            reportWithOffset(ParseError, false, pc->lastYieldOffset,
  1.1098 +                             JSMSG_YIELD_IN_ARROW, js_yield_str);
  1.1099 +            return null();
  1.1100 +        }
  1.1101 +        if (type == ExpressionBody) {
  1.1102 +            reportBadReturn(pn, ParseError,
  1.1103 +                            JSMSG_BAD_GENERATOR_RETURN,
  1.1104 +                            JSMSG_BAD_ANON_GENERATOR_RETURN);
  1.1105 +            return null();
  1.1106 +        }
  1.1107 +        break;
  1.1108 +
  1.1109 +      case StarGenerator:
  1.1110 +        JS_ASSERT(kind != Arrow);
  1.1111 +        JS_ASSERT(type == StatementListBody);
  1.1112 +        break;
  1.1113 +    }
  1.1114 +
  1.1115 +    /* Check for falling off the end of a function that returns a value. */
  1.1116 +    if (options().extraWarningsOption && pc->funHasReturnExpr && !checkFinalReturn(pn))
  1.1117 +        return null();
  1.1118 +
  1.1119 +    /* Define the 'arguments' binding if necessary. */
  1.1120 +    if (!checkFunctionArguments())
  1.1121 +        return null();
  1.1122 +
  1.1123 +    return pn;
  1.1124 +}
  1.1125 +
  1.1126 +/* See comment for use in Parser::functionDef. */
  1.1127 +template <>
  1.1128 +bool
  1.1129 +Parser<FullParseHandler>::makeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom)
  1.1130 +{
  1.1131 +    /* Turn pn into a definition. */
  1.1132 +    pc->updateDecl(atom, pn);
  1.1133 +
  1.1134 +    /* Change all uses of dn to be uses of pn. */
  1.1135 +    for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
  1.1136 +        JS_ASSERT(pnu->isUsed());
  1.1137 +        JS_ASSERT(!pnu->isDefn());
  1.1138 +        pnu->pn_lexdef = (Definition *) pn;
  1.1139 +        pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
  1.1140 +    }
  1.1141 +    pn->pn_dflags |= dn->pn_dflags & PND_USE2DEF_FLAGS;
  1.1142 +    pn->dn_uses = dn;
  1.1143 +
  1.1144 +    /*
  1.1145 +     * A PNK_FUNCTION node must be a definition, so convert shadowed function
  1.1146 +     * statements into nops. This is valid since all body-level function
  1.1147 +     * statement initialization happens at the beginning of the function
  1.1148 +     * (thus, only the last statement's effect is visible). E.g., in
  1.1149 +     *
  1.1150 +     *   function outer() {
  1.1151 +     *     function g() { return 1 }
  1.1152 +     *     assertEq(g(), 2);
  1.1153 +     *     function g() { return 2 }
  1.1154 +     *     assertEq(g(), 2);
  1.1155 +     *   }
  1.1156 +     *
  1.1157 +     * both asserts are valid.
  1.1158 +     */
  1.1159 +    if (dn->getKind() == PNK_FUNCTION) {
  1.1160 +        JS_ASSERT(dn->functionIsHoisted());
  1.1161 +        pn->dn_uses = dn->pn_link;
  1.1162 +        handler.prepareNodeForMutation(dn);
  1.1163 +        dn->setKind(PNK_NOP);
  1.1164 +        dn->setArity(PN_NULLARY);
  1.1165 +        return true;
  1.1166 +    }
  1.1167 +
  1.1168 +    /*
  1.1169 +     * If dn is arg, or in [var, const, let] and has an initializer, then we
  1.1170 +     * must rewrite it to be an assignment node, whose freshly allocated
  1.1171 +     * left-hand side becomes a use of pn.
  1.1172 +     */
  1.1173 +    if (dn->canHaveInitializer()) {
  1.1174 +        if (ParseNode *rhs = dn->expr()) {
  1.1175 +            ParseNode *lhs = handler.makeAssignment(dn, rhs);
  1.1176 +            if (!lhs)
  1.1177 +                return false;
  1.1178 +            pn->dn_uses = lhs;
  1.1179 +            dn->pn_link = nullptr;
  1.1180 +            dn = (Definition *) lhs;
  1.1181 +        }
  1.1182 +    }
  1.1183 +
  1.1184 +    /* Turn dn into a use of pn. */
  1.1185 +    JS_ASSERT(dn->isKind(PNK_NAME));
  1.1186 +    JS_ASSERT(dn->isArity(PN_NAME));
  1.1187 +    JS_ASSERT(dn->pn_atom == atom);
  1.1188 +    dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETNAME : JSOP_NAME);
  1.1189 +    dn->setDefn(false);
  1.1190 +    dn->setUsed(true);
  1.1191 +    dn->pn_lexdef = (Definition *) pn;
  1.1192 +    dn->pn_cookie.makeFree();
  1.1193 +    dn->pn_dflags &= ~PND_BOUND;
  1.1194 +    return true;
  1.1195 +}
  1.1196 +
  1.1197 +/*
  1.1198 + * Parameter block types for the several Binder functions.  We use a common
  1.1199 + * helper function signature in order to share code among destructuring and
  1.1200 + * simple variable declaration parsers.  In the destructuring case, the binder
  1.1201 + * function is called indirectly from the variable declaration parser by way
  1.1202 + * of CheckDestructuring and its friends.
  1.1203 + */
  1.1204 +
  1.1205 +template <typename ParseHandler>
  1.1206 +struct BindData
  1.1207 +{
  1.1208 +    BindData(ExclusiveContext *cx) : let(cx) {}
  1.1209 +
  1.1210 +    typedef bool
  1.1211 +    (*Binder)(BindData *data, HandlePropertyName name, Parser<ParseHandler> *parser);
  1.1212 +
  1.1213 +    /* name node for definition processing and error source coordinates */
  1.1214 +    typename ParseHandler::Node pn;
  1.1215 +
  1.1216 +    JSOp            op;         /* prolog bytecode or nop */
  1.1217 +    Binder          binder;     /* binder, discriminates u */
  1.1218 +
  1.1219 +    struct LetData {
  1.1220 +        LetData(ExclusiveContext *cx) : blockObj(cx) {}
  1.1221 +        VarContext varContext;
  1.1222 +        RootedStaticBlockObject blockObj;
  1.1223 +        unsigned   overflow;
  1.1224 +    } let;
  1.1225 +
  1.1226 +    void initLet(VarContext varContext, StaticBlockObject &blockObj, unsigned overflow) {
  1.1227 +        this->pn = ParseHandler::null();
  1.1228 +        this->op = JSOP_NOP;
  1.1229 +        this->binder = Parser<ParseHandler>::bindLet;
  1.1230 +        this->let.varContext = varContext;
  1.1231 +        this->let.blockObj = &blockObj;
  1.1232 +        this->let.overflow = overflow;
  1.1233 +    }
  1.1234 +
  1.1235 +    void initVarOrConst(JSOp op) {
  1.1236 +        this->op = op;
  1.1237 +        this->binder = Parser<ParseHandler>::bindVarOrConst;
  1.1238 +    }
  1.1239 +};
  1.1240 +
  1.1241 +template <typename ParseHandler>
  1.1242 +JSFunction *
  1.1243 +Parser<ParseHandler>::newFunction(GenericParseContext *pc, HandleAtom atom,
  1.1244 +                                  FunctionSyntaxKind kind, JSObject *proto)
  1.1245 +{
  1.1246 +    JS_ASSERT_IF(kind == Statement, atom != nullptr);
  1.1247 +
  1.1248 +    /*
  1.1249 +     * Find the global compilation context in order to pre-set the newborn
  1.1250 +     * function's parent slot to pc->sc->as<GlobalObject>()->scopeChain. If the
  1.1251 +     * global context is a compile-and-go one, we leave the pre-set parent
  1.1252 +     * intact; otherwise we clear parent and proto.
  1.1253 +     */
  1.1254 +    while (pc->parent)
  1.1255 +        pc = pc->parent;
  1.1256 +
  1.1257 +    RootedFunction fun(context);
  1.1258 +    JSFunction::Flags flags = (kind == Expression)
  1.1259 +                              ? JSFunction::INTERPRETED_LAMBDA
  1.1260 +                              : (kind == Arrow)
  1.1261 +                                ? JSFunction::INTERPRETED_LAMBDA_ARROW
  1.1262 +                                : JSFunction::INTERPRETED;
  1.1263 +    gc::AllocKind allocKind = JSFunction::FinalizeKind;
  1.1264 +    if (kind == Arrow)
  1.1265 +        allocKind = JSFunction::ExtendedFinalizeKind;
  1.1266 +    fun = NewFunctionWithProto(context, NullPtr(), nullptr, 0, flags, NullPtr(), atom, proto,
  1.1267 +                               allocKind, MaybeSingletonObject);
  1.1268 +    if (!fun)
  1.1269 +        return nullptr;
  1.1270 +    if (options().selfHostingMode)
  1.1271 +        fun->setIsSelfHostedBuiltin();
  1.1272 +    return fun;
  1.1273 +}
  1.1274 +
  1.1275 +static bool
  1.1276 +MatchOrInsertSemicolon(TokenStream &ts)
  1.1277 +{
  1.1278 +    TokenKind tt = ts.peekTokenSameLine(TokenStream::Operand);
  1.1279 +    if (tt == TOK_ERROR)
  1.1280 +        return false;
  1.1281 +    if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {
  1.1282 +        /* Advance the scanner for proper error location reporting. */
  1.1283 +        ts.getToken(TokenStream::Operand);
  1.1284 +        ts.reportError(JSMSG_SEMI_BEFORE_STMNT);
  1.1285 +        return false;
  1.1286 +    }
  1.1287 +    (void) ts.matchToken(TOK_SEMI);
  1.1288 +    return true;
  1.1289 +}
  1.1290 +
  1.1291 +template <typename ParseHandler>
  1.1292 +typename ParseHandler::DefinitionNode
  1.1293 +Parser<ParseHandler>::getOrCreateLexicalDependency(ParseContext<ParseHandler> *pc, JSAtom *atom)
  1.1294 +{
  1.1295 +    AtomDefnAddPtr p = pc->lexdeps->lookupForAdd(atom);
  1.1296 +    if (p)
  1.1297 +        return p.value().get<ParseHandler>();
  1.1298 +
  1.1299 +    DefinitionNode dn = handler.newPlaceholder(atom, pc->blockid(), pos());
  1.1300 +    if (!dn)
  1.1301 +        return ParseHandler::nullDefinition();
  1.1302 +    DefinitionSingle def = DefinitionSingle::new_<ParseHandler>(dn);
  1.1303 +    if (!pc->lexdeps->add(p, atom, def))
  1.1304 +        return ParseHandler::nullDefinition();
  1.1305 +    return dn;
  1.1306 +}
  1.1307 +
  1.1308 +static bool
  1.1309 +ConvertDefinitionToNamedLambdaUse(TokenStream &ts, ParseContext<FullParseHandler> *pc,
  1.1310 +                                  FunctionBox *funbox, Definition *dn)
  1.1311 +{
  1.1312 +    dn->setOp(JSOP_CALLEE);
  1.1313 +    if (!dn->pn_cookie.set(ts, pc->staticLevel, 0))
  1.1314 +        return false;
  1.1315 +    dn->pn_dflags |= PND_BOUND;
  1.1316 +    JS_ASSERT(dn->kind() == Definition::NAMED_LAMBDA);
  1.1317 +
  1.1318 +    /*
  1.1319 +     * Since 'dn' is a placeholder, it has not been defined in the
  1.1320 +     * ParseContext and hence we must manually flag a closed-over
  1.1321 +     * callee name as needing a dynamic scope (this is done for all
  1.1322 +     * definitions in the ParseContext by generateFunctionBindings).
  1.1323 +     *
  1.1324 +     * If 'dn' has been assigned to, then we also flag the function
  1.1325 +     * scope has needing a dynamic scope so that dynamic scope
  1.1326 +     * setter can either ignore the set (in non-strict mode) or
  1.1327 +     * produce an error (in strict mode).
  1.1328 +     */
  1.1329 +    if (dn->isClosed() || dn->isAssigned())
  1.1330 +        funbox->setNeedsDeclEnvObject();
  1.1331 +    return true;
  1.1332 +}
  1.1333 +
  1.1334 +/*
  1.1335 + * Beware: this function is called for functions nested in other functions or
  1.1336 + * global scripts but not for functions compiled through the Function
  1.1337 + * constructor or JSAPI. To always execute code when a function has finished
  1.1338 + * parsing, use Parser::functionBody.
  1.1339 + */
  1.1340 +template <>
  1.1341 +bool
  1.1342 +Parser<FullParseHandler>::leaveFunction(ParseNode *fn, ParseContext<FullParseHandler> *outerpc,
  1.1343 +                                        FunctionSyntaxKind kind)
  1.1344 +{
  1.1345 +    outerpc->blockidGen = pc->blockidGen;
  1.1346 +
  1.1347 +    FunctionBox *funbox = fn->pn_funbox;
  1.1348 +    JS_ASSERT(funbox == pc->sc->asFunctionBox());
  1.1349 +
  1.1350 +    /* Propagate unresolved lexical names up to outerpc->lexdeps. */
  1.1351 +    if (pc->lexdeps->count()) {
  1.1352 +        for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) {
  1.1353 +            JSAtom *atom = r.front().key();
  1.1354 +            Definition *dn = r.front().value().get<FullParseHandler>();
  1.1355 +            JS_ASSERT(dn->isPlaceholder());
  1.1356 +
  1.1357 +            if (atom == funbox->function()->name() && kind == Expression) {
  1.1358 +                if (!ConvertDefinitionToNamedLambdaUse(tokenStream, pc, funbox, dn))
  1.1359 +                    return false;
  1.1360 +                continue;
  1.1361 +            }
  1.1362 +
  1.1363 +            Definition *outer_dn = outerpc->decls().lookupFirst(atom);
  1.1364 +
  1.1365 +            /*
  1.1366 +             * Make sure to deoptimize lexical dependencies that are polluted
  1.1367 +             * by eval and function statements (which both flag the function as
  1.1368 +             * having an extensible scope) or any enclosing 'with'.
  1.1369 +             */
  1.1370 +            if (funbox->hasExtensibleScope() || outerpc->parsingWith)
  1.1371 +                handler.deoptimizeUsesWithin(dn, fn->pn_pos);
  1.1372 +
  1.1373 +            if (!outer_dn) {
  1.1374 +                /*
  1.1375 +                 * Create a new placeholder for our outer lexdep. We could
  1.1376 +                 * simply re-use the inner placeholder, but that introduces
  1.1377 +                 * subtleties in the case where we find a later definition
  1.1378 +                 * that captures an existing lexdep. For example:
  1.1379 +                 *
  1.1380 +                 *   function f() { function g() { x; } let x; }
  1.1381 +                 *
  1.1382 +                 * Here, g's TOK_UPVARS node lists the placeholder for x,
  1.1383 +                 * which must be captured by the 'let' declaration later,
  1.1384 +                 * since 'let's are hoisted.  Taking g's placeholder as our
  1.1385 +                 * own would work fine. But consider:
  1.1386 +                 *
  1.1387 +                 *   function f() { x; { function g() { x; } let x; } }
  1.1388 +                 *
  1.1389 +                 * Here, the 'let' must not capture all the uses of f's
  1.1390 +                 * lexdep entry for x, but it must capture the x node
  1.1391 +                 * referred to from g's TOK_UPVARS node.  Always turning
  1.1392 +                 * inherited lexdeps into uses of a new outer definition
  1.1393 +                 * allows us to handle both these cases in a natural way.
  1.1394 +                 */
  1.1395 +                outer_dn = getOrCreateLexicalDependency(outerpc, atom);
  1.1396 +                if (!outer_dn)
  1.1397 +                    return false;
  1.1398 +            }
  1.1399 +
  1.1400 +            /*
  1.1401 +             * Insert dn's uses list at the front of outer_dn's list.
  1.1402 +             *
  1.1403 +             * Without loss of generality or correctness, we allow a dn to
  1.1404 +             * be in inner and outer lexdeps, since the purpose of lexdeps
  1.1405 +             * is one-pass coordination of name use and definition across
  1.1406 +             * functions, and if different dn's are used we'll merge lists
  1.1407 +             * when leaving the inner function.
  1.1408 +             *
  1.1409 +             * The dn == outer_dn case arises with generator expressions
  1.1410 +             * (see LegacyCompExprTransplanter::transplant, the PN_CODE/PN_NAME
  1.1411 +             * case), and nowhere else, currently.
  1.1412 +             */
  1.1413 +            if (dn != outer_dn) {
  1.1414 +                if (ParseNode *pnu = dn->dn_uses) {
  1.1415 +                    while (true) {
  1.1416 +                        pnu->pn_lexdef = outer_dn;
  1.1417 +                        if (!pnu->pn_link)
  1.1418 +                            break;
  1.1419 +                        pnu = pnu->pn_link;
  1.1420 +                    }
  1.1421 +                    pnu->pn_link = outer_dn->dn_uses;
  1.1422 +                    outer_dn->dn_uses = dn->dn_uses;
  1.1423 +                    dn->dn_uses = nullptr;
  1.1424 +                }
  1.1425 +
  1.1426 +                outer_dn->pn_dflags |= dn->pn_dflags & ~PND_PLACEHOLDER;
  1.1427 +            }
  1.1428 +
  1.1429 +            /* Mark the outer dn as escaping. */
  1.1430 +            outer_dn->pn_dflags |= PND_CLOSED;
  1.1431 +        }
  1.1432 +    }
  1.1433 +
  1.1434 +    InternalHandle<Bindings*> bindings =
  1.1435 +        InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings);
  1.1436 +    return pc->generateFunctionBindings(context, tokenStream, alloc, bindings);
  1.1437 +}
  1.1438 +
  1.1439 +template <>
  1.1440 +bool
  1.1441 +Parser<SyntaxParseHandler>::leaveFunction(Node fn, ParseContext<SyntaxParseHandler> *outerpc,
  1.1442 +                                          FunctionSyntaxKind kind)
  1.1443 +{
  1.1444 +    outerpc->blockidGen = pc->blockidGen;
  1.1445 +
  1.1446 +    FunctionBox *funbox = pc->sc->asFunctionBox();
  1.1447 +    return addFreeVariablesFromLazyFunction(funbox->function(), outerpc);
  1.1448 +}
  1.1449 +
  1.1450 +/*
  1.1451 + * defineArg is called for both the arguments of a regular function definition
  1.1452 + * and the arguments specified by the Function constructor.
  1.1453 + *
  1.1454 + * The 'disallowDuplicateArgs' bool indicates whether the use of another
  1.1455 + * feature (destructuring or default arguments) disables duplicate arguments.
  1.1456 + * (ECMA-262 requires us to support duplicate parameter names, but, for newer
  1.1457 + * features, we consider the code to have "opted in" to higher standards and
  1.1458 + * forbid duplicates.)
  1.1459 + *
  1.1460 + * If 'duplicatedArg' is non-null, then DefineArg assigns to it any previous
  1.1461 + * argument with the same name. The caller may use this to report an error when
  1.1462 + * one of the abovementioned features occurs after a duplicate.
  1.1463 + */
  1.1464 +template <typename ParseHandler>
  1.1465 +bool
  1.1466 +Parser<ParseHandler>::defineArg(Node funcpn, HandlePropertyName name,
  1.1467 +                                bool disallowDuplicateArgs, Node *duplicatedArg)
  1.1468 +{
  1.1469 +    SharedContext *sc = pc->sc;
  1.1470 +
  1.1471 +    /* Handle duplicate argument names. */
  1.1472 +    if (DefinitionNode prevDecl = pc->decls().lookupFirst(name)) {
  1.1473 +        Node pn = handler.getDefinitionNode(prevDecl);
  1.1474 +
  1.1475 +        /*
  1.1476 +         * Strict-mode disallows duplicate args. We may not know whether we are
  1.1477 +         * in strict mode or not (since the function body hasn't been parsed).
  1.1478 +         * In such cases, report will queue up the potential error and return
  1.1479 +         * 'true'.
  1.1480 +         */
  1.1481 +        if (sc->needStrictChecks()) {
  1.1482 +            JSAutoByteString bytes;
  1.1483 +            if (!AtomToPrintableString(context, name, &bytes))
  1.1484 +                return false;
  1.1485 +            if (!report(ParseStrictError, pc->sc->strict, pn,
  1.1486 +                        JSMSG_DUPLICATE_FORMAL, bytes.ptr()))
  1.1487 +            {
  1.1488 +                return false;
  1.1489 +            }
  1.1490 +        }
  1.1491 +
  1.1492 +        if (disallowDuplicateArgs) {
  1.1493 +            report(ParseError, false, pn, JSMSG_BAD_DUP_ARGS);
  1.1494 +            return false;
  1.1495 +        }
  1.1496 +
  1.1497 +        if (duplicatedArg)
  1.1498 +            *duplicatedArg = pn;
  1.1499 +
  1.1500 +        /* ParseContext::define assumes and asserts prevDecl is not in decls. */
  1.1501 +        JS_ASSERT(handler.getDefinitionKind(prevDecl) == Definition::ARG);
  1.1502 +        pc->prepareToAddDuplicateArg(name, prevDecl);
  1.1503 +    }
  1.1504 +
  1.1505 +    Node argpn = newName(name);
  1.1506 +    if (!argpn)
  1.1507 +        return false;
  1.1508 +
  1.1509 +    if (!checkStrictBinding(name, argpn))
  1.1510 +        return false;
  1.1511 +
  1.1512 +    handler.addFunctionArgument(funcpn, argpn);
  1.1513 +    return pc->define(tokenStream, name, argpn, Definition::ARG);
  1.1514 +}
  1.1515 +
  1.1516 +template <typename ParseHandler>
  1.1517 +/* static */ bool
  1.1518 +Parser<ParseHandler>::bindDestructuringArg(BindData<ParseHandler> *data,
  1.1519 +                                           HandlePropertyName name, Parser<ParseHandler> *parser)
  1.1520 +{
  1.1521 +    ParseContext<ParseHandler> *pc = parser->pc;
  1.1522 +    JS_ASSERT(pc->sc->isFunctionBox());
  1.1523 +
  1.1524 +    if (pc->decls().lookupFirst(name)) {
  1.1525 +        parser->report(ParseError, false, null(), JSMSG_BAD_DUP_ARGS);
  1.1526 +        return false;
  1.1527 +    }
  1.1528 +
  1.1529 +    if (!parser->checkStrictBinding(name, data->pn))
  1.1530 +        return false;
  1.1531 +
  1.1532 +    return pc->define(parser->tokenStream, name, data->pn, Definition::VAR);
  1.1533 +}
  1.1534 +
  1.1535 +template <typename ParseHandler>
  1.1536 +bool
  1.1537 +Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, Node *listp, Node funcpn,
  1.1538 +                                        bool *hasRest)
  1.1539 +{
  1.1540 +    FunctionBox *funbox = pc->sc->asFunctionBox();
  1.1541 +
  1.1542 +    *hasRest = false;
  1.1543 +
  1.1544 +    bool parenFreeArrow = false;
  1.1545 +    if (kind == Arrow && tokenStream.peekToken() == TOK_NAME) {
  1.1546 +        parenFreeArrow = true;
  1.1547 +    } else {
  1.1548 +        if (tokenStream.getToken() != TOK_LP) {
  1.1549 +            report(ParseError, false, null(),
  1.1550 +                   kind == Arrow ? JSMSG_BAD_ARROW_ARGS : JSMSG_PAREN_BEFORE_FORMAL);
  1.1551 +            return false;
  1.1552 +        }
  1.1553 +
  1.1554 +        // Record the start of function source (for FunctionToString). If we
  1.1555 +        // are parenFreeArrow, we will set this below, after consuming the NAME.
  1.1556 +        funbox->setStart(tokenStream);
  1.1557 +    }
  1.1558 +
  1.1559 +    Node argsbody = handler.newList(PNK_ARGSBODY);
  1.1560 +    if (!argsbody)
  1.1561 +        return false;
  1.1562 +    handler.setFunctionBody(funcpn, argsbody);
  1.1563 +
  1.1564 +    if (parenFreeArrow || !tokenStream.matchToken(TOK_RP)) {
  1.1565 +        bool hasDefaults = false;
  1.1566 +        Node duplicatedArg = null();
  1.1567 +        Node list = null();
  1.1568 +
  1.1569 +        do {
  1.1570 +            if (*hasRest) {
  1.1571 +                report(ParseError, false, null(), JSMSG_PARAMETER_AFTER_REST);
  1.1572 +                return false;
  1.1573 +            }
  1.1574 +
  1.1575 +            TokenKind tt = tokenStream.getToken();
  1.1576 +            JS_ASSERT_IF(parenFreeArrow, tt == TOK_NAME);
  1.1577 +            switch (tt) {
  1.1578 +              case TOK_LB:
  1.1579 +              case TOK_LC:
  1.1580 +              {
  1.1581 +                /* See comment below in the TOK_NAME case. */
  1.1582 +                if (duplicatedArg) {
  1.1583 +                    report(ParseError, false, duplicatedArg, JSMSG_BAD_DUP_ARGS);
  1.1584 +                    return false;
  1.1585 +                }
  1.1586 +
  1.1587 +                if (hasDefaults) {
  1.1588 +                    report(ParseError, false, null(), JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT);
  1.1589 +                    return false;
  1.1590 +                }
  1.1591 +
  1.1592 +                funbox->hasDestructuringArgs = true;
  1.1593 +
  1.1594 +                /*
  1.1595 +                 * A destructuring formal parameter turns into one or more
  1.1596 +                 * local variables initialized from properties of a single
  1.1597 +                 * anonymous positional parameter, so here we must tweak our
  1.1598 +                 * binder and its data.
  1.1599 +                 */
  1.1600 +                BindData<ParseHandler> data(context);
  1.1601 +                data.pn = ParseHandler::null();
  1.1602 +                data.op = JSOP_DEFVAR;
  1.1603 +                data.binder = bindDestructuringArg;
  1.1604 +                Node lhs = destructuringExpr(&data, tt);
  1.1605 +                if (!lhs)
  1.1606 +                    return false;
  1.1607 +
  1.1608 +                /*
  1.1609 +                 * Synthesize a destructuring assignment from the single
  1.1610 +                 * anonymous positional parameter into the destructuring
  1.1611 +                 * left-hand-side expression and accumulate it in list.
  1.1612 +                 */
  1.1613 +                HandlePropertyName name = context->names().empty;
  1.1614 +                Node rhs = newName(name);
  1.1615 +                if (!rhs)
  1.1616 +                    return false;
  1.1617 +
  1.1618 +                if (!pc->define(tokenStream, name, rhs, Definition::ARG))
  1.1619 +                    return false;
  1.1620 +
  1.1621 +                Node item = handler.newBinary(PNK_ASSIGN, lhs, rhs);
  1.1622 +                if (!item)
  1.1623 +                    return false;
  1.1624 +                if (list) {
  1.1625 +                    handler.addList(list, item);
  1.1626 +                } else {
  1.1627 +                    list = handler.newList(PNK_VAR, item);
  1.1628 +                    if (!list)
  1.1629 +                        return false;
  1.1630 +                    *listp = list;
  1.1631 +                }
  1.1632 +                break;
  1.1633 +              }
  1.1634 +
  1.1635 +              case TOK_YIELD:
  1.1636 +                if (!checkYieldNameValidity())
  1.1637 +                    return false;
  1.1638 +                goto TOK_NAME;
  1.1639 +
  1.1640 +              case TOK_TRIPLEDOT:
  1.1641 +              {
  1.1642 +                *hasRest = true;
  1.1643 +                tt = tokenStream.getToken();
  1.1644 +                if (tt != TOK_NAME) {
  1.1645 +                    if (tt != TOK_ERROR)
  1.1646 +                        report(ParseError, false, null(), JSMSG_NO_REST_NAME);
  1.1647 +                    return false;
  1.1648 +                }
  1.1649 +                goto TOK_NAME;
  1.1650 +              }
  1.1651 +
  1.1652 +              TOK_NAME:
  1.1653 +              case TOK_NAME:
  1.1654 +              {
  1.1655 +                if (parenFreeArrow)
  1.1656 +                    funbox->setStart(tokenStream);
  1.1657 +
  1.1658 +                RootedPropertyName name(context, tokenStream.currentName());
  1.1659 +                bool disallowDuplicateArgs = funbox->hasDestructuringArgs || hasDefaults;
  1.1660 +                if (!defineArg(funcpn, name, disallowDuplicateArgs, &duplicatedArg))
  1.1661 +                    return false;
  1.1662 +
  1.1663 +                if (tokenStream.matchToken(TOK_ASSIGN)) {
  1.1664 +                    // A default argument without parentheses would look like:
  1.1665 +                    // a = expr => body, but both operators are right-associative, so
  1.1666 +                    // that would have been parsed as a = (expr => body) instead.
  1.1667 +                    // Therefore it's impossible to get here with parenFreeArrow.
  1.1668 +                    JS_ASSERT(!parenFreeArrow);
  1.1669 +
  1.1670 +                    if (*hasRest) {
  1.1671 +                        report(ParseError, false, null(), JSMSG_REST_WITH_DEFAULT);
  1.1672 +                        return false;
  1.1673 +                    }
  1.1674 +                    if (duplicatedArg) {
  1.1675 +                        report(ParseError, false, duplicatedArg, JSMSG_BAD_DUP_ARGS);
  1.1676 +                        return false;
  1.1677 +                    }
  1.1678 +                    if (!hasDefaults) {
  1.1679 +                        hasDefaults = true;
  1.1680 +
  1.1681 +                        // The Function.length property is the number of formals
  1.1682 +                        // before the first default argument.
  1.1683 +                        funbox->length = pc->numArgs() - 1;
  1.1684 +                    }
  1.1685 +                    Node def_expr = assignExprWithoutYield(JSMSG_YIELD_IN_DEFAULT);
  1.1686 +                    if (!def_expr)
  1.1687 +                        return false;
  1.1688 +                    handler.setLastFunctionArgumentDefault(funcpn, def_expr);
  1.1689 +                }
  1.1690 +
  1.1691 +                break;
  1.1692 +              }
  1.1693 +
  1.1694 +              default:
  1.1695 +                report(ParseError, false, null(), JSMSG_MISSING_FORMAL);
  1.1696 +                /* FALL THROUGH */
  1.1697 +              case TOK_ERROR:
  1.1698 +                return false;
  1.1699 +            }
  1.1700 +        } while (!parenFreeArrow && tokenStream.matchToken(TOK_COMMA));
  1.1701 +
  1.1702 +        if (!parenFreeArrow && tokenStream.getToken() != TOK_RP) {
  1.1703 +            report(ParseError, false, null(), JSMSG_PAREN_AFTER_FORMAL);
  1.1704 +            return false;
  1.1705 +        }
  1.1706 +
  1.1707 +        if (!hasDefaults)
  1.1708 +            funbox->length = pc->numArgs() - *hasRest;
  1.1709 +    }
  1.1710 +
  1.1711 +    return true;
  1.1712 +}
  1.1713 +
  1.1714 +template <>
  1.1715 +bool
  1.1716 +Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
  1.1717 +                                                  ParseNode **pn_, FunctionSyntaxKind kind,
  1.1718 +                                                  bool *pbodyProcessed)
  1.1719 +{
  1.1720 +    ParseNode *&pn = *pn_;
  1.1721 +    *pbodyProcessed = false;
  1.1722 +
  1.1723 +    /* Function statements add a binding to the enclosing scope. */
  1.1724 +    bool bodyLevel = pc->atBodyLevel();
  1.1725 +
  1.1726 +    if (kind == Statement) {
  1.1727 +        /*
  1.1728 +         * Handle redeclaration and optimize cases where we can statically bind the
  1.1729 +         * function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
  1.1730 +         */
  1.1731 +        if (Definition *dn = pc->decls().lookupFirst(funName)) {
  1.1732 +            JS_ASSERT(!dn->isUsed());
  1.1733 +            JS_ASSERT(dn->isDefn());
  1.1734 +
  1.1735 +            if (options().extraWarningsOption || dn->kind() == Definition::CONST) {
  1.1736 +                JSAutoByteString name;
  1.1737 +                ParseReportKind reporter = (dn->kind() != Definition::CONST)
  1.1738 +                                           ? ParseExtraWarning
  1.1739 +                                           : ParseError;
  1.1740 +                if (!AtomToPrintableString(context, funName, &name) ||
  1.1741 +                    !report(reporter, false, nullptr, JSMSG_REDECLARED_VAR,
  1.1742 +                            Definition::kindString(dn->kind()), name.ptr()))
  1.1743 +                {
  1.1744 +                    return false;
  1.1745 +                }
  1.1746 +            }
  1.1747 +
  1.1748 +            /*
  1.1749 +             * Body-level function statements are effectively variable
  1.1750 +             * declarations where the initialization is hoisted to the
  1.1751 +             * beginning of the block. This means that any other variable
  1.1752 +             * declaration with the same name is really just an assignment to
  1.1753 +             * the function's binding (which is mutable), so turn any existing
  1.1754 +             * declaration into a use.
  1.1755 +             */
  1.1756 +            if (bodyLevel && !makeDefIntoUse(dn, pn, funName))
  1.1757 +                return false;
  1.1758 +        } else if (bodyLevel) {
  1.1759 +            /*
  1.1760 +             * If this function was used before it was defined, claim the
  1.1761 +             * pre-created definition node for this function that primaryExpr
  1.1762 +             * put in pc->lexdeps on first forward reference, and recycle pn.
  1.1763 +             */
  1.1764 +            if (Definition *fn = pc->lexdeps.lookupDefn<FullParseHandler>(funName)) {
  1.1765 +                JS_ASSERT(fn->isDefn());
  1.1766 +                fn->setKind(PNK_FUNCTION);
  1.1767 +                fn->setArity(PN_CODE);
  1.1768 +                fn->pn_pos.begin = pn->pn_pos.begin;
  1.1769 +                fn->pn_pos.end = pn->pn_pos.end;
  1.1770 +
  1.1771 +                fn->pn_body = nullptr;
  1.1772 +                fn->pn_cookie.makeFree();
  1.1773 +
  1.1774 +                pc->lexdeps->remove(funName);
  1.1775 +                handler.freeTree(pn);
  1.1776 +                pn = fn;
  1.1777 +            }
  1.1778 +
  1.1779 +            if (!pc->define(tokenStream, funName, pn, Definition::VAR))
  1.1780 +                return false;
  1.1781 +        }
  1.1782 +
  1.1783 +        if (bodyLevel) {
  1.1784 +            JS_ASSERT(pn->functionIsHoisted());
  1.1785 +            JS_ASSERT_IF(pc->sc->isFunctionBox(), !pn->pn_cookie.isFree());
  1.1786 +            JS_ASSERT_IF(!pc->sc->isFunctionBox(), pn->pn_cookie.isFree());
  1.1787 +        } else {
  1.1788 +            /*
  1.1789 +             * As a SpiderMonkey-specific extension, non-body-level function
  1.1790 +             * statements (e.g., functions in an "if" or "while" block) are
  1.1791 +             * dynamically bound when control flow reaches the statement.
  1.1792 +             */
  1.1793 +            JS_ASSERT(!pc->sc->strict);
  1.1794 +            JS_ASSERT(pn->pn_cookie.isFree());
  1.1795 +            if (pc->sc->isFunctionBox()) {
  1.1796 +                FunctionBox *funbox = pc->sc->asFunctionBox();
  1.1797 +                funbox->setMightAliasLocals();
  1.1798 +                funbox->setHasExtensibleScope();
  1.1799 +            }
  1.1800 +            pn->setOp(JSOP_DEFFUN);
  1.1801 +
  1.1802 +            /*
  1.1803 +             * Instead of setting bindingsAccessedDynamically, which would be
  1.1804 +             * overly conservative, remember the names of all function
  1.1805 +             * statements and mark any bindings with the same as aliased at the
  1.1806 +             * end of functionBody.
  1.1807 +             */
  1.1808 +            if (!pc->funcStmts) {
  1.1809 +                pc->funcStmts = context->new_<FuncStmtSet>(context);
  1.1810 +                if (!pc->funcStmts || !pc->funcStmts->init())
  1.1811 +                    return false;
  1.1812 +            }
  1.1813 +            if (!pc->funcStmts->put(funName))
  1.1814 +                return false;
  1.1815 +
  1.1816 +            /*
  1.1817 +             * Due to the implicit declaration mechanism, 'arguments' will not
  1.1818 +             * have decls and, even if it did, they will not be noted as closed
  1.1819 +             * in the emitter. Thus, in the corner case of function statements
  1.1820 +             * overridding arguments, flag the whole scope as dynamic.
  1.1821 +             */
  1.1822 +            if (funName == context->names().arguments)
  1.1823 +                pc->sc->setBindingsAccessedDynamically();
  1.1824 +        }
  1.1825 +
  1.1826 +        /* No further binding (in BindNameToSlot) is needed for functions. */
  1.1827 +        pn->pn_dflags |= PND_BOUND;
  1.1828 +    } else {
  1.1829 +        /* A function expression does not introduce any binding. */
  1.1830 +        pn->setOp(kind == Arrow ? JSOP_LAMBDA_ARROW : JSOP_LAMBDA);
  1.1831 +    }
  1.1832 +
  1.1833 +    // When a lazily-parsed function is called, we only fully parse (and emit)
  1.1834 +    // that function, not any of its nested children. The initial syntax-only
  1.1835 +    // parse recorded the free variables of nested functions and their extents,
  1.1836 +    // so we can skip over them after accounting for their free variables.
  1.1837 +    if (LazyScript *lazyOuter = handler.lazyOuterFunction()) {
  1.1838 +        JSFunction *fun = handler.nextLazyInnerFunction();
  1.1839 +        JS_ASSERT(!fun->isLegacyGenerator());
  1.1840 +        FunctionBox *funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ false),
  1.1841 +                                             fun->generatorKind());
  1.1842 +        if (!funbox)
  1.1843 +            return false;
  1.1844 +
  1.1845 +        if (!addFreeVariablesFromLazyFunction(fun, pc))
  1.1846 +            return false;
  1.1847 +
  1.1848 +        // The position passed to tokenStream.advance() is relative to
  1.1849 +        // userbuf.base() while LazyScript::{begin,end} offsets are relative to
  1.1850 +        // the outermost script source. N.B: userbuf.base() is initialized
  1.1851 +        // (in TokenStream()) to begin() - column() so that column numbers in
  1.1852 +        // the lazily parsed script are correct.
  1.1853 +        uint32_t userbufBase = lazyOuter->begin() - lazyOuter->column();
  1.1854 +        tokenStream.advance(fun->lazyScript()->end() - userbufBase);
  1.1855 +
  1.1856 +        *pbodyProcessed = true;
  1.1857 +        return true;
  1.1858 +    }
  1.1859 +
  1.1860 +    return true;
  1.1861 +}
  1.1862 +
  1.1863 +template <class T, class U>
  1.1864 +static inline void
  1.1865 +PropagateTransitiveParseFlags(const T *inner, U *outer)
  1.1866 +{
  1.1867 +   if (inner->bindingsAccessedDynamically())
  1.1868 +     outer->setBindingsAccessedDynamically();
  1.1869 +   if (inner->hasDebuggerStatement())
  1.1870 +     outer->setHasDebuggerStatement();
  1.1871 +}
  1.1872 +
  1.1873 +template <typename ParseHandler>
  1.1874 +bool
  1.1875 +Parser<ParseHandler>::addFreeVariablesFromLazyFunction(JSFunction *fun,
  1.1876 +                                                       ParseContext<ParseHandler> *pc)
  1.1877 +{
  1.1878 +    // Update any definition nodes in this context according to free variables
  1.1879 +    // in a lazily parsed inner function.
  1.1880 +
  1.1881 +    LazyScript *lazy = fun->lazyScript();
  1.1882 +    HeapPtrAtom *freeVariables = lazy->freeVariables();
  1.1883 +    for (size_t i = 0; i < lazy->numFreeVariables(); i++) {
  1.1884 +        JSAtom *atom = freeVariables[i];
  1.1885 +
  1.1886 +        // 'arguments' will be implicitly bound within the inner function.
  1.1887 +        if (atom == context->names().arguments)
  1.1888 +            continue;
  1.1889 +
  1.1890 +        DefinitionNode dn = pc->decls().lookupFirst(atom);
  1.1891 +
  1.1892 +        if (!dn) {
  1.1893 +            dn = getOrCreateLexicalDependency(pc, atom);
  1.1894 +            if (!dn)
  1.1895 +                return false;
  1.1896 +        }
  1.1897 +
  1.1898 +        /* Mark the outer dn as escaping. */
  1.1899 +        handler.setFlag(handler.getDefinitionNode(dn), PND_CLOSED);
  1.1900 +    }
  1.1901 +
  1.1902 +    PropagateTransitiveParseFlags(lazy, pc->sc);
  1.1903 +    return true;
  1.1904 +}
  1.1905 +
  1.1906 +template <>
  1.1907 +bool
  1.1908 +Parser<SyntaxParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
  1.1909 +                                                    Node *pn, FunctionSyntaxKind kind,
  1.1910 +                                                    bool *pbodyProcessed)
  1.1911 +{
  1.1912 +    *pbodyProcessed = false;
  1.1913 +
  1.1914 +    /* Function statements add a binding to the enclosing scope. */
  1.1915 +    bool bodyLevel = pc->atBodyLevel();
  1.1916 +
  1.1917 +    if (kind == Statement) {
  1.1918 +        /*
  1.1919 +         * Handle redeclaration and optimize cases where we can statically bind the
  1.1920 +         * function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
  1.1921 +         */
  1.1922 +        if (DefinitionNode dn = pc->decls().lookupFirst(funName)) {
  1.1923 +            if (dn == Definition::CONST) {
  1.1924 +                JSAutoByteString name;
  1.1925 +                if (!AtomToPrintableString(context, funName, &name) ||
  1.1926 +                    !report(ParseError, false, null(), JSMSG_REDECLARED_VAR,
  1.1927 +                            Definition::kindString(dn), name.ptr()))
  1.1928 +                {
  1.1929 +                    return false;
  1.1930 +                }
  1.1931 +            }
  1.1932 +        } else if (bodyLevel) {
  1.1933 +            if (pc->lexdeps.lookupDefn<SyntaxParseHandler>(funName))
  1.1934 +                pc->lexdeps->remove(funName);
  1.1935 +
  1.1936 +            if (!pc->define(tokenStream, funName, *pn, Definition::VAR))
  1.1937 +                return false;
  1.1938 +        }
  1.1939 +
  1.1940 +        if (!bodyLevel && funName == context->names().arguments)
  1.1941 +            pc->sc->setBindingsAccessedDynamically();
  1.1942 +    }
  1.1943 +
  1.1944 +    if (kind == Arrow) {
  1.1945 +        /* Arrow functions cannot yet be parsed lazily. */
  1.1946 +        return abortIfSyntaxParser();
  1.1947 +    }
  1.1948 +
  1.1949 +    return true;
  1.1950 +}
  1.1951 +
  1.1952 +template <typename ParseHandler>
  1.1953 +typename ParseHandler::Node
  1.1954 +Parser<ParseHandler>::functionDef(HandlePropertyName funName, const TokenStream::Position &start,
  1.1955 +                                  FunctionType type, FunctionSyntaxKind kind,
  1.1956 +                                  GeneratorKind generatorKind)
  1.1957 +{
  1.1958 +    JS_ASSERT_IF(kind == Statement, funName);
  1.1959 +
  1.1960 +    /* Make a TOK_FUNCTION node. */
  1.1961 +    Node pn = handler.newFunctionDefinition();
  1.1962 +    if (!pn)
  1.1963 +        return null();
  1.1964 +
  1.1965 +    bool bodyProcessed;
  1.1966 +    if (!checkFunctionDefinition(funName, &pn, kind, &bodyProcessed))
  1.1967 +        return null();
  1.1968 +
  1.1969 +    if (bodyProcessed)
  1.1970 +        return pn;
  1.1971 +
  1.1972 +    RootedObject proto(context);
  1.1973 +    if (generatorKind == StarGenerator) {
  1.1974 +        // If we are off the main thread, the generator meta-objects have
  1.1975 +        // already been created by js::StartOffThreadParseScript, so cx will not
  1.1976 +        // be necessary.
  1.1977 +        JSContext *cx = context->maybeJSContext();
  1.1978 +        proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, context->global());
  1.1979 +        if (!proto)
  1.1980 +            return null();
  1.1981 +    }
  1.1982 +    RootedFunction fun(context, newFunction(pc, funName, kind, proto));
  1.1983 +    if (!fun)
  1.1984 +        return null();
  1.1985 +
  1.1986 +    // Speculatively parse using the directives of the parent parsing context.
  1.1987 +    // If a directive is encountered (e.g., "use strict") that changes how the
  1.1988 +    // function should have been parsed, we backup and reparse with the new set
  1.1989 +    // of directives.
  1.1990 +    Directives directives(pc);
  1.1991 +    Directives newDirectives = directives;
  1.1992 +
  1.1993 +    while (true) {
  1.1994 +        if (functionArgsAndBody(pn, fun, type, kind, generatorKind, directives, &newDirectives))
  1.1995 +            break;
  1.1996 +        if (tokenStream.hadError() || directives == newDirectives)
  1.1997 +            return null();
  1.1998 +
  1.1999 +        // Assignment must be monotonic to prevent reparsing iloops
  1.2000 +        JS_ASSERT_IF(directives.strict(), newDirectives.strict());
  1.2001 +        JS_ASSERT_IF(directives.asmJS(), newDirectives.asmJS());
  1.2002 +        directives = newDirectives;
  1.2003 +
  1.2004 +        tokenStream.seek(start);
  1.2005 +        if (funName && tokenStream.getToken() == TOK_ERROR)
  1.2006 +            return null();
  1.2007 +
  1.2008 +        // functionArgsAndBody may have already set pn->pn_body before failing.
  1.2009 +        handler.setFunctionBody(pn, null());
  1.2010 +    }
  1.2011 +
  1.2012 +    return pn;
  1.2013 +}
  1.2014 +
  1.2015 +template <>
  1.2016 +bool
  1.2017 +Parser<FullParseHandler>::finishFunctionDefinition(ParseNode *pn, FunctionBox *funbox,
  1.2018 +                                                   ParseNode *prelude, ParseNode *body)
  1.2019 +{
  1.2020 +    pn->pn_pos.end = pos().end;
  1.2021 +
  1.2022 +    /*
  1.2023 +     * If there were destructuring formal parameters, prepend the initializing
  1.2024 +     * comma expression that we synthesized to body. If the body is a return
  1.2025 +     * node, we must make a special PNK_SEQ node, to prepend the destructuring
  1.2026 +     * code without bracing the decompilation of the function body.
  1.2027 +     */
  1.2028 +    if (prelude) {
  1.2029 +        if (!body->isArity(PN_LIST)) {
  1.2030 +            ParseNode *block;
  1.2031 +
  1.2032 +            block = ListNode::create(PNK_SEQ, &handler);
  1.2033 +            if (!block)
  1.2034 +                return false;
  1.2035 +            block->pn_pos = body->pn_pos;
  1.2036 +            block->initList(body);
  1.2037 +
  1.2038 +            body = block;
  1.2039 +        }
  1.2040 +
  1.2041 +        ParseNode *item = UnaryNode::create(PNK_SEMI, &handler);
  1.2042 +        if (!item)
  1.2043 +            return false;
  1.2044 +
  1.2045 +        item->pn_pos.begin = item->pn_pos.end = body->pn_pos.begin;
  1.2046 +        item->pn_kid = prelude;
  1.2047 +        item->pn_next = body->pn_head;
  1.2048 +        body->pn_head = item;
  1.2049 +        if (body->pn_tail == &body->pn_head)
  1.2050 +            body->pn_tail = &item->pn_next;
  1.2051 +        ++body->pn_count;
  1.2052 +        body->pn_xflags |= PNX_DESTRUCT;
  1.2053 +    }
  1.2054 +
  1.2055 +    JS_ASSERT(pn->pn_funbox == funbox);
  1.2056 +    JS_ASSERT(pn->pn_body->isKind(PNK_ARGSBODY));
  1.2057 +    pn->pn_body->append(body);
  1.2058 +    pn->pn_body->pn_pos = body->pn_pos;
  1.2059 +
  1.2060 +    return true;
  1.2061 +}
  1.2062 +
  1.2063 +template <>
  1.2064 +bool
  1.2065 +Parser<SyntaxParseHandler>::finishFunctionDefinition(Node pn, FunctionBox *funbox,
  1.2066 +                                                     Node prelude, Node body)
  1.2067 +{
  1.2068 +    // The LazyScript for a lazily parsed function needs to be constructed
  1.2069 +    // while its ParseContext and associated lexdeps and inner functions are
  1.2070 +    // still available.
  1.2071 +
  1.2072 +    if (funbox->inWith)
  1.2073 +        return abortIfSyntaxParser();
  1.2074 +
  1.2075 +    size_t numFreeVariables = pc->lexdeps->count();
  1.2076 +    size_t numInnerFunctions = pc->innerFunctions.length();
  1.2077 +
  1.2078 +    RootedFunction fun(context, funbox->function());
  1.2079 +    LazyScript *lazy = LazyScript::CreateRaw(context, fun, numFreeVariables, numInnerFunctions,
  1.2080 +                                             versionNumber(), funbox->bufStart, funbox->bufEnd,
  1.2081 +                                             funbox->startLine, funbox->startColumn);
  1.2082 +    if (!lazy)
  1.2083 +        return false;
  1.2084 +
  1.2085 +    HeapPtrAtom *freeVariables = lazy->freeVariables();
  1.2086 +    size_t i = 0;
  1.2087 +    for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront())
  1.2088 +        freeVariables[i++].init(r.front().key());
  1.2089 +    JS_ASSERT(i == numFreeVariables);
  1.2090 +
  1.2091 +    HeapPtrFunction *innerFunctions = lazy->innerFunctions();
  1.2092 +    for (size_t i = 0; i < numInnerFunctions; i++)
  1.2093 +        innerFunctions[i].init(pc->innerFunctions[i]);
  1.2094 +
  1.2095 +    if (pc->sc->strict)
  1.2096 +        lazy->setStrict();
  1.2097 +    lazy->setGeneratorKind(funbox->generatorKind());
  1.2098 +    if (funbox->usesArguments && funbox->usesApply)
  1.2099 +        lazy->setUsesArgumentsAndApply();
  1.2100 +    PropagateTransitiveParseFlags(funbox, lazy);
  1.2101 +
  1.2102 +    fun->initLazyScript(lazy);
  1.2103 +    return true;
  1.2104 +}
  1.2105 +
  1.2106 +template <>
  1.2107 +bool
  1.2108 +Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
  1.2109 +                                              FunctionType type, FunctionSyntaxKind kind,
  1.2110 +                                              GeneratorKind generatorKind,
  1.2111 +                                              Directives inheritedDirectives,
  1.2112 +                                              Directives *newDirectives)
  1.2113 +{
  1.2114 +    ParseContext<FullParseHandler> *outerpc = pc;
  1.2115 +
  1.2116 +    // Create box for fun->object early to protect against last-ditch GC.
  1.2117 +    FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
  1.2118 +    if (!funbox)
  1.2119 +        return false;
  1.2120 +
  1.2121 +    // Try a syntax parse for this inner function.
  1.2122 +    do {
  1.2123 +        Parser<SyntaxParseHandler> *parser = handler.syntaxParser;
  1.2124 +        if (!parser)
  1.2125 +            break;
  1.2126 +
  1.2127 +        {
  1.2128 +            // Move the syntax parser to the current position in the stream.
  1.2129 +            TokenStream::Position position(keepAtoms);
  1.2130 +            tokenStream.tell(&position);
  1.2131 +            if (!parser->tokenStream.seek(position, tokenStream))
  1.2132 +                return false;
  1.2133 +
  1.2134 +            ParseContext<SyntaxParseHandler> funpc(parser, outerpc, SyntaxParseHandler::null(), funbox,
  1.2135 +                                                   newDirectives, outerpc->staticLevel + 1,
  1.2136 +                                                   outerpc->blockidGen,
  1.2137 +                                                   /* blockScopeDepth = */ 0);
  1.2138 +            if (!funpc.init(tokenStream))
  1.2139 +                return false;
  1.2140 +
  1.2141 +            if (!parser->functionArgsAndBodyGeneric(SyntaxParseHandler::NodeGeneric,
  1.2142 +                                                    fun, type, kind, newDirectives))
  1.2143 +            {
  1.2144 +                if (parser->hadAbortedSyntaxParse()) {
  1.2145 +                    // Try again with a full parse.
  1.2146 +                    parser->clearAbortedSyntaxParse();
  1.2147 +                    break;
  1.2148 +                }
  1.2149 +                return false;
  1.2150 +            }
  1.2151 +
  1.2152 +            outerpc->blockidGen = funpc.blockidGen;
  1.2153 +
  1.2154 +            // Advance this parser over tokens processed by the syntax parser.
  1.2155 +            parser->tokenStream.tell(&position);
  1.2156 +            if (!tokenStream.seek(position, parser->tokenStream))
  1.2157 +                return false;
  1.2158 +
  1.2159 +            // Update the end position of the parse node.
  1.2160 +            pn->pn_pos.end = tokenStream.currentToken().pos.end;
  1.2161 +        }
  1.2162 +
  1.2163 +        if (!addFreeVariablesFromLazyFunction(fun, pc))
  1.2164 +            return false;
  1.2165 +
  1.2166 +        pn->pn_blockid = outerpc->blockid();
  1.2167 +        PropagateTransitiveParseFlags(funbox, outerpc->sc);
  1.2168 +        return true;
  1.2169 +    } while (false);
  1.2170 +
  1.2171 +    // Continue doing a full parse for this inner function.
  1.2172 +    ParseContext<FullParseHandler> funpc(this, pc, pn, funbox, newDirectives,
  1.2173 +                                         outerpc->staticLevel + 1, outerpc->blockidGen,
  1.2174 +                                         /* blockScopeDepth = */ 0);
  1.2175 +    if (!funpc.init(tokenStream))
  1.2176 +        return false;
  1.2177 +
  1.2178 +    if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
  1.2179 +        return false;
  1.2180 +
  1.2181 +    if (!leaveFunction(pn, outerpc, kind))
  1.2182 +        return false;
  1.2183 +
  1.2184 +    pn->pn_blockid = outerpc->blockid();
  1.2185 +
  1.2186 +    /*
  1.2187 +     * Fruit of the poisonous tree: if a closure contains a dynamic name access
  1.2188 +     * (eval, with, etc), we consider the parent to do the same. The reason is
  1.2189 +     * that the deoptimizing effects of dynamic name access apply equally to
  1.2190 +     * parents: any local can be read at runtime.
  1.2191 +     */
  1.2192 +    PropagateTransitiveParseFlags(funbox, outerpc->sc);
  1.2193 +    return true;
  1.2194 +}
  1.2195 +
  1.2196 +template <>
  1.2197 +bool
  1.2198 +Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun,
  1.2199 +                                                FunctionType type, FunctionSyntaxKind kind,
  1.2200 +                                                GeneratorKind generatorKind,
  1.2201 +                                                Directives inheritedDirectives,
  1.2202 +                                                Directives *newDirectives)
  1.2203 +{
  1.2204 +    ParseContext<SyntaxParseHandler> *outerpc = pc;
  1.2205 +
  1.2206 +    // Create box for fun->object early to protect against last-ditch GC.
  1.2207 +    FunctionBox *funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
  1.2208 +    if (!funbox)
  1.2209 +        return false;
  1.2210 +
  1.2211 +    // Initialize early for possible flags mutation via destructuringExpr.
  1.2212 +    ParseContext<SyntaxParseHandler> funpc(this, pc, handler.null(), funbox, newDirectives,
  1.2213 +                                           outerpc->staticLevel + 1, outerpc->blockidGen,
  1.2214 +                                           /* blockScopeDepth = */ 0);
  1.2215 +    if (!funpc.init(tokenStream))
  1.2216 +        return false;
  1.2217 +
  1.2218 +    if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
  1.2219 +        return false;
  1.2220 +
  1.2221 +    if (!leaveFunction(pn, outerpc, kind))
  1.2222 +        return false;
  1.2223 +
  1.2224 +    // This is a lazy function inner to another lazy function. Remember the
  1.2225 +    // inner function so that if the outer function is eventually parsed we do
  1.2226 +    // not need any further parsing or processing of the inner function.
  1.2227 +    JS_ASSERT(fun->lazyScript());
  1.2228 +    return outerpc->innerFunctions.append(fun);
  1.2229 +}
  1.2230 +
  1.2231 +template <>
  1.2232 +ParseNode *
  1.2233 +Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, unsigned staticLevel,
  1.2234 +                                                 bool strict, GeneratorKind generatorKind)
  1.2235 +{
  1.2236 +    Node pn = handler.newFunctionDefinition();
  1.2237 +    if (!pn)
  1.2238 +        return null();
  1.2239 +
  1.2240 +    Directives directives(/* strict = */ strict);
  1.2241 +    FunctionBox *funbox = newFunctionBox(pn, fun, /* outerpc = */ nullptr, directives,
  1.2242 +                                         generatorKind);
  1.2243 +    if (!funbox)
  1.2244 +        return null();
  1.2245 +    funbox->length = fun->nargs() - fun->hasRest();
  1.2246 +
  1.2247 +    Directives newDirectives = directives;
  1.2248 +    ParseContext<FullParseHandler> funpc(this, /* parent = */ nullptr, pn, funbox,
  1.2249 +                                         &newDirectives, staticLevel, /* bodyid = */ 0,
  1.2250 +                                         /* blockScopeDepth = */ 0);
  1.2251 +    if (!funpc.init(tokenStream))
  1.2252 +        return null();
  1.2253 +
  1.2254 +    if (!functionArgsAndBodyGeneric(pn, fun, Normal, Statement, &newDirectives)) {
  1.2255 +        JS_ASSERT(directives == newDirectives);
  1.2256 +        return null();
  1.2257 +    }
  1.2258 +
  1.2259 +    if (fun->isNamedLambda()) {
  1.2260 +        if (AtomDefnPtr p = pc->lexdeps->lookup(fun->name())) {
  1.2261 +            Definition *dn = p.value().get<FullParseHandler>();
  1.2262 +            if (!ConvertDefinitionToNamedLambdaUse(tokenStream, pc, funbox, dn))
  1.2263 +                return nullptr;
  1.2264 +        }
  1.2265 +    }
  1.2266 +
  1.2267 +    InternalHandle<Bindings*> bindings =
  1.2268 +        InternalHandle<Bindings*>::fromMarkedLocation(&funbox->bindings);
  1.2269 +    if (!pc->generateFunctionBindings(context, tokenStream, alloc, bindings))
  1.2270 +        return null();
  1.2271 +
  1.2272 +    if (!FoldConstants(context, &pn, this))
  1.2273 +        return null();
  1.2274 +
  1.2275 +    return pn;
  1.2276 +}
  1.2277 +
  1.2278 +template <typename ParseHandler>
  1.2279 +bool
  1.2280 +Parser<ParseHandler>::functionArgsAndBodyGeneric(Node pn, HandleFunction fun, FunctionType type,
  1.2281 +                                                 FunctionSyntaxKind kind,
  1.2282 +                                                 Directives *newDirectives)
  1.2283 +{
  1.2284 +    // Given a properly initialized parse context, try to parse an actual
  1.2285 +    // function without concern for conversion to strict mode, use of lazy
  1.2286 +    // parsing and such.
  1.2287 +
  1.2288 +    Node prelude = null();
  1.2289 +    bool hasRest;
  1.2290 +    if (!functionArguments(kind, &prelude, pn, &hasRest))
  1.2291 +        return false;
  1.2292 +
  1.2293 +    FunctionBox *funbox = pc->sc->asFunctionBox();
  1.2294 +
  1.2295 +    fun->setArgCount(pc->numArgs());
  1.2296 +    if (hasRest)
  1.2297 +        fun->setHasRest();
  1.2298 +
  1.2299 +    if (type == Getter && fun->nargs() > 0) {
  1.2300 +        report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s");
  1.2301 +        return false;
  1.2302 +    }
  1.2303 +    if (type == Setter && fun->nargs() != 1) {
  1.2304 +        report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
  1.2305 +        return false;
  1.2306 +    }
  1.2307 +
  1.2308 +    if (kind == Arrow && !tokenStream.matchToken(TOK_ARROW)) {
  1.2309 +        report(ParseError, false, null(), JSMSG_BAD_ARROW_ARGS);
  1.2310 +        return false;
  1.2311 +    }
  1.2312 +
  1.2313 +    // Parse the function body.
  1.2314 +    FunctionBodyType bodyType = StatementListBody;
  1.2315 +    if (tokenStream.getToken(TokenStream::Operand) != TOK_LC) {
  1.2316 +        if (funbox->isStarGenerator()) {
  1.2317 +            report(ParseError, false, null(), JSMSG_CURLY_BEFORE_BODY);
  1.2318 +            return false;
  1.2319 +        }
  1.2320 +        tokenStream.ungetToken();
  1.2321 +        bodyType = ExpressionBody;
  1.2322 +        fun->setIsExprClosure();
  1.2323 +    }
  1.2324 +
  1.2325 +    Node body = functionBody(kind, bodyType);
  1.2326 +    if (!body)
  1.2327 +        return false;
  1.2328 +
  1.2329 +    if (fun->name() && !checkStrictBinding(fun->name(), pn))
  1.2330 +        return false;
  1.2331 +
  1.2332 +#if JS_HAS_EXPR_CLOSURES
  1.2333 +    if (bodyType == StatementListBody) {
  1.2334 +#endif
  1.2335 +        if (!tokenStream.matchToken(TOK_RC)) {
  1.2336 +            report(ParseError, false, null(), JSMSG_CURLY_AFTER_BODY);
  1.2337 +            return false;
  1.2338 +        }
  1.2339 +        funbox->bufEnd = pos().begin + 1;
  1.2340 +#if JS_HAS_EXPR_CLOSURES
  1.2341 +    } else {
  1.2342 +        if (tokenStream.hadError())
  1.2343 +            return false;
  1.2344 +        funbox->bufEnd = pos().end;
  1.2345 +        if (kind == Statement && !MatchOrInsertSemicolon(tokenStream))
  1.2346 +            return false;
  1.2347 +    }
  1.2348 +#endif
  1.2349 +
  1.2350 +    return finishFunctionDefinition(pn, funbox, prelude, body);
  1.2351 +}
  1.2352 +
  1.2353 +template <typename ParseHandler>
  1.2354 +bool
  1.2355 +Parser<ParseHandler>::checkYieldNameValidity()
  1.2356 +{
  1.2357 +    // In star generators and in JS >= 1.7, yield is a keyword.  Otherwise in
  1.2358 +    // strict mode, yield is a future reserved word.
  1.2359 +    if (pc->isStarGenerator() || versionNumber() >= JSVERSION_1_7 || pc->sc->strict) {
  1.2360 +        report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield");
  1.2361 +        return false;
  1.2362 +    }
  1.2363 +    return true;
  1.2364 +}
  1.2365 +
  1.2366 +template <typename ParseHandler>
  1.2367 +typename ParseHandler::Node
  1.2368 +Parser<ParseHandler>::functionStmt()
  1.2369 +{
  1.2370 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
  1.2371 +
  1.2372 +    TokenStream::Position start(keepAtoms);
  1.2373 +    tokenStream.tell(&start);
  1.2374 +
  1.2375 +    RootedPropertyName name(context);
  1.2376 +    GeneratorKind generatorKind = NotGenerator;
  1.2377 +    TokenKind tt = tokenStream.getToken();
  1.2378 +
  1.2379 +    if (tt == TOK_MUL) {
  1.2380 +        tokenStream.tell(&start);
  1.2381 +        tt = tokenStream.getToken();
  1.2382 +        generatorKind = StarGenerator;
  1.2383 +    }
  1.2384 +
  1.2385 +    if (tt == TOK_NAME) {
  1.2386 +        name = tokenStream.currentName();
  1.2387 +    } else if (tt == TOK_YIELD) {
  1.2388 +        if (!checkYieldNameValidity())
  1.2389 +            return null();
  1.2390 +        name = tokenStream.currentName();
  1.2391 +    } else {
  1.2392 +        /* Unnamed function expressions are forbidden in statement context. */
  1.2393 +        report(ParseError, false, null(), JSMSG_UNNAMED_FUNCTION_STMT);
  1.2394 +        return null();
  1.2395 +    }
  1.2396 +
  1.2397 +    /* We forbid function statements in strict mode code. */
  1.2398 +    if (!pc->atBodyLevel() && pc->sc->needStrictChecks() &&
  1.2399 +        !report(ParseStrictError, pc->sc->strict, null(), JSMSG_STRICT_FUNCTION_STATEMENT))
  1.2400 +        return null();
  1.2401 +
  1.2402 +    return functionDef(name, start, Normal, Statement, generatorKind);
  1.2403 +}
  1.2404 +
  1.2405 +template <typename ParseHandler>
  1.2406 +typename ParseHandler::Node
  1.2407 +Parser<ParseHandler>::functionExpr()
  1.2408 +{
  1.2409 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
  1.2410 +
  1.2411 +    TokenStream::Position start(keepAtoms);
  1.2412 +    tokenStream.tell(&start);
  1.2413 +
  1.2414 +    GeneratorKind generatorKind = NotGenerator;
  1.2415 +    TokenKind tt = tokenStream.getToken();
  1.2416 +
  1.2417 +    if (tt == TOK_MUL) {
  1.2418 +        tokenStream.tell(&start);
  1.2419 +        tt = tokenStream.getToken();
  1.2420 +        generatorKind = StarGenerator;
  1.2421 +    }
  1.2422 +
  1.2423 +    RootedPropertyName name(context);
  1.2424 +    if (tt == TOK_NAME) {
  1.2425 +        name = tokenStream.currentName();
  1.2426 +    } else if (tt == TOK_YIELD) {
  1.2427 +        if (!checkYieldNameValidity())
  1.2428 +            return null();
  1.2429 +        name = tokenStream.currentName();
  1.2430 +    } else {
  1.2431 +        tokenStream.ungetToken();
  1.2432 +    }
  1.2433 +
  1.2434 +    return functionDef(name, start, Normal, Expression, generatorKind);
  1.2435 +}
  1.2436 +
  1.2437 +/*
  1.2438 + * Return true if this node, known to be an unparenthesized string literal,
  1.2439 + * could be the string of a directive in a Directive Prologue. Directive
  1.2440 + * strings never contain escape sequences or line continuations.
  1.2441 + * isEscapeFreeStringLiteral, below, checks whether the node itself could be
  1.2442 + * a directive.
  1.2443 + */
  1.2444 +static inline bool
  1.2445 +IsEscapeFreeStringLiteral(const TokenPos &pos, JSAtom *str)
  1.2446 +{
  1.2447 +    /*
  1.2448 +     * If the string's length in the source code is its length as a value,
  1.2449 +     * accounting for the quotes, then it must not contain any escape
  1.2450 +     * sequences or line continuations.
  1.2451 +     */
  1.2452 +    return pos.begin + str->length() + 2 == pos.end;
  1.2453 +}
  1.2454 +
  1.2455 +template <>
  1.2456 +bool
  1.2457 +Parser<SyntaxParseHandler>::asmJS(Node list)
  1.2458 +{
  1.2459 +    // While asm.js could technically be validated and compiled during syntax
  1.2460 +    // parsing, we have no guarantee that some later JS wouldn't abort the
  1.2461 +    // syntax parse and cause us to re-parse (and re-compile) the asm.js module.
  1.2462 +    // For simplicity, unconditionally abort the syntax parse when "use asm" is
  1.2463 +    // encountered so that asm.js is always validated/compiled exactly once
  1.2464 +    // during a full parse.
  1.2465 +    JS_ALWAYS_FALSE(abortIfSyntaxParser());
  1.2466 +    return false;
  1.2467 +}
  1.2468 +
  1.2469 +template <>
  1.2470 +bool
  1.2471 +Parser<FullParseHandler>::asmJS(Node list)
  1.2472 +{
  1.2473 +    // If we are already inside "use asm" that means we are either actively
  1.2474 +    // compiling or we are reparsing after asm.js validation failure. In either
  1.2475 +    // case, nothing to do here.
  1.2476 +    if (pc->useAsmOrInsideUseAsm())
  1.2477 +        return true;
  1.2478 +
  1.2479 +    // If there is no ScriptSource, then we are doing a non-compiling parse and
  1.2480 +    // so we shouldn't (and can't, without a ScriptSource) compile.
  1.2481 +    if (ss == nullptr)
  1.2482 +        return true;
  1.2483 +
  1.2484 +    pc->sc->asFunctionBox()->useAsm = true;
  1.2485 +
  1.2486 +#ifdef JS_ION
  1.2487 +    // Attempt to validate and compile this asm.js module. On success, the
  1.2488 +    // tokenStream has been advanced to the closing }. On failure, the
  1.2489 +    // tokenStream is in an indeterminate state and we must reparse the
  1.2490 +    // function from the beginning. Reparsing is triggered by marking that a
  1.2491 +    // new directive has been encountered and returning 'false'.
  1.2492 +    bool validated;
  1.2493 +    if (!CompileAsmJS(context, *this, list, &validated))
  1.2494 +        return false;
  1.2495 +    if (!validated) {
  1.2496 +        pc->newDirectives->setAsmJS();
  1.2497 +        return false;
  1.2498 +    }
  1.2499 +#endif
  1.2500 +
  1.2501 +    return true;
  1.2502 +}
  1.2503 +
  1.2504 +/*
  1.2505 + * Recognize Directive Prologue members and directives. Assuming |pn| is a
  1.2506 + * candidate for membership in a directive prologue, recognize directives and
  1.2507 + * set |pc|'s flags accordingly. If |pn| is indeed part of a prologue, set its
  1.2508 + * |pn_prologue| flag.
  1.2509 + *
  1.2510 + * Note that the following is a strict mode function:
  1.2511 + *
  1.2512 + * function foo() {
  1.2513 + *   "blah" // inserted semi colon
  1.2514 + *        "blurgh"
  1.2515 + *   "use\x20loose"
  1.2516 + *   "use strict"
  1.2517 + * }
  1.2518 + *
  1.2519 + * That is, even though "use\x20loose" can never be a directive, now or in the
  1.2520 + * future (because of the hex escape), the Directive Prologue extends through it
  1.2521 + * to the "use strict" statement, which is indeed a directive.
  1.2522 + */
  1.2523 +template <typename ParseHandler>
  1.2524 +bool
  1.2525 +Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool *cont)
  1.2526 +{
  1.2527 +    TokenPos directivePos;
  1.2528 +    JSAtom *directive = handler.isStringExprStatement(pn, &directivePos);
  1.2529 +
  1.2530 +    *cont = !!directive;
  1.2531 +    if (!*cont)
  1.2532 +        return true;
  1.2533 +
  1.2534 +    if (IsEscapeFreeStringLiteral(directivePos, directive)) {
  1.2535 +        // Mark this statement as being a possibly legitimate part of a
  1.2536 +        // directive prologue, so the bytecode emitter won't warn about it being
  1.2537 +        // useless code. (We mustn't just omit the statement entirely yet, as it
  1.2538 +        // could be producing the value of an eval or JSScript execution.)
  1.2539 +        //
  1.2540 +        // Note that even if the string isn't one we recognize as a directive,
  1.2541 +        // the emitter still shouldn't flag it as useless, as it could become a
  1.2542 +        // directive in the future. We don't want to interfere with people
  1.2543 +        // taking advantage of directive-prologue-enabled features that appear
  1.2544 +        // in other browsers first.
  1.2545 +        handler.setPrologue(pn);
  1.2546 +
  1.2547 +        if (directive == context->names().useStrict) {
  1.2548 +            // We're going to be in strict mode. Note that this scope explicitly
  1.2549 +            // had "use strict";
  1.2550 +            pc->sc->setExplicitUseStrict();
  1.2551 +            if (!pc->sc->strict) {
  1.2552 +                if (pc->sc->isFunctionBox()) {
  1.2553 +                    // Request that this function be reparsed as strict.
  1.2554 +                    pc->newDirectives->setStrict();
  1.2555 +                    return false;
  1.2556 +                } else {
  1.2557 +                    // We don't reparse global scopes, so we keep track of the
  1.2558 +                    // one possible strict violation that could occur in the
  1.2559 +                    // directive prologue -- octal escapes -- and complain now.
  1.2560 +                    if (tokenStream.sawOctalEscape()) {
  1.2561 +                        report(ParseError, false, null(), JSMSG_DEPRECATED_OCTAL);
  1.2562 +                        return false;
  1.2563 +                    }
  1.2564 +                    pc->sc->strict = true;
  1.2565 +                }
  1.2566 +            }
  1.2567 +        } else if (directive == context->names().useAsm) {
  1.2568 +            if (pc->sc->isFunctionBox())
  1.2569 +                return asmJS(list);
  1.2570 +            return report(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL);
  1.2571 +        }
  1.2572 +    }
  1.2573 +    return true;
  1.2574 +}
  1.2575 +
  1.2576 +/*
  1.2577 + * Parse the statements in a block, creating a StatementList node that lists
  1.2578 + * the statements.  If called from block-parsing code, the caller must match
  1.2579 + * '{' before and '}' after.
  1.2580 + */
  1.2581 +template <typename ParseHandler>
  1.2582 +typename ParseHandler::Node
  1.2583 +Parser<ParseHandler>::statements()
  1.2584 +{
  1.2585 +    JS_CHECK_RECURSION(context, return null());
  1.2586 +
  1.2587 +    Node pn = handler.newStatementList(pc->blockid(), pos());
  1.2588 +    if (!pn)
  1.2589 +        return null();
  1.2590 +
  1.2591 +    Node saveBlock = pc->blockNode;
  1.2592 +    pc->blockNode = pn;
  1.2593 +
  1.2594 +    bool canHaveDirectives = pc->atBodyLevel();
  1.2595 +    for (;;) {
  1.2596 +        TokenKind tt = tokenStream.peekToken(TokenStream::Operand);
  1.2597 +        if (tt <= TOK_EOF || tt == TOK_RC) {
  1.2598 +            if (tt == TOK_ERROR) {
  1.2599 +                if (tokenStream.isEOF())
  1.2600 +                    isUnexpectedEOF_ = true;
  1.2601 +                return null();
  1.2602 +            }
  1.2603 +            break;
  1.2604 +        }
  1.2605 +        Node next = statement(canHaveDirectives);
  1.2606 +        if (!next) {
  1.2607 +            if (tokenStream.isEOF())
  1.2608 +                isUnexpectedEOF_ = true;
  1.2609 +            return null();
  1.2610 +        }
  1.2611 +
  1.2612 +        if (canHaveDirectives) {
  1.2613 +            if (!maybeParseDirective(pn, next, &canHaveDirectives))
  1.2614 +                return null();
  1.2615 +        }
  1.2616 +
  1.2617 +        handler.addStatementToList(pn, next, pc);
  1.2618 +    }
  1.2619 +
  1.2620 +    /*
  1.2621 +     * Handle the case where there was a let declaration under this block.  If
  1.2622 +     * it replaced pc->blockNode with a new block node then we must refresh pn
  1.2623 +     * and then restore pc->blockNode.
  1.2624 +     */
  1.2625 +    if (pc->blockNode != pn)
  1.2626 +        pn = pc->blockNode;
  1.2627 +    pc->blockNode = saveBlock;
  1.2628 +    return pn;
  1.2629 +}
  1.2630 +
  1.2631 +template <typename ParseHandler>
  1.2632 +typename ParseHandler::Node
  1.2633 +Parser<ParseHandler>::condition()
  1.2634 +{
  1.2635 +    MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
  1.2636 +    Node pn = exprInParens();
  1.2637 +    if (!pn)
  1.2638 +        return null();
  1.2639 +    MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
  1.2640 +
  1.2641 +    /* Check for (a = b) and warn about possible (a == b) mistype. */
  1.2642 +    if (handler.isOperationWithoutParens(pn, PNK_ASSIGN) &&
  1.2643 +        !report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
  1.2644 +    {
  1.2645 +        return null();
  1.2646 +    }
  1.2647 +    return pn;
  1.2648 +}
  1.2649 +
  1.2650 +template <typename ParseHandler>
  1.2651 +bool
  1.2652 +Parser<ParseHandler>::matchLabel(MutableHandle<PropertyName*> label)
  1.2653 +{
  1.2654 +    TokenKind tt = tokenStream.peekTokenSameLine(TokenStream::Operand);
  1.2655 +    if (tt == TOK_ERROR)
  1.2656 +        return false;
  1.2657 +    if (tt == TOK_NAME) {
  1.2658 +        tokenStream.consumeKnownToken(TOK_NAME);
  1.2659 +        label.set(tokenStream.currentName());
  1.2660 +    } else if (tt == TOK_YIELD) {
  1.2661 +        tokenStream.consumeKnownToken(TOK_YIELD);
  1.2662 +        if (!checkYieldNameValidity())
  1.2663 +            return false;
  1.2664 +        label.set(tokenStream.currentName());
  1.2665 +    } else {
  1.2666 +        label.set(nullptr);
  1.2667 +    }
  1.2668 +    return true;
  1.2669 +}
  1.2670 +
  1.2671 +template <typename ParseHandler>
  1.2672 +bool
  1.2673 +Parser<ParseHandler>::reportRedeclaration(Node pn, bool isConst, JSAtom *atom)
  1.2674 +{
  1.2675 +    JSAutoByteString name;
  1.2676 +    if (AtomToPrintableString(context, atom, &name))
  1.2677 +        report(ParseError, false, pn, JSMSG_REDECLARED_VAR, isConst ? "const" : "variable", name.ptr());
  1.2678 +    return false;
  1.2679 +}
  1.2680 +
  1.2681 +/*
  1.2682 + * Define a let-variable in a block, let-expression, or comprehension scope. pc
  1.2683 + * must already be in such a scope.
  1.2684 + *
  1.2685 + * Throw a SyntaxError if 'atom' is an invalid name. Otherwise create a
  1.2686 + * property for the new variable on the block object, pc->staticScope;
  1.2687 + * populate data->pn->pn_{op,cookie,defn,dflags}; and stash a pointer to
  1.2688 + * data->pn in a slot of the block object.
  1.2689 + */
  1.2690 +template <>
  1.2691 +/* static */ bool
  1.2692 +Parser<FullParseHandler>::bindLet(BindData<FullParseHandler> *data,
  1.2693 +                                  HandlePropertyName name, Parser<FullParseHandler> *parser)
  1.2694 +{
  1.2695 +    ParseContext<FullParseHandler> *pc = parser->pc;
  1.2696 +    ParseNode *pn = data->pn;
  1.2697 +    if (!parser->checkStrictBinding(name, pn))
  1.2698 +        return false;
  1.2699 +
  1.2700 +    ExclusiveContext *cx = parser->context;
  1.2701 +
  1.2702 +    Rooted<StaticBlockObject *> blockObj(cx, data->let.blockObj);
  1.2703 +    unsigned index = blockObj->numVariables();
  1.2704 +    if (index >= StaticBlockObject::LOCAL_INDEX_LIMIT) {
  1.2705 +        parser->report(ParseError, false, pn, data->let.overflow);
  1.2706 +        return false;
  1.2707 +    }
  1.2708 +
  1.2709 +    /*
  1.2710 +     * Assign block-local index to pn->pn_cookie right away, encoding it as an
  1.2711 +     * upvar cookie whose skip tells the current static level. The emitter will
  1.2712 +     * adjust the node's slot based on its stack depth model -- and, for global
  1.2713 +     * and eval code, js::frontend::CompileScript will adjust the slot
  1.2714 +     * again to include script->nfixed.
  1.2715 +     */
  1.2716 +    if (!pn->pn_cookie.set(parser->tokenStream, pc->staticLevel, index))
  1.2717 +        return false;
  1.2718 +
  1.2719 +    /*
  1.2720 +     * For bindings that are hoisted to the beginning of the block/function,
  1.2721 +     * define() right now. Otherwise, delay define until PushLetScope.
  1.2722 +     */
  1.2723 +    if (data->let.varContext == HoistVars) {
  1.2724 +        JS_ASSERT(!pc->atBodyLevel());
  1.2725 +        Definition *dn = pc->decls().lookupFirst(name);
  1.2726 +        if (dn && dn->pn_blockid == pc->blockid())
  1.2727 +            return parser->reportRedeclaration(pn, dn->isConst(), name);
  1.2728 +        if (!pc->define(parser->tokenStream, name, pn, Definition::LET))
  1.2729 +            return false;
  1.2730 +    }
  1.2731 +
  1.2732 +    bool redeclared;
  1.2733 +    RootedId id(cx, NameToId(name));
  1.2734 +    RootedShape shape(cx, StaticBlockObject::addVar(cx, blockObj, id, index, &redeclared));
  1.2735 +    if (!shape) {
  1.2736 +        if (redeclared)
  1.2737 +            parser->reportRedeclaration(pn, false, name);
  1.2738 +        return false;
  1.2739 +    }
  1.2740 +
  1.2741 +    /* Store pn in the static block object. */
  1.2742 +    blockObj->setDefinitionParseNode(index, reinterpret_cast<Definition *>(pn));
  1.2743 +    return true;
  1.2744 +}
  1.2745 +
  1.2746 +template <>
  1.2747 +/* static */ bool
  1.2748 +Parser<SyntaxParseHandler>::bindLet(BindData<SyntaxParseHandler> *data,
  1.2749 +                                    HandlePropertyName name, Parser<SyntaxParseHandler> *parser)
  1.2750 +{
  1.2751 +    if (!parser->checkStrictBinding(name, data->pn))
  1.2752 +        return false;
  1.2753 +
  1.2754 +    return true;
  1.2755 +}
  1.2756 +
  1.2757 +template <typename ParseHandler, class Op>
  1.2758 +static inline bool
  1.2759 +ForEachLetDef(TokenStream &ts, ParseContext<ParseHandler> *pc,
  1.2760 +              HandleStaticBlockObject blockObj, Op op)
  1.2761 +{
  1.2762 +    for (Shape::Range<CanGC> r(ts.context(), blockObj->lastProperty()); !r.empty(); r.popFront()) {
  1.2763 +        Shape &shape = r.front();
  1.2764 +
  1.2765 +        /* Beware the destructuring dummy slots. */
  1.2766 +        if (JSID_IS_INT(shape.propid()))
  1.2767 +            continue;
  1.2768 +
  1.2769 +        if (!op(ts, pc, blockObj, shape, JSID_TO_ATOM(shape.propid())))
  1.2770 +            return false;
  1.2771 +    }
  1.2772 +    return true;
  1.2773 +}
  1.2774 +
  1.2775 +template <typename ParseHandler>
  1.2776 +struct PopLetDecl {
  1.2777 +    bool operator()(TokenStream &, ParseContext<ParseHandler> *pc, HandleStaticBlockObject,
  1.2778 +                    const Shape &, JSAtom *atom)
  1.2779 +    {
  1.2780 +        pc->popLetDecl(atom);
  1.2781 +        return true;
  1.2782 +    }
  1.2783 +};
  1.2784 +
  1.2785 +// We compute the maximum block scope depth, in slots, of a compilation unit at
  1.2786 +// parse-time.  Each nested statement has a field indicating the maximum block
  1.2787 +// scope depth that is nested inside it.  When we leave a nested statement, we
  1.2788 +// add the number of slots in the statement to the nested depth, and use that to
  1.2789 +// update the maximum block scope depth of the outer statement or parse
  1.2790 +// context.  In the end, pc->blockScopeDepth will indicate the number of slots
  1.2791 +// to reserve in the fixed part of a stack frame.
  1.2792 +//
  1.2793 +template <typename ParseHandler>
  1.2794 +static void
  1.2795 +AccumulateBlockScopeDepth(ParseContext<ParseHandler> *pc)
  1.2796 +{
  1.2797 +    uint32_t innerDepth = pc->topStmt->innerBlockScopeDepth;
  1.2798 +    StmtInfoPC *outer = pc->topStmt->down;
  1.2799 +
  1.2800 +    if (pc->topStmt->isBlockScope)
  1.2801 +        innerDepth += pc->topStmt->staticScope->template as<StaticBlockObject>().numVariables();
  1.2802 +
  1.2803 +    if (outer) {
  1.2804 +        if (outer->innerBlockScopeDepth < innerDepth)
  1.2805 +            outer->innerBlockScopeDepth = innerDepth;
  1.2806 +    } else {
  1.2807 +        if (pc->blockScopeDepth < innerDepth)
  1.2808 +            pc->blockScopeDepth = innerDepth;
  1.2809 +    }
  1.2810 +}
  1.2811 +
  1.2812 +template <typename ParseHandler>
  1.2813 +static void
  1.2814 +PopStatementPC(TokenStream &ts, ParseContext<ParseHandler> *pc)
  1.2815 +{
  1.2816 +    RootedNestedScopeObject scopeObj(ts.context(), pc->topStmt->staticScope);
  1.2817 +    JS_ASSERT(!!scopeObj == pc->topStmt->isNestedScope);
  1.2818 +
  1.2819 +    AccumulateBlockScopeDepth(pc);
  1.2820 +    FinishPopStatement(pc);
  1.2821 +
  1.2822 +    if (scopeObj) {
  1.2823 +        if (scopeObj->is<StaticBlockObject>()) {
  1.2824 +            RootedStaticBlockObject blockObj(ts.context(), &scopeObj->as<StaticBlockObject>());
  1.2825 +            JS_ASSERT(!blockObj->inDictionaryMode());
  1.2826 +            ForEachLetDef(ts, pc, blockObj, PopLetDecl<ParseHandler>());
  1.2827 +        }
  1.2828 +        scopeObj->resetEnclosingNestedScopeFromParser();
  1.2829 +    }
  1.2830 +}
  1.2831 +
  1.2832 +/*
  1.2833 + * The function LexicalLookup searches a static binding for the given name in
  1.2834 + * the stack of statements enclosing the statement currently being parsed. Each
  1.2835 + * statement that introduces a new scope has a corresponding scope object, on
  1.2836 + * which the bindings for that scope are stored. LexicalLookup either returns
  1.2837 + * the innermost statement which has a scope object containing a binding with
  1.2838 + * the given name, or nullptr.
  1.2839 + */
  1.2840 +template <class ContextT>
  1.2841 +typename ContextT::StmtInfo *
  1.2842 +LexicalLookup(ContextT *ct, HandleAtom atom, int *slotp, typename ContextT::StmtInfo *stmt)
  1.2843 +{
  1.2844 +    RootedId id(ct->sc->context, AtomToId(atom));
  1.2845 +
  1.2846 +    if (!stmt)
  1.2847 +        stmt = ct->topScopeStmt;
  1.2848 +    for (; stmt; stmt = stmt->downScope) {
  1.2849 +        /*
  1.2850 +         * With-statements introduce dynamic bindings. Since dynamic bindings
  1.2851 +         * can potentially override any static bindings introduced by statements
  1.2852 +         * further up the stack, we have to abort the search.
  1.2853 +         */
  1.2854 +        if (stmt->type == STMT_WITH)
  1.2855 +            break;
  1.2856 +
  1.2857 +        // Skip statements that do not introduce a new scope
  1.2858 +        if (!stmt->isBlockScope)
  1.2859 +            continue;
  1.2860 +
  1.2861 +        StaticBlockObject &blockObj = stmt->staticBlock();
  1.2862 +        Shape *shape = blockObj.nativeLookup(ct->sc->context, id);
  1.2863 +        if (shape) {
  1.2864 +            if (slotp)
  1.2865 +                *slotp = blockObj.shapeToIndex(*shape);
  1.2866 +            return stmt;
  1.2867 +        }
  1.2868 +    }
  1.2869 +
  1.2870 +    if (slotp)
  1.2871 +        *slotp = -1;
  1.2872 +    return stmt;
  1.2873 +}
  1.2874 +
  1.2875 +template <typename ParseHandler>
  1.2876 +static inline bool
  1.2877 +OuterLet(ParseContext<ParseHandler> *pc, StmtInfoPC *stmt, HandleAtom atom)
  1.2878 +{
  1.2879 +    while (stmt->downScope) {
  1.2880 +        stmt = LexicalLookup(pc, atom, nullptr, stmt->downScope);
  1.2881 +        if (!stmt)
  1.2882 +            return false;
  1.2883 +        if (stmt->type == STMT_BLOCK)
  1.2884 +            return true;
  1.2885 +    }
  1.2886 +    return false;
  1.2887 +}
  1.2888 +
  1.2889 +template <typename ParseHandler>
  1.2890 +/* static */ bool
  1.2891 +Parser<ParseHandler>::bindVarOrConst(BindData<ParseHandler> *data,
  1.2892 +                                     HandlePropertyName name, Parser<ParseHandler> *parser)
  1.2893 +{
  1.2894 +    ExclusiveContext *cx = parser->context;
  1.2895 +    ParseContext<ParseHandler> *pc = parser->pc;
  1.2896 +    Node pn = data->pn;
  1.2897 +    bool isConstDecl = data->op == JSOP_DEFCONST;
  1.2898 +
  1.2899 +    /* Default best op for pn is JSOP_NAME; we'll try to improve below. */
  1.2900 +    parser->handler.setOp(pn, JSOP_NAME);
  1.2901 +
  1.2902 +    if (!parser->checkStrictBinding(name, pn))
  1.2903 +        return false;
  1.2904 +
  1.2905 +    StmtInfoPC *stmt = LexicalLookup(pc, name, nullptr, (StmtInfoPC *)nullptr);
  1.2906 +
  1.2907 +    if (stmt && stmt->type == STMT_WITH) {
  1.2908 +        parser->handler.setFlag(pn, PND_DEOPTIMIZED);
  1.2909 +        if (pc->sc->isFunctionBox()) {
  1.2910 +            FunctionBox *funbox = pc->sc->asFunctionBox();
  1.2911 +            funbox->setMightAliasLocals();
  1.2912 +        }
  1.2913 +
  1.2914 +        /*
  1.2915 +         * This definition isn't being added to the parse context's
  1.2916 +         * declarations, so make sure to indicate the need to deoptimize
  1.2917 +         * the script's arguments object. Mark the function as if it
  1.2918 +         * contained a debugger statement, which will deoptimize arguments
  1.2919 +         * as much as possible.
  1.2920 +         */
  1.2921 +        if (name == cx->names().arguments)
  1.2922 +            pc->sc->setHasDebuggerStatement();
  1.2923 +
  1.2924 +        return true;
  1.2925 +    }
  1.2926 +
  1.2927 +    DefinitionList::Range defs = pc->decls().lookupMulti(name);
  1.2928 +    JS_ASSERT_IF(stmt, !defs.empty());
  1.2929 +
  1.2930 +    if (defs.empty()) {
  1.2931 +        return pc->define(parser->tokenStream, name, pn,
  1.2932 +                          isConstDecl ? Definition::CONST : Definition::VAR);
  1.2933 +    }
  1.2934 +
  1.2935 +    /*
  1.2936 +     * There was a previous declaration with the same name. The standard
  1.2937 +     * disallows several forms of redeclaration. Critically,
  1.2938 +     *   let (x) { var x; } // error
  1.2939 +     * is not allowed which allows us to turn any non-error redeclaration
  1.2940 +     * into a use of the initial declaration.
  1.2941 +     */
  1.2942 +    DefinitionNode dn = defs.front<ParseHandler>();
  1.2943 +    Definition::Kind dn_kind = parser->handler.getDefinitionKind(dn);
  1.2944 +    if (dn_kind == Definition::ARG) {
  1.2945 +        JSAutoByteString bytes;
  1.2946 +        if (!AtomToPrintableString(cx, name, &bytes))
  1.2947 +            return false;
  1.2948 +
  1.2949 +        if (isConstDecl) {
  1.2950 +            parser->report(ParseError, false, pn, JSMSG_REDECLARED_PARAM, bytes.ptr());
  1.2951 +            return false;
  1.2952 +        }
  1.2953 +        if (!parser->report(ParseExtraWarning, false, pn, JSMSG_VAR_HIDES_ARG, bytes.ptr()))
  1.2954 +            return false;
  1.2955 +    } else {
  1.2956 +        bool error = (isConstDecl ||
  1.2957 +                      dn_kind == Definition::CONST ||
  1.2958 +                      (dn_kind == Definition::LET &&
  1.2959 +                       (stmt->type != STMT_CATCH || OuterLet(pc, stmt, name))));
  1.2960 +
  1.2961 +        if (parser->options().extraWarningsOption
  1.2962 +            ? data->op != JSOP_DEFVAR || dn_kind != Definition::VAR
  1.2963 +            : error)
  1.2964 +        {
  1.2965 +            JSAutoByteString bytes;
  1.2966 +            ParseReportKind reporter = error ? ParseError : ParseExtraWarning;
  1.2967 +            if (!AtomToPrintableString(cx, name, &bytes) ||
  1.2968 +                !parser->report(reporter, false, pn, JSMSG_REDECLARED_VAR,
  1.2969 +                                Definition::kindString(dn_kind), bytes.ptr()))
  1.2970 +            {
  1.2971 +                return false;
  1.2972 +            }
  1.2973 +        }
  1.2974 +    }
  1.2975 +
  1.2976 +    parser->handler.linkUseToDef(pn, dn);
  1.2977 +    return true;
  1.2978 +}
  1.2979 +
  1.2980 +template <>
  1.2981 +bool
  1.2982 +Parser<FullParseHandler>::makeSetCall(ParseNode *pn, unsigned msg)
  1.2983 +{
  1.2984 +    JS_ASSERT(pn->isKind(PNK_CALL));
  1.2985 +    JS_ASSERT(pn->isArity(PN_LIST));
  1.2986 +    JS_ASSERT(pn->isOp(JSOP_CALL) || pn->isOp(JSOP_SPREADCALL) ||
  1.2987 +              pn->isOp(JSOP_EVAL) || pn->isOp(JSOP_SPREADEVAL) ||
  1.2988 +              pn->isOp(JSOP_FUNCALL) || pn->isOp(JSOP_FUNAPPLY));
  1.2989 +
  1.2990 +    if (!report(ParseStrictError, pc->sc->strict, pn, msg))
  1.2991 +        return false;
  1.2992 +    handler.markAsSetCall(pn);
  1.2993 +    return true;
  1.2994 +}
  1.2995 +
  1.2996 +template <typename ParseHandler>
  1.2997 +bool
  1.2998 +Parser<ParseHandler>::noteNameUse(HandlePropertyName name, Node pn)
  1.2999 +{
  1.3000 +    StmtInfoPC *stmt = LexicalLookup(pc, name, nullptr, (StmtInfoPC *)nullptr);
  1.3001 +
  1.3002 +    DefinitionList::Range defs = pc->decls().lookupMulti(name);
  1.3003 +
  1.3004 +    DefinitionNode dn;
  1.3005 +    if (!defs.empty()) {
  1.3006 +        dn = defs.front<ParseHandler>();
  1.3007 +    } else {
  1.3008 +        /*
  1.3009 +         * No definition before this use in any lexical scope.
  1.3010 +         * Create a placeholder definition node to either:
  1.3011 +         * - Be adopted when we parse the real defining
  1.3012 +         *   declaration, or
  1.3013 +         * - Be left as a free variable definition if we never
  1.3014 +         *   see the real definition.
  1.3015 +         */
  1.3016 +        dn = getOrCreateLexicalDependency(pc, name);
  1.3017 +        if (!dn)
  1.3018 +            return false;
  1.3019 +    }
  1.3020 +
  1.3021 +    handler.linkUseToDef(pn, dn);
  1.3022 +
  1.3023 +    if (stmt && stmt->type == STMT_WITH)
  1.3024 +        handler.setFlag(pn, PND_DEOPTIMIZED);
  1.3025 +
  1.3026 +    return true;
  1.3027 +}
  1.3028 +
  1.3029 +template <>
  1.3030 +bool
  1.3031 +Parser<FullParseHandler>::bindDestructuringVar(BindData<FullParseHandler> *data, ParseNode *pn)
  1.3032 +{
  1.3033 +    JS_ASSERT(pn->isKind(PNK_NAME));
  1.3034 +
  1.3035 +    RootedPropertyName name(context, pn->pn_atom->asPropertyName());
  1.3036 +
  1.3037 +    data->pn = pn;
  1.3038 +    if (!data->binder(data, name, this))
  1.3039 +        return false;
  1.3040 +
  1.3041 +    /*
  1.3042 +     * Select the appropriate name-setting opcode, respecting eager selection
  1.3043 +     * done by the data->binder function.
  1.3044 +     */
  1.3045 +    if (pn->pn_dflags & PND_BOUND)
  1.3046 +        pn->setOp(JSOP_SETLOCAL);
  1.3047 +    else if (data->op == JSOP_DEFCONST)
  1.3048 +        pn->setOp(JSOP_SETCONST);
  1.3049 +    else
  1.3050 +        pn->setOp(JSOP_SETNAME);
  1.3051 +
  1.3052 +    if (data->op == JSOP_DEFCONST)
  1.3053 +        pn->pn_dflags |= PND_CONST;
  1.3054 +
  1.3055 +    pn->markAsAssigned();
  1.3056 +    return true;
  1.3057 +}
  1.3058 +
  1.3059 +/*
  1.3060 + * Destructuring patterns can appear in two kinds of contexts:
  1.3061 + *
  1.3062 + * - assignment-like: assignment expressions and |for| loop heads.  In
  1.3063 + *   these cases, the patterns' property value positions can be
  1.3064 + *   arbitrary lvalue expressions; the destructuring is just a fancy
  1.3065 + *   assignment.
  1.3066 + *
  1.3067 + * - declaration-like: |var| and |let| declarations, functions' formal
  1.3068 + *   parameter lists, |catch| clauses, and comprehension tails.  In
  1.3069 + *   these cases, the patterns' property value positions must be
  1.3070 + *   simple names; the destructuring defines them as new variables.
  1.3071 + *
  1.3072 + * In both cases, other code parses the pattern as an arbitrary
  1.3073 + * primaryExpr, and then, here in CheckDestructuring, verify that the
  1.3074 + * tree is a valid destructuring expression.
  1.3075 + *
  1.3076 + * In assignment-like contexts, we parse the pattern with
  1.3077 + * pc->inDeclDestructuring clear, so the lvalue expressions in the
  1.3078 + * pattern are parsed normally.  primaryExpr links variable references
  1.3079 + * into the appropriate use chains; creates placeholder definitions;
  1.3080 + * and so on.  CheckDestructuring is called with |data| nullptr (since
  1.3081 + * we won't be binding any new names), and we specialize lvalues as
  1.3082 + * appropriate.
  1.3083 + *
  1.3084 + * In declaration-like contexts, the normal variable reference
  1.3085 + * processing would just be an obstruction, because we're going to
  1.3086 + * define the names that appear in the property value positions as new
  1.3087 + * variables anyway.  In this case, we parse the pattern with
  1.3088 + * pc->inDeclDestructuring set, which directs primaryExpr to leave
  1.3089 + * whatever name nodes it creates unconnected.  Then, here in
  1.3090 + * CheckDestructuring, we require the pattern's property value
  1.3091 + * positions to be simple names, and define them as appropriate to the
  1.3092 + * context.  For these calls, |data| points to the right sort of
  1.3093 + * BindData.
  1.3094 + *
  1.3095 + * The 'toplevel' is a private detail of the recursive strategy used by
  1.3096 + * CheckDestructuring and callers should use the default value.
  1.3097 + */
  1.3098 +template <>
  1.3099 +bool
  1.3100 +Parser<FullParseHandler>::checkDestructuring(BindData<FullParseHandler> *data,
  1.3101 +                                             ParseNode *left, bool toplevel)
  1.3102 +{
  1.3103 +    bool ok;
  1.3104 +
  1.3105 +    if (left->isKind(PNK_ARRAYCOMP)) {
  1.3106 +        report(ParseError, false, left, JSMSG_ARRAY_COMP_LEFTSIDE);
  1.3107 +        return false;
  1.3108 +    }
  1.3109 +
  1.3110 +    Rooted<StaticBlockObject *> blockObj(context);
  1.3111 +    blockObj = data && data->binder == bindLet ? data->let.blockObj.get() : nullptr;
  1.3112 +
  1.3113 +    if (left->isKind(PNK_ARRAY)) {
  1.3114 +        for (ParseNode *pn = left->pn_head; pn; pn = pn->pn_next) {
  1.3115 +            if (!pn->isKind(PNK_ELISION)) {
  1.3116 +                if (pn->isKind(PNK_ARRAY) || pn->isKind(PNK_OBJECT)) {
  1.3117 +                    ok = checkDestructuring(data, pn, false);
  1.3118 +                } else {
  1.3119 +                    if (data) {
  1.3120 +                        if (!pn->isKind(PNK_NAME)) {
  1.3121 +                            report(ParseError, false, pn, JSMSG_NO_VARIABLE_NAME);
  1.3122 +                            return false;
  1.3123 +                        }
  1.3124 +                        ok = bindDestructuringVar(data, pn);
  1.3125 +                    } else {
  1.3126 +                        ok = checkAndMarkAsAssignmentLhs(pn, KeyedDestructuringAssignment);
  1.3127 +                    }
  1.3128 +                }
  1.3129 +                if (!ok)
  1.3130 +                    return false;
  1.3131 +            }
  1.3132 +        }
  1.3133 +    } else {
  1.3134 +        JS_ASSERT(left->isKind(PNK_OBJECT));
  1.3135 +        for (ParseNode *member = left->pn_head; member; member = member->pn_next) {
  1.3136 +            MOZ_ASSERT(member->isKind(PNK_COLON));
  1.3137 +            ParseNode *expr = member->pn_right;
  1.3138 +
  1.3139 +            if (expr->isKind(PNK_ARRAY) || expr->isKind(PNK_OBJECT)) {
  1.3140 +                ok = checkDestructuring(data, expr, false);
  1.3141 +            } else if (data) {
  1.3142 +                if (!expr->isKind(PNK_NAME)) {
  1.3143 +                    report(ParseError, false, expr, JSMSG_NO_VARIABLE_NAME);
  1.3144 +                    return false;
  1.3145 +                }
  1.3146 +                ok = bindDestructuringVar(data, expr);
  1.3147 +            } else {
  1.3148 +                /*
  1.3149 +                 * If this is a destructuring shorthand ({x} = ...), then
  1.3150 +                 * identifierName wasn't used to parse |x|.  As a result, |x|
  1.3151 +                 * hasn't been officially linked to its def or registered in
  1.3152 +                 * lexdeps.  Do that now.
  1.3153 +                 */
  1.3154 +                if (member->pn_right == member->pn_left) {
  1.3155 +                    RootedPropertyName name(context, expr->pn_atom->asPropertyName());
  1.3156 +                    if (!noteNameUse(name, expr))
  1.3157 +                        return false;
  1.3158 +                }
  1.3159 +                ok = checkAndMarkAsAssignmentLhs(expr, KeyedDestructuringAssignment);
  1.3160 +            }
  1.3161 +            if (!ok)
  1.3162 +                return false;
  1.3163 +        }
  1.3164 +    }
  1.3165 +
  1.3166 +    return true;
  1.3167 +}
  1.3168 +
  1.3169 +template <>
  1.3170 +bool
  1.3171 +Parser<SyntaxParseHandler>::checkDestructuring(BindData<SyntaxParseHandler> *data,
  1.3172 +                                               Node left, bool toplevel)
  1.3173 +{
  1.3174 +    return abortIfSyntaxParser();
  1.3175 +}
  1.3176 +
  1.3177 +template <typename ParseHandler>
  1.3178 +typename ParseHandler::Node
  1.3179 +Parser<ParseHandler>::destructuringExpr(BindData<ParseHandler> *data, TokenKind tt)
  1.3180 +{
  1.3181 +    JS_ASSERT(tokenStream.isCurrentTokenType(tt));
  1.3182 +
  1.3183 +    pc->inDeclDestructuring = true;
  1.3184 +    Node pn = primaryExpr(tt);
  1.3185 +    pc->inDeclDestructuring = false;
  1.3186 +    if (!pn)
  1.3187 +        return null();
  1.3188 +    if (!checkDestructuring(data, pn))
  1.3189 +        return null();
  1.3190 +    return pn;
  1.3191 +}
  1.3192 +
  1.3193 +template <typename ParseHandler>
  1.3194 +typename ParseHandler::Node
  1.3195 +Parser<ParseHandler>::pushLexicalScope(HandleStaticBlockObject blockObj, StmtInfoPC *stmt)
  1.3196 +{
  1.3197 +    JS_ASSERT(blockObj);
  1.3198 +
  1.3199 +    ObjectBox *blockbox = newObjectBox(blockObj);
  1.3200 +    if (!blockbox)
  1.3201 +        return null();
  1.3202 +
  1.3203 +    PushStatementPC(pc, stmt, STMT_BLOCK);
  1.3204 +    blockObj->initEnclosingNestedScopeFromParser(pc->staticScope);
  1.3205 +    FinishPushNestedScope(pc, stmt, *blockObj.get());
  1.3206 +    stmt->isBlockScope = true;
  1.3207 +
  1.3208 +    Node pn = handler.newLexicalScope(blockbox);
  1.3209 +    if (!pn)
  1.3210 +        return null();
  1.3211 +
  1.3212 +    if (!GenerateBlockId(tokenStream, pc, stmt->blockid))
  1.3213 +        return null();
  1.3214 +    handler.setBlockId(pn, stmt->blockid);
  1.3215 +    return pn;
  1.3216 +}
  1.3217 +
  1.3218 +template <typename ParseHandler>
  1.3219 +typename ParseHandler::Node
  1.3220 +Parser<ParseHandler>::pushLexicalScope(StmtInfoPC *stmt)
  1.3221 +{
  1.3222 +    RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context));
  1.3223 +    if (!blockObj)
  1.3224 +        return null();
  1.3225 +
  1.3226 +    return pushLexicalScope(blockObj, stmt);
  1.3227 +}
  1.3228 +
  1.3229 +struct AddLetDecl
  1.3230 +{
  1.3231 +    uint32_t blockid;
  1.3232 +
  1.3233 +    AddLetDecl(uint32_t blockid) : blockid(blockid) {}
  1.3234 +
  1.3235 +    bool operator()(TokenStream &ts, ParseContext<FullParseHandler> *pc,
  1.3236 +                    HandleStaticBlockObject blockObj, const Shape &shape, JSAtom *)
  1.3237 +    {
  1.3238 +        ParseNode *def = (ParseNode *) blockObj->getSlot(shape.slot()).toPrivate();
  1.3239 +        def->pn_blockid = blockid;
  1.3240 +        RootedPropertyName name(ts.context(), def->name());
  1.3241 +        return pc->define(ts, name, def, Definition::LET);
  1.3242 +    }
  1.3243 +};
  1.3244 +
  1.3245 +template <>
  1.3246 +ParseNode *
  1.3247 +Parser<FullParseHandler>::pushLetScope(HandleStaticBlockObject blockObj, StmtInfoPC *stmt)
  1.3248 +{
  1.3249 +    JS_ASSERT(blockObj);
  1.3250 +    ParseNode *pn = pushLexicalScope(blockObj, stmt);
  1.3251 +    if (!pn)
  1.3252 +        return null();
  1.3253 +
  1.3254 +    pn->pn_dflags |= PND_LET;
  1.3255 +
  1.3256 +    /* Populate the new scope with decls found in the head with updated blockid. */
  1.3257 +    if (!ForEachLetDef(tokenStream, pc, blockObj, AddLetDecl(stmt->blockid)))
  1.3258 +        return null();
  1.3259 +
  1.3260 +    return pn;
  1.3261 +}
  1.3262 +
  1.3263 +template <>
  1.3264 +SyntaxParseHandler::Node
  1.3265 +Parser<SyntaxParseHandler>::pushLetScope(HandleStaticBlockObject blockObj, StmtInfoPC *stmt)
  1.3266 +{
  1.3267 +    JS_ALWAYS_FALSE(abortIfSyntaxParser());
  1.3268 +    return SyntaxParseHandler::NodeFailure;
  1.3269 +}
  1.3270 +
  1.3271 +/*
  1.3272 + * Parse a let block statement or let expression (determined by 'letContext').
  1.3273 + * In both cases, bindings are not hoisted to the top of the enclosing block
  1.3274 + * and thus must be carefully injected between variables() and the let body.
  1.3275 + */
  1.3276 +template <typename ParseHandler>
  1.3277 +typename ParseHandler::Node
  1.3278 +Parser<ParseHandler>::letBlock(LetContext letContext)
  1.3279 +{
  1.3280 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_LET));
  1.3281 +
  1.3282 +    RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context));
  1.3283 +    if (!blockObj)
  1.3284 +        return null();
  1.3285 +
  1.3286 +    uint32_t begin = pos().begin;
  1.3287 +
  1.3288 +    MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_LET);
  1.3289 +
  1.3290 +    Node vars = variables(PNK_LET, nullptr, blockObj, DontHoistVars);
  1.3291 +    if (!vars)
  1.3292 +        return null();
  1.3293 +
  1.3294 +    MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_LET);
  1.3295 +
  1.3296 +    StmtInfoPC stmtInfo(context);
  1.3297 +    Node block = pushLetScope(blockObj, &stmtInfo);
  1.3298 +    if (!block)
  1.3299 +        return null();
  1.3300 +
  1.3301 +    Node pnlet = handler.newBinary(PNK_LET, vars, block);
  1.3302 +    if (!pnlet)
  1.3303 +        return null();
  1.3304 +    handler.setBeginPosition(pnlet, begin);
  1.3305 +
  1.3306 +    bool needExprStmt = false;
  1.3307 +    if (letContext == LetStatement && !tokenStream.matchToken(TOK_LC, TokenStream::Operand)) {
  1.3308 +        /*
  1.3309 +         * Strict mode eliminates a grammar ambiguity with unparenthesized
  1.3310 +         * LetExpressions in an ExpressionStatement. If followed immediately
  1.3311 +         * by an arguments list, it's ambiguous whether the let expression
  1.3312 +         * is the callee or the call is inside the let expression body.
  1.3313 +         *
  1.3314 +         * See bug 569464.
  1.3315 +         */
  1.3316 +        if (!report(ParseStrictError, pc->sc->strict, pnlet,
  1.3317 +                    JSMSG_STRICT_CODE_LET_EXPR_STMT))
  1.3318 +        {
  1.3319 +            return null();
  1.3320 +        }
  1.3321 +
  1.3322 +        /*
  1.3323 +         * If this is really an expression in let statement guise, then we
  1.3324 +         * need to wrap the PNK_LET node in a PNK_SEMI node so that we pop
  1.3325 +         * the return value of the expression.
  1.3326 +         */
  1.3327 +        needExprStmt = true;
  1.3328 +        letContext = LetExpresion;
  1.3329 +    }
  1.3330 +
  1.3331 +    Node expr;
  1.3332 +    if (letContext == LetStatement) {
  1.3333 +        expr = statements();
  1.3334 +        if (!expr)
  1.3335 +            return null();
  1.3336 +        MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LET);
  1.3337 +    } else {
  1.3338 +        JS_ASSERT(letContext == LetExpresion);
  1.3339 +        expr = assignExpr();
  1.3340 +        if (!expr)
  1.3341 +            return null();
  1.3342 +    }
  1.3343 +    handler.setLexicalScopeBody(block, expr);
  1.3344 +    PopStatementPC(tokenStream, pc);
  1.3345 +
  1.3346 +    handler.setEndPosition(pnlet, pos().end);
  1.3347 +
  1.3348 +    if (needExprStmt) {
  1.3349 +        if (!MatchOrInsertSemicolon(tokenStream))
  1.3350 +            return null();
  1.3351 +        return handler.newExprStatement(pnlet, pos().end);
  1.3352 +    }
  1.3353 +    return pnlet;
  1.3354 +}
  1.3355 +
  1.3356 +template <typename ParseHandler>
  1.3357 +static bool
  1.3358 +PushBlocklikeStatement(TokenStream &ts, StmtInfoPC *stmt, StmtType type,
  1.3359 +                       ParseContext<ParseHandler> *pc)
  1.3360 +{
  1.3361 +    PushStatementPC(pc, stmt, type);
  1.3362 +    return GenerateBlockId(ts, pc, stmt->blockid);
  1.3363 +}
  1.3364 +
  1.3365 +template <typename ParseHandler>
  1.3366 +typename ParseHandler::Node
  1.3367 +Parser<ParseHandler>::blockStatement()
  1.3368 +{
  1.3369 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
  1.3370 +
  1.3371 +    StmtInfoPC stmtInfo(context);
  1.3372 +    if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_BLOCK, pc))
  1.3373 +        return null();
  1.3374 +
  1.3375 +    Node list = statements();
  1.3376 +    if (!list)
  1.3377 +        return null();
  1.3378 +
  1.3379 +    MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_COMPOUND);
  1.3380 +    PopStatementPC(tokenStream, pc);
  1.3381 +    return list;
  1.3382 +}
  1.3383 +
  1.3384 +template <typename ParseHandler>
  1.3385 +typename ParseHandler::Node
  1.3386 +Parser<ParseHandler>::newBindingNode(PropertyName *name, bool functionScope, VarContext varContext)
  1.3387 +{
  1.3388 +    /*
  1.3389 +     * If this name is being injected into an existing block/function, see if
  1.3390 +     * it has already been declared or if it resolves an outstanding lexdep.
  1.3391 +     * Otherwise, this is a let block/expr that introduces a new scope and thus
  1.3392 +     * shadows existing decls and doesn't resolve existing lexdeps. Duplicate
  1.3393 +     * names are caught by bindLet.
  1.3394 +     */
  1.3395 +    if (varContext == HoistVars) {
  1.3396 +        if (AtomDefnPtr p = pc->lexdeps->lookup(name)) {
  1.3397 +            DefinitionNode lexdep = p.value().get<ParseHandler>();
  1.3398 +            JS_ASSERT(handler.getDefinitionKind(lexdep) == Definition::PLACEHOLDER);
  1.3399 +
  1.3400 +            Node pn = handler.getDefinitionNode(lexdep);
  1.3401 +            if (handler.dependencyCovered(pn, pc->blockid(), functionScope)) {
  1.3402 +                handler.setBlockId(pn, pc->blockid());
  1.3403 +                pc->lexdeps->remove(p);
  1.3404 +                handler.setPosition(pn, pos());
  1.3405 +                return pn;
  1.3406 +            }
  1.3407 +        }
  1.3408 +    }
  1.3409 +
  1.3410 +    /* Make a new node for this declarator name (or destructuring pattern). */
  1.3411 +    return newName(name);
  1.3412 +}
  1.3413 +
  1.3414 +/*
  1.3415 + * The 'blockObj' parameter is non-null when parsing the 'vars' in a let
  1.3416 + * expression, block statement, non-top-level let declaration in statement
  1.3417 + * context, and the let-initializer of a for-statement.
  1.3418 + */
  1.3419 +template <typename ParseHandler>
  1.3420 +typename ParseHandler::Node
  1.3421 +Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple,
  1.3422 +                                StaticBlockObject *blockObj, VarContext varContext)
  1.3423 +{
  1.3424 +    /*
  1.3425 +     * The four options here are:
  1.3426 +     * - PNK_VAR:   We're parsing var declarations.
  1.3427 +     * - PNK_CONST: We're parsing const declarations.
  1.3428 +     * - PNK_LET:   We are parsing a let declaration.
  1.3429 +     * - PNK_CALL:  We are parsing the head of a let block.
  1.3430 +     */
  1.3431 +    JS_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET || kind == PNK_CALL);
  1.3432 +
  1.3433 +    /*
  1.3434 +     * The simple flag is set if the declaration has the form 'var x', with
  1.3435 +     * only one variable declared and no initializer expression.
  1.3436 +     */
  1.3437 +    JS_ASSERT_IF(psimple, *psimple);
  1.3438 +
  1.3439 +    JSOp op = blockObj ? JSOP_NOP : kind == PNK_VAR ? JSOP_DEFVAR : JSOP_DEFCONST;
  1.3440 +
  1.3441 +    Node pn = handler.newList(kind, null(), op);
  1.3442 +    if (!pn)
  1.3443 +        return null();
  1.3444 +
  1.3445 +    /*
  1.3446 +     * SpiderMonkey const is really "write once per initialization evaluation"
  1.3447 +     * var, whereas let is block scoped. ES-Harmony wants block-scoped const so
  1.3448 +     * this code will change soon.
  1.3449 +     */
  1.3450 +    BindData<ParseHandler> data(context);
  1.3451 +    if (blockObj)
  1.3452 +        data.initLet(varContext, *blockObj, JSMSG_TOO_MANY_LOCALS);
  1.3453 +    else
  1.3454 +        data.initVarOrConst(op);
  1.3455 +
  1.3456 +    bool first = true;
  1.3457 +    Node pn2;
  1.3458 +    do {
  1.3459 +        if (psimple && !first)
  1.3460 +            *psimple = false;
  1.3461 +        first = false;
  1.3462 +
  1.3463 +        TokenKind tt = tokenStream.getToken();
  1.3464 +        if (tt == TOK_LB || tt == TOK_LC) {
  1.3465 +            if (psimple)
  1.3466 +                *psimple = false;
  1.3467 +
  1.3468 +            pc->inDeclDestructuring = true;
  1.3469 +            pn2 = primaryExpr(tt);
  1.3470 +            pc->inDeclDestructuring = false;
  1.3471 +            if (!pn2)
  1.3472 +                return null();
  1.3473 +
  1.3474 +            if (!checkDestructuring(&data, pn2))
  1.3475 +                return null();
  1.3476 +            bool ignored;
  1.3477 +            if (pc->parsingForInit && matchInOrOf(&ignored)) {
  1.3478 +                tokenStream.ungetToken();
  1.3479 +                handler.addList(pn, pn2);
  1.3480 +                continue;
  1.3481 +            }
  1.3482 +
  1.3483 +            MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL);
  1.3484 +
  1.3485 +            Node init = assignExpr();
  1.3486 +            if (!init)
  1.3487 +                return null();
  1.3488 +
  1.3489 +            pn2 = handler.newBinaryOrAppend(PNK_ASSIGN, pn2, init, pc);
  1.3490 +            if (!pn2)
  1.3491 +                return null();
  1.3492 +            handler.addList(pn, pn2);
  1.3493 +            continue;
  1.3494 +        }
  1.3495 +
  1.3496 +        if (tt != TOK_NAME) {
  1.3497 +            if (tt == TOK_YIELD) {
  1.3498 +                if (!checkYieldNameValidity())
  1.3499 +                    return null();
  1.3500 +            } else {
  1.3501 +                if (tt != TOK_ERROR)
  1.3502 +                    report(ParseError, false, null(), JSMSG_NO_VARIABLE_NAME);
  1.3503 +                return null();
  1.3504 +            }
  1.3505 +        }
  1.3506 +
  1.3507 +        RootedPropertyName name(context, tokenStream.currentName());
  1.3508 +        pn2 = newBindingNode(name, kind == PNK_VAR || kind == PNK_CONST, varContext);
  1.3509 +        if (!pn2)
  1.3510 +            return null();
  1.3511 +        if (data.op == JSOP_DEFCONST)
  1.3512 +            handler.setFlag(pn2, PND_CONST);
  1.3513 +        data.pn = pn2;
  1.3514 +        if (!data.binder(&data, name, this))
  1.3515 +            return null();
  1.3516 +        handler.addList(pn, pn2);
  1.3517 +
  1.3518 +        if (tokenStream.matchToken(TOK_ASSIGN)) {
  1.3519 +            if (psimple)
  1.3520 +                *psimple = false;
  1.3521 +
  1.3522 +            Node init = assignExpr();
  1.3523 +            if (!init)
  1.3524 +                return null();
  1.3525 +
  1.3526 +            if (!handler.finishInitializerAssignment(pn2, init, data.op))
  1.3527 +                return null();
  1.3528 +        }
  1.3529 +    } while (tokenStream.matchToken(TOK_COMMA));
  1.3530 +
  1.3531 +    return pn;
  1.3532 +}
  1.3533 +
  1.3534 +template <>
  1.3535 +ParseNode *
  1.3536 +Parser<FullParseHandler>::letDeclaration()
  1.3537 +{
  1.3538 +    handler.disableSyntaxParser();
  1.3539 +
  1.3540 +    ParseNode *pn;
  1.3541 +
  1.3542 +    do {
  1.3543 +        /*
  1.3544 +         * This is a let declaration. We must be directly under a block per the
  1.3545 +         * proposed ES4 specs, but not an implicit block created due to
  1.3546 +         * 'for (let ...)'. If we pass this error test, make the enclosing
  1.3547 +         * StmtInfoPC be our scope. Further let declarations in this block will
  1.3548 +         * find this scope statement and use the same block object.
  1.3549 +         *
  1.3550 +         * If we are the first let declaration in this block (i.e., when the
  1.3551 +         * enclosing maybe-scope StmtInfoPC isn't yet a scope statement) then
  1.3552 +         * we also need to set pc->blockNode to be our PNK_LEXICALSCOPE.
  1.3553 +         */
  1.3554 +        StmtInfoPC *stmt = pc->topStmt;
  1.3555 +        if (stmt && (!stmt->maybeScope() || stmt->isForLetBlock)) {
  1.3556 +            report(ParseError, false, null(), JSMSG_LET_DECL_NOT_IN_BLOCK);
  1.3557 +            return null();
  1.3558 +        }
  1.3559 +
  1.3560 +        if (stmt && stmt->isBlockScope) {
  1.3561 +            JS_ASSERT(pc->staticScope == stmt->staticScope);
  1.3562 +        } else {
  1.3563 +            if (pc->atBodyLevel()) {
  1.3564 +                /*
  1.3565 +                 * ES4 specifies that let at top level and at body-block scope
  1.3566 +                 * does not shadow var, so convert back to var.
  1.3567 +                 */
  1.3568 +                pn = variables(PNK_VAR);
  1.3569 +                if (!pn)
  1.3570 +                    return null();
  1.3571 +                pn->pn_xflags |= PNX_POPVAR;
  1.3572 +                break;
  1.3573 +            }
  1.3574 +
  1.3575 +            /*
  1.3576 +             * Some obvious assertions here, but they may help clarify the
  1.3577 +             * situation. This stmt is not yet a scope, so it must not be a
  1.3578 +             * catch block (catch is a lexical scope by definition).
  1.3579 +             */
  1.3580 +            JS_ASSERT(!stmt->isBlockScope);
  1.3581 +            JS_ASSERT(stmt != pc->topScopeStmt);
  1.3582 +            JS_ASSERT(stmt->type == STMT_BLOCK ||
  1.3583 +                      stmt->type == STMT_SWITCH ||
  1.3584 +                      stmt->type == STMT_TRY ||
  1.3585 +                      stmt->type == STMT_FINALLY);
  1.3586 +            JS_ASSERT(!stmt->downScope);
  1.3587 +
  1.3588 +            /* Convert the block statement into a scope statement. */
  1.3589 +            StaticBlockObject *blockObj = StaticBlockObject::create(context);
  1.3590 +            if (!blockObj)
  1.3591 +                return null();
  1.3592 +
  1.3593 +            ObjectBox *blockbox = newObjectBox(blockObj);
  1.3594 +            if (!blockbox)
  1.3595 +                return null();
  1.3596 +
  1.3597 +            /*
  1.3598 +             * Insert stmt on the pc->topScopeStmt/stmtInfo.downScope linked
  1.3599 +             * list stack, if it isn't already there.  If it is there, but it
  1.3600 +             * lacks the SIF_SCOPE flag, it must be a try, catch, or finally
  1.3601 +             * block.
  1.3602 +             */
  1.3603 +            stmt->isBlockScope = stmt->isNestedScope = true;
  1.3604 +            stmt->downScope = pc->topScopeStmt;
  1.3605 +            pc->topScopeStmt = stmt;
  1.3606 +
  1.3607 +            blockObj->initEnclosingNestedScopeFromParser(pc->staticScope);
  1.3608 +            pc->staticScope = blockObj;
  1.3609 +            stmt->staticScope = blockObj;
  1.3610 +
  1.3611 +#ifdef DEBUG
  1.3612 +            ParseNode *tmp = pc->blockNode;
  1.3613 +            JS_ASSERT(!tmp || !tmp->isKind(PNK_LEXICALSCOPE));
  1.3614 +#endif
  1.3615 +
  1.3616 +            /* Create a new lexical scope node for these statements. */
  1.3617 +            ParseNode *pn1 = LexicalScopeNode::create(PNK_LEXICALSCOPE, &handler);
  1.3618 +            if (!pn1)
  1.3619 +                return null();
  1.3620 +
  1.3621 +            pn1->pn_pos = pc->blockNode->pn_pos;
  1.3622 +            pn1->pn_objbox = blockbox;
  1.3623 +            pn1->pn_expr = pc->blockNode;
  1.3624 +            pn1->pn_blockid = pc->blockNode->pn_blockid;
  1.3625 +            pc->blockNode = pn1;
  1.3626 +        }
  1.3627 +
  1.3628 +        pn = variables(PNK_LET, nullptr, &pc->staticScope->as<StaticBlockObject>(), HoistVars);
  1.3629 +        if (!pn)
  1.3630 +            return null();
  1.3631 +        pn->pn_xflags = PNX_POPVAR;
  1.3632 +    } while (0);
  1.3633 +
  1.3634 +    return MatchOrInsertSemicolon(tokenStream) ? pn : nullptr;
  1.3635 +}
  1.3636 +
  1.3637 +template <>
  1.3638 +SyntaxParseHandler::Node
  1.3639 +Parser<SyntaxParseHandler>::letDeclaration()
  1.3640 +{
  1.3641 +    JS_ALWAYS_FALSE(abortIfSyntaxParser());
  1.3642 +    return SyntaxParseHandler::NodeFailure;
  1.3643 +}
  1.3644 +
  1.3645 +template <>
  1.3646 +ParseNode *
  1.3647 +Parser<FullParseHandler>::letStatement()
  1.3648 +{
  1.3649 +    handler.disableSyntaxParser();
  1.3650 +
  1.3651 +    /* Check for a let statement or let expression. */
  1.3652 +    ParseNode *pn;
  1.3653 +    if (tokenStream.peekToken() == TOK_LP) {
  1.3654 +        pn = letBlock(LetStatement);
  1.3655 +        JS_ASSERT_IF(pn, pn->isKind(PNK_LET) || pn->isKind(PNK_SEMI));
  1.3656 +    } else {
  1.3657 +        pn = letDeclaration();
  1.3658 +    }
  1.3659 +    return pn;
  1.3660 +}
  1.3661 +
  1.3662 +template <>
  1.3663 +SyntaxParseHandler::Node
  1.3664 +Parser<SyntaxParseHandler>::letStatement()
  1.3665 +{
  1.3666 +    JS_ALWAYS_FALSE(abortIfSyntaxParser());
  1.3667 +    return SyntaxParseHandler::NodeFailure;
  1.3668 +}
  1.3669 +
  1.3670 +template<typename ParseHandler>
  1.3671 +typename ParseHandler::Node
  1.3672 +Parser<ParseHandler>::importDeclaration()
  1.3673 +{
  1.3674 +    JS_ASSERT(tokenStream.currentToken().type == TOK_IMPORT);
  1.3675 +
  1.3676 +    if (pc->sc->isFunctionBox() || !pc->atBodyLevel()) {
  1.3677 +        report(ParseError, false, null(), JSMSG_IMPORT_DECL_AT_TOP_LEVEL);
  1.3678 +        return null();
  1.3679 +    }
  1.3680 +
  1.3681 +    uint32_t begin = pos().begin;
  1.3682 +    TokenKind tt = tokenStream.getToken();
  1.3683 +
  1.3684 +    Node importSpecSet = handler.newList(PNK_IMPORT_SPEC_LIST);
  1.3685 +    if (!importSpecSet)
  1.3686 +        return null();
  1.3687 +
  1.3688 +    if (tt == TOK_NAME || tt == TOK_LC) {
  1.3689 +        if (tt == TOK_NAME) {
  1.3690 +            // Handle the form |import a from 'b'|, by adding a single import
  1.3691 +            // specifier to the list, with 'default' as the import name and
  1.3692 +            // 'a' as the binding name. This is equivalent to
  1.3693 +            // |import { default as a } from 'b'|.
  1.3694 +            Node importName = newName(context->names().default_);
  1.3695 +            if (!importName)
  1.3696 +                return null();
  1.3697 +
  1.3698 +            Node bindingName = newName(tokenStream.currentName());
  1.3699 +            if (!bindingName)
  1.3700 +                return null();
  1.3701 +
  1.3702 +            Node importSpec = handler.newBinary(PNK_IMPORT_SPEC, importName, bindingName);
  1.3703 +            if (!importSpec)
  1.3704 +                return null();
  1.3705 +
  1.3706 +            handler.addList(importSpecSet, importSpec);
  1.3707 +        } else {
  1.3708 +            do {
  1.3709 +                // Handle the forms |import {} from 'a'| and
  1.3710 +                // |import { ..., } from 'a'| (where ... is non empty), by
  1.3711 +                // escaping the loop early if the next token is }.
  1.3712 +                tt = tokenStream.peekToken(TokenStream::KeywordIsName);
  1.3713 +                if (tt == TOK_ERROR)
  1.3714 +                    return null();
  1.3715 +                if (tt == TOK_RC)
  1.3716 +                    break;
  1.3717 +
  1.3718 +                // If the next token is a keyword, the previous call to
  1.3719 +                // peekToken matched it as a TOK_NAME, and put it in the
  1.3720 +                // lookahead buffer, so this call will match keywords as well.
  1.3721 +                MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_IMPORT_NAME);
  1.3722 +                Node importName = newName(tokenStream.currentName());
  1.3723 +                if (!importName)
  1.3724 +                    return null();
  1.3725 +
  1.3726 +                if (tokenStream.getToken() == TOK_NAME &&
  1.3727 +                    tokenStream.currentName() == context->names().as)
  1.3728 +                {
  1.3729 +                    if (tokenStream.getToken() != TOK_NAME) {
  1.3730 +                        report(ParseError, false, null(), JSMSG_NO_BINDING_NAME);
  1.3731 +                        return null();
  1.3732 +                    }
  1.3733 +                } else {
  1.3734 +                    // Keywords cannot be bound to themselves, so an import name
  1.3735 +                    // that is a keyword is a syntax error if it is not followed
  1.3736 +                    // by the keyword 'as'.
  1.3737 +                    if (IsKeyword(importName->name())) {
  1.3738 +                        JSAutoByteString bytes;
  1.3739 +                        if (!AtomToPrintableString(context, importName->name(), &bytes))
  1.3740 +                            return null();
  1.3741 +                        report(ParseError, false, null(), JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr());
  1.3742 +                        return null();
  1.3743 +                    }
  1.3744 +                    tokenStream.ungetToken();
  1.3745 +                }
  1.3746 +                Node bindingName = newName(tokenStream.currentName());
  1.3747 +                if (!bindingName)
  1.3748 +                    return null();
  1.3749 +
  1.3750 +                Node importSpec = handler.newBinary(PNK_IMPORT_SPEC, importName, bindingName);
  1.3751 +                if (!importSpec)
  1.3752 +                    return null();
  1.3753 +
  1.3754 +                handler.addList(importSpecSet, importSpec);
  1.3755 +            } while (tokenStream.matchToken(TOK_COMMA));
  1.3756 +
  1.3757 +            MUST_MATCH_TOKEN(TOK_RC, JSMSG_RC_AFTER_IMPORT_SPEC_LIST);
  1.3758 +        }
  1.3759 +
  1.3760 +        if (tokenStream.getToken() != TOK_NAME ||
  1.3761 +            tokenStream.currentName() != context->names().from)
  1.3762 +        {
  1.3763 +            report(ParseError, false, null(), JSMSG_FROM_AFTER_IMPORT_SPEC_SET);
  1.3764 +            return null();
  1.3765 +        }
  1.3766 +
  1.3767 +        MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM);
  1.3768 +    } else {
  1.3769 +        if (tt != TOK_STRING) {
  1.3770 +            report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_IMPORT);
  1.3771 +            return null();
  1.3772 +        }
  1.3773 +
  1.3774 +        // Handle the form |import 'a'| by leaving the list empty. This is
  1.3775 +        // equivalent to |import {} from 'a'|.
  1.3776 +        importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin;
  1.3777 +    }
  1.3778 +
  1.3779 +    Node moduleSpec = stringLiteral();
  1.3780 +    if (!moduleSpec)
  1.3781 +        return null();
  1.3782 +
  1.3783 +    if (!MatchOrInsertSemicolon(tokenStream))
  1.3784 +        return null();
  1.3785 +
  1.3786 +    return handler.newImportDeclaration(importSpecSet, moduleSpec,
  1.3787 +                                        TokenPos(begin, pos().end));
  1.3788 +}
  1.3789 +
  1.3790 +template<>
  1.3791 +SyntaxParseHandler::Node
  1.3792 +Parser<SyntaxParseHandler>::importDeclaration()
  1.3793 +{
  1.3794 +    JS_ALWAYS_FALSE(abortIfSyntaxParser());
  1.3795 +    return SyntaxParseHandler::NodeFailure;
  1.3796 +}
  1.3797 +
  1.3798 +template<typename ParseHandler>
  1.3799 +typename ParseHandler::Node
  1.3800 +Parser<ParseHandler>::exportDeclaration()
  1.3801 +{
  1.3802 +    JS_ASSERT(tokenStream.currentToken().type == TOK_EXPORT);
  1.3803 +
  1.3804 +    if (pc->sc->isFunctionBox() || !pc->atBodyLevel()) {
  1.3805 +        report(ParseError, false, null(), JSMSG_EXPORT_DECL_AT_TOP_LEVEL);
  1.3806 +        return null();
  1.3807 +    }
  1.3808 +
  1.3809 +    uint32_t begin = pos().begin;
  1.3810 +
  1.3811 +    Node kid;
  1.3812 +    switch (TokenKind tt = tokenStream.getToken()) {
  1.3813 +      case TOK_LC:
  1.3814 +      case TOK_MUL:
  1.3815 +        kid = handler.newList(PNK_EXPORT_SPEC_LIST);
  1.3816 +        if (!kid)
  1.3817 +            return null();
  1.3818 +
  1.3819 +        if (tt == TOK_LC) {
  1.3820 +            do {
  1.3821 +                // Handle the forms |export {}| and |export { ..., }| (where ...
  1.3822 +                // is non empty), by escaping the loop early if the next token
  1.3823 +                // is }.
  1.3824 +                tt = tokenStream.peekToken();
  1.3825 +                if (tt == TOK_ERROR)
  1.3826 +                    return null();
  1.3827 +                if (tt == TOK_RC)
  1.3828 +                    break;
  1.3829 +
  1.3830 +                MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_BINDING_NAME);
  1.3831 +                Node bindingName = newName(tokenStream.currentName());
  1.3832 +                if (!bindingName)
  1.3833 +                    return null();
  1.3834 +
  1.3835 +                if (tokenStream.getToken() == TOK_NAME &&
  1.3836 +                    tokenStream.currentName() == context->names().as)
  1.3837 +                {
  1.3838 +                    if (tokenStream.getToken(TokenStream::KeywordIsName) != TOK_NAME) {
  1.3839 +                        report(ParseError, false, null(), JSMSG_NO_EXPORT_NAME);
  1.3840 +                        return null();
  1.3841 +                    }
  1.3842 +                } else {
  1.3843 +                    tokenStream.ungetToken();
  1.3844 +                }
  1.3845 +                Node exportName = newName(tokenStream.currentName());
  1.3846 +                if (!exportName)
  1.3847 +                    return null();
  1.3848 +
  1.3849 +                Node exportSpec = handler.newBinary(PNK_EXPORT_SPEC, bindingName, exportName);
  1.3850 +                if (!exportSpec)
  1.3851 +                    return null();
  1.3852 +
  1.3853 +                handler.addList(kid, exportSpec);
  1.3854 +            } while (tokenStream.matchToken(TOK_COMMA));
  1.3855 +
  1.3856 +            MUST_MATCH_TOKEN(TOK_RC, JSMSG_RC_AFTER_EXPORT_SPEC_LIST);
  1.3857 +        } else {
  1.3858 +            // Handle the form |export *| by adding a special export batch
  1.3859 +            // specifier to the list.
  1.3860 +            Node exportSpec = handler.newNullary(PNK_EXPORT_BATCH_SPEC, JSOP_NOP, pos());
  1.3861 +            if (!kid)
  1.3862 +                return null();
  1.3863 +
  1.3864 +            handler.addList(kid, exportSpec);
  1.3865 +        }
  1.3866 +        if (tokenStream.getToken() == TOK_NAME &&
  1.3867 +            tokenStream.currentName() == context->names().from)
  1.3868 +        {
  1.3869 +            MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM);
  1.3870 +
  1.3871 +            Node moduleSpec = stringLiteral();
  1.3872 +            if (!moduleSpec)
  1.3873 +                return null();
  1.3874 +
  1.3875 +            if (!MatchOrInsertSemicolon(tokenStream))
  1.3876 +                return null();
  1.3877 +
  1.3878 +            return handler.newExportFromDeclaration(begin, kid, moduleSpec);
  1.3879 +        } else {
  1.3880 +            tokenStream.ungetToken();
  1.3881 +        }
  1.3882 +
  1.3883 +        kid = MatchOrInsertSemicolon(tokenStream) ? kid : nullptr;
  1.3884 +        if (!kid)
  1.3885 +            return null();
  1.3886 +        break;
  1.3887 +
  1.3888 +      case TOK_FUNCTION:
  1.3889 +        kid = functionStmt();
  1.3890 +        if (!kid)
  1.3891 +            return null();
  1.3892 +        break;
  1.3893 +
  1.3894 +      case TOK_VAR:
  1.3895 +      case TOK_CONST:
  1.3896 +        kid = variables(tt == TOK_VAR ? PNK_VAR : PNK_CONST);
  1.3897 +        if (!kid)
  1.3898 +            return null();
  1.3899 +        kid->pn_xflags = PNX_POPVAR;
  1.3900 +
  1.3901 +        kid = MatchOrInsertSemicolon(tokenStream) ? kid : nullptr;
  1.3902 +        if (!kid)
  1.3903 +            return null();
  1.3904 +        break;
  1.3905 +
  1.3906 +      case TOK_NAME:
  1.3907 +        // Handle the form |export a} in the same way as |export let a|, by
  1.3908 +        // acting as if we've just seen the let keyword. Simply unget the token
  1.3909 +        // and fall through.
  1.3910 +        tokenStream.ungetToken();
  1.3911 +      case TOK_LET:
  1.3912 +        kid = letDeclaration();
  1.3913 +        if (!kid)
  1.3914 +            return null();
  1.3915 +        break;
  1.3916 +
  1.3917 +      default:
  1.3918 +        report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_EXPORT);
  1.3919 +        return null();
  1.3920 +    }
  1.3921 +
  1.3922 +    return handler.newExportDeclaration(kid, TokenPos(begin, pos().end));
  1.3923 +}
  1.3924 +
  1.3925 +template<>
  1.3926 +SyntaxParseHandler::Node
  1.3927 +Parser<SyntaxParseHandler>::exportDeclaration()
  1.3928 +{
  1.3929 +    JS_ALWAYS_FALSE(abortIfSyntaxParser());
  1.3930 +    return SyntaxParseHandler::NodeFailure;
  1.3931 +}
  1.3932 +
  1.3933 +
  1.3934 +template <typename ParseHandler>
  1.3935 +typename ParseHandler::Node
  1.3936 +Parser<ParseHandler>::expressionStatement()
  1.3937 +{
  1.3938 +    tokenStream.ungetToken();
  1.3939 +    Node pnexpr = expr();
  1.3940 +    if (!pnexpr)
  1.3941 +        return null();
  1.3942 +    if (!MatchOrInsertSemicolon(tokenStream))
  1.3943 +        return null();
  1.3944 +    return handler.newExprStatement(pnexpr, pos().end);
  1.3945 +}
  1.3946 +
  1.3947 +template <typename ParseHandler>
  1.3948 +typename ParseHandler::Node
  1.3949 +Parser<ParseHandler>::ifStatement()
  1.3950 +{
  1.3951 +    uint32_t begin = pos().begin;
  1.3952 +
  1.3953 +    /* An IF node has three kids: condition, then, and optional else. */
  1.3954 +    Node cond = condition();
  1.3955 +    if (!cond)
  1.3956 +        return null();
  1.3957 +
  1.3958 +    if (tokenStream.peekToken(TokenStream::Operand) == TOK_SEMI &&
  1.3959 +        !report(ParseExtraWarning, false, null(), JSMSG_EMPTY_CONSEQUENT))
  1.3960 +    {
  1.3961 +        return null();
  1.3962 +    }
  1.3963 +
  1.3964 +    StmtInfoPC stmtInfo(context);
  1.3965 +    PushStatementPC(pc, &stmtInfo, STMT_IF);
  1.3966 +    Node thenBranch = statement();
  1.3967 +    if (!thenBranch)
  1.3968 +        return null();
  1.3969 +
  1.3970 +    Node elseBranch;
  1.3971 +    if (tokenStream.matchToken(TOK_ELSE, TokenStream::Operand)) {
  1.3972 +        stmtInfo.type = STMT_ELSE;
  1.3973 +        elseBranch = statement();
  1.3974 +        if (!elseBranch)
  1.3975 +            return null();
  1.3976 +    } else {
  1.3977 +        elseBranch = null();
  1.3978 +    }
  1.3979 +
  1.3980 +    PopStatementPC(tokenStream, pc);
  1.3981 +    return handler.newIfStatement(begin, cond, thenBranch, elseBranch);
  1.3982 +}
  1.3983 +
  1.3984 +template <typename ParseHandler>
  1.3985 +typename ParseHandler::Node
  1.3986 +Parser<ParseHandler>::doWhileStatement()
  1.3987 +{
  1.3988 +    uint32_t begin = pos().begin;
  1.3989 +    StmtInfoPC stmtInfo(context);
  1.3990 +    PushStatementPC(pc, &stmtInfo, STMT_DO_LOOP);
  1.3991 +    Node body = statement();
  1.3992 +    if (!body)
  1.3993 +        return null();
  1.3994 +    MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO);
  1.3995 +    Node cond = condition();
  1.3996 +    if (!cond)
  1.3997 +        return null();
  1.3998 +    PopStatementPC(tokenStream, pc);
  1.3999 +
  1.4000 +    if (versionNumber() == JSVERSION_ECMA_3) {
  1.4001 +        // Pedantically require a semicolon or line break, following ES3.
  1.4002 +        // Bug 880329 proposes removing this case.
  1.4003 +        if (!MatchOrInsertSemicolon(tokenStream))
  1.4004 +            return null();
  1.4005 +    } else {
  1.4006 +        // The semicolon after do-while is even more optional than most
  1.4007 +        // semicolons in JS.  Web compat required this by 2004:
  1.4008 +        //   http://bugzilla.mozilla.org/show_bug.cgi?id=238945
  1.4009 +        // ES3 and ES5 disagreed, but ES6 conforms to Web reality:
  1.4010 +        //   https://bugs.ecmascript.org/show_bug.cgi?id=157
  1.4011 +        (void) tokenStream.matchToken(TOK_SEMI);
  1.4012 +    }
  1.4013 +
  1.4014 +    return handler.newDoWhileStatement(body, cond, TokenPos(begin, pos().end));
  1.4015 +}
  1.4016 +
  1.4017 +template <typename ParseHandler>
  1.4018 +typename ParseHandler::Node
  1.4019 +Parser<ParseHandler>::whileStatement()
  1.4020 +{
  1.4021 +    uint32_t begin = pos().begin;
  1.4022 +    StmtInfoPC stmtInfo(context);
  1.4023 +    PushStatementPC(pc, &stmtInfo, STMT_WHILE_LOOP);
  1.4024 +    Node cond = condition();
  1.4025 +    if (!cond)
  1.4026 +        return null();
  1.4027 +    Node body = statement();
  1.4028 +    if (!body)
  1.4029 +        return null();
  1.4030 +    PopStatementPC(tokenStream, pc);
  1.4031 +    return handler.newWhileStatement(begin, cond, body);
  1.4032 +}
  1.4033 +
  1.4034 +template <typename ParseHandler>
  1.4035 +bool
  1.4036 +Parser<ParseHandler>::matchInOrOf(bool *isForOfp)
  1.4037 +{
  1.4038 +    if (tokenStream.matchToken(TOK_IN)) {
  1.4039 +        *isForOfp = false;
  1.4040 +        return true;
  1.4041 +    }
  1.4042 +    if (tokenStream.matchContextualKeyword(context->names().of)) {
  1.4043 +        *isForOfp = true;
  1.4044 +        return true;
  1.4045 +    }
  1.4046 +    return false;
  1.4047 +}
  1.4048 +
  1.4049 +template <>
  1.4050 +bool
  1.4051 +Parser<FullParseHandler>::isValidForStatementLHS(ParseNode *pn1, JSVersion version,
  1.4052 +                                                 bool isForDecl, bool isForEach,
  1.4053 +                                                 ParseNodeKind headKind)
  1.4054 +{
  1.4055 +    if (isForDecl) {
  1.4056 +        if (pn1->pn_count > 1)
  1.4057 +            return false;
  1.4058 +        if (pn1->isOp(JSOP_DEFCONST))
  1.4059 +            return false;
  1.4060 +
  1.4061 +        // In JS 1.7 only, for (var [K, V] in EXPR) has a special meaning.
  1.4062 +        // Hence all other destructuring decls are banned there.
  1.4063 +        if (version == JSVERSION_1_7 && !isForEach && headKind == PNK_FORIN) {
  1.4064 +            ParseNode *lhs = pn1->pn_head;
  1.4065 +            if (lhs->isKind(PNK_ASSIGN))
  1.4066 +                lhs = lhs->pn_left;
  1.4067 +
  1.4068 +            if (lhs->isKind(PNK_OBJECT))
  1.4069 +                return false;
  1.4070 +            if (lhs->isKind(PNK_ARRAY) && lhs->pn_count != 2)
  1.4071 +                return false;
  1.4072 +        }
  1.4073 +        return true;
  1.4074 +    }
  1.4075 +
  1.4076 +    switch (pn1->getKind()) {
  1.4077 +      case PNK_NAME:
  1.4078 +      case PNK_DOT:
  1.4079 +      case PNK_CALL:
  1.4080 +      case PNK_ELEM:
  1.4081 +        return true;
  1.4082 +
  1.4083 +      case PNK_ARRAY:
  1.4084 +      case PNK_OBJECT:
  1.4085 +        // In JS 1.7 only, for ([K, V] in EXPR) has a special meaning.
  1.4086 +        // Hence all other destructuring left-hand sides are banned there.
  1.4087 +        if (version == JSVERSION_1_7 && !isForEach && headKind == PNK_FORIN)
  1.4088 +            return pn1->isKind(PNK_ARRAY) && pn1->pn_count == 2;
  1.4089 +        return true;
  1.4090 +
  1.4091 +      default:
  1.4092 +        return false;
  1.4093 +    }
  1.4094 +}
  1.4095 +
  1.4096 +template <>
  1.4097 +ParseNode *
  1.4098 +Parser<FullParseHandler>::forStatement()
  1.4099 +{
  1.4100 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
  1.4101 +    uint32_t begin = pos().begin;
  1.4102 +
  1.4103 +    StmtInfoPC forStmt(context);
  1.4104 +    PushStatementPC(pc, &forStmt, STMT_FOR_LOOP);
  1.4105 +
  1.4106 +    bool isForEach = false;
  1.4107 +    unsigned iflags = 0;
  1.4108 +
  1.4109 +    if (allowsForEachIn() && tokenStream.matchContextualKeyword(context->names().each)) {
  1.4110 +        iflags = JSITER_FOREACH;
  1.4111 +        isForEach = true;
  1.4112 +    }
  1.4113 +
  1.4114 +    MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
  1.4115 +
  1.4116 +    /*
  1.4117 +     * True if we have 'for (var/let/const ...)', except in the oddball case
  1.4118 +     * where 'let' begins a let-expression in 'for (let (...) ...)'.
  1.4119 +     */
  1.4120 +    bool isForDecl = false;
  1.4121 +
  1.4122 +    /* Non-null when isForDecl is true for a 'for (let ...)' statement. */
  1.4123 +    RootedStaticBlockObject blockObj(context);
  1.4124 +
  1.4125 +    /* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
  1.4126 +    ParseNode *pn1;
  1.4127 +
  1.4128 +    {
  1.4129 +        TokenKind tt = tokenStream.peekToken(TokenStream::Operand);
  1.4130 +        if (tt == TOK_SEMI) {
  1.4131 +            pn1 = nullptr;
  1.4132 +        } else {
  1.4133 +            /*
  1.4134 +             * Set pn1 to a var list or an initializing expression.
  1.4135 +             *
  1.4136 +             * Set the parsingForInit flag during parsing of the first clause
  1.4137 +             * of the for statement.  This flag will be used by the RelExpr
  1.4138 +             * production; if it is set, then the 'in' keyword will not be
  1.4139 +             * recognized as an operator, leaving it available to be parsed as
  1.4140 +             * part of a for/in loop.
  1.4141 +             *
  1.4142 +             * A side effect of this restriction is that (unparenthesized)
  1.4143 +             * expressions involving an 'in' operator are illegal in the init
  1.4144 +             * clause of an ordinary for loop.
  1.4145 +             */
  1.4146 +            pc->parsingForInit = true;
  1.4147 +            if (tt == TOK_VAR || tt == TOK_CONST) {
  1.4148 +                isForDecl = true;
  1.4149 +                tokenStream.consumeKnownToken(tt);
  1.4150 +                pn1 = variables(tt == TOK_VAR ? PNK_VAR : PNK_CONST);
  1.4151 +            }
  1.4152 +            else if (tt == TOK_LET) {
  1.4153 +                handler.disableSyntaxParser();
  1.4154 +                (void) tokenStream.getToken();
  1.4155 +                if (tokenStream.peekToken() == TOK_LP) {
  1.4156 +                    pn1 = letBlock(LetExpresion);
  1.4157 +                } else {
  1.4158 +                    isForDecl = true;
  1.4159 +                    blockObj = StaticBlockObject::create(context);
  1.4160 +                    if (!blockObj)
  1.4161 +                        return null();
  1.4162 +                    pn1 = variables(PNK_LET, nullptr, blockObj, DontHoistVars);
  1.4163 +                }
  1.4164 +            }
  1.4165 +            else {
  1.4166 +                pn1 = expr();
  1.4167 +            }
  1.4168 +            pc->parsingForInit = false;
  1.4169 +            if (!pn1)
  1.4170 +                return null();
  1.4171 +        }
  1.4172 +    }
  1.4173 +
  1.4174 +    JS_ASSERT_IF(isForDecl, pn1->isArity(PN_LIST));
  1.4175 +    JS_ASSERT(!!blockObj == (isForDecl && pn1->isOp(JSOP_NOP)));
  1.4176 +
  1.4177 +    // The form 'for (let <vars>; <expr2>; <expr3>) <stmt>' generates an
  1.4178 +    // implicit block even if stmt is not a BlockStatement.
  1.4179 +    // If the loop has that exact form, then:
  1.4180 +    // - forLetImpliedBlock is the node for the implicit block scope.
  1.4181 +    // - forLetDecl is the node for the decl 'let <vars>'.
  1.4182 +    // Otherwise both are null.
  1.4183 +    ParseNode *forLetImpliedBlock = nullptr;
  1.4184 +    ParseNode *forLetDecl = nullptr;
  1.4185 +
  1.4186 +    // If non-null, the node for the decl 'var v = expr1' in the weirdo form
  1.4187 +    // 'for (var v = expr1 in expr2) stmt'.
  1.4188 +    ParseNode *hoistedVar = nullptr;
  1.4189 +
  1.4190 +    /*
  1.4191 +     * We can be sure that it's a for/in loop if there's still an 'in'
  1.4192 +     * keyword here, even if JavaScript recognizes 'in' as an operator,
  1.4193 +     * as we've excluded 'in' from being parsed in RelExpr by setting
  1.4194 +     * pc->parsingForInit.
  1.4195 +     */
  1.4196 +    StmtInfoPC letStmt(context); /* used if blockObj != nullptr. */
  1.4197 +    ParseNode *pn2, *pn3;      /* forHead->pn_kid2 and pn_kid3. */
  1.4198 +    ParseNodeKind headKind = PNK_FORHEAD;
  1.4199 +    if (pn1) {
  1.4200 +        bool isForOf;
  1.4201 +        if (matchInOrOf(&isForOf))
  1.4202 +            headKind = isForOf ? PNK_FOROF : PNK_FORIN;
  1.4203 +    }
  1.4204 +
  1.4205 +    if (headKind == PNK_FOROF || headKind == PNK_FORIN) {
  1.4206 +        /*
  1.4207 +         * Parse the rest of the for/in or for/of head.
  1.4208 +         *
  1.4209 +         * Here pn1 is everything to the left of 'in' or 'of'. At the end of
  1.4210 +         * this block, pn1 is a decl or nullptr, pn2 is the assignment target
  1.4211 +         * that receives the enumeration value each iteration, and pn3 is the
  1.4212 +         * rhs of 'in'.
  1.4213 +         */
  1.4214 +        if (headKind == PNK_FOROF) {
  1.4215 +            forStmt.type = STMT_FOR_OF_LOOP;
  1.4216 +            forStmt.type = (headKind == PNK_FOROF) ? STMT_FOR_OF_LOOP : STMT_FOR_IN_LOOP;
  1.4217 +            if (isForEach) {
  1.4218 +                report(ParseError, false, null(), JSMSG_BAD_FOR_EACH_LOOP);
  1.4219 +                return null();
  1.4220 +            }
  1.4221 +        } else {
  1.4222 +            forStmt.type = STMT_FOR_IN_LOOP;
  1.4223 +            iflags |= JSITER_ENUMERATE;
  1.4224 +        }
  1.4225 +
  1.4226 +        /* Check that the left side of the 'in' or 'of' is valid. */
  1.4227 +        if (!isValidForStatementLHS(pn1, versionNumber(), isForDecl, isForEach, headKind)) {
  1.4228 +            report(ParseError, false, pn1, JSMSG_BAD_FOR_LEFTSIDE);
  1.4229 +            return null();
  1.4230 +        }
  1.4231 +
  1.4232 +        /*
  1.4233 +         * After the following if-else, pn2 will point to the name or
  1.4234 +         * destructuring pattern on in's left. pn1 will point to the decl, if
  1.4235 +         * any, else nullptr. Note that the "declaration with initializer" case
  1.4236 +         * rewrites the loop-head, moving the decl and setting pn1 to nullptr.
  1.4237 +         */
  1.4238 +        if (isForDecl) {
  1.4239 +            pn2 = pn1->pn_head;
  1.4240 +            if ((pn2->isKind(PNK_NAME) && pn2->maybeExpr()) || pn2->isKind(PNK_ASSIGN)) {
  1.4241 +                /*
  1.4242 +                 * Declaration with initializer.
  1.4243 +                 *
  1.4244 +                 * Rewrite 'for (<decl> x = i in o)' where <decl> is 'var' or
  1.4245 +                 * 'const' to hoist the initializer or the entire decl out of
  1.4246 +                 * the loop head.
  1.4247 +                 */
  1.4248 +                if (headKind == PNK_FOROF) {
  1.4249 +                    report(ParseError, false, pn2, JSMSG_INVALID_FOR_OF_INIT);
  1.4250 +                    return null();
  1.4251 +                }
  1.4252 +                if (blockObj) {
  1.4253 +                    report(ParseError, false, pn2, JSMSG_INVALID_FOR_IN_INIT);
  1.4254 +                    return null();
  1.4255 +                }
  1.4256 +
  1.4257 +                hoistedVar = pn1;
  1.4258 +
  1.4259 +                /*
  1.4260 +                 * All of 'var x = i' is hoisted above 'for (x in o)'.
  1.4261 +                 *
  1.4262 +                 * Request JSOP_POP here since the var is for a simple
  1.4263 +                 * name (it is not a destructuring binding's left-hand
  1.4264 +                 * side) and it has an initializer.
  1.4265 +                 */
  1.4266 +                pn1->pn_xflags |= PNX_POPVAR;
  1.4267 +                pn1 = nullptr;
  1.4268 +
  1.4269 +                if (pn2->isKind(PNK_ASSIGN)) {
  1.4270 +                    pn2 = pn2->pn_left;
  1.4271 +                    JS_ASSERT(pn2->isKind(PNK_ARRAY) || pn2->isKind(PNK_OBJECT) ||
  1.4272 +                              pn2->isKind(PNK_NAME));
  1.4273 +                }
  1.4274 +            }
  1.4275 +        } else {
  1.4276 +            /* Not a declaration. */
  1.4277 +            JS_ASSERT(!blockObj);
  1.4278 +            pn2 = pn1;
  1.4279 +            pn1 = nullptr;
  1.4280 +
  1.4281 +            if (!checkAndMarkAsAssignmentLhs(pn2, PlainAssignment))
  1.4282 +                return null();
  1.4283 +        }
  1.4284 +
  1.4285 +        pn3 = (headKind == PNK_FOROF) ? assignExpr() : expr();
  1.4286 +        if (!pn3)
  1.4287 +            return null();
  1.4288 +
  1.4289 +        if (blockObj) {
  1.4290 +            /*
  1.4291 +             * Now that the pn3 has been parsed, push the let scope. To hold
  1.4292 +             * the blockObj for the emitter, wrap the PNK_LEXICALSCOPE node
  1.4293 +             * created by PushLetScope around the for's initializer. This also
  1.4294 +             * serves to indicate the let-decl to the emitter.
  1.4295 +             */
  1.4296 +            ParseNode *block = pushLetScope(blockObj, &letStmt);
  1.4297 +            if (!block)
  1.4298 +                return null();
  1.4299 +            letStmt.isForLetBlock = true;
  1.4300 +            block->pn_expr = pn1;
  1.4301 +            block->pn_pos = pn1->pn_pos;
  1.4302 +            pn1 = block;
  1.4303 +        }
  1.4304 +
  1.4305 +        if (isForDecl) {
  1.4306 +            /*
  1.4307 +             * pn2 is part of a declaration. Make a copy that can be passed to
  1.4308 +             * EmitAssignment. Take care to do this after PushLetScope.
  1.4309 +             */
  1.4310 +            pn2 = cloneLeftHandSide(pn2);
  1.4311 +            if (!pn2)
  1.4312 +                return null();
  1.4313 +        }
  1.4314 +
  1.4315 +        switch (pn2->getKind()) {
  1.4316 +          case PNK_NAME:
  1.4317 +            /* Beware 'for (arguments in ...)' with or without a 'var'. */
  1.4318 +            pn2->markAsAssigned();
  1.4319 +            break;
  1.4320 +
  1.4321 +          case PNK_ASSIGN:
  1.4322 +            MOZ_ASSUME_UNREACHABLE("forStatement TOK_ASSIGN");
  1.4323 +
  1.4324 +          case PNK_ARRAY:
  1.4325 +          case PNK_OBJECT:
  1.4326 +            if (versionNumber() == JSVERSION_1_7) {
  1.4327 +                /*
  1.4328 +                 * Destructuring for-in requires [key, value] enumeration
  1.4329 +                 * in JS1.7.
  1.4330 +                 */
  1.4331 +                if (!isForEach && headKind == PNK_FORIN)
  1.4332 +                    iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
  1.4333 +            }
  1.4334 +            break;
  1.4335 +
  1.4336 +          default:;
  1.4337 +        }
  1.4338 +    } else {
  1.4339 +        if (isForEach) {
  1.4340 +            reportWithOffset(ParseError, false, begin, JSMSG_BAD_FOR_EACH_LOOP);
  1.4341 +            return null();
  1.4342 +        }
  1.4343 +
  1.4344 +        headKind = PNK_FORHEAD;
  1.4345 +
  1.4346 +        if (blockObj) {
  1.4347 +            /*
  1.4348 +             * Desugar 'for (let A; B; C) D' into 'let (A) { for (; B; C) D }'
  1.4349 +             * to induce the correct scoping for A.
  1.4350 +             */
  1.4351 +            forLetImpliedBlock = pushLetScope(blockObj, &letStmt);
  1.4352 +            if (!forLetImpliedBlock)
  1.4353 +                return null();
  1.4354 +            letStmt.isForLetBlock = true;
  1.4355 +
  1.4356 +            forLetDecl = pn1;
  1.4357 +            pn1 = nullptr;
  1.4358 +        }
  1.4359 +
  1.4360 +        /* Parse the loop condition or null into pn2. */
  1.4361 +        MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
  1.4362 +        if (tokenStream.peekToken(TokenStream::Operand) == TOK_SEMI) {
  1.4363 +            pn2 = nullptr;
  1.4364 +        } else {
  1.4365 +            pn2 = expr();
  1.4366 +            if (!pn2)
  1.4367 +                return null();
  1.4368 +        }
  1.4369 +
  1.4370 +        /* Parse the update expression or null into pn3. */
  1.4371 +        MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND);
  1.4372 +        if (tokenStream.peekToken(TokenStream::Operand) == TOK_RP) {
  1.4373 +            pn3 = nullptr;
  1.4374 +        } else {
  1.4375 +            pn3 = expr();
  1.4376 +            if (!pn3)
  1.4377 +                return null();
  1.4378 +        }
  1.4379 +    }
  1.4380 +
  1.4381 +    MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
  1.4382 +
  1.4383 +    TokenPos headPos(begin, pos().end);
  1.4384 +    ParseNode *forHead = handler.newForHead(headKind, pn1, pn2, pn3, headPos);
  1.4385 +    if (!forHead)
  1.4386 +        return null();
  1.4387 +
  1.4388 +    /* Parse the loop body. */
  1.4389 +    ParseNode *body = statement();
  1.4390 +    if (!body)
  1.4391 +        return null();
  1.4392 +
  1.4393 +    if (blockObj)
  1.4394 +        PopStatementPC(tokenStream, pc);
  1.4395 +    PopStatementPC(tokenStream, pc);
  1.4396 +
  1.4397 +    ParseNode *forLoop = handler.newForStatement(begin, forHead, body, iflags);
  1.4398 +    if (!forLoop)
  1.4399 +        return null();
  1.4400 +
  1.4401 +    if (hoistedVar) {
  1.4402 +        ParseNode *pnseq = handler.newList(PNK_SEQ, hoistedVar);
  1.4403 +        if (!pnseq)
  1.4404 +            return null();
  1.4405 +        pnseq->pn_pos = forLoop->pn_pos;
  1.4406 +        pnseq->append(forLoop);
  1.4407 +        return pnseq;
  1.4408 +    }
  1.4409 +    if (forLetImpliedBlock) {
  1.4410 +        forLetImpliedBlock->pn_expr = forLoop;
  1.4411 +        forLetImpliedBlock->pn_pos = forLoop->pn_pos;
  1.4412 +        ParseNode *let = handler.newBinary(PNK_LET, forLetDecl, forLetImpliedBlock);
  1.4413 +        if (!let)
  1.4414 +            return null();
  1.4415 +        let->pn_pos = forLoop->pn_pos;
  1.4416 +        return let;
  1.4417 +    }
  1.4418 +    return forLoop;
  1.4419 +}
  1.4420 +
  1.4421 +template <>
  1.4422 +SyntaxParseHandler::Node
  1.4423 +Parser<SyntaxParseHandler>::forStatement()
  1.4424 +{
  1.4425 +    /*
  1.4426 +     * 'for' statement parsing is fantastically complicated and requires being
  1.4427 +     * able to inspect the parse tree for previous parts of the 'for'. Syntax
  1.4428 +     * parsing of 'for' statements is thus done separately, and only handles
  1.4429 +     * the types of 'for' statements likely to be seen in web content.
  1.4430 +     */
  1.4431 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
  1.4432 +
  1.4433 +    StmtInfoPC forStmt(context);
  1.4434 +    PushStatementPC(pc, &forStmt, STMT_FOR_LOOP);
  1.4435 +
  1.4436 +    /* Don't parse 'for each' loops. */
  1.4437 +    if (allowsForEachIn()) {
  1.4438 +        TokenKind tt = tokenStream.peekToken();
  1.4439 +        // Not all "yield" tokens are names, but the ones that aren't names are
  1.4440 +        // invalid in this context anyway.
  1.4441 +        if (tt == TOK_NAME || tt == TOK_YIELD) {
  1.4442 +            JS_ALWAYS_FALSE(abortIfSyntaxParser());
  1.4443 +            return null();
  1.4444 +        }
  1.4445 +    }
  1.4446 +
  1.4447 +    MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
  1.4448 +
  1.4449 +    /* True if we have 'for (var ...)'. */
  1.4450 +    bool isForDecl = false;
  1.4451 +    bool simpleForDecl = true;
  1.4452 +
  1.4453 +    /* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
  1.4454 +    Node lhsNode;
  1.4455 +
  1.4456 +    {
  1.4457 +        TokenKind tt = tokenStream.peekToken(TokenStream::Operand);
  1.4458 +        if (tt == TOK_SEMI) {
  1.4459 +            lhsNode = null();
  1.4460 +        } else {
  1.4461 +            /* Set lhsNode to a var list or an initializing expression. */
  1.4462 +            pc->parsingForInit = true;
  1.4463 +            if (tt == TOK_VAR) {
  1.4464 +                isForDecl = true;
  1.4465 +                tokenStream.consumeKnownToken(tt);
  1.4466 +                lhsNode = variables(tt == TOK_VAR ? PNK_VAR : PNK_CONST, &simpleForDecl);
  1.4467 +            }
  1.4468 +            else if (tt == TOK_CONST || tt == TOK_LET) {
  1.4469 +                JS_ALWAYS_FALSE(abortIfSyntaxParser());
  1.4470 +                return null();
  1.4471 +            }
  1.4472 +            else {
  1.4473 +                lhsNode = expr();
  1.4474 +            }
  1.4475 +            if (!lhsNode)
  1.4476 +                return null();
  1.4477 +            pc->parsingForInit = false;
  1.4478 +        }
  1.4479 +    }
  1.4480 +
  1.4481 +    /*
  1.4482 +     * We can be sure that it's a for/in loop if there's still an 'in'
  1.4483 +     * keyword here, even if JavaScript recognizes 'in' as an operator,
  1.4484 +     * as we've excluded 'in' from being parsed in RelExpr by setting
  1.4485 +     * pc->parsingForInit.
  1.4486 +     */
  1.4487 +    bool isForOf;
  1.4488 +    if (lhsNode && matchInOrOf(&isForOf)) {
  1.4489 +        /* Parse the rest of the for/in or for/of head. */
  1.4490 +        forStmt.type = isForOf ? STMT_FOR_OF_LOOP : STMT_FOR_IN_LOOP;
  1.4491 +
  1.4492 +        /* Check that the left side of the 'in' or 'of' is valid. */
  1.4493 +        if (!isForDecl &&
  1.4494 +            lhsNode != SyntaxParseHandler::NodeName &&
  1.4495 +            lhsNode != SyntaxParseHandler::NodeGetProp &&
  1.4496 +            lhsNode != SyntaxParseHandler::NodeLValue)
  1.4497 +        {
  1.4498 +            JS_ALWAYS_FALSE(abortIfSyntaxParser());
  1.4499 +            return null();
  1.4500 +        }
  1.4501 +
  1.4502 +        if (!simpleForDecl) {
  1.4503 +            JS_ALWAYS_FALSE(abortIfSyntaxParser());
  1.4504 +            return null();
  1.4505 +        }
  1.4506 +
  1.4507 +        if (!isForDecl && !checkAndMarkAsAssignmentLhs(lhsNode, PlainAssignment))
  1.4508 +            return null();
  1.4509 +
  1.4510 +        if (!expr())
  1.4511 +            return null();
  1.4512 +    } else {
  1.4513 +        /* Parse the loop condition or null. */
  1.4514 +        MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
  1.4515 +        if (tokenStream.peekToken(TokenStream::Operand) != TOK_SEMI) {
  1.4516 +            if (!expr())
  1.4517 +                return null();
  1.4518 +        }
  1.4519 +
  1.4520 +        /* Parse the update expression or null. */
  1.4521 +        MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND);
  1.4522 +        if (tokenStream.peekToken(TokenStream::Operand) != TOK_RP) {
  1.4523 +            if (!expr())
  1.4524 +                return null();
  1.4525 +        }
  1.4526 +    }
  1.4527 +
  1.4528 +    MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
  1.4529 +
  1.4530 +    /* Parse the loop body. */
  1.4531 +    if (!statement())
  1.4532 +        return null();
  1.4533 +
  1.4534 +    PopStatementPC(tokenStream, pc);
  1.4535 +    return SyntaxParseHandler::NodeGeneric;
  1.4536 +}
  1.4537 +
  1.4538 +template <typename ParseHandler>
  1.4539 +typename ParseHandler::Node
  1.4540 +Parser<ParseHandler>::switchStatement()
  1.4541 +{
  1.4542 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_SWITCH));
  1.4543 +    uint32_t begin = pos().begin;
  1.4544 +
  1.4545 +    MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH);
  1.4546 +
  1.4547 +    Node discriminant = exprInParens();
  1.4548 +    if (!discriminant)
  1.4549 +        return null();
  1.4550 +
  1.4551 +    MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_SWITCH);
  1.4552 +    MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH);
  1.4553 +
  1.4554 +    StmtInfoPC stmtInfo(context);
  1.4555 +    PushStatementPC(pc, &stmtInfo, STMT_SWITCH);
  1.4556 +
  1.4557 +    if (!GenerateBlockId(tokenStream, pc, pc->topStmt->blockid))
  1.4558 +        return null();
  1.4559 +
  1.4560 +    Node caseList = handler.newStatementList(pc->blockid(), pos());
  1.4561 +    if (!caseList)
  1.4562 +        return null();
  1.4563 +
  1.4564 +    Node saveBlock = pc->blockNode;
  1.4565 +    pc->blockNode = caseList;
  1.4566 +
  1.4567 +    bool seenDefault = false;
  1.4568 +    TokenKind tt;
  1.4569 +    while ((tt = tokenStream.getToken()) != TOK_RC) {
  1.4570 +        uint32_t caseBegin = pos().begin;
  1.4571 +
  1.4572 +        Node caseExpr;
  1.4573 +        switch (tt) {
  1.4574 +          case TOK_DEFAULT:
  1.4575 +            if (seenDefault) {
  1.4576 +                report(ParseError, false, null(), JSMSG_TOO_MANY_DEFAULTS);
  1.4577 +                return null();
  1.4578 +            }
  1.4579 +            seenDefault = true;
  1.4580 +            caseExpr = null();  // The default case has pn_left == nullptr.
  1.4581 +            break;
  1.4582 +
  1.4583 +          case TOK_CASE:
  1.4584 +            caseExpr = expr();
  1.4585 +            if (!caseExpr)
  1.4586 +                return null();
  1.4587 +            break;
  1.4588 +
  1.4589 +          case TOK_ERROR:
  1.4590 +            return null();
  1.4591 +
  1.4592 +          default:
  1.4593 +            report(ParseError, false, null(), JSMSG_BAD_SWITCH);
  1.4594 +            return null();
  1.4595 +        }
  1.4596 +
  1.4597 +        MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE);
  1.4598 +
  1.4599 +        Node body = handler.newStatementList(pc->blockid(), pos());
  1.4600 +        if (!body)
  1.4601 +            return null();
  1.4602 +
  1.4603 +        while ((tt = tokenStream.peekToken(TokenStream::Operand)) != TOK_RC &&
  1.4604 +               tt != TOK_CASE && tt != TOK_DEFAULT) {
  1.4605 +            if (tt == TOK_ERROR)
  1.4606 +                return null();
  1.4607 +            Node stmt = statement();
  1.4608 +            if (!stmt)
  1.4609 +                return null();
  1.4610 +            handler.addList(body, stmt);
  1.4611 +        }
  1.4612 +
  1.4613 +        Node casepn = handler.newCaseOrDefault(caseBegin, caseExpr, body);
  1.4614 +        if (!casepn)
  1.4615 +            return null();
  1.4616 +        handler.addList(caseList, casepn);
  1.4617 +    }
  1.4618 +
  1.4619 +    /*
  1.4620 +     * Handle the case where there was a let declaration in any case in
  1.4621 +     * the switch body, but not within an inner block.  If it replaced
  1.4622 +     * pc->blockNode with a new block node then we must refresh caseList and
  1.4623 +     * then restore pc->blockNode.
  1.4624 +     */
  1.4625 +    if (pc->blockNode != caseList)
  1.4626 +        caseList = pc->blockNode;
  1.4627 +    pc->blockNode = saveBlock;
  1.4628 +
  1.4629 +    PopStatementPC(tokenStream, pc);
  1.4630 +
  1.4631 +    handler.setEndPosition(caseList, pos().end);
  1.4632 +
  1.4633 +    return handler.newSwitchStatement(begin, discriminant, caseList);
  1.4634 +}
  1.4635 +
  1.4636 +template <typename ParseHandler>
  1.4637 +typename ParseHandler::Node
  1.4638 +Parser<ParseHandler>::continueStatement()
  1.4639 +{
  1.4640 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_CONTINUE));
  1.4641 +    uint32_t begin = pos().begin;
  1.4642 +
  1.4643 +    RootedPropertyName label(context);
  1.4644 +    if (!matchLabel(&label))
  1.4645 +        return null();
  1.4646 +
  1.4647 +    StmtInfoPC *stmt = pc->topStmt;
  1.4648 +    if (label) {
  1.4649 +        for (StmtInfoPC *stmt2 = nullptr; ; stmt = stmt->down) {
  1.4650 +            if (!stmt) {
  1.4651 +                report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND);
  1.4652 +                return null();
  1.4653 +            }
  1.4654 +            if (stmt->type == STMT_LABEL) {
  1.4655 +                if (stmt->label == label) {
  1.4656 +                    if (!stmt2 || !stmt2->isLoop()) {
  1.4657 +                        report(ParseError, false, null(), JSMSG_BAD_CONTINUE);
  1.4658 +                        return null();
  1.4659 +                    }
  1.4660 +                    break;
  1.4661 +                }
  1.4662 +            } else {
  1.4663 +                stmt2 = stmt;
  1.4664 +            }
  1.4665 +        }
  1.4666 +    } else {
  1.4667 +        for (; ; stmt = stmt->down) {
  1.4668 +            if (!stmt) {
  1.4669 +                report(ParseError, false, null(), JSMSG_BAD_CONTINUE);
  1.4670 +                return null();
  1.4671 +            }
  1.4672 +            if (stmt->isLoop())
  1.4673 +                break;
  1.4674 +        }
  1.4675 +    }
  1.4676 +
  1.4677 +    if (!MatchOrInsertSemicolon(tokenStream))
  1.4678 +        return null();
  1.4679 +
  1.4680 +    return handler.newContinueStatement(label, TokenPos(begin, pos().end));
  1.4681 +}
  1.4682 +
  1.4683 +template <typename ParseHandler>
  1.4684 +typename ParseHandler::Node
  1.4685 +Parser<ParseHandler>::breakStatement()
  1.4686 +{
  1.4687 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_BREAK));
  1.4688 +    uint32_t begin = pos().begin;
  1.4689 +
  1.4690 +    RootedPropertyName label(context);
  1.4691 +    if (!matchLabel(&label))
  1.4692 +        return null();
  1.4693 +    StmtInfoPC *stmt = pc->topStmt;
  1.4694 +    if (label) {
  1.4695 +        for (; ; stmt = stmt->down) {
  1.4696 +            if (!stmt) {
  1.4697 +                report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND);
  1.4698 +                return null();
  1.4699 +            }
  1.4700 +            if (stmt->type == STMT_LABEL && stmt->label == label)
  1.4701 +                break;
  1.4702 +        }
  1.4703 +    } else {
  1.4704 +        for (; ; stmt = stmt->down) {
  1.4705 +            if (!stmt) {
  1.4706 +                report(ParseError, false, null(), JSMSG_TOUGH_BREAK);
  1.4707 +                return null();
  1.4708 +            }
  1.4709 +            if (stmt->isLoop() || stmt->type == STMT_SWITCH)
  1.4710 +                break;
  1.4711 +        }
  1.4712 +    }
  1.4713 +
  1.4714 +    if (!MatchOrInsertSemicolon(tokenStream))
  1.4715 +        return null();
  1.4716 +
  1.4717 +    return handler.newBreakStatement(label, TokenPos(begin, pos().end));
  1.4718 +}
  1.4719 +
  1.4720 +template <typename ParseHandler>
  1.4721 +typename ParseHandler::Node
  1.4722 +Parser<ParseHandler>::returnStatement()
  1.4723 +{
  1.4724 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_RETURN));
  1.4725 +    uint32_t begin = pos().begin;
  1.4726 +
  1.4727 +    if (!pc->sc->isFunctionBox()) {
  1.4728 +        report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
  1.4729 +        return null();
  1.4730 +    }
  1.4731 +
  1.4732 +    // Parse an optional operand.
  1.4733 +    //
  1.4734 +    // This is ugly, but we don't want to require a semicolon.
  1.4735 +    Node exprNode;
  1.4736 +    switch (tokenStream.peekTokenSameLine(TokenStream::Operand)) {
  1.4737 +      case TOK_ERROR:
  1.4738 +        return null();
  1.4739 +      case TOK_EOF:
  1.4740 +      case TOK_EOL:
  1.4741 +      case TOK_SEMI:
  1.4742 +      case TOK_RC:
  1.4743 +        exprNode = null();
  1.4744 +        pc->funHasReturnVoid = true;
  1.4745 +        break;
  1.4746 +      default: {
  1.4747 +        exprNode = expr();
  1.4748 +        if (!exprNode)
  1.4749 +            return null();
  1.4750 +        pc->funHasReturnExpr = true;
  1.4751 +      }
  1.4752 +    }
  1.4753 +
  1.4754 +    if (!MatchOrInsertSemicolon(tokenStream))
  1.4755 +        return null();
  1.4756 +
  1.4757 +    Node pn = handler.newReturnStatement(exprNode, TokenPos(begin, pos().end));
  1.4758 +    if (!pn)
  1.4759 +        return null();
  1.4760 +
  1.4761 +    if (options().extraWarningsOption && pc->funHasReturnExpr && pc->funHasReturnVoid &&
  1.4762 +        !reportBadReturn(pn, ParseExtraWarning,
  1.4763 +                         JSMSG_NO_RETURN_VALUE, JSMSG_ANON_NO_RETURN_VALUE))
  1.4764 +    {
  1.4765 +        return null();
  1.4766 +    }
  1.4767 +
  1.4768 +    if (pc->isLegacyGenerator() && exprNode) {
  1.4769 +        /* Disallow "return v;" in legacy generators. */
  1.4770 +        reportBadReturn(pn, ParseError, JSMSG_BAD_GENERATOR_RETURN,
  1.4771 +                        JSMSG_BAD_ANON_GENERATOR_RETURN);
  1.4772 +        return null();
  1.4773 +    }
  1.4774 +
  1.4775 +    return pn;
  1.4776 +}
  1.4777 +
  1.4778 +template <typename ParseHandler>
  1.4779 +typename ParseHandler::Node
  1.4780 +Parser<ParseHandler>::yieldExpression()
  1.4781 +{
  1.4782 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_YIELD));
  1.4783 +    uint32_t begin = pos().begin;
  1.4784 +
  1.4785 +    switch (pc->generatorKind()) {
  1.4786 +      case StarGenerator:
  1.4787 +      {
  1.4788 +        JS_ASSERT(pc->sc->isFunctionBox());
  1.4789 +
  1.4790 +        pc->lastYieldOffset = begin;
  1.4791 +
  1.4792 +        ParseNodeKind kind = tokenStream.matchToken(TOK_MUL) ? PNK_YIELD_STAR : PNK_YIELD;
  1.4793 +
  1.4794 +        // ES6 generators require a value.
  1.4795 +        Node exprNode = assignExpr();
  1.4796 +        if (!exprNode)
  1.4797 +            return null();
  1.4798 +
  1.4799 +        return handler.newUnary(kind, JSOP_NOP, begin, exprNode);
  1.4800 +      }
  1.4801 +
  1.4802 +      case NotGenerator:
  1.4803 +        // We are in code that has not seen a yield, but we are in JS 1.7 or
  1.4804 +        // later.  Try to transition to being a legacy generator.
  1.4805 +        JS_ASSERT(tokenStream.versionNumber() >= JSVERSION_1_7);
  1.4806 +        JS_ASSERT(pc->lastYieldOffset == ParseContext<ParseHandler>::NoYieldOffset);
  1.4807 +
  1.4808 +        if (!abortIfSyntaxParser())
  1.4809 +            return null();
  1.4810 +
  1.4811 +        if (!pc->sc->isFunctionBox()) {
  1.4812 +            report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_yield_str);
  1.4813 +            return null();
  1.4814 +        }
  1.4815 +
  1.4816 +        pc->sc->asFunctionBox()->setGeneratorKind(LegacyGenerator);
  1.4817 +
  1.4818 +        if (pc->funHasReturnExpr) {
  1.4819 +            /* As in Python (see PEP-255), disallow return v; in generators. */
  1.4820 +            reportBadReturn(null(), ParseError, JSMSG_BAD_GENERATOR_RETURN,
  1.4821 +                            JSMSG_BAD_ANON_GENERATOR_RETURN);
  1.4822 +            return null();
  1.4823 +        }
  1.4824 +        // Fall through.
  1.4825 +
  1.4826 +      case LegacyGenerator:
  1.4827 +      {
  1.4828 +        // We are in a legacy generator: a function that has already seen a
  1.4829 +        // yield, or in a legacy generator comprehension.
  1.4830 +        JS_ASSERT(pc->sc->isFunctionBox());
  1.4831 +
  1.4832 +        pc->lastYieldOffset = begin;
  1.4833 +
  1.4834 +        // Legacy generators do not require a value.
  1.4835 +        Node exprNode;
  1.4836 +        switch (tokenStream.peekTokenSameLine(TokenStream::Operand)) {
  1.4837 +          case TOK_ERROR:
  1.4838 +            return null();
  1.4839 +          case TOK_EOF:
  1.4840 +          case TOK_EOL:
  1.4841 +          case TOK_SEMI:
  1.4842 +          case TOK_RC:
  1.4843 +          case TOK_RB:
  1.4844 +          case TOK_RP:
  1.4845 +          case TOK_COLON:
  1.4846 +          case TOK_COMMA:
  1.4847 +            // No value.
  1.4848 +            exprNode = null();
  1.4849 +            // ES6 does not permit yield without an operand.  We should
  1.4850 +            // encourage users of yield expressions of this kind to pass an
  1.4851 +            // operand, to bring users closer to standard syntax.
  1.4852 +            if (!reportWithOffset(ParseWarning, false, pos().begin, JSMSG_YIELD_WITHOUT_OPERAND))
  1.4853 +                return null();
  1.4854 +            break;
  1.4855 +          default:
  1.4856 +            exprNode = assignExpr();
  1.4857 +            if (!exprNode)
  1.4858 +                return null();
  1.4859 +        }
  1.4860 +
  1.4861 +        return handler.newUnary(PNK_YIELD, JSOP_NOP, begin, exprNode);
  1.4862 +      }
  1.4863 +    }
  1.4864 +
  1.4865 +    MOZ_ASSUME_UNREACHABLE("yieldExpr");
  1.4866 +}
  1.4867 +
  1.4868 +template <>
  1.4869 +ParseNode *
  1.4870 +Parser<FullParseHandler>::withStatement()
  1.4871 +{
  1.4872 +    // test262/ch12/12.10/12.10-0-1.js fails if we try to parse with-statements
  1.4873 +    // in syntax-parse mode. See bug 892583.
  1.4874 +    if (handler.syntaxParser) {
  1.4875 +        handler.disableSyntaxParser();
  1.4876 +        abortedSyntaxParse = true;
  1.4877 +        return null();
  1.4878 +    }
  1.4879 +
  1.4880 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_WITH));
  1.4881 +    uint32_t begin = pos().begin;
  1.4882 +
  1.4883 +    // In most cases, we want the constructs forbidden in strict mode code to be
  1.4884 +    // a subset of those that JSOPTION_EXTRA_WARNINGS warns about, and we should
  1.4885 +    // use reportStrictModeError.  However, 'with' is the sole instance of a
  1.4886 +    // construct that is forbidden in strict mode code, but doesn't even merit a
  1.4887 +    // warning under JSOPTION_EXTRA_WARNINGS.  See
  1.4888 +    // https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1.
  1.4889 +    if (pc->sc->strict && !report(ParseStrictError, true, null(), JSMSG_STRICT_CODE_WITH))
  1.4890 +        return null();
  1.4891 +
  1.4892 +    MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH);
  1.4893 +    Node objectExpr = exprInParens();
  1.4894 +    if (!objectExpr)
  1.4895 +        return null();
  1.4896 +    MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH);
  1.4897 +
  1.4898 +    bool oldParsingWith = pc->parsingWith;
  1.4899 +    pc->parsingWith = true;
  1.4900 +
  1.4901 +    StmtInfoPC stmtInfo(context);
  1.4902 +    PushStatementPC(pc, &stmtInfo, STMT_WITH);
  1.4903 +    Rooted<StaticWithObject *> staticWith(context, StaticWithObject::create(context));
  1.4904 +    if (!staticWith)
  1.4905 +        return null();
  1.4906 +    staticWith->initEnclosingNestedScopeFromParser(pc->staticScope);
  1.4907 +    FinishPushNestedScope(pc, &stmtInfo, *staticWith);
  1.4908 +
  1.4909 +    Node innerBlock = statement();
  1.4910 +    if (!innerBlock)
  1.4911 +        return null();
  1.4912 +
  1.4913 +    PopStatementPC(tokenStream, pc);
  1.4914 +
  1.4915 +    pc->sc->setBindingsAccessedDynamically();
  1.4916 +    pc->parsingWith = oldParsingWith;
  1.4917 +
  1.4918 +    /*
  1.4919 +     * Make sure to deoptimize lexical dependencies inside the |with|
  1.4920 +     * to safely optimize binding globals (see bug 561923).
  1.4921 +     */
  1.4922 +    for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) {
  1.4923 +        DefinitionNode defn = r.front().value().get<FullParseHandler>();
  1.4924 +        DefinitionNode lexdep = handler.resolve(defn);
  1.4925 +        handler.deoptimizeUsesWithin(lexdep, TokenPos(begin, pos().begin));
  1.4926 +    }
  1.4927 +
  1.4928 +    ObjectBox *staticWithBox = newObjectBox(staticWith);
  1.4929 +    if (!staticWithBox)
  1.4930 +        return null();
  1.4931 +    return handler.newWithStatement(begin, objectExpr, innerBlock, staticWithBox);
  1.4932 +}
  1.4933 +
  1.4934 +template <>
  1.4935 +SyntaxParseHandler::Node
  1.4936 +Parser<SyntaxParseHandler>::withStatement()
  1.4937 +{
  1.4938 +    JS_ALWAYS_FALSE(abortIfSyntaxParser());
  1.4939 +    return null();
  1.4940 +}
  1.4941 +
  1.4942 +template <typename ParseHandler>
  1.4943 +typename ParseHandler::Node
  1.4944 +Parser<ParseHandler>::labeledStatement()
  1.4945 +{
  1.4946 +    uint32_t begin = pos().begin;
  1.4947 +    RootedPropertyName label(context, tokenStream.currentName());
  1.4948 +    for (StmtInfoPC *stmt = pc->topStmt; stmt; stmt = stmt->down) {
  1.4949 +        if (stmt->type == STMT_LABEL && stmt->label == label) {
  1.4950 +            report(ParseError, false, null(), JSMSG_DUPLICATE_LABEL);
  1.4951 +            return null();
  1.4952 +        }
  1.4953 +    }
  1.4954 +
  1.4955 +    tokenStream.consumeKnownToken(TOK_COLON);
  1.4956 +
  1.4957 +    /* Push a label struct and parse the statement. */
  1.4958 +    StmtInfoPC stmtInfo(context);
  1.4959 +    PushStatementPC(pc, &stmtInfo, STMT_LABEL);
  1.4960 +    stmtInfo.label = label;
  1.4961 +    Node pn = statement();
  1.4962 +    if (!pn)
  1.4963 +        return null();
  1.4964 +
  1.4965 +    /* Pop the label, set pn_expr, and return early. */
  1.4966 +    PopStatementPC(tokenStream, pc);
  1.4967 +
  1.4968 +    return handler.newLabeledStatement(label, pn, begin);
  1.4969 +}
  1.4970 +
  1.4971 +template <typename ParseHandler>
  1.4972 +typename ParseHandler::Node
  1.4973 +Parser<ParseHandler>::throwStatement()
  1.4974 +{
  1.4975 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_THROW));
  1.4976 +    uint32_t begin = pos().begin;
  1.4977 +
  1.4978 +    /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */
  1.4979 +    TokenKind tt = tokenStream.peekTokenSameLine(TokenStream::Operand);
  1.4980 +    if (tt == TOK_ERROR)
  1.4981 +        return null();
  1.4982 +    if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) {
  1.4983 +        report(ParseError, false, null(), JSMSG_SYNTAX_ERROR);
  1.4984 +        return null();
  1.4985 +    }
  1.4986 +
  1.4987 +    Node throwExpr = expr();
  1.4988 +    if (!throwExpr)
  1.4989 +        return null();
  1.4990 +
  1.4991 +    if (!MatchOrInsertSemicolon(tokenStream))
  1.4992 +        return null();
  1.4993 +
  1.4994 +    return handler.newThrowStatement(throwExpr, TokenPos(begin, pos().end));
  1.4995 +}
  1.4996 +
  1.4997 +template <typename ParseHandler>
  1.4998 +typename ParseHandler::Node
  1.4999 +Parser<ParseHandler>::tryStatement()
  1.5000 +{
  1.5001 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_TRY));
  1.5002 +    uint32_t begin = pos().begin;
  1.5003 +
  1.5004 +    /*
  1.5005 +     * try nodes are ternary.
  1.5006 +     * kid1 is the try statement
  1.5007 +     * kid2 is the catch node list or null
  1.5008 +     * kid3 is the finally statement
  1.5009 +     *
  1.5010 +     * catch nodes are ternary.
  1.5011 +     * kid1 is the lvalue (TOK_NAME, TOK_LB, or TOK_LC)
  1.5012 +     * kid2 is the catch guard or null if no guard
  1.5013 +     * kid3 is the catch block
  1.5014 +     *
  1.5015 +     * catch lvalue nodes are either:
  1.5016 +     *   TOK_NAME for a single identifier
  1.5017 +     *   TOK_RB or TOK_RC for a destructuring left-hand side
  1.5018 +     *
  1.5019 +     * finally nodes are TOK_LC statement lists.
  1.5020 +     */
  1.5021 +
  1.5022 +    MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
  1.5023 +    StmtInfoPC stmtInfo(context);
  1.5024 +    if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_TRY, pc))
  1.5025 +        return null();
  1.5026 +    Node innerBlock = statements();
  1.5027 +    if (!innerBlock)
  1.5028 +        return null();
  1.5029 +    MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_TRY);
  1.5030 +    PopStatementPC(tokenStream, pc);
  1.5031 +
  1.5032 +    bool hasUnconditionalCatch = false;
  1.5033 +    Node catchList = null();
  1.5034 +    TokenKind tt = tokenStream.getToken();
  1.5035 +    if (tt == TOK_CATCH) {
  1.5036 +        catchList = handler.newList(PNK_CATCH);
  1.5037 +        if (!catchList)
  1.5038 +            return null();
  1.5039 +
  1.5040 +        do {
  1.5041 +            Node pnblock;
  1.5042 +            BindData<ParseHandler> data(context);
  1.5043 +
  1.5044 +            /* Check for another catch after unconditional catch. */
  1.5045 +            if (hasUnconditionalCatch) {
  1.5046 +                report(ParseError, false, null(), JSMSG_CATCH_AFTER_GENERAL);
  1.5047 +                return null();
  1.5048 +            }
  1.5049 +
  1.5050 +            /*
  1.5051 +             * Create a lexical scope node around the whole catch clause,
  1.5052 +             * including the head.
  1.5053 +             */
  1.5054 +            pnblock = pushLexicalScope(&stmtInfo);
  1.5055 +            if (!pnblock)
  1.5056 +                return null();
  1.5057 +            stmtInfo.type = STMT_CATCH;
  1.5058 +
  1.5059 +            /*
  1.5060 +             * Legal catch forms are:
  1.5061 +             *   catch (lhs)
  1.5062 +             *   catch (lhs if <boolean_expression>)
  1.5063 +             * where lhs is a name or a destructuring left-hand side.
  1.5064 +             * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD)
  1.5065 +             */
  1.5066 +            MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
  1.5067 +
  1.5068 +            /*
  1.5069 +             * Contrary to ECMA Ed. 3, the catch variable is lexically
  1.5070 +             * scoped, not a property of a new Object instance.  This is
  1.5071 +             * an intentional change that anticipates ECMA Ed. 4.
  1.5072 +             */
  1.5073 +            data.initLet(HoistVars, pc->staticScope->template as<StaticBlockObject>(),
  1.5074 +                         JSMSG_TOO_MANY_CATCH_VARS);
  1.5075 +            JS_ASSERT(data.let.blockObj);
  1.5076 +
  1.5077 +            tt = tokenStream.getToken();
  1.5078 +            Node catchName;
  1.5079 +            switch (tt) {
  1.5080 +              case TOK_LB:
  1.5081 +              case TOK_LC:
  1.5082 +                catchName = destructuringExpr(&data, tt);
  1.5083 +                if (!catchName)
  1.5084 +                    return null();
  1.5085 +                break;
  1.5086 +
  1.5087 +              case TOK_YIELD:
  1.5088 +                if (!checkYieldNameValidity())
  1.5089 +                    return null();
  1.5090 +                // Fall through.
  1.5091 +              case TOK_NAME:
  1.5092 +              {
  1.5093 +                RootedPropertyName label(context, tokenStream.currentName());
  1.5094 +                catchName = newBindingNode(label, false);
  1.5095 +                if (!catchName)
  1.5096 +                    return null();
  1.5097 +                data.pn = catchName;
  1.5098 +                if (!data.binder(&data, label, this))
  1.5099 +                    return null();
  1.5100 +                break;
  1.5101 +              }
  1.5102 +
  1.5103 +              default:
  1.5104 +                report(ParseError, false, null(), JSMSG_CATCH_IDENTIFIER);
  1.5105 +                return null();
  1.5106 +            }
  1.5107 +
  1.5108 +            Node catchGuard = null();
  1.5109 +#if JS_HAS_CATCH_GUARD
  1.5110 +            /*
  1.5111 +             * We use 'catch (x if x === 5)' (not 'catch (x : x === 5)')
  1.5112 +             * to avoid conflicting with the JS2/ECMAv4 type annotation
  1.5113 +             * catchguard syntax.
  1.5114 +             */
  1.5115 +            if (tokenStream.matchToken(TOK_IF)) {
  1.5116 +                catchGuard = expr();
  1.5117 +                if (!catchGuard)
  1.5118 +                    return null();
  1.5119 +            }
  1.5120 +#endif
  1.5121 +            MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH);
  1.5122 +
  1.5123 +            MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);
  1.5124 +            Node catchBody = statements();
  1.5125 +            if (!catchBody)
  1.5126 +                return null();
  1.5127 +            MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_CATCH);
  1.5128 +            PopStatementPC(tokenStream, pc);
  1.5129 +
  1.5130 +            if (!catchGuard)
  1.5131 +                hasUnconditionalCatch = true;
  1.5132 +
  1.5133 +            if (!handler.addCatchBlock(catchList, pnblock, catchName, catchGuard, catchBody))
  1.5134 +                return null();
  1.5135 +            handler.setEndPosition(catchList, pos().end);
  1.5136 +            handler.setEndPosition(pnblock, pos().end);
  1.5137 +
  1.5138 +            tt = tokenStream.getToken(TokenStream::Operand);
  1.5139 +        } while (tt == TOK_CATCH);
  1.5140 +    }
  1.5141 +
  1.5142 +    Node finallyBlock = null();
  1.5143 +
  1.5144 +    if (tt == TOK_FINALLY) {
  1.5145 +        MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
  1.5146 +        if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_FINALLY, pc))
  1.5147 +            return null();
  1.5148 +        finallyBlock = statements();
  1.5149 +        if (!finallyBlock)
  1.5150 +            return null();
  1.5151 +        MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY);
  1.5152 +        PopStatementPC(tokenStream, pc);
  1.5153 +    } else {
  1.5154 +        tokenStream.ungetToken();
  1.5155 +    }
  1.5156 +    if (!catchList && !finallyBlock) {
  1.5157 +        report(ParseError, false, null(), JSMSG_CATCH_OR_FINALLY);
  1.5158 +        return null();
  1.5159 +    }
  1.5160 +
  1.5161 +    return handler.newTryStatement(begin, innerBlock, catchList, finallyBlock);
  1.5162 +}
  1.5163 +
  1.5164 +template <typename ParseHandler>
  1.5165 +typename ParseHandler::Node
  1.5166 +Parser<ParseHandler>::debuggerStatement()
  1.5167 +{
  1.5168 +    TokenPos p;
  1.5169 +    p.begin = pos().begin;
  1.5170 +    if (!MatchOrInsertSemicolon(tokenStream))
  1.5171 +        return null();
  1.5172 +    p.end = pos().end;
  1.5173 +
  1.5174 +    pc->sc->setBindingsAccessedDynamically();
  1.5175 +    pc->sc->setHasDebuggerStatement();
  1.5176 +
  1.5177 +    return handler.newDebuggerStatement(p);
  1.5178 +}
  1.5179 +
  1.5180 +template <typename ParseHandler>
  1.5181 +typename ParseHandler::Node
  1.5182 +Parser<ParseHandler>::statement(bool canHaveDirectives)
  1.5183 +{
  1.5184 +    JS_CHECK_RECURSION(context, return null());
  1.5185 +
  1.5186 +    switch (TokenKind tt = tokenStream.getToken(TokenStream::Operand)) {
  1.5187 +      case TOK_LC:
  1.5188 +        return blockStatement();
  1.5189 +
  1.5190 +      case TOK_CONST:
  1.5191 +        if (!abortIfSyntaxParser())
  1.5192 +            return null();
  1.5193 +        // FALL THROUGH
  1.5194 +      case TOK_VAR: {
  1.5195 +        Node pn = variables(tt == TOK_CONST ? PNK_CONST : PNK_VAR);
  1.5196 +        if (!pn)
  1.5197 +            return null();
  1.5198 +
  1.5199 +        // Tell js_EmitTree to generate a final POP.
  1.5200 +        handler.setListFlag(pn, PNX_POPVAR);
  1.5201 +
  1.5202 +        if (!MatchOrInsertSemicolon(tokenStream))
  1.5203 +            return null();
  1.5204 +        return pn;
  1.5205 +      }
  1.5206 +
  1.5207 +      case TOK_LET:
  1.5208 +        return letStatement();
  1.5209 +      case TOK_IMPORT:
  1.5210 +        return importDeclaration();
  1.5211 +      case TOK_EXPORT:
  1.5212 +        return exportDeclaration();
  1.5213 +      case TOK_SEMI:
  1.5214 +        return handler.newEmptyStatement(pos());
  1.5215 +      case TOK_IF:
  1.5216 +        return ifStatement();
  1.5217 +      case TOK_DO:
  1.5218 +        return doWhileStatement();
  1.5219 +      case TOK_WHILE:
  1.5220 +        return whileStatement();
  1.5221 +      case TOK_FOR:
  1.5222 +        return forStatement();
  1.5223 +      case TOK_SWITCH:
  1.5224 +        return switchStatement();
  1.5225 +      case TOK_CONTINUE:
  1.5226 +        return continueStatement();
  1.5227 +      case TOK_BREAK:
  1.5228 +        return breakStatement();
  1.5229 +      case TOK_RETURN:
  1.5230 +        return returnStatement();
  1.5231 +      case TOK_WITH:
  1.5232 +        return withStatement();
  1.5233 +      case TOK_THROW:
  1.5234 +        return throwStatement();
  1.5235 +      case TOK_TRY:
  1.5236 +        return tryStatement();
  1.5237 +      case TOK_FUNCTION:
  1.5238 +        return functionStmt();
  1.5239 +      case TOK_DEBUGGER:
  1.5240 +        return debuggerStatement();
  1.5241 +
  1.5242 +      /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */
  1.5243 +      case TOK_CATCH:
  1.5244 +        report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY);
  1.5245 +        return null();
  1.5246 +
  1.5247 +      case TOK_FINALLY:
  1.5248 +        report(ParseError, false, null(), JSMSG_FINALLY_WITHOUT_TRY);
  1.5249 +        return null();
  1.5250 +
  1.5251 +      case TOK_ERROR:
  1.5252 +        return null();
  1.5253 +
  1.5254 +      case TOK_STRING:
  1.5255 +        if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) {
  1.5256 +            if (!abortIfSyntaxParser())
  1.5257 +                return null();
  1.5258 +            if (!report(ParseWarning, false, null(), JSMSG_USE_ASM_DIRECTIVE_FAIL))
  1.5259 +                return null();
  1.5260 +        }
  1.5261 +        return expressionStatement();
  1.5262 +
  1.5263 +      case TOK_YIELD:
  1.5264 +        if (tokenStream.peekToken() == TOK_COLON) {
  1.5265 +            if (!checkYieldNameValidity())
  1.5266 +                return null();
  1.5267 +            return labeledStatement();
  1.5268 +        }
  1.5269 +        return expressionStatement();
  1.5270 +
  1.5271 +      case TOK_NAME:
  1.5272 +        if (tokenStream.peekToken() == TOK_COLON)
  1.5273 +            return labeledStatement();
  1.5274 +        return expressionStatement();
  1.5275 +
  1.5276 +      default:
  1.5277 +        return expressionStatement();
  1.5278 +    }
  1.5279 +}
  1.5280 +
  1.5281 +template <typename ParseHandler>
  1.5282 +typename ParseHandler::Node
  1.5283 +Parser<ParseHandler>::expr()
  1.5284 +{
  1.5285 +    Node pn = assignExpr();
  1.5286 +    if (pn && tokenStream.matchToken(TOK_COMMA)) {
  1.5287 +        Node seq = handler.newList(PNK_COMMA, pn);
  1.5288 +        if (!seq)
  1.5289 +            return null();
  1.5290 +        do {
  1.5291 +            if (handler.isUnparenthesizedYield(pn)) {
  1.5292 +                report(ParseError, false, pn, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
  1.5293 +                return null();
  1.5294 +            }
  1.5295 +
  1.5296 +            pn = assignExpr();
  1.5297 +            if (!pn)
  1.5298 +                return null();
  1.5299 +            handler.addList(seq, pn);
  1.5300 +        } while (tokenStream.matchToken(TOK_COMMA));
  1.5301 +        return seq;
  1.5302 +    }
  1.5303 +    return pn;
  1.5304 +}
  1.5305 +
  1.5306 +static const JSOp ParseNodeKindToJSOp[] = {
  1.5307 +    JSOP_OR,
  1.5308 +    JSOP_AND,
  1.5309 +    JSOP_BITOR,
  1.5310 +    JSOP_BITXOR,
  1.5311 +    JSOP_BITAND,
  1.5312 +    JSOP_STRICTEQ,
  1.5313 +    JSOP_EQ,
  1.5314 +    JSOP_STRICTNE,
  1.5315 +    JSOP_NE,
  1.5316 +    JSOP_LT,
  1.5317 +    JSOP_LE,
  1.5318 +    JSOP_GT,
  1.5319 +    JSOP_GE,
  1.5320 +    JSOP_INSTANCEOF,
  1.5321 +    JSOP_IN,
  1.5322 +    JSOP_LSH,
  1.5323 +    JSOP_RSH,
  1.5324 +    JSOP_URSH,
  1.5325 +    JSOP_ADD,
  1.5326 +    JSOP_SUB,
  1.5327 +    JSOP_MUL,
  1.5328 +    JSOP_DIV,
  1.5329 +    JSOP_MOD
  1.5330 +};
  1.5331 +
  1.5332 +static inline JSOp
  1.5333 +BinaryOpParseNodeKindToJSOp(ParseNodeKind pnk)
  1.5334 +{
  1.5335 +    JS_ASSERT(pnk >= PNK_BINOP_FIRST);
  1.5336 +    JS_ASSERT(pnk <= PNK_BINOP_LAST);
  1.5337 +    return ParseNodeKindToJSOp[pnk - PNK_BINOP_FIRST];
  1.5338 +}
  1.5339 +
  1.5340 +static bool
  1.5341 +IsBinaryOpToken(TokenKind tok, bool parsingForInit)
  1.5342 +{
  1.5343 +    return tok == TOK_IN ? !parsingForInit : TokenKindIsBinaryOp(tok);
  1.5344 +}
  1.5345 +
  1.5346 +static ParseNodeKind
  1.5347 +BinaryOpTokenKindToParseNodeKind(TokenKind tok)
  1.5348 +{
  1.5349 +    JS_ASSERT(TokenKindIsBinaryOp(tok));
  1.5350 +    return ParseNodeKind(PNK_BINOP_FIRST + (tok - TOK_BINOP_FIRST));
  1.5351 +}
  1.5352 +
  1.5353 +static const int PrecedenceTable[] = {
  1.5354 +    1, /* PNK_OR */
  1.5355 +    2, /* PNK_AND */
  1.5356 +    3, /* PNK_BITOR */
  1.5357 +    4, /* PNK_BITXOR */
  1.5358 +    5, /* PNK_BITAND */
  1.5359 +    6, /* PNK_STRICTEQ */
  1.5360 +    6, /* PNK_EQ */
  1.5361 +    6, /* PNK_STRICTNE */
  1.5362 +    6, /* PNK_NE */
  1.5363 +    7, /* PNK_LT */
  1.5364 +    7, /* PNK_LE */
  1.5365 +    7, /* PNK_GT */
  1.5366 +    7, /* PNK_GE */
  1.5367 +    7, /* PNK_INSTANCEOF */
  1.5368 +    7, /* PNK_IN */
  1.5369 +    8, /* PNK_LSH */
  1.5370 +    8, /* PNK_RSH */
  1.5371 +    8, /* PNK_URSH */
  1.5372 +    9, /* PNK_ADD */
  1.5373 +    9, /* PNK_SUB */
  1.5374 +    10, /* PNK_STAR */
  1.5375 +    10, /* PNK_DIV */
  1.5376 +    10  /* PNK_MOD */
  1.5377 +};
  1.5378 +
  1.5379 +static const int PRECEDENCE_CLASSES = 10;
  1.5380 +
  1.5381 +static int
  1.5382 +Precedence(ParseNodeKind pnk) {
  1.5383 +    // Everything binds tighter than PNK_LIMIT, because we want to reduce all
  1.5384 +    // nodes to a single node when we reach a token that is not another binary
  1.5385 +    // operator.
  1.5386 +    if (pnk == PNK_LIMIT)
  1.5387 +        return 0;
  1.5388 +
  1.5389 +    JS_ASSERT(pnk >= PNK_BINOP_FIRST);
  1.5390 +    JS_ASSERT(pnk <= PNK_BINOP_LAST);
  1.5391 +    return PrecedenceTable[pnk - PNK_BINOP_FIRST];
  1.5392 +}
  1.5393 +
  1.5394 +template <typename ParseHandler>
  1.5395 +MOZ_ALWAYS_INLINE typename ParseHandler::Node
  1.5396 +Parser<ParseHandler>::orExpr1()
  1.5397 +{
  1.5398 +    // Shift-reduce parser for the left-associative binary operator part of
  1.5399 +    // the JS syntax.
  1.5400 +
  1.5401 +    // Conceptually there's just one stack, a stack of pairs (lhs, op).
  1.5402 +    // It's implemented using two separate arrays, though.
  1.5403 +    Node nodeStack[PRECEDENCE_CLASSES];
  1.5404 +    ParseNodeKind kindStack[PRECEDENCE_CLASSES];
  1.5405 +    int depth = 0;
  1.5406 +
  1.5407 +    bool oldParsingForInit = pc->parsingForInit;
  1.5408 +    pc->parsingForInit = false;
  1.5409 +
  1.5410 +    Node pn;
  1.5411 +    for (;;) {
  1.5412 +        pn = unaryExpr();
  1.5413 +        if (!pn)
  1.5414 +            return pn;
  1.5415 +
  1.5416 +        // If a binary operator follows, consume it and compute the
  1.5417 +        // corresponding operator.
  1.5418 +        TokenKind tok = tokenStream.getToken();
  1.5419 +        if (tok == TOK_ERROR)
  1.5420 +            return null();
  1.5421 +        ParseNodeKind pnk;
  1.5422 +        if (IsBinaryOpToken(tok, oldParsingForInit)) {
  1.5423 +            pnk = BinaryOpTokenKindToParseNodeKind(tok);
  1.5424 +        } else {
  1.5425 +            tok = TOK_EOF;
  1.5426 +            pnk = PNK_LIMIT;
  1.5427 +        }
  1.5428 +
  1.5429 +        // If pnk has precedence less than or equal to another operator on the
  1.5430 +        // stack, reduce. This combines nodes on the stack until we form the
  1.5431 +        // actual lhs of pnk.
  1.5432 +        //
  1.5433 +        // The >= in this condition works because all the operators in question
  1.5434 +        // are left-associative; if any were not, the case where two operators
  1.5435 +        // have equal precedence would need to be handled specially, and the
  1.5436 +        // stack would need to be a Vector.
  1.5437 +        while (depth > 0 && Precedence(kindStack[depth - 1]) >= Precedence(pnk)) {
  1.5438 +            depth--;
  1.5439 +            ParseNodeKind combiningPnk = kindStack[depth];
  1.5440 +            JSOp combiningOp = BinaryOpParseNodeKindToJSOp(combiningPnk);
  1.5441 +            pn = handler.newBinaryOrAppend(combiningPnk, nodeStack[depth], pn, pc, combiningOp);
  1.5442 +            if (!pn)
  1.5443 +                return pn;
  1.5444 +        }
  1.5445 +
  1.5446 +        if (pnk == PNK_LIMIT)
  1.5447 +            break;
  1.5448 +
  1.5449 +        nodeStack[depth] = pn;
  1.5450 +        kindStack[depth] = pnk;
  1.5451 +        depth++;
  1.5452 +        JS_ASSERT(depth <= PRECEDENCE_CLASSES);
  1.5453 +    }
  1.5454 +
  1.5455 +    JS_ASSERT(depth == 0);
  1.5456 +    pc->parsingForInit = oldParsingForInit;
  1.5457 +    return pn;
  1.5458 +}
  1.5459 +
  1.5460 +template <typename ParseHandler>
  1.5461 +MOZ_ALWAYS_INLINE typename ParseHandler::Node
  1.5462 +Parser<ParseHandler>::condExpr1()
  1.5463 +{
  1.5464 +    Node condition = orExpr1();
  1.5465 +    if (!condition || !tokenStream.isCurrentTokenType(TOK_HOOK))
  1.5466 +        return condition;
  1.5467 +
  1.5468 +    /*
  1.5469 +     * Always accept the 'in' operator in the middle clause of a ternary,
  1.5470 +     * where it's unambiguous, even if we might be parsing the init of a
  1.5471 +     * for statement.
  1.5472 +     */
  1.5473 +    bool oldParsingForInit = pc->parsingForInit;
  1.5474 +    pc->parsingForInit = false;
  1.5475 +    Node thenExpr = assignExpr();
  1.5476 +    pc->parsingForInit = oldParsingForInit;
  1.5477 +    if (!thenExpr)
  1.5478 +        return null();
  1.5479 +
  1.5480 +    MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND);
  1.5481 +
  1.5482 +    Node elseExpr = assignExpr();
  1.5483 +    if (!elseExpr)
  1.5484 +        return null();
  1.5485 +
  1.5486 +    tokenStream.getToken(); /* read one token past the end */
  1.5487 +    return handler.newConditional(condition, thenExpr, elseExpr);
  1.5488 +}
  1.5489 +
  1.5490 +template <>
  1.5491 +bool
  1.5492 +Parser<FullParseHandler>::checkAndMarkAsAssignmentLhs(ParseNode *pn, AssignmentFlavor flavor)
  1.5493 +{
  1.5494 +    switch (pn->getKind()) {
  1.5495 +      case PNK_NAME:
  1.5496 +        if (!checkStrictAssignment(pn, flavor))
  1.5497 +            return false;
  1.5498 +        if (flavor == KeyedDestructuringAssignment) {
  1.5499 +            /*
  1.5500 +             * We may be called on a name node that has already been
  1.5501 +             * specialized, in the very weird "for (var [x] = i in o) ..."
  1.5502 +             * case. See bug 558633.
  1.5503 +             */
  1.5504 +            if (!(js_CodeSpec[pn->getOp()].format & JOF_SET))
  1.5505 +                pn->setOp(JSOP_SETNAME);
  1.5506 +        } else {
  1.5507 +            pn->setOp(pn->isOp(JSOP_GETLOCAL) ? JSOP_SETLOCAL : JSOP_SETNAME);
  1.5508 +        }
  1.5509 +        pn->markAsAssigned();
  1.5510 +        break;
  1.5511 +
  1.5512 +      case PNK_DOT:
  1.5513 +      case PNK_ELEM:
  1.5514 +        break;
  1.5515 +
  1.5516 +      case PNK_ARRAY:
  1.5517 +      case PNK_OBJECT:
  1.5518 +        if (flavor == CompoundAssignment) {
  1.5519 +            report(ParseError, false, null(), JSMSG_BAD_DESTRUCT_ASS);
  1.5520 +            return false;
  1.5521 +        }
  1.5522 +        if (!checkDestructuring(nullptr, pn))
  1.5523 +            return false;
  1.5524 +        break;
  1.5525 +
  1.5526 +      case PNK_CALL:
  1.5527 +        if (!makeSetCall(pn, JSMSG_BAD_LEFTSIDE_OF_ASS))
  1.5528 +            return false;
  1.5529 +        break;
  1.5530 +
  1.5531 +      default:
  1.5532 +        report(ParseError, false, pn, JSMSG_BAD_LEFTSIDE_OF_ASS);
  1.5533 +        return false;
  1.5534 +    }
  1.5535 +    return true;
  1.5536 +}
  1.5537 +
  1.5538 +template <>
  1.5539 +bool
  1.5540 +Parser<SyntaxParseHandler>::checkAndMarkAsAssignmentLhs(Node pn, AssignmentFlavor flavor)
  1.5541 +{
  1.5542 +    /* Full syntax checking of valid assignment LHS terms requires a parse tree. */
  1.5543 +    if (pn != SyntaxParseHandler::NodeName &&
  1.5544 +        pn != SyntaxParseHandler::NodeGetProp &&
  1.5545 +        pn != SyntaxParseHandler::NodeLValue)
  1.5546 +    {
  1.5547 +        return abortIfSyntaxParser();
  1.5548 +    }
  1.5549 +    return checkStrictAssignment(pn, flavor);
  1.5550 +}
  1.5551 +
  1.5552 +template <typename ParseHandler>
  1.5553 +typename ParseHandler::Node
  1.5554 +Parser<ParseHandler>::assignExpr()
  1.5555 +{
  1.5556 +    JS_CHECK_RECURSION(context, return null());
  1.5557 +
  1.5558 +    // It's very common at this point to have a "detectably simple" expression,
  1.5559 +    // i.e. a name/number/string token followed by one of the following tokens
  1.5560 +    // that obviously isn't part of an expression: , ; : ) ] }
  1.5561 +    //
  1.5562 +    // (In Parsemark this happens 81.4% of the time;  in code with large
  1.5563 +    // numeric arrays, such as some Kraken benchmarks, it happens more often.)
  1.5564 +    //
  1.5565 +    // In such cases, we can avoid the full expression parsing route through
  1.5566 +    // assignExpr(), condExpr1(), orExpr1(), unaryExpr(), memberExpr(), and
  1.5567 +    // primaryExpr().
  1.5568 +
  1.5569 +    TokenKind tt = tokenStream.getToken(TokenStream::Operand);
  1.5570 +
  1.5571 +    if (tt == TOK_NAME && tokenStream.nextTokenEndsExpr())
  1.5572 +        return identifierName();
  1.5573 +
  1.5574 +    if (tt == TOK_NUMBER && tokenStream.nextTokenEndsExpr())
  1.5575 +        return newNumber(tokenStream.currentToken());
  1.5576 +
  1.5577 +    if (tt == TOK_STRING && tokenStream.nextTokenEndsExpr())
  1.5578 +        return stringLiteral();
  1.5579 +
  1.5580 +    if (tt == TOK_YIELD && (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()))
  1.5581 +        return yieldExpression();
  1.5582 +
  1.5583 +    tokenStream.ungetToken();
  1.5584 +
  1.5585 +    // Save the tokenizer state in case we find an arrow function and have to
  1.5586 +    // rewind.
  1.5587 +    TokenStream::Position start(keepAtoms);
  1.5588 +    tokenStream.tell(&start);
  1.5589 +
  1.5590 +    Node lhs = condExpr1();
  1.5591 +    if (!lhs)
  1.5592 +        return null();
  1.5593 +
  1.5594 +    ParseNodeKind kind;
  1.5595 +    JSOp op;
  1.5596 +    switch (tokenStream.currentToken().type) {
  1.5597 +      case TOK_ASSIGN:       kind = PNK_ASSIGN;       op = JSOP_NOP;    break;
  1.5598 +      case TOK_ADDASSIGN:    kind = PNK_ADDASSIGN;    op = JSOP_ADD;    break;
  1.5599 +      case TOK_SUBASSIGN:    kind = PNK_SUBASSIGN;    op = JSOP_SUB;    break;
  1.5600 +      case TOK_BITORASSIGN:  kind = PNK_BITORASSIGN;  op = JSOP_BITOR;  break;
  1.5601 +      case TOK_BITXORASSIGN: kind = PNK_BITXORASSIGN; op = JSOP_BITXOR; break;
  1.5602 +      case TOK_BITANDASSIGN: kind = PNK_BITANDASSIGN; op = JSOP_BITAND; break;
  1.5603 +      case TOK_LSHASSIGN:    kind = PNK_LSHASSIGN;    op = JSOP_LSH;    break;
  1.5604 +      case TOK_RSHASSIGN:    kind = PNK_RSHASSIGN;    op = JSOP_RSH;    break;
  1.5605 +      case TOK_URSHASSIGN:   kind = PNK_URSHASSIGN;   op = JSOP_URSH;   break;
  1.5606 +      case TOK_MULASSIGN:    kind = PNK_MULASSIGN;    op = JSOP_MUL;    break;
  1.5607 +      case TOK_DIVASSIGN:    kind = PNK_DIVASSIGN;    op = JSOP_DIV;    break;
  1.5608 +      case TOK_MODASSIGN:    kind = PNK_MODASSIGN;    op = JSOP_MOD;    break;
  1.5609 +
  1.5610 +      case TOK_ARROW: {
  1.5611 +        tokenStream.seek(start);
  1.5612 +        if (!abortIfSyntaxParser())
  1.5613 +            return null();
  1.5614 +
  1.5615 +        if (tokenStream.getToken() == TOK_ERROR)
  1.5616 +            return null();
  1.5617 +        tokenStream.ungetToken();
  1.5618 +
  1.5619 +        return functionDef(NullPtr(), start, Normal, Arrow, NotGenerator);
  1.5620 +      }
  1.5621 +
  1.5622 +      default:
  1.5623 +        JS_ASSERT(!tokenStream.isCurrentTokenAssignment());
  1.5624 +        tokenStream.ungetToken();
  1.5625 +        return lhs;
  1.5626 +    }
  1.5627 +
  1.5628 +    AssignmentFlavor flavor = kind == PNK_ASSIGN ? PlainAssignment : CompoundAssignment;
  1.5629 +    if (!checkAndMarkAsAssignmentLhs(lhs, flavor))
  1.5630 +        return null();
  1.5631 +
  1.5632 +    Node rhs = assignExpr();
  1.5633 +    if (!rhs)
  1.5634 +        return null();
  1.5635 +
  1.5636 +    return handler.newBinaryOrAppend(kind, lhs, rhs, pc, op);
  1.5637 +}
  1.5638 +
  1.5639 +static const char incop_name_str[][10] = {"increment", "decrement"};
  1.5640 +
  1.5641 +template <>
  1.5642 +bool
  1.5643 +Parser<FullParseHandler>::checkAndMarkAsIncOperand(ParseNode *kid, TokenKind tt, bool preorder)
  1.5644 +{
  1.5645 +    // Check.
  1.5646 +    if (!kid->isKind(PNK_NAME) &&
  1.5647 +        !kid->isKind(PNK_DOT) &&
  1.5648 +        !kid->isKind(PNK_ELEM) &&
  1.5649 +        !(kid->isKind(PNK_CALL) &&
  1.5650 +          (kid->isOp(JSOP_CALL) || kid->isOp(JSOP_SPREADCALL) ||
  1.5651 +           kid->isOp(JSOP_EVAL) || kid->isOp(JSOP_SPREADEVAL) ||
  1.5652 +           kid->isOp(JSOP_FUNCALL) ||
  1.5653 +           kid->isOp(JSOP_FUNAPPLY))))
  1.5654 +    {
  1.5655 +        report(ParseError, false, null(), JSMSG_BAD_OPERAND, incop_name_str[tt == TOK_DEC]);
  1.5656 +        return false;
  1.5657 +    }
  1.5658 +
  1.5659 +    if (!checkStrictAssignment(kid, IncDecAssignment))
  1.5660 +        return false;
  1.5661 +
  1.5662 +    // Mark.
  1.5663 +    if (kid->isKind(PNK_NAME)) {
  1.5664 +        kid->markAsAssigned();
  1.5665 +    } else if (kid->isKind(PNK_CALL)) {
  1.5666 +        if (!makeSetCall(kid, JSMSG_BAD_INCOP_OPERAND))
  1.5667 +            return false;
  1.5668 +    }
  1.5669 +    return true;
  1.5670 +}
  1.5671 +
  1.5672 +template <>
  1.5673 +bool
  1.5674 +Parser<SyntaxParseHandler>::checkAndMarkAsIncOperand(Node kid, TokenKind tt, bool preorder)
  1.5675 +{
  1.5676 +    // To the extent of what we support in syntax-parse mode, the rules for
  1.5677 +    // inc/dec operands are the same as for assignment. There are differences,
  1.5678 +    // such as destructuring; but if we hit any of those cases, we'll abort and
  1.5679 +    // reparse in full mode.
  1.5680 +    return checkAndMarkAsAssignmentLhs(kid, IncDecAssignment);
  1.5681 +}
  1.5682 +
  1.5683 +template <typename ParseHandler>
  1.5684 +typename ParseHandler::Node
  1.5685 +Parser<ParseHandler>::unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin)
  1.5686 +{
  1.5687 +    Node kid = unaryExpr();
  1.5688 +    if (!kid)
  1.5689 +        return null();
  1.5690 +    return handler.newUnary(kind, op, begin, kid);
  1.5691 +}
  1.5692 +
  1.5693 +template <typename ParseHandler>
  1.5694 +typename ParseHandler::Node
  1.5695 +Parser<ParseHandler>::unaryExpr()
  1.5696 +{
  1.5697 +    Node pn, pn2;
  1.5698 +
  1.5699 +    JS_CHECK_RECURSION(context, return null());
  1.5700 +
  1.5701 +    TokenKind tt = tokenStream.getToken(TokenStream::Operand);
  1.5702 +    uint32_t begin = pos().begin;
  1.5703 +    switch (tt) {
  1.5704 +      case TOK_TYPEOF:
  1.5705 +        return unaryOpExpr(PNK_TYPEOF, JSOP_TYPEOF, begin);
  1.5706 +      case TOK_VOID:
  1.5707 +        return unaryOpExpr(PNK_VOID, JSOP_VOID, begin);
  1.5708 +      case TOK_NOT:
  1.5709 +        return unaryOpExpr(PNK_NOT, JSOP_NOT, begin);
  1.5710 +      case TOK_BITNOT:
  1.5711 +        return unaryOpExpr(PNK_BITNOT, JSOP_BITNOT, begin);
  1.5712 +      case TOK_ADD:
  1.5713 +        return unaryOpExpr(PNK_POS, JSOP_POS, begin);
  1.5714 +      case TOK_SUB:
  1.5715 +        return unaryOpExpr(PNK_NEG, JSOP_NEG, begin);
  1.5716 +
  1.5717 +      case TOK_INC:
  1.5718 +      case TOK_DEC:
  1.5719 +      {
  1.5720 +        TokenKind tt2 = tokenStream.getToken(TokenStream::Operand);
  1.5721 +        pn2 = memberExpr(tt2, true);
  1.5722 +        if (!pn2)
  1.5723 +            return null();
  1.5724 +        if (!checkAndMarkAsIncOperand(pn2, tt, true))
  1.5725 +            return null();
  1.5726 +        return handler.newUnary((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT,
  1.5727 +                                JSOP_NOP,
  1.5728 +                                begin,
  1.5729 +                                pn2);
  1.5730 +      }
  1.5731 +
  1.5732 +      case TOK_DELETE: {
  1.5733 +        Node expr = unaryExpr();
  1.5734 +        if (!expr)
  1.5735 +            return null();
  1.5736 +
  1.5737 +        // Per spec, deleting any unary expression is valid -- it simply
  1.5738 +        // returns true -- except for one case that is illegal in strict mode.
  1.5739 +        if (handler.isName(expr)) {
  1.5740 +            if (!report(ParseStrictError, pc->sc->strict, expr, JSMSG_DEPRECATED_DELETE_OPERAND))
  1.5741 +                return null();
  1.5742 +            pc->sc->setBindingsAccessedDynamically();
  1.5743 +        }
  1.5744 +
  1.5745 +        return handler.newDelete(begin, expr);
  1.5746 +      }
  1.5747 +
  1.5748 +      case TOK_ERROR:
  1.5749 +        return null();
  1.5750 +
  1.5751 +      default:
  1.5752 +        pn = memberExpr(tt, true);
  1.5753 +        if (!pn)
  1.5754 +            return null();
  1.5755 +
  1.5756 +        /* Don't look across a newline boundary for a postfix incop. */
  1.5757 +        tt = tokenStream.peekTokenSameLine(TokenStream::Operand);
  1.5758 +        if (tt == TOK_INC || tt == TOK_DEC) {
  1.5759 +            tokenStream.consumeKnownToken(tt);
  1.5760 +            if (!checkAndMarkAsIncOperand(pn, tt, false))
  1.5761 +                return null();
  1.5762 +            return handler.newUnary((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT,
  1.5763 +                                    JSOP_NOP,
  1.5764 +                                    begin,
  1.5765 +                                    pn);
  1.5766 +        }
  1.5767 +        return pn;
  1.5768 +    }
  1.5769 +    MOZ_ASSUME_UNREACHABLE("unaryExpr");
  1.5770 +}
  1.5771 +
  1.5772 +/*
  1.5773 + * A dedicated helper for transplanting the legacy comprehension expression E in
  1.5774 + *
  1.5775 + *   [E for (V in I)]   // legacy array comprehension
  1.5776 + *   (E for (V in I))   // legacy generator expression
  1.5777 + *
  1.5778 + * from its initial location in the AST, on the left of the 'for', to its final
  1.5779 + * position on the right. To avoid a separate pass we do this by adjusting the
  1.5780 + * blockids and name binding links that were established when E was parsed.
  1.5781 + *
  1.5782 + * A legacy generator expression desugars like so:
  1.5783 + *
  1.5784 + *   (E for (V in I)) => (function () { for (var V in I) yield E; })()
  1.5785 + *
  1.5786 + * so the transplanter must adjust static level as well as blockid. E's source
  1.5787 + * coordinates in root->pn_pos are critical to deciding which binding links to
  1.5788 + * preserve and which to cut.
  1.5789 + *
  1.5790 + * NB: This is not a general tree transplanter -- it knows in particular that
  1.5791 + * the one or more bindings induced by V have not yet been created.
  1.5792 + */
  1.5793 +class LegacyCompExprTransplanter
  1.5794 +{
  1.5795 +    ParseNode       *root;
  1.5796 +    Parser<FullParseHandler> *parser;
  1.5797 +    ParseContext<FullParseHandler> *outerpc;
  1.5798 +    GeneratorKind   comprehensionKind;
  1.5799 +    unsigned        adjust;
  1.5800 +    HashSet<Definition *> visitedImplicitArguments;
  1.5801 +
  1.5802 +  public:
  1.5803 +    LegacyCompExprTransplanter(ParseNode *pn, Parser<FullParseHandler> *parser,
  1.5804 +                               ParseContext<FullParseHandler> *outerpc,
  1.5805 +                               GeneratorKind kind, unsigned adj)
  1.5806 +      : root(pn), parser(parser), outerpc(outerpc), comprehensionKind(kind), adjust(adj),
  1.5807 +        visitedImplicitArguments(parser->context)
  1.5808 +    {}
  1.5809 +
  1.5810 +    bool init() {
  1.5811 +        return visitedImplicitArguments.init();
  1.5812 +    }
  1.5813 +
  1.5814 +    bool transplant(ParseNode *pn);
  1.5815 +};
  1.5816 +
  1.5817 +/*
  1.5818 + * Any definitions nested within the legacy comprehension expression of a
  1.5819 + * generator expression must move "down" one static level, which of course
  1.5820 + * increases the upvar-frame-skip count.
  1.5821 + */
  1.5822 +template <typename ParseHandler>
  1.5823 +static bool
  1.5824 +BumpStaticLevel(TokenStream &ts, ParseNode *pn, ParseContext<ParseHandler> *pc)
  1.5825 +{
  1.5826 +    if (pn->pn_cookie.isFree())
  1.5827 +        return true;
  1.5828 +
  1.5829 +    unsigned level = unsigned(pn->pn_cookie.level()) + 1;
  1.5830 +    JS_ASSERT(level >= pc->staticLevel);
  1.5831 +    return pn->pn_cookie.set(ts, level, pn->pn_cookie.slot());
  1.5832 +}
  1.5833 +
  1.5834 +template <typename ParseHandler>
  1.5835 +static bool
  1.5836 +AdjustBlockId(TokenStream &ts, ParseNode *pn, unsigned adjust, ParseContext<ParseHandler> *pc)
  1.5837 +{
  1.5838 +    JS_ASSERT(pn->isArity(PN_LIST) || pn->isArity(PN_CODE) || pn->isArity(PN_NAME));
  1.5839 +    if (BlockIdLimit - pn->pn_blockid <= adjust + 1) {
  1.5840 +        ts.reportError(JSMSG_NEED_DIET, "program");
  1.5841 +        return false;
  1.5842 +    }
  1.5843 +    pn->pn_blockid += adjust;
  1.5844 +    if (pn->pn_blockid >= pc->blockidGen)
  1.5845 +        pc->blockidGen = pn->pn_blockid + 1;
  1.5846 +    return true;
  1.5847 +}
  1.5848 +
  1.5849 +bool
  1.5850 +LegacyCompExprTransplanter::transplant(ParseNode *pn)
  1.5851 +{
  1.5852 +    ParseContext<FullParseHandler> *pc = parser->pc;
  1.5853 +
  1.5854 +    bool isGenexp = comprehensionKind != NotGenerator;
  1.5855 +
  1.5856 +    if (!pn)
  1.5857 +        return true;
  1.5858 +
  1.5859 +    switch (pn->getArity()) {
  1.5860 +      case PN_LIST:
  1.5861 +        for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
  1.5862 +            if (!transplant(pn2))
  1.5863 +                return false;
  1.5864 +        }
  1.5865 +        if (pn->pn_pos >= root->pn_pos) {
  1.5866 +            if (!AdjustBlockId(parser->tokenStream, pn, adjust, pc))
  1.5867 +                return false;
  1.5868 +        }
  1.5869 +        break;
  1.5870 +
  1.5871 +      case PN_TERNARY:
  1.5872 +        if (!transplant(pn->pn_kid1) ||
  1.5873 +            !transplant(pn->pn_kid2) ||
  1.5874 +            !transplant(pn->pn_kid3))
  1.5875 +            return false;
  1.5876 +        break;
  1.5877 +
  1.5878 +      case PN_BINARY:
  1.5879 +      case PN_BINARY_OBJ:
  1.5880 +        if (!transplant(pn->pn_left))
  1.5881 +            return false;
  1.5882 +
  1.5883 +        /* Binary TOK_COLON nodes can have left == right. See bug 492714. */
  1.5884 +        if (pn->pn_right != pn->pn_left) {
  1.5885 +            if (!transplant(pn->pn_right))
  1.5886 +                return false;
  1.5887 +        }
  1.5888 +        break;
  1.5889 +
  1.5890 +      case PN_UNARY:
  1.5891 +        if (!transplant(pn->pn_kid))
  1.5892 +            return false;
  1.5893 +        break;
  1.5894 +
  1.5895 +      case PN_CODE:
  1.5896 +      case PN_NAME:
  1.5897 +        if (!transplant(pn->maybeExpr()))
  1.5898 +            return false;
  1.5899 +
  1.5900 +        if (pn->isDefn()) {
  1.5901 +            if (isGenexp && !BumpStaticLevel(parser->tokenStream, pn, pc))
  1.5902 +                return false;
  1.5903 +        } else if (pn->isUsed()) {
  1.5904 +            JS_ASSERT(pn->pn_cookie.isFree());
  1.5905 +
  1.5906 +            Definition *dn = pn->pn_lexdef;
  1.5907 +            JS_ASSERT(dn->isDefn());
  1.5908 +
  1.5909 +            /*
  1.5910 +             * Adjust the definition's block id only if it is a placeholder not
  1.5911 +             * to the left of the root node, and if pn is the last use visited
  1.5912 +             * in the legacy comprehension expression (to avoid adjusting the
  1.5913 +             * blockid multiple times).
  1.5914 +             *
  1.5915 +             * Non-placeholder definitions within the legacy comprehension
  1.5916 +             * expression will be visited further below.
  1.5917 +             */
  1.5918 +            if (dn->isPlaceholder() && dn->pn_pos >= root->pn_pos && dn->dn_uses == pn) {
  1.5919 +                if (isGenexp && !BumpStaticLevel(parser->tokenStream, dn, pc))
  1.5920 +                    return false;
  1.5921 +                if (!AdjustBlockId(parser->tokenStream, dn, adjust, pc))
  1.5922 +                    return false;
  1.5923 +            }
  1.5924 +
  1.5925 +            RootedAtom atom(parser->context, pn->pn_atom);
  1.5926 +#ifdef DEBUG
  1.5927 +            StmtInfoPC *stmt = LexicalLookup(pc, atom, nullptr, (StmtInfoPC *)nullptr);
  1.5928 +            JS_ASSERT(!stmt || stmt != pc->topStmt);
  1.5929 +#endif
  1.5930 +            if (isGenexp && !dn->isOp(JSOP_CALLEE)) {
  1.5931 +                JS_ASSERT(!pc->decls().lookupFirst(atom));
  1.5932 +
  1.5933 +                if (dn->pn_pos < root->pn_pos) {
  1.5934 +                    /*
  1.5935 +                     * The variable originally appeared to be a use of a
  1.5936 +                     * definition or placeholder outside the generator, but now
  1.5937 +                     * we know it is scoped within the legacy comprehension
  1.5938 +                     * tail's clauses. Make it (along with any other uses within
  1.5939 +                     * the generator) a use of a new placeholder in the
  1.5940 +                     * generator's lexdeps.
  1.5941 +                     */
  1.5942 +                    Definition *dn2 = parser->handler.newPlaceholder(atom, parser->pc->blockid(),
  1.5943 +                                                                     parser->pos());
  1.5944 +                    if (!dn2)
  1.5945 +                        return false;
  1.5946 +                    dn2->pn_pos = root->pn_pos;
  1.5947 +
  1.5948 +                    /*
  1.5949 +                     * Change all uses of |dn| that lie within the generator's
  1.5950 +                     * |yield| expression into uses of dn2.
  1.5951 +                     */
  1.5952 +                    ParseNode **pnup = &dn->dn_uses;
  1.5953 +                    ParseNode *pnu;
  1.5954 +                    while ((pnu = *pnup) != nullptr && pnu->pn_pos >= root->pn_pos) {
  1.5955 +                        pnu->pn_lexdef = dn2;
  1.5956 +                        dn2->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
  1.5957 +                        pnup = &pnu->pn_link;
  1.5958 +                    }
  1.5959 +                    dn2->dn_uses = dn->dn_uses;
  1.5960 +                    dn->dn_uses = *pnup;
  1.5961 +                    *pnup = nullptr;
  1.5962 +                    DefinitionSingle def = DefinitionSingle::new_<FullParseHandler>(dn2);
  1.5963 +                    if (!pc->lexdeps->put(atom, def))
  1.5964 +                        return false;
  1.5965 +                    if (dn->isClosed())
  1.5966 +                        dn2->pn_dflags |= PND_CLOSED;
  1.5967 +                } else if (dn->isPlaceholder()) {
  1.5968 +                    /*
  1.5969 +                     * The variable first occurs free in the 'yield' expression;
  1.5970 +                     * move the existing placeholder node (and all its uses)
  1.5971 +                     * from the parent's lexdeps into the generator's lexdeps.
  1.5972 +                     */
  1.5973 +                    outerpc->lexdeps->remove(atom);
  1.5974 +                    DefinitionSingle def = DefinitionSingle::new_<FullParseHandler>(dn);
  1.5975 +                    if (!pc->lexdeps->put(atom, def))
  1.5976 +                        return false;
  1.5977 +                } else if (dn->isImplicitArguments()) {
  1.5978 +                    /*
  1.5979 +                     * Implicit 'arguments' Definition nodes (see
  1.5980 +                     * PND_IMPLICITARGUMENTS in Parser::functionBody) are only
  1.5981 +                     * reachable via the lexdefs of their uses. Unfortunately,
  1.5982 +                     * there may be multiple uses, so we need to maintain a set
  1.5983 +                     * to only bump the definition once.
  1.5984 +                     */
  1.5985 +                    if (isGenexp && !visitedImplicitArguments.has(dn)) {
  1.5986 +                        if (!BumpStaticLevel(parser->tokenStream, dn, pc))
  1.5987 +                            return false;
  1.5988 +                        if (!AdjustBlockId(parser->tokenStream, dn, adjust, pc))
  1.5989 +                            return false;
  1.5990 +                        if (!visitedImplicitArguments.put(dn))
  1.5991 +                            return false;
  1.5992 +                    }
  1.5993 +                }
  1.5994 +            }
  1.5995 +        }
  1.5996 +
  1.5997 +        if (pn->pn_pos >= root->pn_pos) {
  1.5998 +            if (!AdjustBlockId(parser->tokenStream, pn, adjust, pc))
  1.5999 +                return false;
  1.6000 +        }
  1.6001 +        break;
  1.6002 +
  1.6003 +      case PN_NULLARY:
  1.6004 +        /* Nothing. */
  1.6005 +        break;
  1.6006 +    }
  1.6007 +    return true;
  1.6008 +}
  1.6009 +
  1.6010 +// Parsing legacy (JS1.7-style) comprehensions is terrible: we parse the head
  1.6011 +// expression as if it's part of a comma expression, then when we see the "for"
  1.6012 +// we transplant the parsed expression into the inside of a constructed
  1.6013 +// for-of/for-in/for-each tail.  Transplanting an already-parsed expression is
  1.6014 +// tricky, but the LegacyCompExprTransplanter handles most of that.
  1.6015 +//
  1.6016 +// The one remaining thing to patch up is the block scope depth.  We need to
  1.6017 +// compute the maximum block scope depth of a function, so we know how much
  1.6018 +// space to reserve in the fixed part of a stack frame.  Normally this is done
  1.6019 +// whenever we leave a statement, via AccumulateBlockScopeDepth.  However if the
  1.6020 +// head has a let expression, we need to re-assign that depth to the tail of the
  1.6021 +// comprehension.
  1.6022 +//
  1.6023 +// Thing is, we don't actually know what that depth is, because the only
  1.6024 +// information we keep is the maximum nested depth within a statement, so we
  1.6025 +// just conservatively propagate the maximum nested depth from the top statement
  1.6026 +// to the comprehension tail.
  1.6027 +//
  1.6028 +template <typename ParseHandler>
  1.6029 +static unsigned
  1.6030 +LegacyComprehensionHeadBlockScopeDepth(ParseContext<ParseHandler> *pc)
  1.6031 +{
  1.6032 +    return pc->topStmt ? pc->topStmt->innerBlockScopeDepth : pc->blockScopeDepth;
  1.6033 +}
  1.6034 +
  1.6035 +/*
  1.6036 + * Starting from a |for| keyword after the first array initialiser element or
  1.6037 + * an expression in an open parenthesis, parse the tail of the comprehension
  1.6038 + * or generator expression signified by this |for| keyword in context.
  1.6039 + *
  1.6040 + * Return null on failure, else return the top-most parse node for the array
  1.6041 + * comprehension or generator expression, with a unary node as the body of the
  1.6042 + * (possibly nested) for-loop, initialized by |kind, op, kid|.
  1.6043 + */
  1.6044 +template <>
  1.6045 +ParseNode *
  1.6046 +Parser<FullParseHandler>::legacyComprehensionTail(ParseNode *bodyStmt, unsigned blockid,
  1.6047 +                                                  GeneratorKind comprehensionKind,
  1.6048 +                                                  ParseContext<FullParseHandler> *outerpc,
  1.6049 +                                                  unsigned innerBlockScopeDepth)
  1.6050 +{
  1.6051 +    /*
  1.6052 +     * If we saw any inner functions while processing the generator expression
  1.6053 +     * then they may have upvars referring to the let vars in this generator
  1.6054 +     * which were not correctly processed. Bail out and start over without
  1.6055 +     * allowing lazy parsing.
  1.6056 +     */
  1.6057 +    if (handler.syntaxParser) {
  1.6058 +        handler.disableSyntaxParser();
  1.6059 +        abortedSyntaxParse = true;
  1.6060 +        return nullptr;
  1.6061 +    }
  1.6062 +
  1.6063 +    unsigned adjust;
  1.6064 +    ParseNode *pn, *pn2, *pn3, **pnp;
  1.6065 +    StmtInfoPC stmtInfo(context);
  1.6066 +    BindData<FullParseHandler> data(context);
  1.6067 +    TokenKind tt;
  1.6068 +
  1.6069 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
  1.6070 +
  1.6071 +    bool isGenexp = comprehensionKind != NotGenerator;
  1.6072 +
  1.6073 +    if (isGenexp) {
  1.6074 +        JS_ASSERT(comprehensionKind == LegacyGenerator);
  1.6075 +        /*
  1.6076 +         * Generator expression desugars to an immediately applied lambda that
  1.6077 +         * yields the next value from a for-in loop (possibly nested, and with
  1.6078 +         * optional if guard). Make pn be the TOK_LC body node.
  1.6079 +         */
  1.6080 +        pn = pushLexicalScope(&stmtInfo);
  1.6081 +        if (!pn)
  1.6082 +            return null();
  1.6083 +        adjust = pn->pn_blockid - blockid;
  1.6084 +    } else {
  1.6085 +        /*
  1.6086 +         * Make a parse-node and literal object representing the block scope of
  1.6087 +         * this array comprehension. Our caller in primaryExpr, the TOK_LB case
  1.6088 +         * aka the array initialiser case, has passed the blockid to claim for
  1.6089 +         * the comprehension's block scope. We allocate that id or one above it
  1.6090 +         * here, by calling PushLexicalScope.
  1.6091 +         *
  1.6092 +         * In the case of a comprehension expression that has nested blocks
  1.6093 +         * (e.g., let expressions), we will allocate a higher blockid but then
  1.6094 +         * slide all blocks "to the right" to make room for the comprehension's
  1.6095 +         * block scope.
  1.6096 +         */
  1.6097 +        adjust = pc->blockid();
  1.6098 +        pn = pushLexicalScope(&stmtInfo);
  1.6099 +        if (!pn)
  1.6100 +            return null();
  1.6101 +
  1.6102 +        JS_ASSERT(blockid <= pn->pn_blockid);
  1.6103 +        JS_ASSERT(blockid < pc->blockidGen);
  1.6104 +        JS_ASSERT(pc->bodyid < blockid);
  1.6105 +        pn->pn_blockid = stmtInfo.blockid = blockid;
  1.6106 +        JS_ASSERT(adjust < blockid);
  1.6107 +        adjust = blockid - adjust;
  1.6108 +    }
  1.6109 +
  1.6110 +    handler.setBeginPosition(pn, bodyStmt);
  1.6111 +
  1.6112 +    pnp = &pn->pn_expr;
  1.6113 +
  1.6114 +    LegacyCompExprTransplanter transplanter(bodyStmt, this, outerpc, comprehensionKind, adjust);
  1.6115 +    if (!transplanter.init())
  1.6116 +        return null();
  1.6117 +
  1.6118 +    if (!transplanter.transplant(bodyStmt))
  1.6119 +        return null();
  1.6120 +
  1.6121 +    JS_ASSERT(pc->staticScope && pc->staticScope == pn->pn_objbox->object);
  1.6122 +    data.initLet(HoistVars, pc->staticScope->as<StaticBlockObject>(), JSMSG_ARRAY_INIT_TOO_BIG);
  1.6123 +
  1.6124 +    do {
  1.6125 +        /*
  1.6126 +         * FOR node is binary, left is loop control and right is body.  Use
  1.6127 +         * index to count each block-local let-variable on the left-hand side
  1.6128 +         * of the in/of.
  1.6129 +         */
  1.6130 +        pn2 = BinaryNode::create(PNK_FOR, &handler);
  1.6131 +        if (!pn2)
  1.6132 +            return null();
  1.6133 +
  1.6134 +        pn2->setOp(JSOP_ITER);
  1.6135 +        pn2->pn_iflags = JSITER_ENUMERATE;
  1.6136 +        if (allowsForEachIn() && tokenStream.matchContextualKeyword(context->names().each))
  1.6137 +            pn2->pn_iflags |= JSITER_FOREACH;
  1.6138 +        MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
  1.6139 +
  1.6140 +        uint32_t startYieldOffset = pc->lastYieldOffset;
  1.6141 +
  1.6142 +        RootedPropertyName name(context);
  1.6143 +        tt = tokenStream.getToken();
  1.6144 +        switch (tt) {
  1.6145 +          case TOK_LB:
  1.6146 +          case TOK_LC:
  1.6147 +            pc->inDeclDestructuring = true;
  1.6148 +            pn3 = primaryExpr(tt);
  1.6149 +            pc->inDeclDestructuring = false;
  1.6150 +            if (!pn3)
  1.6151 +                return null();
  1.6152 +            break;
  1.6153 +
  1.6154 +          case TOK_NAME:
  1.6155 +            name = tokenStream.currentName();
  1.6156 +
  1.6157 +            /*
  1.6158 +             * Create a name node with pn_op JSOP_NAME.  We can't set pn_op to
  1.6159 +             * JSOP_GETLOCAL here, because we don't yet know the block's depth
  1.6160 +             * in the operand stack frame.  The code generator computes that,
  1.6161 +             * and it tries to bind all names to slots, so we must let it do
  1.6162 +             * the deed.
  1.6163 +             */
  1.6164 +            pn3 = newBindingNode(name, false);
  1.6165 +            if (!pn3)
  1.6166 +                return null();
  1.6167 +            break;
  1.6168 +
  1.6169 +          default:
  1.6170 +            report(ParseError, false, null(), JSMSG_NO_VARIABLE_NAME);
  1.6171 +
  1.6172 +          case TOK_ERROR:
  1.6173 +            return null();
  1.6174 +        }
  1.6175 +
  1.6176 +        bool isForOf;
  1.6177 +        if (!matchInOrOf(&isForOf)) {
  1.6178 +            report(ParseError, false, null(), JSMSG_IN_AFTER_FOR_NAME);
  1.6179 +            return null();
  1.6180 +        }
  1.6181 +        ParseNodeKind headKind = PNK_FORIN;
  1.6182 +        if (isForOf) {
  1.6183 +            if (pn2->pn_iflags != JSITER_ENUMERATE) {
  1.6184 +                JS_ASSERT(pn2->pn_iflags == (JSITER_FOREACH | JSITER_ENUMERATE));
  1.6185 +                report(ParseError, false, null(), JSMSG_BAD_FOR_EACH_LOOP);
  1.6186 +                return null();
  1.6187 +            }
  1.6188 +            pn2->pn_iflags = 0;
  1.6189 +            headKind = PNK_FOROF;
  1.6190 +        }
  1.6191 +
  1.6192 +        ParseNode *pn4 = expr();
  1.6193 +        if (!pn4)
  1.6194 +            return null();
  1.6195 +        MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
  1.6196 +
  1.6197 +        if (isGenexp && pc->lastYieldOffset != startYieldOffset) {
  1.6198 +            reportWithOffset(ParseError, false, pc->lastYieldOffset,
  1.6199 +                             JSMSG_BAD_GENEXP_BODY, js_yield_str);
  1.6200 +            return null();
  1.6201 +        }
  1.6202 +
  1.6203 +        switch (tt) {
  1.6204 +          case TOK_LB:
  1.6205 +          case TOK_LC:
  1.6206 +            if (!checkDestructuring(&data, pn3))
  1.6207 +                return null();
  1.6208 +
  1.6209 +            if (versionNumber() == JSVERSION_1_7 &&
  1.6210 +                !(pn2->pn_iflags & JSITER_FOREACH) &&
  1.6211 +                !isForOf)
  1.6212 +            {
  1.6213 +                /* Destructuring requires [key, value] enumeration in JS1.7. */
  1.6214 +                if (!pn3->isKind(PNK_ARRAY) || pn3->pn_count != 2) {
  1.6215 +                    report(ParseError, false, null(), JSMSG_BAD_FOR_LEFTSIDE);
  1.6216 +                    return null();
  1.6217 +                }
  1.6218 +
  1.6219 +                JS_ASSERT(pn2->isOp(JSOP_ITER));
  1.6220 +                JS_ASSERT(pn2->pn_iflags & JSITER_ENUMERATE);
  1.6221 +                JS_ASSERT(headKind == PNK_FORIN);
  1.6222 +                pn2->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
  1.6223 +            }
  1.6224 +            break;
  1.6225 +
  1.6226 +          case TOK_NAME:
  1.6227 +            data.pn = pn3;
  1.6228 +            if (!data.binder(&data, name, this))
  1.6229 +                return null();
  1.6230 +            break;
  1.6231 +
  1.6232 +          default:;
  1.6233 +        }
  1.6234 +
  1.6235 +        /*
  1.6236 +         * Synthesize a declaration. Every definition must appear in the parse
  1.6237 +         * tree in order for ComprehensionTranslator to work.
  1.6238 +         */
  1.6239 +        ParseNode *vars = ListNode::create(PNK_VAR, &handler);
  1.6240 +        if (!vars)
  1.6241 +            return null();
  1.6242 +        vars->setOp(JSOP_NOP);
  1.6243 +        vars->pn_pos = pn3->pn_pos;
  1.6244 +        vars->makeEmpty();
  1.6245 +        vars->append(pn3);
  1.6246 +
  1.6247 +        /* Definitions can't be passed directly to EmitAssignment as lhs. */
  1.6248 +        pn3 = cloneLeftHandSide(pn3);
  1.6249 +        if (!pn3)
  1.6250 +            return null();
  1.6251 +
  1.6252 +        pn2->pn_left = handler.newTernary(headKind, vars, pn3, pn4);
  1.6253 +        if (!pn2->pn_left)
  1.6254 +            return null();
  1.6255 +        *pnp = pn2;
  1.6256 +        pnp = &pn2->pn_right;
  1.6257 +    } while (tokenStream.matchToken(TOK_FOR));
  1.6258 +
  1.6259 +    if (tokenStream.matchToken(TOK_IF)) {
  1.6260 +        pn2 = TernaryNode::create(PNK_IF, &handler);
  1.6261 +        if (!pn2)
  1.6262 +            return null();
  1.6263 +        pn2->pn_kid1 = condition();
  1.6264 +        if (!pn2->pn_kid1)
  1.6265 +            return null();
  1.6266 +        *pnp = pn2;
  1.6267 +        pnp = &pn2->pn_kid2;
  1.6268 +    }
  1.6269 +
  1.6270 +    *pnp = bodyStmt;
  1.6271 +
  1.6272 +    pc->topStmt->innerBlockScopeDepth += innerBlockScopeDepth;
  1.6273 +    PopStatementPC(tokenStream, pc);
  1.6274 +
  1.6275 +    handler.setEndPosition(pn, pos().end);
  1.6276 +
  1.6277 +    return pn;
  1.6278 +}
  1.6279 +
  1.6280 +template <>
  1.6281 +SyntaxParseHandler::Node
  1.6282 +Parser<SyntaxParseHandler>::legacyComprehensionTail(SyntaxParseHandler::Node bodyStmt,
  1.6283 +                                                    unsigned blockid,
  1.6284 +                                                    GeneratorKind comprehensionKind,
  1.6285 +                                                    ParseContext<SyntaxParseHandler> *outerpc,
  1.6286 +                                                    unsigned innerBlockScopeDepth)
  1.6287 +{
  1.6288 +    abortIfSyntaxParser();
  1.6289 +    return null();
  1.6290 +}
  1.6291 +
  1.6292 +template <>
  1.6293 +ParseNode*
  1.6294 +Parser<FullParseHandler>::legacyArrayComprehension(ParseNode *array)
  1.6295 +{
  1.6296 +    array->setKind(PNK_ARRAYCOMP);
  1.6297 +
  1.6298 +    // Remove the single element from array's linked list, leaving us with an
  1.6299 +    // empty array literal and a comprehension expression.
  1.6300 +    JS_ASSERT(array->pn_count == 1);
  1.6301 +    ParseNode *bodyExpr = array->last();
  1.6302 +    array->pn_count = 0;
  1.6303 +    array->pn_tail = &array->pn_head;
  1.6304 +    *array->pn_tail = nullptr;
  1.6305 +
  1.6306 +    ParseNode *arrayPush = handler.newUnary(PNK_ARRAYPUSH, JSOP_ARRAYPUSH,
  1.6307 +                                            bodyExpr->pn_pos.begin, bodyExpr);
  1.6308 +    if (!arrayPush)
  1.6309 +        return null();
  1.6310 +
  1.6311 +    ParseNode *comp = legacyComprehensionTail(arrayPush, array->pn_blockid, NotGenerator,
  1.6312 +                                              nullptr, LegacyComprehensionHeadBlockScopeDepth(pc));
  1.6313 +    if (!comp)
  1.6314 +        return null();
  1.6315 +
  1.6316 +    MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION);
  1.6317 +
  1.6318 +    TokenPos p = handler.getPosition(array);
  1.6319 +    p.end = pos().end;
  1.6320 +    return handler.newArrayComprehension(comp, array->pn_blockid, p);
  1.6321 +}
  1.6322 +
  1.6323 +template <>
  1.6324 +SyntaxParseHandler::Node
  1.6325 +Parser<SyntaxParseHandler>::legacyArrayComprehension(Node array)
  1.6326 +{
  1.6327 +    abortIfSyntaxParser();
  1.6328 +    return null();
  1.6329 +}
  1.6330 +
  1.6331 +template <typename ParseHandler>
  1.6332 +typename ParseHandler::Node
  1.6333 +Parser<ParseHandler>::generatorComprehensionLambda(GeneratorKind comprehensionKind,
  1.6334 +                                                   unsigned begin, Node innerStmt)
  1.6335 +{
  1.6336 +    JS_ASSERT(comprehensionKind == LegacyGenerator || comprehensionKind == StarGenerator);
  1.6337 +    JS_ASSERT(!!innerStmt == (comprehensionKind == LegacyGenerator));
  1.6338 +
  1.6339 +    Node genfn = handler.newFunctionDefinition();
  1.6340 +    if (!genfn)
  1.6341 +        return null();
  1.6342 +    handler.setOp(genfn, JSOP_LAMBDA);
  1.6343 +
  1.6344 +    ParseContext<ParseHandler> *outerpc = pc;
  1.6345 +
  1.6346 +    // If we are off the main thread, the generator meta-objects have
  1.6347 +    // already been created by js::StartOffThreadParseScript, so cx will not
  1.6348 +    // be necessary.
  1.6349 +    RootedObject proto(context);
  1.6350 +    if (comprehensionKind == StarGenerator) {
  1.6351 +        JSContext *cx = context->maybeJSContext();
  1.6352 +        proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, context->global());
  1.6353 +        if (!proto)
  1.6354 +            return null();
  1.6355 +    }
  1.6356 +
  1.6357 +    RootedFunction fun(context, newFunction(outerpc, /* atom = */ NullPtr(), Expression, proto));
  1.6358 +    if (!fun)
  1.6359 +        return null();
  1.6360 +
  1.6361 +    // Create box for fun->object early to root it.
  1.6362 +    Directives directives(/* strict = */ outerpc->sc->strict);
  1.6363 +    FunctionBox *genFunbox = newFunctionBox(genfn, fun, outerpc, directives, comprehensionKind);
  1.6364 +    if (!genFunbox)
  1.6365 +        return null();
  1.6366 +
  1.6367 +    ParseContext<ParseHandler> genpc(this, outerpc, genfn, genFunbox,
  1.6368 +                                     /* newDirectives = */ nullptr,
  1.6369 +                                     outerpc->staticLevel + 1, outerpc->blockidGen,
  1.6370 +                                     /* blockScopeDepth = */ 0);
  1.6371 +    if (!genpc.init(tokenStream))
  1.6372 +        return null();
  1.6373 +
  1.6374 +    /*
  1.6375 +     * We assume conservatively that any deoptimization flags in pc->sc
  1.6376 +     * come from the kid. So we propagate these flags into genfn. For code
  1.6377 +     * simplicity we also do not detect if the flags were only set in the
  1.6378 +     * kid and could be removed from pc->sc.
  1.6379 +     */
  1.6380 +    genFunbox->anyCxFlags = outerpc->sc->anyCxFlags;
  1.6381 +    if (outerpc->sc->isFunctionBox())
  1.6382 +        genFunbox->funCxFlags = outerpc->sc->asFunctionBox()->funCxFlags;
  1.6383 +
  1.6384 +    JS_ASSERT(genFunbox->generatorKind() == comprehensionKind);
  1.6385 +    genFunbox->inGenexpLambda = true;
  1.6386 +    handler.setBlockId(genfn, genpc.bodyid);
  1.6387 +
  1.6388 +    Node body;
  1.6389 +
  1.6390 +    if (comprehensionKind == StarGenerator) {
  1.6391 +        body = comprehension(StarGenerator);
  1.6392 +        if (!body)
  1.6393 +            return null();
  1.6394 +    } else {
  1.6395 +        JS_ASSERT(comprehensionKind == LegacyGenerator);
  1.6396 +        body = legacyComprehensionTail(innerStmt, outerpc->blockid(), LegacyGenerator,
  1.6397 +                                       outerpc, LegacyComprehensionHeadBlockScopeDepth(outerpc));
  1.6398 +        if (!body)
  1.6399 +            return null();
  1.6400 +    }
  1.6401 +
  1.6402 +    if (comprehensionKind == StarGenerator)
  1.6403 +        MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
  1.6404 +
  1.6405 +    handler.setBeginPosition(body, begin);
  1.6406 +    handler.setEndPosition(body, pos().end);
  1.6407 +
  1.6408 +    handler.setBeginPosition(genfn, begin);
  1.6409 +    handler.setEndPosition(genfn, pos().end);
  1.6410 +
  1.6411 +    // Note that if we ever start syntax-parsing generators, we will also
  1.6412 +    // need to propagate the closed-over variable set to the inner
  1.6413 +    // lazyscript, as in finishFunctionDefinition.
  1.6414 +    handler.setFunctionBody(genfn, body);
  1.6415 +
  1.6416 +    PropagateTransitiveParseFlags(genFunbox, outerpc->sc);
  1.6417 +
  1.6418 +    if (!leaveFunction(genfn, outerpc))
  1.6419 +        return null();
  1.6420 +
  1.6421 +    return genfn;
  1.6422 +}
  1.6423 +
  1.6424 +#if JS_HAS_GENERATOR_EXPRS
  1.6425 +
  1.6426 +/*
  1.6427 + * Starting from a |for| keyword after an expression, parse the comprehension
  1.6428 + * tail completing this generator expression. Wrap the expression at kid in a
  1.6429 + * generator function that is immediately called to evaluate to the generator
  1.6430 + * iterator that is the value of this legacy generator expression.
  1.6431 + *
  1.6432 + * |kid| must be the expression before the |for| keyword; we return an
  1.6433 + * application of a generator function that includes the |for| loops and
  1.6434 + * |if| guards, with |kid| as the operand of a |yield| expression as the
  1.6435 + * innermost loop body.
  1.6436 + *
  1.6437 + * Note how unlike Python, we do not evaluate the expression to the right of
  1.6438 + * the first |in| in the chain of |for| heads. Instead, a generator expression
  1.6439 + * is merely sugar for a generator function expression and its application.
  1.6440 + */
  1.6441 +template <>
  1.6442 +ParseNode *
  1.6443 +Parser<FullParseHandler>::legacyGeneratorExpr(ParseNode *expr)
  1.6444 +{
  1.6445 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
  1.6446 +
  1.6447 +    /* Create a |yield| node for |kid|. */
  1.6448 +    ParseNode *yieldExpr = handler.newUnary(PNK_YIELD, JSOP_NOP, expr->pn_pos.begin, expr);
  1.6449 +    if (!yieldExpr)
  1.6450 +        return null();
  1.6451 +    yieldExpr->setInParens(true);
  1.6452 +
  1.6453 +    // A statement to wrap the yield expression.
  1.6454 +    ParseNode *yieldStmt = handler.newExprStatement(yieldExpr, expr->pn_pos.end);
  1.6455 +    if (!yieldStmt)
  1.6456 +        return null();
  1.6457 +
  1.6458 +    /* Make a new node for the desugared generator function. */
  1.6459 +    ParseNode *genfn = generatorComprehensionLambda(LegacyGenerator, expr->pn_pos.begin, yieldStmt);
  1.6460 +    if (!genfn)
  1.6461 +        return null();
  1.6462 +
  1.6463 +    /*
  1.6464 +     * Our result is a call expression that invokes the anonymous generator
  1.6465 +     * function object.
  1.6466 +     */
  1.6467 +    ParseNode *result = ListNode::create(PNK_GENEXP, &handler);
  1.6468 +    if (!result)
  1.6469 +        return null();
  1.6470 +    result->setOp(JSOP_CALL);
  1.6471 +    result->pn_pos.begin = genfn->pn_pos.begin;
  1.6472 +    result->initList(genfn);
  1.6473 +    return result;
  1.6474 +}
  1.6475 +
  1.6476 +template <>
  1.6477 +SyntaxParseHandler::Node
  1.6478 +Parser<SyntaxParseHandler>::legacyGeneratorExpr(Node kid)
  1.6479 +{
  1.6480 +    JS_ALWAYS_FALSE(abortIfSyntaxParser());
  1.6481 +    return SyntaxParseHandler::NodeFailure;
  1.6482 +}
  1.6483 +
  1.6484 +static const char js_generator_str[] = "generator";
  1.6485 +
  1.6486 +#endif /* JS_HAS_GENERATOR_EXPRS */
  1.6487 +
  1.6488 +template <typename ParseHandler>
  1.6489 +typename ParseHandler::Node
  1.6490 +Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
  1.6491 +{
  1.6492 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
  1.6493 +
  1.6494 +    uint32_t begin = pos().begin;
  1.6495 +
  1.6496 +    MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
  1.6497 +
  1.6498 +    // FIXME: Destructuring binding (bug 980828).
  1.6499 +
  1.6500 +    MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME);
  1.6501 +    RootedPropertyName name(context, tokenStream.currentName());
  1.6502 +    if (name == context->names().let) {
  1.6503 +        report(ParseError, false, null(), JSMSG_LET_COMP_BINDING);
  1.6504 +        return null();
  1.6505 +    }
  1.6506 +    if (!tokenStream.matchContextualKeyword(context->names().of)) {
  1.6507 +        report(ParseError, false, null(), JSMSG_OF_AFTER_FOR_NAME);
  1.6508 +        return null();
  1.6509 +    }
  1.6510 +
  1.6511 +    Node rhs = assignExpr();
  1.6512 +    if (!rhs)
  1.6513 +        return null();
  1.6514 +
  1.6515 +    MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_OF_ITERABLE);
  1.6516 +
  1.6517 +    TokenPos headPos(begin, pos().end);
  1.6518 +
  1.6519 +    StmtInfoPC stmtInfo(context);
  1.6520 +    BindData<ParseHandler> data(context);
  1.6521 +    RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context));
  1.6522 +    if (!blockObj)
  1.6523 +        return null();
  1.6524 +    data.initLet(DontHoistVars, *blockObj, JSMSG_TOO_MANY_LOCALS);
  1.6525 +    Node lhs = newName(name);
  1.6526 +    if (!lhs)
  1.6527 +        return null();
  1.6528 +    Node decls = handler.newList(PNK_LET, lhs, JSOP_NOP);
  1.6529 +    if (!decls)
  1.6530 +        return null();
  1.6531 +    data.pn = lhs;
  1.6532 +    if (!data.binder(&data, name, this))
  1.6533 +        return null();
  1.6534 +    Node letScope = pushLetScope(blockObj, &stmtInfo);
  1.6535 +    if (!letScope)
  1.6536 +        return null();
  1.6537 +    handler.setLexicalScopeBody(letScope, decls);
  1.6538 +
  1.6539 +    Node assignLhs = newName(name);
  1.6540 +    if (!assignLhs)
  1.6541 +        return null();
  1.6542 +    if (!noteNameUse(name, assignLhs))
  1.6543 +        return null();
  1.6544 +    handler.setOp(assignLhs, JSOP_SETNAME);
  1.6545 +
  1.6546 +    Node head = handler.newForHead(PNK_FOROF, letScope, assignLhs, rhs, headPos);
  1.6547 +    if (!head)
  1.6548 +        return null();
  1.6549 +
  1.6550 +    Node tail = comprehensionTail(comprehensionKind);
  1.6551 +    if (!tail)
  1.6552 +        return null();
  1.6553 +
  1.6554 +    PopStatementPC(tokenStream, pc);
  1.6555 +
  1.6556 +    return handler.newForStatement(begin, head, tail, JSOP_ITER);
  1.6557 +}
  1.6558 +
  1.6559 +template <typename ParseHandler>
  1.6560 +typename ParseHandler::Node
  1.6561 +Parser<ParseHandler>::comprehensionIf(GeneratorKind comprehensionKind)
  1.6562 +{
  1.6563 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_IF));
  1.6564 +
  1.6565 +    uint32_t begin = pos().begin;
  1.6566 +
  1.6567 +    MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
  1.6568 +    Node cond = assignExpr();
  1.6569 +    if (!cond)
  1.6570 +        return null();
  1.6571 +    MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
  1.6572 +
  1.6573 +    /* Check for (a = b) and warn about possible (a == b) mistype. */
  1.6574 +    if (handler.isOperationWithoutParens(cond, PNK_ASSIGN) &&
  1.6575 +        !report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
  1.6576 +    {
  1.6577 +        return null();
  1.6578 +    }
  1.6579 +
  1.6580 +    Node then = comprehensionTail(comprehensionKind);
  1.6581 +    if (!then)
  1.6582 +        return null();
  1.6583 +
  1.6584 +    return handler.newIfStatement(begin, cond, then, null());
  1.6585 +}
  1.6586 +
  1.6587 +template <typename ParseHandler>
  1.6588 +typename ParseHandler::Node
  1.6589 +Parser<ParseHandler>::comprehensionTail(GeneratorKind comprehensionKind)
  1.6590 +{
  1.6591 +    JS_CHECK_RECURSION(context, return null());
  1.6592 +
  1.6593 +    if (tokenStream.matchToken(TOK_FOR, TokenStream::Operand))
  1.6594 +        return comprehensionFor(comprehensionKind);
  1.6595 +
  1.6596 +    if (tokenStream.matchToken(TOK_IF, TokenStream::Operand))
  1.6597 +        return comprehensionIf(comprehensionKind);
  1.6598 +
  1.6599 +    uint32_t begin = pos().begin;
  1.6600 +
  1.6601 +    Node bodyExpr = assignExpr();
  1.6602 +    if (!bodyExpr)
  1.6603 +        return null();
  1.6604 +
  1.6605 +    if (comprehensionKind == NotGenerator)
  1.6606 +        return handler.newUnary(PNK_ARRAYPUSH, JSOP_ARRAYPUSH, begin, bodyExpr);
  1.6607 +
  1.6608 +    JS_ASSERT(comprehensionKind == StarGenerator);
  1.6609 +    Node yieldExpr = handler.newUnary(PNK_YIELD, JSOP_NOP, begin, bodyExpr);
  1.6610 +    if (!yieldExpr)
  1.6611 +        return null();
  1.6612 +    handler.setInParens(yieldExpr);
  1.6613 +
  1.6614 +    return handler.newExprStatement(yieldExpr, pos().end);
  1.6615 +}
  1.6616 +
  1.6617 +// Parse an ES6 generator or array comprehension, starting at the first 'for'.
  1.6618 +// The caller is responsible for matching the ending TOK_RP or TOK_RB.
  1.6619 +template <typename ParseHandler>
  1.6620 +typename ParseHandler::Node
  1.6621 +Parser<ParseHandler>::comprehension(GeneratorKind comprehensionKind)
  1.6622 +{
  1.6623 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
  1.6624 +
  1.6625 +    uint32_t startYieldOffset = pc->lastYieldOffset;
  1.6626 +
  1.6627 +    Node body = comprehensionFor(comprehensionKind);
  1.6628 +    if (!body)
  1.6629 +        return null();
  1.6630 +
  1.6631 +    if (comprehensionKind != NotGenerator && pc->lastYieldOffset != startYieldOffset) {
  1.6632 +        reportWithOffset(ParseError, false, pc->lastYieldOffset,
  1.6633 +                         JSMSG_BAD_GENEXP_BODY, js_yield_str);
  1.6634 +        return null();
  1.6635 +    }
  1.6636 +
  1.6637 +    return body;
  1.6638 +}
  1.6639 +
  1.6640 +template <typename ParseHandler>
  1.6641 +typename ParseHandler::Node
  1.6642 +Parser<ParseHandler>::arrayComprehension(uint32_t begin)
  1.6643 +{
  1.6644 +    Node inner = comprehension(NotGenerator);
  1.6645 +    if (!inner)
  1.6646 +        return null();
  1.6647 +
  1.6648 +    MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION);
  1.6649 +
  1.6650 +    Node comp = handler.newList(PNK_ARRAYCOMP, inner);
  1.6651 +    if (!comp)
  1.6652 +        return null();
  1.6653 +
  1.6654 +    handler.setBeginPosition(comp, begin);
  1.6655 +    handler.setEndPosition(comp, pos().end);
  1.6656 +
  1.6657 +    return comp;
  1.6658 +}
  1.6659 +
  1.6660 +template <typename ParseHandler>
  1.6661 +typename ParseHandler::Node
  1.6662 +Parser<ParseHandler>::generatorComprehension(uint32_t begin)
  1.6663 +{
  1.6664 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
  1.6665 +
  1.6666 +    // We have no problem parsing generator comprehensions inside lazy
  1.6667 +    // functions, but the bytecode emitter currently can't handle them that way,
  1.6668 +    // because when it goes to emit the code for the inner generator function,
  1.6669 +    // it expects outer functions to have non-lazy scripts.
  1.6670 +    if (!abortIfSyntaxParser())
  1.6671 +        return null();
  1.6672 +
  1.6673 +    Node genfn = generatorComprehensionLambda(StarGenerator, begin, null());
  1.6674 +    if (!genfn)
  1.6675 +        return null();
  1.6676 +
  1.6677 +    Node result = handler.newList(PNK_GENEXP, genfn, JSOP_CALL);
  1.6678 +    if (!result)
  1.6679 +        return null();
  1.6680 +    handler.setBeginPosition(result, begin);
  1.6681 +    handler.setEndPosition(result, pos().end);
  1.6682 +
  1.6683 +    return result;
  1.6684 +}
  1.6685 +
  1.6686 +template <typename ParseHandler>
  1.6687 +typename ParseHandler::Node
  1.6688 +Parser<ParseHandler>::assignExprWithoutYield(unsigned msg)
  1.6689 +{
  1.6690 +    uint32_t startYieldOffset = pc->lastYieldOffset;
  1.6691 +    Node res = assignExpr();
  1.6692 +    if (res && pc->lastYieldOffset != startYieldOffset) {
  1.6693 +        reportWithOffset(ParseError, false, pc->lastYieldOffset,
  1.6694 +                         msg, js_yield_str);
  1.6695 +        return null();
  1.6696 +    }
  1.6697 +    return res;
  1.6698 +}
  1.6699 +
  1.6700 +template <typename ParseHandler>
  1.6701 +bool
  1.6702 +Parser<ParseHandler>::argumentList(Node listNode, bool *isSpread)
  1.6703 +{
  1.6704 +    if (tokenStream.matchToken(TOK_RP, TokenStream::Operand)) {
  1.6705 +        handler.setEndPosition(listNode, pos().end);
  1.6706 +        return true;
  1.6707 +    }
  1.6708 +
  1.6709 +    uint32_t startYieldOffset = pc->lastYieldOffset;
  1.6710 +    bool arg0 = true;
  1.6711 +
  1.6712 +    do {
  1.6713 +        bool spread = false;
  1.6714 +        uint32_t begin = 0;
  1.6715 +        if (tokenStream.matchToken(TOK_TRIPLEDOT, TokenStream::Operand)) {
  1.6716 +            spread = true;
  1.6717 +            begin = pos().begin;
  1.6718 +            *isSpread = true;
  1.6719 +        }
  1.6720 +
  1.6721 +        Node argNode = assignExpr();
  1.6722 +        if (!argNode)
  1.6723 +            return false;
  1.6724 +        if (spread) {
  1.6725 +            argNode = handler.newUnary(PNK_SPREAD, JSOP_NOP, begin, argNode);
  1.6726 +            if (!argNode)
  1.6727 +                return null();
  1.6728 +        }
  1.6729 +
  1.6730 +        if (handler.isOperationWithoutParens(argNode, PNK_YIELD) &&
  1.6731 +            tokenStream.peekToken() == TOK_COMMA) {
  1.6732 +            report(ParseError, false, argNode, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
  1.6733 +            return false;
  1.6734 +        }
  1.6735 +#if JS_HAS_GENERATOR_EXPRS
  1.6736 +        if (!spread && tokenStream.matchToken(TOK_FOR)) {
  1.6737 +            if (pc->lastYieldOffset != startYieldOffset) {
  1.6738 +                reportWithOffset(ParseError, false, pc->lastYieldOffset,
  1.6739 +                                 JSMSG_BAD_GENEXP_BODY, js_yield_str);
  1.6740 +                return false;
  1.6741 +            }
  1.6742 +            argNode = legacyGeneratorExpr(argNode);
  1.6743 +            if (!argNode)
  1.6744 +                return false;
  1.6745 +            if (!arg0 || tokenStream.peekToken() == TOK_COMMA) {
  1.6746 +                report(ParseError, false, argNode, JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
  1.6747 +                return false;
  1.6748 +            }
  1.6749 +        }
  1.6750 +#endif
  1.6751 +        arg0 = false;
  1.6752 +
  1.6753 +        handler.addList(listNode, argNode);
  1.6754 +    } while (tokenStream.matchToken(TOK_COMMA));
  1.6755 +
  1.6756 +    if (tokenStream.getToken() != TOK_RP) {
  1.6757 +        report(ParseError, false, null(), JSMSG_PAREN_AFTER_ARGS);
  1.6758 +        return false;
  1.6759 +    }
  1.6760 +    handler.setEndPosition(listNode, pos().end);
  1.6761 +    return true;
  1.6762 +}
  1.6763 +
  1.6764 +template <typename ParseHandler>
  1.6765 +typename ParseHandler::Node
  1.6766 +Parser<ParseHandler>::memberExpr(TokenKind tt, bool allowCallSyntax)
  1.6767 +{
  1.6768 +    JS_ASSERT(tokenStream.isCurrentTokenType(tt));
  1.6769 +
  1.6770 +    Node lhs;
  1.6771 +
  1.6772 +    JS_CHECK_RECURSION(context, return null());
  1.6773 +
  1.6774 +    /* Check for new expression first. */
  1.6775 +    if (tt == TOK_NEW) {
  1.6776 +        lhs = handler.newList(PNK_NEW, null(), JSOP_NEW);
  1.6777 +        if (!lhs)
  1.6778 +            return null();
  1.6779 +
  1.6780 +        tt = tokenStream.getToken(TokenStream::Operand);
  1.6781 +        Node ctorExpr = memberExpr(tt, false);
  1.6782 +        if (!ctorExpr)
  1.6783 +            return null();
  1.6784 +
  1.6785 +        handler.addList(lhs, ctorExpr);
  1.6786 +
  1.6787 +        if (tokenStream.matchToken(TOK_LP)) {
  1.6788 +            bool isSpread = false;
  1.6789 +            if (!argumentList(lhs, &isSpread))
  1.6790 +                return null();
  1.6791 +            if (isSpread)
  1.6792 +                handler.setOp(lhs, JSOP_SPREADNEW);
  1.6793 +        }
  1.6794 +    } else {
  1.6795 +        lhs = primaryExpr(tt);
  1.6796 +        if (!lhs)
  1.6797 +            return null();
  1.6798 +    }
  1.6799 +
  1.6800 +    while ((tt = tokenStream.getToken()) > TOK_EOF) {
  1.6801 +        Node nextMember;
  1.6802 +        if (tt == TOK_DOT) {
  1.6803 +            tt = tokenStream.getToken(TokenStream::KeywordIsName);
  1.6804 +            if (tt == TOK_ERROR)
  1.6805 +                return null();
  1.6806 +            if (tt == TOK_NAME) {
  1.6807 +                PropertyName *field = tokenStream.currentName();
  1.6808 +                nextMember = handler.newPropertyAccess(lhs, field, pos().end);
  1.6809 +                if (!nextMember)
  1.6810 +                    return null();
  1.6811 +            } else {
  1.6812 +                report(ParseError, false, null(), JSMSG_NAME_AFTER_DOT);
  1.6813 +                return null();
  1.6814 +            }
  1.6815 +        } else if (tt == TOK_LB) {
  1.6816 +            Node propExpr = expr();
  1.6817 +            if (!propExpr)
  1.6818 +                return null();
  1.6819 +
  1.6820 +            MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
  1.6821 +
  1.6822 +            nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end);
  1.6823 +            if (!nextMember)
  1.6824 +                return null();
  1.6825 +        } else if (allowCallSyntax && tt == TOK_LP) {
  1.6826 +            JSOp op = JSOP_CALL;
  1.6827 +            nextMember = handler.newList(PNK_CALL, null(), JSOP_CALL);
  1.6828 +            if (!nextMember)
  1.6829 +                return null();
  1.6830 +
  1.6831 +            if (JSAtom *atom = handler.isName(lhs)) {
  1.6832 +                if (atom == context->names().eval) {
  1.6833 +                    /* Select JSOP_EVAL and flag pc as heavyweight. */
  1.6834 +                    op = JSOP_EVAL;
  1.6835 +                    pc->sc->setBindingsAccessedDynamically();
  1.6836 +
  1.6837 +                    /*
  1.6838 +                     * In non-strict mode code, direct calls to eval can add
  1.6839 +                     * variables to the call object.
  1.6840 +                     */
  1.6841 +                    if (pc->sc->isFunctionBox() && !pc->sc->strict)
  1.6842 +                        pc->sc->asFunctionBox()->setHasExtensibleScope();
  1.6843 +                }
  1.6844 +            } else if (JSAtom *atom = handler.isGetProp(lhs)) {
  1.6845 +                /* Select JSOP_FUNAPPLY given foo.apply(...). */
  1.6846 +                if (atom == context->names().apply) {
  1.6847 +                    op = JSOP_FUNAPPLY;
  1.6848 +                    if (pc->sc->isFunctionBox())
  1.6849 +                        pc->sc->asFunctionBox()->usesApply = true;
  1.6850 +                } else if (atom == context->names().call) {
  1.6851 +                    op = JSOP_FUNCALL;
  1.6852 +                }
  1.6853 +            }
  1.6854 +
  1.6855 +            handler.setBeginPosition(nextMember, lhs);
  1.6856 +            handler.addList(nextMember, lhs);
  1.6857 +
  1.6858 +            bool isSpread = false;
  1.6859 +            if (!argumentList(nextMember, &isSpread))
  1.6860 +                return null();
  1.6861 +            if (isSpread)
  1.6862 +                op = (op == JSOP_EVAL ? JSOP_SPREADEVAL : JSOP_SPREADCALL);
  1.6863 +            handler.setOp(nextMember, op);
  1.6864 +        } else {
  1.6865 +            tokenStream.ungetToken();
  1.6866 +            return lhs;
  1.6867 +        }
  1.6868 +
  1.6869 +        lhs = nextMember;
  1.6870 +    }
  1.6871 +    if (tt == TOK_ERROR)
  1.6872 +        return null();
  1.6873 +    return lhs;
  1.6874 +}
  1.6875 +
  1.6876 +template <typename ParseHandler>
  1.6877 +typename ParseHandler::Node
  1.6878 +Parser<ParseHandler>::newName(PropertyName *name)
  1.6879 +{
  1.6880 +    return handler.newName(name, pc->blockid(), pos());
  1.6881 +}
  1.6882 +
  1.6883 +template <typename ParseHandler>
  1.6884 +typename ParseHandler::Node
  1.6885 +Parser<ParseHandler>::identifierName()
  1.6886 +{
  1.6887 +    RootedPropertyName name(context, tokenStream.currentName());
  1.6888 +    Node pn = newName(name);
  1.6889 +    if (!pn)
  1.6890 +        return null();
  1.6891 +
  1.6892 +    if (!pc->inDeclDestructuring && !noteNameUse(name, pn))
  1.6893 +        return null();
  1.6894 +
  1.6895 +    return pn;
  1.6896 +}
  1.6897 +
  1.6898 +template <typename ParseHandler>
  1.6899 +typename ParseHandler::Node
  1.6900 +Parser<ParseHandler>::stringLiteral()
  1.6901 +{
  1.6902 +    JSAtom *atom = tokenStream.currentToken().atom();
  1.6903 +
  1.6904 +    // Large strings are fast to parse but slow to compress. Stop compression on
  1.6905 +    // them, so we don't wait for a long time for compression to finish at the
  1.6906 +    // end of compilation.
  1.6907 +    const size_t HUGE_STRING = 50000;
  1.6908 +    if (sct && sct->active() && atom->length() >= HUGE_STRING)
  1.6909 +        sct->abort();
  1.6910 +
  1.6911 +    return handler.newStringLiteral(atom, pos());
  1.6912 +}
  1.6913 +
  1.6914 +template <typename ParseHandler>
  1.6915 +typename ParseHandler::Node
  1.6916 +Parser<ParseHandler>::newRegExp()
  1.6917 +{
  1.6918 +    // Create the regexp even when doing a syntax parse, to check the regexp's syntax.
  1.6919 +    const jschar *chars = tokenStream.getTokenbuf().begin();
  1.6920 +    size_t length = tokenStream.getTokenbuf().length();
  1.6921 +    RegExpFlag flags = tokenStream.currentToken().regExpFlags();
  1.6922 +
  1.6923 +    Rooted<RegExpObject*> reobj(context);
  1.6924 +    if (RegExpStatics *res = context->global()->getRegExpStatics())
  1.6925 +        reobj = RegExpObject::create(context, res, chars, length, flags, &tokenStream);
  1.6926 +    else
  1.6927 +        reobj = RegExpObject::createNoStatics(context, chars, length, flags, &tokenStream);
  1.6928 +
  1.6929 +    if (!reobj)
  1.6930 +        return null();
  1.6931 +
  1.6932 +    return handler.newRegExp(reobj, pos(), *this);
  1.6933 +}
  1.6934 +
  1.6935 +template <typename ParseHandler>
  1.6936 +typename ParseHandler::Node
  1.6937 +Parser<ParseHandler>::arrayInitializer()
  1.6938 +{
  1.6939 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_LB));
  1.6940 +
  1.6941 +    uint32_t begin = pos().begin;
  1.6942 +    Node literal = handler.newArrayLiteral(begin, pc->blockidGen);
  1.6943 +    if (!literal)
  1.6944 +        return null();
  1.6945 +
  1.6946 +    if (tokenStream.matchToken(TOK_RB, TokenStream::Operand)) {
  1.6947 +        /*
  1.6948 +         * Mark empty arrays as non-constant, since we cannot easily
  1.6949 +         * determine their type.
  1.6950 +         */
  1.6951 +        handler.setListFlag(literal, PNX_NONCONST);
  1.6952 +    } else if (tokenStream.matchToken(TOK_FOR, TokenStream::Operand)) {
  1.6953 +        // ES6 array comprehension.
  1.6954 +        return arrayComprehension(begin);
  1.6955 +    } else {
  1.6956 +        bool spread = false, missingTrailingComma = false;
  1.6957 +        uint32_t index = 0;
  1.6958 +        for (; ; index++) {
  1.6959 +            if (index == JSObject::NELEMENTS_LIMIT) {
  1.6960 +                report(ParseError, false, null(), JSMSG_ARRAY_INIT_TOO_BIG);
  1.6961 +                return null();
  1.6962 +            }
  1.6963 +
  1.6964 +            TokenKind tt = tokenStream.peekToken(TokenStream::Operand);
  1.6965 +            if (tt == TOK_RB)
  1.6966 +                break;
  1.6967 +
  1.6968 +            if (tt == TOK_COMMA) {
  1.6969 +                tokenStream.consumeKnownToken(TOK_COMMA);
  1.6970 +                if (!handler.addElision(literal, pos()))
  1.6971 +                    return null();
  1.6972 +            } else if (tt == TOK_TRIPLEDOT) {
  1.6973 +                spread = true;
  1.6974 +                tokenStream.consumeKnownToken(TOK_TRIPLEDOT);
  1.6975 +                uint32_t begin = pos().begin;
  1.6976 +                Node inner = assignExpr();
  1.6977 +                if (!inner)
  1.6978 +                    return null();
  1.6979 +                if (!handler.addSpreadElement(literal, begin, inner))
  1.6980 +                    return null();
  1.6981 +            } else {
  1.6982 +                Node element = assignExpr();
  1.6983 +                if (!element)
  1.6984 +                    return null();
  1.6985 +                if (foldConstants && !FoldConstants(context, &element, this))
  1.6986 +                    return null();
  1.6987 +                if (!handler.addArrayElement(literal, element))
  1.6988 +                    return null();
  1.6989 +            }
  1.6990 +
  1.6991 +            if (tt != TOK_COMMA) {
  1.6992 +                /* If we didn't already match TOK_COMMA in above case. */
  1.6993 +                if (!tokenStream.matchToken(TOK_COMMA)) {
  1.6994 +                    missingTrailingComma = true;
  1.6995 +                    break;
  1.6996 +                }
  1.6997 +            }
  1.6998 +        }
  1.6999 +
  1.7000 +        /*
  1.7001 +         * At this point, (index == 0 && missingTrailingComma) implies one
  1.7002 +         * element initialiser was parsed.
  1.7003 +         *
  1.7004 +         * A legacy array comprehension of the form:
  1.7005 +         *
  1.7006 +         *   [i * j for (i in o) for (j in p) if (i != j)]
  1.7007 +         *
  1.7008 +         * translates to roughly the following let expression:
  1.7009 +         *
  1.7010 +         *   let (array = new Array, i, j) {
  1.7011 +         *     for (i in o) let {
  1.7012 +         *       for (j in p)
  1.7013 +         *         if (i != j)
  1.7014 +         *           array.push(i * j)
  1.7015 +         *     }
  1.7016 +         *     array
  1.7017 +         *   }
  1.7018 +         *
  1.7019 +         * where array is a nameless block-local variable. The "roughly" means
  1.7020 +         * that an implementation may optimize away the array.push.  A legacy
  1.7021 +         * array comprehension opens exactly one block scope, no matter how many
  1.7022 +         * for heads it contains.
  1.7023 +         *
  1.7024 +         * Each let () {...} or for (let ...) ... compiles to:
  1.7025 +         *
  1.7026 +         *   JSOP_PUSHN <N>            // Push space for block-scoped locals.
  1.7027 +         *   (JSOP_PUSHBLOCKSCOPE <O>) // If a local is aliased, push on scope
  1.7028 +         *                             // chain.
  1.7029 +         *   ...
  1.7030 +         *   JSOP_DEBUGLEAVEBLOCK      // Invalidate any DebugScope proxies.
  1.7031 +         *   JSOP_POPBLOCKSCOPE?       // Pop off scope chain, if needed.
  1.7032 +         *   JSOP_POPN <N>             // Pop space for block-scoped locals.
  1.7033 +         *
  1.7034 +         * where <o> is a literal object representing the block scope,
  1.7035 +         * with <n> properties, naming each var declared in the block.
  1.7036 +         *
  1.7037 +         * Each var declaration in a let-block binds a name in <o> at compile
  1.7038 +         * time. A block-local var is accessed by the JSOP_GETLOCAL and
  1.7039 +         * JSOP_SETLOCAL ops. These ops have an immediate operand, the local
  1.7040 +         * slot's stack index from fp->spbase.
  1.7041 +         *
  1.7042 +         * The legacy array comprehension iteration step, array.push(i * j) in
  1.7043 +         * the example above, is done by <i * j>; JSOP_ARRAYPUSH <array>, where
  1.7044 +         * <array> is the index of array's stack slot.
  1.7045 +         */
  1.7046 +        if (index == 0 && !spread && tokenStream.matchToken(TOK_FOR) && missingTrailingComma)
  1.7047 +            return legacyArrayComprehension(literal);
  1.7048 +
  1.7049 +        MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_LIST);
  1.7050 +    }
  1.7051 +    handler.setEndPosition(literal, pos().end);
  1.7052 +    return literal;
  1.7053 +}
  1.7054 +
  1.7055 +static JSAtom*
  1.7056 +DoubleToAtom(ExclusiveContext *cx, double value)
  1.7057 +{
  1.7058 +    // This is safe because doubles can not be moved.
  1.7059 +    Value tmp = DoubleValue(value);
  1.7060 +    return ToAtom<CanGC>(cx, HandleValue::fromMarkedLocation(&tmp));
  1.7061 +}
  1.7062 +
  1.7063 +template <typename ParseHandler>
  1.7064 +typename ParseHandler::Node
  1.7065 +Parser<ParseHandler>::objectLiteral()
  1.7066 +{
  1.7067 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
  1.7068 +
  1.7069 +    /*
  1.7070 +     * A map from property names we've seen thus far to a mask of property
  1.7071 +     * assignment types.
  1.7072 +     */
  1.7073 +    AtomIndexMap seen;
  1.7074 +
  1.7075 +    enum AssignmentType {
  1.7076 +        GET     = 0x1,
  1.7077 +        SET     = 0x2,
  1.7078 +        VALUE   = 0x4 | GET | SET
  1.7079 +    };
  1.7080 +
  1.7081 +    Node literal = handler.newObjectLiteral(pos().begin);
  1.7082 +    if (!literal)
  1.7083 +        return null();
  1.7084 +
  1.7085 +    RootedAtom atom(context);
  1.7086 +    for (;;) {
  1.7087 +        TokenKind ltok = tokenStream.getToken(TokenStream::KeywordIsName);
  1.7088 +        if (ltok == TOK_RC)
  1.7089 +            break;
  1.7090 +
  1.7091 +        JSOp op = JSOP_INITPROP;
  1.7092 +        Node propname;
  1.7093 +        switch (ltok) {
  1.7094 +          case TOK_NUMBER:
  1.7095 +            atom = DoubleToAtom(context, tokenStream.currentToken().number());
  1.7096 +            if (!atom)
  1.7097 +                return null();
  1.7098 +            propname = newNumber(tokenStream.currentToken());
  1.7099 +            break;
  1.7100 +
  1.7101 +          case TOK_NAME: {
  1.7102 +            atom = tokenStream.currentName();
  1.7103 +            if (atom == context->names().get) {
  1.7104 +                op = JSOP_INITPROP_GETTER;
  1.7105 +            } else if (atom == context->names().set) {
  1.7106 +                op = JSOP_INITPROP_SETTER;
  1.7107 +            } else {
  1.7108 +                propname = handler.newIdentifier(atom, pos());
  1.7109 +                if (!propname)
  1.7110 +                    return null();
  1.7111 +                break;
  1.7112 +            }
  1.7113 +
  1.7114 +            // We have parsed |get| or |set|. Look for an accessor property
  1.7115 +            // name next.
  1.7116 +            TokenKind tt = tokenStream.getToken(TokenStream::KeywordIsName);
  1.7117 +            if (tt == TOK_NAME) {
  1.7118 +                atom = tokenStream.currentName();
  1.7119 +                propname = newName(atom->asPropertyName());
  1.7120 +                if (!propname)
  1.7121 +                    return null();
  1.7122 +            } else if (tt == TOK_STRING) {
  1.7123 +                atom = tokenStream.currentToken().atom();
  1.7124 +
  1.7125 +                uint32_t index;
  1.7126 +                if (atom->isIndex(&index)) {
  1.7127 +                    propname = handler.newNumber(index, NoDecimal, pos());
  1.7128 +                    if (!propname)
  1.7129 +                        return null();
  1.7130 +                    atom = DoubleToAtom(context, index);
  1.7131 +                    if (!atom)
  1.7132 +                        return null();
  1.7133 +                } else {
  1.7134 +                    propname = stringLiteral();
  1.7135 +                    if (!propname)
  1.7136 +                        return null();
  1.7137 +                }
  1.7138 +            } else if (tt == TOK_NUMBER) {
  1.7139 +                atom = DoubleToAtom(context, tokenStream.currentToken().number());
  1.7140 +                if (!atom)
  1.7141 +                    return null();
  1.7142 +                propname = newNumber(tokenStream.currentToken());
  1.7143 +                if (!propname)
  1.7144 +                    return null();
  1.7145 +            } else {
  1.7146 +                // Not an accessor property after all.
  1.7147 +                tokenStream.ungetToken();
  1.7148 +                propname = handler.newIdentifier(atom, pos());
  1.7149 +                if (!propname)
  1.7150 +                    return null();
  1.7151 +                op = JSOP_INITPROP;
  1.7152 +                break;
  1.7153 +            }
  1.7154 +
  1.7155 +            JS_ASSERT(op == JSOP_INITPROP_GETTER || op == JSOP_INITPROP_SETTER);
  1.7156 +            break;
  1.7157 +          }
  1.7158 +
  1.7159 +          case TOK_STRING: {
  1.7160 +            atom = tokenStream.currentToken().atom();
  1.7161 +            uint32_t index;
  1.7162 +            if (atom->isIndex(&index)) {
  1.7163 +                propname = handler.newNumber(index, NoDecimal, pos());
  1.7164 +                if (!propname)
  1.7165 +                    return null();
  1.7166 +            } else {
  1.7167 +                propname = stringLiteral();
  1.7168 +                if (!propname)
  1.7169 +                    return null();
  1.7170 +            }
  1.7171 +            break;
  1.7172 +          }
  1.7173 +
  1.7174 +          default:
  1.7175 +            report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
  1.7176 +            return null();
  1.7177 +        }
  1.7178 +
  1.7179 +        if (op == JSOP_INITPROP) {
  1.7180 +            TokenKind tt = tokenStream.getToken();
  1.7181 +            Node propexpr;
  1.7182 +            if (tt == TOK_COLON) {
  1.7183 +                propexpr = assignExpr();
  1.7184 +                if (!propexpr)
  1.7185 +                    return null();
  1.7186 +
  1.7187 +                if (foldConstants && !FoldConstants(context, &propexpr, this))
  1.7188 +                    return null();
  1.7189 +
  1.7190 +                /*
  1.7191 +                 * Treat initializers which mutate __proto__ as non-constant,
  1.7192 +                 * so that we can later assume singleton objects delegate to
  1.7193 +                 * the default Object.prototype.
  1.7194 +                 */
  1.7195 +                if (!handler.isConstant(propexpr) || atom == context->names().proto)
  1.7196 +                    handler.setListFlag(literal, PNX_NONCONST);
  1.7197 +
  1.7198 +                if (!handler.addPropertyDefinition(literal, propname, propexpr))
  1.7199 +                    return null();
  1.7200 +            }
  1.7201 +            else if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC)) {
  1.7202 +                /*
  1.7203 +                 * Support, e.g., |var {x, y} = o| as destructuring shorthand
  1.7204 +                 * for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8.
  1.7205 +                 */
  1.7206 +                if (!abortIfSyntaxParser())
  1.7207 +                    return null();
  1.7208 +                tokenStream.ungetToken();
  1.7209 +                if (!tokenStream.checkForKeyword(atom->charsZ(), atom->length(), nullptr))
  1.7210 +                    return null();
  1.7211 +                PropertyName *name = handler.isName(propname);
  1.7212 +                JS_ASSERT(atom);
  1.7213 +                propname = newName(name);
  1.7214 +                if (!propname)
  1.7215 +                    return null();
  1.7216 +                if (!handler.addShorthandPropertyDefinition(literal, propname))
  1.7217 +                    return null();
  1.7218 +            }
  1.7219 +            else {
  1.7220 +                report(ParseError, false, null(), JSMSG_COLON_AFTER_ID);
  1.7221 +                return null();
  1.7222 +            }
  1.7223 +        } else {
  1.7224 +            /* NB: Getter function in { get x(){} } is unnamed. */
  1.7225 +            Rooted<PropertyName*> funName(context, nullptr);
  1.7226 +            TokenStream::Position start(keepAtoms);
  1.7227 +            tokenStream.tell(&start);
  1.7228 +            Node accessor = functionDef(funName, start, op == JSOP_INITPROP_GETTER ? Getter : Setter,
  1.7229 +                                        Expression, NotGenerator);
  1.7230 +            if (!accessor)
  1.7231 +                return null();
  1.7232 +            if (!handler.addAccessorPropertyDefinition(literal, propname, accessor, op))
  1.7233 +                return null();
  1.7234 +        }
  1.7235 +
  1.7236 +        /*
  1.7237 +         * Check for duplicate property names.  Duplicate data properties
  1.7238 +         * only conflict in strict mode.  Duplicate getter or duplicate
  1.7239 +         * setter halves always conflict.  A data property conflicts with
  1.7240 +         * any part of an accessor property.
  1.7241 +         */
  1.7242 +        AssignmentType assignType;
  1.7243 +        if (op == JSOP_INITPROP)
  1.7244 +            assignType = VALUE;
  1.7245 +        else if (op == JSOP_INITPROP_GETTER)
  1.7246 +            assignType = GET;
  1.7247 +        else if (op == JSOP_INITPROP_SETTER)
  1.7248 +            assignType = SET;
  1.7249 +        else
  1.7250 +            MOZ_ASSUME_UNREACHABLE("bad opcode in object initializer");
  1.7251 +
  1.7252 +        AtomIndexAddPtr p = seen.lookupForAdd(atom);
  1.7253 +        if (p) {
  1.7254 +            jsatomid index = p.value();
  1.7255 +            AssignmentType oldAssignType = AssignmentType(index);
  1.7256 +            if ((oldAssignType & assignType) &&
  1.7257 +                (oldAssignType != VALUE || assignType != VALUE || pc->sc->needStrictChecks()))
  1.7258 +            {
  1.7259 +                JSAutoByteString name;
  1.7260 +                if (!AtomToPrintableString(context, atom, &name))
  1.7261 +                    return null();
  1.7262 +
  1.7263 +                ParseReportKind reportKind =
  1.7264 +                    (oldAssignType == VALUE && assignType == VALUE && !pc->sc->needStrictChecks())
  1.7265 +                    ? ParseWarning
  1.7266 +                    : (pc->sc->needStrictChecks() ? ParseStrictError : ParseError);
  1.7267 +                if (!report(reportKind, pc->sc->strict, null(),
  1.7268 +                            JSMSG_DUPLICATE_PROPERTY, name.ptr()))
  1.7269 +                {
  1.7270 +                    return null();
  1.7271 +                }
  1.7272 +            }
  1.7273 +            p.value() = assignType | oldAssignType;
  1.7274 +        } else {
  1.7275 +            if (!seen.add(p, atom, assignType))
  1.7276 +                return null();
  1.7277 +        }
  1.7278 +
  1.7279 +        TokenKind tt = tokenStream.getToken();
  1.7280 +        if (tt == TOK_RC)
  1.7281 +            break;
  1.7282 +        if (tt != TOK_COMMA) {
  1.7283 +            report(ParseError, false, null(), JSMSG_CURLY_AFTER_LIST);
  1.7284 +            return null();
  1.7285 +        }
  1.7286 +    }
  1.7287 +
  1.7288 +    handler.setEndPosition(literal, pos().end);
  1.7289 +    return literal;
  1.7290 +}
  1.7291 +
  1.7292 +template <typename ParseHandler>
  1.7293 +typename ParseHandler::Node
  1.7294 +Parser<ParseHandler>::primaryExpr(TokenKind tt)
  1.7295 +{
  1.7296 +    JS_ASSERT(tokenStream.isCurrentTokenType(tt));
  1.7297 +    JS_CHECK_RECURSION(context, return null());
  1.7298 +
  1.7299 +    switch (tt) {
  1.7300 +      case TOK_FUNCTION:
  1.7301 +        return functionExpr();
  1.7302 +
  1.7303 +      case TOK_LB:
  1.7304 +        return arrayInitializer();
  1.7305 +
  1.7306 +      case TOK_LC:
  1.7307 +        return objectLiteral();
  1.7308 +
  1.7309 +      case TOK_LET:
  1.7310 +        return letBlock(LetExpresion);
  1.7311 +
  1.7312 +      case TOK_LP:
  1.7313 +        return parenExprOrGeneratorComprehension();
  1.7314 +
  1.7315 +      case TOK_STRING:
  1.7316 +        return stringLiteral();
  1.7317 +
  1.7318 +      case TOK_YIELD:
  1.7319 +        if (!checkYieldNameValidity())
  1.7320 +            return null();
  1.7321 +        // Fall through.
  1.7322 +      case TOK_NAME:
  1.7323 +        return identifierName();
  1.7324 +
  1.7325 +      case TOK_REGEXP:
  1.7326 +        return newRegExp();
  1.7327 +
  1.7328 +      case TOK_NUMBER:
  1.7329 +        return newNumber(tokenStream.currentToken());
  1.7330 +
  1.7331 +      case TOK_TRUE:
  1.7332 +        return handler.newBooleanLiteral(true, pos());
  1.7333 +      case TOK_FALSE:
  1.7334 +        return handler.newBooleanLiteral(false, pos());
  1.7335 +      case TOK_THIS:
  1.7336 +        return handler.newThisLiteral(pos());
  1.7337 +      case TOK_NULL:
  1.7338 +        return handler.newNullLiteral(pos());
  1.7339 +
  1.7340 +      case TOK_RP:
  1.7341 +        // Not valid expression syntax, but this is valid in an arrow function
  1.7342 +        // with no params: `() => body`.
  1.7343 +        if (tokenStream.peekToken() == TOK_ARROW) {
  1.7344 +            tokenStream.ungetToken();  // put back right paren
  1.7345 +
  1.7346 +            // Now just return something that will allow parsing to continue.
  1.7347 +            // It doesn't matter what; when we reach the =>, we will rewind and
  1.7348 +            // reparse the whole arrow function. See Parser::assignExpr.
  1.7349 +            return handler.newNullLiteral(pos());
  1.7350 +        }
  1.7351 +        report(ParseError, false, null(), JSMSG_SYNTAX_ERROR);
  1.7352 +        return null();
  1.7353 +
  1.7354 +      case TOK_TRIPLEDOT:
  1.7355 +        // Not valid expression syntax, but this is valid in an arrow function
  1.7356 +        // with a rest param: `(a, b, ...rest) => body`.
  1.7357 +        if (tokenStream.matchToken(TOK_NAME) &&
  1.7358 +            tokenStream.matchToken(TOK_RP) &&
  1.7359 +            tokenStream.peekToken() == TOK_ARROW)
  1.7360 +        {
  1.7361 +            tokenStream.ungetToken();  // put back right paren
  1.7362 +
  1.7363 +            // Return an arbitrary expression node. See case TOK_RP above.
  1.7364 +            return handler.newNullLiteral(pos());
  1.7365 +        }
  1.7366 +        report(ParseError, false, null(), JSMSG_SYNTAX_ERROR);
  1.7367 +        return null();
  1.7368 +
  1.7369 +      case TOK_ERROR:
  1.7370 +        /* The scanner or one of its subroutines reported the error. */
  1.7371 +        return null();
  1.7372 +
  1.7373 +      default:
  1.7374 +        report(ParseError, false, null(), JSMSG_SYNTAX_ERROR);
  1.7375 +        return null();
  1.7376 +    }
  1.7377 +}
  1.7378 +
  1.7379 +template <typename ParseHandler>
  1.7380 +typename ParseHandler::Node
  1.7381 +Parser<ParseHandler>::parenExprOrGeneratorComprehension()
  1.7382 +{
  1.7383 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_LP));
  1.7384 +    uint32_t begin = pos().begin;
  1.7385 +    uint32_t startYieldOffset = pc->lastYieldOffset;
  1.7386 +
  1.7387 +    if (tokenStream.matchToken(TOK_FOR, TokenStream::Operand))
  1.7388 +        return generatorComprehension(begin);
  1.7389 +
  1.7390 +    /*
  1.7391 +     * Always accept the 'in' operator in a parenthesized expression,
  1.7392 +     * where it's unambiguous, even if we might be parsing the init of a
  1.7393 +     * for statement.
  1.7394 +     */
  1.7395 +    bool oldParsingForInit = pc->parsingForInit;
  1.7396 +    pc->parsingForInit = false;
  1.7397 +    Node pn = expr();
  1.7398 +    pc->parsingForInit = oldParsingForInit;
  1.7399 +
  1.7400 +    if (!pn)
  1.7401 +        return null();
  1.7402 +
  1.7403 +#if JS_HAS_GENERATOR_EXPRS
  1.7404 +    if (tokenStream.matchToken(TOK_FOR)) {
  1.7405 +        if (pc->lastYieldOffset != startYieldOffset) {
  1.7406 +            reportWithOffset(ParseError, false, pc->lastYieldOffset,
  1.7407 +                             JSMSG_BAD_GENEXP_BODY, js_yield_str);
  1.7408 +            return null();
  1.7409 +        }
  1.7410 +        if (handler.isOperationWithoutParens(pn, PNK_COMMA)) {
  1.7411 +            report(ParseError, false, null(),
  1.7412 +                   JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
  1.7413 +            return null();
  1.7414 +        }
  1.7415 +        pn = legacyGeneratorExpr(pn);
  1.7416 +        if (!pn)
  1.7417 +            return null();
  1.7418 +        handler.setBeginPosition(pn, begin);
  1.7419 +        if (tokenStream.getToken() != TOK_RP) {
  1.7420 +            report(ParseError, false, null(),
  1.7421 +                   JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
  1.7422 +            return null();
  1.7423 +        }
  1.7424 +        handler.setEndPosition(pn, pos().end);
  1.7425 +        handler.setInParens(pn);
  1.7426 +        return pn;
  1.7427 +    }
  1.7428 +#endif /* JS_HAS_GENERATOR_EXPRS */
  1.7429 +
  1.7430 +    pn = handler.setInParens(pn);
  1.7431 +
  1.7432 +    MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
  1.7433 +
  1.7434 +    return pn;
  1.7435 +}
  1.7436 +
  1.7437 +// Legacy generator comprehensions can sometimes appear without parentheses.
  1.7438 +// For example:
  1.7439 +//
  1.7440 +//   foo(x for (x in bar))
  1.7441 +//
  1.7442 +// In this case the parens are part of the call, and not part of the generator
  1.7443 +// comprehension.  This can happen in these contexts:
  1.7444 +//
  1.7445 +//   if (_)
  1.7446 +//   while (_) {}
  1.7447 +//   do {} while (_)
  1.7448 +//   switch (_) {}
  1.7449 +//   with (_) {}
  1.7450 +//   foo(_) // must be first and only argument
  1.7451 +//
  1.7452 +// This is not the case for ES6 generator comprehensions; they must always be in
  1.7453 +// parentheses.
  1.7454 +
  1.7455 +template <typename ParseHandler>
  1.7456 +typename ParseHandler::Node
  1.7457 +Parser<ParseHandler>::exprInParens()
  1.7458 +{
  1.7459 +    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_LP));
  1.7460 +    uint32_t begin = pos().begin;
  1.7461 +    uint32_t startYieldOffset = pc->lastYieldOffset;
  1.7462 +
  1.7463 +    /*
  1.7464 +     * Always accept the 'in' operator in a parenthesized expression,
  1.7465 +     * where it's unambiguous, even if we might be parsing the init of a
  1.7466 +     * for statement.
  1.7467 +     */
  1.7468 +    bool oldParsingForInit = pc->parsingForInit;
  1.7469 +    pc->parsingForInit = false;
  1.7470 +    Node pn = expr();
  1.7471 +    pc->parsingForInit = oldParsingForInit;
  1.7472 +
  1.7473 +    if (!pn)
  1.7474 +        return null();
  1.7475 +
  1.7476 +#if JS_HAS_GENERATOR_EXPRS
  1.7477 +    if (tokenStream.matchToken(TOK_FOR)) {
  1.7478 +        if (pc->lastYieldOffset != startYieldOffset) {
  1.7479 +            reportWithOffset(ParseError, false, pc->lastYieldOffset,
  1.7480 +                             JSMSG_BAD_GENEXP_BODY, js_yield_str);
  1.7481 +            return null();
  1.7482 +        }
  1.7483 +        if (handler.isOperationWithoutParens(pn, PNK_COMMA)) {
  1.7484 +            report(ParseError, false, null(),
  1.7485 +                   JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
  1.7486 +            return null();
  1.7487 +        }
  1.7488 +        pn = legacyGeneratorExpr(pn);
  1.7489 +        if (!pn)
  1.7490 +            return null();
  1.7491 +        handler.setBeginPosition(pn, begin);
  1.7492 +    }
  1.7493 +#endif /* JS_HAS_GENERATOR_EXPRS */
  1.7494 +
  1.7495 +    return pn;
  1.7496 +}
  1.7497 +
  1.7498 +template class Parser<FullParseHandler>;
  1.7499 +template class Parser<SyntaxParseHandler>;
  1.7500 +
  1.7501 +} /* namespace frontend */
  1.7502 +} /* namespace js */

mercurial