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