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/. */
7 #include "frontend/ParseNode.h"
9 #include "mozilla/FloatingPoint.h"
10 #include "mozilla/Try.h" // MOZ_TRY*
14 #include "frontend/CompilationStencil.h" // ExtensibleCompilationStencil
15 #include "frontend/FullParseHandler.h"
16 #include "frontend/ParseContext.h"
17 #include "frontend/Parser.h" // ParserBase
18 #include "frontend/ParserAtom.h" // ParserAtomsTable, TaggedParserAtomIndex
19 #include "frontend/SharedContext.h"
20 #include "js/Printer.h"
21 #include "vm/Scope.h" // GetScopeDataTrailingNames
24 using namespace js::frontend
;
27 void ListNode::checkConsistency() const {
28 ParseNode
* const* tailNode
;
29 uint32_t actualCount
= 0;
30 if (const ParseNode
* last
= head()) {
31 const ParseNode
* pn
= last
;
38 tailNode
= &last
->pn_next
;
42 MOZ_ASSERT(tail() == tailNode
);
43 MOZ_ASSERT(count() == actualCount
);
48 * Allocate a ParseNode from parser's node freelist or, failing that, from
49 * cx's temporary arena.
51 void* ParseNodeAllocator::allocNode(size_t size
) {
52 LifoAlloc::AutoFallibleScope
fallibleAllocator(&alloc
);
53 void* p
= alloc
.alloc(size
);
55 ReportOutOfMemory(fc
);
60 ParseNodeResult
ParseNode::appendOrCreateList(ParseNodeKind kind
,
61 ParseNode
* left
, ParseNode
* right
,
62 FullParseHandler
* handler
,
64 // The asm.js specification is written in ECMAScript grammar terms that
65 // specify *only* a binary tree. It's a royal pain to implement the asm.js
66 // spec to act upon n-ary lists as created below. So for asm.js, form a
67 // binary tree of lists exactly as ECMAScript would by skipping the
68 // following optimization.
69 if (!pc
->useAsmOrInsideUseAsm()) {
70 // Left-associative trees of a given operator (e.g. |a + b + c|) are
71 // binary trees in the spec: (+ (+ a b) c) in Lisp terms. Recursively
72 // processing such a tree, exactly implemented that way, would blow the
73 // the stack. We use a list node that uses O(1) stack to represent
74 // such operations: (+ a b c).
76 // (**) is right-associative; per spec |a ** b ** c| parses as
77 // (** a (** b c)). But we treat this the same way, creating a list
78 // node: (** a b c). All consumers must understand that this must be
79 // processed with a right fold, whereas the list (+ a b c) must be
80 // processed with a left fold because (+) is left-associative.
82 if (left
->isKind(kind
) &&
83 (kind
== ParseNodeKind::PowExpr
? !left
->isInParens()
84 : left
->isBinaryOperation())) {
85 ListNode
* list
= &left
->as
<ListNode
>();
88 list
->pn_pos
.end
= right
->pn_pos
.end
;
95 MOZ_TRY_VAR(list
, handler
->newResult
<ListNode
>(kind
, left
));
101 const ParseNode::TypeCode
ParseNode::typeCodeTable
[] = {
102 #define TYPE_CODE(_name, type) type::classTypeCode(),
103 FOR_EACH_PARSE_NODE_KIND(TYPE_CODE
)
109 const size_t ParseNode::sizeTable
[] = {
110 # define NODE_SIZE(_name, type) sizeof(type),
111 FOR_EACH_PARSE_NODE_KIND(NODE_SIZE
)
115 static const char* const parseNodeNames
[] = {
116 # define STRINGIFY(name, _type) #name,
117 FOR_EACH_PARSE_NODE_KIND(STRINGIFY
)
121 static void DumpParseTree(const ParserAtomsTable
* parserAtoms
, ParseNode
* pn
,
122 GenericPrinter
& out
, int indent
) {
126 pn
->dump(parserAtoms
, out
, indent
);
130 void frontend::DumpParseTree(ParserBase
* parser
, ParseNode
* pn
,
131 GenericPrinter
& out
, int indent
) {
132 ParserAtomsTable
* parserAtoms
= parser
? &parser
->parserAtoms() : nullptr;
133 ::DumpParseTree(parserAtoms
, pn
, out
, indent
);
136 static void IndentNewLine(GenericPrinter
& out
, int indent
) {
138 for (int i
= 0; i
< indent
; ++i
) {
143 void ParseNode::dump() { dump(nullptr); }
145 void ParseNode::dump(const ParserAtomsTable
* parserAtoms
) {
146 js::Fprinter
out(stderr
);
147 dump(parserAtoms
, out
);
150 void ParseNode::dump(const ParserAtomsTable
* parserAtoms
, GenericPrinter
& out
) {
151 dump(parserAtoms
, out
, 0);
155 void ParseNode::dump(const ParserAtomsTable
* parserAtoms
, GenericPrinter
& out
,
158 # define DUMP(K, T) \
159 case ParseNodeKind::K: \
160 as<T>().dumpImpl(parserAtoms, out, indent); \
162 FOR_EACH_PARSE_NODE_KIND(DUMP
)
165 out
.printf("#<BAD NODE %p, kind=%u>", (void*)this, unsigned(getKind()));
169 void NullaryNode::dumpImpl(const ParserAtomsTable
* parserAtoms
,
170 GenericPrinter
& out
, int indent
) {
172 case ParseNodeKind::TrueExpr
:
175 case ParseNodeKind::FalseExpr
:
178 case ParseNodeKind::NullExpr
:
181 case ParseNodeKind::RawUndefinedExpr
:
182 out
.put("#undefined");
186 out
.printf("(%s)", parseNodeNames
[getKindAsIndex()]);
190 void NumericLiteral::dumpImpl(const ParserAtomsTable
* parserAtoms
,
191 GenericPrinter
& out
, int indent
) {
193 const char* cstr
= NumberToCString(&cbuf
, value());
195 if (!std::isfinite(value())) {
198 out
.printf("%s", cstr
);
201 void BigIntLiteral::dumpImpl(const ParserAtomsTable
* parserAtoms
,
202 GenericPrinter
& out
, int indent
) {
203 out
.printf("(%s)", parseNodeNames
[getKindAsIndex()]);
206 void RegExpLiteral::dumpImpl(const ParserAtomsTable
* parserAtoms
,
207 GenericPrinter
& out
, int indent
) {
208 out
.printf("(%s)", parseNodeNames
[getKindAsIndex()]);
211 static void DumpCharsNoNewline(const ParserAtomsTable
* parserAtoms
,
212 TaggedParserAtomIndex index
,
213 GenericPrinter
& out
) {
216 parserAtoms
->dumpCharsNoQuote(out
, index
);
218 DumpTaggedParserAtomIndexNoQuote(out
, index
, nullptr);
223 void LoopControlStatement::dumpImpl(const ParserAtomsTable
* parserAtoms
,
224 GenericPrinter
& out
, int indent
) {
225 const char* name
= parseNodeNames
[getKindAsIndex()];
226 out
.printf("(%s", name
);
229 DumpCharsNoNewline(parserAtoms
, label_
, out
);
234 void UnaryNode::dumpImpl(const ParserAtomsTable
* parserAtoms
,
235 GenericPrinter
& out
, int indent
) {
236 const char* name
= parseNodeNames
[getKindAsIndex()];
237 out
.printf("(%s ", name
);
238 indent
+= strlen(name
) + 2;
239 ::DumpParseTree(parserAtoms
, kid(), out
, indent
);
243 void BinaryNode::dumpImpl(const ParserAtomsTable
* parserAtoms
,
244 GenericPrinter
& out
, int indent
) {
245 if (isKind(ParseNodeKind::DotExpr
)) {
248 ::DumpParseTree(parserAtoms
, right(), out
, indent
+ 2);
251 if (as
<PropertyAccess
>().isSuper()) {
254 ::DumpParseTree(parserAtoms
, left(), out
, indent
+ 2);
261 const char* name
= parseNodeNames
[getKindAsIndex()];
262 out
.printf("(%s ", name
);
263 indent
+= strlen(name
) + 2;
264 ::DumpParseTree(parserAtoms
, left(), out
, indent
);
265 IndentNewLine(out
, indent
);
266 ::DumpParseTree(parserAtoms
, right(), out
, indent
);
270 void TernaryNode::dumpImpl(const ParserAtomsTable
* parserAtoms
,
271 GenericPrinter
& out
, int indent
) {
272 const char* name
= parseNodeNames
[getKindAsIndex()];
273 out
.printf("(%s ", name
);
274 indent
+= strlen(name
) + 2;
275 ::DumpParseTree(parserAtoms
, kid1(), out
, indent
);
276 IndentNewLine(out
, indent
);
277 ::DumpParseTree(parserAtoms
, kid2(), out
, indent
);
278 IndentNewLine(out
, indent
);
279 ::DumpParseTree(parserAtoms
, kid3(), out
, indent
);
283 void FunctionNode::dumpImpl(const ParserAtomsTable
* parserAtoms
,
284 GenericPrinter
& out
, int indent
) {
285 const char* name
= parseNodeNames
[getKindAsIndex()];
286 out
.printf("(%s ", name
);
287 indent
+= strlen(name
) + 2;
288 ::DumpParseTree(parserAtoms
, body(), out
, indent
);
292 void ModuleNode::dumpImpl(const ParserAtomsTable
* parserAtoms
,
293 GenericPrinter
& out
, int indent
) {
294 const char* name
= parseNodeNames
[getKindAsIndex()];
295 out
.printf("(%s ", name
);
296 indent
+= strlen(name
) + 2;
297 ::DumpParseTree(parserAtoms
, body(), out
, indent
);
301 void ListNode::dumpImpl(const ParserAtomsTable
* parserAtoms
,
302 GenericPrinter
& out
, int indent
) {
303 const char* name
= parseNodeNames
[getKindAsIndex()];
304 out
.printf("(%s [", name
);
305 if (ParseNode
* listHead
= head()) {
306 indent
+= strlen(name
) + 3;
307 ::DumpParseTree(parserAtoms
, listHead
, out
, indent
);
308 for (ParseNode
* item
: contentsFrom(listHead
->pn_next
)) {
309 IndentNewLine(out
, indent
);
310 ::DumpParseTree(parserAtoms
, item
, out
, indent
);
316 void NameNode::dumpImpl(const ParserAtomsTable
* parserAtoms
,
317 GenericPrinter
& out
, int indent
) {
319 case ParseNodeKind::StringExpr
:
320 case ParseNodeKind::TemplateStringExpr
:
321 case ParseNodeKind::ObjectPropertyName
:
322 DumpCharsNoNewline(parserAtoms
, atom_
, out
);
325 case ParseNodeKind::Name
:
326 case ParseNodeKind::PrivateName
: // atom() already includes the '#', no
327 // need to specially include it.
328 case ParseNodeKind::PropertyNameExpr
:
330 out
.put("#<null name>");
331 } else if (parserAtoms
) {
332 if (atom_
== TaggedParserAtomIndex::WellKnown::empty()) {
333 out
.put("#<zero-length name>");
335 parserAtoms
->dumpCharsNoQuote(out
, atom_
);
338 DumpTaggedParserAtomIndexNoQuote(out
, atom_
, nullptr);
342 case ParseNodeKind::LabelStmt
: {
343 this->as
<LabeledStatement
>().dumpImpl(parserAtoms
, out
, indent
);
348 const char* name
= parseNodeNames
[getKindAsIndex()];
349 out
.printf("(%s)", name
);
355 void LabeledStatement::dumpImpl(const ParserAtomsTable
* parserAtoms
,
356 GenericPrinter
& out
, int indent
) {
357 const char* name
= parseNodeNames
[getKindAsIndex()];
358 out
.printf("(%s ", name
);
359 DumpCharsNoNewline(parserAtoms
, label(), out
);
360 indent
+= strlen(name
) + 2;
361 IndentNewLine(out
, indent
);
362 ::DumpParseTree(parserAtoms
, statement(), out
, indent
);
366 template <ParseNodeKind Kind
, typename ScopeType
>
367 void BaseScopeNode
<Kind
, ScopeType
>::dumpImpl(
368 const ParserAtomsTable
* parserAtoms
, GenericPrinter
& out
, int indent
) {
369 const char* name
= parseNodeNames
[getKindAsIndex()];
370 out
.printf("(%s [", name
);
371 int nameIndent
= indent
+ strlen(name
) + 3;
372 if (!isEmptyScope()) {
373 typename
ScopeType::ParserData
* bindings
= scopeBindings();
374 auto names
= GetScopeDataTrailingNames(bindings
);
375 for (uint32_t i
= 0; i
< names
.size(); i
++) {
376 auto index
= names
[i
].name();
378 if (index
== TaggedParserAtomIndex::WellKnown::empty()) {
379 out
.put("#<zero-length name>");
381 parserAtoms
->dumpCharsNoQuote(out
, index
);
384 DumpTaggedParserAtomIndexNoQuote(out
, index
, nullptr);
386 if (i
< names
.size() - 1) {
387 IndentNewLine(out
, nameIndent
);
393 IndentNewLine(out
, indent
);
394 ::DumpParseTree(parserAtoms
, scopeBody(), out
, indent
);
398 # ifdef ENABLE_DECORATORS
399 void ClassMethod::dumpImpl(const ParserAtomsTable
* parserAtoms
,
400 GenericPrinter
& out
, int indent
) {
402 decorators_
->dumpImpl(parserAtoms
, out
, indent
);
404 Base::dumpImpl(parserAtoms
, out
, indent
);
407 void ClassField::dumpImpl(const ParserAtomsTable
* parserAtoms
,
408 GenericPrinter
& out
, int indent
) {
410 decorators_
->dumpImpl(parserAtoms
, out
, indent
);
413 Base::dumpImpl(parserAtoms
, out
, indent
);
414 IndentNewLine(out
, indent
+ 2);
415 if (accessorGetterNode_
) {
416 out
.printf("getter: ");
417 accessorGetterNode_
->dumpImpl(parserAtoms
, out
, indent
);
419 IndentNewLine(out
, indent
+ 2);
420 if (accessorSetterNode_
) {
421 out
.printf("setter: ");
422 accessorSetterNode_
->dumpImpl(parserAtoms
, out
, indent
);
426 void ClassNode::dumpImpl(const ParserAtomsTable
* parserAtoms
,
427 GenericPrinter
& out
, int indent
) {
429 decorators_
->dumpImpl(parserAtoms
, out
, indent
);
431 Base::dumpImpl(parserAtoms
, out
, indent
);
437 TaggedParserAtomIndex
NumericLiteral::toAtom(
438 FrontendContext
* fc
, ParserAtomsTable
& parserAtoms
) const {
439 return NumberToParserAtom(fc
, parserAtoms
, value());
442 RegExpObject
* RegExpLiteral::create(
443 JSContext
* cx
, FrontendContext
* fc
, ParserAtomsTable
& parserAtoms
,
444 CompilationAtomCache
& atomCache
,
445 ExtensibleCompilationStencil
& stencil
) const {
446 return stencil
.regExpData
[index_
].createRegExpAndEnsureAtom(
447 cx
, fc
, parserAtoms
, atomCache
);
450 bool js::frontend::IsAnonymousFunctionDefinition(ParseNode
* pn
) {
452 // 12.15.2 (ArrowFunction, AsyncArrowFunction).
453 // 14.1.12 (FunctionExpression).
454 // 14.4.8 (Generatoression).
455 // 14.6.8 (AsyncFunctionExpression)
456 if (pn
->is
<FunctionNode
>() &&
457 !pn
->as
<FunctionNode
>().funbox()->explicitName()) {
461 // 14.5.8 (ClassExpression)
462 if (pn
->is
<ClassNode
>() && !pn
->as
<ClassNode
>().names()) {