Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef frontend_FullParseHandler_h
8 #define frontend_FullParseHandler_h
10 #include "mozilla/PodOperations.h"
12 #include "frontend/ParseNode.h"
13 #include "frontend/SharedContext.h"
15 namespace js {
16 namespace frontend {
18 template <typename ParseHandler>
19 class Parser;
21 class SyntaxParseHandler;
23 // Parse handler used when generating a full parse tree for all code which the
24 // parser encounters.
25 class FullParseHandler
26 {
27 ParseNodeAllocator allocator;
28 TokenStream &tokenStream;
29 bool foldConstants;
31 ParseNode *allocParseNode(size_t size) {
32 JS_ASSERT(size == sizeof(ParseNode));
33 return static_cast<ParseNode *>(allocator.allocNode());
34 }
36 ParseNode *cloneNode(const ParseNode &other) {
37 ParseNode *node = allocParseNode(sizeof(ParseNode));
38 if (!node)
39 return nullptr;
40 mozilla::PodAssign(node, &other);
41 return node;
42 }
44 /*
45 * If this is a full parse to construct the bytecode for a function that
46 * was previously lazily parsed, that lazy function and the current index
47 * into its inner functions. We do not want to reparse the inner functions.
48 */
49 LazyScript * const lazyOuterFunction_;
50 size_t lazyInnerFunctionIndex;
52 const TokenPos &pos() {
53 return tokenStream.currentToken().pos;
54 }
56 public:
58 /*
59 * If non-nullptr, points to a syntax parser which can be used for inner
60 * functions. Cleared if language features not handled by the syntax parser
61 * are encountered, in which case all future activity will use the full
62 * parser.
63 */
64 Parser<SyntaxParseHandler> *syntaxParser;
66 /* new_ methods for creating parse nodes. These report OOM on context. */
67 JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
69 typedef ParseNode *Node;
70 typedef Definition *DefinitionNode;
72 FullParseHandler(ExclusiveContext *cx, LifoAlloc &alloc,
73 TokenStream &tokenStream, bool foldConstants,
74 Parser<SyntaxParseHandler> *syntaxParser, LazyScript *lazyOuterFunction)
75 : allocator(cx, alloc),
76 tokenStream(tokenStream),
77 foldConstants(foldConstants),
78 lazyOuterFunction_(lazyOuterFunction),
79 lazyInnerFunctionIndex(0),
80 syntaxParser(syntaxParser)
81 {}
83 static ParseNode *null() { return nullptr; }
85 ParseNode *freeTree(ParseNode *pn) { return allocator.freeTree(pn); }
86 void prepareNodeForMutation(ParseNode *pn) { return allocator.prepareNodeForMutation(pn); }
87 const Token ¤tToken() { return tokenStream.currentToken(); }
89 ParseNode *newName(PropertyName *name, uint32_t blockid, const TokenPos &pos) {
90 return new_<NameNode>(PNK_NAME, JSOP_NAME, name, blockid, pos);
91 }
93 Definition *newPlaceholder(JSAtom *atom, uint32_t blockid, const TokenPos &pos) {
94 Definition *dn =
95 (Definition *) new_<NameNode>(PNK_NAME, JSOP_NOP, atom, blockid, pos);
96 if (!dn)
97 return nullptr;
98 dn->setDefn(true);
99 dn->pn_dflags |= PND_PLACEHOLDER;
100 return dn;
101 }
103 ParseNode *newIdentifier(JSAtom *atom, const TokenPos &pos) {
104 return new_<NullaryNode>(PNK_NAME, JSOP_NOP, pos, atom);
105 }
107 ParseNode *newNumber(double value, DecimalPoint decimalPoint, const TokenPos &pos) {
108 ParseNode *pn = new_<NullaryNode>(PNK_NUMBER, pos);
109 if (!pn)
110 return nullptr;
111 pn->initNumber(value, decimalPoint);
112 return pn;
113 }
115 ParseNode *newBooleanLiteral(bool cond, const TokenPos &pos) {
116 return new_<BooleanLiteral>(cond, pos);
117 }
119 ParseNode *newStringLiteral(JSAtom *atom, const TokenPos &pos) {
120 return new_<NullaryNode>(PNK_STRING, JSOP_STRING, pos, atom);
121 }
123 ParseNode *newThisLiteral(const TokenPos &pos) {
124 return new_<ThisLiteral>(pos);
125 }
127 ParseNode *newNullLiteral(const TokenPos &pos) {
128 return new_<NullLiteral>(pos);
129 }
131 // The Boxer object here is any object that can allocate ObjectBoxes.
132 // Specifically, a Boxer has a .newObjectBox(T) method that accepts a
133 // Rooted<RegExpObject*> argument and returns an ObjectBox*.
134 template <class Boxer>
135 ParseNode *newRegExp(HandleObject reobj, const TokenPos &pos, Boxer &boxer) {
136 ObjectBox *objbox = boxer.newObjectBox(reobj);
137 if (!objbox)
138 return null();
139 return new_<RegExpLiteral>(objbox, pos);
140 }
142 ParseNode *newConditional(ParseNode *cond, ParseNode *thenExpr, ParseNode *elseExpr) {
143 return new_<ConditionalExpression>(cond, thenExpr, elseExpr);
144 }
146 void markAsSetCall(ParseNode *pn) {
147 pn->pn_xflags |= PNX_SETCALL;
148 }
150 ParseNode *newDelete(uint32_t begin, ParseNode *expr) {
151 if (expr->getKind() == PNK_NAME) {
152 expr->pn_dflags |= PND_DEOPTIMIZED;
153 expr->setOp(JSOP_DELNAME);
154 }
155 return newUnary(PNK_DELETE, JSOP_NOP, begin, expr);
156 }
158 ParseNode *newNullary(ParseNodeKind kind, JSOp op, const TokenPos &pos) {
159 return new_<NullaryNode>(kind, op, pos);
160 }
162 ParseNode *newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, ParseNode *kid) {
163 TokenPos pos(begin, kid ? kid->pn_pos.end : begin + 1);
164 return new_<UnaryNode>(kind, op, pos, kid);
165 }
167 ParseNode *newBinary(ParseNodeKind kind, JSOp op = JSOP_NOP) {
168 return new_<BinaryNode>(kind, op, pos(), (ParseNode *) nullptr, (ParseNode *) nullptr);
169 }
170 ParseNode *newBinary(ParseNodeKind kind, ParseNode *left,
171 JSOp op = JSOP_NOP) {
172 return new_<BinaryNode>(kind, op, left->pn_pos, left, (ParseNode *) nullptr);
173 }
174 ParseNode *newBinary(ParseNodeKind kind, ParseNode *left, ParseNode *right,
175 JSOp op = JSOP_NOP) {
176 TokenPos pos(left->pn_pos.begin, right->pn_pos.end);
177 return new_<BinaryNode>(kind, op, pos, left, right);
178 }
179 ParseNode *newBinaryOrAppend(ParseNodeKind kind, ParseNode *left, ParseNode *right,
180 ParseContext<FullParseHandler> *pc, JSOp op = JSOP_NOP)
181 {
182 return ParseNode::newBinaryOrAppend(kind, op, left, right, this, pc, foldConstants);
183 }
185 ParseNode *newTernary(ParseNodeKind kind,
186 ParseNode *first, ParseNode *second, ParseNode *third,
187 JSOp op = JSOP_NOP)
188 {
189 return new_<TernaryNode>(kind, op, first, second, third);
190 }
192 // Expressions
194 ParseNode *newArrayComprehension(ParseNode *body, unsigned blockid, const TokenPos &pos) {
195 JS_ASSERT(pos.begin <= body->pn_pos.begin);
196 JS_ASSERT(body->pn_pos.end <= pos.end);
197 ParseNode *pn = new_<ListNode>(PNK_ARRAYCOMP, pos);
198 if (!pn)
199 return nullptr;
200 pn->pn_blockid = blockid;
201 pn->append(body);
202 return pn;
203 }
205 ParseNode *newArrayLiteral(uint32_t begin, unsigned blockid) {
206 ParseNode *literal = new_<ListNode>(PNK_ARRAY, TokenPos(begin, begin + 1));
207 // Later in this stack: remove dependency on this opcode.
208 if (literal) {
209 literal->setOp(JSOP_NEWINIT);
210 literal->pn_blockid = blockid;
211 }
212 return literal;
213 }
215 bool addElision(ParseNode *literal, const TokenPos &pos) {
216 ParseNode *elision = new_<NullaryNode>(PNK_ELISION, pos);
217 if (!elision)
218 return false;
219 literal->append(elision);
220 literal->pn_xflags |= PNX_SPECIALARRAYINIT | PNX_NONCONST;
221 return true;
222 }
224 bool addSpreadElement(ParseNode *literal, uint32_t begin, ParseNode *inner) {
225 TokenPos pos(begin, inner->pn_pos.end);
226 ParseNode *spread = new_<UnaryNode>(PNK_SPREAD, JSOP_NOP, pos, inner);
227 if (!spread)
228 return null();
229 literal->append(spread);
230 literal->pn_xflags |= PNX_SPECIALARRAYINIT | PNX_NONCONST;
231 return true;
232 }
234 bool addArrayElement(ParseNode *literal, ParseNode *element) {
235 if (!element->isConstant())
236 literal->pn_xflags |= PNX_NONCONST;
237 literal->append(element);
238 return true;
239 }
241 ParseNode *newObjectLiteral(uint32_t begin) {
242 ParseNode *literal = new_<ListNode>(PNK_OBJECT, TokenPos(begin, begin + 1));
243 // Later in this stack: remove dependency on this opcode.
244 if (literal)
245 literal->setOp(JSOP_NEWINIT);
246 return literal;
247 }
249 bool addPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *expr) {
250 ParseNode *propdef = newBinary(PNK_COLON, name, expr, JSOP_INITPROP);
251 if (!propdef)
252 return false;
253 literal->append(propdef);
254 return true;
255 }
257 bool addShorthandPropertyDefinition(ParseNode *literal, ParseNode *name) {
258 JS_ASSERT(literal->isArity(PN_LIST));
259 literal->pn_xflags |= PNX_DESTRUCT | PNX_NONCONST; // XXX why PNX_DESTRUCT?
260 return addPropertyDefinition(literal, name, name);
261 }
263 bool addAccessorPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *fn, JSOp op)
264 {
265 JS_ASSERT(literal->isArity(PN_LIST));
266 literal->pn_xflags |= PNX_NONCONST;
268 ParseNode *propdef = newBinary(PNK_COLON, name, fn, op);
269 if (!propdef)
270 return false;
271 literal->append(propdef);
272 return true;
273 }
275 // Statements
277 ParseNode *newStatementList(unsigned blockid, const TokenPos &pos) {
278 ParseNode *pn = new_<ListNode>(PNK_STATEMENTLIST, pos);
279 if (pn)
280 pn->pn_blockid = blockid;
281 return pn;
282 }
284 template <typename PC>
285 void addStatementToList(ParseNode *list, ParseNode *stmt, PC *pc) {
286 JS_ASSERT(list->isKind(PNK_STATEMENTLIST));
288 if (stmt->isKind(PNK_FUNCTION)) {
289 if (pc->atBodyLevel()) {
290 // PNX_FUNCDEFS notifies the emitter that the block contains
291 // body-level function definitions that should be processed
292 // before the rest of nodes.
293 list->pn_xflags |= PNX_FUNCDEFS;
294 } else {
295 // General deoptimization was done in Parser::functionDef.
296 JS_ASSERT_IF(pc->sc->isFunctionBox(),
297 pc->sc->asFunctionBox()->hasExtensibleScope());
298 }
299 }
301 list->append(stmt);
302 }
304 ParseNode *newEmptyStatement(const TokenPos &pos) {
305 return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, pos, (ParseNode *) nullptr);
306 }
308 ParseNode *newImportDeclaration(ParseNode *importSpecSet,
309 ParseNode *moduleSpec, const TokenPos &pos)
310 {
311 ParseNode *pn = new_<BinaryNode>(PNK_IMPORT, JSOP_NOP, pos,
312 importSpecSet, moduleSpec);
313 if (!pn)
314 return null();
315 return pn;
316 }
318 ParseNode *newExportDeclaration(ParseNode *kid, const TokenPos &pos) {
319 return new_<UnaryNode>(PNK_EXPORT, JSOP_NOP, pos, kid);
320 }
322 ParseNode *newExportFromDeclaration(uint32_t begin, ParseNode *exportSpecSet,
323 ParseNode *moduleSpec)
324 {
325 ParseNode *pn = new_<BinaryNode>(PNK_EXPORT_FROM, JSOP_NOP, exportSpecSet, moduleSpec);
326 if (!pn)
327 return null();
328 pn->pn_pos.begin = begin;
329 return pn;
330 }
332 ParseNode *newExprStatement(ParseNode *expr, uint32_t end) {
333 JS_ASSERT(expr->pn_pos.end <= end);
334 return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, TokenPos(expr->pn_pos.begin, end), expr);
335 }
337 ParseNode *newIfStatement(uint32_t begin, ParseNode *cond, ParseNode *thenBranch,
338 ParseNode *elseBranch)
339 {
340 ParseNode *pn = new_<TernaryNode>(PNK_IF, JSOP_NOP, cond, thenBranch, elseBranch);
341 if (!pn)
342 return null();
343 pn->pn_pos.begin = begin;
344 return pn;
345 }
347 ParseNode *newDoWhileStatement(ParseNode *body, ParseNode *cond, const TokenPos &pos) {
348 return new_<BinaryNode>(PNK_DOWHILE, JSOP_NOP, pos, body, cond);
349 }
351 ParseNode *newWhileStatement(uint32_t begin, ParseNode *cond, ParseNode *body) {
352 TokenPos pos(begin, body->pn_pos.end);
353 return new_<BinaryNode>(PNK_WHILE, JSOP_NOP, pos, cond, body);
354 }
356 ParseNode *newForStatement(uint32_t begin, ParseNode *forHead, ParseNode *body,
357 unsigned iflags)
358 {
359 /* A FOR node is binary, left is loop control and right is the body. */
360 JSOp op = forHead->isKind(PNK_FORIN) ? JSOP_ITER : JSOP_NOP;
361 BinaryNode *pn = new_<BinaryNode>(PNK_FOR, op, TokenPos(begin, body->pn_pos.end),
362 forHead, body);
363 if (!pn)
364 return null();
365 pn->pn_iflags = iflags;
366 return pn;
367 }
369 ParseNode *newForHead(ParseNodeKind kind, ParseNode *pn1, ParseNode *pn2, ParseNode *pn3,
370 const TokenPos &pos)
371 {
372 JS_ASSERT(kind == PNK_FORIN || kind == PNK_FOROF || kind == PNK_FORHEAD);
373 return new_<TernaryNode>(kind, JSOP_NOP, pn1, pn2, pn3, pos);
374 }
376 ParseNode *newSwitchStatement(uint32_t begin, ParseNode *discriminant, ParseNode *caseList) {
377 TokenPos pos(begin, caseList->pn_pos.end);
378 return new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, pos, discriminant, caseList);
379 }
381 ParseNode *newCaseOrDefault(uint32_t begin, ParseNode *expr, ParseNode *body) {
382 TokenPos pos(begin, body->pn_pos.end);
383 return new_<BinaryNode>(expr ? PNK_CASE : PNK_DEFAULT, JSOP_NOP, pos, expr, body);
384 }
386 ParseNode *newContinueStatement(PropertyName *label, const TokenPos &pos) {
387 return new_<ContinueStatement>(label, pos);
388 }
390 ParseNode *newBreakStatement(PropertyName *label, const TokenPos &pos) {
391 return new_<BreakStatement>(label, pos);
392 }
394 ParseNode *newReturnStatement(ParseNode *expr, const TokenPos &pos) {
395 JS_ASSERT_IF(expr, pos.encloses(expr->pn_pos));
396 return new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, pos, expr);
397 }
399 ParseNode *newWithStatement(uint32_t begin, ParseNode *expr, ParseNode *body,
400 ObjectBox *staticWith) {
401 return new_<BinaryObjNode>(PNK_WITH, JSOP_NOP, TokenPos(begin, body->pn_pos.end),
402 expr, body, staticWith);
403 }
405 ParseNode *newLabeledStatement(PropertyName *label, ParseNode *stmt, uint32_t begin) {
406 return new_<LabeledStatement>(label, stmt, begin);
407 }
409 ParseNode *newThrowStatement(ParseNode *expr, const TokenPos &pos) {
410 JS_ASSERT(pos.encloses(expr->pn_pos));
411 return new_<UnaryNode>(PNK_THROW, JSOP_THROW, pos, expr);
412 }
414 ParseNode *newTryStatement(uint32_t begin, ParseNode *body, ParseNode *catchList,
415 ParseNode *finallyBlock) {
416 TokenPos pos(begin, (finallyBlock ? finallyBlock : catchList)->pn_pos.end);
417 return new_<TernaryNode>(PNK_TRY, JSOP_NOP, body, catchList, finallyBlock, pos);
418 }
420 ParseNode *newDebuggerStatement(const TokenPos &pos) {
421 return new_<DebuggerStatement>(pos);
422 }
424 ParseNode *newPropertyAccess(ParseNode *pn, PropertyName *name, uint32_t end) {
425 return new_<PropertyAccess>(pn, name, pn->pn_pos.begin, end);
426 }
428 ParseNode *newPropertyByValue(ParseNode *lhs, ParseNode *index, uint32_t end) {
429 return new_<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
430 }
432 inline bool addCatchBlock(ParseNode *catchList, ParseNode *letBlock,
433 ParseNode *catchName, ParseNode *catchGuard, ParseNode *catchBody);
435 inline void setLastFunctionArgumentDefault(ParseNode *funcpn, ParseNode *pn);
436 inline ParseNode *newFunctionDefinition();
437 void setFunctionBody(ParseNode *pn, ParseNode *kid) {
438 pn->pn_body = kid;
439 }
440 void setFunctionBox(ParseNode *pn, FunctionBox *funbox) {
441 JS_ASSERT(pn->isKind(PNK_FUNCTION));
442 pn->pn_funbox = funbox;
443 }
444 void addFunctionArgument(ParseNode *pn, ParseNode *argpn) {
445 pn->pn_body->append(argpn);
446 }
448 inline ParseNode *newLexicalScope(ObjectBox *blockbox);
449 inline void setLexicalScopeBody(ParseNode *block, ParseNode *body);
451 bool isOperationWithoutParens(ParseNode *pn, ParseNodeKind kind) {
452 return pn->isKind(kind) && !pn->isInParens();
453 }
455 inline bool finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op);
457 void setBeginPosition(ParseNode *pn, ParseNode *oth) {
458 setBeginPosition(pn, oth->pn_pos.begin);
459 }
460 void setBeginPosition(ParseNode *pn, uint32_t begin) {
461 pn->pn_pos.begin = begin;
462 JS_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
463 }
465 void setEndPosition(ParseNode *pn, ParseNode *oth) {
466 setEndPosition(pn, oth->pn_pos.end);
467 }
468 void setEndPosition(ParseNode *pn, uint32_t end) {
469 pn->pn_pos.end = end;
470 JS_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
471 }
473 void setPosition(ParseNode *pn, const TokenPos &pos) {
474 pn->pn_pos = pos;
475 }
476 TokenPos getPosition(ParseNode *pn) {
477 return pn->pn_pos;
478 }
480 ParseNode *newList(ParseNodeKind kind, ParseNode *kid = nullptr, JSOp op = JSOP_NOP) {
481 ParseNode *pn = ListNode::create(kind, this);
482 if (!pn)
483 return nullptr;
484 pn->setOp(op);
485 pn->makeEmpty();
486 if (kid) {
487 pn->pn_pos.begin = kid->pn_pos.begin;
488 pn->append(kid);
489 }
490 return pn;
491 }
492 void addList(ParseNode *pn, ParseNode *kid) {
493 pn->append(kid);
494 }
496 bool isUnparenthesizedYield(ParseNode *pn) {
497 return pn->isKind(PNK_YIELD) && !pn->isInParens();
498 }
500 void setOp(ParseNode *pn, JSOp op) {
501 pn->setOp(op);
502 }
503 void setBlockId(ParseNode *pn, unsigned blockid) {
504 pn->pn_blockid = blockid;
505 }
506 void setFlag(ParseNode *pn, unsigned flag) {
507 pn->pn_dflags |= flag;
508 }
509 void setListFlag(ParseNode *pn, unsigned flag) {
510 JS_ASSERT(pn->isArity(PN_LIST));
511 pn->pn_xflags |= flag;
512 }
513 ParseNode *setInParens(ParseNode *pn) {
514 pn->setInParens(true);
515 return pn;
516 }
517 void setPrologue(ParseNode *pn) {
518 pn->pn_prologue = true;
519 }
521 bool isConstant(ParseNode *pn) {
522 return pn->isConstant();
523 }
524 PropertyName *isName(ParseNode *pn) {
525 return pn->isKind(PNK_NAME) ? pn->pn_atom->asPropertyName() : nullptr;
526 }
527 bool isCall(ParseNode *pn) {
528 return pn->isKind(PNK_CALL);
529 }
530 PropertyName *isGetProp(ParseNode *pn) {
531 return pn->is<PropertyAccess>() ? &pn->as<PropertyAccess>().name() : nullptr;
532 }
533 JSAtom *isStringExprStatement(ParseNode *pn, TokenPos *pos) {
534 if (JSAtom *atom = pn->isStringExprStatement()) {
535 *pos = pn->pn_kid->pn_pos;
536 return atom;
537 }
538 return nullptr;
539 }
541 inline ParseNode *makeAssignment(ParseNode *pn, ParseNode *rhs);
543 static Definition *getDefinitionNode(Definition *dn) {
544 return dn;
545 }
546 static Definition::Kind getDefinitionKind(Definition *dn) {
547 return dn->kind();
548 }
549 void linkUseToDef(ParseNode *pn, Definition *dn)
550 {
551 JS_ASSERT(!pn->isUsed());
552 JS_ASSERT(!pn->isDefn());
553 JS_ASSERT(pn != dn->dn_uses);
554 JS_ASSERT(dn->isDefn());
555 pn->pn_link = dn->dn_uses;
556 dn->dn_uses = pn;
557 dn->pn_dflags |= pn->pn_dflags & PND_USE2DEF_FLAGS;
558 pn->setUsed(true);
559 pn->pn_lexdef = dn;
560 }
561 Definition *resolve(Definition *dn) {
562 return dn->resolve();
563 }
564 void deoptimizeUsesWithin(Definition *dn, const TokenPos &pos)
565 {
566 for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
567 JS_ASSERT(pnu->isUsed());
568 JS_ASSERT(!pnu->isDefn());
569 if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end)
570 pnu->pn_dflags |= PND_DEOPTIMIZED;
571 }
572 }
573 bool dependencyCovered(ParseNode *pn, unsigned blockid, bool functionScope) {
574 return pn->pn_blockid >= blockid;
575 }
577 static uintptr_t definitionToBits(Definition *dn) {
578 return uintptr_t(dn);
579 }
580 static Definition *definitionFromBits(uintptr_t bits) {
581 return (Definition *) bits;
582 }
583 static Definition *nullDefinition() {
584 return nullptr;
585 }
586 void disableSyntaxParser() {
587 syntaxParser = nullptr;
588 }
590 LazyScript *lazyOuterFunction() {
591 return lazyOuterFunction_;
592 }
593 JSFunction *nextLazyInnerFunction() {
594 JS_ASSERT(lazyInnerFunctionIndex < lazyOuterFunction()->numInnerFunctions());
595 return lazyOuterFunction()->innerFunctions()[lazyInnerFunctionIndex++];
596 }
597 };
599 inline bool
600 FullParseHandler::addCatchBlock(ParseNode *catchList, ParseNode *letBlock,
601 ParseNode *catchName, ParseNode *catchGuard, ParseNode *catchBody)
602 {
603 ParseNode *catchpn = newTernary(PNK_CATCH, catchName, catchGuard, catchBody);
604 if (!catchpn)
605 return false;
607 catchList->append(letBlock);
608 letBlock->pn_expr = catchpn;
609 return true;
610 }
612 inline void
613 FullParseHandler::setLastFunctionArgumentDefault(ParseNode *funcpn, ParseNode *defaultValue)
614 {
615 ParseNode *arg = funcpn->pn_body->last();
616 arg->pn_dflags |= PND_DEFAULT;
617 arg->pn_expr = defaultValue;
618 }
620 inline ParseNode *
621 FullParseHandler::newFunctionDefinition()
622 {
623 ParseNode *pn = CodeNode::create(PNK_FUNCTION, this);
624 if (!pn)
625 return nullptr;
626 pn->pn_body = nullptr;
627 pn->pn_funbox = nullptr;
628 pn->pn_cookie.makeFree();
629 pn->pn_dflags = 0;
630 return pn;
631 }
633 inline ParseNode *
634 FullParseHandler::newLexicalScope(ObjectBox *blockbox)
635 {
636 ParseNode *pn = LexicalScopeNode::create(PNK_LEXICALSCOPE, this);
637 if (!pn)
638 return nullptr;
640 pn->pn_objbox = blockbox;
641 pn->pn_cookie.makeFree();
642 pn->pn_dflags = 0;
643 return pn;
644 }
646 inline void
647 FullParseHandler::setLexicalScopeBody(ParseNode *block, ParseNode *kid)
648 {
649 block->pn_expr = kid;
650 }
652 inline bool
653 FullParseHandler::finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op)
654 {
655 if (pn->isUsed()) {
656 pn = makeAssignment(pn, init);
657 if (!pn)
658 return false;
659 } else {
660 pn->pn_expr = init;
661 }
663 pn->setOp((pn->pn_dflags & PND_BOUND)
664 ? JSOP_SETLOCAL
665 : (op == JSOP_DEFCONST)
666 ? JSOP_SETCONST
667 : JSOP_SETNAME);
669 pn->markAsAssigned();
671 /* The declarator's position must include the initializer. */
672 pn->pn_pos.end = init->pn_pos.end;
673 return true;
674 }
676 inline ParseNode *
677 FullParseHandler::makeAssignment(ParseNode *pn, ParseNode *rhs)
678 {
679 ParseNode *lhs = cloneNode(*pn);
680 if (!lhs)
681 return nullptr;
683 if (pn->isUsed()) {
684 Definition *dn = pn->pn_lexdef;
685 ParseNode **pnup = &dn->dn_uses;
687 while (*pnup != pn)
688 pnup = &(*pnup)->pn_link;
689 *pnup = lhs;
690 lhs->pn_link = pn->pn_link;
691 pn->pn_link = nullptr;
692 }
694 pn->setKind(PNK_ASSIGN);
695 pn->setOp(JSOP_NOP);
696 pn->setArity(PN_BINARY);
697 pn->setInParens(false);
698 pn->setUsed(false);
699 pn->setDefn(false);
700 pn->pn_left = lhs;
701 pn->pn_right = rhs;
702 pn->pn_pos.end = rhs->pn_pos.end;
703 return lhs;
704 }
706 } // frontend
707 } // js
709 #endif /* frontend_FullParseHandler_h */