ParseNode.cpp (14541B)
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 #include "frontend/ParseNode.h" 8 9 #include "mozilla/Try.h" // MOZ_TRY* 10 11 #include "jsnum.h" 12 13 #include "frontend/CompilationStencil.h" // ExtensibleCompilationStencil 14 #include "frontend/FullParseHandler.h" 15 #include "frontend/ParseContext.h" 16 #include "frontend/Parser.h" // ParserBase 17 #include "frontend/ParserAtom.h" // ParserAtomsTable, TaggedParserAtomIndex 18 #include "frontend/SharedContext.h" 19 #include "js/Printer.h" 20 #include "vm/Scope.h" // GetScopeDataTrailingNames 21 22 using namespace js; 23 using namespace js::frontend; 24 25 #ifdef DEBUG 26 void ListNode::checkConsistency() const { 27 ParseNode* const* tailNode; 28 uint32_t actualCount = 0; 29 if (const ParseNode* last = head()) { 30 const ParseNode* pn = last; 31 while (pn) { 32 last = pn; 33 pn = pn->pn_next; 34 actualCount++; 35 } 36 37 tailNode = &last->pn_next; 38 } else { 39 tailNode = &head_; 40 } 41 MOZ_ASSERT(tail() == tailNode); 42 MOZ_ASSERT(count() == actualCount); 43 } 44 #endif 45 46 /* 47 * Allocate a ParseNode from parser's node freelist or, failing that, from 48 * cx's temporary arena. 49 */ 50 void* ParseNodeAllocator::allocNode(size_t size) { 51 LifoAlloc::AutoFallibleScope fallibleAllocator(&alloc); 52 void* p = alloc.alloc(size); 53 if (!p) { 54 ReportOutOfMemory(fc); 55 } 56 return p; 57 } 58 59 ParseNodeResult ParseNode::appendOrCreateList(ParseNodeKind kind, 60 ParseNode* left, ParseNode* right, 61 FullParseHandler* handler, 62 ParseContext* pc) { 63 // The asm.js specification is written in ECMAScript grammar terms that 64 // specify *only* a binary tree. It's a royal pain to implement the asm.js 65 // spec to act upon n-ary lists as created below. So for asm.js, form a 66 // binary tree of lists exactly as ECMAScript would by skipping the 67 // following optimization. 68 if (!pc->useAsmOrInsideUseAsm()) { 69 // Left-associative trees of a given operator (e.g. |a + b + c|) are 70 // binary trees in the spec: (+ (+ a b) c) in Lisp terms. Recursively 71 // processing such a tree, exactly implemented that way, would blow the 72 // the stack. We use a list node that uses O(1) stack to represent 73 // such operations: (+ a b c). 74 // 75 // (**) is right-associative; per spec |a ** b ** c| parses as 76 // (** a (** b c)). But we treat this the same way, creating a list 77 // node: (** a b c). All consumers must understand that this must be 78 // processed with a right fold, whereas the list (+ a b c) must be 79 // processed with a left fold because (+) is left-associative. 80 // 81 if (left->isKind(kind) && 82 (kind == ParseNodeKind::PowExpr ? !left->isInParens() 83 : left->isBinaryOperation())) { 84 ListNode* list = &left->as<ListNode>(); 85 86 list->append(right); 87 list->pn_pos.end = right->pn_pos.end; 88 89 return list; 90 } 91 } 92 93 ListNode* list = MOZ_TRY(handler->newResult<ListNode>(kind, left)); 94 95 list->append(right); 96 return list; 97 } 98 99 const ParseNode::TypeCode ParseNode::typeCodeTable[] = { 100 #define TYPE_CODE(_name, type) type::classTypeCode(), 101 FOR_EACH_PARSE_NODE_KIND(TYPE_CODE) 102 #undef TYPE_CODE 103 }; 104 105 #ifdef DEBUG 106 107 const size_t ParseNode::sizeTable[] = { 108 # define NODE_SIZE(_name, type) sizeof(type), 109 FOR_EACH_PARSE_NODE_KIND(NODE_SIZE) 110 # undef NODE_SIZE 111 }; 112 113 static const char* const parseNodeNames[] = { 114 # define STRINGIFY(name, _type) #name, 115 FOR_EACH_PARSE_NODE_KIND(STRINGIFY) 116 # undef STRINGIFY 117 }; 118 119 static void DumpParseTree(const ParserAtomsTable* parserAtoms, ParseNode* pn, 120 GenericPrinter& out, int indent) { 121 if (pn == nullptr) { 122 out.put("#NULL"); 123 } else { 124 pn->dump(parserAtoms, out, indent); 125 } 126 } 127 128 void frontend::DumpParseTree(ParserBase* parser, ParseNode* pn, 129 GenericPrinter& out, int indent) { 130 ParserAtomsTable* parserAtoms = parser ? &parser->parserAtoms() : nullptr; 131 ::DumpParseTree(parserAtoms, pn, out, indent); 132 } 133 134 static void IndentNewLine(GenericPrinter& out, int indent) { 135 out.putChar('\n'); 136 for (int i = 0; i < indent; ++i) { 137 out.putChar(' '); 138 } 139 } 140 141 void ParseNode::dump() { dump(nullptr); } 142 143 void ParseNode::dump(const ParserAtomsTable* parserAtoms) { 144 js::Fprinter out(stderr); 145 dump(parserAtoms, out); 146 } 147 148 void ParseNode::dump(const ParserAtomsTable* parserAtoms, GenericPrinter& out) { 149 dump(parserAtoms, out, 0); 150 out.putChar('\n'); 151 } 152 153 void ParseNode::dump(const ParserAtomsTable* parserAtoms, GenericPrinter& out, 154 int indent) { 155 switch (getKind()) { 156 # define DUMP(K, T) \ 157 case ParseNodeKind::K: \ 158 as<T>().dumpImpl(parserAtoms, out, indent); \ 159 break; 160 FOR_EACH_PARSE_NODE_KIND(DUMP) 161 # undef DUMP 162 default: 163 out.printf("#<BAD NODE %p, kind=%u>", (void*)this, unsigned(getKind())); 164 } 165 } 166 167 void NullaryNode::dumpImpl(const ParserAtomsTable* parserAtoms, 168 GenericPrinter& out, int indent) { 169 switch (getKind()) { 170 case ParseNodeKind::TrueExpr: 171 out.put("#true"); 172 break; 173 case ParseNodeKind::FalseExpr: 174 out.put("#false"); 175 break; 176 case ParseNodeKind::NullExpr: 177 out.put("#null"); 178 break; 179 case ParseNodeKind::RawUndefinedExpr: 180 out.put("#undefined"); 181 break; 182 183 default: 184 out.printf("(%s)", parseNodeNames[getKindAsIndex()]); 185 } 186 } 187 188 void NumericLiteral::dumpImpl(const ParserAtomsTable* parserAtoms, 189 GenericPrinter& out, int indent) { 190 ToCStringBuf cbuf; 191 const char* cstr = NumberToCString(&cbuf, value()); 192 MOZ_ASSERT(cstr); 193 if (!std::isfinite(value())) { 194 out.put("#"); 195 } 196 out.printf("%s", cstr); 197 } 198 199 void BigIntLiteral::dumpImpl(const ParserAtomsTable* parserAtoms, 200 GenericPrinter& out, int indent) { 201 out.printf("(%s)", parseNodeNames[getKindAsIndex()]); 202 } 203 204 void RegExpLiteral::dumpImpl(const ParserAtomsTable* parserAtoms, 205 GenericPrinter& out, int indent) { 206 out.printf("(%s)", parseNodeNames[getKindAsIndex()]); 207 } 208 209 static void DumpCharsNoNewline(const ParserAtomsTable* parserAtoms, 210 TaggedParserAtomIndex index, 211 GenericPrinter& out) { 212 out.put("\""); 213 if (parserAtoms) { 214 parserAtoms->dumpCharsNoQuote(out, index); 215 } else { 216 DumpTaggedParserAtomIndexNoQuote(out, index, nullptr); 217 } 218 out.put("\""); 219 } 220 221 void LoopControlStatement::dumpImpl(const ParserAtomsTable* parserAtoms, 222 GenericPrinter& out, int indent) { 223 const char* name = parseNodeNames[getKindAsIndex()]; 224 out.printf("(%s", name); 225 if (label_) { 226 out.printf(" "); 227 DumpCharsNoNewline(parserAtoms, label_, out); 228 } 229 out.printf(")"); 230 } 231 232 void UnaryNode::dumpImpl(const ParserAtomsTable* parserAtoms, 233 GenericPrinter& out, int indent) { 234 const char* name = parseNodeNames[getKindAsIndex()]; 235 out.printf("(%s ", name); 236 indent += strlen(name) + 2; 237 ::DumpParseTree(parserAtoms, kid(), out, indent); 238 out.printf(")"); 239 } 240 241 void BinaryNode::dumpImpl(const ParserAtomsTable* parserAtoms, 242 GenericPrinter& out, int indent) { 243 if (isKind(ParseNodeKind::DotExpr)) { 244 out.put("(."); 245 246 ::DumpParseTree(parserAtoms, right(), out, indent + 2); 247 248 out.putChar(' '); 249 if (as<PropertyAccess>().isSuper()) { 250 out.put("super"); 251 } else { 252 ::DumpParseTree(parserAtoms, left(), out, indent + 2); 253 } 254 255 out.printf(")"); 256 return; 257 } 258 259 const char* name = parseNodeNames[getKindAsIndex()]; 260 out.printf("(%s ", name); 261 indent += strlen(name) + 2; 262 ::DumpParseTree(parserAtoms, left(), out, indent); 263 IndentNewLine(out, indent); 264 ::DumpParseTree(parserAtoms, right(), out, indent); 265 out.printf(")"); 266 } 267 268 void TernaryNode::dumpImpl(const ParserAtomsTable* parserAtoms, 269 GenericPrinter& out, int indent) { 270 const char* name = parseNodeNames[getKindAsIndex()]; 271 out.printf("(%s ", name); 272 indent += strlen(name) + 2; 273 ::DumpParseTree(parserAtoms, kid1(), out, indent); 274 IndentNewLine(out, indent); 275 ::DumpParseTree(parserAtoms, kid2(), out, indent); 276 IndentNewLine(out, indent); 277 ::DumpParseTree(parserAtoms, kid3(), out, indent); 278 out.printf(")"); 279 } 280 281 void FunctionNode::dumpImpl(const ParserAtomsTable* parserAtoms, 282 GenericPrinter& out, int indent) { 283 const char* name = parseNodeNames[getKindAsIndex()]; 284 out.printf("(%s ", name); 285 indent += strlen(name) + 2; 286 ::DumpParseTree(parserAtoms, body(), out, indent); 287 out.printf(")"); 288 } 289 290 void ModuleNode::dumpImpl(const ParserAtomsTable* parserAtoms, 291 GenericPrinter& out, int indent) { 292 const char* name = parseNodeNames[getKindAsIndex()]; 293 out.printf("(%s ", name); 294 indent += strlen(name) + 2; 295 ::DumpParseTree(parserAtoms, body(), out, indent); 296 out.printf(")"); 297 } 298 299 void ListNode::dumpImpl(const ParserAtomsTable* parserAtoms, 300 GenericPrinter& out, int indent) { 301 const char* name = parseNodeNames[getKindAsIndex()]; 302 out.printf("(%s [", name); 303 if (ParseNode* listHead = head()) { 304 indent += strlen(name) + 3; 305 ::DumpParseTree(parserAtoms, listHead, out, indent); 306 for (ParseNode* item : contentsFrom(listHead->pn_next)) { 307 IndentNewLine(out, indent); 308 ::DumpParseTree(parserAtoms, item, out, indent); 309 } 310 } 311 out.printf("])"); 312 } 313 314 void NameNode::dumpImpl(const ParserAtomsTable* parserAtoms, 315 GenericPrinter& out, int indent) { 316 switch (getKind()) { 317 case ParseNodeKind::StringExpr: 318 case ParseNodeKind::TemplateStringExpr: 319 case ParseNodeKind::ObjectPropertyName: 320 DumpCharsNoNewline(parserAtoms, atom_, out); 321 return; 322 323 case ParseNodeKind::Name: 324 case ParseNodeKind::PrivateName: // atom() already includes the '#', no 325 // need to specially include it. 326 case ParseNodeKind::PropertyNameExpr: 327 if (!atom_) { 328 out.put("#<null name>"); 329 } else if (parserAtoms) { 330 if (atom_ == TaggedParserAtomIndex::WellKnown::empty()) { 331 out.put("#<zero-length name>"); 332 } else { 333 parserAtoms->dumpCharsNoQuote(out, atom_); 334 } 335 } else { 336 DumpTaggedParserAtomIndexNoQuote(out, atom_, nullptr); 337 } 338 return; 339 340 case ParseNodeKind::LabelStmt: { 341 this->as<LabeledStatement>().dumpImpl(parserAtoms, out, indent); 342 return; 343 } 344 345 default: { 346 const char* name = parseNodeNames[getKindAsIndex()]; 347 out.printf("(%s)", name); 348 return; 349 } 350 } 351 } 352 353 void LabeledStatement::dumpImpl(const ParserAtomsTable* parserAtoms, 354 GenericPrinter& out, int indent) { 355 const char* name = parseNodeNames[getKindAsIndex()]; 356 out.printf("(%s ", name); 357 DumpCharsNoNewline(parserAtoms, label(), out); 358 indent += strlen(name) + 2; 359 IndentNewLine(out, indent); 360 ::DumpParseTree(parserAtoms, statement(), out, indent); 361 out.printf(")"); 362 } 363 364 template <ParseNodeKind Kind, typename ScopeType> 365 void BaseScopeNode<Kind, ScopeType>::dumpImpl( 366 const ParserAtomsTable* parserAtoms, GenericPrinter& out, int indent) { 367 const char* name = parseNodeNames[getKindAsIndex()]; 368 out.printf("(%s [", name); 369 int nameIndent = indent + strlen(name) + 3; 370 if (!isEmptyScope()) { 371 typename ScopeType::ParserData* bindings = scopeBindings(); 372 auto names = GetScopeDataTrailingNames(bindings); 373 for (uint32_t i = 0; i < names.size(); i++) { 374 auto index = names[i].name(); 375 if (parserAtoms) { 376 if (index == TaggedParserAtomIndex::WellKnown::empty()) { 377 out.put("#<zero-length name>"); 378 } else { 379 parserAtoms->dumpCharsNoQuote(out, index); 380 } 381 } else { 382 DumpTaggedParserAtomIndexNoQuote(out, index, nullptr); 383 } 384 if (i < names.size() - 1) { 385 IndentNewLine(out, nameIndent); 386 } 387 } 388 } 389 out.putChar(']'); 390 indent += 2; 391 IndentNewLine(out, indent); 392 ::DumpParseTree(parserAtoms, scopeBody(), out, indent); 393 out.printf(")"); 394 } 395 396 # ifdef ENABLE_DECORATORS 397 void ClassMethod::dumpImpl(const ParserAtomsTable* parserAtoms, 398 GenericPrinter& out, int indent) { 399 if (decorators_) { 400 decorators_->dumpImpl(parserAtoms, out, indent); 401 } 402 Base::dumpImpl(parserAtoms, out, indent); 403 } 404 405 void ClassField::dumpImpl(const ParserAtomsTable* parserAtoms, 406 GenericPrinter& out, int indent) { 407 if (decorators_) { 408 decorators_->dumpImpl(parserAtoms, out, indent); 409 out.putChar(' '); 410 } 411 Base::dumpImpl(parserAtoms, out, indent); 412 IndentNewLine(out, indent + 2); 413 if (accessorGetterNode_) { 414 out.printf("getter: "); 415 accessorGetterNode_->dumpImpl(parserAtoms, out, indent); 416 } 417 IndentNewLine(out, indent + 2); 418 if (accessorSetterNode_) { 419 out.printf("setter: "); 420 accessorSetterNode_->dumpImpl(parserAtoms, out, indent); 421 } 422 } 423 424 void ClassNode::dumpImpl(const ParserAtomsTable* parserAtoms, 425 GenericPrinter& out, int indent) { 426 if (decorators_) { 427 decorators_->dumpImpl(parserAtoms, out, indent); 428 } 429 Base::dumpImpl(parserAtoms, out, indent); 430 } 431 # endif 432 433 #endif 434 435 TaggedParserAtomIndex NumericLiteral::toAtom( 436 FrontendContext* fc, ParserAtomsTable& parserAtoms) const { 437 return NumberToParserAtom(fc, parserAtoms, value()); 438 } 439 440 RegExpObject* RegExpLiteral::create( 441 JSContext* cx, FrontendContext* fc, ParserAtomsTable& parserAtoms, 442 CompilationAtomCache& atomCache, 443 ExtensibleCompilationStencil& stencil) const { 444 return stencil.regExpData[index_].createRegExpAndEnsureAtom( 445 cx, fc, parserAtoms, atomCache); 446 } 447 448 bool js::frontend::IsAnonymousFunctionDefinition(ParseNode* pn) { 449 // ES 2017 draft 450 // 12.15.2 (ArrowFunction, AsyncArrowFunction). 451 // 14.1.12 (FunctionExpression). 452 // 14.4.8 (Generatoression). 453 // 14.6.8 (AsyncFunctionExpression) 454 if (pn->is<FunctionNode>() && 455 !pn->as<FunctionNode>().funbox()->explicitName()) { 456 return true; 457 } 458 459 // 14.5.8 (ClassExpression) 460 if (pn->is<ClassNode>() && !pn->as<ClassNode>().names()) { 461 return true; 462 } 463 464 return false; 465 }