PageRenderTime 89ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/js/src/frontend/Parser.cpp

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