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