Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
* vim: set ts=8 sts=2 et sw=2 tw=80:
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 <cstddef> // std::nullptr_t
14
#include <string.h>
15
16
#include "frontend/ParseNode.h"
17
#include "frontend/SharedContext.h"
18
#include "frontend/Stencil.h"
19
#include "vm/JSContext.h"
20
21
namespace js {
22
23
class RegExpObject;
24
25
namespace frontend {
26
27
class TokenStreamAnyChars;
28
29
enum class SourceKind {
30
// We are parsing from a text source (Parser.h)
31
Text,
32
// We are parsing from a binary source (BinASTParser.h)
33
Binary,
34
};
35
36
// Parse handler used when generating a full parse tree for all code which the
37
// parser encounters.
38
class FullParseHandler {
39
ParseNodeAllocator allocator;
40
41
ParseNode* allocParseNode(size_t size) {
42
return static_cast<ParseNode*>(allocator.allocNode(size));
43
}
44
45
/*
46
* If this is a full parse to construct the bytecode for a function that
47
* was previously lazily parsed, we still don't want to full parse the
48
* inner functions. These members are used for this functionality:
49
*
50
* - lazyOuterFunction_ holds the lazyScript for this current parse
51
* - lazyInnerFunctionIndex is used as we skip over inner functions
52
* (see skipLazyInnerFunction),
53
*/
54
const Rooted<LazyScript*> lazyOuterFunction_;
55
size_t lazyInnerFunctionIndex;
56
57
size_t lazyClosedOverBindingIndex;
58
59
const SourceKind sourceKind_;
60
61
public:
62
/* new_ methods for creating parse nodes. These report OOM on context. */
63
JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
64
65
// FIXME: Use ListNode instead of ListNodeType as an alias (bug 1489008).
66
using Node = ParseNode*;
67
68
#define DECLARE_TYPE(typeName, longTypeName, asMethodName) \
69
using longTypeName = typeName*;
70
FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
71
#undef DECLARE_TYPE
72
73
using NullNode = std::nullptr_t;
74
75
bool isPropertyAccess(Node node) {
76
return node->isKind(ParseNodeKind::DotExpr) ||
77
node->isKind(ParseNodeKind::ElemExpr);
78
}
79
80
bool isFunctionCall(Node node) {
81
// Note: super() is a special form, *not* a function call.
82
return node->isKind(ParseNodeKind::CallExpr);
83
}
84
85
static bool isUnparenthesizedDestructuringPattern(Node node) {
86
return !node->isInParens() && (node->isKind(ParseNodeKind::ObjectExpr) ||
87
node->isKind(ParseNodeKind::ArrayExpr));
88
}
89
90
static bool isParenthesizedDestructuringPattern(Node node) {
91
// Technically this isn't a destructuring pattern at all -- the grammar
92
// doesn't treat it as such. But we need to know when this happens to
93
// consider it a SyntaxError rather than an invalid-left-hand-side
94
// ReferenceError.
95
return node->isInParens() && (node->isKind(ParseNodeKind::ObjectExpr) ||
96
node->isKind(ParseNodeKind::ArrayExpr));
97
}
98
99
FullParseHandler(JSContext* cx, LifoAlloc& alloc,
100
LazyScript* lazyOuterFunction,
101
SourceKind kind = SourceKind::Text)
102
: allocator(cx, alloc),
103
lazyOuterFunction_(cx, lazyOuterFunction),
104
lazyInnerFunctionIndex(0),
105
lazyClosedOverBindingIndex(0),
106
sourceKind_(kind) {
107
// The LazyScript::gcthings() array contains the inner function list
108
// followed by the closed-over bindings data. Advance the index for
109
// closed-over bindings to the end of the inner functions. The
110
// nextLazyInnerFunction / nextLazyClosedOverBinding accessors confirm we
111
// have the expected types. See also: LazyScript::Create.
112
if (lazyOuterFunction) {
113
for (JS::GCCellPtr gcThing : lazyOuterFunction->gcthings()) {
114
if (gcThing.is<JSObject>()) {
115
lazyClosedOverBindingIndex++;
116
} else {
117
break;
118
}
119
}
120
}
121
}
122
123
static NullNode null() { return NullNode(); }
124
125
#define DECLARE_AS(typeName, longTypeName, asMethodName) \
126
static longTypeName asMethodName(Node node) { return &node->as<typeName>(); }
127
FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
128
#undef DECLARE_AS
129
130
// The FullParseHandler may be used to create nodes for text sources
131
// (from Parser.h) or for binary sources (from BinASTParser.h). In the latter
132
// case, some common assumptions on offsets are incorrect, e.g. in `a + b`,
133
// `a`, `b` and `+` may be stored in any order. We use `sourceKind()`
134
// to determine whether we need to check these assumptions.
135
SourceKind sourceKind() const { return sourceKind_; }
136
137
NameNodeType newName(PropertyName* name, const TokenPos& pos, JSContext* cx) {
138
return new_<NameNode>(ParseNodeKind::Name, name, pos);
139
}
140
141
UnaryNodeType newComputedName(Node expr, uint32_t begin, uint32_t end) {
142
TokenPos pos(begin, end);
143
return new_<UnaryNode>(ParseNodeKind::ComputedName, pos, expr);
144
}
145
146
NameNodeType newObjectLiteralPropertyName(JSAtom* atom, const TokenPos& pos) {
147
return new_<NameNode>(ParseNodeKind::ObjectPropertyName, atom, pos);
148
}
149
150
NumericLiteralType newNumber(double value, DecimalPoint decimalPoint,
151
const TokenPos& pos) {
152
return new_<NumericLiteral>(value, decimalPoint, pos);
153
}
154
155
BigIntLiteralType newBigInt(BigIntIndex index, ParseInfo& parseInfo,
156
const TokenPos& pos) {
157
return new_<BigIntLiteral>(index, parseInfo, pos);
158
}
159
160
BooleanLiteralType newBooleanLiteral(bool cond, const TokenPos& pos) {
161
return new_<BooleanLiteral>(cond, pos);
162
}
163
164
NameNodeType newStringLiteral(JSAtom* atom, const TokenPos& pos) {
165
return new_<NameNode>(ParseNodeKind::StringExpr, atom, pos);
166
}
167
168
NameNodeType newTemplateStringLiteral(JSAtom* atom, const TokenPos& pos) {
169
return new_<NameNode>(ParseNodeKind::TemplateStringExpr, atom, pos);
170
}
171
172
CallSiteNodeType newCallSiteObject(uint32_t begin) {
173
CallSiteNode* callSiteObj = new_<CallSiteNode>(begin);
174
if (!callSiteObj) {
175
return null();
176
}
177
178
ListNode* rawNodes = newArrayLiteral(callSiteObj->pn_pos.begin);
179
if (!rawNodes) {
180
return null();
181
}
182
183
addArrayElement(callSiteObj, rawNodes);
184
185
return callSiteObj;
186
}
187
188
void addToCallSiteObject(CallSiteNodeType callSiteObj, Node rawNode,
189
Node cookedNode) {
190
MOZ_ASSERT(callSiteObj->isKind(ParseNodeKind::CallSiteObj));
191
MOZ_ASSERT(rawNode->isKind(ParseNodeKind::TemplateStringExpr));
192
MOZ_ASSERT(cookedNode->isKind(ParseNodeKind::TemplateStringExpr) ||
193
cookedNode->isKind(ParseNodeKind::RawUndefinedExpr));
194
195
addArrayElement(callSiteObj, cookedNode);
196
addArrayElement(callSiteObj->rawNodes(), rawNode);
197
198
/*
199
* We don't know when the last noSubstTemplate will come in, and we
200
* don't want to deal with this outside this method
201
*/
202
setEndPosition(callSiteObj, callSiteObj->rawNodes());
203
}
204
205
ThisLiteralType newThisLiteral(const TokenPos& pos, Node thisName) {
206
return new_<ThisLiteral>(pos, thisName);
207
}
208
209
NullLiteralType newNullLiteral(const TokenPos& pos) {
210
return new_<NullLiteral>(pos);
211
}
212
213
RawUndefinedLiteralType newRawUndefinedLiteral(const TokenPos& pos) {
214
return new_<RawUndefinedLiteral>(pos);
215
}
216
217
// The Boxer object here is any object that can allocate ObjectBoxes.
218
// Specifically, a Boxer has a .newObjectBox(T) method that accepts a
219
// Rooted<RegExpObject*> argument and returns an ObjectBox*.
220
//
221
// Used only by BinAST now.
222
template <class Boxer>
223
RegExpLiteralType newRegExp(RegExpObject* reobj, const TokenPos& pos,
224
Boxer& boxer) {
225
ObjectBox* objbox = boxer.newObjectBox(reobj);
226
if (!objbox) {
227
return null();
228
}
229
return new_<RegExpLiteral>(objbox, pos);
230
}
231
232
RegExpLiteralType newRegExp(RegExpIndex index, const TokenPos& pos) {
233
return new_<RegExpLiteral>(index, pos);
234
}
235
236
ConditionalExpressionType newConditional(Node cond, Node thenExpr,
237
Node elseExpr) {
238
return new_<ConditionalExpression>(cond, thenExpr, elseExpr);
239
}
240
241
UnaryNodeType newDelete(uint32_t begin, Node expr) {
242
if (expr->isKind(ParseNodeKind::Name)) {
243
return newUnary(ParseNodeKind::DeleteNameExpr, begin, expr);
244
}
245
246
if (expr->isKind(ParseNodeKind::DotExpr)) {
247
return newUnary(ParseNodeKind::DeletePropExpr, begin, expr);
248
}
249
250
if (expr->isKind(ParseNodeKind::ElemExpr)) {
251
return newUnary(ParseNodeKind::DeleteElemExpr, begin, expr);
252
}
253
254
if (expr->isKind(ParseNodeKind::OptionalChain)) {
255
Node kid = expr->as<UnaryNode>().kid();
256
// Handle property deletion explictly. OptionalCall is handled
257
// via DeleteExpr.
258
if (kid->isKind(ParseNodeKind::DotExpr) ||
259
kid->isKind(ParseNodeKind::OptionalDotExpr) ||
260
kid->isKind(ParseNodeKind::ElemExpr) ||
261
kid->isKind(ParseNodeKind::OptionalElemExpr)) {
262
return newUnary(ParseNodeKind::DeleteOptionalChainExpr, begin, kid);
263
}
264
}
265
266
return newUnary(ParseNodeKind::DeleteExpr, begin, expr);
267
}
268
269
UnaryNodeType newTypeof(uint32_t begin, Node kid) {
270
ParseNodeKind pnk = kid->isKind(ParseNodeKind::Name)
271
? ParseNodeKind::TypeOfNameExpr
272
: ParseNodeKind::TypeOfExpr;
273
return newUnary(pnk, begin, kid);
274
}
275
276
UnaryNodeType newUnary(ParseNodeKind kind, uint32_t begin, Node kid) {
277
TokenPos pos(begin, kid->pn_pos.end);
278
return new_<UnaryNode>(kind, pos, kid);
279
}
280
281
UnaryNodeType newUpdate(ParseNodeKind kind, uint32_t begin, Node kid) {
282
TokenPos pos(begin, kid->pn_pos.end);
283
return new_<UnaryNode>(kind, pos, kid);
284
}
285
286
UnaryNodeType newSpread(uint32_t begin, Node kid) {
287
TokenPos pos(begin, kid->pn_pos.end);
288
return new_<UnaryNode>(ParseNodeKind::Spread, pos, kid);
289
}
290
291
private:
292
BinaryNodeType newBinary(ParseNodeKind kind, Node left, Node right) {
293
TokenPos pos(left->pn_pos.begin, right->pn_pos.end);
294
return new_<BinaryNode>(kind, pos, left, right);
295
}
296
297
public:
298
Node appendOrCreateList(ParseNodeKind kind, Node left, Node right,
299
ParseContext* pc) {
300
return ParseNode::appendOrCreateList(kind, left, right, this, pc);
301
}
302
303
// Expressions
304
305
ListNodeType newArrayLiteral(uint32_t begin) {
306
return new_<ListNode>(ParseNodeKind::ArrayExpr, TokenPos(begin, begin + 1));
307
}
308
309
MOZ_MUST_USE bool addElision(ListNodeType literal, const TokenPos& pos) {
310
MOZ_ASSERT(literal->isKind(ParseNodeKind::ArrayExpr));
311
312
NullaryNode* elision = new_<NullaryNode>(ParseNodeKind::Elision, pos);
313
if (!elision) {
314
return false;
315
}
316
addList(/* list = */ literal, /* kid = */ elision);
317
literal->setHasArrayHoleOrSpread();
318
literal->setHasNonConstInitializer();
319
return true;
320
}
321
322
MOZ_MUST_USE bool addSpreadElement(ListNodeType literal, uint32_t begin,
323
Node inner) {
324
MOZ_ASSERT(literal->isKind(ParseNodeKind::ArrayExpr));
325
326
UnaryNodeType spread = newSpread(begin, inner);
327
if (!spread) {
328
return false;
329
}
330
addList(/* list = */ literal, /* kid = */ spread);
331
literal->setHasArrayHoleOrSpread();
332
literal->setHasNonConstInitializer();
333
return true;
334
}
335
336
void addArrayElement(ListNodeType literal, Node element) {
337
if (!element->isConstant()) {
338
literal->setHasNonConstInitializer();
339
}
340
addList(/* list = */ literal, /* kid = */ element);
341
}
342
343
CallNodeType newCall(Node callee, Node args, JSOp callOp) {
344
return new_<CallNode>(ParseNodeKind::CallExpr, callOp, callee, args);
345
}
346
347
OptionalCallNodeType newOptionalCall(Node callee, Node args, JSOp callOp) {
348
return new_<CallNode>(ParseNodeKind::OptionalCallExpr, callOp, callee,
349
args);
350
}
351
352
ListNodeType newArguments(const TokenPos& pos) {
353
return new_<ListNode>(ParseNodeKind::Arguments, pos);
354
}
355
356
CallNodeType newSuperCall(Node callee, Node args, bool isSpread) {
357
return new_<CallNode>(ParseNodeKind::SuperCallExpr,
358
isSpread ? JSOp::SpreadSuperCall : JSOp::SuperCall,
359
callee, args);
360
}
361
362
CallNodeType newTaggedTemplate(Node tag, Node args, JSOp callOp) {
363
return new_<CallNode>(ParseNodeKind::TaggedTemplateExpr, callOp, tag, args);
364
}
365
366
ListNodeType newObjectLiteral(uint32_t begin) {
367
return new_<ListNode>(ParseNodeKind::ObjectExpr,
368
TokenPos(begin, begin + 1));
369
}
370
371
ClassNodeType newClass(Node name, Node heritage,
372
LexicalScopeNodeType memberBlock,
373
const TokenPos& pos) {
374
return new_<ClassNode>(name, heritage, memberBlock, pos);
375
}
376
ListNodeType newClassMemberList(uint32_t begin) {
377
return new_<ListNode>(ParseNodeKind::ClassMemberList,
378
TokenPos(begin, begin + 1));
379
}
380
ClassNamesType newClassNames(Node outer, Node inner, const TokenPos& pos) {
381
return new_<ClassNames>(outer, inner, pos);
382
}
383
BinaryNodeType newNewTarget(NullaryNodeType newHolder,
384
NullaryNodeType targetHolder) {
385
return new_<BinaryNode>(ParseNodeKind::NewTargetExpr, newHolder,
386
targetHolder);
387
}
388
NullaryNodeType newPosHolder(const TokenPos& pos) {
389
return new_<NullaryNode>(ParseNodeKind::PosHolder, pos);
390
}
391
UnaryNodeType newSuperBase(Node thisName, const TokenPos& pos) {
392
return new_<UnaryNode>(ParseNodeKind::SuperBase, pos, thisName);
393
}
394
MOZ_MUST_USE bool addPrototypeMutation(ListNodeType literal, uint32_t begin,
395
Node expr) {
396
MOZ_ASSERT(literal->isKind(ParseNodeKind::ObjectExpr));
397
398
// Object literals with mutated [[Prototype]] are non-constant so that
399
// singleton objects will have Object.prototype as their [[Prototype]].
400
literal->setHasNonConstInitializer();
401
402
UnaryNode* mutation = newUnary(ParseNodeKind::MutateProto, begin, expr);
403
if (!mutation) {
404
return false;
405
}
406
addList(/* list = */ literal, /* kid = */ mutation);
407
return true;
408
}
409
410
BinaryNodeType newPropertyDefinition(Node key, Node val) {
411
MOZ_ASSERT(isUsableAsObjectPropertyName(key));
412
checkAndSetIsDirectRHSAnonFunction(val);
413
return new_<PropertyDefinition>(key, val, AccessorType::None);
414
}
415
416
void addPropertyDefinition(ListNodeType literal, BinaryNodeType propdef) {
417
MOZ_ASSERT(literal->isKind(ParseNodeKind::ObjectExpr));
418
MOZ_ASSERT(propdef->isKind(ParseNodeKind::PropertyDefinition));
419
420
if (!propdef->right()->isConstant()) {
421
literal->setHasNonConstInitializer();
422
}
423
424
addList(/* list = */ literal, /* kid = */ propdef);
425
}
426
427
MOZ_MUST_USE bool addPropertyDefinition(ListNodeType literal, Node key,
428
Node val) {
429
BinaryNode* propdef = newPropertyDefinition(key, val);
430
if (!propdef) {
431
return false;
432
}
433
addPropertyDefinition(literal, propdef);
434
return true;
435
}
436
437
MOZ_MUST_USE bool addShorthand(ListNodeType literal, NameNodeType name,
438
NameNodeType expr) {
439
MOZ_ASSERT(literal->isKind(ParseNodeKind::ObjectExpr));
440
MOZ_ASSERT(name->isKind(ParseNodeKind::ObjectPropertyName));
441
MOZ_ASSERT(expr->isKind(ParseNodeKind::Name));
442
MOZ_ASSERT(name->atom() == expr->atom());
443
444
literal->setHasNonConstInitializer();
445
BinaryNode* propdef = newBinary(ParseNodeKind::Shorthand, name, expr);
446
if (!propdef) {
447
return false;
448
}
449
addList(/* list = */ literal, /* kid = */ propdef);
450
return true;
451
}
452
453
MOZ_MUST_USE bool addSpreadProperty(ListNodeType literal, uint32_t begin,
454
Node inner) {
455
MOZ_ASSERT(literal->isKind(ParseNodeKind::ObjectExpr));
456
457
literal->setHasNonConstInitializer();
458
ParseNode* spread = newSpread(begin, inner);
459
if (!spread) {
460
return false;
461
}
462
addList(/* list = */ literal, /* kid = */ spread);
463
return true;
464
}
465
466
MOZ_MUST_USE bool addObjectMethodDefinition(ListNodeType literal, Node key,
467
FunctionNodeType funNode,
468
AccessorType atype) {
469
literal->setHasNonConstInitializer();
470
471
checkAndSetIsDirectRHSAnonFunction(funNode);
472
473
ParseNode* propdef =
474
newObjectMethodOrPropertyDefinition(key, funNode, atype);
475
if (!propdef) {
476
return false;
477
}
478
479
addList(/* list = */ literal, /* kid = */ propdef);
480
return true;
481
}
482
483
MOZ_MUST_USE ClassMethod* newClassMethodDefinition(Node key,
484
FunctionNodeType funNode,
485
AccessorType atype,
486
bool isStatic) {
487
MOZ_ASSERT(isUsableAsObjectPropertyName(key));
488
489
checkAndSetIsDirectRHSAnonFunction(funNode);
490
491
return new_<ClassMethod>(key, funNode, atype, isStatic);
492
}
493
494
MOZ_MUST_USE ClassField* newClassFieldDefinition(
495
Node name, FunctionNodeType initializer) {
496
MOZ_ASSERT(isUsableAsObjectPropertyName(name));
497
498
return new_<ClassField>(name, initializer);
499
}
500
501
MOZ_MUST_USE bool addClassMemberDefinition(ListNodeType memberList,
502
Node member) {
503
MOZ_ASSERT(memberList->isKind(ParseNodeKind::ClassMemberList));
504
// Constructors can be surrounded by LexicalScopes.
505
MOZ_ASSERT(member->isKind(ParseNodeKind::ClassMethod) ||
506
member->isKind(ParseNodeKind::ClassField) ||
507
(member->isKind(ParseNodeKind::LexicalScope) &&
508
member->as<LexicalScopeNode>().scopeBody()->isKind(
509
ParseNodeKind::ClassMethod)));
510
511
addList(/* list = */ memberList, /* kid = */ member);
512
return true;
513
}
514
515
void deleteConstructorScope(JSContext* cx, ListNodeType memberList) {
516
for (ParseNode* member : memberList->contents()) {
517
if (member->is<LexicalScopeNode>()) {
518
LexicalScopeNode* node = &member->as<LexicalScopeNode>();
519
MOZ_ASSERT(node->scopeBody()->isKind(ParseNodeKind::ClassMethod));
520
MOZ_ASSERT(node->scopeBody()->as<ClassMethod>().method().syntaxKind() ==
521
FunctionSyntaxKind::ClassConstructor ||
522
node->scopeBody()->as<ClassMethod>().method().syntaxKind() ==
523
FunctionSyntaxKind::DerivedClassConstructor);
524
// Check isEmptyScope instead of asserting, because this function must
525
// be idempotent: when parsing via asm.js, this function is called, then
526
// later, after asm.js parsing fails, this function is called again on
527
// the same scope. (See bug 1555979)
528
if (!node->isEmptyScope()) {
529
MOZ_ASSERT(node->scopeBindings()->length == 1);
530
MOZ_ASSERT(node->scopeBindings()->trailingNames[0].name() ==
531
cx->names().dotInitializers);
532
node->clearScopeBindings();
533
}
534
}
535
}
536
}
537
538
UnaryNodeType newInitialYieldExpression(uint32_t begin, Node gen) {
539
TokenPos pos(begin, begin + 1);
540
return new_<UnaryNode>(ParseNodeKind::InitialYield, pos, gen);
541
}
542
543
UnaryNodeType newYieldExpression(uint32_t begin, Node value) {
544
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
545
return new_<UnaryNode>(ParseNodeKind::YieldExpr, pos, value);
546
}
547
548
UnaryNodeType newYieldStarExpression(uint32_t begin, Node value) {
549
TokenPos pos(begin, value->pn_pos.end);
550
return new_<UnaryNode>(ParseNodeKind::YieldStarExpr, pos, value);
551
}
552
553
UnaryNodeType newAwaitExpression(uint32_t begin, Node value) {
554
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
555
return new_<UnaryNode>(ParseNodeKind::AwaitExpr, pos, value);
556
}
557
558
UnaryNodeType newOptionalChain(uint32_t begin, Node value) {
559
TokenPos pos(begin, value->pn_pos.end);
560
return new_<UnaryNode>(ParseNodeKind::OptionalChain, pos, value);
561
}
562
563
// Statements
564
565
ListNodeType newStatementList(const TokenPos& pos) {
566
return new_<ListNode>(ParseNodeKind::StatementList, pos);
567
}
568
569
MOZ_MUST_USE bool isFunctionStmt(Node stmt) {
570
while (stmt->isKind(ParseNodeKind::LabelStmt)) {
571
stmt = stmt->as<LabeledStatement>().statement();
572
}
573
return stmt->is<FunctionNode>();
574
}
575
576
void addStatementToList(ListNodeType list, Node stmt) {
577
MOZ_ASSERT(list->isKind(ParseNodeKind::StatementList));
578
579
addList(/* list = */ list, /* kid = */ stmt);
580
581
if (isFunctionStmt(stmt)) {
582
// Notify the emitter that the block contains body-level function
583
// definitions that should be processed before the rest of nodes.
584
list->setHasTopLevelFunctionDeclarations();
585
}
586
}
587
588
void setListEndPosition(ListNodeType list, const TokenPos& pos) {
589
MOZ_ASSERT(list->isKind(ParseNodeKind::StatementList));
590
list->pn_pos.end = pos.end;
591
}
592
593
void addCaseStatementToList(ListNodeType list, CaseClauseType caseClause) {
594
MOZ_ASSERT(list->isKind(ParseNodeKind::StatementList));
595
596
addList(/* list = */ list, /* kid = */ caseClause);
597
598
if (caseClause->statementList()->hasTopLevelFunctionDeclarations()) {
599
list->setHasTopLevelFunctionDeclarations();
600
}
601
}
602
603
MOZ_MUST_USE bool prependInitialYield(ListNodeType stmtList, Node genName) {
604
MOZ_ASSERT(stmtList->isKind(ParseNodeKind::StatementList));
605
606
TokenPos yieldPos(stmtList->pn_pos.begin, stmtList->pn_pos.begin + 1);
607
NullaryNode* makeGen =
608
new_<NullaryNode>(ParseNodeKind::Generator, yieldPos);
609
if (!makeGen) {
610
return false;
611
}
612
613
ParseNode* genInit =
614
newAssignment(ParseNodeKind::AssignExpr, /* lhs = */ genName,
615
/* rhs = */ makeGen);
616
if (!genInit) {
617
return false;
618
}
619
620
UnaryNode* initialYield =
621
newInitialYieldExpression(yieldPos.begin, genInit);
622
if (!initialYield) {
623
return false;
624
}
625
626
stmtList->prepend(initialYield);
627
return true;
628
}
629
630
BinaryNodeType newSetThis(Node thisName, Node value) {
631
return newBinary(ParseNodeKind::SetThis, thisName, value);
632
}
633
634
NullaryNodeType newEmptyStatement(const TokenPos& pos) {
635
return new_<NullaryNode>(ParseNodeKind::EmptyStmt, pos);
636
}
637
638
BinaryNodeType newImportDeclaration(Node importSpecSet, Node moduleSpec,
639
const TokenPos& pos) {
640
return new_<BinaryNode>(ParseNodeKind::ImportDecl, pos, importSpecSet,
641
moduleSpec);
642
}
643
644
BinaryNodeType newImportSpec(Node importNameNode, Node bindingName) {
645
return newBinary(ParseNodeKind::ImportSpec, importNameNode, bindingName);
646
}
647
648
UnaryNodeType newExportDeclaration(Node kid, const TokenPos& pos) {
649
return new_<UnaryNode>(ParseNodeKind::ExportStmt, pos, kid);
650
}
651
652
BinaryNodeType newExportFromDeclaration(uint32_t begin, Node exportSpecSet,
653
Node moduleSpec) {
654
BinaryNode* decl = new_<BinaryNode>(ParseNodeKind::ExportFromStmt,
655
exportSpecSet, moduleSpec);
656
if (!decl) {
657
return nullptr;
658
}
659
decl->pn_pos.begin = begin;
660
return decl;
661
}
662
663
BinaryNodeType newExportDefaultDeclaration(Node kid, Node maybeBinding,
664
const TokenPos& pos) {
665
if (maybeBinding) {
666
MOZ_ASSERT(maybeBinding->isKind(ParseNodeKind::Name));
667
MOZ_ASSERT(!maybeBinding->isInParens());
668
669
checkAndSetIsDirectRHSAnonFunction(kid);
670
}
671
672
return new_<BinaryNode>(ParseNodeKind::ExportDefaultStmt, pos, kid,
673
maybeBinding);
674
}
675
676
BinaryNodeType newExportSpec(Node bindingName, Node exportName) {
677
return newBinary(ParseNodeKind::ExportSpec, bindingName, exportName);
678
}
679
680
NullaryNodeType newExportBatchSpec(const TokenPos& pos) {
681
return new_<NullaryNode>(ParseNodeKind::ExportBatchSpecStmt, pos);
682
}
683
684
BinaryNodeType newImportMeta(NullaryNodeType importHolder,
685
NullaryNodeType metaHolder) {
686
return new_<BinaryNode>(ParseNodeKind::ImportMetaExpr, importHolder,
687
metaHolder);
688
}
689
690
BinaryNodeType newCallImport(NullaryNodeType importHolder, Node singleArg) {
691
return new_<BinaryNode>(ParseNodeKind::CallImportExpr, importHolder,
692
singleArg);
693
}
694
695
UnaryNodeType newExprStatement(Node expr, uint32_t end) {
696
MOZ_ASSERT_IF(sourceKind() == SourceKind::Text, expr->pn_pos.end <= end);
697
return new_<UnaryNode>(ParseNodeKind::ExpressionStmt,
698
TokenPos(expr->pn_pos.begin, end), expr);
699
}
700
701
UnaryNodeType newExprStatement(Node expr) {
702
return newExprStatement(expr, expr->pn_pos.end);
703
}
704
705
TernaryNodeType newIfStatement(uint32_t begin, Node cond, Node thenBranch,
706
Node elseBranch) {
707
TernaryNode* node =
708
new_<TernaryNode>(ParseNodeKind::IfStmt, cond, thenBranch, elseBranch);
709
if (!node) {
710
return nullptr;
711
}
712
node->pn_pos.begin = begin;
713
return node;
714
}
715
716
BinaryNodeType newDoWhileStatement(Node body, Node cond,
717
const TokenPos& pos) {
718
return new_<BinaryNode>(ParseNodeKind::DoWhileStmt, pos, body, cond);
719
}
720
721
BinaryNodeType newWhileStatement(uint32_t begin, Node cond, Node body) {
722
TokenPos pos(begin, body->pn_pos.end);
723
return new_<BinaryNode>(ParseNodeKind::WhileStmt, pos, cond, body);
724
}
725
726
ForNodeType newForStatement(uint32_t begin, TernaryNodeType forHead,
727
Node body, unsigned iflags) {
728
return new_<ForNode>(TokenPos(begin, body->pn_pos.end), forHead, body,
729
iflags);
730
}
731
732
TernaryNodeType newForHead(Node init, Node test, Node update,
733
const TokenPos& pos) {
734
return new_<TernaryNode>(ParseNodeKind::ForHead, init, test, update, pos);
735
}
736
737
TernaryNodeType newForInOrOfHead(ParseNodeKind kind, Node target,
738
Node iteratedExpr, const TokenPos& pos) {
739
MOZ_ASSERT(kind == ParseNodeKind::ForIn || kind == ParseNodeKind::ForOf);
740
return new_<TernaryNode>(kind, target, nullptr, iteratedExpr, pos);
741
}
742
743
SwitchStatementType newSwitchStatement(
744
uint32_t begin, Node discriminant,
745
LexicalScopeNodeType lexicalForCaseList, bool hasDefault) {
746
return new_<SwitchStatement>(begin, discriminant, lexicalForCaseList,
747
hasDefault);
748
}
749
750
CaseClauseType newCaseOrDefault(uint32_t begin, Node expr, Node body) {
751
return new_<CaseClause>(expr, body, begin);
752
}
753
754
ContinueStatementType newContinueStatement(PropertyName* label,
755
const TokenPos& pos) {
756
return new_<ContinueStatement>(label, pos);
757
}
758
759
BreakStatementType newBreakStatement(PropertyName* label,
760
const TokenPos& pos) {
761
return new_<BreakStatement>(label, pos);
762
}
763
764
UnaryNodeType newReturnStatement(Node expr, const TokenPos& pos) {
765
MOZ_ASSERT_IF(expr && sourceKind() == SourceKind::Text,
766
pos.encloses(expr->pn_pos));
767
return new_<UnaryNode>(ParseNodeKind::ReturnStmt, pos, expr);
768
}
769
770
UnaryNodeType newExpressionBody(Node expr) {
771
return new_<UnaryNode>(ParseNodeKind::ReturnStmt, expr->pn_pos, expr);
772
}
773
774
BinaryNodeType newWithStatement(uint32_t begin, Node expr, Node body) {
775
return new_<BinaryNode>(ParseNodeKind::WithStmt,
776
TokenPos(begin, body->pn_pos.end), expr, body);
777
}
778
779
LabeledStatementType newLabeledStatement(PropertyName* label, Node stmt,
780
uint32_t begin) {
781
return new_<LabeledStatement>(label, stmt, begin);
782
}
783
784
UnaryNodeType newThrowStatement(Node expr, const TokenPos& pos) {
785
MOZ_ASSERT_IF(sourceKind() == SourceKind::Text, pos.encloses(expr->pn_pos));
786
return new_<UnaryNode>(ParseNodeKind::ThrowStmt, pos, expr);
787
}
788
789
TernaryNodeType newTryStatement(uint32_t begin, Node body,
790
LexicalScopeNodeType catchScope,
791
Node finallyBlock) {
792
return new_<TryNode>(begin, body, catchScope, finallyBlock);
793
}
794
795
DebuggerStatementType newDebuggerStatement(const TokenPos& pos) {
796
return new_<DebuggerStatement>(pos);
797
}
798
799
NameNodeType newPropertyName(PropertyName* name, const TokenPos& pos) {
800
return new_<NameNode>(ParseNodeKind::PropertyNameExpr, name, pos);
801
}
802
803
PropertyAccessType newPropertyAccess(Node expr, NameNodeType key) {
804
return new_<PropertyAccess>(expr, key, expr->pn_pos.begin, key->pn_pos.end);
805
}
806
807
PropertyByValueType newPropertyByValue(Node lhs, Node index, uint32_t end) {
808
return new_<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
809
}
810
811
OptionalPropertyAccessType newOptionalPropertyAccess(Node expr,
812
NameNodeType key) {
813
return new_<OptionalPropertyAccess>(expr, key, expr->pn_pos.begin,
814
key->pn_pos.end);
815
}
816
817
OptionalPropertyByValueType newOptionalPropertyByValue(Node lhs, Node index,
818
uint32_t end) {
819
return new_<OptionalPropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
820
}
821
822
bool setupCatchScope(LexicalScopeNodeType lexicalScope, Node catchName,
823
Node catchBody) {
824
BinaryNode* catchClause;
825
if (catchName) {
826
catchClause =
827
new_<BinaryNode>(ParseNodeKind::Catch, catchName, catchBody);
828
} else {
829
catchClause = new_<BinaryNode>(ParseNodeKind::Catch, catchBody->pn_pos,
830
catchName, catchBody);
831
}
832
if (!catchClause) {
833
return false;
834
}
835
lexicalScope->setScopeBody(catchClause);
836
return true;
837
}
838
839
inline MOZ_MUST_USE bool setLastFunctionFormalParameterDefault(
840
FunctionNodeType funNode, Node defaultValue);
841
842
void checkAndSetIsDirectRHSAnonFunction(Node pn) {
843
if (IsAnonymousFunctionDefinition(pn)) {
844
pn->setDirectRHSAnonFunction(true);
845
}
846
}
847
848
FunctionNodeType newFunction(FunctionSyntaxKind syntaxKind,
849
const TokenPos& pos) {
850
return new_<FunctionNode>(syntaxKind, pos);
851
}
852
853
BinaryNodeType newObjectMethodOrPropertyDefinition(Node key, Node value,
854
AccessorType atype) {
855
MOZ_ASSERT(isUsableAsObjectPropertyName(key));
856
857
return new_<PropertyDefinition>(key, value, atype);
858
}
859
860
BinaryNodeType newShorthandPropertyDefinition(Node key, Node value) {
861
MOZ_ASSERT(isUsableAsObjectPropertyName(key));
862
863
return newBinary(ParseNodeKind::Shorthand, key, value);
864
}
865
866
ListNodeType newParamsBody(const TokenPos& pos) {
867
return new_<ListNode>(ParseNodeKind::ParamsBody, pos);
868
}
869
870
void setFunctionFormalParametersAndBody(FunctionNodeType funNode,
871
ListNodeType paramsBody) {
872
MOZ_ASSERT_IF(paramsBody, paramsBody->isKind(ParseNodeKind::ParamsBody));
873
funNode->setBody(paramsBody);
874
}
875
void setFunctionBox(FunctionNodeType funNode, FunctionBox* funbox) {
876
funNode->setFunbox(funbox);
877
funbox->functionNode = funNode;
878
}
879
void addFunctionFormalParameter(FunctionNodeType funNode, Node argpn) {
880
addList(/* list = */ funNode->body(), /* kid = */ argpn);
881
}
882
void setFunctionBody(FunctionNodeType funNode, LexicalScopeNodeType body) {
883
MOZ_ASSERT(funNode->body()->isKind(ParseNodeKind::ParamsBody));
884
addList(/* list = */ funNode->body(), /* kid = */ body);
885
}
886
887
ModuleNodeType newModule(const TokenPos& pos) {
888
return new_<ModuleNode>(pos);
889
}
890
891
LexicalScopeNodeType newLexicalScope(LexicalScope::Data* bindings, Node body,
892
ScopeKind kind = ScopeKind::Lexical) {
893
return new_<LexicalScopeNode>(bindings, body, kind);
894
}
895
896
CallNodeType newNewExpression(uint32_t begin, Node ctor, Node args,
897
bool isSpread) {
898
return new_<CallNode>(ParseNodeKind::NewExpr,
899
isSpread ? JSOp::SpreadNew : JSOp::New,
900
TokenPos(begin, args->pn_pos.end), ctor, args);
901
}
902
903
AssignmentNodeType newAssignment(ParseNodeKind kind, Node lhs, Node rhs) {
904
if ((kind == ParseNodeKind::AssignExpr ||
905
kind == ParseNodeKind::InitExpr) &&
906
lhs->isKind(ParseNodeKind::Name) && !lhs->isInParens()) {
907
checkAndSetIsDirectRHSAnonFunction(rhs);
908
}
909
910
return new_<AssignmentNode>(kind, lhs, rhs);
911
}
912
913
bool isUnparenthesizedAssignment(Node node) {
914
if ((node->isKind(ParseNodeKind::AssignExpr)) && !node->isInParens()) {
915
return true;
916
}
917
918
return false;
919
}
920
921
bool isUnparenthesizedUnaryExpression(Node node) {
922
if (!node->isInParens()) {
923
ParseNodeKind kind = node->getKind();
924
return kind == ParseNodeKind::VoidExpr ||
925
kind == ParseNodeKind::NotExpr ||
926
kind == ParseNodeKind::BitNotExpr ||
927
kind == ParseNodeKind::PosExpr || kind == ParseNodeKind::NegExpr ||
928
IsTypeofKind(kind) || IsDeleteKind(kind);
929
}
930
return false;
931
}
932
933
bool isReturnStatement(Node node) {
934
return node->isKind(ParseNodeKind::ReturnStmt);
935
}
936
937
bool isStatementPermittedAfterReturnStatement(Node node) {
938
ParseNodeKind kind = node->getKind();
939
return kind == ParseNodeKind::Function || kind == ParseNodeKind::VarStmt ||
940
kind == ParseNodeKind::BreakStmt ||
941
kind == ParseNodeKind::ThrowStmt || kind == ParseNodeKind::EmptyStmt;
942
}
943
944
bool isSuperBase(Node node) { return node->isKind(ParseNodeKind::SuperBase); }
945
946
bool isUsableAsObjectPropertyName(Node node) {
947
return node->isKind(ParseNodeKind::NumberExpr) ||
948
node->isKind(ParseNodeKind::BigIntExpr) ||
949
node->isKind(ParseNodeKind::ObjectPropertyName) ||
950
node->isKind(ParseNodeKind::StringExpr) ||
951
node->isKind(ParseNodeKind::ComputedName);
952
}
953
954
AssignmentNodeType finishInitializerAssignment(NameNodeType nameNode,
955
Node init) {
956
MOZ_ASSERT(nameNode->isKind(ParseNodeKind::Name));
957
MOZ_ASSERT(!nameNode->isInParens());
958
959
checkAndSetIsDirectRHSAnonFunction(init);
960
961
return newAssignment(ParseNodeKind::AssignExpr, nameNode, init);
962
}
963
964
void setBeginPosition(Node pn, Node oth) {
965
setBeginPosition(pn, oth->pn_pos.begin);
966
}
967
void setBeginPosition(Node pn, uint32_t begin) {
968
pn->pn_pos.begin = begin;
969
MOZ_ASSERT_IF(sourceKind() == SourceKind::Text,
970
pn->pn_pos.begin <= pn->pn_pos.end);
971
}
972
973
void setEndPosition(Node pn, Node oth) {
974
setEndPosition(pn, oth->pn_pos.end);
975
}
976
void setEndPosition(Node pn, uint32_t end) {
977
pn->pn_pos.end = end;
978
MOZ_ASSERT_IF(sourceKind() == SourceKind::Text,
979
pn->pn_pos.begin <= pn->pn_pos.end);
980
}
981
982
uint32_t getFunctionNameOffset(Node func, TokenStreamAnyChars& ts) {
983
return func->pn_pos.begin;
984
}
985
986
bool isDeclarationKind(ParseNodeKind kind) {
987
return kind == ParseNodeKind::VarStmt || kind == ParseNodeKind::LetDecl ||
988
kind == ParseNodeKind::ConstDecl;
989
}
990
991
ListNodeType newList(ParseNodeKind kind, const TokenPos& pos) {
992
MOZ_ASSERT(!isDeclarationKind(kind));
993
return new_<ListNode>(kind, pos);
994
}
995
996
public:
997
ListNodeType newList(ParseNodeKind kind, Node kid) {
998
MOZ_ASSERT(!isDeclarationKind(kind));
999
return new_<ListNode>(kind, kid);
1000
}
1001
1002
ListNodeType newDeclarationList(ParseNodeKind kind, const TokenPos& pos) {
1003
MOZ_ASSERT(isDeclarationKind(kind));
1004
return new_<ListNode>(kind, pos);
1005
}
1006
1007
bool isDeclarationList(Node node) {
1008
return isDeclarationKind(node->getKind());
1009
}
1010
1011
Node singleBindingFromDeclaration(ListNodeType decl) {
1012
MOZ_ASSERT(isDeclarationList(decl));
1013
MOZ_ASSERT(decl->count() == 1);
1014
return decl->head();
1015
}
1016
1017
ListNodeType newCommaExpressionList(Node kid) {
1018
return new_<ListNode>(ParseNodeKind::CommaExpr, kid);
1019
}
1020
1021
void addList(ListNodeType list, Node kid) {
1022
if (sourceKind_ == SourceKind::Text) {
1023
list->append(kid);
1024
} else {
1025
list->appendWithoutOrderAssumption(kid);
1026
}
1027
}
1028
1029
void setListHasNonConstInitializer(ListNodeType literal) {
1030
literal->setHasNonConstInitializer();
1031
}
1032
template <typename NodeType>
1033
MOZ_MUST_USE NodeType parenthesize(NodeType node) {
1034
node->setInParens(true);
1035
return node;
1036
}
1037
template <typename NodeType>
1038
MOZ_MUST_USE NodeType setLikelyIIFE(NodeType node) {
1039
return parenthesize(node);
1040
}
1041
void setInDirectivePrologue(UnaryNodeType exprStmt) {
1042
exprStmt->setIsDirectivePrologueMember();
1043
}
1044
1045
bool isName(Node node) { return node->isKind(ParseNodeKind::Name); }
1046
1047
bool isArgumentsName(Node node, JSContext* cx) {
1048
return node->isKind(ParseNodeKind::Name) &&
1049
node->as<NameNode>().atom() == cx->names().arguments;
1050
}
1051
1052
bool isEvalName(Node node, JSContext* cx) {
1053
return node->isKind(ParseNodeKind::Name) &&
1054
node->as<NameNode>().atom() == cx->names().eval;
1055
}
1056
1057
bool isAsyncKeyword(Node node, JSContext* cx) {
1058
return node->isKind(ParseNodeKind::Name) &&
1059
node->pn_pos.begin + strlen("async") == node->pn_pos.end &&
1060
node->as<NameNode>().atom() == cx->names().async;
1061
}
1062
1063
PropertyName* maybeDottedProperty(Node pn) {
1064
return pn->is<PropertyAccess>() ? &pn->as<PropertyAccess>().name()
1065
: nullptr;
1066
}
1067
JSAtom* isStringExprStatement(Node pn, TokenPos* pos) {
1068
if (pn->is<UnaryNode>()) {
1069
UnaryNode* unary = &pn->as<UnaryNode>();
1070
if (JSAtom* atom = unary->isStringExprStatement()) {
1071
*pos = unary->kid()->pn_pos;
1072
return atom;
1073
}
1074
}
1075
return nullptr;
1076
}
1077
1078
bool canSkipLazyInnerFunctions() { return !!lazyOuterFunction_; }
1079
bool canSkipLazyClosedOverBindings() { return !!lazyOuterFunction_; }
1080
bool canSkipRegexpSyntaxParse() { return !!lazyOuterFunction_; }
1081
JSFunction* nextLazyInnerFunction() {
1082
return &lazyOuterFunction_->gcthings()[lazyInnerFunctionIndex++]
1083
.as<JSObject>()
1084
.as<JSFunction>();
1085
}
1086
JSAtom* nextLazyClosedOverBinding() {
1087
auto gcthings = lazyOuterFunction_->gcthings();
1088
1089
// Trailing nullptrs were elided in PerHandlerParser::finishFunction().
1090
if (lazyClosedOverBindingIndex >= gcthings.Length()) {
1091
return nullptr;
1092
}
1093
1094
// These entries are either JSAtom* or nullptr, so use the 'asCell()'
1095
// accessor which is faster.
1096
gc::Cell* cell = gcthings[lazyClosedOverBindingIndex++].asCell();
1097
MOZ_ASSERT_IF(cell, cell->is<JSAtom>());
1098
return static_cast<JSAtom*>(cell);
1099
}
1100
};
1101
1102
inline bool FullParseHandler::setLastFunctionFormalParameterDefault(
1103
FunctionNodeType funNode, Node defaultValue) {
1104
ListNode* body = funNode->body();
1105
ParseNode* arg = body->last();
1106
ParseNode* pn = newAssignment(ParseNodeKind::AssignExpr, arg, defaultValue);
1107
if (!pn) {
1108
return false;
1109
}
1110
1111
body->replaceLast(pn);
1112
return true;
1113
}
1114
1115
} // namespace frontend
1116
} // namespace js
1117
1118
#endif /* frontend_FullParseHandler_h */