PageRenderTime 96ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/js/src/frontend/Parser.cpp

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