Line data Source code
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/. */
6 :
7 : #ifndef frontend_FullParseHandler_h
8 : #define frontend_FullParseHandler_h
9 :
10 : #include "mozilla/Attributes.h"
11 : #include "mozilla/PodOperations.h"
12 :
13 : #include <string.h>
14 :
15 : #include "frontend/ParseNode.h"
16 : #include "frontend/SharedContext.h"
17 :
18 : namespace js {
19 : namespace frontend {
20 :
21 : // Parse handler used when generating a full parse tree for all code which the
22 : // parser encounters.
23 1691 : class FullParseHandler
24 : {
25 : ParseNodeAllocator allocator;
26 :
27 310719 : ParseNode* allocParseNode(size_t size) {
28 310719 : MOZ_ASSERT(size == sizeof(ParseNode));
29 310719 : return static_cast<ParseNode*>(allocator.allocNode());
30 : }
31 :
32 : ParseNode* cloneNode(const ParseNode& other) {
33 : ParseNode* node = allocParseNode(sizeof(ParseNode));
34 : if (!node)
35 : return nullptr;
36 : mozilla::PodAssign(node, &other);
37 : return node;
38 : }
39 :
40 : /*
41 : * If this is a full parse to construct the bytecode for a function that
42 : * was previously lazily parsed, that lazy function and the current index
43 : * into its inner functions. We do not want to reparse the inner functions.
44 : */
45 : const Rooted<LazyScript*> lazyOuterFunction_;
46 : size_t lazyInnerFunctionIndex;
47 : size_t lazyClosedOverBindingIndex;
48 :
49 : public:
50 : /* new_ methods for creating parse nodes. These report OOM on context. */
51 310666 : JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
52 :
53 : typedef ParseNode* Node;
54 :
55 14443 : bool isPropertyAccess(ParseNode* node) {
56 14443 : return node->isKind(PNK_DOT) || node->isKind(PNK_ELEM);
57 : }
58 :
59 0 : bool isFunctionCall(ParseNode* node) {
60 : // Note: super() is a special form, *not* a function call.
61 0 : return node->isKind(PNK_CALL);
62 : }
63 :
64 9189 : static bool isUnparenthesizedDestructuringPattern(ParseNode* node) {
65 9189 : return !node->isInParens() && (node->isKind(PNK_OBJECT) || node->isKind(PNK_ARRAY));
66 : }
67 :
68 2079 : static bool isParenthesizedDestructuringPattern(ParseNode* node) {
69 : // Technically this isn't a destructuring pattern at all -- the grammar
70 : // doesn't treat it as such. But we need to know when this happens to
71 : // consider it a SyntaxError rather than an invalid-left-hand-side
72 : // ReferenceError.
73 2079 : return node->isInParens() && (node->isKind(PNK_OBJECT) || node->isKind(PNK_ARRAY));
74 : }
75 :
76 : static bool isDestructuringPatternAnyParentheses(ParseNode* node) {
77 : return isUnparenthesizedDestructuringPattern(node) ||
78 : isParenthesizedDestructuringPattern(node);
79 : }
80 :
81 1690 : FullParseHandler(JSContext* cx, LifoAlloc& alloc, LazyScript* lazyOuterFunction)
82 1690 : : allocator(cx, alloc),
83 : lazyOuterFunction_(cx, lazyOuterFunction),
84 : lazyInnerFunctionIndex(0),
85 1690 : lazyClosedOverBindingIndex(0)
86 1690 : {}
87 :
88 17952 : static ParseNode* null() { return nullptr; }
89 :
90 3645 : ParseNode* freeTree(ParseNode* pn) { return allocator.freeTree(pn); }
91 455 : void prepareNodeForMutation(ParseNode* pn) { return allocator.prepareNodeForMutation(pn); }
92 :
93 91188 : ParseNode* newName(PropertyName* name, const TokenPos& pos, JSContext* cx)
94 : {
95 91188 : return new_<NameNode>(PNK_NAME, JSOP_GETNAME, name, pos);
96 : }
97 :
98 5 : ParseNode* newComputedName(ParseNode* expr, uint32_t begin, uint32_t end) {
99 5 : TokenPos pos(begin, end);
100 5 : return new_<UnaryNode>(PNK_COMPUTED_NAME, JSOP_NOP, pos, expr);
101 : }
102 :
103 7851 : ParseNode* newObjectLiteralPropertyName(JSAtom* atom, const TokenPos& pos) {
104 7851 : return new_<NullaryNode>(PNK_OBJECT_PROPERTY_NAME, JSOP_NOP, pos, atom);
105 : }
106 :
107 9347 : ParseNode* newNumber(double value, DecimalPoint decimalPoint, const TokenPos& pos) {
108 9347 : ParseNode* pn = new_<NullaryNode>(PNK_NUMBER, pos);
109 9347 : if (!pn)
110 0 : return nullptr;
111 9347 : pn->initNumber(value, decimalPoint);
112 9347 : return pn;
113 : }
114 :
115 2325 : ParseNode* newBooleanLiteral(bool cond, const TokenPos& pos) {
116 2325 : return new_<BooleanLiteral>(cond, pos);
117 : }
118 :
119 17859 : ParseNode* newStringLiteral(JSAtom* atom, const TokenPos& pos) {
120 17859 : return new_<NullaryNode>(PNK_STRING, JSOP_NOP, pos, atom);
121 : }
122 :
123 863 : ParseNode* newTemplateStringLiteral(JSAtom* atom, const TokenPos& pos) {
124 863 : return new_<NullaryNode>(PNK_TEMPLATE_STRING, JSOP_NOP, pos, atom);
125 : }
126 :
127 1 : ParseNode* newCallSiteObject(uint32_t begin) {
128 1 : ParseNode* callSite = new_<CallSiteNode>(begin);
129 1 : if (!callSite)
130 0 : return null();
131 :
132 1 : Node propExpr = newArrayLiteral(callSite->pn_pos.begin);
133 1 : if (!propExpr)
134 0 : return null();
135 :
136 1 : addArrayElement(callSite, propExpr);
137 :
138 1 : return callSite;
139 : }
140 :
141 3 : void addToCallSiteObject(ParseNode* callSiteObj, ParseNode* rawNode, ParseNode* cookedNode) {
142 3 : MOZ_ASSERT(callSiteObj->isKind(PNK_CALLSITEOBJ));
143 :
144 3 : addArrayElement(callSiteObj, cookedNode);
145 3 : addArrayElement(callSiteObj->pn_head, rawNode);
146 :
147 : /*
148 : * We don't know when the last noSubstTemplate will come in, and we
149 : * don't want to deal with this outside this method
150 : */
151 3 : setEndPosition(callSiteObj, callSiteObj->pn_head);
152 3 : }
153 :
154 7628 : ParseNode* newThisLiteral(const TokenPos& pos, ParseNode* thisName) {
155 7628 : return new_<ThisLiteral>(pos, thisName);
156 : }
157 :
158 2043 : ParseNode* newNullLiteral(const TokenPos& pos) {
159 2043 : return new_<NullLiteral>(pos);
160 : }
161 :
162 0 : ParseNode* newRawUndefinedLiteral(const TokenPos& pos) {
163 0 : return new_<RawUndefinedLiteral>(pos);
164 : }
165 :
166 : // The Boxer object here is any object that can allocate ObjectBoxes.
167 : // Specifically, a Boxer has a .newObjectBox(T) method that accepts a
168 : // Rooted<RegExpObject*> argument and returns an ObjectBox*.
169 : template <class Boxer>
170 169 : ParseNode* newRegExp(RegExpObject* reobj, const TokenPos& pos, Boxer& boxer) {
171 169 : ObjectBox* objbox = boxer.newObjectBox(reobj);
172 169 : if (!objbox)
173 0 : return null();
174 169 : return new_<RegExpLiteral>(objbox, pos);
175 : }
176 :
177 652 : ParseNode* newConditional(ParseNode* cond, ParseNode* thenExpr, ParseNode* elseExpr) {
178 652 : return new_<ConditionalExpression>(cond, thenExpr, elseExpr);
179 : }
180 :
181 80 : ParseNode* newDelete(uint32_t begin, ParseNode* expr) {
182 80 : if (expr->isKind(PNK_NAME)) {
183 0 : expr->setOp(JSOP_DELNAME);
184 0 : return newUnary(PNK_DELETENAME, JSOP_NOP, begin, expr);
185 : }
186 :
187 80 : if (expr->isKind(PNK_DOT))
188 51 : return newUnary(PNK_DELETEPROP, JSOP_NOP, begin, expr);
189 :
190 29 : if (expr->isKind(PNK_ELEM))
191 29 : return newUnary(PNK_DELETEELEM, JSOP_NOP, begin, expr);
192 :
193 0 : return newUnary(PNK_DELETEEXPR, JSOP_NOP, begin, expr);
194 : }
195 :
196 502 : ParseNode* newTypeof(uint32_t begin, ParseNode* kid) {
197 502 : TokenPos pos(begin, kid->pn_pos.end);
198 502 : ParseNodeKind kind = kid->isKind(PNK_NAME) ? PNK_TYPEOFNAME : PNK_TYPEOFEXPR;
199 502 : return new_<UnaryNode>(kind, JSOP_NOP, pos, kid);
200 : }
201 :
202 0 : ParseNode* newNullary(ParseNodeKind kind, JSOp op, const TokenPos& pos) {
203 0 : return new_<NullaryNode>(kind, op, pos);
204 : }
205 :
206 3405 : ParseNode* newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, ParseNode* kid) {
207 3405 : TokenPos pos(begin, kid ? kid->pn_pos.end : begin + 1);
208 3405 : return new_<UnaryNode>(kind, op, pos, kid);
209 : }
210 :
211 702 : ParseNode* newUpdate(ParseNodeKind kind, uint32_t begin, ParseNode* kid) {
212 702 : TokenPos pos(begin, kid->pn_pos.end);
213 702 : return new_<UnaryNode>(kind, JSOP_NOP, pos, kid);
214 : }
215 :
216 58 : ParseNode* newSpread(uint32_t begin, ParseNode* kid) {
217 58 : TokenPos pos(begin, kid->pn_pos.end);
218 58 : return new_<UnaryNode>(PNK_SPREAD, JSOP_NOP, pos, kid);
219 : }
220 :
221 0 : ParseNode* newArrayPush(uint32_t begin, ParseNode* kid) {
222 0 : TokenPos pos(begin, kid->pn_pos.end);
223 0 : return new_<UnaryNode>(PNK_ARRAYPUSH, JSOP_ARRAYPUSH, pos, kid);
224 : }
225 :
226 15083 : ParseNode* newBinary(ParseNodeKind kind, ParseNode* left, ParseNode* right,
227 : JSOp op = JSOP_NOP)
228 : {
229 15083 : TokenPos pos(left->pn_pos.begin, right->pn_pos.end);
230 15083 : return new_<BinaryNode>(kind, op, pos, left, right);
231 : }
232 13783 : ParseNode* appendOrCreateList(ParseNodeKind kind, ParseNode* left, ParseNode* right,
233 : ParseContext* pc, JSOp op = JSOP_NOP)
234 : {
235 13783 : return ParseNode::appendOrCreateList(kind, op, left, right, this, pc);
236 : }
237 :
238 461 : ParseNode* newTernary(ParseNodeKind kind,
239 : ParseNode* first, ParseNode* second, ParseNode* third,
240 : JSOp op = JSOP_NOP)
241 : {
242 461 : return new_<TernaryNode>(kind, op, first, second, third);
243 : }
244 :
245 : // Expressions
246 :
247 : ParseNode* newArrayComprehension(ParseNode* body, const TokenPos& pos) {
248 : MOZ_ASSERT(pos.begin <= body->pn_pos.begin);
249 : MOZ_ASSERT(body->pn_pos.end <= pos.end);
250 : ParseNode* pn = new_<ListNode>(PNK_ARRAYCOMP, pos);
251 : if (!pn)
252 : return nullptr;
253 : pn->append(body);
254 : return pn;
255 : }
256 :
257 1284 : ParseNode* newArrayLiteral(uint32_t begin) {
258 1284 : ParseNode* literal = new_<ListNode>(PNK_ARRAY, TokenPos(begin, begin + 1));
259 : // Later in this stack: remove dependency on this opcode.
260 1284 : if (literal)
261 1284 : literal->setOp(JSOP_NEWINIT);
262 1284 : return literal;
263 : }
264 :
265 5 : MOZ_MUST_USE bool addElision(ParseNode* literal, const TokenPos& pos) {
266 5 : ParseNode* elision = new_<NullaryNode>(PNK_ELISION, pos);
267 5 : if (!elision)
268 0 : return false;
269 5 : literal->append(elision);
270 5 : literal->pn_xflags |= PNX_ARRAYHOLESPREAD | PNX_NONCONST;
271 5 : return true;
272 : }
273 :
274 11 : MOZ_MUST_USE bool addSpreadElement(ParseNode* literal, uint32_t begin, ParseNode* inner) {
275 11 : ParseNode* spread = newSpread(begin, inner);
276 11 : if (!spread)
277 0 : return false;
278 11 : literal->append(spread);
279 11 : literal->pn_xflags |= PNX_ARRAYHOLESPREAD | PNX_NONCONST;
280 11 : return true;
281 : }
282 :
283 3051 : void addArrayElement(ParseNode* literal, ParseNode* element) {
284 3051 : if (!element->isConstant())
285 818 : literal->pn_xflags |= PNX_NONCONST;
286 3051 : literal->append(element);
287 3051 : }
288 :
289 21069 : ParseNode* newCall(const TokenPos& pos) {
290 21069 : return newList(PNK_CALL, pos, JSOP_CALL);
291 : }
292 :
293 1 : ParseNode* newTaggedTemplate(const TokenPos& pos) {
294 1 : return newList(PNK_TAGGED_TEMPLATE, pos, JSOP_CALL);
295 : }
296 :
297 2530 : ParseNode* newObjectLiteral(uint32_t begin) {
298 2530 : ParseNode* literal = new_<ListNode>(PNK_OBJECT, TokenPos(begin, begin + 1));
299 : // Later in this stack: remove dependency on this opcode.
300 2530 : if (literal)
301 2530 : literal->setOp(JSOP_NEWINIT);
302 2530 : return literal;
303 : }
304 :
305 32 : ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock,
306 : const TokenPos& pos)
307 : {
308 32 : return new_<ClassNode>(name, heritage, methodBlock, pos);
309 : }
310 32 : ParseNode* newClassMethodList(uint32_t begin) {
311 32 : return new_<ListNode>(PNK_CLASSMETHODLIST, TokenPos(begin, begin + 1));
312 : }
313 26 : ParseNode* newClassNames(ParseNode* outer, ParseNode* inner, const TokenPos& pos) {
314 26 : return new_<ClassNames>(outer, inner, pos);
315 : }
316 12 : ParseNode* newNewTarget(ParseNode* newHolder, ParseNode* targetHolder) {
317 12 : return new_<BinaryNode>(PNK_NEWTARGET, JSOP_NOP, newHolder, targetHolder);
318 : }
319 1007 : ParseNode* newPosHolder(const TokenPos& pos) {
320 1007 : return new_<NullaryNode>(PNK_POSHOLDER, pos);
321 : }
322 26 : ParseNode* newSuperBase(ParseNode* thisName, const TokenPos& pos) {
323 26 : return new_<UnaryNode>(PNK_SUPERBASE, JSOP_NOP, pos, thisName);
324 : }
325 :
326 38 : MOZ_MUST_USE bool addPrototypeMutation(ParseNode* literal, uint32_t begin, ParseNode* expr) {
327 : // Object literals with mutated [[Prototype]] are non-constant so that
328 : // singleton objects will have Object.prototype as their [[Prototype]].
329 38 : setListFlag(literal, PNX_NONCONST);
330 :
331 38 : ParseNode* mutation = newUnary(PNK_MUTATEPROTO, JSOP_NOP, begin, expr);
332 38 : if (!mutation)
333 0 : return false;
334 38 : literal->append(mutation);
335 38 : return true;
336 : }
337 :
338 6418 : MOZ_MUST_USE bool addPropertyDefinition(ParseNode* literal, ParseNode* key, ParseNode* val) {
339 6418 : MOZ_ASSERT(literal->isKind(PNK_OBJECT));
340 6418 : MOZ_ASSERT(literal->isArity(PN_LIST));
341 6418 : MOZ_ASSERT(key->isKind(PNK_NUMBER) ||
342 : key->isKind(PNK_OBJECT_PROPERTY_NAME) ||
343 : key->isKind(PNK_STRING) ||
344 : key->isKind(PNK_COMPUTED_NAME));
345 :
346 6418 : ParseNode* propdef = newBinary(PNK_COLON, key, val, JSOP_INITPROP);
347 6418 : if (!propdef)
348 0 : return false;
349 6418 : literal->append(propdef);
350 6418 : return true;
351 : }
352 :
353 611 : MOZ_MUST_USE bool addShorthand(ParseNode* literal, ParseNode* name, ParseNode* expr) {
354 611 : MOZ_ASSERT(literal->isKind(PNK_OBJECT));
355 611 : MOZ_ASSERT(literal->isArity(PN_LIST));
356 611 : MOZ_ASSERT(name->isKind(PNK_OBJECT_PROPERTY_NAME));
357 611 : MOZ_ASSERT(expr->isKind(PNK_NAME));
358 611 : MOZ_ASSERT(name->pn_atom == expr->pn_atom);
359 :
360 611 : setListFlag(literal, PNX_NONCONST);
361 611 : ParseNode* propdef = newBinary(PNK_SHORTHAND, name, expr, JSOP_INITPROP);
362 611 : if (!propdef)
363 0 : return false;
364 611 : literal->append(propdef);
365 611 : return true;
366 : }
367 :
368 0 : MOZ_MUST_USE bool addSpreadProperty(ParseNode* literal, uint32_t begin, ParseNode* inner) {
369 0 : MOZ_ASSERT(literal->isKind(PNK_OBJECT));
370 0 : MOZ_ASSERT(literal->isArity(PN_LIST));
371 :
372 0 : setListFlag(literal, PNX_NONCONST);
373 0 : ParseNode* spread = newSpread(begin, inner);
374 0 : if (!spread)
375 0 : return false;
376 0 : literal->append(spread);
377 0 : return true;
378 : }
379 :
380 1988 : MOZ_MUST_USE bool addObjectMethodDefinition(ParseNode* literal, ParseNode* key, ParseNode* fn,
381 : JSOp op)
382 : {
383 1988 : MOZ_ASSERT(literal->isArity(PN_LIST));
384 1988 : MOZ_ASSERT(key->isKind(PNK_NUMBER) ||
385 : key->isKind(PNK_OBJECT_PROPERTY_NAME) ||
386 : key->isKind(PNK_STRING) ||
387 : key->isKind(PNK_COMPUTED_NAME));
388 1988 : literal->pn_xflags |= PNX_NONCONST;
389 :
390 1988 : ParseNode* propdef = newBinary(PNK_COLON, key, fn, op);
391 1988 : if (!propdef)
392 0 : return false;
393 1988 : literal->append(propdef);
394 1988 : return true;
395 : }
396 :
397 156 : MOZ_MUST_USE bool addClassMethodDefinition(ParseNode* methodList, ParseNode* key, ParseNode* fn,
398 : JSOp op, bool isStatic)
399 : {
400 156 : MOZ_ASSERT(methodList->isKind(PNK_CLASSMETHODLIST));
401 156 : MOZ_ASSERT(key->isKind(PNK_NUMBER) ||
402 : key->isKind(PNK_OBJECT_PROPERTY_NAME) ||
403 : key->isKind(PNK_STRING) ||
404 : key->isKind(PNK_COMPUTED_NAME));
405 :
406 156 : ParseNode* classMethod = new_<ClassMethod>(key, fn, op, isStatic);
407 156 : if (!classMethod)
408 0 : return false;
409 156 : methodList->append(classMethod);
410 156 : return true;
411 : }
412 :
413 127 : ParseNode* newInitialYieldExpression(uint32_t begin, ParseNode* gen) {
414 127 : TokenPos pos(begin, begin + 1);
415 127 : return new_<UnaryNode>(PNK_INITIALYIELD, JSOP_INITIALYIELD, pos, gen);
416 : }
417 :
418 15 : ParseNode* newYieldExpression(uint32_t begin, ParseNode* value) {
419 15 : TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
420 15 : return new_<UnaryNode>(PNK_YIELD, JSOP_YIELD, pos, value);
421 : }
422 :
423 3 : ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value) {
424 3 : TokenPos pos(begin, value->pn_pos.end);
425 3 : return new_<UnaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value);
426 : }
427 :
428 235 : ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value) {
429 235 : TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
430 235 : return new_<UnaryNode>(PNK_AWAIT, JSOP_AWAIT, pos, value);
431 : }
432 :
433 : // Statements
434 :
435 12856 : ParseNode* newStatementList(const TokenPos& pos) {
436 12856 : return new_<ListNode>(PNK_STATEMENTLIST, pos);
437 : }
438 :
439 36996 : MOZ_MUST_USE bool isFunctionStmt(ParseNode* stmt) {
440 36996 : while (stmt->isKind(PNK_LABEL))
441 0 : stmt = stmt->as<LabeledStatement>().statement();
442 36996 : return stmt->isKind(PNK_FUNCTION);
443 : }
444 :
445 36996 : void addStatementToList(ParseNode* list, ParseNode* stmt) {
446 36996 : MOZ_ASSERT(list->isKind(PNK_STATEMENTLIST));
447 :
448 36996 : list->append(stmt);
449 :
450 36996 : if (isFunctionStmt(stmt)) {
451 : // PNX_FUNCDEFS notifies the emitter that the block contains
452 : // body-level function definitions that should be processed
453 : // before the rest of nodes.
454 1816 : list->pn_xflags |= PNX_FUNCDEFS;
455 : }
456 36996 : }
457 :
458 1112 : void addCaseStatementToList(ParseNode* list, ParseNode* casepn) {
459 1112 : MOZ_ASSERT(list->isKind(PNK_STATEMENTLIST));
460 1112 : MOZ_ASSERT(casepn->isKind(PNK_CASE));
461 1112 : MOZ_ASSERT(casepn->pn_right->isKind(PNK_STATEMENTLIST));
462 :
463 1112 : list->append(casepn);
464 :
465 1112 : if (casepn->pn_right->pn_xflags & PNX_FUNCDEFS)
466 0 : list->pn_xflags |= PNX_FUNCDEFS;
467 1112 : }
468 :
469 127 : MOZ_MUST_USE bool prependInitialYield(ParseNode* stmtList, ParseNode* genName) {
470 127 : MOZ_ASSERT(stmtList->isKind(PNK_STATEMENTLIST));
471 :
472 127 : TokenPos yieldPos(stmtList->pn_pos.begin, stmtList->pn_pos.begin + 1);
473 127 : ParseNode* makeGen = new_<NullaryNode>(PNK_GENERATOR, yieldPos);
474 127 : if (!makeGen)
475 0 : return false;
476 :
477 127 : MOZ_ASSERT(genName->getOp() == JSOP_GETNAME);
478 127 : genName->setOp(JSOP_SETNAME);
479 127 : ParseNode* genInit = newBinary(PNK_ASSIGN, genName, makeGen);
480 127 : if (!genInit)
481 0 : return false;
482 :
483 127 : ParseNode* initialYield = newInitialYieldExpression(yieldPos.begin, genInit);
484 127 : if (!initialYield)
485 0 : return false;
486 :
487 127 : stmtList->prepend(initialYield);
488 127 : return true;
489 : }
490 :
491 13 : ParseNode* newSetThis(ParseNode* thisName, ParseNode* val) {
492 13 : MOZ_ASSERT(thisName->getOp() == JSOP_GETNAME);
493 13 : thisName->setOp(JSOP_SETNAME);
494 13 : return newBinary(PNK_SETTHIS, thisName, val);
495 : }
496 :
497 11 : ParseNode* newEmptyStatement(const TokenPos& pos) {
498 11 : return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, pos, (ParseNode*) nullptr);
499 : }
500 :
501 0 : ParseNode* newImportDeclaration(ParseNode* importSpecSet,
502 : ParseNode* moduleSpec, const TokenPos& pos)
503 : {
504 0 : ParseNode* pn = new_<BinaryNode>(PNK_IMPORT, JSOP_NOP, pos,
505 0 : importSpecSet, moduleSpec);
506 0 : if (!pn)
507 0 : return null();
508 0 : return pn;
509 : }
510 :
511 0 : ParseNode* newExportDeclaration(ParseNode* kid, const TokenPos& pos) {
512 0 : return new_<UnaryNode>(PNK_EXPORT, JSOP_NOP, pos, kid);
513 : }
514 :
515 0 : ParseNode* newExportFromDeclaration(uint32_t begin, ParseNode* exportSpecSet,
516 : ParseNode* moduleSpec)
517 : {
518 0 : ParseNode* pn = new_<BinaryNode>(PNK_EXPORT_FROM, JSOP_NOP, exportSpecSet, moduleSpec);
519 0 : if (!pn)
520 0 : return null();
521 0 : pn->pn_pos.begin = begin;
522 0 : return pn;
523 : }
524 :
525 0 : ParseNode* newExportDefaultDeclaration(ParseNode* kid, ParseNode* maybeBinding,
526 : const TokenPos& pos) {
527 0 : return new_<BinaryNode>(PNK_EXPORT_DEFAULT, JSOP_NOP, pos, kid, maybeBinding);
528 : }
529 :
530 14230 : ParseNode* newExprStatement(ParseNode* expr, uint32_t end) {
531 14230 : MOZ_ASSERT(expr->pn_pos.end <= end);
532 14230 : return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, TokenPos(expr->pn_pos.begin, end), expr);
533 : }
534 :
535 7035 : ParseNode* newIfStatement(uint32_t begin, ParseNode* cond, ParseNode* thenBranch,
536 : ParseNode* elseBranch)
537 : {
538 7035 : ParseNode* pn = new_<TernaryNode>(PNK_IF, JSOP_NOP, cond, thenBranch, elseBranch);
539 7035 : if (!pn)
540 0 : return null();
541 7035 : pn->pn_pos.begin = begin;
542 7035 : return pn;
543 : }
544 :
545 20 : ParseNode* newDoWhileStatement(ParseNode* body, ParseNode* cond, const TokenPos& pos) {
546 20 : return new_<BinaryNode>(PNK_DOWHILE, JSOP_NOP, pos, body, cond);
547 : }
548 :
549 182 : ParseNode* newWhileStatement(uint32_t begin, ParseNode* cond, ParseNode* body) {
550 182 : TokenPos pos(begin, body->pn_pos.end);
551 182 : return new_<BinaryNode>(PNK_WHILE, JSOP_NOP, pos, cond, body);
552 : }
553 :
554 808 : ParseNode* newForStatement(uint32_t begin, ParseNode* forHead, ParseNode* body,
555 : unsigned iflags)
556 : {
557 : /* A FOR node is binary, left is loop control and right is the body. */
558 808 : JSOp op = forHead->isKind(PNK_FORIN) ? JSOP_ITER : JSOP_NOP;
559 1616 : BinaryNode* pn = new_<BinaryNode>(PNK_FOR, op, TokenPos(begin, body->pn_pos.end),
560 808 : forHead, body);
561 808 : if (!pn)
562 0 : return null();
563 808 : pn->pn_iflags = iflags;
564 808 : return pn;
565 : }
566 :
567 0 : ParseNode* newComprehensionFor(uint32_t begin, ParseNode* forHead, ParseNode* body) {
568 : // A PNK_COMPREHENSIONFOR node is binary: left is loop control, right
569 : // is the body.
570 0 : MOZ_ASSERT(forHead->isKind(PNK_FORIN) || forHead->isKind(PNK_FOROF));
571 0 : JSOp op = forHead->isKind(PNK_FORIN) ? JSOP_ITER : JSOP_NOP;
572 0 : BinaryNode* pn = new_<BinaryNode>(PNK_COMPREHENSIONFOR, op,
573 0 : TokenPos(begin, body->pn_pos.end), forHead, body);
574 0 : if (!pn)
575 0 : return null();
576 0 : pn->pn_iflags = JSOP_ITER;
577 0 : return pn;
578 : }
579 :
580 0 : ParseNode* newComprehensionBinding(ParseNode* kid) {
581 0 : MOZ_ASSERT(kid->isKind(PNK_NAME));
582 0 : return new_<ListNode>(PNK_LET, JSOP_NOP, kid);
583 : }
584 :
585 439 : ParseNode* newForHead(ParseNode* init, ParseNode* test, ParseNode* update,
586 : const TokenPos& pos)
587 : {
588 439 : return new_<TernaryNode>(PNK_FORHEAD, JSOP_NOP, init, test, update, pos);
589 : }
590 :
591 369 : ParseNode* newForInOrOfHead(ParseNodeKind kind, ParseNode* target, ParseNode* iteratedExpr,
592 : const TokenPos& pos)
593 : {
594 369 : MOZ_ASSERT(kind == PNK_FORIN || kind == PNK_FOROF);
595 369 : return new_<TernaryNode>(kind, JSOP_NOP, target, nullptr, iteratedExpr, pos);
596 : }
597 :
598 209 : ParseNode* newSwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* caseList) {
599 209 : TokenPos pos(begin, caseList->pn_pos.end);
600 209 : return new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, pos, discriminant, caseList);
601 : }
602 :
603 1112 : ParseNode* newCaseOrDefault(uint32_t begin, ParseNode* expr, ParseNode* body) {
604 1112 : return new_<CaseClause>(expr, body, begin);
605 : }
606 :
607 121 : ParseNode* newContinueStatement(PropertyName* label, const TokenPos& pos) {
608 121 : return new_<ContinueStatement>(label, pos);
609 : }
610 :
611 476 : ParseNode* newBreakStatement(PropertyName* label, const TokenPos& pos) {
612 476 : return new_<BreakStatement>(label, pos);
613 : }
614 :
615 5768 : ParseNode* newReturnStatement(ParseNode* expr, const TokenPos& pos) {
616 5768 : MOZ_ASSERT_IF(expr, pos.encloses(expr->pn_pos));
617 5768 : return new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, pos, expr);
618 : }
619 :
620 348 : ParseNode* newExpressionBody(ParseNode* expr) {
621 348 : return new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, expr->pn_pos, expr);
622 : }
623 :
624 0 : ParseNode* newWithStatement(uint32_t begin, ParseNode* expr, ParseNode* body) {
625 0 : return new_<BinaryNode>(PNK_WITH, JSOP_NOP, TokenPos(begin, body->pn_pos.end),
626 0 : expr, body);
627 : }
628 :
629 0 : ParseNode* newLabeledStatement(PropertyName* label, ParseNode* stmt, uint32_t begin) {
630 0 : return new_<LabeledStatement>(label, stmt, begin);
631 : }
632 :
633 396 : ParseNode* newThrowStatement(ParseNode* expr, const TokenPos& pos) {
634 396 : MOZ_ASSERT(pos.encloses(expr->pn_pos));
635 396 : return new_<UnaryNode>(PNK_THROW, JSOP_THROW, pos, expr);
636 : }
637 :
638 483 : ParseNode* newTryStatement(uint32_t begin, ParseNode* body, ParseNode* catchList,
639 : ParseNode* finallyBlock) {
640 483 : TokenPos pos(begin, (finallyBlock ? finallyBlock : catchList)->pn_pos.end);
641 483 : return new_<TernaryNode>(PNK_TRY, JSOP_NOP, body, catchList, finallyBlock, pos);
642 : }
643 :
644 0 : ParseNode* newDebuggerStatement(const TokenPos& pos) {
645 0 : return new_<DebuggerStatement>(pos);
646 : }
647 :
648 28199 : ParseNode* newPropertyAccess(ParseNode* pn, PropertyName* name, uint32_t end) {
649 28199 : return new_<PropertyAccess>(pn, name, pn->pn_pos.begin, end);
650 : }
651 :
652 3043 : ParseNode* newPropertyByValue(ParseNode* lhs, ParseNode* index, uint32_t end) {
653 3043 : return new_<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
654 : }
655 :
656 : inline MOZ_MUST_USE bool addCatchBlock(ParseNode* catchList, ParseNode* lexicalScope,
657 : ParseNode* catchName, ParseNode* catchGuard,
658 : ParseNode* catchBody);
659 :
660 : inline MOZ_MUST_USE bool setLastFunctionFormalParameterDefault(ParseNode* funcpn,
661 : ParseNode* pn);
662 : inline void setLastFunctionFormalParameterDestructuring(ParseNode* funcpn, ParseNode* pn);
663 :
664 22880 : void checkAndSetIsDirectRHSAnonFunction(ParseNode* pn) {
665 22880 : if (IsAnonymousFunctionDefinition(pn))
666 491 : pn->setDirectRHSAnonFunction(true);
667 22880 : }
668 :
669 3238 : ParseNode* newFunctionStatement(const TokenPos& pos) {
670 3238 : return new_<CodeNode>(PNK_FUNCTION, JSOP_NOP, pos);
671 : }
672 :
673 3211 : ParseNode* newFunctionExpression(const TokenPos& pos) {
674 3211 : return new_<CodeNode>(PNK_FUNCTION, JSOP_LAMBDA, pos);
675 : }
676 :
677 712 : ParseNode* newArrowFunction(const TokenPos& pos) {
678 712 : return new_<CodeNode>(PNK_FUNCTION, JSOP_LAMBDA_ARROW, pos);
679 : }
680 :
681 0 : bool setComprehensionLambdaBody(ParseNode* pn, ParseNode* body) {
682 0 : MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
683 0 : ParseNode* paramsBody = newList(PNK_PARAMSBODY, body);
684 0 : if (!paramsBody)
685 0 : return false;
686 0 : setFunctionFormalParametersAndBody(pn, paramsBody);
687 0 : return true;
688 : }
689 5350 : void setFunctionFormalParametersAndBody(ParseNode* pn, ParseNode* kid) {
690 5350 : MOZ_ASSERT_IF(kid, kid->isKind(PNK_PARAMSBODY));
691 5350 : pn->pn_body = kid;
692 5350 : }
693 7161 : void setFunctionBox(ParseNode* pn, FunctionBox* funbox) {
694 7161 : MOZ_ASSERT(pn->isKind(PNK_FUNCTION));
695 7161 : pn->pn_funbox = funbox;
696 7161 : funbox->functionNode = pn;
697 7161 : }
698 6301 : void addFunctionFormalParameter(ParseNode* pn, ParseNode* argpn) {
699 6301 : pn->pn_body->append(argpn);
700 6301 : }
701 5350 : void setFunctionBody(ParseNode* fn, ParseNode* body) {
702 5350 : MOZ_ASSERT(fn->pn_body->isKind(PNK_PARAMSBODY));
703 5350 : fn->pn_body->append(body);
704 5350 : }
705 :
706 0 : ParseNode* newModule(const TokenPos& pos) {
707 0 : return new_<CodeNode>(PNK_MODULE, JSOP_NOP, pos);
708 : }
709 :
710 12798 : ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) {
711 12798 : return new_<LexicalScopeNode>(bindings, body);
712 : }
713 :
714 983 : Node newNewExpression(uint32_t begin, ParseNode* ctor) {
715 983 : ParseNode* newExpr = newList(PNK_NEW, begin, JSOP_NEW);
716 983 : if (!newExpr)
717 0 : return nullptr;
718 :
719 983 : addList(newExpr, ctor);
720 983 : return newExpr;
721 : }
722 :
723 5583 : ParseNode* newAssignment(ParseNodeKind kind, ParseNode* lhs, ParseNode* rhs,
724 : JSOp op)
725 : {
726 5583 : return newBinary(kind, lhs, rhs, op);
727 : }
728 :
729 : bool isUnparenthesizedYieldExpression(ParseNode* node) {
730 : return node->isKind(PNK_YIELD) && !node->isInParens();
731 : }
732 :
733 : bool isUnparenthesizedCommaExpression(ParseNode* node) {
734 : return node->isKind(PNK_COMMA) && !node->isInParens();
735 : }
736 :
737 16382 : bool isUnparenthesizedAssignment(Node node) {
738 16382 : if (node->isKind(PNK_ASSIGN) && !node->isInParens()) {
739 : // PNK_ASSIGN is also (mis)used for things like |var name = expr;|.
740 : // But this method is only called on actual expressions, so we can
741 : // just assert the node's op is the one used for plain assignment.
742 3 : MOZ_ASSERT(node->isOp(JSOP_NOP));
743 3 : return true;
744 : }
745 :
746 16379 : return false;
747 : }
748 :
749 0 : bool isUnparenthesizedUnaryExpression(ParseNode* node) {
750 0 : if (!node->isInParens()) {
751 0 : ParseNodeKind kind = node->getKind();
752 0 : return kind == PNK_VOID || kind == PNK_NOT || kind == PNK_BITNOT || kind == PNK_POS ||
753 0 : kind == PNK_NEG || IsTypeofKind(kind) || IsDeleteKind(kind);
754 : }
755 0 : return false;
756 : }
757 :
758 36995 : bool isReturnStatement(ParseNode* node) {
759 36995 : return node->isKind(PNK_RETURN);
760 : }
761 :
762 0 : bool isStatementPermittedAfterReturnStatement(ParseNode *node) {
763 0 : ParseNodeKind kind = node->getKind();
764 0 : return kind == PNK_FUNCTION || kind == PNK_VAR || kind == PNK_BREAK || kind == PNK_THROW ||
765 0 : (kind == PNK_SEMI && !node->pn_kid);
766 : }
767 :
768 196317 : bool isSuperBase(ParseNode* node) {
769 196317 : return node->isKind(PNK_SUPERBASE);
770 : }
771 :
772 : inline MOZ_MUST_USE bool finishInitializerAssignment(ParseNode* pn, ParseNode* init);
773 :
774 21070 : void setBeginPosition(ParseNode* pn, ParseNode* oth) {
775 21070 : setBeginPosition(pn, oth->pn_pos.begin);
776 21070 : }
777 21070 : void setBeginPosition(ParseNode* pn, uint32_t begin) {
778 21070 : pn->pn_pos.begin = begin;
779 21070 : MOZ_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
780 21070 : }
781 :
782 4 : void setEndPosition(ParseNode* pn, ParseNode* oth) {
783 4 : setEndPosition(pn, oth->pn_pos.end);
784 4 : }
785 37710 : void setEndPosition(ParseNode* pn, uint32_t end) {
786 37710 : pn->pn_pos.end = end;
787 37710 : MOZ_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
788 37710 : }
789 :
790 0 : uint32_t getFunctionNameOffset(ParseNode* func, TokenStreamAnyChars& ts) {
791 0 : return func->pn_pos.begin;
792 : }
793 :
794 38434 : bool isDeclarationKind(ParseNodeKind kind) {
795 38434 : return kind == PNK_VAR || kind == PNK_LET || kind == PNK_CONST;
796 : }
797 :
798 27418 : ParseNode* newList(ParseNodeKind kind, const TokenPos& pos, JSOp op = JSOP_NOP) {
799 27418 : MOZ_ASSERT(!isDeclarationKind(kind));
800 27418 : return new_<ListNode>(kind, op, pos);
801 : }
802 :
803 : private:
804 983 : ParseNode* newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) {
805 983 : return newList(kind, TokenPos(begin, begin + 1), op);
806 : }
807 :
808 : template<typename T>
809 : ParseNode* newList(ParseNodeKind kind, const T& begin, JSOp op = JSOP_NOP) = delete;
810 :
811 : public:
812 360 : ParseNode* newList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
813 360 : MOZ_ASSERT(!isDeclarationKind(kind));
814 360 : return new_<ListNode>(kind, op, kid);
815 : }
816 :
817 9834 : ParseNode* newDeclarationList(ParseNodeKind kind, const TokenPos& pos, JSOp op) {
818 9834 : MOZ_ASSERT(isDeclarationKind(kind));
819 9834 : return new_<ListNode>(kind, op, pos);
820 : }
821 :
822 816 : bool isDeclarationList(ParseNode* node) {
823 816 : return isDeclarationKind(node->getKind());
824 : }
825 :
826 408 : ParseNode* singleBindingFromDeclaration(ParseNode* decl) {
827 408 : MOZ_ASSERT(isDeclarationList(decl));
828 408 : MOZ_ASSERT(decl->pn_count == 1);
829 408 : return decl->pn_head;
830 : }
831 :
832 461 : ParseNode* newCatchList(const TokenPos& pos) {
833 461 : return new_<ListNode>(PNK_CATCHLIST, JSOP_NOP, pos);
834 : }
835 :
836 97 : ParseNode* newCommaExpressionList(ParseNode* kid) {
837 97 : return newList(PNK_COMMA, kid, JSOP_NOP);
838 : }
839 :
840 69963 : void addList(ParseNode* list, ParseNode* kid) {
841 69963 : list->append(kid);
842 69963 : }
843 :
844 21073 : void setOp(ParseNode* pn, JSOp op) {
845 21073 : pn->setOp(op);
846 21073 : }
847 3081 : void setListFlag(ParseNode* pn, unsigned flag) {
848 3081 : MOZ_ASSERT(pn->isArity(PN_LIST));
849 3081 : pn->pn_xflags |= flag;
850 3081 : }
851 1808 : MOZ_MUST_USE ParseNode* parenthesize(ParseNode* pn) {
852 1808 : pn->setInParens(true);
853 1808 : return pn;
854 : }
855 26 : MOZ_MUST_USE ParseNode* setLikelyIIFE(ParseNode* pn) {
856 26 : return parenthesize(pn);
857 : }
858 112 : void setInDirectivePrologue(ParseNode* pn) {
859 112 : pn->pn_prologue = true;
860 112 : }
861 :
862 6207 : bool isConstant(ParseNode* pn) {
863 6207 : return pn->isConstant();
864 : }
865 :
866 : bool isUnparenthesizedName(ParseNode* node) {
867 : return node->isKind(PNK_NAME) && !node->isInParens();
868 : }
869 :
870 17092 : bool isNameAnyParentheses(ParseNode* node) {
871 17092 : return node->isKind(PNK_NAME);
872 : }
873 :
874 7828 : bool isArgumentsAnyParentheses(ParseNode* node, JSContext* cx) {
875 7828 : return node->isKind(PNK_NAME) && node->pn_atom == cx->names().arguments;
876 : }
877 :
878 18033 : bool isEvalAnyParentheses(ParseNode* node, JSContext* cx) {
879 18033 : return node->isKind(PNK_NAME) && node->pn_atom == cx->names().eval;
880 : }
881 :
882 5025 : const char* nameIsArgumentsEvalAnyParentheses(ParseNode* node, JSContext* cx) {
883 5025 : MOZ_ASSERT(isNameAnyParentheses(node),
884 : "must only call this function on known names");
885 :
886 5025 : if (isEvalAnyParentheses(node, cx))
887 0 : return js_eval_str;
888 5025 : if (isArgumentsAnyParentheses(node, cx))
889 0 : return js_arguments_str;
890 5025 : return nullptr;
891 : }
892 :
893 10231 : bool isAsyncKeyword(ParseNode* node, JSContext* cx) {
894 20407 : return node->isKind(PNK_NAME) &&
895 10309 : node->pn_pos.begin + strlen("async") == node->pn_pos.end &&
896 10309 : node->pn_atom == cx->names().async;
897 : }
898 :
899 : bool isCall(ParseNode* pn) {
900 : return pn->isKind(PNK_CALL);
901 : }
902 21070 : PropertyName* maybeDottedProperty(ParseNode* pn) {
903 21070 : return pn->is<PropertyAccess>() ? &pn->as<PropertyAccess>().name() : nullptr;
904 : }
905 5289 : JSAtom* isStringExprStatement(ParseNode* pn, TokenPos* pos) {
906 5289 : if (JSAtom* atom = pn->isStringExprStatement()) {
907 112 : *pos = pn->pn_kid->pn_pos;
908 112 : return atom;
909 : }
910 5177 : return nullptr;
911 : }
912 :
913 2515 : void adjustGetToSet(ParseNode* node) {
914 2515 : node->setOp(node->isOp(JSOP_GETLOCAL) ? JSOP_SETLOCAL : JSOP_SETNAME);
915 2515 : }
916 :
917 5739 : bool canSkipLazyInnerFunctions() {
918 5739 : return !!lazyOuterFunction_;
919 : }
920 96716 : bool canSkipLazyClosedOverBindings() {
921 96716 : return !!lazyOuterFunction_;
922 : }
923 8144 : LazyScript* lazyOuterFunction() {
924 8144 : return lazyOuterFunction_;
925 : }
926 260 : JSFunction* nextLazyInnerFunction() {
927 260 : MOZ_ASSERT(lazyInnerFunctionIndex < lazyOuterFunction()->numInnerFunctions());
928 260 : return lazyOuterFunction()->innerFunctions()[lazyInnerFunctionIndex++];
929 : }
930 3682 : JSAtom* nextLazyClosedOverBinding() {
931 3682 : MOZ_ASSERT(lazyClosedOverBindingIndex < lazyOuterFunction()->numClosedOverBindings());
932 3682 : return lazyOuterFunction()->closedOverBindings()[lazyClosedOverBindingIndex++];
933 : }
934 : };
935 :
936 : inline bool
937 461 : FullParseHandler::addCatchBlock(ParseNode* catchList, ParseNode* lexicalScope,
938 : ParseNode* catchName, ParseNode* catchGuard,
939 : ParseNode* catchBody)
940 : {
941 461 : ParseNode* catchpn = newTernary(PNK_CATCH, catchName, catchGuard, catchBody);
942 461 : if (!catchpn)
943 0 : return false;
944 461 : catchList->append(lexicalScope);
945 461 : lexicalScope->setScopeBody(catchpn);
946 461 : return true;
947 : }
948 :
949 : inline bool
950 213 : FullParseHandler::setLastFunctionFormalParameterDefault(ParseNode* funcpn,
951 : ParseNode* defaultValue)
952 : {
953 213 : ParseNode* arg = funcpn->pn_body->last();
954 213 : ParseNode* pn = newBinary(PNK_ASSIGN, arg, defaultValue, JSOP_NOP);
955 213 : if (!pn)
956 0 : return false;
957 :
958 213 : checkAndSetIsDirectRHSAnonFunction(defaultValue);
959 :
960 213 : funcpn->pn_body->pn_pos.end = pn->pn_pos.end;
961 213 : ParseNode* pnchild = funcpn->pn_body->pn_head;
962 213 : ParseNode* pnlast = funcpn->pn_body->last();
963 213 : MOZ_ASSERT(pnchild);
964 213 : if (pnchild == pnlast) {
965 38 : funcpn->pn_body->pn_head = pn;
966 : } else {
967 409 : while (pnchild->pn_next != pnlast) {
968 117 : MOZ_ASSERT(pnchild->pn_next);
969 117 : pnchild = pnchild->pn_next;
970 : }
971 175 : pnchild->pn_next = pn;
972 : }
973 213 : funcpn->pn_body->pn_tail = &pn->pn_next;
974 :
975 213 : return true;
976 : }
977 :
978 : inline bool
979 8996 : FullParseHandler::finishInitializerAssignment(ParseNode* pn, ParseNode* init)
980 : {
981 8996 : pn->pn_expr = init;
982 8996 : pn->setOp(JSOP_SETNAME);
983 :
984 : /* The declarator's position must include the initializer. */
985 8996 : pn->pn_pos.end = init->pn_pos.end;
986 8996 : return true;
987 : }
988 :
989 : } // namespace frontend
990 : } // namespace js
991 :
992 : #endif /* frontend_FullParseHandler_h */
|