1// Copyright 2012 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/ast/prettyprinter.h" 6 7#include <stdarg.h> 8 9#include "src/ast/ast-value-factory.h" 10#include "src/ast/scopes.h" 11#include "src/base/platform/platform.h" 12#include "src/globals.h" 13 14namespace v8 { 15namespace internal { 16 17CallPrinter::CallPrinter(Isolate* isolate, bool is_builtin) 18 : builder_(isolate) { 19 isolate_ = isolate; 20 position_ = 0; 21 num_prints_ = 0; 22 found_ = false; 23 done_ = false; 24 is_builtin_ = is_builtin; 25 InitializeAstVisitor(isolate); 26} 27 28Handle<String> CallPrinter::Print(FunctionLiteral* program, int position) { 29 num_prints_ = 0; 30 position_ = position; 31 Find(program); 32 return builder_.Finish().ToHandleChecked(); 33} 34 35 36void CallPrinter::Find(AstNode* node, bool print) { 37 if (done_) return; 38 if (found_) { 39 if (print) { 40 int prev_num_prints = num_prints_; 41 Visit(node); 42 if (prev_num_prints != num_prints_) return; 43 } 44 Print("(intermediate value)"); 45 } else { 46 Visit(node); 47 } 48} 49 50void CallPrinter::Print(const char* str) { 51 if (!found_ || done_) return; 52 num_prints_++; 53 builder_.AppendCString(str); 54} 55 56void CallPrinter::Print(Handle<String> str) { 57 if (!found_ || done_) return; 58 num_prints_++; 59 builder_.AppendString(str); 60} 61 62void CallPrinter::VisitBlock(Block* node) { 63 FindStatements(node->statements()); 64} 65 66 67void CallPrinter::VisitVariableDeclaration(VariableDeclaration* node) {} 68 69 70void CallPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) {} 71 72 73void CallPrinter::VisitExpressionStatement(ExpressionStatement* node) { 74 Find(node->expression()); 75} 76 77 78void CallPrinter::VisitEmptyStatement(EmptyStatement* node) {} 79 80 81void CallPrinter::VisitSloppyBlockFunctionStatement( 82 SloppyBlockFunctionStatement* node) { 83 Find(node->statement()); 84} 85 86 87void CallPrinter::VisitIfStatement(IfStatement* node) { 88 Find(node->condition()); 89 Find(node->then_statement()); 90 if (node->HasElseStatement()) { 91 Find(node->else_statement()); 92 } 93} 94 95 96void CallPrinter::VisitContinueStatement(ContinueStatement* node) {} 97 98 99void CallPrinter::VisitBreakStatement(BreakStatement* node) {} 100 101 102void CallPrinter::VisitReturnStatement(ReturnStatement* node) { 103 Find(node->expression()); 104} 105 106 107void CallPrinter::VisitWithStatement(WithStatement* node) { 108 Find(node->expression()); 109 Find(node->statement()); 110} 111 112 113void CallPrinter::VisitSwitchStatement(SwitchStatement* node) { 114 Find(node->tag()); 115 ZoneList<CaseClause*>* cases = node->cases(); 116 for (int i = 0; i < cases->length(); i++) Find(cases->at(i)); 117} 118 119 120void CallPrinter::VisitCaseClause(CaseClause* clause) { 121 if (!clause->is_default()) { 122 Find(clause->label()); 123 } 124 FindStatements(clause->statements()); 125} 126 127 128void CallPrinter::VisitDoWhileStatement(DoWhileStatement* node) { 129 Find(node->body()); 130 Find(node->cond()); 131} 132 133 134void CallPrinter::VisitWhileStatement(WhileStatement* node) { 135 Find(node->cond()); 136 Find(node->body()); 137} 138 139 140void CallPrinter::VisitForStatement(ForStatement* node) { 141 if (node->init() != NULL) { 142 Find(node->init()); 143 } 144 if (node->cond() != NULL) Find(node->cond()); 145 if (node->next() != NULL) Find(node->next()); 146 Find(node->body()); 147} 148 149 150void CallPrinter::VisitForInStatement(ForInStatement* node) { 151 Find(node->each()); 152 Find(node->enumerable()); 153 Find(node->body()); 154} 155 156 157void CallPrinter::VisitForOfStatement(ForOfStatement* node) { 158 Find(node->assign_iterator()); 159 Find(node->next_result()); 160 Find(node->result_done()); 161 Find(node->assign_each()); 162 Find(node->body()); 163} 164 165 166void CallPrinter::VisitTryCatchStatement(TryCatchStatement* node) { 167 Find(node->try_block()); 168 Find(node->catch_block()); 169} 170 171 172void CallPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) { 173 Find(node->try_block()); 174 Find(node->finally_block()); 175} 176 177 178void CallPrinter::VisitDebuggerStatement(DebuggerStatement* node) {} 179 180 181void CallPrinter::VisitFunctionLiteral(FunctionLiteral* node) { 182 FindStatements(node->body()); 183} 184 185 186void CallPrinter::VisitClassLiteral(ClassLiteral* node) { 187 if (node->extends()) Find(node->extends()); 188 for (int i = 0; i < node->properties()->length(); i++) { 189 Find(node->properties()->at(i)->value()); 190 } 191} 192 193 194void CallPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {} 195 196 197void CallPrinter::VisitDoExpression(DoExpression* node) { Find(node->block()); } 198 199 200void CallPrinter::VisitConditional(Conditional* node) { 201 Find(node->condition()); 202 Find(node->then_expression()); 203 Find(node->else_expression()); 204} 205 206 207void CallPrinter::VisitLiteral(Literal* node) { 208 PrintLiteral(node->value(), true); 209} 210 211 212void CallPrinter::VisitRegExpLiteral(RegExpLiteral* node) { 213 Print("/"); 214 PrintLiteral(node->pattern(), false); 215 Print("/"); 216 if (node->flags() & RegExp::kGlobal) Print("g"); 217 if (node->flags() & RegExp::kIgnoreCase) Print("i"); 218 if (node->flags() & RegExp::kMultiline) Print("m"); 219 if (node->flags() & RegExp::kUnicode) Print("u"); 220 if (node->flags() & RegExp::kSticky) Print("y"); 221} 222 223 224void CallPrinter::VisitObjectLiteral(ObjectLiteral* node) { 225 for (int i = 0; i < node->properties()->length(); i++) { 226 Find(node->properties()->at(i)->value()); 227 } 228} 229 230 231void CallPrinter::VisitArrayLiteral(ArrayLiteral* node) { 232 Print("["); 233 for (int i = 0; i < node->values()->length(); i++) { 234 if (i != 0) Print(","); 235 Find(node->values()->at(i), true); 236 } 237 Print("]"); 238} 239 240 241void CallPrinter::VisitVariableProxy(VariableProxy* node) { 242 if (is_builtin_) { 243 // Variable names of builtins are meaningless due to minification. 244 Print("(var)"); 245 } else { 246 PrintLiteral(node->name(), false); 247 } 248} 249 250 251void CallPrinter::VisitAssignment(Assignment* node) { 252 Find(node->target()); 253 Find(node->value()); 254} 255 256 257void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); } 258 259 260void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); } 261 262 263void CallPrinter::VisitProperty(Property* node) { 264 Expression* key = node->key(); 265 Literal* literal = key->AsLiteral(); 266 if (literal != NULL && literal->value()->IsInternalizedString()) { 267 Find(node->obj(), true); 268 Print("."); 269 PrintLiteral(literal->value(), false); 270 } else { 271 Find(node->obj(), true); 272 Print("["); 273 Find(key, true); 274 Print("]"); 275 } 276} 277 278 279void CallPrinter::VisitCall(Call* node) { 280 bool was_found = !found_ && node->position() == position_; 281 if (was_found) { 282 // Bail out if the error is caused by a direct call to a variable in builtin 283 // code. The variable name is meaningless due to minification. 284 if (is_builtin_ && node->expression()->IsVariableProxy()) { 285 done_ = true; 286 return; 287 } 288 found_ = true; 289 } 290 Find(node->expression(), true); 291 if (!was_found) Print("(...)"); 292 FindArguments(node->arguments()); 293 if (was_found) done_ = true; 294} 295 296 297void CallPrinter::VisitCallNew(CallNew* node) { 298 bool was_found = !found_ && node->position() == position_; 299 if (was_found) { 300 // Bail out if the error is caused by a direct call to a variable in builtin 301 // code. The variable name is meaningless due to minification. 302 if (is_builtin_ && node->expression()->IsVariableProxy()) { 303 done_ = true; 304 return; 305 } 306 found_ = true; 307 } 308 Find(node->expression(), was_found); 309 FindArguments(node->arguments()); 310 if (was_found) done_ = true; 311} 312 313 314void CallPrinter::VisitCallRuntime(CallRuntime* node) { 315 FindArguments(node->arguments()); 316} 317 318 319void CallPrinter::VisitUnaryOperation(UnaryOperation* node) { 320 Token::Value op = node->op(); 321 bool needsSpace = 322 op == Token::DELETE || op == Token::TYPEOF || op == Token::VOID; 323 Print("("); 324 Print(Token::String(op)); 325 if (needsSpace) Print(" "); 326 Find(node->expression(), true); 327 Print(")"); 328} 329 330 331void CallPrinter::VisitCountOperation(CountOperation* node) { 332 Print("("); 333 if (node->is_prefix()) Print(Token::String(node->op())); 334 Find(node->expression(), true); 335 if (node->is_postfix()) Print(Token::String(node->op())); 336 Print(")"); 337} 338 339 340void CallPrinter::VisitBinaryOperation(BinaryOperation* node) { 341 Print("("); 342 Find(node->left(), true); 343 Print(" "); 344 Print(Token::String(node->op())); 345 Print(" "); 346 Find(node->right(), true); 347 Print(")"); 348} 349 350 351void CallPrinter::VisitCompareOperation(CompareOperation* node) { 352 Print("("); 353 Find(node->left(), true); 354 Print(" "); 355 Print(Token::String(node->op())); 356 Print(" "); 357 Find(node->right(), true); 358 Print(")"); 359} 360 361 362void CallPrinter::VisitSpread(Spread* node) { 363 Print("(..."); 364 Find(node->expression(), true); 365 Print(")"); 366} 367 368 369void CallPrinter::VisitEmptyParentheses(EmptyParentheses* node) { 370 UNREACHABLE(); 371} 372 373 374void CallPrinter::VisitThisFunction(ThisFunction* node) {} 375 376 377void CallPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {} 378 379 380void CallPrinter::VisitSuperCallReference(SuperCallReference* node) { 381 Print("super"); 382} 383 384 385void CallPrinter::VisitRewritableExpression(RewritableExpression* node) { 386 Find(node->expression()); 387} 388 389 390void CallPrinter::FindStatements(ZoneList<Statement*>* statements) { 391 if (statements == NULL) return; 392 for (int i = 0; i < statements->length(); i++) { 393 Find(statements->at(i)); 394 } 395} 396 397 398void CallPrinter::FindArguments(ZoneList<Expression*>* arguments) { 399 if (found_) return; 400 for (int i = 0; i < arguments->length(); i++) { 401 Find(arguments->at(i)); 402 } 403} 404 405void CallPrinter::PrintLiteral(Handle<Object> value, bool quote) { 406 if (value->IsString()) { 407 if (quote) Print("\""); 408 Print(Handle<String>::cast(value)); 409 if (quote) Print("\""); 410 } else if (value->IsNull(isolate_)) { 411 Print("null"); 412 } else if (value->IsTrue(isolate_)) { 413 Print("true"); 414 } else if (value->IsFalse(isolate_)) { 415 Print("false"); 416 } else if (value->IsUndefined(isolate_)) { 417 Print("undefined"); 418 } else if (value->IsNumber()) { 419 Print(isolate_->factory()->NumberToString(value)); 420 } else if (value->IsSymbol()) { 421 // Symbols can only occur as literals if they were inserted by the parser. 422 PrintLiteral(handle(Handle<Symbol>::cast(value)->name(), isolate_), false); 423 } 424} 425 426 427void CallPrinter::PrintLiteral(const AstRawString* value, bool quote) { 428 PrintLiteral(value->string(), quote); 429} 430 431 432//----------------------------------------------------------------------------- 433 434 435#ifdef DEBUG 436 437// A helper for ast nodes that use FeedbackVectorSlots. 438static int FormatSlotNode(Vector<char>* buf, Expression* node, 439 const char* node_name, FeedbackVectorSlot slot) { 440 int pos = SNPrintF(*buf, "%s", node_name); 441 if (!slot.IsInvalid()) { 442 pos += SNPrintF(*buf + pos, " Slot(%d)", slot.ToInt()); 443 } 444 return pos; 445} 446 447const char* AstPrinter::Print(AstNode* node) { 448 Init(); 449 Visit(node); 450 return output_; 451} 452 453void AstPrinter::Init() { 454 if (size_ == 0) { 455 DCHECK(output_ == NULL); 456 const int initial_size = 256; 457 output_ = NewArray<char>(initial_size); 458 size_ = initial_size; 459 } 460 output_[0] = '\0'; 461 pos_ = 0; 462} 463 464void AstPrinter::Print(const char* format, ...) { 465 for (;;) { 466 va_list arguments; 467 va_start(arguments, format); 468 int n = VSNPrintF(Vector<char>(output_, size_) + pos_, 469 format, 470 arguments); 471 va_end(arguments); 472 473 if (n >= 0) { 474 // there was enough space - we are done 475 pos_ += n; 476 return; 477 } else { 478 // there was not enough space - allocate more and try again 479 const int slack = 32; 480 int new_size = size_ + (size_ >> 1) + slack; 481 char* new_output = NewArray<char>(new_size); 482 MemCopy(new_output, output_, pos_); 483 DeleteArray(output_); 484 output_ = new_output; 485 size_ = new_size; 486 } 487 } 488} 489 490void AstPrinter::PrintLabels(ZoneList<const AstRawString*>* labels) { 491 if (labels != NULL) { 492 for (int i = 0; i < labels->length(); i++) { 493 PrintLiteral(labels->at(i), false); 494 Print(": "); 495 } 496 } 497} 498 499void AstPrinter::PrintLiteral(Handle<Object> value, bool quote) { 500 Object* object = *value; 501 if (object->IsString()) { 502 String* string = String::cast(object); 503 if (quote) Print("\""); 504 for (int i = 0; i < string->length(); i++) { 505 Print("%c", string->Get(i)); 506 } 507 if (quote) Print("\""); 508 } else if (object->IsNull(isolate_)) { 509 Print("null"); 510 } else if (object->IsTrue(isolate_)) { 511 Print("true"); 512 } else if (object->IsFalse(isolate_)) { 513 Print("false"); 514 } else if (object->IsUndefined(isolate_)) { 515 Print("undefined"); 516 } else if (object->IsNumber()) { 517 Print("%g", object->Number()); 518 } else if (object->IsJSObject()) { 519 // regular expression 520 if (object->IsJSFunction()) { 521 Print("JS-Function"); 522 } else if (object->IsJSArray()) { 523 Print("JS-array[%u]", 524 Smi::cast(JSArray::cast(object)->length())->value()); 525 } else if (object->IsJSObject()) { 526 Print("JS-Object"); 527 } else { 528 Print("?UNKNOWN?"); 529 } 530 } else if (object->IsFixedArray()) { 531 Print("FixedArray"); 532 } else if (object->IsSymbol()) { 533 // Symbols can only occur as literals if they were inserted by the parser. 534 Symbol* symbol = Symbol::cast(object); 535 if (symbol->name()->IsString()) { 536 int length = 0; 537 String* string = String::cast(symbol->name()); 538 std::unique_ptr<char[]> desc = string->ToCString( 539 ALLOW_NULLS, FAST_STRING_TRAVERSAL, 0, string->length(), &length); 540 Print("Symbol(%*s)", length, desc.get()); 541 } else { 542 Print("Symbol()"); 543 } 544 } else { 545 Print("<unknown literal %p>", static_cast<void*>(object)); 546 } 547} 548 549void AstPrinter::PrintLiteral(const AstRawString* value, bool quote) { 550 PrintLiteral(value->string(), quote); 551} 552 553 554//----------------------------------------------------------------------------- 555 556class IndentedScope BASE_EMBEDDED { 557 public: 558 IndentedScope(AstPrinter* printer, const char* txt) 559 : ast_printer_(printer) { 560 ast_printer_->PrintIndented(txt); 561 ast_printer_->Print("\n"); 562 ast_printer_->inc_indent(); 563 } 564 565 IndentedScope(AstPrinter* printer, const char* txt, int pos) 566 : ast_printer_(printer) { 567 ast_printer_->PrintIndented(txt); 568 ast_printer_->Print(" at %d\n", pos); 569 ast_printer_->inc_indent(); 570 } 571 572 virtual ~IndentedScope() { 573 ast_printer_->dec_indent(); 574 } 575 576 private: 577 AstPrinter* ast_printer_; 578}; 579 580 581//----------------------------------------------------------------------------- 582 583AstPrinter::AstPrinter(Isolate* isolate) 584 : isolate_(isolate), output_(nullptr), size_(0), pos_(0), indent_(0) { 585 InitializeAstVisitor(isolate); 586} 587 588AstPrinter::~AstPrinter() { 589 DCHECK(indent_ == 0); 590 DeleteArray(output_); 591} 592 593 594void AstPrinter::PrintIndented(const char* txt) { 595 for (int i = 0; i < indent_; i++) { 596 Print(". "); 597 } 598 Print("%s", txt); 599} 600 601 602void AstPrinter::PrintLiteralIndented(const char* info, 603 Handle<Object> value, 604 bool quote) { 605 PrintIndented(info); 606 Print(" "); 607 PrintLiteral(value, quote); 608 Print("\n"); 609} 610 611 612void AstPrinter::PrintLiteralWithModeIndented(const char* info, 613 Variable* var, 614 Handle<Object> value) { 615 if (var == NULL) { 616 PrintLiteralIndented(info, value, true); 617 } else { 618 EmbeddedVector<char, 256> buf; 619 int pos = 620 SNPrintF(buf, "%s (mode = %s", info, VariableMode2String(var->mode())); 621 SNPrintF(buf + pos, ")"); 622 PrintLiteralIndented(buf.start(), value, true); 623 } 624} 625 626 627void AstPrinter::PrintLabelsIndented(ZoneList<const AstRawString*>* labels) { 628 if (labels == NULL || labels->length() == 0) return; 629 PrintIndented("LABELS "); 630 PrintLabels(labels); 631 Print("\n"); 632} 633 634 635void AstPrinter::PrintIndentedVisit(const char* s, AstNode* node) { 636 IndentedScope indent(this, s, node->position()); 637 Visit(node); 638} 639 640 641const char* AstPrinter::PrintProgram(FunctionLiteral* program) { 642 Init(); 643 { IndentedScope indent(this, "FUNC", program->position()); 644 PrintIndented("KIND"); 645 Print(" %d\n", program->kind()); 646 PrintIndented("YIELD COUNT"); 647 Print(" %d\n", program->yield_count()); 648 PrintLiteralIndented("NAME", program->name(), true); 649 PrintLiteralIndented("INFERRED NAME", program->inferred_name(), true); 650 PrintParameters(program->scope()); 651 PrintDeclarations(program->scope()->declarations()); 652 PrintStatements(program->body()); 653 } 654 return output_; 655} 656 657 658void AstPrinter::PrintOut(Isolate* isolate, AstNode* node) { 659 AstPrinter printer(isolate); 660 printer.Init(); 661 printer.Visit(node); 662 PrintF("%s", printer.output_); 663} 664 665void AstPrinter::PrintDeclarations(Declaration::List* declarations) { 666 if (!declarations->is_empty()) { 667 IndentedScope indent(this, "DECLS"); 668 for (Declaration* decl : *declarations) Visit(decl); 669 } 670} 671 672void AstPrinter::PrintParameters(DeclarationScope* scope) { 673 if (scope->num_parameters() > 0) { 674 IndentedScope indent(this, "PARAMS"); 675 for (int i = 0; i < scope->num_parameters(); i++) { 676 PrintLiteralWithModeIndented("VAR", scope->parameter(i), 677 scope->parameter(i)->name()); 678 } 679 } 680} 681 682 683void AstPrinter::PrintStatements(ZoneList<Statement*>* statements) { 684 for (int i = 0; i < statements->length(); i++) { 685 Visit(statements->at(i)); 686 } 687} 688 689 690void AstPrinter::PrintArguments(ZoneList<Expression*>* arguments) { 691 for (int i = 0; i < arguments->length(); i++) { 692 Visit(arguments->at(i)); 693 } 694} 695 696 697void AstPrinter::VisitBlock(Block* node) { 698 const char* block_txt = 699 node->ignore_completion_value() ? "BLOCK NOCOMPLETIONS" : "BLOCK"; 700 IndentedScope indent(this, block_txt, node->position()); 701 PrintStatements(node->statements()); 702} 703 704 705// TODO(svenpanne) Start with IndentedScope. 706void AstPrinter::VisitVariableDeclaration(VariableDeclaration* node) { 707 PrintLiteralWithModeIndented("VARIABLE", node->proxy()->var(), 708 node->proxy()->name()); 709} 710 711 712// TODO(svenpanne) Start with IndentedScope. 713void AstPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) { 714 PrintIndented("FUNCTION "); 715 PrintLiteral(node->proxy()->name(), true); 716 Print(" = function "); 717 PrintLiteral(node->fun()->name(), false); 718 Print("\n"); 719} 720 721 722void AstPrinter::VisitExpressionStatement(ExpressionStatement* node) { 723 IndentedScope indent(this, "EXPRESSION STATEMENT", node->position()); 724 Visit(node->expression()); 725} 726 727 728void AstPrinter::VisitEmptyStatement(EmptyStatement* node) { 729 IndentedScope indent(this, "EMPTY", node->position()); 730} 731 732 733void AstPrinter::VisitSloppyBlockFunctionStatement( 734 SloppyBlockFunctionStatement* node) { 735 Visit(node->statement()); 736} 737 738 739void AstPrinter::VisitIfStatement(IfStatement* node) { 740 IndentedScope indent(this, "IF", node->position()); 741 PrintIndentedVisit("CONDITION", node->condition()); 742 PrintIndentedVisit("THEN", node->then_statement()); 743 if (node->HasElseStatement()) { 744 PrintIndentedVisit("ELSE", node->else_statement()); 745 } 746} 747 748 749void AstPrinter::VisitContinueStatement(ContinueStatement* node) { 750 IndentedScope indent(this, "CONTINUE", node->position()); 751 PrintLabelsIndented(node->target()->labels()); 752} 753 754 755void AstPrinter::VisitBreakStatement(BreakStatement* node) { 756 IndentedScope indent(this, "BREAK", node->position()); 757 PrintLabelsIndented(node->target()->labels()); 758} 759 760 761void AstPrinter::VisitReturnStatement(ReturnStatement* node) { 762 IndentedScope indent(this, "RETURN", node->position()); 763 Visit(node->expression()); 764} 765 766 767void AstPrinter::VisitWithStatement(WithStatement* node) { 768 IndentedScope indent(this, "WITH", node->position()); 769 PrintIndentedVisit("OBJECT", node->expression()); 770 PrintIndentedVisit("BODY", node->statement()); 771} 772 773 774void AstPrinter::VisitSwitchStatement(SwitchStatement* node) { 775 IndentedScope indent(this, "SWITCH", node->position()); 776 PrintLabelsIndented(node->labels()); 777 PrintIndentedVisit("TAG", node->tag()); 778 for (int i = 0; i < node->cases()->length(); i++) { 779 Visit(node->cases()->at(i)); 780 } 781} 782 783 784void AstPrinter::VisitCaseClause(CaseClause* clause) { 785 if (clause->is_default()) { 786 IndentedScope indent(this, "DEFAULT", clause->position()); 787 PrintStatements(clause->statements()); 788 } else { 789 IndentedScope indent(this, "CASE", clause->position()); 790 Visit(clause->label()); 791 PrintStatements(clause->statements()); 792 } 793} 794 795 796void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) { 797 IndentedScope indent(this, "DO", node->position()); 798 PrintIndented("YIELD COUNT"); 799 Print(" %d\n", node->yield_count()); 800 PrintLabelsIndented(node->labels()); 801 PrintIndentedVisit("BODY", node->body()); 802 PrintIndentedVisit("COND", node->cond()); 803} 804 805 806void AstPrinter::VisitWhileStatement(WhileStatement* node) { 807 IndentedScope indent(this, "WHILE", node->position()); 808 PrintIndented("YIELD COUNT"); 809 Print(" %d\n", node->yield_count()); 810 PrintLabelsIndented(node->labels()); 811 PrintIndentedVisit("COND", node->cond()); 812 PrintIndentedVisit("BODY", node->body()); 813} 814 815 816void AstPrinter::VisitForStatement(ForStatement* node) { 817 IndentedScope indent(this, "FOR", node->position()); 818 PrintIndented("YIELD COUNT"); 819 Print(" %d\n", node->yield_count()); 820 PrintLabelsIndented(node->labels()); 821 if (node->init()) PrintIndentedVisit("INIT", node->init()); 822 if (node->cond()) PrintIndentedVisit("COND", node->cond()); 823 PrintIndentedVisit("BODY", node->body()); 824 if (node->next()) PrintIndentedVisit("NEXT", node->next()); 825} 826 827 828void AstPrinter::VisitForInStatement(ForInStatement* node) { 829 IndentedScope indent(this, "FOR IN", node->position()); 830 PrintIndented("YIELD COUNT"); 831 Print(" %d\n", node->yield_count()); 832 PrintIndentedVisit("FOR", node->each()); 833 PrintIndentedVisit("IN", node->enumerable()); 834 PrintIndentedVisit("BODY", node->body()); 835} 836 837 838void AstPrinter::VisitForOfStatement(ForOfStatement* node) { 839 IndentedScope indent(this, "FOR OF", node->position()); 840 PrintIndented("YIELD COUNT"); 841 Print(" %d\n", node->yield_count()); 842 PrintIndentedVisit("INIT", node->assign_iterator()); 843 PrintIndentedVisit("NEXT", node->next_result()); 844 PrintIndentedVisit("DONE", node->result_done()); 845 PrintIndentedVisit("EACH", node->assign_each()); 846 PrintIndentedVisit("BODY", node->body()); 847} 848 849 850void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) { 851 IndentedScope indent(this, "TRY CATCH", node->position()); 852 PrintTryStatement(node); 853 PrintLiteralWithModeIndented("CATCHVAR", 854 node->variable(), 855 node->variable()->name()); 856 PrintIndentedVisit("CATCH", node->catch_block()); 857} 858 859 860void AstPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) { 861 IndentedScope indent(this, "TRY FINALLY", node->position()); 862 PrintTryStatement(node); 863 PrintIndentedVisit("FINALLY", node->finally_block()); 864} 865 866void AstPrinter::PrintTryStatement(TryStatement* node) { 867 PrintIndentedVisit("TRY", node->try_block()); 868 PrintIndented("CATCH PREDICTION"); 869 const char* prediction = ""; 870 switch (node->catch_prediction()) { 871 case HandlerTable::UNCAUGHT: 872 prediction = "UNCAUGHT"; 873 break; 874 case HandlerTable::CAUGHT: 875 prediction = "CAUGHT"; 876 break; 877 case HandlerTable::PROMISE: 878 prediction = "PROMISE"; 879 break; 880 case HandlerTable::DESUGARING: 881 prediction = "DESUGARING"; 882 break; 883 case HandlerTable::ASYNC_AWAIT: 884 prediction = "ASYNC_AWAIT"; 885 break; 886 } 887 Print(" %s\n", prediction); 888} 889 890void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) { 891 IndentedScope indent(this, "DEBUGGER", node->position()); 892} 893 894 895void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) { 896 IndentedScope indent(this, "FUNC LITERAL", node->position()); 897 PrintLiteralIndented("NAME", node->name(), false); 898 PrintLiteralIndented("INFERRED NAME", node->inferred_name(), false); 899 PrintParameters(node->scope()); 900 // We don't want to see the function literal in this case: it 901 // will be printed via PrintProgram when the code for it is 902 // generated. 903 // PrintStatements(node->body()); 904} 905 906 907void AstPrinter::VisitClassLiteral(ClassLiteral* node) { 908 IndentedScope indent(this, "CLASS LITERAL", node->position()); 909 PrintLiteralIndented("NAME", node->constructor()->name(), false); 910 if (node->extends() != nullptr) { 911 PrintIndentedVisit("EXTENDS", node->extends()); 912 } 913 PrintClassProperties(node->properties()); 914} 915 916void AstPrinter::PrintClassProperties( 917 ZoneList<ClassLiteral::Property*>* properties) { 918 for (int i = 0; i < properties->length(); i++) { 919 ClassLiteral::Property* property = properties->at(i); 920 const char* prop_kind = nullptr; 921 switch (property->kind()) { 922 case ClassLiteral::Property::METHOD: 923 prop_kind = "METHOD"; 924 break; 925 case ClassLiteral::Property::GETTER: 926 prop_kind = "GETTER"; 927 break; 928 case ClassLiteral::Property::SETTER: 929 prop_kind = "SETTER"; 930 break; 931 case ClassLiteral::Property::FIELD: 932 prop_kind = "FIELD"; 933 break; 934 } 935 EmbeddedVector<char, 128> buf; 936 SNPrintF(buf, "PROPERTY%s - %s", property->is_static() ? " - STATIC" : "", 937 prop_kind); 938 IndentedScope prop(this, buf.start()); 939 PrintIndentedVisit("KEY", properties->at(i)->key()); 940 PrintIndentedVisit("VALUE", properties->at(i)->value()); 941 } 942} 943 944 945void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) { 946 IndentedScope indent(this, "NATIVE FUNC LITERAL", node->position()); 947 PrintLiteralIndented("NAME", node->name(), false); 948} 949 950 951void AstPrinter::VisitDoExpression(DoExpression* node) { 952 IndentedScope indent(this, "DO EXPRESSION", node->position()); 953 PrintStatements(node->block()->statements()); 954} 955 956 957void AstPrinter::VisitConditional(Conditional* node) { 958 IndentedScope indent(this, "CONDITIONAL", node->position()); 959 PrintIndentedVisit("CONDITION", node->condition()); 960 PrintIndentedVisit("THEN", node->then_expression()); 961 PrintIndentedVisit("ELSE", node->else_expression()); 962} 963 964 965// TODO(svenpanne) Start with IndentedScope. 966void AstPrinter::VisitLiteral(Literal* node) { 967 PrintLiteralIndented("LITERAL", node->value(), true); 968} 969 970 971void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) { 972 IndentedScope indent(this, "REGEXP LITERAL", node->position()); 973 EmbeddedVector<char, 128> buf; 974 SNPrintF(buf, "literal_index = %d\n", node->literal_index()); 975 PrintIndented(buf.start()); 976 PrintLiteralIndented("PATTERN", node->pattern(), false); 977 int i = 0; 978 if (node->flags() & RegExp::kGlobal) buf[i++] = 'g'; 979 if (node->flags() & RegExp::kIgnoreCase) buf[i++] = 'i'; 980 if (node->flags() & RegExp::kMultiline) buf[i++] = 'm'; 981 if (node->flags() & RegExp::kUnicode) buf[i++] = 'u'; 982 if (node->flags() & RegExp::kSticky) buf[i++] = 'y'; 983 buf[i] = '\0'; 984 PrintIndented("FLAGS "); 985 Print("%s", buf.start()); 986 Print("\n"); 987} 988 989 990void AstPrinter::VisitObjectLiteral(ObjectLiteral* node) { 991 IndentedScope indent(this, "OBJ LITERAL", node->position()); 992 EmbeddedVector<char, 128> buf; 993 SNPrintF(buf, "literal_index = %d\n", node->literal_index()); 994 PrintIndented(buf.start()); 995 PrintObjectProperties(node->properties()); 996} 997 998void AstPrinter::PrintObjectProperties( 999 ZoneList<ObjectLiteral::Property*>* properties) { 1000 for (int i = 0; i < properties->length(); i++) { 1001 ObjectLiteral::Property* property = properties->at(i); 1002 const char* prop_kind = nullptr; 1003 switch (property->kind()) { 1004 case ObjectLiteral::Property::CONSTANT: 1005 prop_kind = "CONSTANT"; 1006 break; 1007 case ObjectLiteral::Property::COMPUTED: 1008 prop_kind = "COMPUTED"; 1009 break; 1010 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 1011 prop_kind = "MATERIALIZED_LITERAL"; 1012 break; 1013 case ObjectLiteral::Property::PROTOTYPE: 1014 prop_kind = "PROTOTYPE"; 1015 break; 1016 case ObjectLiteral::Property::GETTER: 1017 prop_kind = "GETTER"; 1018 break; 1019 case ObjectLiteral::Property::SETTER: 1020 prop_kind = "SETTER"; 1021 break; 1022 } 1023 EmbeddedVector<char, 128> buf; 1024 SNPrintF(buf, "PROPERTY - %s", prop_kind); 1025 IndentedScope prop(this, buf.start()); 1026 PrintIndentedVisit("KEY", properties->at(i)->key()); 1027 PrintIndentedVisit("VALUE", properties->at(i)->value()); 1028 } 1029} 1030 1031 1032void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) { 1033 IndentedScope indent(this, "ARRAY LITERAL", node->position()); 1034 1035 EmbeddedVector<char, 128> buf; 1036 SNPrintF(buf, "literal_index = %d\n", node->literal_index()); 1037 PrintIndented(buf.start()); 1038 if (node->values()->length() > 0) { 1039 IndentedScope indent(this, "VALUES", node->position()); 1040 for (int i = 0; i < node->values()->length(); i++) { 1041 Visit(node->values()->at(i)); 1042 } 1043 } 1044} 1045 1046 1047void AstPrinter::VisitVariableProxy(VariableProxy* node) { 1048 EmbeddedVector<char, 128> buf; 1049 int pos = 1050 FormatSlotNode(&buf, node, "VAR PROXY", node->VariableFeedbackSlot()); 1051 1052 if (!node->is_resolved()) { 1053 SNPrintF(buf + pos, " unresolved"); 1054 PrintLiteralWithModeIndented(buf.start(), nullptr, node->name()); 1055 } else { 1056 Variable* var = node->var(); 1057 switch (var->location()) { 1058 case VariableLocation::UNALLOCATED: 1059 SNPrintF(buf + pos, " unallocated"); 1060 break; 1061 case VariableLocation::PARAMETER: 1062 SNPrintF(buf + pos, " parameter[%d]", var->index()); 1063 break; 1064 case VariableLocation::LOCAL: 1065 SNPrintF(buf + pos, " local[%d]", var->index()); 1066 break; 1067 case VariableLocation::CONTEXT: 1068 SNPrintF(buf + pos, " context[%d]", var->index()); 1069 break; 1070 case VariableLocation::LOOKUP: 1071 SNPrintF(buf + pos, " lookup"); 1072 break; 1073 case VariableLocation::MODULE: 1074 SNPrintF(buf + pos, " module"); 1075 break; 1076 } 1077 PrintLiteralWithModeIndented(buf.start(), var, node->name()); 1078 } 1079} 1080 1081 1082void AstPrinter::VisitAssignment(Assignment* node) { 1083 IndentedScope indent(this, Token::Name(node->op()), node->position()); 1084 Visit(node->target()); 1085 Visit(node->value()); 1086} 1087 1088 1089void AstPrinter::VisitYield(Yield* node) { 1090 EmbeddedVector<char, 128> buf; 1091 SNPrintF(buf, "YIELD id %d", node->yield_id()); 1092 IndentedScope indent(this, buf.start(), node->position()); 1093 Visit(node->expression()); 1094} 1095 1096 1097void AstPrinter::VisitThrow(Throw* node) { 1098 IndentedScope indent(this, "THROW", node->position()); 1099 Visit(node->exception()); 1100} 1101 1102 1103void AstPrinter::VisitProperty(Property* node) { 1104 EmbeddedVector<char, 128> buf; 1105 FormatSlotNode(&buf, node, "PROPERTY", node->PropertyFeedbackSlot()); 1106 IndentedScope indent(this, buf.start(), node->position()); 1107 1108 Visit(node->obj()); 1109 Literal* literal = node->key()->AsLiteral(); 1110 if (literal != NULL && literal->value()->IsInternalizedString()) { 1111 PrintLiteralIndented("NAME", literal->value(), false); 1112 } else { 1113 PrintIndentedVisit("KEY", node->key()); 1114 } 1115} 1116 1117 1118void AstPrinter::VisitCall(Call* node) { 1119 EmbeddedVector<char, 128> buf; 1120 const char* name = 1121 node->tail_call_mode() == TailCallMode::kAllow ? "TAIL CALL" : "CALL"; 1122 FormatSlotNode(&buf, node, name, node->CallFeedbackICSlot()); 1123 IndentedScope indent(this, buf.start()); 1124 1125 Visit(node->expression()); 1126 PrintArguments(node->arguments()); 1127} 1128 1129 1130void AstPrinter::VisitCallNew(CallNew* node) { 1131 IndentedScope indent(this, "CALL NEW", node->position()); 1132 Visit(node->expression()); 1133 PrintArguments(node->arguments()); 1134} 1135 1136 1137void AstPrinter::VisitCallRuntime(CallRuntime* node) { 1138 EmbeddedVector<char, 128> buf; 1139 SNPrintF(buf, "CALL RUNTIME %s", node->debug_name()); 1140 IndentedScope indent(this, buf.start(), node->position()); 1141 PrintArguments(node->arguments()); 1142} 1143 1144 1145void AstPrinter::VisitUnaryOperation(UnaryOperation* node) { 1146 IndentedScope indent(this, Token::Name(node->op()), node->position()); 1147 Visit(node->expression()); 1148} 1149 1150 1151void AstPrinter::VisitCountOperation(CountOperation* node) { 1152 EmbeddedVector<char, 128> buf; 1153 SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"), 1154 Token::Name(node->op())); 1155 IndentedScope indent(this, buf.start(), node->position()); 1156 Visit(node->expression()); 1157} 1158 1159 1160void AstPrinter::VisitBinaryOperation(BinaryOperation* node) { 1161 IndentedScope indent(this, Token::Name(node->op()), node->position()); 1162 Visit(node->left()); 1163 Visit(node->right()); 1164} 1165 1166 1167void AstPrinter::VisitCompareOperation(CompareOperation* node) { 1168 IndentedScope indent(this, Token::Name(node->op()), node->position()); 1169 Visit(node->left()); 1170 Visit(node->right()); 1171} 1172 1173 1174void AstPrinter::VisitSpread(Spread* node) { 1175 IndentedScope indent(this, "...", node->position()); 1176 Visit(node->expression()); 1177} 1178 1179 1180void AstPrinter::VisitEmptyParentheses(EmptyParentheses* node) { 1181 IndentedScope indent(this, "()", node->position()); 1182} 1183 1184 1185void AstPrinter::VisitThisFunction(ThisFunction* node) { 1186 IndentedScope indent(this, "THIS-FUNCTION", node->position()); 1187} 1188 1189 1190void AstPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) { 1191 IndentedScope indent(this, "SUPER-PROPERTY-REFERENCE", node->position()); 1192} 1193 1194 1195void AstPrinter::VisitSuperCallReference(SuperCallReference* node) { 1196 IndentedScope indent(this, "SUPER-CALL-REFERENCE", node->position()); 1197} 1198 1199 1200void AstPrinter::VisitRewritableExpression(RewritableExpression* node) { 1201 Visit(node->expression()); 1202} 1203 1204 1205#endif // DEBUG 1206 1207} // namespace internal 1208} // namespace v8 1209