LCOV - app.info - js/src/frontend/Parser.cpp

LCOV - code coverage report
| Current view: | directory - js/src/frontend - Parser.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 3531 | 2724 | 77.1 %
| Date: | 2012-04-07 | Functions: | 139 | 136 | 97.8 %

           1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=8 sw=4 et tw=99:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is Mozilla Communicator client code, released
          18                 :  * March 31, 1998.
          19                 :  *
          20                 :  * The Initial Developer of the Original Code is
          21                 :  * Netscape Communications Corporation.
          22                 :  * Portions created by the Initial Developer are Copyright (C) 1998
          23                 :  * the Initial Developer. All Rights Reserved.
          24                 :  *
          25                 :  * Contributor(s):
          26                 :  *
          27                 :  * Alternatively, the contents of this file may be used under the terms of
          28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          31                 :  * of those above. If you wish to allow use of your version of this file only
          32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          33                 :  * use your version of this file under the terms of the MPL, indicate your
          34                 :  * decision by deleting the provisions above and replace them with the notice
          35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          36                 :  * the provisions above, a recipient may use your version of this file under
          37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          38                 :  *
          39                 :  * ***** END LICENSE BLOCK ***** */
          40                 :
          41                 : /*
          42                 :  * JS parser.
          43                 :  *
          44                 :  * This is a recursive-descent parser for the JavaScript language specified by
          45                 :  * "The JavaScript 1.5 Language Specification".  It uses lexical and semantic
          46                 :  * feedback to disambiguate non-LL(1) structures.  It generates trees of nodes
          47                 :  * induced by the recursive parsing (not precise syntax trees, see Parser.h).
          48                 :  * After tree construction, it rewrites trees to fold constants and evaluate
          49                 :  * compile-time expressions.  Finally, it calls js::frontend::EmitTree (see
          50                 :  * BytecodeEmitter.h) to generate bytecode.
          51                 :  *
          52                 :  * This parser attempts no error recovery.
          53                 :  */
          54                 :
          55                 : #include "frontend/Parser.h"
          56                 :
          57                 : #include <stdlib.h>
          58                 : #include <string.h>
          59                 : #include "jstypes.h"
          60                 : #include "jsutil.h"
          61                 : #include "jsapi.h"
          62                 : #include "jsarray.h"
          63                 : #include "jsatom.h"
          64                 : #include "jscntxt.h"
          65                 : #include "jsversion.h"
          66                 : #include "jsfun.h"
          67                 : #include "jsgc.h"
          68                 : #include "jsgcmark.h"
          69                 : #include "jsinterp.h"
          70                 : #include "jsiter.h"
          71                 : #include "jslock.h"
          72                 : #include "jsnum.h"
          73                 : #include "jsobj.h"
          74                 : #include "jsopcode.h"
          75                 : #include "jsscope.h"
          76                 : #include "jsscript.h"
          77                 : #include "jsstr.h"
          78                 :
          79                 : #include "frontend/BytecodeCompiler.h"
          80                 : #include "frontend/BytecodeEmitter.h"
          81                 : #include "frontend/FoldConstants.h"
          82                 : #include "frontend/ParseMaps.h"
          83                 : #include "frontend/TokenStream.h"
          84                 :
          85                 : #if JS_HAS_XML_SUPPORT
          86                 : #include "jsxml.h"
          87                 : #endif
          88                 :
          89                 : #include "jsatominlines.h"
          90                 : #include "jsscriptinlines.h"
          91                 :
          92                 : #include "frontend/BytecodeEmitter-inl.h"
          93                 : #include "frontend/ParseMaps-inl.h"
          94                 : #include "frontend/ParseNode-inl.h"
          95                 : #include "vm/RegExpObject-inl.h"
          96                 :
          97                 : using namespace js;
          98                 : using namespace js::gc;
          99                 : using namespace js::frontend;
         100                 :
         101                 : /*
         102                 :  * Insist that the next token be of type tt, or report errno and return null.
         103                 :  * NB: this macro uses cx and ts from its lexical environment.
         104                 :  */
         105                 : #define MUST_MATCH_TOKEN_WITH_FLAGS(tt, errno, __flags)                                     \
         106                 :     JS_BEGIN_MACRO                                                                          \
         107                 :         if (tokenStream.getToken((__flags)) != tt) {                                        \
         108                 :             reportErrorNumber(NULL, JSREPORT_ERROR, errno);                                 \
         109                 :             return NULL;                                                                    \
         110                 :         }                                                                                   \
         111                 :     JS_END_MACRO
         112                 : #define MUST_MATCH_TOKEN(tt, errno) MUST_MATCH_TOKEN_WITH_FLAGS(tt, errno, 0)
         113                 :
         114          109194 : Parser::Parser(JSContext *cx, JSPrincipals *prin, JSPrincipals *originPrin,
         115                 :                StackFrame *cfp, bool foldConstants)
         116                 :   : AutoGCRooter(cx, PARSER),
         117                 :     context(cx),
         118                 :     tokenStream(cx, prin, originPrin),
         119                 :     principals(NULL),
         120                 :     originPrincipals(NULL),
         121                 :     callerFrame(cfp),
         122                 :     callerVarObj(cfp ? &cfp->varObj() : NULL),
         123                 :     allocator(cx),
         124                 :     functionCount(0),
         125                 :     traceListHead(NULL),
         126                 :     tc(NULL),
         127                 :     keepAtoms(cx->runtime),
         128          109194 :     foldConstants(foldConstants)
         129                 : {
         130          109194 :     cx->activeCompilations++;
         131          109194 :     PodArrayZero(tempFreeList);
         132          109194 :     setPrincipals(prin, originPrin);
         133          109194 :     JS_ASSERT_IF(cfp, cfp->isScriptFrame());
         134          109194 : }
         135                 :
         136                 : bool
         137          109194 : Parser::init(const jschar *base, size_t length, const char *filename, unsigned lineno,
         138                 :              JSVersion version)
         139                 : {
         140          109194 :     JSContext *cx = context;
         141          109194 :     if (!cx->ensureParseMapPool())
         142               0 :         return false;
         143          109194 :     tempPoolMark = cx->tempLifoAlloc().mark();
         144          109194 :     if (!tokenStream.init(base, length, filename, lineno, version)) {
         145               0 :         cx->tempLifoAlloc().release(tempPoolMark);
         146               0 :         return false;
         147                 :     }
         148          109194 :     return true;
         149                 : }
         150                 :
         151          218388 : Parser::~Parser()
         152                 : {
         153          109194 :     JSContext *cx = context;
         154          109194 :     if (principals)
         155              64 :         JS_DropPrincipals(cx->runtime, principals);
         156          109194 :     if (originPrincipals)
         157              60 :         JS_DropPrincipals(cx->runtime, originPrincipals);
         158          109194 :     cx->tempLifoAlloc().release(tempPoolMark);
         159          109194 :     cx->activeCompilations--;
         160          109194 : }
         161                 :
         162                 : void
         163          109194 : Parser::setPrincipals(JSPrincipals *prin, JSPrincipals *originPrin)
         164                 : {
         165          109194 :     JS_ASSERT(!principals && !originPrincipals);
         166          109194 :     principals = prin;
         167          109194 :     if (principals)
         168              64 :         JS_HoldPrincipals(principals);
         169          109194 :     originPrincipals = originPrin;
         170          109194 :     if (originPrincipals)
         171              60 :         JS_HoldPrincipals(originPrincipals);
         172          109194 : }
         173                 :
         174                 : ObjectBox *
         175          140461 : Parser::newObjectBox(JSObject *obj)
         176                 : {
         177                 :     /*
         178                 :      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
         179                 :      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
         180                 :      * arenas containing the entries must be alive until we are done with
         181                 :      * scanning, parsing and code generation for the whole script or top-level
         182                 :      * function.
         183                 :      */
         184          140461 :     ObjectBox *objbox = context->tempLifoAlloc().new_<ObjectBox>();
         185          140461 :     if (!objbox) {
         186               0 :         js_ReportOutOfMemory(context);
         187               0 :         return NULL;
         188                 :     }
         189          140461 :     objbox->traceLink = traceListHead;
         190          140461 :     traceListHead = objbox;
         191          140461 :     objbox->emitLink = NULL;
         192          140461 :     objbox->object = obj;
         193          140461 :     objbox->isFunctionBox = false;
         194          140461 :     return objbox;
         195                 : }
         196                 :
         197                 : FunctionBox *
         198          156778 : Parser::newFunctionBox(JSObject *obj, ParseNode *fn, TreeContext *tc)
         199                 : {
         200          156778 :     JS_ASSERT(obj);
         201          156778 :     JS_ASSERT(obj->isFunction());
         202                 :
         203                 :     /*
         204                 :      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
         205                 :      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
         206                 :      * arenas containing the entries must be alive until we are done with
         207                 :      * scanning, parsing and code generation for the whole script or top-level
         208                 :      * function.
         209                 :      */
         210          156778 :     FunctionBox *funbox = context->tempLifoAlloc().newPod<FunctionBox>();
         211          156778 :     if (!funbox) {
         212               0 :         js_ReportOutOfMemory(context);
         213               0 :         return NULL;
         214                 :     }
         215          156778 :     funbox->traceLink = traceListHead;
         216          156778 :     traceListHead = funbox;
         217          156778 :     funbox->emitLink = NULL;
         218          156778 :     funbox->object = obj;
         219          156778 :     funbox->isFunctionBox = true;
         220          156778 :     funbox->node = fn;
         221          156778 :     funbox->siblings = tc->functionList;
         222          156778 :     tc->functionList = funbox;
         223          156778 :     ++tc->parser->functionCount;
         224          156778 :     funbox->kids = NULL;
         225          156778 :     funbox->parent = tc->funbox;
         226          156778 :     funbox->methods = NULL;
         227          156778 :     new (&funbox->bindings) Bindings(context);
         228          156778 :     funbox->queued = false;
         229          156778 :     funbox->inLoop = false;
         230          323592 :     for (StmtInfo *stmt = tc->topStmt; stmt; stmt = stmt->down) {
         231          168461 :         if (STMT_IS_LOOP(stmt)) {
         232            1647 :             funbox->inLoop = true;
         233            1647 :             break;
         234                 :         }
         235                 :     }
         236          156778 :     funbox->level = tc->staticLevel;
         237          156778 :     funbox->tcflags = (TCF_IN_FUNCTION | (tc->flags & (TCF_COMPILE_N_GO | TCF_STRICT_MODE_CODE)));
         238          156778 :     if (tc->innermostWith)
         239             180 :         funbox->tcflags |= TCF_IN_WITH;
         240          156778 :     if (!tc->inFunction()) {
         241          144837 :         JSObject *scope = tc->scopeChain();
         242          441768 :         while (scope) {
         243          152094 :             if (scope->isWith())
         244               0 :                 funbox->tcflags |= TCF_IN_WITH;
         245          152094 :             scope = scope->enclosingScope();
         246                 :         }
         247                 :     }
         248          156778 :     return funbox;
         249                 : }
         250                 :
         251                 : void
         252              15 : Parser::trace(JSTracer *trc)
         253                 : {
         254              15 :     ObjectBox *objbox = traceListHead;
         255              30 :     while (objbox) {
         256               0 :         MarkObjectRoot(trc, &objbox->object, "parser.object");
         257               0 :         if (objbox->isFunctionBox)
         258               0 :             static_cast<FunctionBox *>(objbox)->bindings.trace(trc);
         259               0 :         objbox = objbox->traceLink;
         260                 :     }
         261                 :
         262              21 :     for (TreeContext *tc = this->tc; tc; tc = tc->parent)
         263               6 :         tc->trace(trc);
         264              15 : }
         265                 :
         266                 : static bool
         267             918 : GenerateBlockIdForStmtNode(ParseNode *pn, TreeContext *tc)
         268                 : {
         269             918 :     JS_ASSERT(tc->topStmt);
         270             918 :     JS_ASSERT(STMT_MAYBE_SCOPE(tc->topStmt));
         271             918 :     JS_ASSERT(pn->isKind(PNK_STATEMENTLIST) || pn->isKind(PNK_LEXICALSCOPE));
         272             918 :     if (!GenerateBlockId(tc, tc->topStmt->blockid))
         273               0 :         return false;
         274             918 :     pn->pn_blockid = tc->topStmt->blockid;
         275             918 :     return true;
         276                 : }
         277                 :
         278                 : /*
         279                 :  * Parse a top-level JS script.
         280                 :  */
         281                 : ParseNode *
         282            2367 : Parser::parse(JSObject *chain)
         283                 : {
         284                 :     /*
         285                 :      * Protect atoms from being collected by a GC activation, which might
         286                 :      * - nest on this thread due to out of memory (the so-called "last ditch"
         287                 :      *   GC attempted within js_NewGCThing), or
         288                 :      * - run for any reason on another thread if this thread is suspended on
         289                 :      *   an object lock before it finishes generating bytecode into a script
         290                 :      *   protected from the GC by a root or a stack frame reference.
         291                 :      */
         292            4734 :     TreeContext globaltc(this);
         293            2367 :     if (!globaltc.init(context))
         294               0 :         return NULL;
         295            2367 :     globaltc.setScopeChain(chain);
         296            2367 :     if (!GenerateBlockId(&globaltc, globaltc.bodyid))
         297               0 :         return NULL;
         298                 :
         299            2367 :     ParseNode *pn = statements();
         300            2367 :     if (pn) {
         301            2367 :         if (!tokenStream.matchToken(TOK_EOF)) {
         302               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
         303               0 :             pn = NULL;
         304            2367 :         } else if (foldConstants) {
         305               0 :             if (!FoldConstants(context, pn, &globaltc))
         306               0 :                 pn = NULL;
         307                 :         }
         308                 :     }
         309            2367 :     return pn;
         310                 : }
         311                 :
         312                 : JS_STATIC_ASSERT(UpvarCookie::FREE_LEVEL == JS_BITMASK(JSFB_LEVEL_BITS));
         313                 :
         314                 : /*
         315                 :  * Insist on a final return before control flows out of pn.  Try to be a bit
         316                 :  * smart about loops: do {...; return e2;} while(0) at the end of a function
         317                 :  * that contains an early return e1 will get a strict warning.  Similarly for
         318                 :  * iloops: while (true){...} is treated as though ... returns.
         319                 :  */
         320                 : #define ENDS_IN_OTHER   0
         321                 : #define ENDS_IN_RETURN  1
         322                 : #define ENDS_IN_BREAK   2
         323                 :
         324                 : static int
         325              18 : HasFinalReturn(ParseNode *pn)
         326                 : {
         327                 :     ParseNode *pn2, *pn3;
         328                 :     unsigned rv, rv2, hasDefault;
         329                 :
         330              18 :     switch (pn->getKind()) {
         331                 :       case PNK_STATEMENTLIST:
         332               9 :         if (!pn->pn_head)
         333               0 :             return ENDS_IN_OTHER;
         334               9 :         return HasFinalReturn(pn->last());
         335                 :
         336                 :       case PNK_IF:
         337               9 :         if (!pn->pn_kid3)
         338               9 :             return ENDS_IN_OTHER;
         339               0 :         return HasFinalReturn(pn->pn_kid2) & HasFinalReturn(pn->pn_kid3);
         340                 :
         341                 :       case PNK_WHILE:
         342               0 :         pn2 = pn->pn_left;
         343               0 :         if (pn2->isKind(PNK_TRUE))
         344               0 :             return ENDS_IN_RETURN;
         345               0 :         if (pn2->isKind(PNK_NUMBER) && pn2->pn_dval)
         346               0 :             return ENDS_IN_RETURN;
         347               0 :         return ENDS_IN_OTHER;
         348                 :
         349                 :       case PNK_DOWHILE:
         350               0 :         pn2 = pn->pn_right;
         351               0 :         if (pn2->isKind(PNK_FALSE))
         352               0 :             return HasFinalReturn(pn->pn_left);
         353               0 :         if (pn2->isKind(PNK_TRUE))
         354               0 :             return ENDS_IN_RETURN;
         355               0 :         if (pn2->isKind(PNK_NUMBER)) {
         356               0 :             if (pn2->pn_dval == 0)
         357               0 :                 return HasFinalReturn(pn->pn_left);
         358               0 :             return ENDS_IN_RETURN;
         359                 :         }
         360               0 :         return ENDS_IN_OTHER;
         361                 :
         362                 :       case PNK_FOR:
         363               0 :         pn2 = pn->pn_left;
         364               0 :         if (pn2->isArity(PN_TERNARY) && !pn2->pn_kid2)
         365               0 :             return ENDS_IN_RETURN;
         366               0 :         return ENDS_IN_OTHER;
         367                 :
         368                 :       case PNK_SWITCH:
         369               0 :         rv = ENDS_IN_RETURN;
         370               0 :         hasDefault = ENDS_IN_OTHER;
         371               0 :         pn2 = pn->pn_right;
         372               0 :         if (pn2->isKind(PNK_LEXICALSCOPE))
         373               0 :             pn2 = pn2->expr();
         374               0 :         for (pn2 = pn2->pn_head; rv && pn2; pn2 = pn2->pn_next) {
         375               0 :             if (pn2->isKind(PNK_DEFAULT))
         376               0 :                 hasDefault = ENDS_IN_RETURN;
         377               0 :             pn3 = pn2->pn_right;
         378               0 :             JS_ASSERT(pn3->isKind(PNK_STATEMENTLIST));
         379               0 :             if (pn3->pn_head) {
         380               0 :                 rv2 = HasFinalReturn(pn3->last());
         381               0 :                 if (rv2 == ENDS_IN_OTHER && pn2->pn_next)
         382                 :                     /* Falling through to next case or default. */;
         383                 :                 else
         384               0 :                     rv &= rv2;
         385                 :             }
         386                 :         }
         387                 :         /* If a final switch has no default case, we judge it harshly. */
         388               0 :         rv &= hasDefault;
         389               0 :         return rv;
         390                 :
         391                 :       case PNK_BREAK:
         392               0 :         return ENDS_IN_BREAK;
         393                 :
         394                 :       case PNK_WITH:
         395               0 :         return HasFinalReturn(pn->pn_right);
         396                 :
         397                 :       case PNK_RETURN:
         398               0 :         return ENDS_IN_RETURN;
         399                 :
         400                 :       case PNK_COLON:
         401                 :       case PNK_LEXICALSCOPE:
         402               0 :         return HasFinalReturn(pn->expr());
         403                 :
         404                 :       case PNK_THROW:
         405               0 :         return ENDS_IN_RETURN;
         406                 :
         407                 :       case PNK_TRY:
         408                 :         /* If we have a finally block that returns, we are done. */
         409               0 :         if (pn->pn_kid3) {
         410               0 :             rv = HasFinalReturn(pn->pn_kid3);
         411               0 :             if (rv == ENDS_IN_RETURN)
         412               0 :                 return rv;
         413                 :         }
         414                 :
         415                 :         /* Else check the try block and any and all catch statements. */
         416               0 :         rv = HasFinalReturn(pn->pn_kid1);
         417               0 :         if (pn->pn_kid2) {
         418               0 :             JS_ASSERT(pn->pn_kid2->isArity(PN_LIST));
         419               0 :             for (pn2 = pn->pn_kid2->pn_head; pn2; pn2 = pn2->pn_next)
         420               0 :                 rv &= HasFinalReturn(pn2);
         421                 :         }
         422               0 :         return rv;
         423                 :
         424                 :       case PNK_CATCH:
         425                 :         /* Check this catch block's body. */
         426               0 :         return HasFinalReturn(pn->pn_kid3);
         427                 :
         428                 :       case PNK_LET:
         429                 :         /* Non-binary let statements are let declarations. */
         430               0 :         if (!pn->isArity(PN_BINARY))
         431               0 :             return ENDS_IN_OTHER;
         432               0 :         return HasFinalReturn(pn->pn_right);
         433                 :
         434                 :       default:
         435               0 :         return ENDS_IN_OTHER;
         436                 :     }
         437                 : }
         438                 :
         439                 : static JSBool
         440               9 : ReportBadReturn(JSContext *cx, TreeContext *tc, ParseNode *pn, unsigned flags, unsigned errnum,
         441                 :                 unsigned anonerrnum)
         442                 : {
         443              18 :     JSAutoByteString name;
         444               9 :     if (tc->fun()->atom) {
         445               9 :         if (!js_AtomToPrintableString(cx, tc->fun()->atom, &name))
         446               0 :             return false;
         447                 :     } else {
         448               0 :         errnum = anonerrnum;
         449                 :     }
         450               9 :     return ReportCompileErrorNumber(cx, TS(tc->parser), pn, flags, errnum, name.ptr());
         451                 : }
         452                 :
         453                 : static JSBool
         454               9 : CheckFinalReturn(JSContext *cx, TreeContext *tc, ParseNode *pn)
         455                 : {
         456               9 :     JS_ASSERT(tc->inFunction());
         457               9 :     return HasFinalReturn(pn) == ENDS_IN_RETURN ||
         458                 :            ReportBadReturn(cx, tc, pn, JSREPORT_WARNING | JSREPORT_STRICT,
         459               9 :                            JSMSG_NO_RETURN_VALUE, JSMSG_ANON_NO_RETURN_VALUE);
         460                 : }
         461                 :
         462                 : /*
         463                 :  * Check that it is permitted to assign to lhs.  Strict mode code may not
         464                 :  * assign to 'eval' or 'arguments'.
         465                 :  */
         466                 : static bool
         467          402875 : CheckStrictAssignment(JSContext *cx, TreeContext *tc, ParseNode *lhs)
         468                 : {
         469          402875 :     if (tc->needStrictChecks() && lhs->isKind(PNK_NAME)) {
         470             435 :         JSAtom *atom = lhs->pn_atom;
         471             435 :         JSAtomState *atomState = &cx->runtime->atomState;
         472             435 :         if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) {
         473               0 :             JSAutoByteString name;
         474               0 :             if (!js_AtomToPrintableString(cx, atom, &name) ||
         475                 :                 !ReportStrictModeError(cx, TS(tc->parser), tc, lhs, JSMSG_DEPRECATED_ASSIGN,
         476               0 :                                        name.ptr())) {
         477               0 :                 return false;
         478                 :             }
         479                 :         }
         480                 :     }
         481          402875 :     return true;
         482                 : }
         483                 :
         484                 : /*
         485                 :  * Check that it is permitted to introduce a binding for atom.  Strict mode
         486                 :  * forbids introducing new definitions for 'eval', 'arguments', or for any
         487                 :  * strict mode reserved keyword.  Use pn for reporting error locations, or use
         488                 :  * tc's token stream if pn is NULL.
         489                 :  */
         490                 : bool
         491          587589 : CheckStrictBinding(JSContext *cx, TreeContext *tc, PropertyName *name, ParseNode *pn)
         492                 : {
         493          587589 :     if (!tc->needStrictChecks())
         494          586441 :         return true;
         495                 :
         496            1148 :     JSAtomState *atomState = &cx->runtime->atomState;
         497            2296 :     if (name == atomState->evalAtom ||
         498                 :         name == atomState->argumentsAtom ||
         499            1148 :         FindKeyword(name->charsZ(), name->length()))
         500                 :     {
         501               0 :         JSAutoByteString bytes;
         502               0 :         if (!js_AtomToPrintableString(cx, name, &bytes))
         503               0 :             return false;
         504               0 :         return ReportStrictModeError(cx, TS(tc->parser), tc, pn, JSMSG_BAD_BINDING, bytes.ptr());
         505                 :     }
         506                 :
         507            1148 :     return true;
         508                 : }
         509                 :
         510                 : static bool
         511               0 : ReportBadParameter(JSContext *cx, TreeContext *tc, JSAtom *name, unsigned errorNumber)
         512                 : {
         513               0 :     Definition *dn = tc->decls.lookupFirst(name);
         514               0 :     JSAutoByteString bytes;
         515               0 :     return js_AtomToPrintableString(cx, name, &bytes) &&
         516               0 :            ReportStrictModeError(cx, TS(tc->parser), tc, dn, errorNumber, bytes.ptr());
         517                 : }
         518                 :
         519                 : /*
         520                 :  * In strict mode code, all parameter names must be distinct, must not be
         521                 :  * strict mode reserved keywords, and must not be 'eval' or 'arguments'.  We
         522                 :  * must perform these checks here, and not eagerly during parsing, because a
         523                 :  * function's body may turn on strict mode for the function head.
         524                 :  */
         525                 : bool
         526          166865 : js::CheckStrictParameters(JSContext *cx, TreeContext *tc)
         527                 : {
         528          166865 :     JS_ASSERT(tc->inFunction());
         529                 :
         530          166865 :     if (!tc->needStrictChecks() || tc->bindings.countArgs() == 0)
         531          166451 :         return true;
         532                 :
         533             414 :     JSAtom *argumentsAtom = cx->runtime->atomState.argumentsAtom;
         534             414 :     JSAtom *evalAtom = cx->runtime->atomState.evalAtom;
         535                 :
         536                 :     /* name => whether we've warned about the name already */
         537             828 :     HashMap<JSAtom *, bool> parameters(cx);
         538             414 :     if (!parameters.init(tc->bindings.countArgs()))
         539               0 :         return false;
         540                 :
         541                 :     /* Start with lastVariable(), not lastArgument(), for destructuring. */
         542            1017 :     for (Shape::Range r = tc->bindings.lastVariable(); !r.empty(); r.popFront()) {
         543             603 :         jsid id = r.front().propid();
         544             603 :         if (!JSID_IS_ATOM(id))
         545               0 :             continue;
         546                 :
         547             603 :         JSAtom *name = JSID_TO_ATOM(id);
         548                 :
         549             603 :         if (name == argumentsAtom || name == evalAtom) {
         550               0 :             if (!ReportBadParameter(cx, tc, name, JSMSG_BAD_BINDING))
         551               0 :                 return false;
         552                 :         }
         553                 :
         554             603 :         if (tc->inStrictMode() && FindKeyword(name->charsZ(), name->length())) {
         555                 :             /*
         556                 :              * JSOPTION_STRICT is supposed to warn about future keywords, too,
         557                 :              * but we took care of that in the scanner.
         558                 :              */
         559               0 :             JS_ALWAYS_TRUE(!ReportBadParameter(cx, tc, name, JSMSG_RESERVED_ID));
         560               0 :             return false;
         561                 :         }
         562                 :
         563                 :         /*
         564                 :          * Check for a duplicate parameter: warn or report an error exactly
         565                 :          * once for each duplicated parameter.
         566                 :          */
         567            1206 :         if (HashMap<JSAtom *, bool>::AddPtr p = parameters.lookupForAdd(name)) {
         568               0 :             if (!p->value && !ReportBadParameter(cx, tc, name, JSMSG_DUPLICATE_FORMAL))
         569               0 :                 return false;
         570               0 :             p->value = true;
         571                 :         } else {
         572             603 :             if (!parameters.add(p, name, false))
         573               0 :                 return false;
         574                 :         }
         575                 :     }
         576                 :
         577             414 :     return true;
         578                 : }
         579                 :
         580                 : ParseNode *
         581          167182 : Parser::functionBody(FunctionBodyType type)
         582                 : {
         583          167182 :     JS_ASSERT(tc->inFunction());
         584                 :
         585                 :     StmtInfo stmtInfo;
         586          167182 :     PushStatement(tc, &stmtInfo, STMT_BLOCK, -1);
         587          167182 :     stmtInfo.flags = SIF_BODY_BLOCK;
         588                 :
         589          167182 :     unsigned oldflags = tc->flags;
         590          167182 :     tc->flags &= ~(TCF_RETURN_EXPR | TCF_RETURN_VOID);
         591                 :
         592                 :     ParseNode *pn;
         593          167182 :     if (type == StatementListBody) {
         594          165418 :         pn = statements();
         595                 :     } else {
         596            1764 :         JS_ASSERT(type == ExpressionBody);
         597                 :         JS_ASSERT(JS_HAS_EXPR_CLOSURES);
         598            1764 :         pn = UnaryNode::create(PNK_RETURN, tc);
         599            1764 :         if (pn) {
         600            1764 :             pn->pn_kid = assignExpr();
         601            1764 :             if (!pn->pn_kid) {
         602               0 :                 pn = NULL;
         603                 :             } else {
         604            1764 :                 if (tc->flags & TCF_FUN_IS_GENERATOR) {
         605                 :                     ReportBadReturn(context, tc, pn, JSREPORT_ERROR,
         606                 :                                     JSMSG_BAD_GENERATOR_RETURN,
         607               0 :                                     JSMSG_BAD_ANON_GENERATOR_RETURN);
         608               0 :                     pn = NULL;
         609                 :                 } else {
         610            1764 :                     pn->setOp(JSOP_RETURN);
         611            1764 :                     pn->pn_pos.end = pn->pn_kid->pn_pos.end;
         612                 :                 }
         613                 :             }
         614                 :         }
         615                 :     }
         616                 :
         617          167182 :     if (pn) {
         618          166865 :         JS_ASSERT(!(tc->topStmt->flags & SIF_SCOPE));
         619          166865 :         PopStatementTC(tc);
         620                 :
         621                 :         /* Check for falling off the end of a function that returns a value. */
         622          166874 :         if (context->hasStrictOption() && (tc->flags & TCF_RETURN_EXPR) &&
         623               9 :             !CheckFinalReturn(context, tc, pn)) {
         624               0 :             pn = NULL;
         625                 :         }
         626                 :     }
         627                 :
         628          167182 :     tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
         629          167182 :     return pn;
         630                 : }
         631                 :
         632                 : /* Create a placeholder Definition node for |atom|. */
         633                 : static Definition *
         634          286830 : MakePlaceholder(ParseNode *pn, TreeContext *tc)
         635                 : {
         636          286830 :     Definition *dn = (Definition *) NameNode::create(PNK_NAME, pn->pn_atom, tc);
         637          286830 :     if (!dn)
         638               0 :         return NULL;
         639                 :
         640          286830 :     dn->setOp(JSOP_NOP);
         641          286830 :     dn->setDefn(true);
         642          286830 :     dn->pn_dflags |= PND_PLACEHOLDER;
         643          286830 :     return dn;
         644                 : }
         645                 :
         646                 : static bool
         647          804440 : Define(ParseNode *pn, JSAtom *atom, TreeContext *tc, bool let = false)
         648                 : {
         649          804440 :     JS_ASSERT(!pn->isUsed());
         650          804440 :     JS_ASSERT_IF(pn->isDefn(), pn->isPlaceholder());
         651                 :
         652          804440 :     bool foundLexdep = false;
         653          804440 :     Definition *dn = NULL;
         654                 :
         655          804440 :     if (let)
         656          322985 :         dn = tc->decls.lookupFirst(atom);
         657                 :
         658          804440 :     if (!dn) {
         659          801497 :         dn = tc->lexdeps.lookupDefn(atom);
         660          801497 :         foundLexdep = !!dn;
         661                 :     }
         662                 :
         663          804440 :     if (dn && dn != pn) {
         664            4392 :         ParseNode **pnup = &dn->dn_uses;
         665                 :         ParseNode *pnu;
         666            4392 :         unsigned start = let ? pn->pn_blockid : tc->bodyid;
         667                 :
         668           10008 :         while ((pnu = *pnup) != NULL && pnu->pn_blockid >= start) {
         669            1224 :             JS_ASSERT(pnu->isUsed());
         670            1224 :             pnu->pn_lexdef = (Definition *) pn;
         671            1224 :             pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
         672            1224 :             pnup = &pnu->pn_link;
         673                 :         }
         674                 :
         675            4392 :         if (pnu != dn->dn_uses) {
         676            1179 :             *pnup = pn->dn_uses;
         677            1179 :             pn->dn_uses = dn->dn_uses;
         678            1179 :             dn->dn_uses = pnu;
         679                 :
         680            1179 :             if ((!pnu || pnu->pn_blockid < tc->bodyid) && foundLexdep)
         681            1179 :                 tc->lexdeps->remove(atom);
         682                 :         }
         683                 :
         684            4392 :         pn->pn_dflags |= dn->pn_dflags & PND_CLOSED;
         685                 :     }
         686                 :
         687          804440 :     Definition *toAdd = (Definition *) pn;
         688          804440 :     bool ok = let ? tc->decls.addShadow(atom, toAdd) : tc->decls.addUnique(atom, toAdd);
         689          804440 :     if (!ok)
         690               0 :         return false;
         691          804440 :     pn->setDefn(true);
         692          804440 :     pn->pn_dflags &= ~PND_PLACEHOLDER;
         693          804440 :     if (!tc->parent)
         694          355575 :         pn->pn_dflags |= PND_TOPLEVEL;
         695          804440 :     return true;
         696                 : }
         697                 :
         698                 : static void
         699             207 : ForgetUse(ParseNode *pn)
         700                 : {
         701             207 :     if (!pn->isUsed()) {
         702               0 :         JS_ASSERT(!pn->isDefn());
         703               0 :         return;
         704                 :     }
         705                 :
         706             207 :     ParseNode **pnup = &pn->lexdef()->dn_uses;
         707                 :     ParseNode *pnu;
         708             414 :     while ((pnu = *pnup) != pn)
         709               0 :         pnup = &pnu->pn_link;
         710             207 :     *pnup = pn->pn_link;
         711             207 :     pn->setUsed(false);
         712                 : }
         713                 :
         714                 : static ParseNode *
         715            2610 : MakeAssignment(ParseNode *pn, ParseNode *rhs, TreeContext *tc)
         716                 : {
         717            2610 :     ParseNode *lhs = tc->parser->cloneNode(*pn);
         718            2610 :     if (!lhs)
         719               0 :         return NULL;
         720                 :
         721            2610 :     if (pn->isUsed()) {
         722            2610 :         Definition *dn = pn->pn_lexdef;
         723            2610 :         ParseNode **pnup = &dn->dn_uses;
         724                 :
         725            5382 :         while (*pnup != pn)
         726             162 :             pnup = &(*pnup)->pn_link;
         727            2610 :         *pnup = lhs;
         728            2610 :         lhs->pn_link = pn->pn_link;
         729            2610 :         pn->pn_link = NULL;
         730                 :     }
         731                 :
         732            2610 :     pn->setKind(PNK_ASSIGN);
         733            2610 :     pn->setOp(JSOP_NOP);
         734            2610 :     pn->setArity(PN_BINARY);
         735            2610 :     pn->setInParens(false);
         736            2610 :     pn->setUsed(false);
         737            2610 :     pn->setDefn(false);
         738            2610 :     pn->pn_left = lhs;
         739            2610 :     pn->pn_right = rhs;
         740            2610 :     return lhs;
         741                 : }
         742                 :
         743                 : static ParseNode *
         744              72 : MakeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom, TreeContext *tc)
         745                 : {
         746                 :     /*
         747                 :      * If dn is arg, or in [var, const, let] and has an initializer, then we
         748                 :      * must rewrite it to be an assignment node, whose freshly allocated
         749                 :      * left-hand side becomes a use of pn.
         750                 :      */
         751              72 :     if (dn->isBindingForm()) {
         752              27 :         ParseNode *rhs = dn->expr();
         753              27 :         if (rhs) {
         754               0 :             ParseNode *lhs = MakeAssignment(dn, rhs, tc);
         755               0 :             if (!lhs)
         756               0 :                 return NULL;
         757                 :             //pn->dn_uses = lhs;
         758               0 :             dn = (Definition *) lhs;
         759                 :         }
         760                 :
         761              27 :         dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETNAME : JSOP_NAME);
         762              45 :     } else if (dn->kind() == Definition::FUNCTION) {
         763              27 :         JS_ASSERT(dn->isOp(JSOP_NOP));
         764              27 :         tc->parser->prepareNodeForMutation(dn);
         765              27 :         dn->setKind(PNK_NAME);
         766              27 :         dn->setArity(PN_NAME);
         767              27 :         dn->pn_atom = atom;
         768                 :     }
         769                 :
         770                 :     /* Now make dn no longer a definition, rather a use of pn. */
         771              72 :     JS_ASSERT(dn->isKind(PNK_NAME));
         772              72 :     JS_ASSERT(dn->isArity(PN_NAME));
         773              72 :     JS_ASSERT(dn->pn_atom == atom);
         774                 :
         775             117 :     for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
         776              45 :         JS_ASSERT(pnu->isUsed());
         777              45 :         JS_ASSERT(!pnu->isDefn());
         778              45 :         pnu->pn_lexdef = (Definition *) pn;
         779              45 :         pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
         780                 :     }
         781              72 :     pn->pn_dflags |= dn->pn_dflags & PND_USE2DEF_FLAGS;
         782              72 :     pn->dn_uses = dn;
         783                 :
         784              72 :     dn->setDefn(false);
         785              72 :     dn->setUsed(true);
         786              72 :     dn->pn_lexdef = (Definition *) pn;
         787              72 :     dn->pn_cookie.makeFree();
         788              72 :     dn->pn_dflags &= ~PND_BOUND;
         789              72 :     return dn;
         790                 : }
         791                 :
         792                 : bool
         793          226878 : js::DefineArg(ParseNode *pn, JSAtom *atom, unsigned i, TreeContext *tc)
         794                 : {
         795                 :     /* Flag tc so we don't have to lookup arguments on every use. */
         796          226878 :     if (atom == tc->parser->context->runtime->atomState.argumentsAtom)
         797               0 :         tc->flags |= TCF_FUN_PARAM_ARGUMENTS;
         798                 :
         799                 :     /*
         800                 :      * Make an argument definition node, distinguished by being in tc->decls
         801                 :      * but having PNK_NAME kind and JSOP_NOP op. Insert it in a PNK_ARGSBODY
         802                 :      * list node returned via pn->pn_body.
         803                 :      */
         804          226878 :     ParseNode *argpn = NameNode::create(PNK_NAME, atom, tc);
         805          226878 :     if (!argpn)
         806               0 :         return false;
         807          226878 :     JS_ASSERT(argpn->isKind(PNK_NAME) && argpn->isOp(JSOP_NOP));
         808                 :
         809                 :     /* Arguments are initialized by definition. */
         810          226878 :     argpn->pn_dflags |= PND_INITIALIZED;
         811          226878 :     if (!Define(argpn, atom, tc))
         812               0 :         return false;
         813                 :
         814          226878 :     ParseNode *argsbody = pn->pn_body;
         815          226878 :     if (!argsbody) {
         816           59974 :         argsbody = ListNode::create(PNK_ARGSBODY, tc);
         817           59974 :         if (!argsbody)
         818               0 :             return false;
         819           59974 :         argsbody->setOp(JSOP_NOP);
         820           59974 :         argsbody->makeEmpty();
         821           59974 :         pn->pn_body = argsbody;
         822                 :     }
         823          226878 :     argsbody->append(argpn);
         824                 :
         825          226878 :     argpn->setOp(JSOP_GETARG);
         826          226878 :     argpn->pn_cookie.set(tc->staticLevel, i);
         827          226878 :     argpn->pn_dflags |= PND_BOUND;
         828          226878 :     return true;
         829                 : }
         830                 :
         831                 : /*
         832                 :  * Parameter block types for the several Binder functions.  We use a common
         833                 :  * helper function signature in order to share code among destructuring and
         834                 :  * simple variable declaration parsers.  In the destructuring case, the binder
         835                 :  * function is called indirectly from the variable declaration parser by way
         836                 :  * of CheckDestructuring and its friends.
         837                 :  */
         838                 : typedef JSBool
         839                 : (*Binder)(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc);
         840                 :
         841                 : static JSBool
         842                 : BindLet(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc);
         843                 :
         844                 : static JSBool
         845                 : BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc);
         846                 :
         847                 : struct BindData {
         848          251765 :     BindData() : fresh(true) {}
         849                 :
         850                 :     ParseNode       *pn;        /* name node for definition processing and
         851                 :                                    error source coordinates */
         852                 :     JSOp            op;         /* prolog bytecode or nop */
         853                 :     Binder          binder;     /* binder, discriminates u */
         854                 :     union {
         855                 :         struct {
         856                 :             VarContext varContext;
         857                 :             StaticBlockObject *blockObj;
         858                 :             unsigned   overflow;
         859                 :         } let;
         860                 :     };
         861                 :     bool fresh;
         862                 :
         863          101332 :     void initLet(VarContext varContext, StaticBlockObject &blockObj, unsigned overflow) {
         864          101332 :         this->pn = NULL;
         865          101332 :         this->op = JSOP_NOP;
         866          101332 :         this->binder = BindLet;
         867          101332 :         this->let.varContext = varContext;
         868          101332 :         this->let.blockObj = &blockObj;
         869          101332 :         this->let.overflow = overflow;
         870          101332 :     }
         871                 :
         872          150352 :     void initVarOrConst(JSOp op) {
         873          150352 :         this->op = op;
         874          150352 :         this->binder = BindVarOrConst;
         875          150352 :     }
         876                 : };
         877                 :
         878                 : static bool
         879          121627 : BindLocalVariable(JSContext *cx, TreeContext *tc, ParseNode *pn, BindingKind kind)
         880                 : {
         881          121627 :     JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
         882                 :
         883                 :     /* 'arguments' can be bound as a local only via a destructuring formal parameter. */
         884          121627 :     JS_ASSERT_IF(pn->pn_atom == cx->runtime->atomState.argumentsAtom, kind == VARIABLE);
         885                 :
         886          121627 :     unsigned index = tc->bindings.countVars();
         887          121627 :     if (!tc->bindings.add(cx, pn->pn_atom, kind))
         888               0 :         return false;
         889                 :
         890          121627 :     pn->pn_cookie.set(tc->staticLevel, index);
         891          121627 :     pn->pn_dflags |= PND_BOUND;
         892          121627 :     return true;
         893                 : }
         894                 :
         895                 : #if JS_HAS_DESTRUCTURING
         896                 : static JSBool
         897             162 : BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc)
         898                 : {
         899                 :     /* Flag tc so we don't have to lookup arguments on every use. */
         900             162 :     if (atom == tc->parser->context->runtime->atomState.argumentsAtom)
         901               0 :         tc->flags |= TCF_FUN_PARAM_ARGUMENTS;
         902                 :
         903             162 :     JS_ASSERT(tc->inFunction());
         904                 :
         905                 :     /*
         906                 :      * NB: Check tc->decls rather than tc->bindings, because destructuring
         907                 :      *     bindings aren't added to tc->bindings until after all arguments have
         908                 :      *     been parsed.
         909                 :      */
         910             162 :     if (tc->decls.lookupFirst(atom)) {
         911                 :         ReportCompileErrorNumber(cx, TS(tc->parser), NULL, JSREPORT_ERROR,
         912               0 :                                  JSMSG_DESTRUCT_DUP_ARG);
         913               0 :         return JS_FALSE;
         914                 :     }
         915                 :
         916             162 :     ParseNode *pn = data->pn;
         917                 :
         918                 :     /*
         919                 :      * Distinguish destructured-to binding nodes as vars, not args, by setting
         920                 :      * pn_op to JSOP_SETLOCAL. Parser::functionDef checks for this pn_op value
         921                 :      * when processing the destructuring-assignment AST prelude induced by such
         922                 :      * destructuring args in Parser::functionArguments.
         923                 :      *
         924                 :      * We must set the PND_BOUND flag too to prevent pn_op from being reset to
         925                 :      * JSOP_SETNAME by BindDestructuringVar. The only field not initialized is
         926                 :      * pn_cookie; it gets set in functionDef in the first "if (prelude)" block.
         927                 :      * We have to wait to set the cookie until we can call JSFunction::addLocal
         928                 :      * with kind = JSLOCAL_VAR, after all JSLOCAL_ARG locals have been added.
         929                 :      *
         930                 :      * Thus a destructuring formal parameter binds an ARG (as in arguments[i]
         931                 :      * element) with a null atom name for the object or array passed in to be
         932                 :      * destructured, and zero or more VARs (as in named local variables) for
         933                 :      * the destructured-to identifiers in the property value positions within
         934                 :      * the object or array destructuring pattern, and all ARGs for the formal
         935                 :      * parameter list bound as locals before any VAR for a destructured name.
         936                 :      */
         937             162 :     pn->setOp(JSOP_SETLOCAL);
         938             162 :     pn->pn_dflags |= PND_BOUND;
         939                 :
         940             162 :     return Define(pn, atom, tc);
         941                 : }
         942                 : #endif /* JS_HAS_DESTRUCTURING */
         943                 :
         944                 : JSFunction *
         945          156778 : Parser::newFunction(TreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind)
         946                 : {
         947          156778 :     JS_ASSERT_IF(kind == Statement, atom != NULL);
         948                 :
         949                 :     /*
         950                 :      * Find the global compilation context in order to pre-set the newborn
         951                 :      * function's parent slot to tc->scopeChain. If the global context is a
         952                 :      * compile-and-go one, we leave the pre-set parent intact; otherwise we
         953                 :      * clear parent and proto.
         954                 :      */
         955          371000 :     while (tc->parent)
         956           57444 :         tc = tc->parent;
         957                 :
         958          313556 :     RootedVarObject parent(context);
         959          156778 :     parent = tc->inFunction() ? NULL : tc->scopeChain();
         960                 :
         961                 :     JSFunction *fun =
         962                 :         js_NewFunction(context, NULL, NULL, 0,
         963                 :                        JSFUN_INTERPRETED | (kind == Expression ? JSFUN_LAMBDA : 0),
         964          156778 :                        parent, atom);
         965          156778 :     if (fun && !tc->compileAndGo()) {
         966            2837 :         if (!fun->clearParent(context))
         967               0 :             return NULL;
         968            2837 :         if (!fun->clearType(context))
         969               0 :             return NULL;
         970            2837 :         fun->setEnvironment(NULL);
         971                 :     }
         972          156778 :     return fun;
         973                 : }
         974                 :
         975                 : static JSBool
         976          738575 : MatchOrInsertSemicolon(JSContext *cx, TokenStream *ts)
         977                 : {
         978          738575 :     TokenKind tt = ts->peekTokenSameLine(TSF_OPERAND);
         979          738575 :     if (tt == TOK_ERROR)
         980               0 :         return JS_FALSE;
         981          738575 :     if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {
         982                 :         /* Advance the scanner for proper error location reporting. */
         983              18 :         ts->getToken(TSF_OPERAND);
         984              18 :         ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_SEMI_BEFORE_STMNT);
         985              18 :         return JS_FALSE;
         986                 :     }
         987          738557 :     (void) ts->matchToken(TOK_SEMI);
         988          738557 :     return JS_TRUE;
         989                 : }
         990                 :
         991                 : static FunctionBox *
         992          156778 : EnterFunction(ParseNode *fn, TreeContext *funtc, JSAtom *funAtom = NULL,
         993                 :               FunctionSyntaxKind kind = Expression)
         994                 : {
         995          156778 :     TreeContext *tc = funtc->parent;
         996          156778 :     JSFunction *fun = tc->parser->newFunction(tc, funAtom, kind);
         997          156778 :     if (!fun)
         998               0 :         return NULL;
         999                 :
        1000                 :     /* Create box for fun->object early to protect against last-ditch GC. */
        1001          156778 :     FunctionBox *funbox = tc->parser->newFunctionBox(fun, fn, tc);
        1002          156778 :     if (!funbox)
        1003               0 :         return NULL;
        1004                 :
        1005                 :     /* Initialize non-default members of funtc. */
        1006          156778 :     funtc->flags |= funbox->tcflags;
        1007          156778 :     funtc->blockidGen = tc->blockidGen;
        1008          156778 :     if (!GenerateBlockId(funtc, funtc->bodyid))
        1009               0 :         return NULL;
        1010          156778 :     funtc->setFunction(fun);
        1011          156778 :     funtc->funbox = funbox;
        1012          156778 :     if (!SetStaticLevel(funtc, tc->staticLevel + 1))
        1013               0 :         return NULL;
        1014                 :
        1015          156778 :     return funbox;
        1016                 : }
        1017                 :
        1018                 : static bool
        1019            7577 : DeoptimizeUsesWithin(Definition *dn, const TokenPos &pos)
        1020                 : {
        1021            7577 :     unsigned ndeoptimized = 0;
        1022                 :
        1023          107900 :     for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
        1024          100323 :         JS_ASSERT(pnu->isUsed());
        1025          100323 :         JS_ASSERT(!pnu->isDefn());
        1026          100323 :         if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end) {
        1027           99909 :             pnu->pn_dflags |= PND_DEOPTIMIZED;
        1028           99909 :             ++ndeoptimized;
        1029                 :         }
        1030                 :     }
        1031                 :
        1032            7577 :     return ndeoptimized != 0;
        1033                 : }
        1034                 :
        1035                 : static bool
        1036          156769 : LeaveFunction(ParseNode *fn, TreeContext *funtc, PropertyName *funName = NULL,
        1037                 :               FunctionSyntaxKind kind = Expression)
        1038                 : {
        1039          156769 :     TreeContext *tc = funtc->parent;
        1040          156769 :     tc->blockidGen = funtc->blockidGen;
        1041                 :
        1042          156769 :     FunctionBox *funbox = fn->pn_funbox;
        1043          156769 :     funbox->tcflags |= funtc->flags & (TCF_FUN_FLAGS | TCF_COMPILE_N_GO | TCF_RETURN_EXPR);
        1044                 :
        1045          156769 :     fn->pn_dflags |= PND_INITIALIZED;
        1046          156769 :     if (!tc->topStmt || tc->topStmt->type == STMT_BLOCK)
        1047          155815 :         fn->pn_dflags |= PND_BLOCKCHILD;
        1048                 :
        1049                 :     /*
        1050                 :      * Propagate unresolved lexical names up to tc->lexdeps, and save a copy
        1051                 :      * of funtc->lexdeps in a TOK_UPVARS node wrapping the function's formal
        1052                 :      * params and body. We do this only if there are lexical dependencies not
        1053                 :      * satisfied by the function's declarations, to avoid penalizing functions
        1054                 :      * that use only their arguments and other local bindings.
        1055                 :      */
        1056          156769 :     if (funtc->lexdeps->count()) {
        1057           61321 :         int foundCallee = 0;
        1058                 :
        1059          155794 :         for (AtomDefnRange r = funtc->lexdeps->all(); !r.empty(); r.popFront()) {
        1060           94473 :             JSAtom *atom = r.front().key();
        1061           94473 :             Definition *dn = r.front().value();
        1062           94473 :             JS_ASSERT(dn->isPlaceholder());
        1063                 :
        1064           94473 :             if (atom == funName && kind == Expression) {
        1065             450 :                 dn->setOp(JSOP_CALLEE);
        1066             450 :                 dn->pn_cookie.set(funtc->staticLevel, UpvarCookie::CALLEE_SLOT);
        1067             450 :                 dn->pn_dflags |= PND_BOUND;
        1068             450 :                 foundCallee = 1;
        1069             450 :                 continue;
        1070                 :             }
        1071                 :
        1072           94023 :             Definition *outer_dn = tc->decls.lookupFirst(atom);
        1073                 :
        1074                 :             /*
        1075                 :              * Make sure to deoptimize lexical dependencies that are polluted
        1076                 :              * by eval or with, to safely bind globals (see bug 561923).
        1077                 :              */
        1078           94086 :             if (funtc->callsEval() ||
        1079                 :                 (outer_dn && tc->innermostWith &&
        1080              63 :                  outer_dn->pn_pos < tc->innermostWith->pn_pos)) {
        1081            6659 :                 DeoptimizeUsesWithin(dn, fn->pn_pos);
        1082                 :             }
        1083                 :
        1084           94023 :             if (!outer_dn) {
        1085          132552 :                 AtomDefnAddPtr p = tc->lexdeps->lookupForAdd(atom);
        1086           66276 :                 if (p) {
        1087           10837 :                     outer_dn = p.value();
        1088                 :                 } else {
        1089                 :                     /*
        1090                 :                      * Create a new placeholder for our outer lexdep. We could
        1091                 :                      * simply re-use the inner placeholder, but that introduces
        1092                 :                      * subtleties in the case where we find a later definition
        1093                 :                      * that captures an existing lexdep. For example:
        1094                 :                      *
        1095                 :                      *   function f() { function g() { x; } let x; }
        1096                 :                      *
        1097                 :                      * Here, g's TOK_UPVARS node lists the placeholder for x,
        1098                 :                      * which must be captured by the 'let' declaration later,
        1099                 :                      * since 'let's are hoisted.  Taking g's placeholder as our
        1100                 :                      * own would work fine. But consider:
        1101                 :                      *
        1102                 :                      *   function f() { x; { function g() { x; } let x; } }
        1103                 :                      *
        1104                 :                      * Here, the 'let' must not capture all the uses of f's
        1105                 :                      * lexdep entry for x, but it must capture the x node
        1106                 :                      * referred to from g's TOK_UPVARS node.  Always turning
        1107                 :                      * inherited lexdeps into uses of a new outer definition
        1108                 :                      * allows us to handle both these cases in a natural way.
        1109                 :                      */
        1110           55439 :                     outer_dn = MakePlaceholder(dn, tc);
        1111           55439 :                     if (!outer_dn || !tc->lexdeps->add(p, atom, outer_dn))
        1112               0 :                         return false;
        1113                 :                 }
        1114                 :             }
        1115                 :
        1116                 :             /*
        1117                 :              * Insert dn's uses list at the front of outer_dn's list.
        1118                 :              *
        1119                 :              * Without loss of generality or correctness, we allow a dn to
        1120                 :              * be in inner and outer lexdeps, since the purpose of lexdeps
        1121                 :              * is one-pass coordination of name use and definition across
        1122                 :              * functions, and if different dn's are used we'll merge lists
        1123                 :              * when leaving the inner function.
        1124                 :              *
        1125                 :              * The dn == outer_dn case arises with generator expressions
        1126                 :              * (see CompExprTransplanter::transplant, the PN_FUNC/PN_NAME
        1127                 :              * case), and nowhere else, currently.
        1128                 :              */
        1129           94023 :             if (dn != outer_dn) {
        1130           94023 :                 ParseNode **pnup = &dn->dn_uses;
        1131                 :                 ParseNode *pnu;
        1132                 :
        1133          434053 :                 while ((pnu = *pnup) != NULL) {
        1134          246007 :                     pnu->pn_lexdef = outer_dn;
        1135          246007 :                     pnup = &pnu->pn_link;
        1136                 :                 }
        1137                 :
        1138                 :                 /*
        1139                 :                  * Make dn be a use that redirects to outer_dn, because we
        1140                 :                  * can't replace dn with outer_dn in all the pn_namesets in
        1141                 :                  * the AST where it may be. Instead we make it forward to
        1142                 :                  * outer_dn. See Definition::resolve.
        1143                 :                  */
        1144           94023 :                 *pnup = outer_dn->dn_uses;
        1145           94023 :                 outer_dn->dn_uses = dn;
        1146           94023 :                 outer_dn->pn_dflags |= dn->pn_dflags & ~PND_PLACEHOLDER;
        1147           94023 :                 dn->setDefn(false);
        1148           94023 :                 dn->setUsed(true);
        1149           94023 :                 dn->pn_lexdef = outer_dn;
        1150                 :             }
        1151                 :
        1152                 :             /* Mark the outer dn as escaping. */
        1153           94023 :             outer_dn->pn_dflags |= PND_CLOSED;
        1154                 :         }
        1155                 :
        1156           61321 :         if (funtc->lexdeps->count() - foundCallee != 0) {
        1157           61222 :             ParseNode *body = fn->pn_body;
        1158                 :
        1159           61222 :             fn->pn_body = NameSetNode::create(PNK_UPVARS, tc);
        1160           61222 :             if (!fn->pn_body)
        1161               0 :                 return false;
        1162                 :
        1163           61222 :             fn->pn_body->pn_pos = body->pn_pos;
        1164           61222 :             if (foundCallee)
        1165             351 :                 funtc->lexdeps->remove(funName);
        1166                 :             /* Transfer ownership of the lexdep map to the parse node. */
        1167           61222 :             fn->pn_body->pn_names = funtc->lexdeps;
        1168           61222 :             funtc->lexdeps.clearMap();
        1169           61222 :             fn->pn_body->pn_tree = body;
        1170                 :         } else {
        1171              99 :             funtc->lexdeps.releaseMap(funtc->parser->context);
        1172                 :         }
        1173                 :
        1174                 :     }
        1175                 :
        1176                 :     /*
        1177                 :      * Check whether any parameters have been assigned within this function.
        1178                 :      * In strict mode parameters do not alias arguments[i], and to make the
        1179                 :      * arguments object reflect initial parameter values prior to any mutation
        1180                 :      * we create it eagerly whenever parameters are (or might, in the case of
        1181                 :      * calls to eval) be assigned.
        1182                 :      */
        1183          156769 :     if (funtc->inStrictMode() && funbox->object->toFunction()->nargs > 0) {
        1184             315 :         AtomDeclsIter iter(&funtc->decls);
        1185                 :         Definition *dn;
        1186                 :
        1187             315 :         while ((dn = iter()) != NULL) {
        1188             486 :             if (dn->kind() == Definition::ARG && dn->isAssigned()) {
        1189              54 :                 funbox->tcflags |= TCF_FUN_MUTATES_PARAMETER;
        1190              54 :                 break;
        1191                 :             }
        1192                 :         }
        1193                 :     }
        1194                 :
        1195          156769 :     funbox->bindings.transfer(funtc->parser->context, &funtc->bindings);
        1196                 :
        1197          156769 :     return true;
        1198                 : }
        1199                 :
        1200                 : static bool
        1201                 : DefineGlobal(ParseNode *pn, BytecodeEmitter *bce, PropertyName *name);
        1202                 :
        1203                 : /*
        1204                 :  * FIXME? this Parser method was factored from Parser::functionDef with minimal
        1205                 :  * change, hence the funtc ref param and funbox. It probably should match
        1206                 :  * functionBody, etc., and use tc and tc->funbox instead of taking explicit
        1207                 :  * parameters.
        1208                 :  */
        1209                 : bool
        1210          156571 : Parser::functionArguments(TreeContext &funtc, FunctionBox *funbox, ParseNode **listp)
        1211                 : {
        1212          156571 :     if (tokenStream.getToken() != TOK_LP) {
        1213               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_BEFORE_FORMAL);
        1214               0 :         return false;
        1215                 :     }
        1216                 :
        1217          156571 :     if (!tokenStream.matchToken(TOK_RP)) {
        1218                 : #if JS_HAS_DESTRUCTURING
        1219           55088 :         JSAtom *duplicatedArg = NULL;
        1220           55088 :         bool destructuringArg = false;
        1221           55088 :         ParseNode *list = NULL;
        1222                 : #endif
        1223                 :
        1224          222046 :         do {
        1225          222046 :             switch (TokenKind tt = tokenStream.getToken()) {
        1226                 : #if JS_HAS_DESTRUCTURING
        1227                 :               case TOK_LB:
        1228                 :               case TOK_LC:
        1229                 :               {
        1230                 :                 /* See comment below in the TOK_NAME case. */
        1231              81 :                 if (duplicatedArg)
        1232               0 :                     goto report_dup_and_destructuring;
        1233              81 :                 destructuringArg = true;
        1234                 :
        1235                 :                 /*
        1236                 :                  * A destructuring formal parameter turns into one or more
        1237                 :                  * local variables initialized from properties of a single
        1238                 :                  * anonymous positional parameter, so here we must tweak our
        1239                 :                  * binder and its data.
        1240                 :                  */
        1241              81 :                 BindData data;
        1242              81 :                 data.pn = NULL;
        1243              81 :                 data.op = JSOP_DEFVAR;
        1244              81 :                 data.binder = BindDestructuringArg;
        1245              81 :                 ParseNode *lhs = destructuringExpr(&data, tt);
        1246              81 :                 if (!lhs)
        1247               0 :                     return false;
        1248                 :
        1249                 :                 /*
        1250                 :                  * Adjust fun->nargs to count the single anonymous positional
        1251                 :                  * parameter that is to be destructured.
        1252                 :                  */
        1253                 :                 uint16_t slot;
        1254              81 :                 if (!funtc.bindings.addDestructuring(context, &slot))
        1255               0 :                     return false;
        1256                 :
        1257                 :                 /*
        1258                 :                  * Synthesize a destructuring assignment from the single
        1259                 :                  * anonymous positional parameter into the destructuring
        1260                 :                  * left-hand-side expression and accumulate it in list.
        1261                 :                  */
        1262                 :                 ParseNode *rhs =
        1263              81 :                     NameNode::create(PNK_NAME, context->runtime->atomState.emptyAtom, &funtc);
        1264              81 :                 if (!rhs)
        1265               0 :                     return false;
        1266              81 :                 rhs->setOp(JSOP_GETARG);
        1267              81 :                 rhs->pn_cookie.set(funtc.staticLevel, slot);
        1268              81 :                 rhs->pn_dflags |= PND_BOUND;
        1269                 :
        1270              81 :                 ParseNode *item = new_<BinaryNode>(PNK_ASSIGN, JSOP_NOP, lhs->pn_pos, lhs, rhs);
        1271              81 :                 if (!item)
        1272               0 :                     return false;
        1273              81 :                 if (!list) {
        1274              45 :                     list = ListNode::create(PNK_VAR, &funtc);
        1275              45 :                     if (!list)
        1276               0 :                         return false;
        1277              45 :                     list->makeEmpty();
        1278              45 :                     *listp = list;
        1279                 :                 }
        1280              81 :                 list->append(item);
        1281              81 :                 break;
        1282                 :               }
        1283                 : #endif /* JS_HAS_DESTRUCTURING */
        1284                 :
        1285                 :               case TOK_NAME:
        1286                 :               {
        1287          221965 :                 PropertyName *name = tokenStream.currentToken().name();
        1288                 :
        1289                 : #ifdef JS_HAS_DESTRUCTURING
        1290                 :                 /*
        1291                 :                  * ECMA-262 requires us to support duplicate parameter names,
        1292                 :                  * but if the parameter list includes destructuring, we
        1293                 :                  * consider the code to have "opted in" to higher standards and
        1294                 :                  * forbid duplicates. We may see a destructuring parameter
        1295                 :                  * later, so always note duplicates now.
        1296                 :                  *
        1297                 :                  * Duplicates are warned about (strict option) or cause errors
        1298                 :                  * (strict mode code), but we do those tests in one place
        1299                 :                  * below, after having parsed the body in case it begins with a
        1300                 :                  * "use strict"; directive.
        1301                 :                  *
        1302                 :                  * NB: Check funtc.decls rather than funtc.bindings, because
        1303                 :                  *     destructuring bindings aren't added to funtc.bindings
        1304                 :                  *     until after all arguments have been parsed.
        1305                 :                  */
        1306          221965 :                 if (funtc.decls.lookupFirst(name)) {
        1307              18 :                     funtc.bindings.noteDup();
        1308              18 :                     duplicatedArg = name;
        1309              18 :                     if (destructuringArg)
        1310               0 :                         goto report_dup_and_destructuring;
        1311                 :                 }
        1312                 : #endif
        1313                 :
        1314                 :                 uint16_t slot;
        1315          221965 :                 if (!funtc.bindings.addArgument(context, name, &slot))
        1316               0 :                     return false;
        1317          221965 :                 if (!DefineArg(funbox->node, name, slot, &funtc))
        1318               0 :                     return false;
        1319          221965 :                 break;
        1320                 :               }
        1321                 :
        1322                 :               default:
        1323               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_MISSING_FORMAL);
        1324                 :                 /* FALL THROUGH */
        1325                 :               case TOK_ERROR:
        1326               0 :                 return false;
        1327                 :
        1328                 : #if JS_HAS_DESTRUCTURING
        1329                 :               report_dup_and_destructuring:
        1330               0 :                 Definition *dn = funtc.decls.lookupFirst(duplicatedArg);
        1331               0 :                 reportErrorNumber(dn, JSREPORT_ERROR, JSMSG_DESTRUCT_DUP_ARG);
        1332               0 :                 return false;
        1333                 : #endif
        1334                 :             }
        1335          222046 :         } while (tokenStream.matchToken(TOK_COMMA));
        1336                 :
        1337           55088 :         if (tokenStream.getToken() != TOK_RP) {
        1338               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_AFTER_FORMAL);
        1339               0 :             return false;
        1340                 :         }
        1341                 :     }
        1342                 :
        1343          156571 :     return true;
        1344                 : }
        1345                 :
        1346                 : ParseNode *
        1347          156571 : Parser::functionDef(PropertyName *funName, FunctionType type, FunctionSyntaxKind kind)
        1348                 : {
        1349          156571 :     JS_ASSERT_IF(kind == Statement, funName);
        1350                 :
        1351                 :     /* Make a TOK_FUNCTION node. */
        1352          156571 :     ParseNode *pn = FunctionNode::create(PNK_FUNCTION, tc);
        1353          156571 :     if (!pn)
        1354               0 :         return NULL;
        1355          156571 :     pn->pn_body = NULL;
        1356          156571 :     pn->pn_cookie.makeFree();
        1357          156571 :     pn->pn_dflags = 0;
        1358                 :
        1359                 :     /*
        1360                 :      * Record names for function statements in tc->decls so we know when to
        1361                 :      * avoid optimizing variable references that might name a function.
        1362                 :      */
        1363          156571 :     bool bodyLevel = tc->atBodyLevel();
        1364          156571 :     if (kind == Statement) {
        1365           28621 :         if (Definition *dn = tc->decls.lookupFirst(funName)) {
        1366              81 :             Definition::Kind dn_kind = dn->kind();
        1367                 :
        1368              81 :             JS_ASSERT(!dn->isUsed());
        1369              81 :             JS_ASSERT(dn->isDefn());
        1370                 :
        1371              81 :             if (context->hasStrictOption() || dn_kind == Definition::CONST) {
        1372               0 :                 JSAutoByteString name;
        1373               0 :                 if (!js_AtomToPrintableString(context, funName, &name) ||
        1374                 :                     !reportErrorNumber(NULL,
        1375                 :                                        (dn_kind != Definition::CONST)
        1376                 :                                        ? JSREPORT_WARNING | JSREPORT_STRICT
        1377                 :                                        : JSREPORT_ERROR,
        1378                 :                                        JSMSG_REDECLARED_VAR,
        1379                 :                                        Definition::kindString(dn_kind),
        1380               0 :                                        name.ptr())) {
        1381               0 :                     return NULL;
        1382                 :                 }
        1383                 :             }
        1384                 :
        1385              81 :             if (bodyLevel) {
        1386              72 :                 tc->decls.updateFirst(funName, (Definition *) pn);
        1387              72 :                 pn->setDefn(true);
        1388              72 :                 pn->dn_uses = dn; /* dn->dn_uses is now pn_link */
        1389                 :
        1390              72 :                 if (!MakeDefIntoUse(dn, pn, funName, tc))
        1391               0 :                     return NULL;
        1392                 :             }
        1393           28540 :         } else if (bodyLevel) {
        1394                 :             /*
        1395                 :              * If this function was used before it was defined, claim the
        1396                 :              * pre-created definition node for this function that primaryExpr
        1397                 :              * put in tc->lexdeps on first forward reference, and recycle pn.
        1398                 :              */
        1399                 :
        1400           28198 :             if (Definition *fn = tc->lexdeps.lookupDefn(funName)) {
        1401            1683 :                 JS_ASSERT(fn->isDefn());
        1402            1683 :                 fn->setKind(PNK_FUNCTION);
        1403            1683 :                 fn->setArity(PN_FUNC);
        1404            1683 :                 fn->pn_pos.begin = pn->pn_pos.begin;
        1405                 :
        1406                 :                 /*
        1407                 :                  * Set fn->pn_pos.end too, in case of error before we parse the
        1408                 :                  * closing brace.  See bug 640075.
        1409                 :                  */
        1410            1683 :                 fn->pn_pos.end = pn->pn_pos.end;
        1411                 :
        1412            1683 :                 fn->pn_body = NULL;
        1413            1683 :                 fn->pn_cookie.makeFree();
        1414                 :
        1415            1683 :                 tc->lexdeps->remove(funName);
        1416            1683 :                 freeTree(pn);
        1417            1683 :                 pn = fn;
        1418                 :             }
        1419                 :
        1420           28198 :             if (!Define(pn, funName, tc))
        1421               0 :                 return NULL;
        1422                 :         }
        1423                 :
        1424                 :         /*
        1425                 :          * A function directly inside another's body needs only a local
        1426                 :          * variable to bind its name to its value, and not an activation object
        1427                 :          * property (it might also need the activation property, if the outer
        1428                 :          * function contains with statements, e.g., but the stack slot wins
        1429                 :          * when BytecodeEmitter.cpp's BindNameToSlot can optimize a JSOP_NAME
        1430                 :          * into a JSOP_GETLOCAL bytecode).
        1431                 :          */
        1432           28621 :         if (bodyLevel && tc->inFunction()) {
        1433                 :             /*
        1434                 :              * Define a local in the outer function so that BindNameToSlot
        1435                 :              * can properly optimize accesses. Note that we need a local
        1436                 :              * variable, not an argument, for the function statement. Thus
        1437                 :              * we add a variable even if a parameter with the given name
        1438                 :              * already exists.
        1439                 :              */
        1440                 :             unsigned index;
        1441            3771 :             switch (tc->bindings.lookup(context, funName, &index)) {
        1442                 :               case NONE:
        1443                 :               case ARGUMENT:
        1444            3771 :                 index = tc->bindings.countVars();
        1445            3771 :                 if (!tc->bindings.addVariable(context, funName))
        1446               0 :                     return NULL;
        1447                 :                 /* FALL THROUGH */
        1448                 :
        1449                 :               case VARIABLE:
        1450            3771 :                 pn->pn_cookie.set(tc->staticLevel, index);
        1451            3771 :                 pn->pn_dflags |= PND_BOUND;
        1452            3771 :                 break;
        1453                 :
        1454                 :               default:;
        1455                 :             }
        1456                 :         }
        1457                 :     }
        1458                 :
        1459          156571 :     TreeContext *outertc = tc;
        1460                 :
        1461                 :     /* Initialize early for possible flags mutation via destructuringExpr. */
        1462          313142 :     TreeContext funtc(tc->parser);
        1463          156571 :     if (!funtc.init(context))
        1464               0 :         return NULL;
        1465                 :
        1466          156571 :     FunctionBox *funbox = EnterFunction(pn, &funtc, funName, kind);
        1467          156571 :     if (!funbox)
        1468               0 :         return NULL;
        1469                 :
        1470          156571 :     JSFunction *fun = funbox->function();
        1471                 :
        1472                 :     /* Now parse formal argument list and compute fun->nargs. */
        1473          156571 :     ParseNode *prelude = NULL;
        1474          156571 :     if (!functionArguments(funtc, funbox, &prelude))
        1475               0 :         return NULL;
        1476                 :
        1477          156571 :     fun->setArgCount(funtc.bindings.countArgs());
        1478                 :
        1479                 : #if JS_HAS_DESTRUCTURING
        1480                 :     /*
        1481                 :      * If there were destructuring formal parameters, bind the destructured-to
        1482                 :      * local variables now that we've parsed all the regular and destructuring
        1483                 :      * formal parameters. Because js::Bindings::add must be called first for
        1484                 :      * all ARGUMENTs, then all VARIABLEs and CONSTANTs, and finally all UPVARs,
        1485                 :      * we can't bind vars induced by formal parameter destructuring until after
        1486                 :      * Parser::functionArguments has returned.
        1487                 :      */
        1488          156571 :     if (prelude) {
        1489              45 :         AtomDeclsIter iter(&funtc.decls);
        1490                 :
        1491             423 :         while (Definition *apn = iter()) {
        1492                 :             /* Filter based on pn_op -- see BindDestructuringArg, above. */
        1493             189 :             if (!apn->isOp(JSOP_SETLOCAL))
        1494              27 :                 continue;
        1495                 :
        1496             162 :             if (!BindLocalVariable(context, &funtc, apn, VARIABLE))
        1497               0 :                 return NULL;
        1498                 :         }
        1499                 :     }
        1500                 : #endif
        1501                 :
        1502          156571 :     if (type == Getter && fun->nargs > 0) {
        1503                 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ACCESSOR_WRONG_ARGS,
        1504               0 :                           "getter", "no", "s");
        1505               0 :         return NULL;
        1506                 :     }
        1507          156571 :     if (type == Setter && fun->nargs != 1) {
        1508                 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ACCESSOR_WRONG_ARGS,
        1509               0 :                           "setter", "one", "");
        1510               0 :         return NULL;
        1511                 :     }
        1512                 :
        1513          156571 :     FunctionBodyType bodyType = StatementListBody;
        1514                 : #if JS_HAS_EXPR_CLOSURES
        1515          156571 :     if (tokenStream.getToken(TSF_OPERAND) != TOK_LC) {
        1516            1764 :         tokenStream.ungetToken();
        1517            1764 :         fun->flags |= JSFUN_EXPR_CLOSURE;
        1518            1764 :         bodyType = ExpressionBody;
        1519                 :     }
        1520                 : #else
        1521                 :     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY);
        1522                 : #endif
        1523                 :
        1524          156571 :     ParseNode *body = functionBody(bodyType);
        1525          156571 :     if (!body)
        1526               9 :         return NULL;
        1527                 :
        1528          156562 :     if (funName && !CheckStrictBinding(context, &funtc, funName, pn))
        1529               0 :         return NULL;
        1530                 :
        1531          156562 :     if (!CheckStrictParameters(context, &funtc))
        1532               0 :         return NULL;
        1533                 :
        1534                 : #if JS_HAS_EXPR_CLOSURES
        1535          156562 :     if (bodyType == StatementListBody)
        1536          154798 :         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
        1537            1764 :     else if (kind == Statement && !MatchOrInsertSemicolon(context, &tokenStream))
        1538               0 :         return NULL;
        1539                 : #else
        1540                 :     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
        1541                 : #endif
        1542          156562 :     pn->pn_pos.end = tokenStream.currentToken().pos.end;
        1543                 :
        1544                 :     /*
        1545                 :      * Fruit of the poisonous tree: if a closure calls eval, we consider the
        1546                 :      * parent to call eval. We need this for two reasons: (1) the Jaegermonkey
        1547                 :      * optimizations really need to know if eval is called transitively, and
        1548                 :      * (2) in strict mode, eval called transitively requires eager argument
        1549                 :      * creation in strict mode parent functions.
        1550                 :      *
        1551                 :      * For the latter, we really only need to propagate callsEval if both
        1552                 :      * functions are strict mode, but we don't lose much by always propagating.
        1553                 :      * The only optimization we lose this way is in the case where a function
        1554                 :      * is strict, does not mutate arguments, does not call eval directly, but
        1555                 :      * calls eval transitively.
        1556                 :      */
        1557          156562 :     if (funtc.callsEval())
        1558            3535 :         outertc->noteCallsEval();
        1559                 :
        1560                 : #if JS_HAS_DESTRUCTURING
        1561                 :     /*
        1562                 :      * If there were destructuring formal parameters, prepend the initializing
        1563                 :      * comma expression that we synthesized to body. If the body is a return
        1564                 :      * node, we must make a special PNK_SEQ node, to prepend the destructuring
        1565                 :      * code without bracing the decompilation of the function body.
        1566                 :      */
        1567          156562 :     if (prelude) {
        1568              45 :         if (!body->isArity(PN_LIST)) {
        1569                 :             ParseNode *block;
        1570                 :
        1571               0 :             block = ListNode::create(PNK_SEQ, outertc);
        1572               0 :             if (!block)
        1573               0 :                 return NULL;
        1574               0 :             block->pn_pos = body->pn_pos;
        1575               0 :             block->initList(body);
        1576                 :
        1577               0 :             body = block;
        1578                 :         }
        1579                 :
        1580              45 :         ParseNode *item = UnaryNode::create(PNK_SEMI, outertc);
        1581              45 :         if (!item)
        1582               0 :             return NULL;
        1583                 :
        1584              45 :         item->pn_pos.begin = item->pn_pos.end = body->pn_pos.begin;
        1585              45 :         item->pn_kid = prelude;
        1586              45 :         item->pn_next = body->pn_head;
        1587              45 :         body->pn_head = item;
        1588              45 :         if (body->pn_tail == &body->pn_head)
        1589              27 :             body->pn_tail = &item->pn_next;
        1590              45 :         ++body->pn_count;
        1591              45 :         body->pn_xflags |= PNX_DESTRUCT;
        1592                 :     }
        1593                 : #endif
        1594                 :
        1595                 :     /*
        1596                 :      * If we collected flags that indicate nested heavyweight functions, or
        1597                 :      * this function contains heavyweight-making statements (with statement,
        1598                 :      * visible eval call, or assignment to 'arguments'), flag the function as
        1599                 :      * heavyweight (requiring a call object per invocation).
        1600                 :      */
        1601          156562 :     if (funtc.flags & TCF_FUN_HEAVYWEIGHT) {
        1602            5623 :         fun->flags |= JSFUN_HEAVYWEIGHT;
        1603            5623 :         outertc->flags |= TCF_FUN_HEAVYWEIGHT;
        1604                 :     }
        1605                 :
        1606          156562 :     JSOp op = JSOP_NOP;
        1607          156562 :     if (kind == Expression) {
        1608          127941 :         op = JSOP_LAMBDA;
        1609                 :     } else {
        1610           28621 :         if (!bodyLevel) {
        1611                 :             /*
        1612                 :              * Extension: in non-strict mode code, a function statement not at
        1613                 :              * the top level of a function body or whole program, e.g., in a
        1614                 :              * compound statement such as the "then" part of an "if" statement,
        1615                 :              * binds a closure only if control reaches that sub-statement.
        1616                 :              */
        1617             351 :             JS_ASSERT(!outertc->inStrictMode());
        1618             351 :             op = JSOP_DEFFUN;
        1619             351 :             outertc->noteMightAliasLocals();
        1620             351 :             outertc->noteHasExtensibleScope();
        1621             351 :             outertc->flags |= TCF_FUN_HEAVYWEIGHT;
        1622             351 :             if (fun->atom == context->runtime->atomState.argumentsAtom)
        1623               9 :                 outertc->noteLocalOverwritesArguments();
        1624                 :         }
        1625                 :     }
        1626                 :
        1627          156562 :     funbox->kids = funtc.functionList;
        1628                 :
        1629          156562 :     pn->pn_funbox = funbox;
        1630          156562 :     pn->setOp(op);
        1631          156562 :     if (pn->pn_body) {
        1632           55070 :         pn->pn_body->append(body);
        1633           55070 :         pn->pn_body->pn_pos = body->pn_pos;
        1634                 :     } else {
        1635          101492 :         pn->pn_body = body;
        1636                 :     }
        1637                 :
        1638          156562 :     if (!outertc->inFunction() && bodyLevel && kind == Statement && outertc->compiling()) {
        1639           24499 :         JS_ASSERT(pn->pn_cookie.isFree());
        1640           24499 :         if (!DefineGlobal(pn, outertc->asBytecodeEmitter(), funName))
        1641               0 :             return NULL;
        1642                 :     }
        1643                 :
        1644          156562 :     pn->pn_blockid = outertc->blockid();
        1645                 :
        1646          156562 :     if (!LeaveFunction(pn, &funtc, funName, kind))
        1647               0 :         return NULL;
        1648                 :
        1649                 :     /* If the surrounding function is not strict code, reset the lexer. */
        1650          156562 :     if (!outertc->inStrictMode())
        1651          156256 :         tokenStream.setStrictMode(false);
        1652                 :
        1653          156562 :     return pn;
        1654                 : }
        1655                 :
        1656                 : ParseNode *
        1657           28630 : Parser::functionStmt()
        1658                 : {
        1659           28630 :     PropertyName *name = NULL;
        1660           28630 :     if (tokenStream.getToken(TSF_KEYWORD_IS_NAME) == TOK_NAME) {
        1661           28621 :         name = tokenStream.currentToken().name();
        1662                 :     } else {
        1663                 :         /* Unnamed function expressions are forbidden in statement context. */
        1664               9 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_UNNAMED_FUNCTION_STMT);
        1665               9 :         return NULL;
        1666                 :     }
        1667                 :
        1668                 :     /* We forbid function statements in strict mode code. */
        1669           28972 :     if (!tc->atBodyLevel() && tc->inStrictMode()) {
        1670               0 :         reportErrorNumber(NULL, JSREPORT_STRICT_MODE_ERROR, JSMSG_STRICT_FUNCTION_STATEMENT);
        1671               0 :         return NULL;
        1672                 :     }
        1673                 :
        1674           28621 :     return functionDef(name, Normal, Statement);
        1675                 : }
        1676                 :
        1677                 : ParseNode *
        1678          127653 : Parser::functionExpr()
        1679                 : {
        1680          127653 :     PropertyName *name = NULL;
        1681          127653 :     if (tokenStream.getToken(TSF_KEYWORD_IS_NAME) == TOK_NAME)
        1682            6112 :         name = tokenStream.currentToken().name();
        1683                 :     else
        1684          121541 :         tokenStream.ungetToken();
        1685          127653 :     return functionDef(name, Normal, Expression);
        1686                 : }
        1687                 :
        1688                 : /*
        1689                 :  * Recognize Directive Prologue members and directives. Assuming |pn| is a
        1690                 :  * candidate for membership in a directive prologue, recognize directives and
        1691                 :  * set |tc|'s flags accordingly. If |pn| is indeed part of a prologue, set its
        1692                 :  * |pn_prologue| flag.
        1693                 :  *
        1694                 :  * Note that the following is a strict mode function:
        1695                 :  *
        1696                 :  * function foo() {
        1697                 :  *   "blah" // inserted semi colon
        1698                 :  *        "blurgh"
        1699                 :  *   "use\x20loose"
        1700                 :  *   "use strict"
        1701                 :  * }
        1702                 :  *
        1703                 :  * That is, even though "use\x20loose" can never be a directive, now or in the
        1704                 :  * future (because of the hex escape), the Directive Prologue extends through it
        1705                 :  * to the "use strict" statement, which is indeed a directive.
        1706                 :  */
        1707                 : bool
        1708          183879 : Parser::recognizeDirectivePrologue(ParseNode *pn, bool *isDirectivePrologueMember)
        1709                 : {
        1710          183879 :     *isDirectivePrologueMember = pn->isStringExprStatement();
        1711          183879 :     if (!*isDirectivePrologueMember)
        1712          183043 :         return true;
        1713                 :
        1714             836 :     ParseNode *kid = pn->pn_kid;
        1715             836 :     if (kid->isEscapeFreeStringLiteral()) {
        1716                 :         /*
        1717                 :          * Mark this statement as being a possibly legitimate part of a
        1718                 :          * directive prologue, so the byte code emitter won't warn about it
        1719                 :          * being useless code. (We mustn't just omit the statement entirely yet,
        1720                 :          * as it could be producing the value of an eval or JSScript execution.)
        1721                 :          *
        1722                 :          * Note that even if the string isn't one we recognize as a directive,
        1723                 :          * the emitter still shouldn't flag it as useless, as it could become a
        1724                 :          * directive in the future. We don't want to interfere with people
        1725                 :          * taking advantage of directive-prologue-enabled features that appear
        1726                 :          * in other browsers first.
        1727                 :          */
        1728             836 :         pn->pn_prologue = true;
        1729                 :
        1730             836 :         JSAtom *directive = kid->pn_atom;
        1731             836 :         if (directive == context->runtime->atomState.useStrictAtom) {
        1732                 :             /*
        1733                 :              * Unfortunately, Directive Prologue members in general may contain
        1734                 :              * escapes, even while "use strict" directives may not.  Therefore
        1735                 :              * we must check whether an octal character escape has been seen in
        1736                 :              * any previous directives whenever we encounter a "use strict"
        1737                 :              * directive, so that the octal escape is properly treated as a
        1738                 :              * syntax error.  An example of this case:
        1739                 :              *
        1740                 :              *   function error()
        1741                 :              *   {
        1742                 :              *     "\145"; // octal escape
        1743                 :              *     "use strict"; // retroactively makes "\145" a syntax error
        1744                 :              *   }
        1745                 :              */
        1746             687 :             if (tokenStream.hasOctalCharacterEscape()) {
        1747               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_DEPRECATED_OCTAL);
        1748               0 :                 return false;
        1749                 :             }
        1750                 :
        1751             687 :             tc->flags |= TCF_STRICT_MODE_CODE;
        1752             687 :             tokenStream.setStrictMode();
        1753                 :         }
        1754                 :     }
        1755             836 :     return true;
        1756                 : }
        1757                 :
        1758                 : /*
        1759                 :  * Parse the statements in a block, creating a TOK_LC node that lists the
        1760                 :  * statements' trees.  If called from block-parsing code, the caller must
        1761                 :  * match { before and } after.
        1762                 :  */
        1763                 : ParseNode *
        1764          443902 : Parser::statements()
        1765                 : {
        1766          443902 :     JS_CHECK_RECURSION(context, return NULL);
        1767                 :
        1768          443902 :     ParseNode *pn = ListNode::create(PNK_STATEMENTLIST, tc);
        1769          443902 :     if (!pn)
        1770               0 :         return NULL;
        1771          443902 :     pn->makeEmpty();
        1772          443902 :     pn->pn_blockid = tc->blockid();
        1773          443902 :     ParseNode *saveBlock = tc->blockNode;
        1774          443902 :     tc->blockNode = pn;
        1775                 :
        1776          443902 :     bool inDirectivePrologue = tc->atBodyLevel();
        1777          443902 :     tokenStream.setOctalCharacterEscape(false);
        1778          489628 :     for (;;) {
        1779          933530 :         TokenKind tt = tokenStream.peekToken(TSF_OPERAND);
        1780          933530 :         if (tt <= TOK_EOF || tt == TOK_RC) {
        1781          443531 :             if (tt == TOK_ERROR) {
        1782               0 :                 if (tokenStream.isEOF())
        1783               0 :                     tokenStream.setUnexpectedEOF();
        1784               0 :                 return NULL;
        1785                 :             }
        1786                 :             break;
        1787                 :         }
        1788          489999 :         ParseNode *next = statement();
        1789          489999 :         if (!next) {
        1790             371 :             if (tokenStream.isEOF())
        1791              11 :                 tokenStream.setUnexpectedEOF();
        1792             371 :             return NULL;
        1793                 :         }
        1794                 :
        1795          489628 :         if (inDirectivePrologue && !recognizeDirectivePrologue(next, &inDirectivePrologue))
        1796               0 :             return NULL;
        1797                 :
        1798          489628 :         if (next->isKind(PNK_FUNCTION)) {
        1799                 :             /*
        1800                 :              * PNX_FUNCDEFS notifies the emitter that the block contains body-
        1801                 :              * level function definitions that should be processed before the
        1802                 :              * rest of nodes.
        1803                 :              *
        1804                 :              * TCF_HAS_FUNCTION_STMT is for the TOK_LC case in Statement. It
        1805                 :              * is relevant only for function definitions not at body-level,
        1806                 :              * which we call function statements.
        1807                 :              */
        1808            4086 :             if (tc->atBodyLevel()) {
        1809            3771 :                 pn->pn_xflags |= PNX_FUNCDEFS;
        1810                 :             } else {
        1811                 :                 /*
        1812                 :                  * General deoptimization was done in functionDef, here we just
        1813                 :                  * need to tell TOK_LC in Parser::statement to add braces.
        1814                 :                  */
        1815             315 :                 JS_ASSERT(tc->hasExtensibleScope());
        1816             315 :                 tc->flags |= TCF_HAS_FUNCTION_STMT;
        1817                 :             }
        1818                 :         }
        1819          489628 :         pn->append(next);
        1820                 :     }
        1821                 :
        1822                 :     /*
        1823                 :      * Handle the case where there was a let declaration under this block.  If
        1824                 :      * it replaced tc->blockNode with a new block node then we must refresh pn
        1825                 :      * and then restore tc->blockNode.
        1826                 :      */
        1827          443531 :     if (tc->blockNode != pn)
        1828            1755 :         pn = tc->blockNode;
        1829          443531 :     tc->blockNode = saveBlock;
        1830                 :
        1831          443531 :     pn->pn_pos.end = tokenStream.currentToken().pos.end;
        1832          443531 :     JS_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
        1833          443531 :     return pn;
        1834                 : }
        1835                 :
        1836                 : ParseNode *
        1837           95696 : Parser::condition()
        1838                 : {
        1839           95696 :     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
        1840           95696 :     ParseNode *pn = parenExpr();
        1841           95696 :     if (!pn)
        1842               0 :         return NULL;
        1843           95696 :     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
        1844                 :
        1845                 :     /* Check for (a = b) and warn about possible (a == b) mistype. */
        1846           95696 :     JS_ASSERT_IF(pn->isKind(PNK_ASSIGN), pn->isOp(JSOP_NOP));
        1847           95894 :     if (pn->isKind(PNK_ASSIGN) &&
        1848              99 :         !pn->isInParens() &&
        1849              99 :         !reportErrorNumber(NULL, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_EQUAL_AS_ASSIGN))
        1850                 :     {
        1851               0 :         return NULL;
        1852                 :     }
        1853           95696 :     return pn;
        1854                 : }
        1855                 :
        1856                 : static bool
        1857            1881 : MatchLabel(JSContext *cx, TokenStream *ts, PropertyName **label)
        1858                 : {
        1859            1881 :     TokenKind tt = ts->peekTokenSameLine(TSF_OPERAND);
        1860            1881 :     if (tt == TOK_ERROR)
        1861               0 :         return false;
        1862            1881 :     if (tt == TOK_NAME) {
        1863             144 :         (void) ts->getToken();
        1864             144 :         *label = ts->currentToken().name();
        1865                 :     } else {
        1866            1737 :         *label = NULL;
        1867                 :     }
        1868            1881 :     return true;
        1869                 : }
        1870                 :
        1871                 : static bool
        1872             189 : ReportRedeclaration(JSContext *cx, TreeContext *tc, ParseNode *pn, bool isConst, JSAtom *atom)
        1873                 : {
        1874             378 :     JSAutoByteString name;
        1875             189 :     if (js_AtomToPrintableString(cx, atom, &name)) {
        1876                 :         ReportCompileErrorNumber(cx, TS(tc->parser), pn,
        1877                 :                                  JSREPORT_ERROR, JSMSG_REDECLARED_VAR,
        1878                 :                                  isConst ? "const" : "variable",
        1879             189 :                                  name.ptr());
        1880                 :     }
        1881             189 :     return false;
        1882                 : }
        1883                 :
        1884                 : /*
        1885                 :  * Define a let-variable in a block, let-expression, or comprehension scope. tc
        1886                 :  * must already be in such a scope.
        1887                 :  *
        1888                 :  * Throw a SyntaxError if 'atom' is an invalid name. Otherwise create a
        1889                 :  * property for the new variable on the block object, tc->blockChain;
        1890                 :  * populate data->pn->pn_{op,cookie,defn,dflags}; and stash a pointer to
        1891                 :  * data->pn in a slot of the block object.
        1892                 :  */
        1893                 : static JSBool
        1894          323507 : BindLet(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc)
        1895                 : {
        1896          323507 :     ParseNode *pn = data->pn;
        1897          323507 :     if (!CheckStrictBinding(cx, tc, atom->asPropertyName(), pn))
        1898               0 :         return false;
        1899                 :
        1900          323507 :     StaticBlockObject &blockObj = *data->let.blockObj;
        1901          323507 :     unsigned blockCount = blockObj.slotCount();
        1902          323507 :     if (blockCount == JS_BIT(16)) {
        1903                 :         ReportCompileErrorNumber(cx, TS(tc->parser), pn,
        1904               0 :                                  JSREPORT_ERROR, data->let.overflow);
        1905               0 :         return false;
        1906                 :     }
        1907                 :
        1908                 :     /*
        1909                 :      * For bindings that are hoisted to the beginning of the block/function,
        1910                 :      * Define() right now. For the rest, delay Define() until PushLetScope.
        1911                 :      */
        1912          323507 :     if (data->let.varContext == HoistVars) {
        1913          163827 :         JS_ASSERT(!tc->atBodyLevel());
        1914          163827 :         Definition *dn = tc->decls.lookupFirst(atom);
        1915          163827 :         if (dn && dn->pn_blockid == tc->blockid())
        1916              18 :             return ReportRedeclaration(cx, tc, pn, dn->isConst(), atom);
        1917          163809 :         if (!Define(pn, atom, tc, true))
        1918               0 :             return false;
        1919                 :     }
        1920                 :
        1921                 :     /*
        1922                 :      * Assign block-local index to pn->pn_cookie right away, encoding it as an
        1923                 :      * upvar cookie whose skip tells the current static level. The emitter will
        1924                 :      * adjust the node's slot based on its stack depth model -- and, for global
        1925                 :      * and eval code, js::frontend::CompileScript will adjust the slot
        1926                 :      * again to include script->nfixed.
        1927                 :      */
        1928          323489 :     pn->setOp(JSOP_GETLOCAL);
        1929          323489 :     pn->pn_cookie.set(tc->staticLevel, uint16_t(blockCount));
        1930          323489 :     pn->pn_dflags |= PND_LET | PND_BOUND;
        1931                 :
        1932                 :     /*
        1933                 :      * Define the let binding's property before storing pn in the the binding's
        1934                 :      * slot indexed by blockCount off the class-reserved slot base.
        1935                 :      */
        1936                 :     bool redeclared;
        1937          323489 :     jsid id = ATOM_TO_JSID(atom);
        1938          323489 :     const Shape *shape = blockObj.addVar(cx, id, blockCount, &redeclared);
        1939          323489 :     if (!shape) {
        1940             171 :         if (redeclared)
        1941             171 :             ReportRedeclaration(cx, tc, pn, false, atom);
        1942             171 :         return false;
        1943                 :     }
        1944                 :
        1945                 :     /* Store pn in the static block object. */
        1946          323318 :     blockObj.setDefinitionParseNode(blockCount, reinterpret_cast<Definition *>(pn));
        1947          323318 :     return true;
        1948                 : }
        1949                 :
        1950                 : template <class Op>
        1951                 : static inline bool
        1952          111836 : ForEachLetDef(TreeContext *tc, StaticBlockObject &blockObj, Op op)
        1953                 : {
        1954          602430 :     for (Shape::Range r = blockObj.lastProperty()->all(); !r.empty(); r.popFront()) {
        1955          490594 :         const Shape &shape = r.front();
        1956                 :
        1957                 :         /* Beware the destructuring dummy slots. */
        1958          490594 :         if (JSID_IS_INT(shape.propid()))
        1959            8469 :             continue;
        1960                 :
        1961          482125 :         if (!op(tc, blockObj, shape, JSID_TO_ATOM(shape.propid())))
        1962               0 :             return false;
        1963                 :     }
        1964          111836 :     return true;
        1965                 : }
        1966                 :
        1967                 : struct RemoveDecl {
        1968          322949 :     bool operator()(TreeContext *tc, StaticBlockObject &, const Shape &, JSAtom *atom) {
        1969          322949 :         tc->decls.remove(atom);
        1970          322949 :         return true;
        1971                 :     }
        1972                 : };
        1973                 :
        1974                 : static void
        1975          412876 : PopStatement(TreeContext *tc)
        1976                 : {
        1977          412876 :     if (tc->topStmt->flags & SIF_SCOPE) {
        1978          100675 :         StaticBlockObject &blockObj = *tc->topStmt->blockObj;
        1979          100675 :         JS_ASSERT(!blockObj.inDictionaryMode());
        1980          100675 :         ForEachLetDef(tc, blockObj, RemoveDecl());
        1981                 :     }
        1982          412876 :     PopStatementTC(tc);
        1983          412876 : }
        1984                 :
        1985                 : static inline bool
        1986               9 : OuterLet(TreeContext *tc, StmtInfo *stmt, JSAtom *atom)
        1987                 : {
        1988              18 :     while (stmt->downScope) {
        1989               0 :         stmt = LexicalLookup(tc, atom, NULL, stmt->downScope);
        1990               0 :         if (!stmt)
        1991               0 :             return false;
        1992               0 :         if (stmt->type == STMT_BLOCK)
        1993               0 :             return true;
        1994                 :     }
        1995               9 :     return false;
        1996                 : }
        1997                 :
        1998                 : /*
        1999                 :  * If we are generating global or eval-called-from-global code, bind a "gvar"
        2000                 :  * here, as soon as possible. The JSOP_GETGVAR, etc., ops speed up interpreted
        2001                 :  * global variable access by memoizing name-to-slot mappings during execution
        2002                 :  * of the script prolog (via JSOP_DEFVAR/JSOP_DEFCONST). If the memoization
        2003                 :  * can't be done due to a pre-existing property of the same name as the var or
        2004                 :  * const but incompatible attributes/getter/setter/etc, these ops devolve to
        2005                 :  * JSOP_NAME, etc.
        2006                 :  *
        2007                 :  * For now, don't try to lookup eval frame variables at compile time. This is
        2008                 :  * sub-optimal: we could handle eval-called-from-global-code gvars since eval
        2009                 :  * gets its own script and frame. The eval-from-function-code case is harder,
        2010                 :  * since functions do not atomize gvars and then reserve their atom indexes as
        2011                 :  * stack frame slots.
        2012                 :  */
        2013                 : static bool
        2014           72533 : DefineGlobal(ParseNode *pn, BytecodeEmitter *bce, PropertyName *name)
        2015                 : {
        2016           72533 :     GlobalScope *globalScope = bce->globalScope;
        2017           72533 :     JSObject *globalObj = globalScope->globalObj;
        2018                 :
        2019           72533 :     if (!bce->compileAndGo() || !globalObj || bce->compilingForEval())
        2020            3668 :         return true;
        2021                 :
        2022          137730 :     AtomIndexAddPtr p = globalScope->names.lookupForAdd(name);
        2023           68865 :     if (!p) {
        2024           68811 :         JSContext *cx = bce->parser->context;
        2025                 :
        2026                 :         JSObject *holder;
        2027                 :         JSProperty *prop;
        2028           68811 :         if (!globalObj->lookupProperty(cx, name, &holder, &prop))
        2029               0 :             return false;
        2030                 :
        2031           68811 :         FunctionBox *funbox = pn->isKind(PNK_FUNCTION) ? pn->pn_funbox : NULL;
        2032                 :
        2033           68811 :         GlobalScope::GlobalDef def;
        2034           68811 :         if (prop) {
        2035                 :             /*
        2036                 :              * A few cases where we don't bother aggressively caching:
        2037                 :              *   1) Function value changes.
        2038                 :              *   2) Configurable properties.
        2039                 :              *   3) Properties without slots, or with getters/setters.
        2040                 :              */
        2041             222 :             const Shape *shape = (const Shape *)prop;
        2042             459 :             if (funbox ||
        2043                 :                 globalObj != holder ||
        2044             120 :                 shape->configurable() ||
        2045              39 :                 !shape->hasSlot() ||
        2046              39 :                 !shape->hasDefaultGetter() ||
        2047              39 :                 !shape->hasDefaultSetter()) {
        2048             183 :                 return true;
        2049                 :             }
        2050                 :
        2051              39 :             def = GlobalScope::GlobalDef(shape->slot());
        2052                 :         } else {
        2053           68589 :             def = GlobalScope::GlobalDef(name, funbox);
        2054                 :         }
        2055                 :
        2056           68628 :         if (!globalScope->defs.append(def))
        2057               0 :             return false;
        2058                 :
        2059           68628 :         jsatomid index = globalScope->names.count();
        2060           68628 :         if (!globalScope->names.add(p, name, index))
        2061               0 :             return false;
        2062                 :
        2063           68628 :         JS_ASSERT(index == globalScope->defs.length() - 1);
        2064                 :     } else {
        2065                 :         /*
        2066                 :          * Functions can be redeclared, and the last one takes effect. Check
        2067                 :          * for this and make sure to rewrite the definition.
        2068                 :          *
        2069                 :          * Note: This could overwrite an existing variable declaration, for
        2070                 :          * example:
        2071                 :          *   var c = []
        2072                 :          *   function c() { }
        2073                 :          *
        2074                 :          * This rewrite is allowed because the function will be statically
        2075                 :          * hoisted to the top of the script, and the |c = []| will just
        2076                 :          * overwrite it at runtime.
        2077                 :          */
        2078              54 :         if (pn->isKind(PNK_FUNCTION)) {
        2079              54 :             JS_ASSERT(pn->isArity(PN_FUNC));
        2080              54 :             jsatomid index = p.value();
        2081              54 :             globalScope->defs[index].funbox = pn->pn_funbox;
        2082                 :         }
        2083                 :     }
        2084                 :
        2085           68682 :     pn->pn_dflags |= PND_GVAR;
        2086                 :
        2087           68682 :     return true;
        2088                 : }
        2089                 :
        2090                 : static bool
        2091          104725 : BindTopLevelVar(JSContext *cx, BindData *data, ParseNode *pn, TreeContext *tc)
        2092                 : {
        2093          104725 :     JS_ASSERT(pn->isOp(JSOP_NAME));
        2094          104725 :     JS_ASSERT(!tc->inFunction());
        2095                 :
        2096                 :     /* There's no need to optimize bindings if we're not compiling code. */
        2097          104725 :     if (!tc->compiling())
        2098               9 :         return true;
        2099                 :
        2100                 :     /*
        2101                 :      * Bindings at top level in eval code aren't like bindings at top level in
        2102                 :      * regular code, and we must handle them specially.
        2103                 :      */
        2104          104716 :     if (tc->parser->callerFrame) {
        2105                 :         /*
        2106                 :          * If the eval code is not strict mode code, such bindings are created
        2107                 :          * from scratch in the the caller's environment (if the eval is direct)
        2108                 :          * or in the global environment (if the eval is indirect) -- and they
        2109                 :          * can be deleted.  Therefore we can't bind early.
        2110                 :          */
        2111             576 :         if (!tc->inStrictMode())
        2112             432 :             return true;
        2113                 :
        2114                 :         /*
        2115                 :          * But if the eval code is strict mode code, bindings are added to a
        2116                 :          * new environment specifically for that eval code's compilation, and
        2117                 :          * they can't be deleted.  Thus strict mode eval code does not affect
        2118                 :          * the caller's environment, and we can bind such names early.  (But
        2119                 :          * note: strict mode eval code can still affect the global environment
        2120                 :          * by performing an indirect eval of non-strict mode code.)
        2121                 :          *
        2122                 :          * However, optimizing such bindings requires either precarious
        2123                 :          * type-punning or, ideally, a new kind of Call object specifically for
        2124                 :          * strict mode eval frames.  Further, strict mode eval is not (yet)
        2125                 :          * common.  So for now (until we rewrite the scope chain to not use
        2126                 :          * objects?) just disable optimizations for top-level names in eval
        2127                 :          * code.
        2128                 :          */
        2129             144 :         return true;
        2130                 :     }
        2131                 :
        2132          104140 :     if (pn->pn_dflags & PND_CONST)
        2133           56106 :         return true;
        2134                 :
        2135                 :     /*
        2136                 :      * If this is a global variable, we're compile-and-go, and a global object
        2137                 :      * is present, try to bake in either an already available slot or a
        2138                 :      * predicted slot that will be defined after compiling is completed.
        2139                 :      */
        2140           48034 :     return DefineGlobal(pn, tc->asBytecodeEmitter(), pn->pn_atom->asPropertyName());
        2141                 : }
        2142                 :
        2143                 : static bool
        2144          121492 : BindFunctionLocal(JSContext *cx, BindData *data, MultiDeclRange &mdl, TreeContext *tc)
        2145                 : {
        2146          121492 :     JS_ASSERT(tc->inFunction());
        2147                 :
        2148          121492 :     ParseNode *pn = data->pn;
        2149          121492 :     JSAtom *name = pn->pn_atom;
        2150                 :
        2151                 :     /*
        2152                 :      * Don't create a local variable with the name 'arguments', per ECMA-262.
        2153                 :      * Instead, 'var arguments' always restates that predefined binding of the
        2154                 :      * lexical environment for function activations. Assignments to arguments
        2155                 :      * must be handled specially -- see NoteLValue.
        2156                 :      */
        2157          121492 :     if (name == cx->runtime->atomState.argumentsAtom) {
        2158              27 :         pn->setOp(JSOP_ARGUMENTS);
        2159              27 :         pn->pn_dflags |= PND_BOUND;
        2160              27 :         return true;
        2161                 :     }
        2162                 :
        2163          121465 :     BindingKind kind = tc->bindings.lookup(cx, name, NULL);
        2164          121465 :     if (kind == NONE) {
        2165                 :         /*
        2166                 :          * Property not found in current variable scope: we have not seen this
        2167                 :          * variable before, so bind a new local variable for it. Any locals
        2168                 :          * declared in a with statement body are handled at runtime, by script
        2169                 :          * prolog JSOP_DEFVAR opcodes generated for global and heavyweight-
        2170                 :          * function-local vars.
        2171                 :          */
        2172          121465 :         kind = (data->op == JSOP_DEFCONST) ? CONSTANT : VARIABLE;
        2173                 :
        2174          121465 :         if (!BindLocalVariable(cx, tc, pn, kind))
        2175               0 :             return false;
        2176          121465 :         pn->setOp(JSOP_GETLOCAL);
        2177          121465 :         return true;
        2178                 :     }
        2179                 :
        2180               0 :     if (kind == ARGUMENT) {
        2181               0 :         JS_ASSERT(tc->inFunction());
        2182               0 :         JS_ASSERT(!mdl.empty() && mdl.front()->kind() == Definition::ARG);
        2183                 :     } else {
        2184               0 :         JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
        2185                 :     }
        2186                 :
        2187               0 :     return true;
        2188                 : }
        2189                 :
        2190                 : static JSBool
        2191          229349 : BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc)
        2192                 : {
        2193          229349 :     ParseNode *pn = data->pn;
        2194                 :
        2195                 :     /* Default best op for pn is JSOP_NAME; we'll try to improve below. */
        2196          229349 :     pn->setOp(JSOP_NAME);
        2197                 :
        2198          229349 :     if (!CheckStrictBinding(cx, tc, atom->asPropertyName(), pn))
        2199               0 :         return false;
        2200                 :
        2201          229349 :     StmtInfo *stmt = LexicalLookup(tc, atom, NULL);
        2202                 :
        2203          229349 :     if (stmt && stmt->type == STMT_WITH) {
        2204              81 :         data->fresh = false;
        2205              81 :         pn->pn_dflags |= PND_DEOPTIMIZED;
        2206              81 :         tc->noteMightAliasLocals();
        2207              81 :         return true;
        2208                 :     }
        2209                 :
        2210          229268 :     MultiDeclRange mdl = tc->decls.lookupMulti(atom);
        2211          229268 :     JSOp op = data->op;
        2212                 :
        2213          229268 :     if (stmt || !mdl.empty()) {
        2214            3051 :         Definition *dn = mdl.empty() ? NULL : mdl.front();
        2215            3051 :         Definition::Kind dn_kind = dn ? dn->kind() : Definition::VAR;
        2216                 :
        2217            3051 :         if (dn_kind == Definition::ARG) {
        2218             900 :             JSAutoByteString name;
        2219             450 :             if (!js_AtomToPrintableString(cx, atom, &name))
        2220               0 :                 return JS_FALSE;
        2221                 :
        2222             450 :             if (op == JSOP_DEFCONST) {
        2223                 :                 ReportCompileErrorNumber(cx, TS(tc->parser), pn,
        2224                 :                                          JSREPORT_ERROR, JSMSG_REDECLARED_PARAM,
        2225               0 :                                          name.ptr());
        2226               0 :                 return JS_FALSE;
        2227                 :             }
        2228             450 :             if (!ReportCompileErrorNumber(cx, TS(tc->parser), pn,
        2229                 :                                           JSREPORT_WARNING | JSREPORT_STRICT,
        2230             450 :                                           JSMSG_VAR_HIDES_ARG, name.ptr())) {
        2231               0 :                 return JS_FALSE;
        2232                 :             }
        2233                 :         } else {
        2234                 :             bool error = (op == JSOP_DEFCONST ||
        2235                 :                           dn_kind == Definition::CONST ||
        2236                 :                           (dn_kind == Definition::LET &&
        2237            2601 :                            (stmt->type != STMT_CATCH || OuterLet(tc, stmt, atom))));
        2238                 :
        2239            2601 :             if (cx->hasStrictOption()
        2240                 :                 ? op != JSOP_DEFVAR || dn_kind != Definition::VAR
        2241                 :                 : error) {
        2242               0 :                 JSAutoByteString name;
        2243               0 :                 if (!js_AtomToPrintableString(cx, atom, &name) ||
        2244                 :                     !ReportCompileErrorNumber(cx, TS(tc->parser), pn,
        2245               0 :                                               !error
        2246                 :                                               ? JSREPORT_WARNING | JSREPORT_STRICT
        2247                 :                                               : JSREPORT_ERROR,
        2248                 :                                               JSMSG_REDECLARED_VAR,
        2249                 :                                               Definition::kindString(dn_kind),
        2250               0 :                                               name.ptr())) {
        2251               0 :                     return JS_FALSE;
        2252                 :                 }
        2253                 :             }
        2254                 :         }
        2255                 :     }
        2256                 :
        2257          229268 :     if (mdl.empty()) {
        2258          226217 :         if (!Define(pn, atom, tc))
        2259               0 :             return JS_FALSE;
        2260                 :     } else {
        2261                 :         /*
        2262                 :          * A var declaration never recreates an existing binding, it restates
        2263                 :          * it and possibly reinitializes its value. Beware that if pn becomes a
        2264                 :          * use of |mdl.defn()|, and if we have an initializer for this var or
        2265                 :          * const (typically a const would ;-), then pn must be rewritten into a
        2266                 :          * PNK_ASSIGN node. See js::Parser::variables, further below.
        2267                 :          *
        2268                 :          * A case such as let (x = 1) { var x = 2; print(x); } is even harder.
        2269                 :          * There the x definition is hoisted but the x = 2 assignment mutates
        2270                 :          * the block-local binding of x.
        2271                 :          */
        2272            3051 :         Definition *dn = mdl.front();
        2273                 :
        2274            3051 :         data->fresh = false;
        2275                 :
        2276            3051 :         if (!pn->isUsed()) {
        2277                 :             /* Make pnu be a fresh name node that uses dn. */
        2278            3051 :             ParseNode *pnu = pn;
        2279                 :
        2280            3051 :             if (pn->isDefn()) {
        2281               0 :                 pnu = NameNode::create(PNK_NAME, atom, tc);
        2282               0 :                 if (!pnu)
        2283               0 :                     return JS_FALSE;
        2284                 :             }
        2285                 :
        2286            3051 :             LinkUseToDef(pnu, dn, tc);
        2287            3051 :             pnu->setOp(JSOP_NAME);
        2288                 :         }
        2289                 :
        2290                 :         /* Find the first non-let binding of this atom. */
        2291            6102 :         while (dn->kind() == Definition::LET) {
        2292               9 :             mdl.popFront();
        2293               9 :             if (mdl.empty())
        2294               9 :                 break;
        2295               0 :             dn = mdl.front();
        2296                 :         }
        2297                 :
        2298            3051 :         if (dn) {
        2299               0 :             JS_ASSERT_IF(data->op == JSOP_DEFCONST,
        2300            3051 :                          dn->kind() == Definition::CONST);
        2301            3051 :             return JS_TRUE;
        2302                 :         }
        2303                 :
        2304                 :         /*
        2305                 :          * A var or const that is shadowed by one or more let bindings of the
        2306                 :          * same name, but that has not been declared until this point, must be
        2307                 :          * hoisted above the let bindings.
        2308                 :          */
        2309               0 :         if (!pn->isDefn()) {
        2310               0 :             if (tc->lexdeps->lookup(atom)) {
        2311               0 :                 tc->lexdeps->remove(atom);
        2312                 :             } else {
        2313               0 :                 ParseNode *pn2 = NameNode::create(PNK_NAME, atom, tc);
        2314               0 :                 if (!pn2)
        2315               0 :                     return JS_FALSE;
        2316                 :
        2317                 :                 /* The token stream may be past the location for pn. */
        2318               0 :                 pn2->pn_pos = pn->pn_pos;
        2319               0 :                 pn = pn2;
        2320                 :             }
        2321               0 :             pn->setOp(JSOP_NAME);
        2322                 :         }
        2323                 :
        2324               0 :         if (!tc->decls.addHoist(atom, (Definition *) pn))
        2325               0 :             return JS_FALSE;
        2326               0 :         pn->setDefn(true);
        2327               0 :         pn->pn_dflags &= ~PND_PLACEHOLDER;
        2328                 :     }
        2329                 :
        2330          226217 :     if (data->op == JSOP_DEFCONST)
        2331           56178 :         pn->pn_dflags |= PND_CONST;
        2332                 :
        2333          226217 :     if (tc->inFunction())
        2334          121492 :         return BindFunctionLocal(cx, data, mdl, tc);
        2335                 :
        2336          104725 :     return BindTopLevelVar(cx, data, pn, tc);
        2337                 : }
        2338                 :
        2339                 : static bool
        2340              36 : MakeSetCall(JSContext *cx, ParseNode *pn, TreeContext *tc, unsigned msg)
        2341                 : {
        2342              36 :     JS_ASSERT(pn->isArity(PN_LIST));
        2343              36 :     JS_ASSERT(pn->isOp(JSOP_CALL) || pn->isOp(JSOP_EVAL) ||
        2344              36 :               pn->isOp(JSOP_FUNCALL) || pn->isOp(JSOP_FUNAPPLY));
        2345              36 :     if (!ReportStrictModeError(cx, TS(tc->parser), tc, pn, msg))
        2346               0 :         return false;
        2347                 :
        2348              36 :     ParseNode *pn2 = pn->pn_head;
        2349              36 :     if (pn2->isKind(PNK_FUNCTION) && (pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA)) {
        2350               0 :         ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR, msg);
        2351               0 :         return false;
        2352                 :     }
        2353              36 :     pn->pn_xflags |= PNX_SETCALL;
        2354              36 :     return true;
        2355                 : }
        2356                 :
        2357                 : static void
        2358          561131 : NoteLValue(JSContext *cx, ParseNode *pn, TreeContext *tc, unsigned dflag = PND_ASSIGNED)
        2359                 : {
        2360          561131 :     if (pn->isUsed()) {
        2361          409068 :         Definition *dn = pn->pn_lexdef;
        2362                 :
        2363                 :         /*
        2364                 :          * Save the win of PND_INITIALIZED if we can prove 'var x;' and 'x = y'
        2365                 :          * occur as direct kids of the same block with no forward refs to x.
        2366                 :          */
        2367          439776 :         if (!(dn->pn_dflags & (PND_INITIALIZED | PND_CONST | PND_PLACEHOLDER)) &&
        2368           15782 :             dn->isBlockChild() &&
        2369           12865 :             pn->isBlockChild() &&
        2370                 :             dn->pn_blockid == pn->pn_blockid &&
        2371            2061 :             dn->pn_pos.end <= pn->pn_pos.begin &&
        2372                 :             dn->dn_uses == pn) {
        2373            2043 :             dflag = PND_INITIALIZED;
        2374                 :         }
        2375                 :
        2376          409068 :         dn->pn_dflags |= dflag;
        2377                 :     }
        2378                 :
        2379          561131 :     pn->pn_dflags |= dflag;
        2380                 :
        2381                 :     /*
        2382                 :      * Both arguments and the enclosing function's name are immutable bindings
        2383                 :      * in ES5, so assignments to them must do nothing or throw a TypeError
        2384                 :      * depending on code strictness.  Assignment to arguments is a syntax error
        2385                 :      * in strict mode and thus cannot happen.  Outside strict mode, we optimize
        2386                 :      * away assignment to the function name.  For assignment to function name
        2387                 :      * to fail in strict mode, we must have a binding for it in the scope
        2388                 :      * chain; we ensure this happens by making such functions heavyweight.
        2389                 :      */
        2390          561131 :     JSAtom *lname = pn->pn_atom;
        2391          561131 :     if (lname == cx->runtime->atomState.argumentsAtom) {
        2392              63 :         tc->flags |= TCF_FUN_HEAVYWEIGHT;
        2393              63 :         tc->noteLocalOverwritesArguments();
        2394              63 :         tc->countArgumentsUse(pn);
        2395          561068 :     } else if (tc->inFunction() && lname == tc->fun()->atom) {
        2396              99 :         tc->flags |= TCF_FUN_HEAVYWEIGHT;
        2397                 :     }
        2398          561131 : }
        2399                 :
        2400                 : #if JS_HAS_DESTRUCTURING
        2401                 :
        2402                 : static JSBool
        2403            4392 : BindDestructuringVar(JSContext *cx, BindData *data, ParseNode *pn, TreeContext *tc)
        2404                 : {
        2405                 :     JSAtom *atom;
        2406                 :
        2407                 :     /*
        2408                 :      * Destructuring is a form of assignment, so just as for an initialized
        2409                 :      * simple variable, we must check for assignment to 'arguments' and flag
        2410                 :      * the enclosing function (if any) as heavyweight.
        2411                 :      */
        2412            4392 :     JS_ASSERT(pn->isKind(PNK_NAME));
        2413            4392 :     atom = pn->pn_atom;
        2414            4392 :     if (atom == cx->runtime->atomState.argumentsAtom) {
        2415               0 :         tc->flags |= TCF_FUN_HEAVYWEIGHT;
        2416               0 :         tc->noteLocalOverwritesArguments();
        2417                 :     }
        2418                 :
        2419            4392 :     data->pn = pn;
        2420            4392 :     if (!data->binder(cx, data, atom, tc))
        2421             135 :         return JS_FALSE;
        2422                 :
        2423                 :     /*
        2424                 :      * Select the appropriate name-setting opcode, respecting eager selection
        2425                 :      * done by the data->binder function.
        2426                 :      */
        2427            4257 :     if (pn->pn_dflags & PND_BOUND) {
        2428            3942 :         JS_ASSERT(!(pn->pn_dflags & PND_GVAR));
        2429            3942 :         pn->setOp(pn->isOp(JSOP_ARGUMENTS) ? JSOP_SETNAME : JSOP_SETLOCAL);
        2430                 :     } else {
        2431             315 :         pn->setOp((data->op == JSOP_DEFCONST) ? JSOP_SETCONST : JSOP_SETNAME);
        2432                 :     }
        2433                 :
        2434            4257 :     if (data->op == JSOP_DEFCONST)
        2435               9 :         pn->pn_dflags |= PND_CONST;
        2436                 :
        2437            4257 :     NoteLValue(cx, pn, tc, PND_INITIALIZED);
        2438            4257 :     return JS_TRUE;
        2439                 : }
        2440                 :
        2441                 : /*
        2442                 :  * Here, we are destructuring {... P: Q, ...} = R, where P is any id, Q is any
        2443                 :  * LHS expression except a destructuring initialiser, and R is on the stack.
        2444                 :  * Because R is already evaluated, the usual LHS-specialized bytecodes won't
        2445                 :  * work.  After pushing R[P] we need to evaluate Q's "reference base" QB and
        2446                 :  * then push its property name QN.  At this point the stack looks like
        2447                 :  *
        2448                 :  *   [... R, R[P], QB, QN]
        2449                 :  *
        2450                 :  * We need to set QB[QN] = R[P].  This is a job for JSOP_ENUMELEM, which takes
        2451                 :  * its operands with left-hand side above right-hand side:
        2452                 :  *
        2453                 :  *   [rval, lval, xval]
        2454                 :  *
        2455                 :  * and pops all three values, setting lval[xval] = rval.  But we cannot select
        2456                 :  * JSOP_ENUMELEM yet, because the LHS may turn out to be an arg or local var,
        2457                 :  * which can be optimized further.  So we select JSOP_SETNAME.
        2458                 :  */
        2459                 : static JSBool
        2460             162 : BindDestructuringLHS(JSContext *cx, ParseNode *pn, TreeContext *tc)
        2461                 : {
        2462             162 :     switch (pn->getKind()) {
        2463                 :       case PNK_NAME:
        2464             144 :         NoteLValue(cx, pn, tc);
        2465                 :         /* FALL THROUGH */
        2466                 :
        2467                 :       case PNK_DOT:
        2468                 :       case PNK_LB:
        2469                 :         /*
        2470                 :          * We may be called on a name node that has already been specialized,
        2471                 :          * in the very weird and ECMA-262-required "for (var [x] = i in o) ..."
        2472                 :          * case. See bug 558633.
        2473                 :          */
        2474             162 :         if (!(js_CodeSpec[pn->getOp()].format & JOF_SET))
        2475             162 :             pn->setOp(JSOP_SETNAME);
        2476             162 :         break;
        2477                 :
        2478                 :       case PNK_LP:
        2479               0 :         if (!MakeSetCall(cx, pn, tc, JSMSG_BAD_LEFTSIDE_OF_ASS))
        2480               0 :             return JS_FALSE;
        2481               0 :         break;
        2482                 :
        2483                 : #if JS_HAS_XML_SUPPORT
        2484                 :       case PNK_XMLUNARY:
        2485               0 :         JS_ASSERT(pn->isOp(JSOP_XMLNAME));
        2486               0 :         pn->setOp(JSOP_BINDXMLNAME);
        2487               0 :         break;
        2488                 : #endif
        2489                 :
        2490                 :       default:
        2491                 :         ReportCompileErrorNumber(cx, TS(tc->parser), pn,
        2492               0 :                                  JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS);
        2493               0 :         return JS_FALSE;
        2494                 :     }
        2495                 :
        2496             162 :     return JS_TRUE;
        2497                 : }
        2498                 :
        2499                 : /*
        2500                 :  * Destructuring patterns can appear in two kinds of contexts:
        2501                 :  *
        2502                 :  * - assignment-like: assignment expressions and |for| loop heads.  In
        2503                 :  *   these cases, the patterns' property value positions can be
        2504                 :  *   arbitrary lvalue expressions; the destructuring is just a fancy
        2505                 :  *   assignment.
        2506                 :  *
        2507                 :  * - declaration-like: |var| and |let| declarations, functions' formal
        2508                 :  *   parameter lists, |catch| clauses, and comprehension tails.  In
        2509                 :  *   these cases, the patterns' property value positions must be
        2510                 :  *   simple names; the destructuring defines them as new variables.
        2511                 :  *
        2512                 :  * In both cases, other code parses the pattern as an arbitrary
        2513                 :  * primaryExpr, and then, here in CheckDestructuring, verify that the
        2514                 :  * tree is a valid destructuring expression.
        2515                 :  *
        2516                 :  * In assignment-like contexts, we parse the pattern with the
        2517                 :  * TCF_DECL_DESTRUCTURING flag clear, so the lvalue expressions in the
        2518                 :  * pattern are parsed normally.  primaryExpr links variable references
        2519                 :  * into the appropriate use chains; creates placeholder definitions;
        2520                 :  * and so on.  CheckDestructuring is called with |data| NULL (since we
        2521                 :  * won't be binding any new names), and we specialize lvalues as
        2522                 :  * appropriate.
        2523                 :  *
        2524                 :  * In declaration-like contexts, the normal variable reference
        2525                 :  * processing would just be an obstruction, because we're going to
        2526                 :  * define the names that appear in the property value positions as new
        2527                 :  * variables anyway.  In this case, we parse the pattern with
        2528                 :  * TCF_DECL_DESTRUCTURING set, which directs primaryExpr to leave
        2529                 :  * whatever name nodes it creates unconnected.  Then, here in
        2530                 :  * CheckDestructuring, we require the pattern's property value
        2531                 :  * positions to be simple names, and define them as appropriate to the
        2532                 :  * context.  For these calls, |data| points to the right sort of
        2533                 :  * BindData.
        2534                 :  *
        2535                 :  * See also UndominateInitializers, immediately below. If you change
        2536                 :  * either of these functions, you might have to change the other to
        2537                 :  * match.
        2538                 :  *
        2539                 :  * The 'toplevel' is a private detail of the recursive strategy used by
        2540                 :  * CheckDestructuring and callers should use the default value.
        2541                 :  */
        2542                 : static bool
        2543           12429 : CheckDestructuring(JSContext *cx, BindData *data, ParseNode *left, TreeContext *tc,
        2544                 :                    bool toplevel = true)
        2545                 : {
        2546                 :     bool ok;
        2547                 :
        2548           12429 :     if (left->isKind(PNK_ARRAYCOMP)) {
        2549                 :         ReportCompileErrorNumber(cx, TS(tc->parser), left, JSREPORT_ERROR,
        2550               0 :                                  JSMSG_ARRAY_COMP_LEFTSIDE);
        2551               0 :         return false;
        2552                 :     }
        2553                 :
        2554           12429 :     StaticBlockObject *blockObj = data && data->binder == BindLet ? data->let.blockObj : NULL;
        2555           12429 :     uint32_t blockCountBefore = blockObj ? blockObj->slotCount() : 0;
        2556                 :
        2557           12429 :     if (left->isKind(PNK_RB)) {
        2558           19152 :         for (ParseNode *pn = left->pn_head; pn; pn = pn->pn_next) {
        2559                 :             /* Nullary comma is an elision; binary comma is an expression.*/
        2560            8442 :             if (!pn->isArrayHole()) {
        2561            7407 :                 if (pn->isKind(PNK_RB) || pn->isKind(PNK_RC)) {
        2562            3852 :                     ok = CheckDestructuring(cx, data, pn, tc, false);
        2563                 :                 } else {
        2564            3555 :                     if (data) {
        2565            3447 :                         if (!pn->isKind(PNK_NAME)) {
        2566                 :                             ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR,
        2567               0 :                                                      JSMSG_NO_VARIABLE_NAME);
        2568               0 :                             return false;
        2569                 :                         }
        2570            3447 :                         ok = BindDestructuringVar(cx, data, pn, tc);
        2571                 :                     } else {
        2572             108 :                         ok = BindDestructuringLHS(cx, pn, tc);
        2573                 :                     }
        2574                 :                 }
        2575            7407 :                 if (!ok)
        2576             189 :                     return false;
        2577                 :             }
        2578                 :         }
        2579                 :     } else {
        2580            1530 :         JS_ASSERT(left->isKind(PNK_RC));
        2581            3429 :         for (ParseNode *pair = left->pn_head; pair; pair = pair->pn_next) {
        2582            1962 :             JS_ASSERT(pair->isKind(PNK_COLON));
        2583            1962 :             ParseNode *pn = pair->pn_right;
        2584                 :
        2585            1962 :             if (pn->isKind(PNK_RB) || pn->isKind(PNK_RC)) {
        2586             936 :                 ok = CheckDestructuring(cx, data, pn, tc, false);
        2587            1026 :             } else if (data) {
        2588             972 :                 if (!pn->isKind(PNK_NAME)) {
        2589                 :                     ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR,
        2590              27 :                                              JSMSG_NO_VARIABLE_NAME);
        2591              27 :                     return false;
        2592                 :                 }
        2593             945 :                 ok = BindDestructuringVar(cx, data, pn, tc);
        2594                 :             } else {
        2595              54 :                 ok = BindDestructuringLHS(cx, pn, tc);
        2596                 :             }
        2597            1935 :             if (!ok)
        2598              36 :                 return false;
        2599                 :         }
        2600                 :     }
        2601                 :
        2602                 :     /*
        2603                 :      * The catch/finally handler implementation in the interpreter assumes
        2604                 :      * that any operation that introduces a new scope (like a "let" or "with"
        2605                 :      * block) increases the stack depth. This way, it is possible to restore
        2606                 :      * the scope chain based on stack depth of the handler alone. "let" with
        2607                 :      * an empty destructuring pattern like in
        2608                 :      *
        2609                 :      *   let [] = 1;
        2610                 :      *
        2611                 :      * would violate this assumption as the there would be no let locals to
        2612                 :      * store on the stack.
        2613                 :      *
        2614                 :      * Furthermore, the decompiler needs an abstract stack location to store
        2615                 :      * the decompilation of each let block/expr initializer. E.g., given:
        2616                 :      *
        2617                 :      *   let (x = 1, [[]] = b, y = 3, {a:[]} = c) { ... }
        2618                 :      *
        2619                 :      * four slots are needed.
        2620                 :      *
        2621                 :      * To satisfy both constraints, we push a dummy slot (and add a
        2622                 :      * corresponding dummy property to the block object) for each initializer
        2623                 :      * that doesn't introduce at least one binding.
        2624                 :      */
        2625           12177 :     if (toplevel && blockObj && blockCountBefore == blockObj->slotCount()) {
        2626                 :         bool redeclared;
        2627            4428 :         if (!blockObj->addVar(cx, INT_TO_JSID(blockCountBefore), blockCountBefore, &redeclared))
        2628               0 :             return false;
        2629            4428 :         JS_ASSERT(!redeclared);
        2630            4428 :         JS_ASSERT(blockObj->slotCount() == blockCountBefore + 1);
        2631                 :     }
        2632                 :
        2633           12177 :     return true;
        2634                 : }
        2635                 :
        2636                 : /*
        2637                 :  * Extend the pn_pos.end source coordinate of each name in a destructuring
        2638                 :  * binding such as
        2639                 :  *
        2640                 :  *   var [x, y] = [function () y, 42];
        2641                 :  *
        2642                 :  * to cover the entire initializer, so that the initialized bindings do not
        2643                 :  * appear to dominate any closures in the initializer. See bug 496134.
        2644                 :  *
        2645                 :  * The quick-and-dirty dominance computation in Parser::setFunctionKinds is not
        2646                 :  * very precise. With one-pass SSA construction from structured source code
        2647                 :  * (see "Single-Pass Generation of Static Single Assignment Form for Structured
        2648                 :  * Languages", Brandis and Mössenböck), we could do much better.
        2649                 :  *
        2650                 :  * See CheckDestructuring, immediately above. If you change either of these
        2651                 :  * functions, you might have to change the other to match.
        2652                 :  */
        2653                 : static void
        2654           11475 : UndominateInitializers(ParseNode *left, const TokenPtr &end, TreeContext *tc)
        2655                 : {
        2656           11475 :     if (left->isKind(PNK_RB)) {
        2657           17631 :         for (ParseNode *pn = left->pn_head; pn; pn = pn->pn_next) {
        2658                 :             /* Nullary comma is an elision; binary comma is an expression.*/
        2659            7461 :             if (!pn->isKind(PNK_COMMA) || !pn->isArity(PN_NULLARY)) {
        2660            6435 :                 if (pn->isKind(PNK_RB) || pn->isKind(PNK_RC))
        2661            3591 :                     UndominateInitializers(pn, end, tc);
        2662                 :                 else
        2663            2844 :                     pn->pn_pos.end = end;
        2664                 :             }
        2665                 :         }
        2666                 :     } else {
        2667            1305 :         JS_ASSERT(left->isKind(PNK_RC));
        2668                 :
        2669            2961 :         for (ParseNode *pair = left->pn_head; pair; pair = pair->pn_next) {
        2670            1656 :             JS_ASSERT(pair->isKind(PNK_COLON));
        2671            1656 :             ParseNode *pn = pair->pn_right;
        2672            1656 :             if (pn->isKind(PNK_RB) || pn->isKind(PNK_RC))
        2673             918 :                 UndominateInitializers(pn, end, tc);
        2674                 :             else
        2675             738 :                 pn->pn_pos.end = end;
        2676                 :         }
        2677                 :     }
        2678           11475 : }
        2679                 :
        2680                 : ParseNode *
        2681              81 : Parser::destructuringExpr(BindData *data, TokenKind tt)
        2682                 : {
        2683              81 :     JS_ASSERT(tokenStream.isCurrentTokenType(tt));
        2684                 :
        2685              81 :     tc->flags |= TCF_DECL_DESTRUCTURING;
        2686              81 :     ParseNode *pn = primaryExpr(tt, JS_FALSE);
        2687              81 :     tc->flags &= ~TCF_DECL_DESTRUCTURING;
        2688              81 :     if (!pn)
        2689               0 :         return NULL;
        2690              81 :     if (!CheckDestructuring(context, data, pn, tc))
        2691               0 :         return NULL;
        2692              81 :     return pn;
        2693                 : }
        2694                 :
        2695                 : #endif /* JS_HAS_DESTRUCTURING */
        2696                 :
        2697                 : ParseNode *
        2698           39114 : Parser::returnOrYield(bool useAssignExpr)
        2699                 : {
        2700           39114 :     TokenKind tt = tokenStream.currentToken().type;
        2701           39114 :     if (!tc->inFunction()) {
        2702                 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_RETURN_OR_YIELD,
        2703               0 :                           (tt == TOK_RETURN) ? js_return_str : js_yield_str);
        2704               0 :         return NULL;
        2705                 :     }
        2706                 :
        2707           39114 :     ParseNode *pn = UnaryNode::create((tt == TOK_RETURN) ? PNK_RETURN : PNK_YIELD, tc);
        2708           39114 :     if (!pn)
        2709               0 :         return NULL;
        2710                 :
        2711                 : #if JS_HAS_GENERATORS
        2712           39114 :     if (tt == TOK_YIELD) {
        2713                 :         /*
        2714                 :          * If we're within parens, we won't know if this is a generator expression until we see
        2715                 :          * a |for| token, so we have to delay flagging the current function.
        2716                 :          */
        2717             558 :         if (tc->parenDepth == 0) {
        2718             558 :             tc->flags |= TCF_FUN_IS_GENERATOR;
        2719                 :         } else {
        2720               0 :             tc->yieldCount++;
        2721               0 :             tc->yieldNode = pn;
        2722                 :         }
        2723                 :     }
        2724                 : #endif
        2725                 :
        2726                 :     /* This is ugly, but we don't want to require a semicolon. */
        2727           39114 :     TokenKind tt2 = tokenStream.peekTokenSameLine(TSF_OPERAND);
        2728           39114 :     if (tt2 == TOK_ERROR)
        2729               0 :         return NULL;
        2730                 :
        2731           39114 :     if (tt2 != TOK_EOF && tt2 != TOK_EOL && tt2 != TOK_SEMI && tt2 != TOK_RC
        2732                 : #if JS_HAS_GENERATORS
        2733                 :         && (tt != TOK_YIELD ||
        2734                 :             (tt2 != tt && tt2 != TOK_RB && tt2 != TOK_RP &&
        2735                 :              tt2 != TOK_COLON && tt2 != TOK_COMMA))
        2736                 : #endif
        2737                 :         )
        2738                 :     {
        2739           37602 :         ParseNode *pn2 = useAssignExpr ? assignExpr() : expr();
        2740           37602 :         if (!pn2)
        2741               0 :             return NULL;
        2742                 : #if JS_HAS_GENERATORS
        2743           37602 :         if (tt == TOK_RETURN)
        2744                 : #endif
        2745           37197 :             tc->flags |= TCF_RETURN_EXPR;
        2746           37602 :         pn->pn_pos.end = pn2->pn_pos.end;
        2747           37602 :         pn->pn_kid = pn2;
        2748                 :     } else {
        2749                 : #if JS_HAS_GENERATORS
        2750            1512 :         if (tt == TOK_RETURN)
        2751                 : #endif
        2752            1359 :             tc->flags |= TCF_RETURN_VOID;
        2753                 :     }
        2754                 :
        2755           39114 :     if ((~tc->flags & (TCF_RETURN_EXPR | TCF_FUN_IS_GENERATOR)) == 0) {
        2756                 :         /* As in Python (see PEP-255), disallow return v; in generators. */
        2757                 :         ReportBadReturn(context, tc, pn, JSREPORT_ERROR,
        2758                 :                         JSMSG_BAD_GENERATOR_RETURN,
        2759               0 :                         JSMSG_BAD_ANON_GENERATOR_RETURN);
        2760               0 :         return NULL;
        2761                 :     }
        2762                 :
        2763           39114 :     if (context->hasStrictOption() &&
        2764                 :         (~tc->flags & (TCF_RETURN_EXPR | TCF_RETURN_VOID)) == 0 &&
        2765                 :         !ReportBadReturn(context, tc, pn, JSREPORT_WARNING | JSREPORT_STRICT,
        2766                 :                          JSMSG_NO_RETURN_VALUE,
        2767               0 :                          JSMSG_ANON_NO_RETURN_VALUE)) {
        2768               0 :         return NULL;
        2769                 :     }
        2770                 :
        2771           39114 :     return pn;
        2772                 : }
        2773                 :
        2774                 : static ParseNode *
        2775           98938 : PushLexicalScope(JSContext *cx, TreeContext *tc, StaticBlockObject &obj, StmtInfo *stmt)
        2776                 : {
        2777           98938 :     ParseNode *pn = LexicalScopeNode::create(PNK_LEXICALSCOPE, tc);
        2778           98938 :     if (!pn)
        2779               0 :         return NULL;
        2780                 :
        2781           98938 :     ObjectBox *blockbox = tc->parser->newObjectBox(&obj);
        2782           98938 :     if (!blockbox)
        2783               0 :         return NULL;
        2784                 :
        2785           98938 :     PushBlockScope(tc, stmt, obj, -1);
        2786           98938 :     pn->setOp(JSOP_LEAVEBLOCK);
        2787           98938 :     pn->pn_objbox = blockbox;
        2788           98938 :     pn->pn_cookie.makeFree();
        2789           98938 :     pn->pn_dflags = 0;
        2790           98938 :     if (!GenerateBlockId(tc, stmt->blockid))
        2791               0 :         return NULL;
        2792           98938 :     pn->pn_blockid = stmt->blockid;
        2793           98938 :     return pn;
        2794                 : }
        2795                 :
        2796                 : static ParseNode *
        2797           87777 : PushLexicalScope(JSContext *cx, TreeContext *tc, StmtInfo *stmt)
        2798                 : {
        2799           87777 :     StaticBlockObject *blockObj = StaticBlockObject::create(cx);
        2800           87777 :     if (!blockObj)
        2801               0 :         return NULL;
        2802                 :
        2803           87777 :     return PushLexicalScope(cx, tc, *blockObj, stmt);
        2804                 : }
        2805                 :
        2806                 : #if JS_HAS_BLOCK_SCOPE
        2807                 :
        2808                 : struct AddDecl
        2809                 : {
        2810                 :     uint32_t blockid;
        2811                 :
        2812           11161 :     AddDecl(uint32_t blockid) : blockid(blockid) {}
        2813                 :
        2814          159176 :     bool operator()(TreeContext *tc, StaticBlockObject &blockObj, const Shape &shape, JSAtom *atom)
        2815                 :     {
        2816          159176 :         ParseNode *def = (ParseNode *) blockObj.getSlot(shape.slot()).toPrivate();
        2817          159176 :         def->pn_blockid = blockid;
        2818          159176 :         return Define(def, atom, tc, true);
        2819                 :     }
        2820                 : };
        2821                 :
        2822                 : static ParseNode *
        2823           11161 : PushLetScope(JSContext *cx, TreeContext *tc, StaticBlockObject &blockObj, StmtInfo *stmt)
        2824                 : {
        2825           11161 :     ParseNode *pn = PushLexicalScope(cx, tc, blockObj, stmt);
        2826           11161 :     if (!pn)
        2827               0 :         return NULL;
        2828                 :
        2829                 :     /* Tell codegen to emit JSOP_ENTERLETx (not JSOP_ENTERBLOCK). */
        2830           11161 :     pn->pn_dflags |= PND_LET;
        2831                 :
        2832                 :     /* Populate the new scope with decls found in the head with updated blockid. */
        2833           11161 :     if (!ForEachLetDef(tc, blockObj, AddDecl(stmt->blockid)))
        2834               0 :         return NULL;
        2835                 :
        2836           11161 :     return pn;
        2837                 : }
        2838                 :
        2839                 : /*
        2840                 :  * Parse a let block statement or let expression (determined by 'letContext').
        2841                 :  * In both cases, bindings are not hoisted to the top of the enclosing block
        2842                 :  * and thus must be carefully injected between variables() and the let body.
        2843                 :  */
        2844                 : ParseNode *
        2845            4231 : Parser::letBlock(LetContext letContext)
        2846                 : {
        2847            4231 :     JS_ASSERT(tokenStream.currentToken().type == TOK_LET);
        2848                 :
        2849            4231 :     ParseNode *pnlet = BinaryNode::create(PNK_LET, tc);
        2850            4231 :     if (!pnlet)
        2851               0 :         return NULL;
        2852                 :
        2853            4231 :     StaticBlockObject *blockObj = StaticBlockObject::create(context);
        2854            4231 :     if (!blockObj)
        2855               0 :         return NULL;
        2856                 :
        2857            4231 :     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_LET);
        2858                 :
        2859            4231 :     ParseNode *vars = variables(PNK_LET, blockObj, DontHoistVars);
        2860            4231 :     if (!vars)
        2861             108 :         return NULL;
        2862                 :
        2863            4123 :     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_LET);
        2864                 :
        2865                 :     StmtInfo stmtInfo;
        2866            4105 :     ParseNode *block = PushLetScope(context, tc, *blockObj, &stmtInfo);
        2867            4105 :     if (!block)
        2868               0 :         return NULL;
        2869                 :
        2870            4105 :     pnlet->pn_left = vars;
        2871            4105 :     pnlet->pn_right = block;
        2872                 :
        2873                 :     ParseNode *ret;
        2874            4105 :     if (letContext == LetStatement && !tokenStream.matchToken(TOK_LC, TSF_OPERAND)) {
        2875                 :         /*
        2876                 :          * Strict mode eliminates a grammar ambiguity with unparenthesized
        2877                 :          * LetExpressions in an ExpressionStatement. If followed immediately
        2878                 :          * by an arguments list, it's ambiguous whether the let expression
        2879                 :          * is the callee or the call is inside the let expression body.
        2880                 :          *
        2881                 :          * See bug 569464.
        2882                 :          */
        2883             234 :         if (!ReportStrictModeError(context, &tokenStream, tc, pnlet,
        2884             234 :                                    JSMSG_STRICT_CODE_LET_EXPR_STMT)) {
        2885               0 :             return NULL;
        2886                 :         }
        2887                 :
        2888                 :         /*
        2889                 :          * If this is really an expression in let statement guise, then we
        2890                 :          * need to wrap the TOK_LET node in a TOK_SEMI node so that we pop
        2891                 :          * the return value of the expression.
        2892                 :          */
        2893             234 :         ParseNode *semi = UnaryNode::create(PNK_SEMI, tc);
        2894             234 :         if (!semi)
        2895               0 :             return NULL;
        2896                 :
        2897             234 :         semi->pn_kid = pnlet;
        2898                 :
        2899             234 :         letContext = LetExpresion;
        2900             234 :         ret = semi;
        2901                 :     } else {
        2902            3871 :         ret = pnlet;
        2903                 :     }
        2904                 :
        2905            4105 :     if (letContext == LetStatement) {
        2906            2025 :         JS_ASSERT(block->getOp() == JSOP_LEAVEBLOCK);
        2907            2025 :         block->pn_expr = statements();
        2908            2025 :         if (!block->pn_expr)
        2909              18 :             return NULL;
        2910            2007 :         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LET);
        2911                 :     } else {
        2912            2080 :         JS_ASSERT(letContext == LetExpresion);
        2913            2080 :         block->setOp(JSOP_LEAVEBLOCKEXPR);
        2914            2080 :         block->pn_expr = assignExpr();
        2915            2080 :         if (!block->pn_expr)
        2916               0 :             return NULL;
        2917                 :     }
        2918                 :
        2919            4087 :     PopStatement(tc);
        2920            4087 :     return ret;
        2921                 : }
        2922                 :
        2923                 : #endif /* JS_HAS_BLOCK_SCOPE */
        2924                 :
        2925                 : static bool
        2926          186972 : PushBlocklikeStatement(StmtInfo *stmt, StmtType type, TreeContext *tc)
        2927                 : {
        2928          186972 :     PushStatement(tc, stmt, type, -1);
        2929          186972 :     return GenerateBlockId(tc, stmt->blockid);
        2930                 : }
        2931                 :
        2932                 : static ParseNode *
        2933          548707 : NewBindingNode(JSAtom *atom, TreeContext *tc, StaticBlockObject *blockObj = NULL,
        2934                 :                VarContext varContext = HoistVars)
        2935                 : {
        2936                 :     /*
        2937                 :      * If this name is being injected into an existing block/function, see if
        2938                 :      * it has already been declared or if it resolves an outstanding lexdep.
        2939                 :      * Otherwise, this is a let block/expr that introduces a new scope and thus
        2940                 :      * shadows existing decls and doesn't resolve existing lexdeps. Duplicate
        2941                 :      * names are caught by BindLet.
        2942                 :      */
        2943          548707 :     if (!blockObj || varContext == HoistVars) {
        2944          391628 :         ParseNode *pn = tc->decls.lookupFirst(atom);
        2945          391628 :         AtomDefnPtr removal;
        2946          391628 :         if (pn) {
        2947            3312 :             JS_ASSERT(!pn->isPlaceholder());
        2948                 :         } else {
        2949          388316 :             removal = tc->lexdeps->lookup(atom);
        2950          388316 :             pn = removal ? removal.value() : NULL;
        2951          388316 :             JS_ASSERT_IF(pn, pn->isPlaceholder());
        2952                 :         }
        2953                 :
        2954          391628 :         if (pn) {
        2955            5571 :             JS_ASSERT(pn->isDefn());
        2956                 :
        2957                 :             /*
        2958                 :              * A let binding at top level becomes a var before we get here, so if
        2959                 :              * pn and tc have the same blockid then that id must not be the bodyid.
        2960                 :              * If pn is a forward placeholder definition from the same or a higher
        2961                 :              * block then we claim it.
        2962                 :              */
        2963             441 :             JS_ASSERT_IF(blockObj && pn->pn_blockid == tc->blockid(),
        2964            6012 :                          pn->pn_blockid != tc->bodyid);
        2965                 :
        2966            5571 :             if (pn->isPlaceholder() && pn->pn_blockid >= tc->blockid()) {
        2967             981 :                 pn->pn_blockid = tc->blockid();
        2968             981 :                 tc->lexdeps->remove(removal);
        2969             981 :                 return pn;
        2970                 :             }
        2971                 :         }
        2972                 :     }
        2973                 :
        2974                 :     /* Make a new node for this declarator name (or destructuring pattern). */
        2975          547726 :     JS_ASSERT(tc->parser->tokenStream.currentToken().type == TOK_NAME);
        2976          547726 :     ParseNode *pn = NameNode::create(PNK_NAME, atom, tc);
        2977          547726 :     if (!pn)
        2978               0 :         return NULL;
        2979                 :
        2980          547726 :     if (atom == tc->parser->context->runtime->atomState.argumentsAtom)
        2981              36 :         tc->countArgumentsUse(pn);
        2982                 :
        2983          547726 :     return pn;
        2984                 : }
        2985                 :
        2986                 : ParseNode *
        2987             918 : Parser::switchStatement()
        2988                 : {
        2989             918 :     JS_ASSERT(tc->parser->tokenStream.currentToken().type == TOK_SWITCH);
        2990             918 :     ParseNode *pn = BinaryNode::create(PNK_SWITCH, tc);
        2991             918 :     if (!pn)
        2992               0 :         return NULL;
        2993             918 :     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH);
        2994                 :
        2995                 :     /* pn1 points to the switch's discriminant. */
        2996             918 :     ParseNode *pn1 = parenExpr();
        2997             918 :     if (!pn1)
        2998               0 :         return NULL;
        2999                 :
        3000             918 :     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_SWITCH);
        3001             918 :     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH);
        3002                 :
        3003                 :     /*
        3004                 :      * NB: we must push stmtInfo before calling GenerateBlockIdForStmtNode
        3005                 :      * because that function states tc->topStmt->blockid.
        3006                 :      */
        3007                 :     StmtInfo stmtInfo;
        3008             918 :     PushStatement(tc, &stmtInfo, STMT_SWITCH, -1);
        3009                 :
        3010                 :     /* pn2 is a list of case nodes. The default case has pn_left == NULL */
        3011             918 :     ParseNode *pn2 = ListNode::create(PNK_STATEMENTLIST, tc);
        3012             918 :     if (!pn2)
        3013               0 :         return NULL;
        3014             918 :     pn2->makeEmpty();
        3015             918 :     if (!GenerateBlockIdForStmtNode(pn2, tc))
        3016               0 :         return NULL;
        3017             918 :     ParseNode *saveBlock = tc->blockNode;
        3018             918 :     tc->blockNode = pn2;
        3019                 :
        3020             918 :     bool seenDefault = false;
        3021                 :     TokenKind tt;
        3022            5499 :     while ((tt = tokenStream.getToken()) != TOK_RC) {
        3023                 :         ParseNode *pn3;
        3024            3672 :         switch (tt) {
        3025                 :           case TOK_DEFAULT:
        3026             558 :             if (seenDefault) {
        3027               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_DEFAULTS);
        3028               0 :                 return NULL;
        3029                 :             }
        3030             558 :             seenDefault = true;
        3031             558 :             pn3 = BinaryNode::create(PNK_DEFAULT, tc);
        3032             558 :             if (!pn3)
        3033               0 :                 return NULL;
        3034             558 :             break;
        3035                 :
        3036                 :           case TOK_CASE:
        3037                 :           {
        3038            3114 :             pn3 = BinaryNode::create(PNK_CASE, tc);
        3039            3114 :             if (!pn3)
        3040               0 :                 return NULL;
        3041            3114 :             pn3->pn_left = expr();
        3042            3114 :             if (!pn3->pn_left)
        3043               0 :                 return NULL;
        3044            3114 :             break;
        3045                 :           }
        3046                 :
        3047                 :           case TOK_ERROR:
        3048               0 :             return NULL;
        3049                 :
        3050                 :           default:
        3051               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_SWITCH);
        3052               0 :             return NULL;
        3053                 :         }
        3054                 :
        3055            3672 :         pn2->append(pn3);
        3056            3672 :         if (pn2->pn_count == JS_BIT(16)) {
        3057               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_CASES);
        3058               0 :             return NULL;
        3059                 :         }
        3060                 :
        3061            3672 :         MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE);
        3062                 :
        3063            3672 :         ParseNode *pn4 = ListNode::create(PNK_STATEMENTLIST, tc);
        3064            3672 :         if (!pn4)
        3065               0 :             return NULL;
        3066            3672 :         pn4->makeEmpty();
        3067          162459 :         while ((tt = tokenStream.peekToken(TSF_OPERAND)) != TOK_RC &&
        3068                 :                tt != TOK_CASE && tt != TOK_DEFAULT) {
        3069          155124 :             if (tt == TOK_ERROR)
        3070               0 :                 return NULL;
        3071          155124 :             ParseNode *pn5 = statement();
        3072          155124 :             if (!pn5)
        3073               9 :                 return NULL;
        3074          155115 :             pn4->pn_pos.end = pn5->pn_pos.end;
        3075          155115 :             pn4->append(pn5);
        3076                 :         }
        3077                 :
        3078                 :         /* Fix the PN_LIST so it doesn't begin at the TOK_COLON. */
        3079            3663 :         if (pn4->pn_head)
        3080            2988 :             pn4->pn_pos.begin = pn4->pn_head->pn_pos.begin;
        3081            3663 :         pn3->pn_pos.end = pn4->pn_pos.end;
        3082            3663 :         pn3->pn_right = pn4;
        3083                 :     }
        3084                 :
        3085                 :     /*
        3086                 :      * Handle the case where there was a let declaration in any case in
        3087                 :      * the switch body, but not within an inner block.  If it replaced
        3088                 :      * tc->blockNode with a new block node then we must refresh pn2 and
        3089                 :      * then restore tc->blockNode.
        3090                 :      */
        3091             909 :     if (tc->blockNode != pn2)
        3092             144 :         pn2 = tc->blockNode;
        3093             909 :     tc->blockNode = saveBlock;
        3094             909 :     PopStatement(tc);
        3095                 :
        3096             909 :     pn->pn_pos.end = pn2->pn_pos.end = tokenStream.currentToken().pos.end;
        3097             909 :     pn->pn_left = pn1;
        3098             909 :     pn->pn_right = pn2;
        3099             909 :     return pn;
        3100                 : }
        3101                 :
        3102                 : bool
        3103           30630 : Parser::matchInOrOf(bool *isForOfp)
        3104                 : {
        3105           30630 :     if (tokenStream.matchToken(TOK_IN)) {
        3106            4321 :         *isForOfp = false;
        3107            4321 :         return true;
        3108                 :     }
        3109           26309 :     if (tokenStream.matchToken(TOK_NAME)) {
        3110            1035 :         if (tokenStream.currentToken().name() == context->runtime->atomState.ofAtom) {
        3111            1035 :             *isForOfp = true;
        3112            1035 :             return true;
        3113                 :         }
        3114               0 :         tokenStream.ungetToken();
        3115                 :     }
        3116           25274 :     return false;
        3117                 : }
        3118                 :
        3119                 : ParseNode *
        3120           29893 : Parser::forStatement()
        3121                 : {
        3122           29893 :     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
        3123                 :
        3124                 :     /* A FOR node is binary, left is loop control and right is the body. */
        3125           29893 :     ParseNode *pn = BinaryNode::create(PNK_FOR, tc);
        3126           29893 :     if (!pn)
        3127               0 :         return NULL;
        3128                 :
        3129                 :     StmtInfo forStmt;
        3130           29893 :     PushStatement(tc, &forStmt, STMT_FOR_LOOP, -1);
        3131                 :
        3132           29893 :     pn->setOp(JSOP_ITER);
        3133           29893 :     pn->pn_iflags = 0;
        3134           29893 :     if (tokenStream.matchToken(TOK_NAME)) {
        3135            1152 :         if (tokenStream.currentToken().name() == context->runtime->atomState.eachAtom)
        3136            1152 :             pn->pn_iflags = JSITER_FOREACH;
        3137                 :         else
        3138               0 :             tokenStream.ungetToken();
        3139                 :     }
        3140                 :
        3141           29893 :     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
        3142                 :
        3143                 :     /*
        3144                 :      * True if we have 'for (var/let/const ...)', except in the oddball case
        3145                 :      * where 'let' begins a let-expression in 'for (let (...) ...)'.
        3146                 :      */
        3147           29893 :     bool forDecl = false;
        3148                 :
        3149                 :     /* Non-null when forDecl is true for a 'for (let ...)' statement. */
        3150           29893 :     StaticBlockObject *blockObj = NULL;
        3151                 :
        3152                 :     /* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
        3153                 :     ParseNode *pn1;
        3154                 :
        3155                 :     {
        3156           29893 :         TokenKind tt = tokenStream.peekToken(TSF_OPERAND);
        3157           29893 :         if (tt == TOK_SEMI) {
        3158             307 :             if (pn->pn_iflags & JSITER_FOREACH) {
        3159               0 :                 reportErrorNumber(pn, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP);
        3160               0 :                 return NULL;
        3161                 :             }
        3162                 :
        3163             307 :             pn1 = NULL;
        3164                 :         } else {
        3165                 :             /*
        3166                 :              * Set pn1 to a var list or an initializing expression.
        3167                 :              *
        3168                 :              * Set the TCF_IN_FOR_INIT flag during parsing of the first clause
        3169                 :              * of the for statement.  This flag will be used by the RelExpr
        3170                 :              * production; if it is set, then the 'in' keyword will not be
        3171                 :              * recognized as an operator, leaving it available to be parsed as
        3172                 :              * part of a for/in loop.
        3173                 :              *
        3174                 :              * A side effect of this restriction is that (unparenthesized)
        3175                 :              * expressions involving an 'in' operator are illegal in the init
        3176                 :              * clause of an ordinary for loop.
        3177                 :              */
        3178           29586 :             tc->flags |= TCF_IN_FOR_INIT;
        3179           29586 :             if (tt == TOK_VAR || tt == TOK_CONST) {
        3180           19056 :                 forDecl = true;
        3181           19056 :                 tokenStream.consumeKnownToken(tt);
        3182           19056 :                 pn1 = variables(tt == TOK_VAR ? PNK_VAR : PNK_CONST);
        3183                 :             }
        3184                 : #if JS_HAS_BLOCK_SCOPE
        3185           10530 :             else if (tt == TOK_LET) {
        3186            7227 :                 (void) tokenStream.getToken();
        3187            7227 :                 if (tokenStream.peekToken() == TOK_LP) {
        3188              81 :                     pn1 = letBlock(LetExpresion);
        3189                 :                 } else {
        3190            7146 :                     forDecl = true;
        3191            7146 :                     blockObj = StaticBlockObject::create(context);
        3192            7146 :                     if (!blockObj)
        3193               0 :                         return NULL;
        3194            7146 :                     pn1 = variables(PNK_LET, blockObj, DontHoistVars);
        3195                 :                 }
        3196                 :             }
        3197                 : #endif
        3198                 :             else {
        3199            3303 :                 pn1 = expr();
        3200                 :             }
        3201           29586 :             tc->flags &= ~TCF_IN_FOR_INIT;
        3202           29586 :             if (!pn1)
        3203              90 :                 return NULL;
        3204                 :         }
        3205                 :     }
        3206                 :
        3207           29803 :     JS_ASSERT_IF(forDecl, pn1->isArity(PN_LIST));
        3208           29803 :     JS_ASSERT(!!blockObj == (forDecl && pn1->isOp(JSOP_NOP)));
        3209                 :
        3210           29803 :     const TokenPos pos = tokenStream.currentToken().pos;
        3211                 :
        3212                 :     /* If non-null, the parent that should be returned instead of forHead. */
        3213           29803 :     ParseNode *forParent = NULL;
        3214                 :
        3215                 :     /*
        3216                 :      * We can be sure that it's a for/in loop if there's still an 'in'
        3217                 :      * keyword here, even if JavaScript recognizes 'in' as an operator,
        3218                 :      * as we've excluded 'in' from being parsed in RelExpr by setting
        3219                 :      * the TCF_IN_FOR_INIT flag in our TreeContext.
        3220                 :      */
        3221                 :     ParseNode *forHead;     /* initialized by both branches. */
        3222                 :     StmtInfo letStmt;       /* used if blockObj != NULL. */
        3223                 :     ParseNode *pn2, *pn3;   /* forHead->pn_kid1 and pn_kid2. */
        3224                 :     bool forOf;
        3225           29803 :     if (pn1 && matchInOrOf(&forOf)) {
        3226                 :         /*
        3227                 :          * Parse the rest of the for/in or for/of head.
        3228                 :          *
        3229                 :          * Here pn1 is everything to the left of 'in' or 'of'. At the end of
        3230                 :          * this block, pn1 is a decl or NULL, pn2 is the assignment target that
        3231                 :          * receives the enumeration value each iteration, and pn3 is the rhs of
        3232                 :          * 'in'.
        3233                 :          */
        3234            4582 :         forStmt.type = STMT_FOR_IN_LOOP;
        3235                 :
        3236                 :         /* Set pn_iflags and rule out invalid combinations. */
        3237            4582 :         if (forOf && pn->pn_iflags != 0) {
        3238              27 :             JS_ASSERT(pn->pn_iflags == JSITER_FOREACH);
        3239              27 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP);
        3240              27 :             return NULL;
        3241                 :         }
        3242            4555 :         pn->pn_iflags |= (forOf ? JSITER_FOR_OF : JSITER_ENUMERATE);
        3243                 :
        3244                 :         /* Check that the left side of the 'in' or 'of' is valid. */
        3245           12603 :         if (forDecl
        3246            3052 :             ? (pn1->pn_count > 1 || pn1->isOp(JSOP_DEFCONST)
        3247                 : #if JS_HAS_DESTRUCTURING
        3248            3052 :                || (versionNumber() == JSVERSION_1_7 &&
        3249               0 :                    pn->isOp(JSOP_ITER) &&
        3250               0 :                    !(pn->pn_iflags & JSITER_FOREACH) &&
        3251               0 :                    (pn1->pn_head->isKind(PNK_RC) ||
        3252               0 :                     (pn1->pn_head->isKind(PNK_RB) &&
        3253                 :                      pn1->pn_head->pn_count != 2) ||
        3254               0 :                     (pn1->pn_head->isKind(PNK_ASSIGN) &&
        3255               0 :                      (!pn1->pn_head->pn_left->isKind(PNK_RB) ||
        3256                 :                       pn1->pn_head->pn_left->pn_count != 2))))
        3257                 : #endif
        3258                 :               )
        3259            1503 :             : (!pn1->isKind(PNK_NAME) &&
        3260             117 :                !pn1->isKind(PNK_DOT) &&
        3261                 : #if JS_HAS_DESTRUCTURING
        3262              72 :                ((versionNumber() == JSVERSION_1_7 &&
        3263               0 :                  pn->isOp(JSOP_ITER) &&
        3264               0 :                  !(pn->pn_iflags & JSITER_FOREACH))
        3265               0 :                 ? (!pn1->isKind(PNK_RB) || pn1->pn_count != 2)
        3266             117 :                 : (!pn1->isKind(PNK_RB) && !pn1->isKind(PNK_RC))) &&
        3267                 : #endif
        3268              45 :                !pn1->isKind(PNK_LP) &&
        3269                 : #if JS_HAS_XML_SUPPORT
        3270              45 :                !pn1->isKind(PNK_XMLUNARY) &&
        3271                 : #endif
        3272              45 :                !pn1->isKind(PNK_LB)))
        3273                 :         {
        3274              27 :             reportErrorNumber(pn1, JSREPORT_ERROR, JSMSG_BAD_FOR_LEFTSIDE);
        3275              27 :             return NULL;
        3276                 :         }
        3277                 :
        3278                 :         /*
        3279                 :          * After the following if-else, pn2 will point to the name or
        3280                 :          * destructuring pattern on in's left. pn1 will point to the decl, if
        3281                 :          * any, else NULL. Note that the "declaration with initializer" case
        3282                 :          * rewrites the loop-head, moving the decl and setting pn1 to NULL.
        3283                 :          */
        3284            4528 :         pn2 = NULL;
        3285            4528 :         unsigned dflag = PND_ASSIGNED;
        3286            4528 :         if (forDecl) {
        3287                 :             /* Tell EmitVariables that pn1 is part of a for/in. */
        3288            3052 :             pn1->pn_xflags |= PNX_FORINVAR;
        3289                 :
        3290            3052 :             pn2 = pn1->pn_head;
        3291            6095 :             if ((pn2->isKind(PNK_NAME) && pn2->maybeExpr())
        3292                 : #if JS_HAS_DESTRUCTURING
        3293            3043 :                 || pn2->isKind(PNK_ASSIGN)
        3294                 : #endif
        3295                 :                 )
        3296                 :             {
        3297                 :                 /*
        3298                 :                  * Declaration with initializer.
        3299                 :                  *
        3300                 :                  * Rewrite 'for (<decl> x = i in o)' where <decl> is 'var' or
        3301                 :                  * 'const' to hoist the initializer or the entire decl out of
        3302                 :                  * the loop head.
        3303                 :                  */
        3304                 : #if JS_HAS_BLOCK_SCOPE
        3305              36 :                 if (blockObj) {
        3306               0 :                     reportErrorNumber(pn2, JSREPORT_ERROR, JSMSG_INVALID_FOR_IN_INIT);
        3307               0 :                     return NULL;
        3308                 :                 }
        3309                 : #endif /* JS_HAS_BLOCK_SCOPE */
        3310                 :
        3311              36 :                 ParseNode *pnseq = ListNode::create(PNK_SEQ, tc);
        3312              36 :                 if (!pnseq)
        3313               0 :                     return NULL;
        3314                 :
        3315              36 :                 dflag = PND_INITIALIZED;
        3316                 :
        3317                 :                 /*
        3318                 :                  * All of 'var x = i' is hoisted above 'for (x in o)',
        3319                 :                  * so clear PNX_FORINVAR.
        3320                 :                  *
        3321                 :                  * Request JSOP_POP here since the var is for a simple
        3322                 :                  * name (it is not a destructuring binding's left-hand
        3323                 :                  * side) and it has an initializer.
        3324                 :                  */
        3325              36 :                 pn1->pn_xflags &= ~PNX_FORINVAR;
        3326              36 :                 pn1->pn_xflags |= PNX_POPVAR;
        3327              36 :                 pnseq->initList(pn1);
        3328              36 :                 pn1 = NULL;
        3329                 :
        3330                 : #if JS_HAS_DESTRUCTURING
        3331              36 :                 if (pn2->isKind(PNK_ASSIGN)) {
        3332              27 :                     pn2 = pn2->pn_left;
        3333              27 :                     JS_ASSERT(pn2->isKind(PNK_RB) || pn2->isKind(PNK_RC) ||
        3334              27 :                               pn2->isKind(PNK_NAME));
        3335                 :                 }
        3336                 : #endif
        3337              36 :                 pnseq->append(pn);
        3338              36 :                 forParent = pnseq;
        3339                 :             }
        3340                 :         } else {
        3341                 :             /* Not a declaration. */
        3342            1476 :             JS_ASSERT(!blockObj);
        3343            1476 :             pn2 = pn1;
        3344            1476 :             pn1 = NULL;
        3345                 :
        3346            1476 :             if (!setAssignmentLhsOps(pn2, JSOP_NOP))
        3347               0 :                 return NULL;
        3348                 :         }
        3349                 :
        3350            4528 :         pn3 = expr();
        3351            4528 :         if (!pn3)
        3352               9 :             return NULL;
        3353                 :
        3354            4519 :         if (blockObj) {
        3355                 :             /*
        3356                 :              * Now that the pn3 has been parsed, push the let scope. To hold
        3357                 :              * the blockObj for the emitter, wrap the TOK_LEXICALSCOPE node
        3358                 :              * created by PushLetScope around the for's initializer. This also
        3359                 :              * serves to indicate the let-decl to the emitter.
        3360                 :              */
        3361            1368 :             ParseNode *block = PushLetScope(context, tc, *blockObj, &letStmt);
        3362            1368 :             if (!block)
        3363               0 :                 return NULL;
        3364            1368 :             letStmt.flags |= SIF_FOR_BLOCK;
        3365            1368 :             block->pn_expr = pn1;
        3366            1368 :             pn1 = block;
        3367                 :         }
        3368                 :
        3369            4519 :         if (forDecl) {
        3370                 :             /*
        3371                 :              * pn2 is part of a declaration. Make a copy that can be passed to
        3372                 :              * EmitAssignment. Take care to do this after PushLetScope has
        3373                 :              * Define's the new binding since this pn2->isDefn() which tells
        3374                 :              * CloneLeftHandSide to make the new pn2 a use.
        3375                 :              */
        3376            3052 :             pn2 = CloneLeftHandSide(pn2, tc);
        3377            3052 :             if (!pn2)
        3378               0 :                 return NULL;
        3379                 :         }
        3380                 :
        3381            4519 :         switch (pn2->getKind()) {
        3382                 :           case PNK_NAME:
        3383                 :             /* Beware 'for (arguments in ...)' with or without a 'var'. */
        3384            4258 :             NoteLValue(context, pn2, tc, dflag);
        3385            4258 :             break;
        3386                 :
        3387                 : #if JS_HAS_DESTRUCTURING
        3388                 :           case PNK_ASSIGN:
        3389               0 :             JS_NOT_REACHED("forStatement TOK_ASSIGN");
        3390                 :             break;
        3391                 :
        3392                 :           case PNK_RB:
        3393                 :           case PNK_RC:
        3394             198 :             if (versionNumber() == JSVERSION_1_7) {
        3395                 :                 /*
        3396                 :                  * Destructuring for-in requires [key, value] enumeration
        3397                 :                  * in JS1.7.
        3398                 :                  */
        3399               0 :                 JS_ASSERT(pn->isOp(JSOP_ITER));
        3400               0 :                 if (!(pn->pn_iflags & JSITER_FOREACH))
        3401               0 :                     pn->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
        3402                 :             }
        3403             198 :             break;
        3404                 : #endif
        3405                 :
        3406                 :           default:;
        3407                 :         }
        3408                 :
        3409            4519 :         forHead = TernaryNode::create(PNK_FORIN, tc);
        3410            4519 :         if (!forHead)
        3411               0 :             return NULL;
        3412                 :     } else {
        3413           25221 :         if (blockObj) {
        3414                 :             /*
        3415                 :              * Desugar 'for (let A; B; C) D' into 'let (A) { for (; B; C) D }'
        3416                 :              * to induce the correct scoping for A.
        3417                 :              */
        3418            5688 :             ParseNode *block = PushLetScope(context, tc, *blockObj, &letStmt);
        3419            5688 :             if (!block)
        3420               0 :                 return NULL;
        3421            5688 :             letStmt.flags |= SIF_FOR_BLOCK;
        3422                 :
        3423            5688 :             ParseNode *let = new_<BinaryNode>(PNK_LET, JSOP_NOP, pos, pn1, block);
        3424            5688 :             if (!let)
        3425               0 :                 return NULL;
        3426                 :
        3427            5688 :             pn1 = NULL;
        3428            5688 :             block->pn_expr = pn;
        3429            5688 :             forParent = let;
        3430                 :         }
        3431                 :
        3432           25221 :         if (pn->pn_iflags & JSITER_FOREACH) {
        3433               0 :             reportErrorNumber(pn, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP);
        3434               0 :             return NULL;
        3435                 :         }
        3436           25221 :         pn->setOp(JSOP_NOP);
        3437                 :
        3438                 :         /* Parse the loop condition or null into pn2. */
        3439           25221 :         MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
        3440           25221 :         if (tokenStream.peekToken(TSF_OPERAND) == TOK_SEMI) {
        3441             514 :             pn2 = NULL;
        3442                 :         } else {
        3443           24707 :             pn2 = expr();
        3444           24707 :             if (!pn2)
        3445               0 :                 return NULL;
        3446                 :         }
        3447                 :
        3448                 :         /* Parse the update expression or null into pn3. */
        3449           25221 :         MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND);
        3450           25221 :         if (tokenStream.peekToken(TSF_OPERAND) == TOK_RP) {
        3451             631 :             pn3 = NULL;
        3452                 :         } else {
        3453           24590 :             pn3 = expr();
        3454           24590 :             if (!pn3)
        3455               0 :                 return NULL;
        3456                 :         }
        3457                 :
        3458           25221 :         forHead = TernaryNode::create(PNK_FORHEAD, tc);
        3459           25221 :         if (!forHead)
        3460               0 :             return NULL;
        3461                 :     }
        3462                 :
        3463           29740 :     forHead->pn_pos = pos;
        3464           29740 :     forHead->setOp(JSOP_NOP);
        3465           29740 :     forHead->pn_kid1 = pn1;
        3466           29740 :     forHead->pn_kid2 = pn2;
        3467           29740 :     forHead->pn_kid3 = pn3;
        3468           29740 :     pn->pn_left = forHead;
        3469                 :
        3470           29740 :     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
        3471                 :
        3472                 :     /* Parse the loop body. */
        3473           29686 :     ParseNode *body = statement();
        3474           29686 :     if (!body)
        3475               9 :         return NULL;
        3476                 :
        3477                 :     /* Record the absolute line number for source note emission. */
        3478           29677 :     pn->pn_pos.end = body->pn_pos.end;
        3479           29677 :     pn->pn_right = body;
        3480                 :
        3481           29677 :     if (forParent) {
        3482            5724 :         forParent->pn_pos.begin = pn->pn_pos.begin;
        3483            5724 :         forParent->pn_pos.end = pn->pn_pos.end;
        3484                 :     }
        3485                 :
        3486                 : #if JS_HAS_BLOCK_SCOPE
        3487           29677 :     if (blockObj)
        3488            7047 :         PopStatement(tc);
        3489                 : #endif
        3490           29677 :     PopStatement(tc);
        3491           29677 :     return forParent ? forParent : pn;
        3492                 : }
        3493                 :
        3494                 : ParseNode *
        3495           87255 : Parser::tryStatement()
        3496                 : {
        3497           87255 :     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_TRY));
        3498                 :
        3499                 :     /*
        3500                 :      * try nodes are ternary.
        3501                 :      * kid1 is the try statement
        3502                 :      * kid2 is the catch node list or null
        3503                 :      * kid3 is the finally statement
        3504                 :      *
        3505                 :      * catch nodes are ternary.
        3506                 :      * kid1 is the lvalue (TOK_NAME, TOK_LB, or TOK_LC)
        3507                 :      * kid2 is the catch guard or null if no guard
        3508                 :      * kid3 is the catch block
        3509                 :      *
        3510                 :      * catch lvalue nodes are either:
        3511                 :      *   TOK_NAME for a single identifier
        3512                 :      *   TOK_RB or TOK_RC for a destructuring left-hand side
        3513                 :      *
        3514                 :      * finally nodes are TOK_LC statement lists.
        3515                 :      */
        3516           87255 :     ParseNode *pn = TernaryNode::create(PNK_TRY, tc);
        3517           87255 :     if (!pn)
        3518               0 :         return NULL;
        3519           87255 :     pn->setOp(JSOP_NOP);
        3520                 :
        3521           87255 :     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
        3522                 :     StmtInfo stmtInfo;
        3523           87255 :     if (!PushBlocklikeStatement(&stmtInfo, STMT_TRY, tc))
        3524               0 :         return NULL;
        3525           87255 :     pn->pn_kid1 = statements();
        3526           87255 :     if (!pn->pn_kid1)
        3527               0 :         return NULL;
        3528           87255 :     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_TRY);
        3529           87255 :     PopStatement(tc);
        3530                 :
        3531                 :     ParseNode *lastCatch;
        3532           87255 :     ParseNode *catchList = NULL;
        3533           87255 :     TokenKind tt = tokenStream.getToken();
        3534           87255 :     if (tt == TOK_CATCH) {
        3535           87120 :         catchList = ListNode::create(PNK_CATCHLIST, tc);
        3536           87120 :         if (!catchList)
        3537               0 :             return NULL;
        3538           87120 :         catchList->makeEmpty();
        3539           87120 :         lastCatch = NULL;
        3540                 :
        3541           87120 :         do {
        3542                 :             ParseNode *pnblock;
        3543           87120 :             BindData data;
        3544                 :
        3545                 :             /* Check for another catch after unconditional catch. */
        3546           87120 :             if (lastCatch && !lastCatch->pn_kid2) {
        3547               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_CATCH_AFTER_GENERAL);
        3548               0 :                 return NULL;
        3549                 :             }
        3550                 :
        3551                 :             /*
        3552                 :              * Create a lexical scope node around the whole catch clause,
        3553                 :              * including the head.
        3554                 :              */
        3555           87120 :             pnblock = PushLexicalScope(context, tc, &stmtInfo);
        3556           87120 :             if (!pnblock)
        3557               0 :                 return NULL;
        3558           87120 :             stmtInfo.type = STMT_CATCH;
        3559                 :
        3560                 :             /*
        3561                 :              * Legal catch forms are:
        3562                 :              *   catch (lhs)
        3563                 :              *   catch (lhs if <boolean_expression>)
        3564                 :              * where lhs is a name or a destructuring left-hand side.
        3565                 :              * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD)
        3566                 :              */
        3567           87120 :             ParseNode *pn2 = TernaryNode::create(PNK_CATCH, tc);
        3568           87120 :             if (!pn2)
        3569               0 :                 return NULL;
        3570           87120 :             pnblock->pn_expr = pn2;
        3571           87120 :             MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);
        3572                 :
        3573                 :             /*
        3574                 :              * Contrary to ECMA Ed. 3, the catch variable is lexically
        3575                 :              * scoped, not a property of a new Object instance.  This is
        3576                 :              * an intentional change that anticipates ECMA Ed. 4.
        3577                 :              */
        3578           87120 :             data.initLet(HoistVars, *tc->blockChain, JSMSG_TOO_MANY_CATCH_VARS);
        3579           87120 :             JS_ASSERT(data.let.blockObj && data.let.blockObj == pnblock->pn_objbox->object);
        3580                 :
        3581           87120 :             tt = tokenStream.getToken();
        3582                 :             ParseNode *pn3;
        3583           87120 :             switch (tt) {
        3584                 : #if JS_HAS_DESTRUCTURING
        3585                 :               case TOK_LB:
        3586                 :               case TOK_LC:
        3587               0 :                 pn3 = destructuringExpr(&data, tt);
        3588               0 :                 if (!pn3)
        3589               0 :                     return NULL;
        3590               0 :                 break;
        3591                 : #endif
        3592                 :
        3593                 :               case TOK_NAME:
        3594                 :               {
        3595           87120 :                 JSAtom *label = tokenStream.currentToken().name();
        3596           87120 :                 pn3 = NewBindingNode(label, tc);
        3597           87120 :                 if (!pn3)
        3598               0 :                     return NULL;
        3599           87120 :                 data.pn = pn3;
        3600           87120 :                 if (!data.binder(context, &data, label, tc))
        3601               0 :                     return NULL;
        3602           87120 :                 break;
        3603                 :               }
        3604                 :
        3605                 :               default:
        3606               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_CATCH_IDENTIFIER);
        3607               0 :                 return NULL;
        3608                 :             }
        3609                 :
        3610           87120 :             pn2->pn_kid1 = pn3;
        3611                 : #if JS_HAS_CATCH_GUARD
        3612                 :             /*
        3613                 :              * We use 'catch (x if x === 5)' (not 'catch (x : x === 5)')
        3614                 :              * to avoid conflicting with the JS2/ECMAv4 type annotation
        3615                 :              * catchguard syntax.
        3616                 :              */
        3617           87120 :             if (tokenStream.matchToken(TOK_IF)) {
        3618              45 :                 pn2->pn_kid2 = expr();
        3619              45 :                 if (!pn2->pn_kid2)
        3620               0 :                     return NULL;
        3621                 :             }
        3622                 : #endif
        3623           87120 :             MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH);
        3624                 :
        3625           87120 :             MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);
        3626           87120 :             pn2->pn_kid3 = statements();
        3627           87120 :             if (!pn2->pn_kid3)
        3628               0 :                 return NULL;
        3629           87120 :             MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_CATCH);
        3630           87120 :             PopStatement(tc);
        3631                 :
        3632           87120 :             catchList->append(pnblock);
        3633           87120 :             lastCatch = pn2;
        3634           87120 :             tt = tokenStream.getToken(TSF_OPERAND);
        3635                 :         } while (tt == TOK_CATCH);
        3636                 :     }
        3637           87255 :     pn->pn_kid2 = catchList;
        3638                 :
        3639           87255 :     if (tt == TOK_FINALLY) {
        3640             180 :         MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
        3641             180 :         if (!PushBlocklikeStatement(&stmtInfo, STMT_FINALLY, tc))
        3642               0 :             return NULL;
        3643             180 :         pn->pn_kid3 = statements();
        3644             180 :         if (!pn->pn_kid3)
        3645               0 :             return NULL;
        3646             180 :         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY);
        3647             180 :         PopStatement(tc);
        3648                 :     } else {
        3649           87075 :         tokenStream.ungetToken();
        3650                 :     }
        3651           87255 :     if (!catchList && !pn->pn_kid3) {
        3652               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_CATCH_OR_FINALLY);
        3653               0 :         return NULL;
        3654                 :     }
        3655           87255 :     return pn;
        3656                 : }
        3657                 :
        3658                 : ParseNode *
        3659             648 : Parser::withStatement()
        3660                 : {
        3661             648 :     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_WITH));
        3662                 :
        3663                 :     /*
        3664                 :      * In most cases, we want the constructs forbidden in strict mode
        3665                 :      * code to be a subset of those that JSOPTION_STRICT warns about, and
        3666                 :      * we should use ReportStrictModeError.  However, 'with' is the sole
        3667                 :      * instance of a construct that is forbidden in strict mode code, but
        3668                 :      * doesn't even merit a warning under JSOPTION_STRICT.  See
        3669                 :      * https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1.
        3670                 :      */
        3671             648 :     if (tc->flags & TCF_STRICT_MODE_CODE) {
        3672               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_STRICT_CODE_WITH);
        3673               0 :         return NULL;
        3674                 :     }
        3675                 :
        3676             648 :     ParseNode *pn = BinaryNode::create(PNK_WITH, tc);
        3677             648 :     if (!pn)
        3678               0 :         return NULL;
        3679             648 :     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH);
        3680             648 :     ParseNode *pn2 = parenExpr();
        3681             648 :     if (!pn2)
        3682               0 :         return NULL;
        3683             648 :     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH);
        3684             648 :     pn->pn_left = pn2;
        3685                 :
        3686             648 :     ParseNode *oldWith = tc->innermostWith;
        3687             648 :     tc->innermostWith = pn;
        3688                 :
        3689                 :     StmtInfo stmtInfo;
        3690             648 :     PushStatement(tc, &stmtInfo, STMT_WITH, -1);
        3691             648 :     pn2 = statement();
        3692             648 :     if (!pn2)
        3693               0 :         return NULL;
        3694             648 :     PopStatement(tc);
        3695                 :
        3696             648 :     pn->pn_pos.end = pn2->pn_pos.end;
        3697             648 :     pn->pn_right = pn2;
        3698             648 :     tc->flags |= TCF_FUN_HEAVYWEIGHT;
        3699             648 :     tc->innermostWith = oldWith;
        3700                 :
        3701                 :     /*
        3702                 :      * Make sure to deoptimize lexical dependencies inside the |with|
        3703                 :      * to safely optimize binding globals (see bug 561923).
        3704                 :      */
        3705            1566 :     for (AtomDefnRange r = tc->lexdeps->all(); !r.empty(); r.popFront()) {
        3706             918 :         Definition *defn = r.front().value();
        3707             918 :         Definition *lexdep = defn->resolve();
        3708             918 :         DeoptimizeUsesWithin(lexdep, pn->pn_pos);
        3709                 :     }
        3710                 :
        3711             648 :     return pn;
        3712                 : }
        3713                 :
        3714                 : #if JS_HAS_BLOCK_SCOPE
        3715                 : ParseNode *
        3716            4716 : Parser::letStatement()
        3717                 : {
        3718                 :     ParseNode *pn;
        3719                 :     do {
        3720                 :         /* Check for a let statement or let expression. */
        3721            4716 :         if (tokenStream.peekToken() == TOK_LP) {
        3722            2385 :             pn = letBlock(LetStatement);
        3723            2385 :             if (!pn)
        3724             144 :                 return NULL;
        3725                 :
        3726            2241 :             JS_ASSERT(pn->isKind(PNK_LET) || pn->isKind(PNK_SEMI));
        3727            2241 :             if (pn->isKind(PNK_LET) && pn->pn_expr->getOp() == JSOP_LEAVEBLOCK)
        3728            2007 :                 return pn;
        3729                 :
        3730                 :             /* Let expressions require automatic semicolon insertion. */
        3731             234 :             JS_ASSERT(pn->isKind(PNK_SEMI) || pn->isOp(JSOP_NOP));
        3732             234 :             break;
        3733                 :         }
        3734                 :
        3735                 :         /*
        3736                 :          * This is a let declaration. We must be directly under a block per the
        3737                 :          * proposed ES4 specs, but not an implicit block created due to
        3738                 :          * 'for (let ...)'. If we pass this error test, make the enclosing
        3739                 :          * StmtInfo be our scope. Further let declarations in this block will
        3740                 :          * find this scope statement and use the same block object.
        3741                 :          *
        3742                 :          * If we are the first let declaration in this block (i.e., when the
        3743                 :          * enclosing maybe-scope StmtInfo isn't yet a scope statement) then
        3744                 :          * we also need to set tc->blockNode to be our TOK_LEXICALSCOPE.
        3745                 :          */
        3746            2331 :         StmtInfo *stmt = tc->topStmt;
        3747            6921 :         if (stmt &&
        3748            4590 :             (!STMT_MAYBE_SCOPE(stmt) || (stmt->flags & SIF_FOR_BLOCK))) {
        3749               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_LET_DECL_NOT_IN_BLOCK);
        3750               0 :             return NULL;
        3751                 :         }
        3752                 :
        3753            2331 :         if (stmt && (stmt->flags & SIF_SCOPE)) {
        3754             270 :             JS_ASSERT(tc->blockChain == stmt->blockObj);
        3755                 :         } else {
        3756            2061 :             if (!stmt || (stmt->flags & SIF_BODY_BLOCK)) {
        3757                 :                 /*
        3758                 :                  * ES4 specifies that let at top level and at body-block scope
        3759                 :                  * does not shadow var, so convert back to var.
        3760                 :                  */
        3761             153 :                 pn = variables(PNK_VAR);
        3762             153 :                 if (!pn)
        3763               0 :                     return NULL;
        3764             153 :                 pn->pn_xflags |= PNX_POPVAR;
        3765             153 :                 break;
        3766                 :             }
        3767                 :
        3768                 :             /*
        3769                 :              * Some obvious assertions here, but they may help clarify the
        3770                 :              * situation. This stmt is not yet a scope, so it must not be a
        3771                 :              * catch block (catch is a lexical scope by definition).
        3772                 :              */
        3773            1908 :             JS_ASSERT(!(stmt->flags & SIF_SCOPE));
        3774            1908 :             JS_ASSERT(stmt != tc->topScopeStmt);
        3775               0 :             JS_ASSERT(stmt->type == STMT_BLOCK ||
        3776                 :                       stmt->type == STMT_SWITCH ||
        3777                 :                       stmt->type == STMT_TRY ||
        3778            1908 :                       stmt->type == STMT_FINALLY);
        3779            1908 :             JS_ASSERT(!stmt->downScope);
        3780                 :
        3781                 :             /* Convert the block statement into a scope statement. */
        3782            1908 :             StaticBlockObject *blockObj = StaticBlockObject::create(tc->parser->context);
        3783            1908 :             if (!blockObj)
        3784               0 :                 return NULL;
        3785                 :
        3786            1908 :             ObjectBox *blockbox = tc->parser->newObjectBox(blockObj);
        3787            1908 :             if (!blockbox)
        3788               0 :                 return NULL;
        3789                 :
        3790                 :             /*
        3791                 :              * Insert stmt on the tc->topScopeStmt/stmtInfo.downScope linked
        3792                 :              * list stack, if it isn't already there.  If it is there, but it
        3793                 :              * lacks the SIF_SCOPE flag, it must be a try, catch, or finally
        3794                 :              * block.
        3795                 :              */
        3796            1908 :             stmt->flags |= SIF_SCOPE;
        3797            1908 :             stmt->downScope = tc->topScopeStmt;
        3798            1908 :             tc->topScopeStmt = stmt;
        3799                 :
        3800            1908 :             blockObj->setEnclosingBlock(tc->blockChain);
        3801            1908 :             tc->blockChain = blockObj;
        3802            1908 :             stmt->blockObj = blockObj;
        3803                 :
        3804                 : #ifdef DEBUG
        3805            1908 :             ParseNode *tmp = tc->blockNode;
        3806            1908 :             JS_ASSERT(!tmp || !tmp->isKind(PNK_LEXICALSCOPE));
        3807                 : #endif
        3808                 :
        3809                 :             /* Create a new lexical scope node for these statements. */
        3810            1908 :             ParseNode *pn1 = LexicalScopeNode::create(PNK_LEXICALSCOPE, tc);
        3811            1908 :             if (!pn1)
        3812               0 :                 return NULL;
        3813                 :
        3814            1908 :             pn1->setOp(JSOP_LEAVEBLOCK);
        3815            1908 :             pn1->pn_pos = tc->blockNode->pn_pos;
        3816            1908 :             pn1->pn_objbox = blockbox;
        3817            1908 :             pn1->pn_expr = tc->blockNode;
        3818            1908 :             pn1->pn_blockid = tc->blockNode->pn_blockid;
        3819            1908 :             tc->blockNode = pn1;
        3820                 :         }
        3821                 :
        3822            2178 :         pn = variables(PNK_LET, tc->blockChain, HoistVars);
        3823            2178 :         if (!pn)
        3824              27 :             return NULL;
        3825            2151 :         pn->pn_xflags = PNX_POPVAR;
        3826                 :     } while (0);
        3827                 :
        3828                 :     /* Check termination of this primitive statement. */
        3829            2538 :     return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL;
        3830                 : }
        3831                 : #endif
        3832                 :
        3833                 : ParseNode *
        3834          557492 : Parser::expressionStatement()
        3835                 : {
        3836          557492 :     tokenStream.ungetToken();
        3837          557492 :     ParseNode *pn2 = expr();
        3838          557492 :     if (!pn2)
        3839             193 :         return NULL;
        3840                 :
        3841          557299 :     if (tokenStream.peekToken() == TOK_COLON) {
        3842             207 :         if (!pn2->isKind(PNK_NAME)) {
        3843               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_LABEL);
        3844               0 :             return NULL;
        3845                 :         }
        3846             207 :         JSAtom *label = pn2->pn_atom;
        3847             684 :         for (StmtInfo *stmt = tc->topStmt; stmt; stmt = stmt->down) {
        3848             477 :             if (stmt->type == STMT_LABEL && stmt->label == label) {
        3849               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_DUPLICATE_LABEL);
        3850               0 :                 return NULL;
        3851                 :             }
        3852                 :         }
        3853             207 :         ForgetUse(pn2);
        3854                 :
        3855             207 :         (void) tokenStream.getToken();
        3856                 :
        3857                 :         /* Push a label struct and parse the statement. */
        3858                 :         StmtInfo stmtInfo;
        3859             207 :         PushStatement(tc, &stmtInfo, STMT_LABEL, -1);
        3860             207 :         stmtInfo.label = label;
        3861             207 :         ParseNode *pn = statement();
        3862             207 :         if (!pn)
        3863               0 :             return NULL;
        3864                 :
        3865                 :         /* Normalize empty statement to empty block for the decompiler. */
        3866             207 :         if (pn->isKind(PNK_SEMI) && !pn->pn_kid) {
        3867               0 :             pn->setKind(PNK_STATEMENTLIST);
        3868               0 :             pn->setArity(PN_LIST);
        3869               0 :             pn->makeEmpty();
        3870                 :         }
        3871                 :
        3872                 :         /* Pop the label, set pn_expr, and return early. */
        3873             207 :         PopStatement(tc);
        3874             207 :         pn2->setKind(PNK_COLON);
        3875             207 :         pn2->pn_pos.end = pn->pn_pos.end;
        3876             207 :         pn2->pn_expr = pn;
        3877             207 :         return pn2;
        3878                 :     }
        3879                 :
        3880          557092 :     ParseNode *pn = UnaryNode::create(PNK_SEMI, tc);
        3881          557092 :     if (!pn)
        3882               0 :         return NULL;
        3883          557092 :     pn->pn_pos = pn2->pn_pos;
        3884          557092 :     pn->pn_kid = pn2;
        3885                 :
        3886          557092 :     if (pn2->getKind() == PNK_ASSIGN) {
        3887                 :         /*
        3888                 :          * Keep track of all apparent methods created by assignments such
        3889                 :          * as this.foo = function (...) {...} in a function that could end
        3890                 :          * up a constructor function. See Parser::setFunctionKinds.
        3891                 :          */
        3892          368649 :         JS_ASSERT(pn2->isOp(JSOP_NOP));
        3893          415505 :         if (tc->funbox &&
        3894           35075 :             pn2->pn_left->isOp(JSOP_SETPROP) &&
        3895            8235 :             pn2->pn_left->pn_expr->isKind(PNK_THIS) &&
        3896            3546 :             pn2->pn_right->isOp(JSOP_LAMBDA))
        3897                 :         {
        3898             189 :             JS_ASSERT(!pn2->isDefn());
        3899             189 :             JS_ASSERT(!pn2->isUsed());
        3900             189 :             pn2->pn_right->pn_link = tc->funbox->methods;
        3901             189 :             tc->funbox->methods = pn2->pn_right;
        3902                 :         }
        3903                 :     }
        3904                 :
        3905                 :     /* Check termination of this primitive statement. */
        3906          557092 :     return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL;
        3907                 : }
        3908                 :
        3909                 : ParseNode *
        3910         1085242 : Parser::statement()
        3911                 : {
        3912                 :     ParseNode *pn;
        3913                 :
        3914         1085242 :     JS_CHECK_RECURSION(context, return NULL);
        3915                 :
        3916         1085242 :     switch (tokenStream.getToken(TSF_OPERAND)) {
        3917                 :       case TOK_FUNCTION:
        3918                 :       {
        3919                 : #if JS_HAS_XML_SUPPORT
        3920           28648 :         if (!tc->inStrictMode()) {
        3921           28468 :             TokenKind tt = tokenStream.peekToken(TSF_KEYWORD_IS_NAME);
        3922           28468 :             if (tt == TOK_DBLCOLON)
        3923              18 :                 return expressionStatement();
        3924                 :         }
        3925                 : #endif
        3926           28630 :         return functionStmt();
        3927                 :       }
        3928                 :
        3929                 :       case TOK_IF:
        3930                 :       {
        3931                 :         /* An IF node has three kids: condition, then, and optional else. */
        3932           93371 :         pn = TernaryNode::create(PNK_IF, tc);
        3933           93371 :         if (!pn)
        3934               0 :             return NULL;
        3935           93371 :         ParseNode *pn1 = condition();
        3936           93371 :         if (!pn1)
        3937               0 :             return NULL;
        3938                 :
        3939                 :         StmtInfo stmtInfo;
        3940           93371 :         PushStatement(tc, &stmtInfo, STMT_IF, -1);
        3941           93371 :         ParseNode *pn2 = statement();
        3942           93371 :         if (!pn2)
        3943              36 :             return NULL;
        3944                 :
        3945           99619 :         if (pn2->isKind(PNK_SEMI) &&
        3946            6284 :             !pn2->pn_kid &&
        3947               0 :             !reportErrorNumber(NULL, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_EMPTY_CONSEQUENT))
        3948                 :         {
        3949               0 :             return NULL;
        3950                 :         }
        3951                 :
        3952                 :         ParseNode *pn3;
        3953           93335 :         if (tokenStream.matchToken(TOK_ELSE, TSF_OPERAND)) {
        3954            3304 :             stmtInfo.type = STMT_ELSE;
        3955            3304 :             pn3 = statement();
        3956            3304 :             if (!pn3)
        3957               0 :                 return NULL;
        3958            3304 :             pn->pn_pos.end = pn3->pn_pos.end;
        3959                 :         } else {
        3960           90031 :             pn3 = NULL;
        3961           90031 :             pn->pn_pos.end = pn2->pn_pos.end;
        3962                 :         }
        3963           93335 :         PopStatement(tc);
        3964           93335 :         pn->pn_kid1 = pn1;
        3965           93335 :         pn->pn_kid2 = pn2;
        3966           93335 :         pn->pn_kid3 = pn3;
        3967           93335 :         return pn;
        3968                 :       }
        3969                 :
        3970                 :       case TOK_SWITCH:
        3971             918 :         return switchStatement();
        3972                 :
        3973                 :       case TOK_WHILE:
        3974                 :       {
        3975            2127 :         pn = BinaryNode::create(PNK_WHILE, tc);
        3976            2127 :         if (!pn)
        3977               0 :             return NULL;
        3978                 :         StmtInfo stmtInfo;
        3979            2127 :         PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1);
        3980            2127 :         ParseNode *pn2 = condition();
        3981            2127 :         if (!pn2)
        3982               0 :             return NULL;
        3983            2127 :         pn->pn_left = pn2;
        3984            2127 :         ParseNode *pn3 = statement();
        3985            2127 :         if (!pn3)
        3986               0 :             return NULL;
        3987            2127 :         PopStatement(tc);
        3988            2127 :         pn->pn_pos.end = pn3->pn_pos.end;
        3989            2127 :         pn->pn_right = pn3;
        3990            2127 :         return pn;
        3991                 :       }
        3992                 :
        3993                 :       case TOK_DO:
        3994                 :       {
        3995             189 :         pn = BinaryNode::create(PNK_DOWHILE, tc);
        3996             189 :         if (!pn)
        3997               0 :             return NULL;
        3998                 :         StmtInfo stmtInfo;
        3999             189 :         PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1);
        4000             189 :         ParseNode *pn2 = statement();
        4001             189 :         if (!pn2)
        4002               0 :             return NULL;
        4003             189 :         pn->pn_left = pn2;
        4004             189 :         MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO);
        4005             189 :         ParseNode *pn3 = condition();
        4006             189 :         if (!pn3)
        4007               0 :             return NULL;
        4008             189 :         PopStatement(tc);
        4009             189 :         pn->pn_pos.end = pn3->pn_pos.end;
        4010             189 :         pn->pn_right = pn3;
        4011             189 :         if (versionNumber() != JSVERSION_ECMA_3) {
        4012                 :             /*
        4013                 :              * All legacy and extended versions must do automatic semicolon
        4014                 :              * insertion after do-while.  See the testcase and discussion in
        4015                 :              * http://bugzilla.mozilla.org/show_bug.cgi?id=238945.
        4016                 :              */
        4017             189 :             (void) tokenStream.matchToken(TOK_SEMI);
        4018             189 :             return pn;
        4019                 :         }
        4020               0 :         break;
        4021                 :       }
        4022                 :
        4023                 :       case TOK_FOR:
        4024           29893 :         return forStatement();
        4025                 :
        4026                 :       case TOK_TRY:
        4027           87255 :         return tryStatement();
        4028                 :
        4029                 :       case TOK_THROW:
        4030                 :       {
        4031            2887 :         pn = UnaryNode::create(PNK_THROW, tc);
        4032            2887 :         if (!pn)
        4033               0 :             return NULL;
        4034                 :
        4035                 :         /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */
        4036            2887 :         TokenKind tt = tokenStream.peekTokenSameLine(TSF_OPERAND);
        4037            2887 :         if (tt == TOK_ERROR)
        4038               0 :             return NULL;
        4039            2887 :         if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) {
        4040               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
        4041               0 :             return NULL;
        4042                 :         }
        4043                 :
        4044            2887 :         ParseNode *pn2 = expr();
        4045            2887 :         if (!pn2)
        4046               0 :             return NULL;
        4047            2887 :         pn->pn_pos.end = pn2->pn_pos.end;
        4048            2887 :         pn->setOp(JSOP_THROW);
        4049            2887 :         pn->pn_kid = pn2;
        4050            2887 :         break;
        4051                 :       }
        4052                 :
        4053                 :       /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */
        4054                 :       case TOK_CATCH:
        4055               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_CATCH_WITHOUT_TRY);
        4056               0 :         return NULL;
        4057                 :
        4058                 :       case TOK_FINALLY:
        4059               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_FINALLY_WITHOUT_TRY);
        4060               0 :         return NULL;
        4061                 :
        4062                 :       case TOK_BREAK:
        4063                 :       {
        4064            1728 :         TokenPtr begin = tokenStream.currentToken().pos.begin;
        4065                 :         PropertyName *label;
        4066            1728 :         if (!MatchLabel(context, &tokenStream, &label))
        4067               0 :             return NULL;
        4068            1728 :         TokenPtr end = tokenStream.currentToken().pos.end;
        4069            1728 :         pn = new_<BreakStatement>(label, begin, end);
        4070            1728 :         if (!pn)
        4071               0 :             return NULL;
        4072            1728 :         StmtInfo *stmt = tc->topStmt;
        4073            1728 :         if (label) {
        4074             522 :             for (; ; stmt = stmt->down) {
        4075             630 :                 if (!stmt) {
        4076               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_LABEL_NOT_FOUND);
        4077               0 :                     return NULL;
        4078                 :                 }
        4079             630 :                 if (stmt->type == STMT_LABEL && stmt->label == label)
        4080                 :                     break;
        4081                 :             }
        4082                 :         } else {
        4083            1287 :             for (; ; stmt = stmt->down) {
        4084            2907 :                 if (!stmt) {
        4085               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_TOUGH_BREAK);
        4086               0 :                     return NULL;
        4087                 :                 }
        4088            2907 :                 if (STMT_IS_LOOP(stmt) || stmt->type == STMT_SWITCH)
        4089            1620 :                     break;
        4090                 :             }
        4091                 :         }
        4092            1728 :         break;
        4093                 :       }
        4094                 :
        4095                 :       case TOK_CONTINUE:
        4096                 :       {
        4097             153 :         TokenPtr begin = tokenStream.currentToken().pos.begin;
        4098                 :         PropertyName *label;
        4099             153 :         if (!MatchLabel(context, &tokenStream, &label))
        4100               0 :             return NULL;
        4101             153 :         TokenPtr end = tokenStream.currentToken().pos.begin;
        4102             153 :         pn = new_<ContinueStatement>(label, begin, end);
        4103             153 :         if (!pn)
        4104               0 :             return NULL;
        4105             153 :         StmtInfo *stmt = tc->topStmt;
        4106             153 :         if (label) {
        4107             189 :             for (StmtInfo *stmt2 = NULL; ; stmt = stmt->down) {
        4108             189 :                 if (!stmt) {
        4109               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_LABEL_NOT_FOUND);
        4110               0 :                     return NULL;
        4111                 :                 }
        4112             189 :                 if (stmt->type == STMT_LABEL) {
        4113              36 :                     if (stmt->label == label) {
        4114              36 :                         if (!stmt2 || !STMT_IS_LOOP(stmt2)) {
        4115               0 :                             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_CONTINUE);
        4116               0 :                             return NULL;
        4117                 :                         }
        4118                 :                         break;
        4119                 :                     }
        4120                 :                 } else {
        4121             153 :                     stmt2 = stmt;
        4122                 :                 }
        4123                 :             }
        4124                 :         } else {
        4125             252 :             for (; ; stmt = stmt->down) {
        4126             369 :                 if (!stmt) {
        4127               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_CONTINUE);
        4128               0 :                     return NULL;
        4129                 :                 }
        4130             369 :                 if (STMT_IS_LOOP(stmt))
        4131             117 :                     break;
        4132                 :             }
        4133                 :         }
        4134             153 :         break;
        4135                 :       }
        4136                 :
        4137                 :       case TOK_WITH:
        4138             648 :         return withStatement();
        4139                 :
        4140                 :       case TOK_VAR:
        4141           74956 :         pn = variables(PNK_VAR);
        4142           74956 :         if (!pn)
        4143               9 :             return NULL;
        4144                 :
        4145                 :         /* Tell js_EmitTree to generate a final POP. */
        4146           74947 :         pn->pn_xflags |= PNX_POPVAR;
        4147           74947 :         break;
        4148                 :
        4149                 :       case TOK_CONST:
        4150           56187 :         pn = variables(PNK_CONST);
        4151           56187 :         if (!pn)
        4152               0 :             return NULL;
        4153                 :
        4154                 :         /* Tell js_EmitTree to generate a final POP. */
        4155           56187 :         pn->pn_xflags |= PNX_POPVAR;
        4156           56187 :         break;
        4157                 :
        4158                 : #if JS_HAS_BLOCK_SCOPE
        4159                 :       case TOK_LET:
        4160            4716 :         return letStatement();
        4161                 : #endif /* JS_HAS_BLOCK_SCOPE */
        4162                 :
        4163                 :       case TOK_RETURN:
        4164           38556 :         pn = returnOrYield(false);
        4165           38556 :         if (!pn)
        4166               0 :             return NULL;
        4167           38556 :         break;
        4168                 :
        4169                 :       case TOK_LC:
        4170                 :       {
        4171                 :         unsigned oldflags;
        4172                 :
        4173           99537 :         oldflags = tc->flags;
        4174           99537 :         tc->flags = oldflags & ~TCF_HAS_FUNCTION_STMT;
        4175                 :         StmtInfo stmtInfo;
        4176           99537 :         if (!PushBlocklikeStatement(&stmtInfo, STMT_BLOCK, tc))
        4177               0 :             return NULL;
        4178           99537 :         pn = statements();
        4179           99537 :         if (!pn)
        4180              36 :             return NULL;
        4181                 :
        4182           99501 :         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_COMPOUND);
        4183           99501 :         PopStatement(tc);
        4184                 :
        4185                 :         /*
        4186                 :          * If we contain a function statement and our container is top-level
        4187                 :          * or another block, flag pn to preserve braces when decompiling.
        4188                 :          */
        4189           99753 :         if ((tc->flags & TCF_HAS_FUNCTION_STMT) &&
        4190             252 :             (!tc->topStmt || tc->topStmt->type == STMT_BLOCK)) {
        4191              99 :             pn->pn_xflags |= PNX_NEEDBRACES;
        4192                 :         }
        4193           99501 :         tc->flags = oldflags | (tc->flags & (TCF_FUN_FLAGS | TCF_RETURN_FLAGS));
        4194           99501 :         return pn;
        4195                 :       }
        4196                 :
        4197                 :       case TOK_SEMI:
        4198            1656 :         pn = UnaryNode::create(PNK_SEMI, tc);
        4199            1656 :         if (!pn)
        4200               0 :             return NULL;
        4201            1656 :         return pn;
        4202                 :
        4203                 :       case TOK_DEBUGGER:
        4204            4334 :         pn = tc->parser->new_<DebuggerStatement>(tokenStream.currentToken().pos);
        4205            4334 :         if (!pn)
        4206               0 :             return NULL;
        4207            4334 :         tc->flags |= TCF_FUN_HEAVYWEIGHT;
        4208            4334 :         break;
        4209                 :
        4210                 : #if JS_HAS_XML_SUPPORT
        4211                 :       case TOK_DEFAULT:
        4212                 :       {
        4213               9 :         if (tc->inStrictMode())
        4214               0 :             return expressionStatement();
        4215                 :
        4216               9 :         pn = UnaryNode::create(PNK_DEFXMLNS, tc);
        4217               9 :         if (!pn)
        4218               0 :             return NULL;
        4219              45 :         if (!tokenStream.matchToken(TOK_NAME) ||
        4220               9 :             tokenStream.currentToken().name() != context->runtime->atomState.xmlAtom ||
        4221               9 :             !tokenStream.matchToken(TOK_NAME) ||
        4222               9 :             tokenStream.currentToken().name() != context->runtime->atomState.namespaceAtom ||
        4223               9 :             !tokenStream.matchToken(TOK_ASSIGN))
        4224                 :         {
        4225               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_DEFAULT_XML_NAMESPACE);
        4226               0 :             return NULL;
        4227                 :         }
        4228                 :
        4229               9 :         JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NOP);
        4230                 :
        4231                 :         /* Is this an E4X dagger I see before me? */
        4232               9 :         tc->flags |= TCF_FUN_HEAVYWEIGHT;
        4233               9 :         ParseNode *pn2 = expr();
        4234               9 :         if (!pn2)
        4235               0 :             return NULL;
        4236               9 :         pn->setOp(JSOP_DEFXMLNS);
        4237               9 :         pn->pn_pos.end = pn2->pn_pos.end;
        4238               9 :         pn->pn_kid = pn2;
        4239               9 :         break;
        4240                 :       }
        4241                 : #endif
        4242                 :
        4243                 :       case TOK_ERROR:
        4244               0 :         return NULL;
        4245                 :
        4246                 :       default:
        4247          557474 :         return expressionStatement();
        4248                 :     }
        4249                 :
        4250                 :     /* Check termination of this primitive statement. */
        4251          178801 :     return MatchOrInsertSemicolon(context, &tokenStream) ? pn : NULL;
        4252                 : }
        4253                 :
        4254                 : /*
        4255                 :  * The 'blockObj' parameter is non-null when parsing the 'vars' in a let
        4256                 :  * expression, block statement, non-top-level let declaration in statement
        4257                 :  * context, and the let-initializer of a for-statement.
        4258                 :  */
        4259                 : ParseNode *
        4260          163907 : Parser::variables(ParseNodeKind kind, StaticBlockObject *blockObj, VarContext varContext)
        4261                 : {
        4262                 :     /*
        4263                 :      * The four options here are:
        4264                 :      * - PNK_VAR:   We're parsing var declarations.
        4265                 :      * - PNK_CONST: We're parsing const declarations.
        4266                 :      * - PNK_LET:   We are parsing a let declaration.
        4267                 :      * - PNK_LP:    We are parsing the head of a let block.
        4268                 :      */
        4269          163907 :     JS_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET || kind == PNK_LP);
        4270                 :
        4271          163907 :     ParseNode *pn = ListNode::create(kind, tc);
        4272          163907 :     if (!pn)
        4273               0 :         return NULL;
        4274                 :
        4275          163907 :     pn->setOp(blockObj ? JSOP_NOP : kind == PNK_VAR ? JSOP_DEFVAR : JSOP_DEFCONST);
        4276          163907 :     pn->makeEmpty();
        4277                 :
        4278                 :     /*
        4279                 :      * SpiderMonkey const is really "write once per initialization evaluation"
        4280                 :      * var, whereas let is block scoped. ES-Harmony wants block-scoped const so
        4281                 :      * this code will change soon.
        4282                 :      */
        4283          163907 :     BindData data;
        4284          163907 :     if (blockObj)
        4285           13555 :         data.initLet(varContext, *blockObj, JSMSG_TOO_MANY_LOCALS);
        4286                 :     else
        4287          150352 :         data.initVarOrConst(pn->getOp());
        4288                 :
        4289                 :     ParseNode *pn2;
        4290          468013 :     do {
        4291          468247 :         TokenKind tt = tokenStream.getToken();
        4292                 : #if JS_HAS_DESTRUCTURING
        4293          468247 :         if (tt == TOK_LB || tt == TOK_LC) {
        4294            7272 :             tc->flags |= TCF_DECL_DESTRUCTURING;
        4295            7272 :             pn2 = primaryExpr(tt, JS_FALSE);
        4296            7272 :             tc->flags &= ~TCF_DECL_DESTRUCTURING;
        4297            7272 :             if (!pn2)
        4298               0 :                 return NULL;
        4299                 :
        4300            7272 :             if (!CheckDestructuring(context, &data, pn2, tc))
        4301             162 :                 return NULL;
        4302                 :             bool ignored;
        4303            7110 :             if ((tc->flags & TCF_IN_FOR_INIT) && matchInOrOf(&ignored)) {
        4304             144 :                 tokenStream.ungetToken();
        4305             144 :                 pn->append(pn2);
        4306             144 :                 continue;
        4307                 :             }
        4308                 :
        4309            6966 :             MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_BAD_DESTRUCT_DECL);
        4310            6966 :             JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NOP);
        4311                 :
        4312            6966 :             ParseNode *init = assignExpr();
        4313            6966 :             if (!init)
        4314               0 :                 return NULL;
        4315            6966 :             UndominateInitializers(pn2, init->pn_pos.end, tc);
        4316                 :
        4317            6966 :             pn2 = ParseNode::newBinaryOrAppend(PNK_ASSIGN, JSOP_NOP, pn2, init, tc);
        4318            6966 :             if (!pn2)
        4319               0 :                 return NULL;
        4320            6966 :             pn->append(pn2);
        4321            6966 :             continue;
        4322                 :         }
        4323                 : #endif /* JS_HAS_DESTRUCTURING */
        4324                 :
        4325          460975 :         if (tt != TOK_NAME) {
        4326               9 :             if (tt != TOK_ERROR)
        4327               9 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NO_VARIABLE_NAME);
        4328               9 :             return NULL;
        4329                 :         }
        4330                 :
        4331          460966 :         PropertyName *name = tokenStream.currentToken().name();
        4332          460966 :         pn2 = NewBindingNode(name, tc, blockObj, varContext);
        4333          460966 :         if (!pn2)
        4334               0 :             return NULL;
        4335          460966 :         if (data.op == JSOP_DEFCONST)
        4336           56178 :             pn2->pn_dflags |= PND_CONST;
        4337          460966 :         data.pn = pn2;
        4338          460966 :         if (!data.binder(context, &data, name, tc))
        4339              54 :             return NULL;
        4340          460912 :         pn->append(pn2);
        4341                 :
        4342          460912 :         if (tokenStream.matchToken(TOK_ASSIGN)) {
        4343          150515 :             JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NOP);
        4344                 :
        4345          150515 :             ParseNode *init = assignExpr();
        4346          150515 :             if (!init)
        4347               9 :                 return NULL;
        4348                 :
        4349          150506 :             if (pn2->isUsed()) {
        4350            2610 :                 pn2 = MakeAssignment(pn2, init, tc);
        4351            2610 :                 if (!pn2)
        4352               0 :                     return NULL;
        4353                 :             } else {
        4354          147896 :                 pn2->pn_expr = init;
        4355                 :             }
        4356                 :
        4357          150506 :             JS_ASSERT_IF(pn2->pn_dflags & PND_GVAR, !(pn2->pn_dflags & PND_BOUND));
        4358                 :
        4359          150506 :             pn2->setOp(pn2->isOp(JSOP_ARGUMENTS)
        4360                 :                        ? JSOP_SETNAME
        4361                 :                        : (pn2->pn_dflags & PND_BOUND)
        4362                 :                        ? JSOP_SETLOCAL
        4363                 :                        : (data.op == JSOP_DEFCONST)
        4364                 :                        ? JSOP_SETCONST
        4365          150506 :                        : JSOP_SETNAME);
        4366                 :
        4367          150506 :             NoteLValue(context, pn2, tc, data.fresh ? PND_INITIALIZED : PND_ASSIGNED);
        4368                 :
        4369                 :             /* The declarator's position must include the initializer. */
        4370          150506 :             pn2->pn_pos.end = init->pn_pos.end;
        4371                 :
        4372          150506 :             if (tc->inFunction() && name == context->runtime->atomState.argumentsAtom) {
        4373              27 :                 tc->noteArgumentsNameUse(pn2);
        4374              27 :                 if (!blockObj) {
        4375              27 :                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
        4376              27 :                     tc->noteLocalOverwritesArguments();
        4377                 :                 }
        4378                 :             }
        4379                 :         }
        4380          468013 :     } while (tokenStream.matchToken(TOK_COMMA));
        4381                 :
        4382          163673 :     pn->pn_pos.end = pn->last()->pn_pos.end;
        4383          163673 :     return pn;
        4384                 : }
        4385                 :
        4386                 : ParseNode *
        4387          939085 : Parser::expr()
        4388                 : {
        4389          939085 :     ParseNode *pn = assignExpr();
        4390          939085 :     if (pn && tokenStream.matchToken(TOK_COMMA)) {
        4391            1260 :         ParseNode *pn2 = ListNode::create(PNK_COMMA, tc);
        4392            1260 :         if (!pn2)
        4393               0 :             return NULL;
        4394            1260 :         pn2->pn_pos.begin = pn->pn_pos.begin;
        4395            1260 :         pn2->initList(pn);
        4396            1260 :         pn = pn2;
        4397            2034 :         do {
        4398                 : #if JS_HAS_GENERATORS
        4399            2034 :             pn2 = pn->last();
        4400            2034 :             if (pn2->isKind(PNK_YIELD) && !pn2->isInParens()) {
        4401               0 :                 reportErrorNumber(pn2, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
        4402               0 :                 return NULL;
        4403                 :             }
        4404                 : #endif
        4405            2034 :             pn2 = assignExpr();
        4406            2034 :             if (!pn2)
        4407               0 :                 return NULL;
        4408            2034 :             pn->append(pn2);
        4409            2034 :         } while (tokenStream.matchToken(TOK_COMMA));
        4410            1260 :         pn->pn_pos.end = pn->last()->pn_pos.end;
        4411                 :     }
        4412          939085 :     return pn;
        4413                 : }
        4414                 :
        4415                 : /*
        4416                 :  * For a number of the expression parsers we define an always-inlined version
        4417                 :  * and a never-inlined version (which just calls the always-inlined version).
        4418                 :  * Using the always-inlined version in the hot call-sites givs a ~5% parsing
        4419                 :  * speedup.  These macros help avoid some boilerplate code.
        4420                 :  */
        4421                 : #define BEGIN_EXPR_PARSER(name)                                               \
        4422                 :     JS_ALWAYS_INLINE ParseNode *                                              \
        4423                 :     Parser::name##i()
        4424                 :
        4425                 : #define END_EXPR_PARSER(name)                                                 \
        4426                 :     JS_NEVER_INLINE ParseNode *                                               \
        4427                 :     Parser::name##n() {                                                       \
        4428                 :         return name##i();                                                     \
        4429                 :     }
        4430                 :
        4431         3604805 : BEGIN_EXPR_PARSER(mulExpr1)
        4432                 : {
        4433         3604805 :     ParseNode *pn = unaryExpr();
        4434                 :
        4435                 :     /*
        4436                 :      * Note: unlike addExpr1() et al, we use getToken() here instead of
        4437                 :      * isCurrentTokenType() because unaryExpr() doesn't leave the TokenStream
        4438                 :      * state one past the end of the unary expression.
        4439                 :      */
        4440                 :     TokenKind tt;
        4441         7219034 :     while (pn && ((tt = tokenStream.getToken()) == TOK_STAR || tt == TOK_DIV || tt == TOK_MOD)) {
        4442                 :         ParseNodeKind kind = (tt == TOK_STAR)
        4443                 :                              ? PNK_STAR
        4444                 :                              : (tt == TOK_DIV)
        4445                 :                              ? PNK_DIV
        4446            9424 :                              : PNK_MOD;
        4447            9424 :         JSOp op = tokenStream.currentToken().t_op;
        4448            9424 :         pn = ParseNode::newBinaryOrAppend(kind, op, pn, unaryExpr(), tc);
        4449                 :     }
        4450         3604805 :     return pn;
        4451                 : }
        4452         1533574 : END_EXPR_PARSER(mulExpr1)
        4453                 :
        4454         2071231 : BEGIN_EXPR_PARSER(addExpr1)
        4455                 : {
        4456         2071231 :     ParseNode *pn = mulExpr1i();
        4457         5676036 :     while (pn && tokenStream.isCurrentTokenType(TOK_PLUS, TOK_MINUS)) {
        4458         1533574 :         TokenKind tt = tokenStream.currentToken().type;
        4459         1533574 :         JSOp op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB;
        4460         1533574 :         ParseNodeKind kind = (tt == TOK_PLUS) ? PNK_ADD : PNK_SUB;
        4461         1533574 :         pn = ParseNode::newBinaryOrAppend(kind, op, pn, mulExpr1n(), tc);
        4462                 :     }
        4463         2071231 :     return pn;
        4464                 : }
        4465            5644 : END_EXPR_PARSER(addExpr1)
        4466                 :
        4467                 : inline ParseNodeKind
        4468            5644 : ShiftTokenToParseNodeKind(const Token &token)
        4469                 : {
        4470            5644 :     switch (token.type) {
        4471                 :       case TOK_LSH:
        4472            2043 :         return PNK_LSH;
        4473                 :       case TOK_RSH:
        4474            2215 :         return PNK_RSH;
        4475                 :       default:
        4476            1386 :         JS_ASSERT(token.type == TOK_URSH);
        4477            1386 :         return PNK_URSH;
        4478                 :     }
        4479                 : }
        4480                 :
        4481         2065587 : BEGIN_EXPR_PARSER(shiftExpr1)
        4482                 : {
        4483         2065587 :     ParseNode *left = addExpr1i();
        4484         4136818 :     while (left && tokenStream.isCurrentTokenShift()) {
        4485            5644 :         ParseNodeKind kind = ShiftTokenToParseNodeKind(tokenStream.currentToken());
        4486            5644 :         JSOp op = tokenStream.currentToken().t_op;
        4487            5644 :         ParseNode *right = addExpr1n();
        4488            5644 :         if (!right)
        4489               0 :             return NULL;
        4490            5644 :         left = tc->parser->new_<BinaryNode>(kind, op, left, right);
        4491                 :     }
        4492         2065587 :     return left;
        4493                 : }
        4494          110677 : END_EXPR_PARSER(shiftExpr1)
        4495                 :
        4496                 : inline ParseNodeKind
        4497          110677 : RelationalTokenToParseNodeKind(const Token &token)
        4498                 : {
        4499          110677 :     switch (token.type) {
        4500                 :       case TOK_IN:
        4501           75330 :         return PNK_IN;
        4502                 :       case TOK_INSTANCEOF:
        4503            1901 :         return PNK_INSTANCEOF;
        4504                 :       case TOK_LT:
        4505           26426 :         return PNK_LT;
        4506                 :       case TOK_LE:
        4507            1683 :         return PNK_LE;
        4508                 :       case TOK_GT:
        4509            3087 :         return PNK_GT;
        4510                 :       default:
        4511            2250 :         JS_ASSERT(token.type == TOK_GE);
        4512            2250 :         return PNK_GE;
        4513                 :     }
        4514                 : }
        4515                 :
        4516         1954910 : BEGIN_EXPR_PARSER(relExpr1)
        4517                 : {
        4518         1954910 :     unsigned inForInitFlag = tc->flags & TCF_IN_FOR_INIT;
        4519                 :
        4520                 :     /*
        4521                 :      * Uses of the in operator in shiftExprs are always unambiguous,
        4522                 :      * so unset the flag that prohibits recognizing it.
        4523                 :      */
        4524         1954910 :     tc->flags &= ~TCF_IN_FOR_INIT;
        4525                 :
        4526         1954910 :     ParseNode *pn = shiftExpr1i();
        4527        10044788 :     while (pn &&
        4528         2065348 :            (tokenStream.isCurrentTokenRelational() ||
        4529                 :             /*
        4530                 :              * Recognize the 'in' token as an operator only if we're not
        4531                 :              * currently in the init expr of a for loop.
        4532                 :              */
        4533         2002371 :             (inForInitFlag == 0 && tokenStream.isCurrentTokenType(TOK_IN)) ||
        4534         1956572 :             tokenStream.isCurrentTokenType(TOK_INSTANCEOF))) {
        4535          110677 :         ParseNodeKind kind = RelationalTokenToParseNodeKind(tokenStream.currentToken());
        4536          110677 :         JSOp op = tokenStream.currentToken().t_op;
        4537          110677 :         pn = ParseNode::newBinaryOrAppend(kind, op, pn, shiftExpr1n(), tc);
        4538                 :     }
        4539                 :     /* Restore previous state of inForInit flag. */
        4540         1954910 :     tc->flags |= inForInitFlag;
        4541                 :
        4542         1954910 :     return pn;
        4543                 : }
        4544           22444 : END_EXPR_PARSER(relExpr1)
        4545                 :
        4546                 : inline ParseNodeKind
        4547           22444 : EqualityTokenToParseNodeKind(const Token &token)
        4548                 : {
        4549           22444 :     switch (token.type) {
        4550                 :       case TOK_STRICTEQ:
        4551            9533 :         return PNK_STRICTEQ;
        4552                 :       case TOK_EQ:
        4553            4744 :         return PNK_EQ;
        4554                 :       case TOK_STRICTNE:
        4555            4834 :         return PNK_STRICTNE;
        4556                 :       default:
        4557            3333 :         JS_ASSERT(token.type == TOK_NE);
        4558            3333 :         return PNK_NE;
        4559                 :     }
        4560                 : }
        4561                 :
        4562         1932466 : BEGIN_EXPR_PARSER(eqExpr1)
        4563                 : {
        4564         1932466 :     ParseNode *left = relExpr1i();
        4565         3887376 :     while (left && tokenStream.isCurrentTokenEquality()) {
        4566           22444 :         ParseNodeKind kind = EqualityTokenToParseNodeKind(tokenStream.currentToken());
        4567           22444 :         JSOp op = tokenStream.currentToken().t_op;
        4568           22444 :         ParseNode *right = relExpr1n();
        4569           22444 :         if (!right)
        4570               0 :             return NULL;
        4571           22444 :         left = tc->parser->new_<BinaryNode>(kind, op, left, right);
        4572                 :     }
        4573         1932466 :     return left;
        4574                 : }
        4575            2871 : END_EXPR_PARSER(eqExpr1)
        4576                 :
        4577         1929595 : BEGIN_EXPR_PARSER(bitAndExpr1)
        4578                 : {
        4579         1929595 :     ParseNode *pn = eqExpr1i();
        4580         3862061 :     while (pn && tokenStream.isCurrentTokenType(TOK_BITAND))
        4581            2871 :         pn = ParseNode::newBinaryOrAppend(PNK_BITAND, JSOP_BITAND, pn, eqExpr1n(), tc);
        4582         1929595 :     return pn;
        4583                 : }
        4584            1629 : END_EXPR_PARSER(bitAndExpr1)
        4585                 :
        4586         1927966 : BEGIN_EXPR_PARSER(bitXorExpr1)
        4587                 : {
        4588         1927966 :     ParseNode *pn = bitAndExpr1i();
        4589         3857561 :     while (pn && tokenStream.isCurrentTokenType(TOK_BITXOR))
        4590            1629 :         pn = ParseNode::newBinaryOrAppend(PNK_BITXOR, JSOP_BITXOR, pn, bitAndExpr1n(), tc);
        4591         1927966 :     return pn;
        4592                 : }
        4593            1629 : END_EXPR_PARSER(bitXorExpr1)
        4594                 :
        4595         1926337 : BEGIN_EXPR_PARSER(bitOrExpr1)
        4596                 : {
        4597         1926337 :     ParseNode *pn = bitXorExpr1i();
        4598         3854303 :     while (pn && tokenStream.isCurrentTokenType(TOK_BITOR))
        4599            1629 :         pn = ParseNode::newBinaryOrAppend(PNK_BITOR, JSOP_BITOR, pn, bitXorExpr1n(), tc);
        4600         1926337 :     return pn;
        4601                 : }
        4602            3870 : END_EXPR_PARSER(bitOrExpr1)
        4603                 :
        4604         1922467 : BEGIN_EXPR_PARSER(andExpr1)
        4605                 : {
        4606         1922467 :     ParseNode *pn = bitOrExpr1i();
        4607         3848804 :     while (pn && tokenStream.isCurrentTokenType(TOK_AND))
        4608            3870 :         pn = ParseNode::newBinaryOrAppend(PNK_AND, JSOP_AND, pn, bitOrExpr1n(), tc);
        4609         1922467 :     return pn;
        4610                 : }
        4611            2907 : END_EXPR_PARSER(andExpr1)
        4612                 :
        4613                 : JS_ALWAYS_INLINE ParseNode *
        4614         1919560 : Parser::orExpr1()
        4615                 : {
        4616         1919560 :     ParseNode *pn = andExpr1i();
        4617         3842027 :     while (pn && tokenStream.isCurrentTokenType(TOK_OR))
        4618            2907 :         pn = ParseNode::newBinaryOrAppend(PNK_OR, JSOP_OR, pn, andExpr1n(), tc);
        4619         1919560 :     return pn;
        4620                 : }
        4621                 :
        4622                 : JS_ALWAYS_INLINE ParseNode *
        4623         1919560 : Parser::condExpr1()
        4624                 : {
        4625         1919560 :     ParseNode *condition = orExpr1();
        4626         1919560 :     if (!condition || !tokenStream.isCurrentTokenType(TOK_HOOK))
        4627         1912925 :         return condition;
        4628                 :
        4629                 :     /*
        4630                 :      * Always accept the 'in' operator in the middle clause of a ternary,
        4631                 :      * where it's unambiguous, even if we might be parsing the init of a
        4632                 :      * for statement.
        4633                 :      */
        4634            6635 :     unsigned oldflags = tc->flags;
        4635            6635 :     tc->flags &= ~TCF_IN_FOR_INIT;
        4636            6635 :     ParseNode *thenExpr = assignExpr();
        4637            6635 :     tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
        4638            6635 :     if (!thenExpr)
        4639               0 :         return NULL;
        4640                 :
        4641            6635 :     MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND);
        4642                 :
        4643            6635 :     ParseNode *elseExpr = assignExpr();
        4644            6635 :     if (!elseExpr)
        4645               0 :         return NULL;
        4646                 :
        4647            6635 :     tokenStream.getToken(); /* read one token past the end */
        4648            6635 :     return new_<ConditionalExpression>(condition, thenExpr, elseExpr);
        4649                 : }
        4650                 :
        4651                 : bool
        4652          403430 : Parser::setAssignmentLhsOps(ParseNode *pn, JSOp op)
        4653                 : {
        4654          403430 :     switch (pn->getKind()) {
        4655                 :       case PNK_NAME:
        4656          372744 :         if (!CheckStrictAssignment(context, tc, pn))
        4657               0 :             return false;
        4658          372744 :         pn->setOp(pn->isOp(JSOP_GETLOCAL) ? JSOP_SETLOCAL : JSOP_SETNAME);
        4659          372744 :         NoteLValue(context, pn, tc);
        4660          372744 :         break;
        4661                 :       case PNK_DOT:
        4662           18224 :         pn->setOp(JSOP_SETPROP);
        4663           18224 :         break;
        4664                 :       case PNK_LB:
        4665           12138 :         pn->setOp(JSOP_SETELEM);
        4666           12138 :         break;
        4667                 : #if JS_HAS_DESTRUCTURING
        4668                 :       case PNK_RB:
        4669                 :       case PNK_RC:
        4670             279 :         if (op != JSOP_NOP) {
        4671               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_DESTRUCT_ASS);
        4672               0 :             return false;
        4673                 :         }
        4674             279 :         if (!CheckDestructuring(context, NULL, pn, tc))
        4675               0 :             return false;
        4676             279 :         break;
        4677                 : #endif
        4678                 :       case PNK_LP:
        4679              18 :         if (!MakeSetCall(context, pn, tc, JSMSG_BAD_LEFTSIDE_OF_ASS))
        4680               0 :             return false;
        4681              18 :         break;
        4682                 : #if JS_HAS_XML_SUPPORT
        4683                 :       case PNK_XMLUNARY:
        4684              18 :         JS_ASSERT(pn->isOp(JSOP_XMLNAME));
        4685              18 :         pn->setOp(JSOP_SETXMLNAME);
        4686              18 :         break;
        4687                 : #endif
        4688                 :       default:
        4689               9 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS);
        4690               9 :         return false;
        4691                 :     }
        4692          403421 :     return true;
        4693                 : }
        4694                 :
        4695                 : ParseNode *
        4696         1920118 : Parser::assignExpr()
        4697                 : {
        4698         1920118 :     JS_CHECK_RECURSION(context, return NULL);
        4699                 :
        4700                 : #if JS_HAS_GENERATORS
        4701         1920118 :     if (tokenStream.matchToken(TOK_YIELD, TSF_OPERAND))
        4702             558 :         return returnOrYield(true);
        4703                 : #endif
        4704                 :
        4705         1919560 :     ParseNode *lhs = condExpr1();
        4706         1919560 :     if (!lhs)
        4707             239 :         return NULL;
        4708                 :
        4709                 :     ParseNodeKind kind;
        4710         1919321 :     switch (tokenStream.currentToken().type) {
        4711          373491 :       case TOK_ASSIGN:       kind = PNK_ASSIGN;       break;
        4712           27437 :       case TOK_ADDASSIGN:    kind = PNK_ADDASSIGN;    break;
        4713             315 :       case TOK_SUBASSIGN:    kind = PNK_SUBASSIGN;    break;
        4714             126 :       case TOK_BITORASSIGN:  kind = PNK_BITORASSIGN;  break;
        4715              54 :       case TOK_BITXORASSIGN: kind = PNK_BITXORASSIGN; break;
        4716              36 :       case TOK_BITANDASSIGN: kind = PNK_BITANDASSIGN; break;
        4717              18 :       case TOK_LSHASSIGN:    kind = PNK_LSHASSIGN;    break;
        4718             153 :       case TOK_RSHASSIGN:    kind = PNK_RSHASSIGN;    break;
        4719               0 :       case TOK_URSHASSIGN:   kind = PNK_URSHASSIGN;   break;
        4720             216 :       case TOK_MULASSIGN:    kind = PNK_MULASSIGN;    break;
        4721              63 :       case TOK_DIVASSIGN:    kind = PNK_DIVASSIGN;    break;
        4722              45 :       case TOK_MODASSIGN:    kind = PNK_MODASSIGN;    break;
        4723                 :       default:
        4724         1517367 :         JS_ASSERT(!tokenStream.isCurrentTokenAssignment());
        4725         1517367 :         tokenStream.ungetToken();
        4726         1517367 :         return lhs;
        4727                 :     }
        4728                 :
        4729          401954 :     JSOp op = tokenStream.currentToken().t_op;
        4730          401954 :     if (!setAssignmentLhsOps(lhs, op))
        4731               9 :         return NULL;
        4732                 :
        4733          401945 :     ParseNode *rhs = assignExpr();
        4734          401945 :     if (!rhs)
        4735               0 :         return NULL;
        4736          401945 :     if (lhs->isKind(PNK_NAME) && lhs->isUsed()) {
        4737          371322 :         Definition *dn = lhs->pn_lexdef;
        4738                 :
        4739                 :         /*
        4740                 :          * If the definition is not flagged as assigned, we must have imputed
        4741                 :          * the initialized flag to it, to optimize for flat closures. But that
        4742                 :          * optimization uses source coordinates to check dominance relations,
        4743                 :          * so we must extend the end of the definition to cover the right-hand
        4744                 :          * side of this assignment, i.e., the initializer.
        4745                 :          */
        4746          371322 :         if (!dn->isAssigned()) {
        4747            1251 :             JS_ASSERT(dn->isInitialized());
        4748            1251 :             dn->pn_pos.end = rhs->pn_pos.end;
        4749                 :         }
        4750                 :     }
        4751                 :
        4752          401945 :     return ParseNode::newBinaryOrAppend(kind, op, lhs, rhs, tc);
        4753                 : }
        4754                 :
        4755                 : static bool
        4756           30131 : SetLvalKid(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn, ParseNode *kid,
        4757                 :            const char *name)
        4758                 : {
        4759           32471 :     if (!kid->isKind(PNK_NAME) &&
        4760             909 :         !kid->isKind(PNK_DOT) &&
        4761             486 :         (!kid->isKind(PNK_LP) ||
        4762              18 :          (!kid->isOp(JSOP_CALL) && !kid->isOp(JSOP_EVAL) &&
        4763               0 :           !kid->isOp(JSOP_FUNCALL) && !kid->isOp(JSOP_FUNAPPLY))) &&
        4764                 : #if JS_HAS_XML_SUPPORT
        4765             468 :         !kid->isKind(PNK_XMLUNARY) &&
        4766                 : #endif
        4767             459 :         !kid->isKind(PNK_LB))
        4768                 :     {
        4769               0 :         ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_OPERAND, name);
        4770               0 :         return false;
        4771                 :     }
        4772           30131 :     if (!CheckStrictAssignment(cx, tc, kid))
        4773               0 :         return false;
        4774           30131 :     pn->pn_kid = kid;
        4775           30131 :     return true;
        4776                 : }
        4777                 :
        4778                 : static const char incop_name_str[][10] = {"increment", "decrement"};
        4779                 :
        4780                 : static JSBool
        4781           30131 : SetIncOpKid(JSContext *cx, TokenStream *ts, TreeContext *tc, ParseNode *pn, ParseNode *kid,
        4782                 :             TokenKind tt, bool preorder)
        4783                 : {
        4784                 :     JSOp op;
        4785                 :
        4786           30131 :     if (!SetLvalKid(cx, ts, tc, pn, kid, incop_name_str[tt == TOK_DEC]))
        4787               0 :         return false;
        4788           30131 :     switch (kid->getKind()) {
        4789                 :       case PNK_NAME:
        4790                 :         op = (tt == TOK_INC)
        4791                 :              ? (preorder ? JSOP_INCNAME : JSOP_NAMEINC)
        4792           29222 :              : (preorder ? JSOP_DECNAME : JSOP_NAMEDEC);
        4793           29222 :         NoteLValue(cx, kid, tc);
        4794           29222 :         break;
        4795                 :
        4796                 :       case PNK_DOT:
        4797                 :         op = (tt == TOK_INC)
        4798                 :              ? (preorder ? JSOP_INCPROP : JSOP_PROPINC)
        4799             423 :              : (preorder ? JSOP_DECPROP : JSOP_PROPDEC);
        4800             423 :         break;
        4801                 :
        4802                 :       case PNK_LP:
        4803              18 :         if (!MakeSetCall(cx, kid, tc, JSMSG_BAD_INCOP_OPERAND))
        4804               0 :             return JS_FALSE;
        4805                 :         /* FALL THROUGH */
        4806                 : #if JS_HAS_XML_SUPPORT
        4807                 :       case PNK_XMLUNARY:
        4808              27 :         if (kid->isOp(JSOP_XMLNAME))
        4809               9 :             kid->setOp(JSOP_SETXMLNAME);
        4810                 :         /* FALL THROUGH */
        4811                 : #endif
        4812                 :       case PNK_LB:
        4813                 :         op = (tt == TOK_INC)
        4814                 :              ? (preorder ? JSOP_INCELEM : JSOP_ELEMINC)
        4815             486 :              : (preorder ? JSOP_DECELEM : JSOP_ELEMDEC);
        4816             486 :         break;
        4817                 :
        4818                 :       default:
        4819               0 :         JS_ASSERT(0);
        4820               0 :         op = JSOP_NOP;
        4821                 :     }
        4822           30131 :     pn->setOp(op);
        4823           30131 :     return JS_TRUE;
        4824                 : }
        4825                 :
        4826                 : ParseNode *
        4827          109835 : Parser::unaryOpExpr(ParseNodeKind kind, JSOp op)
        4828                 : {
        4829          109835 :     TokenPtr begin = tokenStream.currentToken().pos.begin;
        4830          109835 :     ParseNode *kid = unaryExpr();
        4831          109835 :     if (!kid)
        4832               4 :         return NULL;
        4833          109831 :     return new_<UnaryNode>(kind, op, TokenPos::make(begin, kid->pn_pos.end), kid);
        4834                 : }
        4835                 :
        4836                 : ParseNode *
        4837         3725324 : Parser::unaryExpr()
        4838                 : {
        4839                 :     ParseNode *pn, *pn2;
        4840                 :
        4841         3725324 :     JS_CHECK_RECURSION(context, return NULL);
        4842                 :
        4843         3725324 :     switch (TokenKind tt = tokenStream.getToken(TSF_OPERAND)) {
        4844                 :       case TOK_TYPEOF:
        4845            2502 :         return unaryOpExpr(PNK_TYPEOF, JSOP_TYPEOF);
        4846                 :       case TOK_VOID:
        4847            1206 :         return unaryOpExpr(PNK_VOID, JSOP_VOID);
        4848                 :       case TOK_NOT:
        4849           76619 :         return unaryOpExpr(PNK_NOT, JSOP_NOT);
        4850                 :       case TOK_BITNOT:
        4851             135 :         return unaryOpExpr(PNK_BITNOT, JSOP_BITNOT);
        4852                 :       case TOK_PLUS:
        4853             333 :         return unaryOpExpr(PNK_POS, JSOP_POS);
        4854                 :       case TOK_MINUS:
        4855           29040 :         return unaryOpExpr(PNK_NEG, JSOP_NEG);
        4856                 :
        4857                 :       case TOK_INC:
        4858                 :       case TOK_DEC:
        4859            7281 :         pn = UnaryNode::create((tt == TOK_INC) ? PNK_PREINCREMENT : PNK_PREDECREMENT, tc);
        4860            7281 :         if (!pn)
        4861               0 :             return NULL;
        4862            7281 :         pn2 = memberExpr(JS_TRUE);
        4863            7281 :         if (!pn2)
        4864               0 :             return NULL;
        4865            7281 :         if (!SetIncOpKid(context, &tokenStream, tc, pn, pn2, tt, true))
        4866               0 :             return NULL;
        4867            7281 :         pn->pn_pos.end = pn2->pn_pos.end;
        4868            7281 :         break;
        4869                 :
        4870                 :       case TOK_DELETE:
        4871                 :       {
        4872            1260 :         pn = UnaryNode::create(PNK_DELETE, tc);
        4873            1260 :         if (!pn)
        4874               0 :             return NULL;
        4875            1260 :         pn2 = unaryExpr();
        4876            1260 :         if (!pn2)
        4877               0 :             return NULL;
        4878            1260 :         pn->pn_pos.end = pn2->pn_pos.end;
        4879                 :
        4880                 :         /*
        4881                 :          * Under ECMA3, deleting any unary expression is valid -- it simply
        4882                 :          * returns true. Here we fold constants before checking for a call
        4883                 :          * expression, in order to rule out delete of a generator expression.
        4884                 :          */
        4885            1260 :         if (foldConstants && !FoldConstants(context, pn2, tc))
        4886               0 :             return NULL;
        4887            1260 :         switch (pn2->getKind()) {
        4888                 :           case PNK_LP:
        4889               0 :             if (!(pn2->pn_xflags & PNX_SETCALL)) {
        4890                 :                 /*
        4891                 :                  * Call MakeSetCall to check for errors, but clear PNX_SETCALL
        4892                 :                  * because the optimizer will eliminate the useless delete.
        4893                 :                  */
        4894               0 :                 if (!MakeSetCall(context, pn2, tc, JSMSG_BAD_DELETE_OPERAND))
        4895               0 :                     return NULL;
        4896               0 :                 pn2->pn_xflags &= ~PNX_SETCALL;
        4897                 :             }
        4898               0 :             break;
        4899                 :           case PNK_NAME:
        4900             486 :             if (!ReportStrictModeError(context, &tokenStream, tc, pn,
        4901             486 :                                        JSMSG_DEPRECATED_DELETE_OPERAND)) {
        4902               0 :                 return NULL;
        4903                 :             }
        4904             486 :             pn2->setOp(JSOP_DELNAME);
        4905             486 :             if (pn2->pn_atom == context->runtime->atomState.argumentsAtom) {
        4906               0 :                 tc->flags |= TCF_FUN_HEAVYWEIGHT;
        4907               0 :                 tc->countArgumentsUse(pn2);
        4908                 :             }
        4909             486 :             break;
        4910                 :           default:;
        4911                 :         }
        4912            1260 :         pn->pn_kid = pn2;
        4913            1260 :         break;
        4914                 :       }
        4915                 :       case TOK_ERROR:
        4916               0 :         return NULL;
        4917                 :
        4918                 :       default:
        4919         3606948 :         tokenStream.ungetToken();
        4920         3606948 :         pn = memberExpr(JS_TRUE);
        4921         3606948 :         if (!pn)
        4922             239 :             return NULL;
        4923                 :
        4924                 :         /* Don't look across a newline boundary for a postfix incop. */
        4925         3606709 :         if (tokenStream.onCurrentLine(pn->pn_pos)) {
        4926         3491329 :             tt = tokenStream.peekTokenSameLine(TSF_OPERAND);
        4927         3491329 :             if (tt == TOK_INC || tt == TOK_DEC) {
        4928           22850 :                 tokenStream.consumeKnownToken(tt);
        4929           22850 :                 pn2 = UnaryNode::create((tt == TOK_INC) ? PNK_POSTINCREMENT : PNK_POSTDECREMENT, tc);
        4930           22850 :                 if (!pn2)
        4931               0 :                     return NULL;
        4932           22850 :                 if (!SetIncOpKid(context, &tokenStream, tc, pn2, pn, tt, false))
        4933               0 :                     return NULL;
        4934           22850 :                 pn2->pn_pos.begin = pn->pn_pos.begin;
        4935           22850 :                 pn = pn2;
        4936                 :             }
        4937                 :         }
        4938         3606709 :         break;
        4939                 :     }
        4940         3615250 :     return pn;
        4941                 : }
        4942                 :
        4943                 : #if JS_HAS_GENERATORS
        4944                 :
        4945                 : /*
        4946                 :  * A dedicated helper for transplanting the comprehension expression E in
        4947                 :  *
        4948                 :  *   [E for (V in I)]   // array comprehension
        4949                 :  *   (E for (V in I))   // generator expression
        4950                 :  *
        4951                 :  * from its initial location in the AST, on the left of the 'for', to its final
        4952                 :  * position on the right. To avoid a separate pass we do this by adjusting the
        4953                 :  * blockids and name binding links that were established when E was parsed.
        4954                 :  *
        4955                 :  * A generator expression desugars like so:
        4956                 :  *
        4957                 :  *   (E for (V in I)) => (function () { for (var V in I) yield E; })()
        4958                 :  *
        4959                 :  * so the transplanter must adjust static level as well as blockid. E's source
        4960                 :  * coordinates in root->pn_pos are critical to deciding which binding links to
        4961                 :  * preserve and which to cut.
        4962                 :  *
        4963                 :  * NB: This is not a general tree transplanter -- it knows in particular that
        4964                 :  * the one or more bindings induced by V have not yet been created.
        4965                 :  */
        4966                 : class CompExprTransplanter {
        4967                 :     ParseNode       *root;
        4968                 :     TreeContext     *tc;
        4969                 :     bool            genexp;
        4970                 :     unsigned           adjust;
        4971                 :     unsigned           funcLevel;
        4972                 :
        4973                 :   public:
        4974             657 :     CompExprTransplanter(ParseNode *pn, TreeContext *tc, bool ge, unsigned adj)
        4975             657 :       : root(pn), tc(tc), genexp(ge), adjust(adj), funcLevel(0)
        4976                 :     {
        4977             657 :     }
        4978                 :
        4979                 :     bool transplant(ParseNode *pn);
        4980                 : };
        4981                 :
        4982                 : /*
        4983                 :  * A helper for lazily checking for the presence of illegal |yield| or |arguments|
        4984                 :  * tokens inside of generator expressions. This must be done lazily since we don't
        4985                 :  * know whether we're in a generator expression until we see the "for" token after
        4986                 :  * we've already parsed the body expression.
        4987                 :  *
        4988                 :  * Use in any context which may turn out to be inside a generator expression. This
        4989                 :  * includes parenthesized expressions and argument lists, and it includes the tail
        4990                 :  * of generator expressions.
        4991                 :  *
        4992                 :  * The guard will keep track of any |yield| or |arguments| tokens that occur while
        4993                 :  * parsing the body. As soon as the parser reaches the end of the body expression,
        4994                 :  * call endBody() to reset the context's state, and then immediately call:
        4995                 :  *
        4996                 :  * - checkValidBody() if this *did* turn out to be a generator expression
        4997                 :  * - maybeNoteGenerator() if this *did not* turn out to be a generator expression
        4998                 :  */
        4999                 : class GenexpGuard {
        5000                 :     TreeContext     *tc;
        5001                 :     uint32_t        startYieldCount;
        5002                 :     uint32_t        startArgumentsCount;
        5003                 :
        5004                 :   public:
        5005          421178 :     explicit GenexpGuard(TreeContext *tc)
        5006          421178 :       : tc(tc)
        5007                 :     {
        5008          421178 :         if (tc->parenDepth == 0) {
        5009          277167 :             tc->yieldCount = tc->argumentsCount = 0;
        5010          277167 :             tc->yieldNode = tc->argumentsNode = NULL;
        5011                 :         }
        5012          421178 :         startYieldCount = tc->yieldCount;
        5013          421178 :         startArgumentsCount = tc->argumentsCount;
        5014          421178 :         tc->parenDepth++;
        5015          421178 :     }
        5016                 :
        5017                 :     void endBody();
        5018                 :     bool checkValidBody(ParseNode *pn);
        5019                 :     bool maybeNoteGenerator(ParseNode *pn);
        5020                 : };
        5021                 :
        5022                 : void
        5023          421015 : GenexpGuard::endBody()
        5024                 : {
        5025          421015 :     tc->parenDepth--;
        5026          421015 : }
        5027                 :
        5028                 : /*
        5029                 :  * Check whether a |yield| or |arguments| token has been encountered in the
        5030                 :  * body expression, and if so, report an error.
        5031                 :  *
        5032                 :  * Call this after endBody() when determining that the body *was* in a
        5033                 :  * generator expression.
        5034                 :  */
        5035                 : bool
        5036             423 : GenexpGuard::checkValidBody(ParseNode *pn)
        5037                 : {
        5038             423 :     if (tc->yieldCount > startYieldCount) {
        5039               0 :         ParseNode *errorNode = tc->yieldNode;
        5040               0 :         if (!errorNode)
        5041               0 :             errorNode = pn;
        5042               0 :         tc->parser->reportErrorNumber(errorNode, JSREPORT_ERROR, JSMSG_BAD_GENEXP_BODY, js_yield_str);
        5043               0 :         return false;
        5044                 :     }
        5045                 :
        5046             423 :     if (tc->argumentsCount > startArgumentsCount) {
        5047               9 :         ParseNode *errorNode = tc->argumentsNode;
        5048               9 :         if (!errorNode)
        5049               0 :             errorNode = pn;
        5050               9 :         tc->parser->reportErrorNumber(errorNode, JSREPORT_ERROR, JSMSG_BAD_GENEXP_BODY, js_arguments_str);
        5051               9 :         return false;
        5052                 :     }
        5053                 :
        5054             414 :     return true;
        5055                 : }
        5056                 :
        5057                 : /*
        5058                 :  * Check whether a |yield| token has been encountered in the body expression,
        5059                 :  * and if so, note that the current function is a generator function.
        5060                 :  *
        5061                 :  * Call this after endBody() when determining that the body *was not* in a
        5062                 :  * generator expression.
        5063                 :  */
        5064                 : bool
        5065          420592 : GenexpGuard::maybeNoteGenerator(ParseNode *pn)
        5066                 : {
        5067          420592 :     if (tc->yieldCount > 0) {
        5068               0 :         tc->flags |= TCF_FUN_IS_GENERATOR;
        5069               0 :         if (!tc->inFunction()) {
        5070                 :             tc->parser->reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_RETURN_OR_YIELD,
        5071               0 :                                           js_yield_str);
        5072               0 :             return false;
        5073                 :         }
        5074               0 :         if (tc->flags & TCF_RETURN_EXPR) {
        5075                 :             /* At the time we saw the yield, we might not have set TCF_FUN_IS_GENERATOR yet. */
        5076                 :             ReportBadReturn(tc->parser->context, tc, pn, JSREPORT_ERROR,
        5077                 :                             JSMSG_BAD_GENERATOR_RETURN,
        5078               0 :                             JSMSG_BAD_ANON_GENERATOR_RETURN);
        5079               0 :             return false;
        5080                 :         }
        5081                 :     }
        5082          420592 :     return true;
        5083                 : }
        5084                 :
        5085                 : /*
        5086                 :  * Any definitions nested within the comprehension expression of a generator
        5087                 :  * expression must move "down" one static level, which of course increases the
        5088                 :  * upvar-frame-skip count.
        5089                 :  */
        5090                 : static bool
        5091             198 : BumpStaticLevel(ParseNode *pn, TreeContext *tc)
        5092                 : {
        5093             198 :     if (!pn->pn_cookie.isFree()) {
        5094               0 :         unsigned level = pn->pn_cookie.level() + 1;
        5095                 :
        5096               0 :         JS_ASSERT(level >= tc->staticLevel);
        5097               0 :         if (level >= UpvarCookie::FREE_LEVEL) {
        5098                 :             JS_ReportErrorNumber(tc->parser->context, js_GetErrorMessage, NULL,
        5099               0 :                                  JSMSG_TOO_DEEP, js_function_str);
        5100               0 :             return false;
        5101                 :         }
        5102                 :
        5103               0 :         pn->pn_cookie.set(level, pn->pn_cookie.slot());
        5104                 :     }
        5105             198 :     return true;
        5106                 : }
        5107                 :
        5108                 : static void
        5109            1251 : AdjustBlockId(ParseNode *pn, unsigned adjust, TreeContext *tc)
        5110                 : {
        5111            1251 :     JS_ASSERT(pn->isArity(PN_LIST) || pn->isArity(PN_FUNC) || pn->isArity(PN_NAME));
        5112            1251 :     pn->pn_blockid += adjust;
        5113            1251 :     if (pn->pn_blockid >= tc->blockidGen)
        5114              18 :         tc->blockidGen = pn->pn_blockid + 1;
        5115            1251 : }
        5116                 :
        5117                 : bool
        5118            2061 : CompExprTransplanter::transplant(ParseNode *pn)
        5119                 : {
        5120            2061 :     if (!pn)
        5121             522 :         return true;
        5122                 :
        5123            1539 :     switch (pn->getArity()) {
        5124                 :       case PN_LIST:
        5125             756 :         for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
        5126             504 :             if (!transplant(pn2))
        5127               0 :                 return false;
        5128                 :         }
        5129             252 :         if (pn->pn_pos >= root->pn_pos)
        5130             252 :             AdjustBlockId(pn, adjust, tc);
        5131             252 :         break;
        5132                 :
        5133                 :       case PN_TERNARY:
        5134               0 :         if (!transplant(pn->pn_kid1) ||
        5135               0 :             !transplant(pn->pn_kid2) ||
        5136               0 :             !transplant(pn->pn_kid3))
        5137               0 :             return false;
        5138               0 :         break;
        5139                 :
        5140                 :       case PN_BINARY:
        5141              72 :         if (!transplant(pn->pn_left))
        5142               0 :             return false;
        5143                 :
        5144                 :         /* Binary TOK_COLON nodes can have left == right. See bug 492714. */
        5145              72 :         if (pn->pn_right != pn->pn_left) {
        5146              72 :             if (!transplant(pn->pn_right))
        5147               0 :                 return false;
        5148                 :         }
        5149              72 :         break;
        5150                 :
        5151                 :       case PN_UNARY:
        5152             216 :         if (!transplant(pn->pn_kid))
        5153               0 :             return false;
        5154             216 :         break;
        5155                 :
        5156                 :       case PN_FUNC:
        5157                 :       {
        5158                 :         /*
        5159                 :          * Only the first level of transplant recursion through functions needs
        5160                 :          * to reparent the funbox, since all descendant functions are correctly
        5161                 :          * linked under the top-most funbox. But every visit to this case needs
        5162                 :          * to update funbox->level.
        5163                 :          *
        5164                 :          * Recall that funbox->level is the static level of the code containing
        5165                 :          * the definition or expression of the function and not the static level
        5166                 :          * of the function's body.
        5167                 :          */
        5168               9 :         FunctionBox *funbox = pn->pn_funbox;
        5169                 :
        5170               9 :         funbox->level = tc->staticLevel + funcLevel;
        5171               9 :         if (++funcLevel == 1 && genexp) {
        5172               0 :             FunctionBox *parent = tc->funbox;
        5173                 :
        5174               0 :             FunctionBox **funboxp = &tc->parent->functionList;
        5175               0 :             while (*funboxp != funbox)
        5176               0 :                 funboxp = &(*funboxp)->siblings;
        5177               0 :             *funboxp = funbox->siblings;
        5178                 :
        5179               0 :             funbox->parent = parent;
        5180               0 :             funbox->siblings = parent->kids;
        5181               0 :             parent->kids = funbox;
        5182               0 :             funbox->level = tc->staticLevel;
        5183                 :         }
        5184                 :         /* FALL THROUGH */
        5185                 :       }
        5186                 :
        5187                 :       case PN_NAME:
        5188             531 :         if (!transplant(pn->maybeExpr()))
        5189               0 :             return false;
        5190             531 :         if (pn->isArity(PN_FUNC))
        5191               9 :             --funcLevel;
        5192                 :
        5193             531 :         if (pn->isDefn()) {
        5194               0 :             if (genexp && !BumpStaticLevel(pn, tc))
        5195               0 :                 return false;
        5196             531 :         } else if (pn->isUsed()) {
        5197             522 :             JS_ASSERT(!pn->isOp(JSOP_NOP));
        5198             522 :             JS_ASSERT(pn->pn_cookie.isFree());
        5199                 :
        5200             522 :             Definition *dn = pn->pn_lexdef;
        5201             522 :             JS_ASSERT(dn->isDefn());
        5202                 :
        5203                 :             /*
        5204                 :              * Adjust the definition's block id only if it is a placeholder not
        5205                 :              * to the left of the root node, and if pn is the last use visited
        5206                 :              * in the comprehension expression (to avoid adjusting the blockid
        5207                 :              * multiple times).
        5208                 :              *
        5209                 :              * Non-placeholder definitions within the comprehension expression
        5210                 :              * will be visited further below.
        5211                 :              */
        5212             522 :             if (dn->isPlaceholder() && dn->pn_pos >= root->pn_pos && dn->dn_uses == pn) {
        5213             468 :                 if (genexp && !BumpStaticLevel(dn, tc))
        5214               0 :                     return false;
        5215             468 :                 AdjustBlockId(dn, adjust, tc);
        5216                 :             }
        5217                 :
        5218             522 :             JSAtom *atom = pn->pn_atom;
        5219                 : #ifdef DEBUG
        5220             522 :             StmtInfo *stmt = LexicalLookup(tc, atom, NULL);
        5221             522 :             JS_ASSERT(!stmt || stmt != tc->topStmt);
        5222                 : #endif
        5223             522 :             if (genexp && !dn->isOp(JSOP_CALLEE)) {
        5224             216 :                 JS_ASSERT(!tc->decls.lookupFirst(atom));
        5225                 :
        5226             216 :                 if (dn->pn_pos < root->pn_pos) {
        5227                 :                     /*
        5228                 :                      * The variable originally appeared to be a use of a
        5229                 :                      * definition or placeholder outside the generator, but now
        5230                 :                      * we know it is scoped within the comprehension tail's
        5231                 :                      * clauses. Make it (along with any other uses within the
        5232                 :                      * generator) a use of a new placeholder in the generator's
        5233                 :                      * lexdeps.
        5234                 :                      */
        5235               0 :                     Definition *dn2 = MakePlaceholder(pn, tc);
        5236               0 :                     if (!dn2)
        5237               0 :                         return false;
        5238               0 :                     dn2->pn_pos = root->pn_pos;
        5239                 :
        5240                 :                     /*
        5241                 :                      * Change all uses of |dn| that lie within the generator's
        5242                 :                      * |yield| expression into uses of dn2.
        5243                 :                      */
        5244               0 :                     ParseNode **pnup = &dn->dn_uses;
        5245                 :                     ParseNode *pnu;
        5246               0 :                     while ((pnu = *pnup) != NULL && pnu->pn_pos >= root->pn_pos) {
        5247               0 :                         pnu->pn_lexdef = dn2;
        5248               0 :                         dn2->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
        5249               0 :                         pnup = &pnu->pn_link;
        5250                 :                     }
        5251               0 :                     dn2->dn_uses = dn->dn_uses;
        5252               0 :                     dn->dn_uses = *pnup;
        5253               0 :                     *pnup = NULL;
        5254               0 :                     if (!tc->lexdeps->put(atom, dn2))
        5255               0 :                         return false;
        5256             216 :                 } else if (dn->isPlaceholder()) {
        5257                 :                     /*
        5258                 :                      * The variable first occurs free in the 'yield' expression;
        5259                 :                      * move the existing placeholder node (and all its uses)
        5260                 :                      * from the parent's lexdeps into the generator's lexdeps.
        5261                 :                      */
        5262             216 :                     tc->parent->lexdeps->remove(atom);
        5263             216 :                     if (!tc->lexdeps->put(atom, dn))
        5264               0 :                         return false;
        5265                 :                 }
        5266                 :             }
        5267                 :         }
        5268                 :
        5269             531 :         if (pn->pn_pos >= root->pn_pos)
        5270             531 :             AdjustBlockId(pn, adjust, tc);
        5271             531 :         break;
        5272                 :
        5273                 :       case PN_NAMESET:
        5274               9 :         if (!transplant(pn->pn_tree))
        5275               0 :             return false;
        5276               9 :         break;
        5277                 :
        5278                 :       case PN_NULLARY:
        5279                 :         /* Nothing. */
        5280             459 :         break;
        5281                 :     }
        5282            1539 :     return true;
        5283                 : }
        5284                 :
        5285                 : /*
        5286                 :  * Starting from a |for| keyword after the first array initialiser element or
        5287                 :  * an expression in an open parenthesis, parse the tail of the comprehension
        5288                 :  * or generator expression signified by this |for| keyword in context.
        5289                 :  *
        5290                 :  * Return null on failure, else return the top-most parse node for the array
        5291                 :  * comprehension or generator expression, with a unary node as the body of the
        5292                 :  * (possibly nested) for-loop, initialized by |kind, op, kid|.
        5293                 :  */
        5294                 : ParseNode *
        5295             657 : Parser::comprehensionTail(ParseNode *kid, unsigned blockid, bool isGenexp,
        5296                 :                           ParseNodeKind kind, JSOp op)
        5297                 : {
        5298                 :     unsigned adjust;
        5299                 :     ParseNode *pn, *pn2, *pn3, **pnp;
        5300                 :     StmtInfo stmtInfo;
        5301             657 :     BindData data;
        5302                 :     TokenKind tt;
        5303                 :
        5304             657 :     JS_ASSERT(tokenStream.currentToken().type == TOK_FOR);
        5305                 :
        5306             657 :     if (kind == PNK_SEMI) {
        5307                 :         /*
        5308                 :          * Generator expression desugars to an immediately applied lambda that
        5309                 :          * yields the next value from a for-in loop (possibly nested, and with
        5310                 :          * optional if guard). Make pn be the TOK_LC body node.
        5311                 :          */
        5312             207 :         pn = PushLexicalScope(context, tc, &stmtInfo);
        5313             207 :         if (!pn)
        5314               0 :             return NULL;
        5315             207 :         adjust = pn->pn_blockid - blockid;
        5316                 :     } else {
        5317             450 :         JS_ASSERT(kind == PNK_ARRAYPUSH);
        5318                 :
        5319                 :         /*
        5320                 :          * Make a parse-node and literal object representing the block scope of
        5321                 :          * this array comprehension. Our caller in primaryExpr, the TOK_LB case
        5322                 :          * aka the array initialiser case, has passed the blockid to claim for
        5323                 :          * the comprehension's block scope. We allocate that id or one above it
        5324                 :          * here, by calling PushLexicalScope.
        5325                 :          *
        5326                 :          * In the case of a comprehension expression that has nested blocks
        5327                 :          * (e.g., let expressions), we will allocate a higher blockid but then
        5328                 :          * slide all blocks "to the right" to make room for the comprehension's
        5329                 :          * block scope.
        5330                 :          */
        5331             450 :         adjust = tc->blockid();
        5332             450 :         pn = PushLexicalScope(context, tc, &stmtInfo);
        5333             450 :         if (!pn)
        5334               0 :             return NULL;
        5335                 :
        5336             450 :         JS_ASSERT(blockid <= pn->pn_blockid);
        5337             450 :         JS_ASSERT(blockid < tc->blockidGen);
        5338             450 :         JS_ASSERT(tc->bodyid < blockid);
        5339             450 :         pn->pn_blockid = stmtInfo.blockid = blockid;
        5340             450 :         JS_ASSERT(adjust < blockid);
        5341             450 :         adjust = blockid - adjust;
        5342                 :     }
        5343                 :
        5344             657 :     pnp = &pn->pn_expr;
        5345                 :
        5346             657 :     CompExprTransplanter transplanter(kid, tc, kind == PNK_SEMI, adjust);
        5347             657 :     transplanter.transplant(kid);
        5348                 :
        5349             657 :     JS_ASSERT(tc->blockChain && tc->blockChain == pn->pn_objbox->object);
        5350             657 :     data.initLet(HoistVars, *tc->blockChain, JSMSG_ARRAY_INIT_TOO_BIG);
        5351                 :
        5352             549 :     do {
        5353                 :         /*
        5354                 :          * FOR node is binary, left is loop control and right is body.  Use
        5355                 :          * index to count each block-local let-variable on the left-hand side
        5356                 :          * of the in/of.
        5357                 :          */
        5358             684 :         pn2 = BinaryNode::create(PNK_FOR, tc);
        5359             684 :         if (!pn2)
        5360               0 :             return NULL;
        5361                 :
        5362             684 :         pn2->setOp(JSOP_ITER);
        5363             684 :         pn2->pn_iflags = JSITER_ENUMERATE;
        5364             684 :         if (tokenStream.matchToken(TOK_NAME)) {
        5365              81 :             if (tokenStream.currentToken().name() == context->runtime->atomState.eachAtom)
        5366              81 :                 pn2->pn_iflags |= JSITER_FOREACH;
        5367                 :             else
        5368               0 :                 tokenStream.ungetToken();
        5369                 :         }
        5370             684 :         MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
        5371                 :
        5372             684 :         GenexpGuard guard(tc);
        5373                 :
        5374             684 :         PropertyName *name = NULL;
        5375             684 :         tt = tokenStream.getToken();
        5376             684 :         switch (tt) {
        5377                 : #if JS_HAS_DESTRUCTURING
        5378                 :           case TOK_LB:
        5379                 :           case TOK_LC:
        5380               9 :             tc->flags |= TCF_DECL_DESTRUCTURING;
        5381               9 :             pn3 = primaryExpr(tt, JS_FALSE);
        5382               9 :             tc->flags &= ~TCF_DECL_DESTRUCTURING;
        5383               9 :             if (!pn3)
        5384               0 :                 return NULL;
        5385               9 :             break;
        5386                 : #endif
        5387                 :
        5388                 :           case TOK_NAME:
        5389             621 :             name = tokenStream.currentToken().name();
        5390                 :
        5391                 :             /*
        5392                 :              * Create a name node with pn_op JSOP_NAME.  We can't set pn_op to
        5393                 :              * JSOP_GETLOCAL here, because we don't yet know the block's depth
        5394                 :              * in the operand stack frame.  The code generator computes that,
        5395                 :              * and it tries to bind all names to slots, so we must let it do
        5396                 :              * the deed.
        5397                 :              */
        5398             621 :             pn3 = NewBindingNode(name, tc);
        5399             621 :             if (!pn3)
        5400               0 :                 return NULL;
        5401             621 :             break;
        5402                 :
        5403                 :           default:
        5404              54 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NO_VARIABLE_NAME);
        5405                 :
        5406                 :           case TOK_ERROR:
        5407              54 :             return NULL;
        5408                 :         }
        5409                 :
        5410                 :         bool forOf;
        5411             630 :         if (!matchInOrOf(&forOf)) {
        5412               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_IN_AFTER_FOR_NAME);
        5413               0 :             return NULL;
        5414                 :         }
        5415             630 :         if (forOf) {
        5416             153 :             if (pn2->pn_iflags != JSITER_ENUMERATE) {
        5417              27 :                 JS_ASSERT(pn2->pn_iflags == (JSITER_FOREACH | JSITER_ENUMERATE));
        5418              27 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP);
        5419              27 :                 return NULL;
        5420                 :             }
        5421             126 :             pn2->pn_iflags = JSITER_FOR_OF;
        5422                 :         }
        5423                 :
        5424             603 :         ParseNode *pn4 = expr();
        5425             603 :         if (!pn4)
        5426               0 :             return NULL;
        5427             603 :         MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
        5428                 :
        5429             549 :         guard.endBody();
        5430                 :
        5431             549 :         if (isGenexp) {
        5432             207 :             if (!guard.checkValidBody(pn2))
        5433               0 :                 return NULL;
        5434                 :         } else {
        5435             342 :             if (!guard.maybeNoteGenerator(pn2))
        5436               0 :                 return NULL;
        5437                 :         }
        5438                 :
        5439             549 :         switch (tt) {
        5440                 : #if JS_HAS_DESTRUCTURING
        5441                 :           case TOK_LB:
        5442                 :           case TOK_LC:
        5443               9 :             if (!CheckDestructuring(context, &data, pn3, tc))
        5444               0 :                 return NULL;
        5445                 :
        5446               9 :             if (versionNumber() == JSVERSION_1_7) {
        5447                 :                 /* Destructuring requires [key, value] enumeration in JS1.7. */
        5448               0 :                 if (!pn3->isKind(PNK_RB) || pn3->pn_count != 2) {
        5449               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_FOR_LEFTSIDE);
        5450               0 :                     return NULL;
        5451                 :                 }
        5452                 :
        5453               0 :                 JS_ASSERT(pn2->isOp(JSOP_ITER));
        5454               0 :                 JS_ASSERT(pn2->pn_iflags & JSITER_ENUMERATE);
        5455               0 :                 if (!(pn2->pn_iflags & JSITER_FOREACH))
        5456               0 :                     pn2->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
        5457                 :             }
        5458               9 :             break;
        5459                 : #endif
        5460                 :
        5461                 :           case TOK_NAME:
        5462             540 :             data.pn = pn3;
        5463             540 :             if (!data.binder(context, &data, name, tc))
        5464               0 :                 return NULL;
        5465             540 :             break;
        5466                 :
        5467                 :           default:;
        5468                 :         }
        5469                 :
        5470                 :         /*
        5471                 :          * Synthesize a declaration. Every definition must appear in the parse
        5472                 :          * tree in order for ComprehensionTranslator to work.
        5473                 :          */
        5474             549 :         ParseNode *vars = ListNode::create(PNK_VAR, tc);
        5475             549 :         if (!vars)
        5476               0 :             return NULL;
        5477             549 :         vars->setOp(JSOP_NOP);
        5478             549 :         vars->pn_pos = pn3->pn_pos;
        5479             549 :         vars->makeEmpty();
        5480             549 :         vars->append(pn3);
        5481             549 :         vars->pn_xflags |= PNX_FORINVAR;
        5482                 :
        5483                 :         /* Definitions can't be passed directly to EmitAssignment as lhs. */
        5484             549 :         pn3 = CloneLeftHandSide(pn3, tc);
        5485             549 :         if (!pn3)
        5486               0 :             return NULL;
        5487                 :
        5488             549 :         pn2->pn_left = new_<TernaryNode>(PNK_FORIN, JSOP_NOP, vars, pn3, pn4);
        5489             549 :         if (!pn2->pn_left)
        5490               0 :             return NULL;
        5491             549 :         *pnp = pn2;
        5492             549 :         pnp = &pn2->pn_right;
        5493             549 :     } while (tokenStream.matchToken(TOK_FOR));
        5494                 :
        5495             522 :     if (tokenStream.matchToken(TOK_IF)) {
        5496               9 :         pn2 = TernaryNode::create(PNK_IF, tc);
        5497               9 :         if (!pn2)
        5498               0 :             return NULL;
        5499               9 :         pn2->pn_kid1 = condition();
        5500               9 :         if (!pn2->pn_kid1)
        5501               0 :             return NULL;
        5502               9 :         *pnp = pn2;
        5503               9 :         pnp = &pn2->pn_kid2;
        5504                 :     }
        5505                 :
        5506             522 :     pn2 = UnaryNode::create(kind, tc);
        5507             522 :     if (!pn2)
        5508               0 :         return NULL;
        5509             522 :     pn2->setOp(op);
        5510             522 :     pn2->pn_kid = kid;
        5511             522 :     *pnp = pn2;
        5512                 :
        5513             522 :     PopStatement(tc);
        5514             522 :     return pn;
        5515                 : }
        5516                 :
        5517                 : #if JS_HAS_GENERATOR_EXPRS
        5518                 :
        5519                 : /*
        5520                 :  * Starting from a |for| keyword after an expression, parse the comprehension
        5521                 :  * tail completing this generator expression. Wrap the expression at kid in a
        5522                 :  * generator function that is immediately called to evaluate to the generator
        5523                 :  * iterator that is the value of this generator expression.
        5524                 :  *
        5525                 :  * |kid| must be the expression before the |for| keyword; we return an
        5526                 :  * application of a generator function that includes the |for| loops and
        5527                 :  * |if| guards, with |kid| as the operand of a |yield| expression as the
        5528                 :  * innermost loop body.
        5529                 :  *
        5530                 :  * Note how unlike Python, we do not evaluate the expression to the right of
        5531                 :  * the first |in| in the chain of |for| heads. Instead, a generator expression
        5532                 :  * is merely sugar for a generator function expression and its application.
        5533                 :  */
        5534                 : ParseNode *
        5535             207 : Parser::generatorExpr(ParseNode *kid)
        5536                 : {
        5537             207 :     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
        5538                 :
        5539                 :     /* Create a |yield| node for |kid|. */
        5540             207 :     ParseNode *pn = UnaryNode::create(PNK_YIELD, tc);
        5541             207 :     if (!pn)
        5542               0 :         return NULL;
        5543             207 :     pn->setOp(JSOP_YIELD);
        5544             207 :     pn->setInParens(true);
        5545             207 :     pn->pn_pos = kid->pn_pos;
        5546             207 :     pn->pn_kid = kid;
        5547             207 :     pn->pn_hidden = true;
        5548                 :
        5549                 :     /* Make a new node for the desugared generator function. */
        5550             207 :     ParseNode *genfn = FunctionNode::create(PNK_FUNCTION, tc);
        5551             207 :     if (!genfn)
        5552               0 :         return NULL;
        5553             207 :     genfn->setOp(JSOP_LAMBDA);
        5554             207 :     JS_ASSERT(!genfn->pn_body);
        5555             207 :     genfn->pn_dflags = 0;
        5556                 :
        5557                 :     {
        5558             207 :         TreeContext *outertc = tc;
        5559             414 :         TreeContext gentc(tc->parser);
        5560             207 :         if (!gentc.init(context))
        5561               0 :             return NULL;
        5562                 :
        5563             207 :         FunctionBox *funbox = EnterFunction(genfn, &gentc);
        5564             207 :         if (!funbox)
        5565               0 :             return NULL;
        5566                 :
        5567                 :         /*
        5568                 :          * We assume conservatively that any deoptimization flag in tc->flags
        5569                 :          * besides TCF_FUN_PARAM_ARGUMENTS can come from the kid. So we
        5570                 :          * propagate these flags into genfn. For code simplicity we also do
        5571                 :          * not detect if the flags were only set in the kid and could be
        5572                 :          * removed from tc->flags.
        5573                 :          */
        5574                 :         gentc.flags |= TCF_FUN_IS_GENERATOR | TCF_GENEXP_LAMBDA |
        5575             207 :                        (outertc->flags & (TCF_FUN_FLAGS & ~TCF_FUN_PARAM_ARGUMENTS));
        5576             207 :         funbox->tcflags |= gentc.flags;
        5577             207 :         genfn->pn_funbox = funbox;
        5578             207 :         genfn->pn_blockid = gentc.bodyid;
        5579                 :
        5580             207 :         ParseNode *body = comprehensionTail(pn, outertc->blockid(), true);
        5581             207 :         if (!body)
        5582               0 :             return NULL;
        5583             207 :         JS_ASSERT(!genfn->pn_body);
        5584             207 :         genfn->pn_body = body;
        5585             207 :         genfn->pn_pos.begin = body->pn_pos.begin = kid->pn_pos.begin;
        5586             207 :         genfn->pn_pos.end = body->pn_pos.end = tokenStream.currentToken().pos.end;
        5587                 :
        5588             207 :         if (!LeaveFunction(genfn, &gentc))
        5589               0 :             return NULL;
        5590                 :     }
        5591                 :
        5592                 :     /*
        5593                 :      * Our result is a call expression that invokes the anonymous generator
        5594                 :      * function object.
        5595                 :      */
        5596             207 :     ParseNode *result = ListNode::create(PNK_LP, tc);
        5597             207 :     if (!result)
        5598               0 :         return NULL;
        5599             207 :     result->setOp(JSOP_CALL);
        5600             207 :     result->pn_pos.begin = genfn->pn_pos.begin;
        5601             207 :     result->initList(genfn);
        5602             207 :     return result;
        5603                 : }
        5604                 :
        5605                 : static const char js_generator_str[] = "generator";
        5606                 :
        5607                 : #endif /* JS_HAS_GENERATOR_EXPRS */
        5608                 : #endif /* JS_HAS_GENERATORS */
        5609                 :
        5610                 : JSBool
        5611          223566 : Parser::argumentList(ParseNode *listNode)
        5612                 : {
        5613          223566 :     if (tokenStream.matchToken(TOK_RP, TSF_OPERAND))
        5614           34165 :         return JS_TRUE;
        5615                 :
        5616          189401 :     GenexpGuard guard(tc);
        5617          189401 :     bool arg0 = true;
        5618                 :
        5619          318922 :     do {
        5620          318932 :         ParseNode *argNode = assignExpr();
        5621          318932 :         if (!argNode)
        5622              10 :             return JS_FALSE;
        5623          318922 :         if (arg0)
        5624          189391 :             guard.endBody();
        5625                 :
        5626                 : #if JS_HAS_GENERATORS
        5627          318922 :         if (argNode->isKind(PNK_YIELD) &&
        5628               0 :             !argNode->isInParens() &&
        5629               0 :             tokenStream.peekToken() == TOK_COMMA) {
        5630               0 :             reportErrorNumber(argNode, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
        5631               0 :             return JS_FALSE;
        5632                 :         }
        5633                 : #endif
        5634                 : #if JS_HAS_GENERATOR_EXPRS
        5635          318922 :         if (tokenStream.matchToken(TOK_FOR)) {
        5636              27 :             if (!guard.checkValidBody(argNode))
        5637               0 :                 return JS_FALSE;
        5638              27 :             argNode = generatorExpr(argNode);
        5639              27 :             if (!argNode)
        5640               0 :                 return JS_FALSE;
        5641              54 :             if (listNode->pn_count > 1 ||
        5642              27 :                 tokenStream.peekToken() == TOK_COMMA) {
        5643                 :                 reportErrorNumber(argNode, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX,
        5644               0 :                                   js_generator_str);
        5645               0 :                 return JS_FALSE;
        5646                 :             }
        5647                 :         } else
        5648                 : #endif
        5649          318895 :         if (arg0 && !guard.maybeNoteGenerator(argNode))
        5650               0 :             return JS_FALSE;
        5651                 :
        5652          318922 :         arg0 = false;
        5653                 :
        5654          318922 :         listNode->append(argNode);
        5655          318922 :     } while (tokenStream.matchToken(TOK_COMMA));
        5656                 :
        5657          189391 :     if (tokenStream.getToken() != TOK_RP) {
        5658               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_PAREN_AFTER_ARGS);
        5659               0 :         return JS_FALSE;
        5660                 :     }
        5661          189391 :     return JS_TRUE;
        5662                 : }
        5663                 :
        5664                 : ParseNode *
        5665         3648825 : Parser::memberExpr(JSBool allowCallSyntax)
        5666                 : {
        5667                 :     ParseNode *lhs;
        5668                 :
        5669         3648825 :     JS_CHECK_RECURSION(context, return NULL);
        5670                 :
        5671                 :     /* Check for new expression first. */
        5672         3648825 :     TokenKind tt = tokenStream.getToken(TSF_OPERAND);
        5673         3648825 :     if (tt == TOK_NEW) {
        5674           34596 :         lhs = ListNode::create(PNK_NEW, tc);
        5675           34596 :         if (!lhs)
        5676               0 :             return NULL;
        5677           34596 :         ParseNode *ctorExpr = memberExpr(JS_FALSE);
        5678           34596 :         if (!ctorExpr)
        5679               0 :             return NULL;
        5680           34596 :         lhs->setOp(JSOP_NEW);
        5681           34596 :         lhs->initList(ctorExpr);
        5682           34596 :         lhs->pn_pos.begin = ctorExpr->pn_pos.begin;
        5683                 :
        5684           34596 :         if (tokenStream.matchToken(TOK_LP) && !argumentList(lhs))
        5685               0 :             return NULL;
        5686           34596 :         if (lhs->pn_count > ARGC_LIMIT) {
        5687                 :             JS_ReportErrorNumber(context, js_GetErrorMessage, NULL,
        5688               0 :                                  JSMSG_TOO_MANY_CON_ARGS);
        5689               0 :             return NULL;
        5690                 :         }
        5691           34596 :         lhs->pn_pos.end = lhs->last()->pn_pos.end;
        5692                 :     } else {
        5693         3614229 :         lhs = primaryExpr(tt, JS_FALSE);
        5694         3614229 :         if (!lhs)
        5695             229 :             return NULL;
        5696                 :
        5697         3614000 :         if (lhs->isXMLNameOp()) {
        5698              90 :             lhs = new_<UnaryNode>(PNK_XMLUNARY, JSOP_XMLNAME, lhs->pn_pos, lhs);
        5699              90 :             if (!lhs)
        5700               0 :                 return NULL;
        5701                 :         }
        5702                 :     }
        5703                 :
        5704         7680860 :     while ((tt = tokenStream.getToken()) > TOK_EOF) {
        5705                 :         ParseNode *nextMember;
        5706         3980784 :         if (tt == TOK_DOT) {
        5707          143210 :             tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
        5708          143210 :             if (tt == TOK_ERROR)
        5709               0 :                 return NULL;
        5710          143210 :             if (tt == TOK_NAME) {
        5711                 : #if JS_HAS_XML_SUPPORT
        5712          143138 :                 if (!tc->inStrictMode() && tokenStream.peekToken() == TOK_DBLCOLON) {
        5713               9 :                     ParseNode *propertyId = propertyQualifiedIdentifier();
        5714               9 :                     if (!propertyId)
        5715               0 :                         return NULL;
        5716                 :
        5717                 :                     nextMember = new_<XMLDoubleColonProperty>(lhs, propertyId,
        5718                 :                                                               lhs->pn_pos.begin,
        5719               9 :                                                               tokenStream.currentToken().pos.end);
        5720               9 :                     if (!nextMember)
        5721               0 :                         return NULL;
        5722                 :                 } else
        5723                 : #endif
        5724                 :                 {
        5725          143129 :                     PropertyName *field = tokenStream.currentToken().name();
        5726                 :                     nextMember = new_<PropertyAccess>(lhs, field,
        5727                 :                                                       lhs->pn_pos.begin,
        5728          143129 :                                                       tokenStream.currentToken().pos.end);
        5729          143129 :                     if (!nextMember)
        5730               0 :                         return NULL;
        5731                 :                 }
        5732                 :             }
        5733                 : #if JS_HAS_XML_SUPPORT
        5734              72 :             else if (!tc->inStrictMode()) {
        5735              72 :                 TokenPtr begin = lhs->pn_pos.begin;
        5736              72 :                 if (tt == TOK_LP) {
        5737                 :                     /* Filters are effectively 'with', so deoptimize names. */
        5738              72 :                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
        5739                 :
        5740                 :                     StmtInfo stmtInfo;
        5741              72 :                     ParseNode *oldWith = tc->innermostWith;
        5742              72 :                     tc->innermostWith = lhs;
        5743              72 :                     PushStatement(tc, &stmtInfo, STMT_WITH, -1);
        5744                 :
        5745              72 :                     ParseNode *filter = bracketedExpr();
        5746              72 :                     if (!filter)
        5747               0 :                         return NULL;
        5748              72 :                     filter->setInParens(true);
        5749              72 :                     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
        5750                 :
        5751              72 :                     tc->innermostWith = oldWith;
        5752              72 :                     PopStatement(tc);
        5753                 :
        5754                 :                     nextMember =
        5755                 :                         new_<XMLFilterExpression>(lhs, filter,
        5756              72 :                                                   begin, tokenStream.currentToken().pos.end);
        5757              72 :                     if (!nextMember)
        5758               0 :                         return NULL;
        5759               0 :                 } else if (tt == TOK_AT || tt == TOK_STAR) {
        5760               0 :                     ParseNode *propertyId = starOrAtPropertyIdentifier(tt);
        5761               0 :                     if (!propertyId)
        5762               0 :                         return NULL;
        5763                 :                     nextMember = new_<XMLProperty>(lhs, propertyId,
        5764               0 :                                                    begin, tokenStream.currentToken().pos.end);
        5765               0 :                     if (!nextMember)
        5766               0 :                         return NULL;
        5767                 :                 } else {
        5768               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT);
        5769               0 :                     return NULL;
        5770                 :                 }
        5771                 :             }
        5772                 : #endif
        5773                 :             else {
        5774               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT);
        5775               0 :                 return NULL;
        5776                 :             }
        5777                 :         }
        5778                 : #if JS_HAS_XML_SUPPORT
        5779         3837574 :         else if (tt == TOK_DBLDOT) {
        5780               9 :             if (tc->inStrictMode()) {
        5781               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT);
        5782               0 :                 return NULL;
        5783                 :             }
        5784                 :
        5785               9 :             nextMember = BinaryNode::create(PNK_DBLDOT, tc);
        5786               9 :             if (!nextMember)
        5787               0 :                 return NULL;
        5788               9 :             tt = tokenStream.getToken(TSF_OPERAND | TSF_KEYWORD_IS_NAME);
        5789               9 :             ParseNode *pn3 = primaryExpr(tt, JS_TRUE);
        5790               9 :             if (!pn3)
        5791               0 :                 return NULL;
        5792               9 :             if (pn3->isKind(PNK_NAME) && !pn3->isInParens()) {
        5793               9 :                 pn3->setKind(PNK_STRING);
        5794               9 :                 pn3->setArity(PN_NULLARY);
        5795               9 :                 pn3->setOp(JSOP_QNAMEPART);
        5796               0 :             } else if (!pn3->isXMLPropertyIdentifier()) {
        5797               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT);
        5798               0 :                 return NULL;
        5799                 :             }
        5800               9 :             nextMember->setOp(JSOP_DESCENDANTS);
        5801               9 :             nextMember->pn_left = lhs;
        5802               9 :             nextMember->pn_right = pn3;
        5803               9 :             nextMember->pn_pos.begin = lhs->pn_pos.begin;
        5804               9 :             nextMember->pn_pos.end = tokenStream.currentToken().pos.end;
        5805                 :         }
        5806                 : #endif
        5807         3837565 :         else if (tt == TOK_LB) {
        5808           49445 :             ParseNode *propExpr = expr();
        5809           49445 :             if (!propExpr)
        5810               0 :                 return NULL;
        5811                 :
        5812           49445 :             MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
        5813           49445 :             TokenPtr begin = lhs->pn_pos.begin, end = tokenStream.currentToken().pos.end;
        5814                 :
        5815                 :             /*
        5816                 :              * Optimize property name lookups.  If the name is a PropertyName,
        5817                 :              * then make a name-based node so the emitter will use a name-based
        5818                 :              * bytecode.  Otherwise make a node using the property expression
        5819                 :              * by value.  If the node is a string containing an index, convert
        5820                 :              * it to a number to save work later.
        5821                 :              */
        5822                 :             uint32_t index;
        5823           49445 :             PropertyName *name = NULL;
        5824           49445 :             if (propExpr->isKind(PNK_STRING)) {
        5825             180 :                 JSAtom *atom = propExpr->pn_atom;
        5826             180 :                 if (atom->isIndex(&index)) {
        5827               9 :                     propExpr->setKind(PNK_NUMBER);
        5828               9 :                     propExpr->setOp(JSOP_DOUBLE);
        5829               9 :                     propExpr->pn_dval = index;
        5830                 :                 } else {
        5831             171 :                     name = atom->asPropertyName();
        5832                 :                 }
        5833           49265 :             } else if (propExpr->isKind(PNK_NUMBER)) {
        5834                 :                 JSAtom *atom;
        5835           18402 :                 if (!js_ValueToAtom(context, NumberValue(propExpr->pn_dval), &atom))
        5836               0 :                     return NULL;
        5837           18402 :                 if (!atom->isIndex(&index))
        5838              72 :                     name = atom->asPropertyName();
        5839                 :             }
        5840                 :
        5841           49445 :             if (name)
        5842             243 :                 nextMember = new_<PropertyAccess>(lhs, name, begin, end);
        5843                 :             else
        5844           49202 :                 nextMember = new_<PropertyByValue>(lhs, propExpr, begin, end);
        5845           49445 :             if (!nextMember)
        5846               0 :                 return NULL;
        5847         3788120 :         } else if (allowCallSyntax && tt == TOK_LP) {
        5848          191014 :             nextMember = ListNode::create(PNK_LP, tc);
        5849          191014 :             if (!nextMember)
        5850               0 :                 return NULL;
        5851          191014 :             nextMember->setOp(JSOP_CALL);
        5852                 :
        5853          191014 :             if (lhs->isOp(JSOP_NAME)) {
        5854          120748 :                 if (lhs->pn_atom == context->runtime->atomState.evalAtom) {
        5855                 :                     /* Select JSOP_EVAL and flag tc as heavyweight. */
        5856            4453 :                     nextMember->setOp(JSOP_EVAL);
        5857            4453 :                     tc->noteCallsEval();
        5858            4453 :                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
        5859                 :                     /*
        5860                 :                      * In non-strict mode code, direct calls to eval can add
        5861                 :                      * variables to the call object.
        5862                 :                      */
        5863            4453 :                     if (!tc->inStrictMode())
        5864            4165 :                         tc->noteHasExtensibleScope();
        5865                 :                 }
        5866           70266 :             } else if (lhs->isOp(JSOP_GETPROP)) {
        5867                 :                 /* Select JSOP_FUNAPPLY given foo.apply(...). */
        5868           62296 :                 if (lhs->pn_atom == context->runtime->atomState.applyAtom)
        5869            1179 :                     nextMember->setOp(JSOP_FUNAPPLY);
        5870           61117 :                 else if (lhs->pn_atom == context->runtime->atomState.callAtom)
        5871            2198 :                     nextMember->setOp(JSOP_FUNCALL);
        5872                 :             }
        5873                 :
        5874          191014 :             nextMember->initList(lhs);
        5875          191014 :             nextMember->pn_pos.begin = lhs->pn_pos.begin;
        5876                 :
        5877          191014 :             if (!argumentList(nextMember))
        5878              10 :                 return NULL;
        5879          191004 :             if (nextMember->pn_count > ARGC_LIMIT) {
        5880                 :                 JS_ReportErrorNumber(context, js_GetErrorMessage, NULL,
        5881               0 :                                      JSMSG_TOO_MANY_FUN_ARGS);
        5882               0 :                 return NULL;
        5883                 :             }
        5884          191004 :             nextMember->pn_pos.end = tokenStream.currentToken().pos.end;
        5885                 :         } else {
        5886         3597106 :             tokenStream.ungetToken();
        5887         3597106 :             return lhs;
        5888                 :         }
        5889                 :
        5890          383668 :         lhs = nextMember;
        5891                 :     }
        5892           51480 :     if (tt == TOK_ERROR)
        5893               0 :         return NULL;
        5894           51480 :     return lhs;
        5895                 : }
        5896                 :
        5897                 : ParseNode *
        5898          231165 : Parser::bracketedExpr()
        5899                 : {
        5900                 :     unsigned oldflags;
        5901                 :     ParseNode *pn;
        5902                 :
        5903                 :     /*
        5904                 :      * Always accept the 'in' operator in a parenthesized expression,
        5905                 :      * where it's unambiguous, even if we might be parsing the init of a
        5906                 :      * for statement.
        5907                 :      */
        5908          231165 :     oldflags = tc->flags;
        5909          231165 :     tc->flags &= ~TCF_IN_FOR_INIT;
        5910          231165 :     pn = expr();
        5911          231165 :     tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
        5912          231165 :     return pn;
        5913                 : }
        5914                 :
        5915                 : #if JS_HAS_XML_SUPPORT
        5916                 :
        5917                 : ParseNode *
        5918               0 : Parser::endBracketedExpr()
        5919                 : {
        5920               0 :     JS_ASSERT(!tc->inStrictMode());
        5921                 :
        5922               0 :     ParseNode *pn = bracketedExpr();
        5923               0 :     if (!pn)
        5924               0 :         return NULL;
        5925                 :
        5926               0 :     MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_ATTR_EXPR);
        5927               0 :     return pn;
        5928                 : }
        5929                 :
        5930                 : /*
        5931                 :  * From the ECMA-357 grammar in 11.1.1 and 11.1.2:
        5932                 :  *
        5933                 :  *      AttributeIdentifier:
        5934                 :  *              @ PropertySelector
        5935                 :  *              @ QualifiedIdentifier
        5936                 :  *              @ [ Expression ]
        5937                 :  *
        5938                 :  *      PropertySelector:
        5939                 :  *              Identifier
        5940                 :  *              *
        5941                 :  *
        5942                 :  *      QualifiedIdentifier:
        5943                 :  *              PropertySelector :: PropertySelector
        5944                 :  *              PropertySelector :: [ Expression ]
        5945                 :  *
        5946                 :  * We adapt AttributeIdentifier and QualifiedIdentier to be LL(1), like so:
        5947                 :  *
        5948                 :  *      AttributeIdentifier:
        5949                 :  *              @ QualifiedIdentifier
        5950                 :  *              @ [ Expression ]
        5951                 :  *
        5952                 :  *      PropertySelector:
        5953                 :  *              Identifier
        5954                 :  *              *
        5955                 :  *
        5956                 :  *      QualifiedIdentifier:
        5957                 :  *              PropertySelector :: PropertySelector
        5958                 :  *              PropertySelector :: [ Expression ]
        5959                 :  *              PropertySelector
        5960                 :  *
        5961                 :  * As PrimaryExpression: Identifier is in ECMA-262 and we want the semantics
        5962                 :  * for that rule to result in a name node, but ECMA-357 extends the grammar
        5963                 :  * to include PrimaryExpression: QualifiedIdentifier, we must factor further:
        5964                 :  *
        5965                 :  *      QualifiedIdentifier:
        5966                 :  *              PropertySelector QualifiedSuffix
        5967                 :  *
        5968                 :  *      QualifiedSuffix:
        5969                 :  *              :: PropertySelector
        5970                 :  *              :: [ Expression ]
        5971                 :  *              /nothing/
        5972                 :  *
        5973                 :  * And use this production instead of PrimaryExpression: QualifiedIdentifier:
        5974                 :  *
        5975                 :  *      PrimaryExpression:
        5976                 :  *              Identifier QualifiedSuffix
        5977                 :  *
        5978                 :  * We hoist the :: match into callers of QualifiedSuffix, in order to tweak
        5979                 :  * PropertySelector vs. Identifier pn_arity, pn_op, and other members.
        5980                 :  */
        5981                 : ParseNode *
        5982              54 : Parser::propertySelector()
        5983                 : {
        5984              54 :     JS_ASSERT(!tc->inStrictMode());
        5985                 :
        5986                 :     ParseNode *selector;
        5987              54 :     if (tokenStream.isCurrentTokenType(TOK_STAR)) {
        5988              45 :         selector = NullaryNode::create(PNK_ANYNAME, tc);
        5989              45 :         if (!selector)
        5990               0 :             return NULL;
        5991              45 :         selector->setOp(JSOP_ANYNAME);
        5992              45 :         selector->pn_atom = context->runtime->atomState.starAtom;
        5993                 :     } else {
        5994               9 :         JS_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME));
        5995               9 :         selector = NullaryNode::create(PNK_NAME, tc);
        5996               9 :         if (!selector)
        5997               0 :             return NULL;
        5998               9 :         selector->setOp(JSOP_QNAMEPART);
        5999               9 :         selector->setArity(PN_NAME);
        6000               9 :         selector->pn_atom = tokenStream.currentToken().name();
        6001               9 :         selector->pn_cookie.makeFree();
        6002                 :     }
        6003              54 :     return selector;
        6004                 : }
        6005                 :
        6006                 : ParseNode *
        6007              72 : Parser::qualifiedSuffix(ParseNode *pn)
        6008                 : {
        6009              72 :     JS_ASSERT(!tc->inStrictMode());
        6010                 :
        6011              72 :     JS_ASSERT(tokenStream.currentToken().type == TOK_DBLCOLON);
        6012              72 :     ParseNode *pn2 = NameNode::create(PNK_DBLCOLON, NULL, tc);
        6013              72 :     if (!pn2)
        6014               0 :         return NULL;
        6015                 :
        6016                 :     /* This qualifiedSuffice may refer to 'arguments'. */
        6017              72 :     tc->flags |= TCF_FUN_HEAVYWEIGHT;
        6018              72 :     tc->noteLocalOverwritesArguments();
        6019                 :
        6020                 :     /* Left operand of :: must be evaluated if it is an identifier. */
        6021              72 :     if (pn->isOp(JSOP_QNAMEPART))
        6022               0 :         pn->setOp(JSOP_NAME);
        6023                 :
        6024              72 :     TokenKind tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
        6025              72 :     if (tt == TOK_STAR || tt == TOK_NAME) {
        6026                 :         /* Inline and specialize propertySelector for JSOP_QNAMECONST. */
        6027              72 :         pn2->setOp(JSOP_QNAMECONST);
        6028              72 :         pn2->pn_pos.begin = pn->pn_pos.begin;
        6029                 :         pn2->pn_atom = (tt == TOK_STAR)
        6030                 :                        ? context->runtime->atomState.starAtom
        6031              72 :                        : tokenStream.currentToken().name();
        6032              72 :         pn2->pn_expr = pn;
        6033              72 :         pn2->pn_cookie.makeFree();
        6034              72 :         return pn2;
        6035                 :     }
        6036                 :
        6037               0 :     if (tt != TOK_LB) {
        6038               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
        6039               0 :         return NULL;
        6040                 :     }
        6041               0 :     ParseNode *pn3 = endBracketedExpr();
        6042               0 :     if (!pn3)
        6043               0 :         return NULL;
        6044                 :
        6045               0 :     pn2->setOp(JSOP_QNAME);
        6046               0 :     pn2->setArity(PN_BINARY);
        6047               0 :     pn2->pn_pos.begin = pn->pn_pos.begin;
        6048               0 :     pn2->pn_pos.end = pn3->pn_pos.end;
        6049               0 :     pn2->pn_left = pn;
        6050               0 :     pn2->pn_right = pn3;
        6051               0 :     return pn2;
        6052                 : }
        6053                 :
        6054                 : ParseNode *
        6055              54 : Parser::qualifiedIdentifier()
        6056                 : {
        6057              54 :     JS_ASSERT(!tc->inStrictMode());
        6058                 :
        6059              54 :     ParseNode *pn = propertySelector();
        6060              54 :     if (!pn)
        6061               0 :         return NULL;
        6062              54 :     if (tokenStream.matchToken(TOK_DBLCOLON)) {
        6063                 :         /* Hack for bug 496316. Slowing down E4X won't make it go away, alas. */
        6064              27 :         tc->flags |= TCF_FUN_HEAVYWEIGHT;
        6065              27 :         tc->noteLocalOverwritesArguments();
        6066              27 :         pn = qualifiedSuffix(pn);
        6067                 :     }
        6068              54 :     return pn;
        6069                 : }
        6070                 :
        6071                 : ParseNode *
        6072               9 : Parser::attributeIdentifier()
        6073                 : {
        6074               9 :     JS_ASSERT(!tc->inStrictMode());
        6075                 :
        6076               9 :     JS_ASSERT(tokenStream.currentToken().type == TOK_AT);
        6077               9 :     ParseNode *pn = UnaryNode::create(PNK_AT, tc);
        6078               9 :     if (!pn)
        6079               0 :         return NULL;
        6080               9 :     pn->setOp(JSOP_TOATTRNAME);
        6081                 :
        6082                 :     ParseNode *pn2;
        6083               9 :     TokenKind tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
        6084               9 :     if (tt == TOK_STAR || tt == TOK_NAME) {
        6085               9 :         pn2 = qualifiedIdentifier();
        6086               0 :     } else if (tt == TOK_LB) {
        6087               0 :         pn2 = endBracketedExpr();
        6088                 :     } else {
        6089               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
        6090               0 :         return NULL;
        6091                 :     }
        6092               9 :     if (!pn2)
        6093               0 :         return NULL;
        6094               9 :     pn->pn_kid = pn2;
        6095               9 :     return pn;
        6096                 : }
        6097                 :
        6098                 : /*
        6099                 :  * Make a TOK_LC unary node whose pn_kid is an expression.
        6100                 :  */
        6101                 : ParseNode *
        6102               0 : Parser::xmlExpr(JSBool inTag)
        6103                 : {
        6104               0 :     JS_ASSERT(!tc->inStrictMode());
        6105                 :
        6106               0 :     JS_ASSERT(tokenStream.currentToken().type == TOK_LC);
        6107               0 :     ParseNode *pn = UnaryNode::create(PNK_XMLCURLYEXPR, tc);
        6108               0 :     if (!pn)
        6109               0 :         return NULL;
        6110                 :
        6111                 :     /*
        6112                 :      * Turn off XML tag mode. We save the old value of the flag because it may
        6113                 :      * already be off: XMLExpr is called both from within a tag, and from
        6114                 :      * within text contained in an element, but outside of any start, end, or
        6115                 :      * point tag.
        6116                 :      */
        6117               0 :     bool oldflag = tokenStream.isXMLTagMode();
        6118               0 :     tokenStream.setXMLTagMode(false);
        6119               0 :     ParseNode *pn2 = expr();
        6120               0 :     if (!pn2)
        6121               0 :         return NULL;
        6122                 :
        6123               0 :     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_XML_EXPR);
        6124               0 :     tokenStream.setXMLTagMode(oldflag);
        6125               0 :     pn->pn_kid = pn2;
        6126               0 :     pn->setOp(inTag ? JSOP_XMLTAGEXPR : JSOP_XMLELTEXPR);
        6127               0 :     return pn;
        6128                 : }
        6129                 :
        6130                 : ParseNode *
        6131          297581 : Parser::atomNode(ParseNodeKind kind, JSOp op)
        6132                 : {
        6133          297581 :     ParseNode *node = NullaryNode::create(kind, tc);
        6134          297581 :     if (!node)
        6135               0 :         return NULL;
        6136          297581 :     node->setOp(op);
        6137          297581 :     const Token &tok = tokenStream.currentToken();
        6138          297581 :     node->pn_atom = tok.atom();
        6139          297581 :     return node;
        6140                 : }
        6141                 :
        6142                 : /*
        6143                 :  * Parse the productions:
        6144                 :  *
        6145                 :  *      XMLNameExpr:
        6146                 :  *              XMLName XMLNameExpr?
        6147                 :  *              { Expr } XMLNameExpr?
        6148                 :  *
        6149                 :  * Return a PN_LIST, PN_UNARY, or PN_NULLARY according as XMLNameExpr produces
        6150                 :  * a list of names and/or expressions, a single expression, or a single name.
        6151                 :  * If PN_LIST or PN_NULLARY, getKind() will be PNK_XMLNAME.  Otherwise if
        6152                 :  * PN_UNARY, getKind() will be PNK_XMLCURLYEXPR.
        6153                 :  */
        6154                 : ParseNode *
        6155            5695 : Parser::xmlNameExpr()
        6156                 : {
        6157            5695 :     JS_ASSERT(!tc->inStrictMode());
        6158                 :
        6159                 :     ParseNode *pn, *pn2, *list;
        6160                 :     TokenKind tt;
        6161                 :
        6162            5695 :     pn = list = NULL;
        6163            5695 :     do {
        6164            5695 :         tt = tokenStream.currentToken().type;
        6165            5695 :         if (tt == TOK_LC) {
        6166               0 :             pn2 = xmlExpr(JS_TRUE);
        6167               0 :             if (!pn2)
        6168               0 :                 return NULL;
        6169                 :         } else {
        6170            5695 :             JS_ASSERT(tt == TOK_XMLNAME);
        6171            5695 :             JS_ASSERT(tokenStream.currentToken().t_op == JSOP_STRING);
        6172            5695 :             pn2 = atomNode(PNK_XMLNAME, JSOP_STRING);
        6173            5695 :             if (!pn2)
        6174               0 :                 return NULL;
        6175                 :         }
        6176                 :
        6177            5695 :         if (!pn) {
        6178            5695 :             pn = pn2;
        6179                 :         } else {
        6180               0 :             if (!list) {
        6181               0 :                 list = ListNode::create(PNK_XMLNAME, tc);
        6182               0 :                 if (!list)
        6183               0 :                     return NULL;
        6184               0 :                 list->pn_pos.begin = pn->pn_pos.begin;
        6185               0 :                 list->initList(pn);
        6186               0 :                 list->pn_xflags = PNX_CANTFOLD;
        6187               0 :                 pn = list;
        6188                 :             }
        6189               0 :             pn->pn_pos.end = pn2->pn_pos.end;
        6190               0 :             pn->append(pn2);
        6191                 :         }
        6192            5695 :     } while ((tt = tokenStream.getToken()) == TOK_XMLNAME || tt == TOK_LC);
        6193                 :
        6194            5695 :     tokenStream.ungetToken();
        6195            5695 :     return pn;
        6196                 : }
        6197                 :
        6198                 : /*
        6199                 :  * Macro to test whether an XMLNameExpr or XMLTagContent node can be folded
        6200                 :  * at compile time into a JSXML tree.
        6201                 :  */
        6202                 : #define XML_FOLDABLE(pn)        ((pn)->isArity(PN_LIST)                     \
        6203                 :                                  ? ((pn)->pn_xflags & PNX_CANTFOLD) == 0    \
        6204                 :                                  : !(pn)->isKind(PNK_XMLCURLYEXPR))
        6205                 :
        6206                 : /*
        6207                 :  * Parse the productions:
        6208                 :  *
        6209                 :  *      XMLTagContent:
        6210                 :  *              XMLNameExpr
        6211                 :  *              XMLTagContent S XMLNameExpr S? = S? XMLAttr
        6212                 :  *              XMLTagContent S XMLNameExpr S? = S? { Expr }
        6213                 :  *
        6214                 :  * Return a PN_LIST, PN_UNARY, or PN_NULLARY according to how XMLTagContent
        6215                 :  * produces a list of name and attribute values and/or braced expressions, a
        6216                 :  * single expression, or a single name.
        6217                 :  *
        6218                 :  * If PN_LIST or PN_NULLARY, getKind() will be PNK_XMLNAME for the case where
        6219                 :  * XMLTagContent: XMLNameExpr.  If getKind() is not PNK_XMLNAME but getArity()
        6220                 :  * is PN_LIST, getKind() will be tagkind.  If PN_UNARY, getKind() will be
        6221                 :  * PNK_XMLCURLYEXPR and we parsed exactly one expression.
        6222                 :  */
        6223                 : ParseNode *
        6224            4299 : Parser::xmlTagContent(ParseNodeKind tagkind, JSAtom **namep)
        6225                 : {
        6226            4299 :     JS_ASSERT(!tc->inStrictMode());
        6227                 :
        6228                 :     ParseNode *pn, *pn2, *list;
        6229                 :     TokenKind tt;
        6230                 :
        6231            4299 :     pn = xmlNameExpr();
        6232            4299 :     if (!pn)
        6233               0 :         return NULL;
        6234            4299 :     *namep = (pn->isArity(PN_NULLARY)) ? pn->pn_atom : NULL;
        6235            4299 :     list = NULL;
        6236                 :
        6237            9994 :     while (tokenStream.matchToken(TOK_XMLSPACE)) {
        6238            1396 :         tt = tokenStream.getToken();
        6239            1396 :         if (tt != TOK_XMLNAME && tt != TOK_LC) {
        6240               0 :             tokenStream.ungetToken();
        6241               0 :             break;
        6242                 :         }
        6243                 :
        6244            1396 :         pn2 = xmlNameExpr();
        6245            1396 :         if (!pn2)
        6246               0 :             return NULL;
        6247            1396 :         if (!list) {
        6248            1396 :             list = ListNode::create(tagkind, tc);
        6249            1396 :             if (!list)
        6250               0 :                 return NULL;
        6251            1396 :             list->pn_pos.begin = pn->pn_pos.begin;
        6252            1396 :             list->initList(pn);
        6253            1396 :             pn = list;
        6254                 :         }
        6255            1396 :         pn->append(pn2);
        6256            1396 :         if (!XML_FOLDABLE(pn2))
        6257               0 :             pn->pn_xflags |= PNX_CANTFOLD;
        6258                 :
        6259            1396 :         tokenStream.matchToken(TOK_XMLSPACE);
        6260            1396 :         MUST_MATCH_TOKEN(TOK_ASSIGN, JSMSG_NO_ASSIGN_IN_XML_ATTR);
        6261            1396 :         tokenStream.matchToken(TOK_XMLSPACE);
        6262                 :
        6263            1396 :         tt = tokenStream.getToken();
        6264            1396 :         if (tt == TOK_XMLATTR) {
        6265            1396 :             JS_ASSERT(tokenStream.currentToken().t_op == JSOP_STRING);
        6266            1396 :             pn2 = atomNode(PNK_XMLATTR, JSOP_STRING);
        6267               0 :         } else if (tt == TOK_LC) {
        6268               0 :             pn2 = xmlExpr(JS_TRUE);
        6269               0 :             pn->pn_xflags |= PNX_CANTFOLD;
        6270                 :         } else {
        6271               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_ATTR_VALUE);
        6272               0 :             return NULL;
        6273                 :         }
        6274            1396 :         if (!pn2)
        6275               0 :             return NULL;
        6276            1396 :         pn->pn_pos.end = pn2->pn_pos.end;
        6277            1396 :         pn->append(pn2);
        6278                 :     }
        6279                 :
        6280            4299 :     return pn;
        6281                 : }
        6282                 :
        6283                 : #define XML_CHECK_FOR_ERROR_AND_EOF(tt,result)                                              \
        6284                 :     JS_BEGIN_MACRO                                                                          \
        6285                 :         if ((tt) <= TOK_EOF) {                                                              \
        6286                 :             if ((tt) == TOK_EOF) {                                                          \
        6287                 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_END_OF_XML_SOURCE);           \
        6288                 :             }                                                                               \
        6289                 :             return result;                                                                  \
        6290                 :         }                                                                                   \
        6291                 :     JS_END_MACRO
        6292                 :
        6293                 : /*
        6294                 :  * Consume XML element tag content, including the TOK_XMLETAGO (</) sequence
        6295                 :  * that opens the end tag for the container.
        6296                 :  */
        6297                 : JSBool
        6298            1929 : Parser::xmlElementContent(ParseNode *pn)
        6299                 : {
        6300            1929 :     JS_ASSERT(!tc->inStrictMode());
        6301                 :
        6302            1929 :     tokenStream.setXMLTagMode(false);
        6303             703 :     for (;;) {
        6304            2632 :         TokenKind tt = tokenStream.getToken(TSF_XMLTEXTMODE);
        6305            2632 :         XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE);
        6306                 :
        6307            2632 :         JS_ASSERT(tt == TOK_XMLSPACE || tt == TOK_XMLTEXT);
        6308            2632 :         JSAtom *textAtom = tokenStream.currentToken().atom();
        6309            2632 :         if (textAtom) {
        6310                 :             /* Non-zero-length XML text scanned. */
        6311             909 :             JS_ASSERT(tokenStream.currentToken().t_op == JSOP_STRING);
        6312                 :             ParseNode *pn2 = atomNode(tt == TOK_XMLSPACE ? PNK_XMLSPACE : PNK_XMLTEXT,
        6313             909 :                                       JSOP_STRING);
        6314             909 :             if (!pn2)
        6315               0 :                 return false;
        6316             909 :             pn->pn_pos.end = pn2->pn_pos.end;
        6317             909 :             pn->append(pn2);
        6318                 :         }
        6319                 :
        6320            2632 :         tt = tokenStream.getToken(TSF_OPERAND);
        6321            2632 :         XML_CHECK_FOR_ERROR_AND_EOF(tt, JS_FALSE);
        6322            2632 :         if (tt == TOK_XMLETAGO)
        6323                 :             break;
        6324                 :
        6325                 :         ParseNode *pn2;
        6326             703 :         if (tt == TOK_LC) {
        6327               0 :             pn2 = xmlExpr(JS_FALSE);
        6328               0 :             if (!pn2)
        6329               0 :                 return false;
        6330               0 :             pn->pn_xflags |= PNX_CANTFOLD;
        6331             703 :         } else if (tt == TOK_XMLSTAGO) {
        6332             703 :             pn2 = xmlElementOrList(JS_FALSE);
        6333             703 :             if (!pn2)
        6334               0 :                 return false;
        6335             703 :             pn2->pn_xflags &= ~PNX_XMLROOT;
        6336             703 :             pn->pn_xflags |= pn2->pn_xflags;
        6337               0 :         } else if (tt == TOK_XMLPI) {
        6338               0 :             const Token &tok = tokenStream.currentToken();
        6339               0 :             pn2 = new_<XMLProcessingInstruction>(tok.xmlPITarget(), tok.xmlPIData(), tok.pos);
        6340               0 :             if (!pn2)
        6341               0 :                 return false;
        6342                 :         } else {
        6343               0 :             JS_ASSERT(tt == TOK_XMLCDATA || tt == TOK_XMLCOMMENT);
        6344                 :             pn2 = atomNode(tt == TOK_XMLCDATA ? PNK_XMLCDATA : PNK_XMLCOMMENT,
        6345               0 :                            tokenStream.currentToken().t_op);
        6346               0 :             if (!pn2)
        6347               0 :                 return false;
        6348                 :         }
        6349             703 :         pn->pn_pos.end = pn2->pn_pos.end;
        6350             703 :         pn->append(pn2);
        6351                 :     }
        6352            1929 :     tokenStream.setXMLTagMode(true);
        6353                 :
        6354            1929 :     JS_ASSERT(tokenStream.currentToken().type == TOK_XMLETAGO);
        6355            1929 :     return JS_TRUE;
        6356                 : }
        6357                 :
        6358                 : /*
        6359                 :  * Return a PN_LIST node containing an XML or XMLList Initialiser.
        6360                 :  */
        6361                 : ParseNode *
        6362            2406 : Parser::xmlElementOrList(JSBool allowList)
        6363                 : {
        6364            2406 :     JS_ASSERT(!tc->inStrictMode());
        6365                 :
        6366                 :     ParseNode *pn, *pn2, *list;
        6367                 :     TokenKind tt;
        6368                 :     JSAtom *startAtom, *endAtom;
        6369                 :
        6370            2406 :     JS_CHECK_RECURSION(context, return NULL);
        6371                 :
        6372            2406 :     JS_ASSERT(tokenStream.currentToken().type == TOK_XMLSTAGO);
        6373            2406 :     pn = ListNode::create(PNK_XMLSTAGO, tc);
        6374            2406 :     if (!pn)
        6375               0 :         return NULL;
        6376                 :
        6377            2406 :     tokenStream.setXMLTagMode(true);
        6378            2406 :     tt = tokenStream.getToken();
        6379            2406 :     if (tt == TOK_ERROR)
        6380               0 :         return NULL;
        6381                 :
        6382            2406 :     if (tt == TOK_XMLNAME || tt == TOK_LC) {
        6383                 :         /*
        6384                 :          * XMLElement.  Append the tag and its contents, if any, to pn.
        6385                 :          */
        6386            2388 :         pn2 = xmlTagContent(PNK_XMLSTAGO, &startAtom);
        6387            2388 :         if (!pn2)
        6388               0 :             return NULL;
        6389            2388 :         tokenStream.matchToken(TOK_XMLSPACE);
        6390                 :
        6391            2388 :         tt = tokenStream.getToken();
        6392            2388 :         if (tt == TOK_XMLPTAGC) {
        6393                 :             /* Point tag (/>): recycle pn if pn2 is a list of tag contents. */
        6394             477 :             if (pn2->isKind(PNK_XMLSTAGO)) {
        6395              18 :                 pn->makeEmpty();
        6396              18 :                 freeTree(pn);
        6397              18 :                 pn = pn2;
        6398                 :             } else {
        6399             459 :                 JS_ASSERT(pn2->isKind(PNK_XMLNAME) || pn2->isKind(PNK_XMLCURLYEXPR));
        6400             459 :                 pn->initList(pn2);
        6401             459 :                 if (!XML_FOLDABLE(pn2))
        6402               0 :                     pn->pn_xflags |= PNX_CANTFOLD;
        6403                 :             }
        6404             477 :             pn->setKind(PNK_XMLPTAGC);
        6405             477 :             pn->pn_xflags |= PNX_XMLROOT;
        6406                 :         } else {
        6407                 :             /* We had better have a tag-close (>) at this point. */
        6408            1911 :             if (tt != TOK_XMLTAGC) {
        6409               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX);
        6410               0 :                 return NULL;
        6411                 :             }
        6412            1911 :             pn2->pn_pos.end = tokenStream.currentToken().pos.end;
        6413                 :
        6414                 :             /* Make sure pn2 is a TOK_XMLSTAGO list containing tag contents. */
        6415            1911 :             if (!pn2->isKind(PNK_XMLSTAGO)) {
        6416             533 :                 pn->initList(pn2);
        6417             533 :                 if (!XML_FOLDABLE(pn2))
        6418               0 :                     pn->pn_xflags |= PNX_CANTFOLD;
        6419             533 :                 pn2 = pn;
        6420             533 :                 pn = ListNode::create(PNK_XMLTAGC, tc);
        6421             533 :                 if (!pn)
        6422               0 :                     return NULL;
        6423                 :             }
        6424                 :
        6425                 :             /* Now make pn a nominal-root TOK_XMLELEM list containing pn2. */
        6426            1911 :             pn->setKind(PNK_XMLELEM);
        6427            1911 :             pn->pn_pos.begin = pn2->pn_pos.begin;
        6428            1911 :             pn->initList(pn2);
        6429            1911 :             if (!XML_FOLDABLE(pn2))
        6430               0 :                 pn->pn_xflags |= PNX_CANTFOLD;
        6431            1911 :             pn->pn_xflags |= PNX_XMLROOT;
        6432                 :
        6433                 :             /* Get element contents and delimiting end-tag-open sequence. */
        6434            1911 :             if (!xmlElementContent(pn))
        6435               0 :                 return NULL;
        6436                 :
        6437            1911 :             tt = tokenStream.getToken();
        6438            1911 :             XML_CHECK_FOR_ERROR_AND_EOF(tt, NULL);
        6439            1911 :             if (tt != TOK_XMLNAME && tt != TOK_LC) {
        6440               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX);
        6441               0 :                 return NULL;
        6442                 :             }
        6443                 :
        6444                 :             /* Parse end tag; check mismatch at compile-time if we can. */
        6445            1911 :             pn2 = xmlTagContent(PNK_XMLETAGO, &endAtom);
        6446            1911 :             if (!pn2)
        6447               0 :                 return NULL;
        6448            1911 :             if (pn2->isKind(PNK_XMLETAGO)) {
        6449                 :                 /* Oops, end tag has attributes! */
        6450               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX);
        6451               0 :                 return NULL;
        6452                 :             }
        6453            1911 :             if (endAtom && startAtom && endAtom != startAtom) {
        6454                 :                 /* End vs. start tag name mismatch: point to the tag name. */
        6455                 :                 reportErrorNumber(pn2, JSREPORT_UC | JSREPORT_ERROR, JSMSG_XML_TAG_NAME_MISMATCH,
        6456               0 :                                   startAtom->chars());
        6457               0 :                 return NULL;
        6458                 :             }
        6459                 :
        6460                 :             /* Make a TOK_XMLETAGO list with pn2 as its single child. */
        6461            1911 :             JS_ASSERT(pn2->isKind(PNK_XMLNAME) || pn2->isKind(PNK_XMLCURLYEXPR));
        6462            1911 :             list = ListNode::create(PNK_XMLETAGO, tc);
        6463            1911 :             if (!list)
        6464               0 :                 return NULL;
        6465            1911 :             list->initList(pn2);
        6466            1911 :             pn->append(list);
        6467            1911 :             if (!XML_FOLDABLE(pn2)) {
        6468               0 :                 list->pn_xflags |= PNX_CANTFOLD;
        6469               0 :                 pn->pn_xflags |= PNX_CANTFOLD;
        6470                 :             }
        6471                 :
        6472            1911 :             tokenStream.matchToken(TOK_XMLSPACE);
        6473            1911 :             MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_TAG_SYNTAX);
        6474                 :         }
        6475                 :
        6476                 :         /* Set pn_op now that pn has been updated to its final value. */
        6477            2388 :         pn->setOp(JSOP_TOXML);
        6478              18 :     } else if (allowList && tt == TOK_XMLTAGC) {
        6479                 :         /* XMLList Initialiser. */
        6480              18 :         pn->setKind(PNK_XMLLIST);
        6481              18 :         pn->setOp(JSOP_TOXMLLIST);
        6482              18 :         pn->makeEmpty();
        6483              18 :         pn->pn_xflags |= PNX_XMLROOT;
        6484              18 :         if (!xmlElementContent(pn))
        6485               0 :             return NULL;
        6486                 :
        6487              18 :         MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_LIST_SYNTAX);
        6488                 :     } else {
        6489               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_NAME_SYNTAX);
        6490               0 :         return NULL;
        6491                 :     }
        6492            2406 :     tokenStream.setXMLTagMode(false);
        6493                 :
        6494            2406 :     pn->pn_pos.end = tokenStream.currentToken().pos.end;
        6495            2406 :     return pn;
        6496                 : }
        6497                 :
        6498                 : ParseNode *
        6499            1703 : Parser::xmlElementOrListRoot(JSBool allowList)
        6500                 : {
        6501            1703 :     JS_ASSERT(!tc->inStrictMode());
        6502                 :
        6503                 :     /*
        6504                 :      * Force XML support to be enabled so that comments and CDATA literals
        6505                 :      * are recognized, instead of <! followed by -- starting an HTML comment
        6506                 :      * to end of line (used in script tags to hide content from old browsers
        6507                 :      * that don't recognize <script>).
        6508                 :      */
        6509            1703 :     bool hadXML = tokenStream.hasXML();
        6510            1703 :     tokenStream.setXML(true);
        6511            1703 :     ParseNode *pn = xmlElementOrList(allowList);
        6512            1703 :     tokenStream.setXML(hadXML);
        6513            1703 :     return pn;
        6514                 : }
        6515                 :
        6516                 : ParseNode *
        6517            1378 : Parser::parseXMLText(JSObject *chain, bool allowList)
        6518                 : {
        6519                 :     /*
        6520                 :      * Push a compiler frame if we have no frames, or if the top frame is a
        6521                 :      * lightweight function activation, or if its scope chain doesn't match
        6522                 :      * the one passed to us.
        6523                 :      */
        6524            2756 :     TreeContext xmltc(this);
        6525            1378 :     if (!xmltc.init(context))
        6526               0 :         return NULL;
        6527            1378 :     JS_ASSERT(!xmltc.inStrictMode());
        6528            1378 :     xmltc.setScopeChain(chain);
        6529                 :
        6530                 :     /* Set XML-only mode to turn off special treatment of {expr} in XML. */
        6531            1378 :     tokenStream.setXMLOnlyMode();
        6532            1378 :     TokenKind tt = tokenStream.getToken(TSF_OPERAND);
        6533                 :
        6534                 :     ParseNode *pn;
        6535            1378 :     if (tt != TOK_XMLSTAGO) {
        6536               0 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_MARKUP);
        6537               0 :         pn = NULL;
        6538                 :     } else {
        6539            1378 :         pn = xmlElementOrListRoot(allowList);
        6540                 :     }
        6541            1378 :     tokenStream.setXMLOnlyMode(false);
        6542                 :
        6543            1378 :     return pn;
        6544                 : }
        6545                 :
        6546                 : #endif /* JS_HAS_XMLSUPPORT */
        6547                 :
        6548                 : bool
        6549               9 : Parser::checkForFunctionNode(PropertyName *name, ParseNode *node)
        6550                 : {
        6551                 :     /*
        6552                 :      * In |a.ns::name|, |ns| refers to an in-scope variable, so |ns| can't be a
        6553                 :      * keyword.  (Exception: |function::name| is the actual name property, not
        6554                 :      * what E4X would expose.)  We parsed |ns| accepting a keyword as a name,
        6555                 :      * so we must implement the keyword restriction manually in this case.
        6556                 :      */
        6557               9 :     if (const KeywordInfo *ki = FindKeyword(name->charsZ(), name->length())) {
        6558               9 :         if (ki->tokentype != TOK_FUNCTION) {
        6559               0 :             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_KEYWORD_NOT_NS);
        6560               0 :             return false;
        6561                 :         }
        6562                 :
        6563               9 :         node->setArity(PN_NULLARY);
        6564               9 :         node->setKind(PNK_FUNCTION);
        6565                 :     }
        6566                 :
        6567               9 :     return true;
        6568                 : }
        6569                 :
        6570                 : #if JS_HAS_XML_SUPPORT
        6571                 : ParseNode *
        6572               9 : Parser::propertyQualifiedIdentifier()
        6573                 : {
        6574               9 :     JS_ASSERT(!tc->inStrictMode());
        6575               9 :     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME));
        6576               9 :     JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NAME);
        6577               9 :     JS_ASSERT(tokenStream.peekToken() == TOK_DBLCOLON);
        6578                 :
        6579                 :     /* Deoptimize QualifiedIdentifier properties to avoid tricky analysis. */
        6580               9 :     tc->flags |= TCF_FUN_HEAVYWEIGHT;
        6581               9 :     tc->noteLocalOverwritesArguments();
        6582                 :
        6583               9 :     PropertyName *name = tokenStream.currentToken().name();
        6584               9 :     ParseNode *node = NameNode::create(PNK_NAME, name, tc);
        6585               9 :     if (!node)
        6586               0 :         return NULL;
        6587               9 :     node->setOp(JSOP_NAME);
        6588               9 :     node->pn_dflags |= PND_DEOPTIMIZED;
        6589                 :
        6590               9 :     if (!checkForFunctionNode(name, node))
        6591               0 :         return NULL;
        6592                 :
        6593               9 :     tokenStream.consumeKnownToken(TOK_DBLCOLON);
        6594               9 :     return qualifiedSuffix(node);
        6595                 : }
        6596                 : #endif
        6597                 :
        6598                 : ParseNode *
        6599         2494533 : Parser::identifierName(bool afterDoubleDot)
        6600                 : {
        6601         2494533 :     JS_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME));
        6602                 :
        6603         2494533 :     PropertyName *name = tokenStream.currentToken().name();
        6604         2494533 :     ParseNode *node = NameNode::create(PNK_NAME, name, tc);
        6605         2494533 :     if (!node)
        6606               0 :         return NULL;
        6607         2494533 :     JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NAME);
        6608         2494533 :     node->setOp(JSOP_NAME);
        6609                 :
        6610         2494533 :     if ((tc->flags & (TCF_IN_FUNCTION | TCF_FUN_PARAM_ARGUMENTS)) == TCF_IN_FUNCTION &&
        6611                 :         name == context->runtime->atomState.argumentsAtom)
        6612                 :     {
        6613                 :         /*
        6614                 :          * Bind early to JSOP_ARGUMENTS to relieve later code from having
        6615                 :          * to do this work (new rule for the emitter to count on).
        6616                 :          */
        6617            8586 :         if (!afterDoubleDot) {
        6618                 :             /*
        6619                 :              * Note use of |arguments| to ensure we can properly create the
        6620                 :              * |arguments| object for this function.
        6621                 :              */
        6622            4284 :             tc->noteArgumentsNameUse(node);
        6623                 :
        6624            4284 :             if (!(tc->flags & TCF_DECL_DESTRUCTURING) && !tc->inStatement(STMT_WITH)) {
        6625            4284 :                 node->setOp(JSOP_ARGUMENTS);
        6626            4284 :                 node->pn_dflags |= PND_BOUND;
        6627                 :             }
        6628                 :         }
        6629         4980480 :     } else if ((!afterDoubleDot
        6630                 : #if JS_HAS_XML_SUPPORT
        6631               0 :                 || (!tc->inStrictMode() && tokenStream.peekToken() == TOK_DBLCOLON)
        6632                 : #endif
        6633         2490240 :                ) && !(tc->flags & TCF_DECL_DESTRUCTURING))
        6634                 :     {
        6635                 :         /* In case this is a generator expression outside of any function. */
        6636         2485992 :         if (!tc->inFunction() && name == context->runtime->atomState.argumentsAtom)
        6637             350 :             tc->countArgumentsUse(node);
        6638                 :
        6639         2485992 :         StmtInfo *stmt = LexicalLookup(tc, name, NULL);
        6640                 :
        6641         2485992 :         MultiDeclRange mdl = tc->decls.lookupMulti(name);
        6642                 :
        6643                 :         Definition *dn;
        6644         2485992 :         if (!mdl.empty()) {
        6645          697132 :             dn = mdl.front();
        6646                 :         } else {
        6647         3577720 :             if (AtomDefnAddPtr p = tc->lexdeps->lookupForAdd(name)) {
        6648         1557469 :                 dn = p.value();
        6649                 :             } else {
        6650                 :                 /*
        6651                 :                  * No definition before this use in any lexical scope.
        6652                 :                  * Create a placeholder definition node to either:
        6653                 :                  * - Be adopted when we parse the real defining
        6654                 :                  *   declaration, or
        6655                 :                  * - Be left as a free variable definition if we never
        6656                 :                  *   see the real definition.
        6657                 :                  */
        6658          231391 :                 dn = MakePlaceholder(node, tc);
        6659          231391 :                 if (!dn || !tc->lexdeps->add(p, name, dn))
        6660               0 :                     return NULL;
        6661                 :             }
        6662                 :         }
        6663                 :
        6664         2485992 :         JS_ASSERT(dn->isDefn());
        6665         2485992 :         LinkUseToDef(node, dn, tc);
        6666                 :
        6667         2485992 :         if (stmt && stmt->type == STMT_WITH)
        6668             720 :             node->pn_dflags |= PND_DEOPTIMIZED;
        6669                 :     }
        6670                 :
        6671                 : #if JS_HAS_XML_SUPPORT
        6672         2494533 :     if (!tc->inStrictMode() && tokenStream.matchToken(TOK_DBLCOLON)) {
        6673               9 :         if (afterDoubleDot) {
        6674               0 :             if (!checkForFunctionNode(name, node))
        6675               0 :                 return NULL;
        6676                 :         }
        6677               9 :         node = qualifiedSuffix(node);
        6678               9 :         if (!node)
        6679               0 :             return NULL;
        6680                 :     }
        6681                 : #endif
        6682                 :
        6683         2494533 :     return node;
        6684                 : }
        6685                 :
        6686                 : #if JS_HAS_XML_SUPPORT
        6687                 : ParseNode *
        6688              72 : Parser::starOrAtPropertyIdentifier(TokenKind tt)
        6689                 : {
        6690              72 :     JS_ASSERT(tt == TOK_AT || tt == TOK_STAR);
        6691              72 :     if (tc->inStrictMode()) {
        6692              18 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
        6693              18 :         return NULL;
        6694                 :     }
        6695              54 :     return (tt == TOK_AT) ? attributeIdentifier() : qualifiedIdentifier();
        6696                 : }
        6697                 : #endif
        6698                 :
        6699                 : ParseNode *
        6700         3621600 : Parser::primaryExpr(TokenKind tt, bool afterDoubleDot)
        6701                 : {
        6702         3621600 :     JS_ASSERT(tokenStream.isCurrentTokenType(tt));
        6703                 :
        6704                 :     ParseNode *pn, *pn2, *pn3;
        6705                 :     JSOp op;
        6706                 :
        6707         3621600 :     JS_CHECK_RECURSION(context, return NULL);
        6708                 :
        6709         3621600 :     switch (tt) {
        6710                 :       case TOK_FUNCTION:
        6711                 : #if JS_HAS_XML_SUPPORT
        6712          127680 :         if (!tc->inStrictMode() && tokenStream.matchToken(TOK_DBLCOLON, TSF_KEYWORD_IS_NAME)) {
        6713              27 :             pn2 = NullaryNode::create(PNK_FUNCTION, tc);
        6714              27 :             if (!pn2)
        6715               0 :                 return NULL;
        6716              27 :             pn = qualifiedSuffix(pn2);
        6717              27 :             if (!pn)
        6718               0 :                 return NULL;
        6719              27 :             break;
        6720                 :         }
        6721                 : #endif
        6722          127653 :         pn = functionExpr();
        6723          127653 :         if (!pn)
        6724               9 :             return NULL;
        6725          127644 :         break;
        6726                 :
        6727                 :       case TOK_LB:
        6728                 :       {
        6729                 :         JSBool matched;
        6730                 :         unsigned index;
        6731                 :
        6732           28294 :         pn = ListNode::create(PNK_RB, tc);
        6733           28294 :         if (!pn)
        6734               0 :             return NULL;
        6735           28294 :         pn->setOp(JSOP_NEWINIT);
        6736           28294 :         pn->makeEmpty();
        6737                 :
        6738                 : #if JS_HAS_GENERATORS
        6739           28294 :         pn->pn_blockid = tc->blockidGen;
        6740                 : #endif
        6741                 :
        6742           28294 :         matched = tokenStream.matchToken(TOK_RB, TSF_OPERAND);
        6743           28294 :         if (!matched) {
        6744           64831 :             for (index = 0; ; index++) {
        6745           64831 :                 if (index == StackSpace::ARGS_LENGTH_MAX) {
        6746               0 :                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_ARRAY_INIT_TOO_BIG);
        6747               0 :                     return NULL;
        6748                 :                 }
        6749                 :
        6750           64831 :                 tt = tokenStream.peekToken(TSF_OPERAND);
        6751           64831 :                 if (tt == TOK_RB) {
        6752             603 :                     pn->pn_xflags |= PNX_ENDCOMMA;
        6753             603 :                     break;
        6754                 :                 }
        6755                 :
        6756           64228 :                 if (tt == TOK_COMMA) {
        6757                 :                     /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */
        6758            5922 :                     tokenStream.matchToken(TOK_COMMA);
        6759            5922 :                     pn2 = NullaryNode::create(PNK_COMMA, tc);
        6760            5922 :                     pn->pn_xflags |= PNX_HOLEY | PNX_NONCONST;
        6761                 :                 } else {
        6762           58306 :                     pn2 = assignExpr();
        6763           58306 :                     if (pn2 && !pn2->isConstant())
        6764           18704 :                         pn->pn_xflags |= PNX_NONCONST;
        6765                 :                 }
        6766           64228 :                 if (!pn2)
        6767               0 :                     return NULL;
        6768           64228 :                 pn->append(pn2);
        6769                 :
        6770           64228 :                 if (tt != TOK_COMMA) {
        6771                 :                     /* If we didn't already match TOK_COMMA in above case. */
        6772           58306 :                     if (!tokenStream.matchToken(TOK_COMMA))
        6773           18029 :                         break;
        6774                 :                 }
        6775                 :             }
        6776                 :
        6777                 : #if JS_HAS_GENERATORS
        6778                 :             /*
        6779                 :              * At this point, (index == 0 && pn->pn_count != 0) implies one
        6780                 :              * element initialiser was parsed.
        6781                 :              *
        6782                 :              * An array comprehension of the form:
        6783                 :              *
        6784                 :              *   [i * j for (i in o) for (j in p) if (i != j)]
        6785                 :              *
        6786                 :              * translates to roughly the following let expression:
        6787                 :              *
        6788                 :              *   let (array = new Array, i, j) {
        6789                 :              *     for (i in o) let {
        6790                 :              *       for (j in p)
        6791                 :              *         if (i != j)
        6792                 :              *           array.push(i * j)
        6793                 :              *     }
        6794                 :              *     array
        6795                 :              *   }
        6796                 :              *
        6797                 :              * where array is a nameless block-local variable. The "roughly"
        6798                 :              * means that an implementation may optimize away the array.push.
        6799                 :              * An array comprehension opens exactly one block scope, no matter
        6800                 :              * how many for heads it contains.
        6801                 :              *
        6802                 :              * Each let () {...} or for (let ...) ... compiles to:
        6803                 :              *
        6804                 :              *   JSOP_ENTERBLOCK <o> ... JSOP_LEAVEBLOCK <n>
        6805                 :              *
        6806                 :              * where <o> is a literal object representing the block scope,
        6807                 :              * with <n> properties, naming each var declared in the block.
        6808                 :              *
        6809                 :              * Each var declaration in a let-block binds a name in <o> at
        6810                 :              * compile time, and allocates a slot on the operand stack at
        6811                 :              * runtime via JSOP_ENTERBLOCK. A block-local var is accessed by
        6812                 :              * the JSOP_GETLOCAL and JSOP_SETLOCAL ops. These ops have an
        6813                 :              * immediate operand, the local slot's stack index from fp->spbase.
        6814                 :              *
        6815                 :              * The array comprehension iteration step, array.push(i * j) in
        6816                 :              * the example above, is done by <i * j>; JSOP_ARRAYCOMP <array>,
        6817                 :              * where <array> is the index of array's stack slot.
        6818                 :              */
        6819           18632 :             if (index == 0 && pn->pn_count != 0 && tokenStream.matchToken(TOK_FOR)) {
        6820                 :                 ParseNode *pnexp, *pntop;
        6821                 :
        6822                 :                 /* Relabel pn as an array comprehension node. */
        6823             450 :                 pn->setKind(PNK_ARRAYCOMP);
        6824                 :
        6825                 :                 /*
        6826                 :                  * Remove the comprehension expression from pn's linked list
        6827                 :                  * and save it via pnexp.  We'll re-install it underneath the
        6828                 :                  * ARRAYPUSH node after we parse the rest of the comprehension.
        6829                 :                  */
        6830             450 :                 pnexp = pn->last();
        6831             450 :                 JS_ASSERT(pn->pn_count == 1);
        6832             450 :                 pn->pn_count = 0;
        6833             450 :                 pn->pn_tail = &pn->pn_head;
        6834             450 :                 *pn->pn_tail = NULL;
        6835                 :
        6836                 :                 pntop = comprehensionTail(pnexp, pn->pn_blockid, false,
        6837             450 :                                           PNK_ARRAYPUSH, JSOP_ARRAYPUSH);
        6838             450 :                 if (!pntop)
        6839             135 :                     return NULL;
        6840             315 :                 pn->append(pntop);
        6841                 :             }
        6842                 : #endif /* JS_HAS_GENERATORS */
        6843                 :
        6844           18497 :             MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_LIST);
        6845                 :         }
        6846           28159 :         pn->pn_pos.end = tokenStream.currentToken().pos.end;
        6847           28159 :         return pn;
        6848                 :       }
        6849                 :
        6850                 :       case TOK_LC:
        6851                 :       {
        6852                 :         ParseNode *pnval;
        6853                 :
        6854                 :         /*
        6855                 :          * A map from property names we've seen thus far to a mask of property
        6856                 :          * assignment types, stored and retrieved with ALE_SET_INDEX/ALE_INDEX.
        6857                 :          */
        6858           31626 :         AtomIndexMap seen(context);
        6859                 :
        6860                 :         enum AssignmentType {
        6861                 :             GET     = 0x1,
        6862                 :             SET     = 0x2,
        6863                 :             VALUE   = 0x4 | GET | SET
        6864                 :         };
        6865                 :
        6866           15813 :         pn = ListNode::create(PNK_RC, tc);
        6867           15813 :         if (!pn)
        6868               0 :             return NULL;
        6869           15813 :         pn->setOp(JSOP_NEWINIT);
        6870           15813 :         pn->makeEmpty();
        6871                 :
        6872           15220 :         for (;;) {
        6873                 :             JSAtom *atom;
        6874           31033 :             TokenKind ltok = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
        6875           31033 :             TokenPtr begin = tokenStream.currentToken().pos.begin;
        6876           31033 :             switch (ltok) {
        6877                 :               case TOK_NUMBER:
        6878             531 :                 pn3 = NullaryNode::create(PNK_NUMBER, tc);
        6879             531 :                 if (!pn3)
        6880               0 :                     return NULL;
        6881             531 :                 pn3->pn_dval = tokenStream.currentToken().number();
        6882             531 :                 if (!js_ValueToAtom(context, DoubleValue(pn3->pn_dval), &atom))
        6883               0 :                     return NULL;
        6884             531 :                 break;
        6885                 :               case TOK_NAME:
        6886                 :                 {
        6887           16905 :                     atom = tokenStream.currentToken().name();
        6888           16905 :                     if (atom == context->runtime->atomState.getAtom) {
        6889             567 :                         op = JSOP_GETTER;
        6890           16338 :                     } else if (atom == context->runtime->atomState.setAtom) {
        6891             379 :                         op = JSOP_SETTER;
        6892                 :                     } else {
        6893           15959 :                         pn3 = NullaryNode::create(PNK_NAME, tc);
        6894           15959 :                         if (!pn3)
        6895               0 :                             return NULL;
        6896           15959 :                         pn3->pn_atom = atom;
        6897           15959 :                         break;
        6898                 :                     }
        6899                 :
        6900             946 :                     tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
        6901             946 :                     if (tt == TOK_NAME) {
        6902             297 :                         atom = tokenStream.currentToken().name();
        6903             297 :                         pn3 = NameNode::create(PNK_NAME, atom, tc);
        6904             297 :                         if (!pn3)
        6905               0 :                             return NULL;
        6906             649 :                     } else if (tt == TOK_STRING) {
        6907               0 :                         atom = tokenStream.currentToken().atom();
        6908                 :
        6909                 :                         uint32_t index;
        6910               0 :                         if (atom->isIndex(&index)) {
        6911               0 :                             pn3 = NullaryNode::create(PNK_NUMBER, tc);
        6912               0 :                             if (!pn3)
        6913               0 :                                 return NULL;
        6914               0 :                             pn3->pn_dval = index;
        6915               0 :                             if (!js_ValueToAtom(context, DoubleValue(pn3->pn_dval), &atom))
        6916               0 :                                 return NULL;
        6917                 :                         } else {
        6918               0 :                             pn3 = NameNode::create(PNK_STRING, atom, tc);
        6919               0 :                             if (!pn3)
        6920               0 :                                 return NULL;
        6921                 :                         }
        6922             649 :                     } else if (tt == TOK_NUMBER) {
        6923               0 :                         pn3 = NullaryNode::create(PNK_NUMBER, tc);
        6924               0 :                         if (!pn3)
        6925               0 :                             return NULL;
        6926               0 :                         pn3->pn_dval = tokenStream.currentToken().number();
        6927               0 :                         if (!js_ValueToAtom(context, DoubleValue(pn3->pn_dval), &atom))
        6928               0 :                             return NULL;
        6929                 :                     } else {
        6930             649 :                         tokenStream.ungetToken();
        6931             649 :                         pn3 = NullaryNode::create(PNK_NAME, tc);
        6932             649 :                         if (!pn3)
        6933               0 :                             return NULL;
        6934             649 :                         pn3->pn_atom = atom;
        6935             649 :                         break;
        6936                 :                     }
        6937                 :
        6938             297 :                     pn->pn_xflags |= PNX_NONCONST;
        6939                 :
        6940                 :                     /* NB: Getter function in { get x(){} } is unnamed. */
        6941             297 :                     pn2 = functionDef(NULL, op == JSOP_GETTER ? Getter : Setter, Expression);
        6942             297 :                     if (!pn2)
        6943               0 :                         return NULL;
        6944             297 :                     TokenPos pos = {begin, pn2->pn_pos.end};
        6945             297 :                     pn2 = new_<BinaryNode>(PNK_COLON, op, pos, pn3, pn2);
        6946             297 :                     goto skip;
        6947                 :                 }
        6948                 :               case TOK_STRING: {
        6949            7875 :                 atom = tokenStream.currentToken().atom();
        6950                 :                 uint32_t index;
        6951            7875 :                 if (atom->isIndex(&index)) {
        6952             513 :                     pn3 = NullaryNode::create(PNK_NUMBER, tc);
        6953             513 :                     if (!pn3)
        6954               0 :                         return NULL;
        6955             513 :                     pn3->pn_dval = index;
        6956                 :                 } else {
        6957            7362 :                     pn3 = NullaryNode::create(PNK_STRING, tc);
        6958            7362 :                     if (!pn3)
        6959               0 :                         return NULL;
        6960            7362 :                     pn3->pn_atom = atom;
        6961                 :                 }
        6962            7875 :                 break;
        6963                 :               }
        6964                 :               case TOK_RC:
        6965            5722 :                 goto end_obj_init;
        6966                 :               default:
        6967               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_PROP_ID);
        6968               0 :                 return NULL;
        6969                 :             }
        6970                 :
        6971           25014 :             op = JSOP_INITPROP;
        6972           25014 :             tt = tokenStream.getToken();
        6973           25014 :             if (tt == TOK_COLON) {
        6974           24816 :                 pnval = assignExpr();
        6975           24816 :                 if (!pnval)
        6976               9 :                     return NULL;
        6977                 :
        6978                 :                 /*
        6979                 :                  * Treat initializers which mutate __proto__ as non-constant,
        6980                 :                  * so that we can later assume singleton objects delegate to
        6981                 :                  * the default Object.prototype.
        6982                 :                  */
        6983           24807 :                 if (!pnval->isConstant() || atom == context->runtime->atomState.protoAtom)
        6984           12806 :                     pn->pn_xflags |= PNX_NONCONST;
        6985                 :             }
        6986                 : #if JS_HAS_DESTRUCTURING_SHORTHAND
        6987             198 :             else if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC)) {
        6988                 :                 /*
        6989                 :                  * Support, e.g., |var {x, y} = o| as destructuring shorthand
        6990                 :                  * for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8.
        6991                 :                  */
        6992             198 :                 tokenStream.ungetToken();
        6993             198 :                 if (!tokenStream.checkForKeyword(atom->charsZ(), atom->length(), NULL, NULL))
        6994               0 :                     return NULL;
        6995             198 :                 pn->pn_xflags |= PNX_DESTRUCT | PNX_NONCONST;
        6996             198 :                 pnval = pn3;
        6997             198 :                 JS_ASSERT(pnval->isKind(PNK_NAME));
        6998             198 :                 pnval->setArity(PN_NAME);
        6999             198 :                 ((NameNode *)pnval)->initCommon(tc);
        7000                 :             }
        7001                 : #endif
        7002                 :             else {
        7003               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_COLON_AFTER_ID);
        7004               0 :                 return NULL;
        7005                 :             }
        7006                 :
        7007                 :             {
        7008           25005 :                 TokenPos pos = {begin, pnval->pn_pos.end};
        7009           25005 :                 pn2 = new_<BinaryNode>(PNK_COLON, op, pos, pn3, pnval);
        7010                 :             }
        7011                 :           skip:
        7012           25302 :             if (!pn2)
        7013               0 :                 return NULL;
        7014           25302 :             pn->append(pn2);
        7015                 :
        7016                 :             /*
        7017                 :              * Check for duplicate property names.  Duplicate data properties
        7018                 :              * only conflict in strict mode.  Duplicate getter or duplicate
        7019                 :              * setter halves always conflict.  A data property conflicts with
        7020                 :              * any part of an accessor property.
        7021                 :              */
        7022                 :             AssignmentType assignType;
        7023           25302 :             if (op == JSOP_INITPROP) {
        7024           25005 :                 assignType = VALUE;
        7025             297 :             } else if (op == JSOP_GETTER) {
        7026             207 :                 assignType = GET;
        7027              90 :             } else if (op == JSOP_SETTER) {
        7028              90 :                 assignType = SET;
        7029                 :             } else {
        7030               0 :                 JS_NOT_REACHED("bad opcode in object initializer");
        7031                 :                 assignType = VALUE; /* try to error early */
        7032                 :             }
        7033                 :
        7034           50604 :             AtomIndexAddPtr p = seen.lookupForAdd(atom);
        7035           25302 :             if (p) {
        7036              90 :                 jsatomid index = p.value();
        7037              90 :                 AssignmentType oldAssignType = AssignmentType(index);
        7038             144 :                 if ((oldAssignType & assignType) &&
        7039              54 :                     (oldAssignType != VALUE || assignType != VALUE || tc->needStrictChecks()))
        7040                 :                 {
        7041               0 :                     JSAutoByteString name;
        7042               0 :                     if (!js_AtomToPrintableString(context, atom, &name))
        7043               0 :                         return NULL;
        7044                 :
        7045                 :                     unsigned flags = (oldAssignType == VALUE &&
        7046                 :                                    assignType == VALUE &&
        7047               0 :                                    !tc->inStrictMode())
        7048                 :                                   ? JSREPORT_WARNING
        7049               0 :                                   : JSREPORT_ERROR;
        7050               0 :                     if (!ReportCompileErrorNumber(context, &tokenStream, NULL, flags,
        7051               0 :                                                   JSMSG_DUPLICATE_PROPERTY, name.ptr()))
        7052                 :                     {
        7053               0 :                         return NULL;
        7054                 :                     }
        7055                 :                 }
        7056              90 :                 p.value() = assignType | oldAssignType;
        7057                 :             } else {
        7058           25212 :                 if (!seen.add(p, atom, assignType))
        7059               0 :                     return NULL;
        7060                 :             }
        7061                 :
        7062           25302 :             tt = tokenStream.getToken();
        7063           25302 :             if (tt == TOK_RC)
        7064                 :                 goto end_obj_init;
        7065           15220 :             if (tt != TOK_COMMA) {
        7066               0 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_CURLY_AFTER_LIST);
        7067               0 :                 return NULL;
        7068                 :             }
        7069                 :         }
        7070                 :
        7071                 :       end_obj_init:
        7072           15804 :         pn->pn_pos.end = tokenStream.currentToken().pos.end;
        7073           15804 :         return pn;
        7074                 :       }
        7075                 :
        7076                 : #if JS_HAS_BLOCK_SCOPE
        7077                 :       case TOK_LET:
        7078            1765 :         pn = letBlock(LetExpresion);
        7079            1765 :         if (!pn)
        7080               0 :             return NULL;
        7081            1765 :         break;
        7082                 : #endif
        7083                 :
        7084                 :       case TOK_LP:
        7085                 :       {
        7086                 :         JSBool genexp;
        7087                 :
        7088          133831 :         pn = parenExpr(&genexp);
        7089          133831 :         if (!pn)
        7090              27 :             return NULL;
        7091          133804 :         pn->setInParens(true);
        7092          133804 :         if (!genexp)
        7093          133624 :             MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
        7094          133804 :         break;
        7095                 :       }
        7096                 :
        7097                 :       case TOK_STRING:
        7098          289554 :         pn = atomNode(PNK_STRING, JSOP_STRING);
        7099          289554 :         if (!pn)
        7100               0 :             return NULL;
        7101          289554 :         break;
        7102                 :
        7103                 : #if JS_HAS_XML_SUPPORT
        7104                 :       case TOK_AT:
        7105                 :       case TOK_STAR:
        7106              72 :         pn = starOrAtPropertyIdentifier(tt);
        7107              72 :         break;
        7108                 :
        7109                 :       case TOK_XMLSTAGO:
        7110             325 :         pn = xmlElementOrListRoot(JS_TRUE);
        7111             325 :         if (!pn)
        7112               0 :             return NULL;
        7113             325 :         break;
        7114                 :
        7115                 :       case TOK_XMLCDATA:
        7116              27 :         JS_ASSERT(!tc->inStrictMode());
        7117              27 :         pn = atomNode(PNK_XMLCDATA, JSOP_XMLCDATA);
        7118              27 :         if (!pn)
        7119               0 :             return NULL;
        7120              27 :         break;
        7121                 :
        7122                 :       case TOK_XMLCOMMENT:
        7123               0 :         JS_ASSERT(!tc->inStrictMode());
        7124               0 :         pn = atomNode(PNK_XMLCOMMENT, JSOP_XMLCOMMENT);
        7125               0 :         if (!pn)
        7126               0 :             return NULL;
        7127               0 :         break;
        7128                 :
        7129                 :       case TOK_XMLPI: {
        7130               0 :         JS_ASSERT(!tc->inStrictMode());
        7131               0 :         const Token &tok = tokenStream.currentToken();
        7132               0 :         pn = new_<XMLProcessingInstruction>(tok.xmlPITarget(), tok.xmlPIData(), tok.pos);
        7133               0 :         if (!pn)
        7134               0 :             return NULL;
        7135               0 :         break;
        7136                 :       }
        7137                 : #endif
        7138                 :
        7139                 :       case TOK_NAME:
        7140         2494533 :         pn = identifierName(afterDoubleDot);
        7141         2494533 :         break;
        7142                 :
        7143                 :       case TOK_REGEXP:
        7144                 :       {
        7145            3686 :         pn = NullaryNode::create(PNK_REGEXP, tc);
        7146            3686 :         if (!pn)
        7147               0 :             return NULL;
        7148                 :
        7149            3686 :         const jschar *chars = tokenStream.getTokenbuf().begin();
        7150            3686 :         size_t length = tokenStream.getTokenbuf().length();
        7151            3686 :         RegExpFlag flags = tokenStream.currentToken().regExpFlags();
        7152            3686 :         RegExpStatics *res = context->regExpStatics();
        7153                 :
        7154                 :         RegExpObject *reobj;
        7155            3686 :         if (context->hasfp())
        7156             126 :             reobj = RegExpObject::create(context, res, chars, length, flags, &tokenStream);
        7157                 :         else
        7158            3560 :             reobj = RegExpObject::createNoStatics(context, chars, length, flags, &tokenStream);
        7159                 :
        7160            3686 :         if (!reobj)
        7161               9 :             return NULL;
        7162                 :
        7163            3677 :         if (!tc->compileAndGo()) {
        7164              18 :             if (!reobj->clearParent(context))
        7165               0 :                 return NULL;
        7166              18 :             if (!reobj->clearType(context))
        7167               0 :                 return NULL;
        7168                 :         }
        7169                 :
        7170            3677 :         pn->pn_objbox = tc->parser->newObjectBox(reobj);
        7171            3677 :         if (!pn->pn_objbox)
        7172               0 :             return NULL;
        7173                 :
        7174            3677 :         pn->setOp(JSOP_REGEXP);
        7175            3677 :         break;
        7176                 :       }
        7177                 :
        7178                 :       case TOK_NUMBER:
        7179          399588 :         pn = NullaryNode::create(PNK_NUMBER, tc);
        7180          399588 :         if (!pn)
        7181               0 :             return NULL;
        7182          399588 :         pn->setOp(JSOP_DOUBLE);
        7183          399588 :         pn->pn_dval = tokenStream.currentToken().number();
        7184          399588 :         break;
        7185                 :
        7186                 :       case TOK_TRUE:
        7187           12483 :         return new_<BooleanLiteral>(true, tokenStream.currentToken().pos);
        7188                 :       case TOK_FALSE:
        7189            9484 :         return new_<BooleanLiteral>(false, tokenStream.currentToken().pos);
        7190                 :       case TOK_THIS:
        7191           90824 :         return new_<ThisLiteral>(tokenStream.currentToken().pos);
        7192                 :       case TOK_NULL:
        7193           13619 :         return new_<NullLiteral>(tokenStream.currentToken().pos);
        7194                 :
        7195                 :       case TOK_ERROR:
        7196                 :         /* The scanner or one of its subroutines reported the error. */
        7197               0 :         return NULL;
        7198                 :
        7199                 :       default:
        7200              22 :         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
        7201              22 :         return NULL;
        7202                 :     }
        7203         3451016 :     return pn;
        7204                 : }
        7205                 :
        7206                 : ParseNode *
        7207          231093 : Parser::parenExpr(JSBool *genexp)
        7208                 : {
        7209                 :     TokenPtr begin;
        7210                 :     ParseNode *pn;
        7211                 :
        7212          231093 :     JS_ASSERT(tokenStream.currentToken().type == TOK_LP);
        7213          231093 :     begin = tokenStream.currentToken().pos.begin;
        7214                 :
        7215          231093 :     if (genexp)
        7216          133831 :         *genexp = JS_FALSE;
        7217                 :
        7218          231093 :     GenexpGuard guard(tc);
        7219                 :
        7220          231093 :     pn = bracketedExpr();
        7221          231093 :     if (!pn)
        7222              18 :         return NULL;
        7223          231075 :     guard.endBody();
        7224                 :
        7225                 : #if JS_HAS_GENERATOR_EXPRS
        7226          231075 :     if (tokenStream.matchToken(TOK_FOR)) {
        7227             189 :         if (!guard.checkValidBody(pn))
        7228               9 :             return NULL;
        7229             180 :         JS_ASSERT(!pn->isKind(PNK_YIELD));
        7230             180 :         if (pn->isKind(PNK_COMMA) && !pn->isInParens()) {
        7231                 :             reportErrorNumber(pn->last(), JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX,
        7232               0 :                               js_generator_str);
        7233               0 :             return NULL;
        7234                 :         }
        7235             180 :         pn = generatorExpr(pn);
        7236             180 :         if (!pn)
        7237               0 :             return NULL;
        7238             180 :         pn->pn_pos.begin = begin;
        7239             180 :         if (genexp) {
        7240             180 :             if (tokenStream.getToken() != TOK_RP) {
        7241                 :                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX,
        7242               0 :                                   js_generator_str);
        7243               0 :                 return NULL;
        7244                 :             }
        7245             180 :             pn->pn_pos.end = tokenStream.currentToken().pos.end;
        7246             180 :             *genexp = JS_TRUE;
        7247                 :         }
        7248                 :     } else
        7249                 : #endif /* JS_HAS_GENERATOR_EXPRS */
        7250                 :
        7251          230886 :     if (!guard.maybeNoteGenerator(pn))
        7252               0 :         return NULL;
        7253                 :
        7254          231066 :     return pn;
        7255                 : }

Generated by: LCOV version 1.7