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 #include "src/objects-inl.h" 14 #include "src/string-builder-inl.h" 15 16 namespace v8 { 17 namespace internal { 18 19 CallPrinter::CallPrinter(Isolate* isolate, bool is_user_js) 20 : builder_(new IncrementalStringBuilder(isolate)) { 21 isolate_ = isolate; 22 position_ = 0; 23 num_prints_ = 0; 24 found_ = false; 25 done_ = false; 26 is_call_error_ = false; 27 is_iterator_error_ = false; 28 is_async_iterator_error_ = false; 29 is_user_js_ = is_user_js; 30 function_kind_ = kNormalFunction; 31 InitializeAstVisitor(isolate); 32 } 33 34 CallPrinter::~CallPrinter() {} 35 36 CallPrinter::ErrorHint CallPrinter::GetErrorHint() const { 37 if (is_call_error_) { 38 if (is_iterator_error_) return ErrorHint::kCallAndNormalIterator; 39 if (is_async_iterator_error_) return ErrorHint::kCallAndAsyncIterator; 40 } else { 41 if (is_iterator_error_) return ErrorHint::kNormalIterator; 42 if (is_async_iterator_error_) return ErrorHint::kAsyncIterator; 43 } 44 return ErrorHint::kNone; 45 } 46 47 Handle<String> CallPrinter::Print(FunctionLiteral* program, int position) { 48 num_prints_ = 0; 49 position_ = position; 50 Find(program); 51 return builder_->Finish().ToHandleChecked(); 52 } 53 54 55 void CallPrinter::Find(AstNode* node, bool print) { 56 if (found_) { 57 if (print) { 58 int prev_num_prints = num_prints_; 59 Visit(node); 60 if (prev_num_prints != num_prints_) return; 61 } 62 Print("(intermediate value)"); 63 } else { 64 Visit(node); 65 } 66 } 67 68 void CallPrinter::Print(const char* str) { 69 if (!found_ || done_) return; 70 num_prints_++; 71 builder_->AppendCString(str); 72 } 73 74 void CallPrinter::Print(Handle<String> str) { 75 if (!found_ || done_) return; 76 num_prints_++; 77 builder_->AppendString(str); 78 } 79 80 void CallPrinter::VisitBlock(Block* node) { 81 FindStatements(node->statements()); 82 } 83 84 85 void CallPrinter::VisitVariableDeclaration(VariableDeclaration* node) {} 86 87 88 void CallPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) {} 89 90 91 void CallPrinter::VisitExpressionStatement(ExpressionStatement* node) { 92 Find(node->expression()); 93 } 94 95 96 void CallPrinter::VisitEmptyStatement(EmptyStatement* node) {} 97 98 99 void CallPrinter::VisitSloppyBlockFunctionStatement( 100 SloppyBlockFunctionStatement* node) { 101 Find(node->statement()); 102 } 103 104 105 void CallPrinter::VisitIfStatement(IfStatement* node) { 106 Find(node->condition()); 107 Find(node->then_statement()); 108 if (node->HasElseStatement()) { 109 Find(node->else_statement()); 110 } 111 } 112 113 114 void CallPrinter::VisitContinueStatement(ContinueStatement* node) {} 115 116 117 void CallPrinter::VisitBreakStatement(BreakStatement* node) {} 118 119 120 void CallPrinter::VisitReturnStatement(ReturnStatement* node) { 121 Find(node->expression()); 122 } 123 124 125 void CallPrinter::VisitWithStatement(WithStatement* node) { 126 Find(node->expression()); 127 Find(node->statement()); 128 } 129 130 131 void CallPrinter::VisitSwitchStatement(SwitchStatement* node) { 132 Find(node->tag()); 133 for (CaseClause* clause : *node->cases()) { 134 if (!clause->is_default()) Find(clause->label()); 135 FindStatements(clause->statements()); 136 } 137 } 138 139 140 void CallPrinter::VisitDoWhileStatement(DoWhileStatement* node) { 141 Find(node->body()); 142 Find(node->cond()); 143 } 144 145 146 void CallPrinter::VisitWhileStatement(WhileStatement* node) { 147 Find(node->cond()); 148 Find(node->body()); 149 } 150 151 152 void CallPrinter::VisitForStatement(ForStatement* node) { 153 if (node->init() != nullptr) { 154 Find(node->init()); 155 } 156 if (node->cond() != nullptr) Find(node->cond()); 157 if (node->next() != nullptr) Find(node->next()); 158 Find(node->body()); 159 } 160 161 162 void CallPrinter::VisitForInStatement(ForInStatement* node) { 163 Find(node->each()); 164 Find(node->enumerable()); 165 Find(node->body()); 166 } 167 168 169 void CallPrinter::VisitForOfStatement(ForOfStatement* node) { 170 Find(node->assign_iterator()); 171 Find(node->next_result()); 172 Find(node->result_done()); 173 Find(node->assign_each()); 174 Find(node->body()); 175 } 176 177 178 void CallPrinter::VisitTryCatchStatement(TryCatchStatement* node) { 179 Find(node->try_block()); 180 Find(node->catch_block()); 181 } 182 183 184 void CallPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) { 185 Find(node->try_block()); 186 Find(node->finally_block()); 187 } 188 189 190 void CallPrinter::VisitDebuggerStatement(DebuggerStatement* node) {} 191 192 193 void CallPrinter::VisitFunctionLiteral(FunctionLiteral* node) { 194 FunctionKind last_function_kind = function_kind_; 195 function_kind_ = node->kind(); 196 FindStatements(node->body()); 197 function_kind_ = last_function_kind; 198 } 199 200 201 void CallPrinter::VisitClassLiteral(ClassLiteral* node) { 202 if (node->extends()) Find(node->extends()); 203 for (int i = 0; i < node->properties()->length(); i++) { 204 Find(node->properties()->at(i)->value()); 205 } 206 } 207 208 void CallPrinter::VisitInitializeClassFieldsStatement( 209 InitializeClassFieldsStatement* node) { 210 for (int i = 0; i < node->fields()->length(); i++) { 211 Find(node->fields()->at(i)->value()); 212 } 213 } 214 215 void CallPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {} 216 217 218 void CallPrinter::VisitDoExpression(DoExpression* node) { Find(node->block()); } 219 220 221 void CallPrinter::VisitConditional(Conditional* node) { 222 Find(node->condition()); 223 Find(node->then_expression()); 224 Find(node->else_expression()); 225 } 226 227 228 void CallPrinter::VisitLiteral(Literal* node) { 229 // TODO(adamk): Teach Literal how to print its values without 230 // allocating on the heap. 231 PrintLiteral(node->BuildValue(isolate_), true); 232 } 233 234 235 void CallPrinter::VisitRegExpLiteral(RegExpLiteral* node) { 236 Print("/"); 237 PrintLiteral(node->pattern(), false); 238 Print("/"); 239 if (node->flags() & RegExp::kGlobal) Print("g"); 240 if (node->flags() & RegExp::kIgnoreCase) Print("i"); 241 if (node->flags() & RegExp::kMultiline) Print("m"); 242 if (node->flags() & RegExp::kUnicode) Print("u"); 243 if (node->flags() & RegExp::kSticky) Print("y"); 244 } 245 246 247 void CallPrinter::VisitObjectLiteral(ObjectLiteral* node) { 248 Print("{"); 249 for (int i = 0; i < node->properties()->length(); i++) { 250 Find(node->properties()->at(i)->value()); 251 } 252 Print("}"); 253 } 254 255 256 void CallPrinter::VisitArrayLiteral(ArrayLiteral* node) { 257 Print("["); 258 for (int i = 0; i < node->values()->length(); i++) { 259 if (i != 0) Print(","); 260 Expression* subexpr = node->values()->at(i); 261 Spread* spread = subexpr->AsSpread(); 262 if (spread != nullptr && !found_ && 263 position_ == spread->expression()->position()) { 264 found_ = true; 265 is_iterator_error_ = true; 266 Find(spread->expression(), true); 267 done_ = true; 268 return; 269 } 270 Find(subexpr, true); 271 } 272 Print("]"); 273 } 274 275 276 void CallPrinter::VisitVariableProxy(VariableProxy* node) { 277 if (is_user_js_) { 278 PrintLiteral(node->name(), false); 279 } else { 280 // Variable names of non-user code are meaningless due to minification. 281 Print("(var)"); 282 } 283 } 284 285 286 void CallPrinter::VisitAssignment(Assignment* node) { 287 Find(node->target()); 288 Find(node->value()); 289 } 290 291 void CallPrinter::VisitCompoundAssignment(CompoundAssignment* node) { 292 VisitAssignment(node); 293 } 294 295 void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); } 296 297 void CallPrinter::VisitYieldStar(YieldStar* node) { 298 if (!found_ && position_ == node->expression()->position()) { 299 found_ = true; 300 if (IsAsyncFunction(function_kind_)) 301 is_async_iterator_error_ = true; 302 else 303 is_iterator_error_ = true; 304 Print("yield* "); 305 } 306 Find(node->expression()); 307 } 308 309 void CallPrinter::VisitAwait(Await* node) { Find(node->expression()); } 310 311 void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); } 312 313 314 void CallPrinter::VisitProperty(Property* node) { 315 Expression* key = node->key(); 316 Literal* literal = key->AsLiteral(); 317 if (literal != nullptr && 318 literal->BuildValue(isolate_)->IsInternalizedString()) { 319 Find(node->obj(), true); 320 Print("."); 321 // TODO(adamk): Teach Literal how to print its values without 322 // allocating on the heap. 323 PrintLiteral(literal->BuildValue(isolate_), false); 324 } else { 325 Find(node->obj(), true); 326 Print("["); 327 Find(key, true); 328 Print("]"); 329 } 330 } 331 332 void CallPrinter::VisitResolvedProperty(ResolvedProperty* node) {} 333 334 void CallPrinter::VisitCall(Call* node) { 335 bool was_found = false; 336 if (node->position() == position_) { 337 is_call_error_ = true; 338 was_found = !found_; 339 } 340 if (was_found) { 341 // Bail out if the error is caused by a direct call to a variable in 342 // non-user JS code. The variable name is meaningless due to minification. 343 if (!is_user_js_ && node->expression()->IsVariableProxy()) { 344 done_ = true; 345 return; 346 } 347 found_ = true; 348 } 349 Find(node->expression(), true); 350 if (!was_found) Print("(...)"); 351 FindArguments(node->arguments()); 352 if (was_found) { 353 done_ = true; 354 found_ = false; 355 } 356 } 357 358 359 void CallPrinter::VisitCallNew(CallNew* node) { 360 bool was_found = false; 361 if (node->position() == position_) { 362 is_call_error_ = true; 363 was_found = !found_; 364 } 365 if (was_found) { 366 // Bail out if the error is caused by a direct call to a variable in 367 // non-user JS code. The variable name is meaningless due to minification. 368 if (!is_user_js_ && node->expression()->IsVariableProxy()) { 369 done_ = true; 370 return; 371 } 372 found_ = true; 373 } 374 Find(node->expression(), was_found); 375 FindArguments(node->arguments()); 376 if (was_found) { 377 done_ = true; 378 found_ = false; 379 } 380 } 381 382 383 void CallPrinter::VisitCallRuntime(CallRuntime* node) { 384 FindArguments(node->arguments()); 385 } 386 387 388 void CallPrinter::VisitUnaryOperation(UnaryOperation* node) { 389 Token::Value op = node->op(); 390 bool needsSpace = 391 op == Token::DELETE || op == Token::TYPEOF || op == Token::VOID; 392 Print("("); 393 Print(Token::String(op)); 394 if (needsSpace) Print(" "); 395 Find(node->expression(), true); 396 Print(")"); 397 } 398 399 400 void CallPrinter::VisitCountOperation(CountOperation* node) { 401 Print("("); 402 if (node->is_prefix()) Print(Token::String(node->op())); 403 Find(node->expression(), true); 404 if (node->is_postfix()) Print(Token::String(node->op())); 405 Print(")"); 406 } 407 408 409 void CallPrinter::VisitBinaryOperation(BinaryOperation* node) { 410 Print("("); 411 Find(node->left(), true); 412 Print(" "); 413 Print(Token::String(node->op())); 414 Print(" "); 415 Find(node->right(), true); 416 Print(")"); 417 } 418 419 void CallPrinter::VisitNaryOperation(NaryOperation* node) { 420 Print("("); 421 Find(node->first(), true); 422 for (size_t i = 0; i < node->subsequent_length(); ++i) { 423 Print(" "); 424 Print(Token::String(node->op())); 425 Print(" "); 426 Find(node->subsequent(i), true); 427 } 428 Print(")"); 429 } 430 431 void CallPrinter::VisitCompareOperation(CompareOperation* node) { 432 Print("("); 433 Find(node->left(), true); 434 Print(" "); 435 Print(Token::String(node->op())); 436 Print(" "); 437 Find(node->right(), true); 438 Print(")"); 439 } 440 441 442 void CallPrinter::VisitSpread(Spread* node) { 443 Print("(..."); 444 Find(node->expression(), true); 445 Print(")"); 446 } 447 448 void CallPrinter::VisitStoreInArrayLiteral(StoreInArrayLiteral* node) { 449 Find(node->array()); 450 Find(node->index()); 451 Find(node->value()); 452 } 453 454 void CallPrinter::VisitEmptyParentheses(EmptyParentheses* node) { 455 UNREACHABLE(); 456 } 457 458 void CallPrinter::VisitGetIterator(GetIterator* node) { 459 bool was_found = false; 460 if (node->position() == position_) { 461 is_async_iterator_error_ = node->hint() == IteratorType::kAsync; 462 is_iterator_error_ = !is_async_iterator_error_; 463 was_found = !found_; 464 if (was_found) { 465 found_ = true; 466 } 467 } 468 Find(node->iterable_for_call_printer(), true); 469 if (was_found) { 470 done_ = true; 471 found_ = false; 472 } 473 } 474 475 void CallPrinter::VisitGetTemplateObject(GetTemplateObject* node) {} 476 477 void CallPrinter::VisitTemplateLiteral(TemplateLiteral* node) { 478 for (Expression* substitution : *node->substitutions()) { 479 Find(substitution, true); 480 } 481 } 482 483 void CallPrinter::VisitImportCallExpression(ImportCallExpression* node) { 484 Print("ImportCall("); 485 Find(node->argument(), true); 486 Print(")"); 487 } 488 489 void CallPrinter::VisitThisFunction(ThisFunction* node) {} 490 491 492 void CallPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {} 493 494 495 void CallPrinter::VisitSuperCallReference(SuperCallReference* node) { 496 Print("super"); 497 } 498 499 500 void CallPrinter::VisitRewritableExpression(RewritableExpression* node) { 501 Find(node->expression()); 502 } 503 504 void CallPrinter::FindStatements(ZonePtrList<Statement>* statements) { 505 if (statements == nullptr) return; 506 for (int i = 0; i < statements->length(); i++) { 507 Find(statements->at(i)); 508 } 509 } 510 511 void CallPrinter::FindArguments(ZonePtrList<Expression>* arguments) { 512 if (found_) return; 513 for (int i = 0; i < arguments->length(); i++) { 514 Find(arguments->at(i)); 515 } 516 } 517 518 void CallPrinter::PrintLiteral(Handle<Object> value, bool quote) { 519 if (value->IsString()) { 520 if (quote) Print("\""); 521 Print(Handle<String>::cast(value)); 522 if (quote) Print("\""); 523 } else if (value->IsNull(isolate_)) { 524 Print("null"); 525 } else if (value->IsTrue(isolate_)) { 526 Print("true"); 527 } else if (value->IsFalse(isolate_)) { 528 Print("false"); 529 } else if (value->IsUndefined(isolate_)) { 530 Print("undefined"); 531 } else if (value->IsNumber()) { 532 Print(isolate_->factory()->NumberToString(value)); 533 } else if (value->IsSymbol()) { 534 // Symbols can only occur as literals if they were inserted by the parser. 535 PrintLiteral(handle(Handle<Symbol>::cast(value)->name(), isolate_), false); 536 } 537 } 538 539 540 void CallPrinter::PrintLiteral(const AstRawString* value, bool quote) { 541 PrintLiteral(value->string(), quote); 542 } 543 544 545 //----------------------------------------------------------------------------- 546 547 548 #ifdef DEBUG 549 550 const char* AstPrinter::Print(AstNode* node) { 551 Init(); 552 Visit(node); 553 return output_; 554 } 555 556 void AstPrinter::Init() { 557 if (size_ == 0) { 558 DCHECK_NULL(output_); 559 const int initial_size = 256; 560 output_ = NewArray<char>(initial_size); 561 size_ = initial_size; 562 } 563 output_[0] = '\0'; 564 pos_ = 0; 565 } 566 567 void AstPrinter::Print(const char* format, ...) { 568 for (;;) { 569 va_list arguments; 570 va_start(arguments, format); 571 int n = VSNPrintF(Vector<char>(output_, size_) + pos_, 572 format, 573 arguments); 574 va_end(arguments); 575 576 if (n >= 0) { 577 // there was enough space - we are done 578 pos_ += n; 579 return; 580 } else { 581 // there was not enough space - allocate more and try again 582 const int slack = 32; 583 int new_size = size_ + (size_ >> 1) + slack; 584 char* new_output = NewArray<char>(new_size); 585 MemCopy(new_output, output_, pos_); 586 DeleteArray(output_); 587 output_ = new_output; 588 size_ = new_size; 589 } 590 } 591 } 592 593 void AstPrinter::PrintLabels(ZonePtrList<const AstRawString>* labels) { 594 if (labels != nullptr) { 595 for (int i = 0; i < labels->length(); i++) { 596 PrintLiteral(labels->at(i), false); 597 Print(": "); 598 } 599 } 600 } 601 602 void AstPrinter::PrintLiteral(Literal* literal, bool quote) { 603 switch (literal->type()) { 604 case Literal::kString: 605 PrintLiteral(literal->AsRawString(), quote); 606 break; 607 case Literal::kSymbol: 608 const char* symbol; 609 switch (literal->AsSymbol()) { 610 case AstSymbol::kHomeObjectSymbol: 611 symbol = "HomeObjectSymbol"; 612 } 613 Print("%s", symbol); 614 break; 615 case Literal::kSmi: 616 Print("%d", Smi::ToInt(literal->AsSmiLiteral())); 617 break; 618 case Literal::kHeapNumber: 619 Print("%g", literal->AsNumber()); 620 break; 621 case Literal::kBigInt: 622 Print("%sn", literal->AsBigInt().c_str()); 623 break; 624 case Literal::kNull: 625 Print("null"); 626 break; 627 case Literal::kUndefined: 628 Print("undefined"); 629 break; 630 case Literal::kTheHole: 631 Print("the hole"); 632 break; 633 case Literal::kBoolean: 634 if (literal->ToBooleanIsTrue()) { 635 Print("true"); 636 } else { 637 Print("false"); 638 } 639 break; 640 } 641 } 642 643 void AstPrinter::PrintLiteral(const AstRawString* value, bool quote) { 644 if (quote) Print("\""); 645 if (value != nullptr) { 646 const char* format = value->is_one_byte() ? "%c" : "%lc"; 647 const int increment = value->is_one_byte() ? 1 : 2; 648 const unsigned char* raw_bytes = value->raw_data(); 649 for (int i = 0; i < value->length(); i += increment) { 650 Print(format, raw_bytes[i]); 651 } 652 } 653 if (quote) Print("\""); 654 } 655 656 void AstPrinter::PrintLiteral(const AstConsString* value, bool quote) { 657 if (quote) Print("\""); 658 if (value != nullptr) { 659 std::forward_list<const AstRawString*> strings = value->ToRawStrings(); 660 for (const AstRawString* string : strings) { 661 PrintLiteral(string, false); 662 } 663 } 664 if (quote) Print("\""); 665 } 666 667 //----------------------------------------------------------------------------- 668 669 class IndentedScope BASE_EMBEDDED { 670 public: 671 IndentedScope(AstPrinter* printer, const char* txt) 672 : ast_printer_(printer) { 673 ast_printer_->PrintIndented(txt); 674 ast_printer_->Print("\n"); 675 ast_printer_->inc_indent(); 676 } 677 678 IndentedScope(AstPrinter* printer, const char* txt, int pos) 679 : ast_printer_(printer) { 680 ast_printer_->PrintIndented(txt); 681 ast_printer_->Print(" at %d\n", pos); 682 ast_printer_->inc_indent(); 683 } 684 685 virtual ~IndentedScope() { 686 ast_printer_->dec_indent(); 687 } 688 689 private: 690 AstPrinter* ast_printer_; 691 }; 692 693 694 //----------------------------------------------------------------------------- 695 696 AstPrinter::AstPrinter(uintptr_t stack_limit) 697 : output_(nullptr), size_(0), pos_(0), indent_(0) { 698 InitializeAstVisitor(stack_limit); 699 } 700 701 AstPrinter::~AstPrinter() { 702 DCHECK_EQ(indent_, 0); 703 DeleteArray(output_); 704 } 705 706 707 void AstPrinter::PrintIndented(const char* txt) { 708 for (int i = 0; i < indent_; i++) { 709 Print(". "); 710 } 711 Print("%s", txt); 712 } 713 714 void AstPrinter::PrintLiteralIndented(const char* info, Literal* literal, 715 bool quote) { 716 PrintIndented(info); 717 Print(" "); 718 PrintLiteral(literal, quote); 719 Print("\n"); 720 } 721 722 void AstPrinter::PrintLiteralIndented(const char* info, 723 const AstRawString* value, bool quote) { 724 PrintIndented(info); 725 Print(" "); 726 PrintLiteral(value, quote); 727 Print("\n"); 728 } 729 730 void AstPrinter::PrintLiteralIndented(const char* info, 731 const AstConsString* value, bool quote) { 732 PrintIndented(info); 733 Print(" "); 734 PrintLiteral(value, quote); 735 Print("\n"); 736 } 737 738 void AstPrinter::PrintLiteralWithModeIndented(const char* info, Variable* var, 739 const AstRawString* value) { 740 if (var == nullptr) { 741 PrintLiteralIndented(info, value, true); 742 } else { 743 EmbeddedVector<char, 256> buf; 744 int pos = 745 SNPrintF(buf, "%s (%p) (mode = %s", info, reinterpret_cast<void*>(var), 746 VariableMode2String(var->mode())); 747 SNPrintF(buf + pos, ")"); 748 PrintLiteralIndented(buf.start(), value, true); 749 } 750 } 751 752 void AstPrinter::PrintLabelsIndented(ZonePtrList<const AstRawString>* labels, 753 const char* prefix) { 754 if (labels == nullptr || labels->length() == 0) return; 755 PrintIndented(prefix); 756 Print("LABELS "); 757 PrintLabels(labels); 758 Print("\n"); 759 } 760 761 762 void AstPrinter::PrintIndentedVisit(const char* s, AstNode* node) { 763 if (node != nullptr) { 764 IndentedScope indent(this, s, node->position()); 765 Visit(node); 766 } 767 } 768 769 770 const char* AstPrinter::PrintProgram(FunctionLiteral* program) { 771 Init(); 772 { IndentedScope indent(this, "FUNC", program->position()); 773 PrintIndented("KIND"); 774 Print(" %d\n", program->kind()); 775 PrintIndented("SUSPEND COUNT"); 776 Print(" %d\n", program->suspend_count()); 777 PrintLiteralIndented("NAME", program->raw_name(), true); 778 if (program->raw_inferred_name()) { 779 PrintLiteralIndented("INFERRED NAME", program->raw_inferred_name(), true); 780 } 781 if (program->requires_instance_fields_initializer()) { 782 Print(" REQUIRES INSTANCE FIELDS INITIALIZER\n"); 783 } 784 PrintParameters(program->scope()); 785 PrintDeclarations(program->scope()->declarations()); 786 PrintStatements(program->body()); 787 } 788 return output_; 789 } 790 791 792 void AstPrinter::PrintOut(Isolate* isolate, AstNode* node) { 793 AstPrinter printer(isolate->stack_guard()->real_climit()); 794 printer.Init(); 795 printer.Visit(node); 796 PrintF("%s", printer.output_); 797 } 798 799 void AstPrinter::PrintDeclarations(Declaration::List* declarations) { 800 if (!declarations->is_empty()) { 801 IndentedScope indent(this, "DECLS"); 802 for (Declaration* decl : *declarations) Visit(decl); 803 } 804 } 805 806 void AstPrinter::PrintParameters(DeclarationScope* scope) { 807 if (scope->num_parameters() > 0) { 808 IndentedScope indent(this, "PARAMS"); 809 for (int i = 0; i < scope->num_parameters(); i++) { 810 PrintLiteralWithModeIndented("VAR", scope->parameter(i), 811 scope->parameter(i)->raw_name()); 812 } 813 } 814 } 815 816 void AstPrinter::PrintStatements(ZonePtrList<Statement>* statements) { 817 for (int i = 0; i < statements->length(); i++) { 818 Visit(statements->at(i)); 819 } 820 } 821 822 void AstPrinter::PrintArguments(ZonePtrList<Expression>* arguments) { 823 for (int i = 0; i < arguments->length(); i++) { 824 Visit(arguments->at(i)); 825 } 826 } 827 828 829 void AstPrinter::VisitBlock(Block* node) { 830 const char* block_txt = 831 node->ignore_completion_value() ? "BLOCK NOCOMPLETIONS" : "BLOCK"; 832 IndentedScope indent(this, block_txt, node->position()); 833 PrintLabelsIndented(node->labels()); 834 PrintStatements(node->statements()); 835 } 836 837 838 // TODO(svenpanne) Start with IndentedScope. 839 void AstPrinter::VisitVariableDeclaration(VariableDeclaration* node) { 840 PrintLiteralWithModeIndented("VARIABLE", node->proxy()->var(), 841 node->proxy()->raw_name()); 842 } 843 844 845 // TODO(svenpanne) Start with IndentedScope. 846 void AstPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) { 847 PrintIndented("FUNCTION "); 848 PrintLiteral(node->proxy()->raw_name(), true); 849 Print(" = function "); 850 PrintLiteral(node->fun()->raw_name(), false); 851 Print("\n"); 852 } 853 854 855 void AstPrinter::VisitExpressionStatement(ExpressionStatement* node) { 856 IndentedScope indent(this, "EXPRESSION STATEMENT", node->position()); 857 Visit(node->expression()); 858 } 859 860 861 void AstPrinter::VisitEmptyStatement(EmptyStatement* node) { 862 IndentedScope indent(this, "EMPTY", node->position()); 863 } 864 865 866 void AstPrinter::VisitSloppyBlockFunctionStatement( 867 SloppyBlockFunctionStatement* node) { 868 Visit(node->statement()); 869 } 870 871 872 void AstPrinter::VisitIfStatement(IfStatement* node) { 873 IndentedScope indent(this, "IF", node->position()); 874 PrintIndentedVisit("CONDITION", node->condition()); 875 PrintIndentedVisit("THEN", node->then_statement()); 876 if (node->HasElseStatement()) { 877 PrintIndentedVisit("ELSE", node->else_statement()); 878 } 879 } 880 881 882 void AstPrinter::VisitContinueStatement(ContinueStatement* node) { 883 IndentedScope indent(this, "CONTINUE", node->position()); 884 PrintLabelsIndented(node->target()->labels()); 885 } 886 887 888 void AstPrinter::VisitBreakStatement(BreakStatement* node) { 889 IndentedScope indent(this, "BREAK", node->position()); 890 PrintLabelsIndented(node->target()->labels()); 891 } 892 893 894 void AstPrinter::VisitReturnStatement(ReturnStatement* node) { 895 IndentedScope indent(this, "RETURN", node->position()); 896 Visit(node->expression()); 897 } 898 899 900 void AstPrinter::VisitWithStatement(WithStatement* node) { 901 IndentedScope indent(this, "WITH", node->position()); 902 PrintIndentedVisit("OBJECT", node->expression()); 903 PrintIndentedVisit("BODY", node->statement()); 904 } 905 906 907 void AstPrinter::VisitSwitchStatement(SwitchStatement* node) { 908 IndentedScope indent(this, "SWITCH", node->position()); 909 PrintLabelsIndented(node->labels()); 910 PrintIndentedVisit("TAG", node->tag()); 911 for (CaseClause* clause : *node->cases()) { 912 if (clause->is_default()) { 913 IndentedScope indent(this, "DEFAULT"); 914 PrintStatements(clause->statements()); 915 } else { 916 IndentedScope indent(this, "CASE"); 917 Visit(clause->label()); 918 PrintStatements(clause->statements()); 919 } 920 } 921 } 922 923 924 void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) { 925 IndentedScope indent(this, "DO", node->position()); 926 PrintLabelsIndented(node->labels()); 927 PrintLabelsIndented(node->own_labels(), "OWN "); 928 PrintIndentedVisit("BODY", node->body()); 929 PrintIndentedVisit("COND", node->cond()); 930 } 931 932 933 void AstPrinter::VisitWhileStatement(WhileStatement* node) { 934 IndentedScope indent(this, "WHILE", node->position()); 935 PrintLabelsIndented(node->labels()); 936 PrintLabelsIndented(node->own_labels(), "OWN "); 937 PrintIndentedVisit("COND", node->cond()); 938 PrintIndentedVisit("BODY", node->body()); 939 } 940 941 942 void AstPrinter::VisitForStatement(ForStatement* node) { 943 IndentedScope indent(this, "FOR", node->position()); 944 PrintLabelsIndented(node->labels()); 945 PrintLabelsIndented(node->own_labels(), "OWN "); 946 if (node->init()) PrintIndentedVisit("INIT", node->init()); 947 if (node->cond()) PrintIndentedVisit("COND", node->cond()); 948 PrintIndentedVisit("BODY", node->body()); 949 if (node->next()) PrintIndentedVisit("NEXT", node->next()); 950 } 951 952 953 void AstPrinter::VisitForInStatement(ForInStatement* node) { 954 IndentedScope indent(this, "FOR IN", node->position()); 955 PrintLabelsIndented(node->labels()); 956 PrintLabelsIndented(node->own_labels(), "OWN "); 957 PrintIndentedVisit("FOR", node->each()); 958 PrintIndentedVisit("IN", node->enumerable()); 959 PrintIndentedVisit("BODY", node->body()); 960 } 961 962 963 void AstPrinter::VisitForOfStatement(ForOfStatement* node) { 964 IndentedScope indent(this, "FOR OF", node->position()); 965 PrintLabelsIndented(node->labels()); 966 PrintLabelsIndented(node->own_labels(), "OWN "); 967 PrintIndentedVisit("INIT", node->assign_iterator()); 968 PrintIndentedVisit("NEXT", node->next_result()); 969 PrintIndentedVisit("DONE", node->result_done()); 970 PrintIndentedVisit("EACH", node->assign_each()); 971 PrintIndentedVisit("BODY", node->body()); 972 } 973 974 975 void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) { 976 IndentedScope indent(this, "TRY CATCH", node->position()); 977 PrintIndentedVisit("TRY", node->try_block()); 978 PrintIndented("CATCH PREDICTION"); 979 const char* prediction = ""; 980 switch (node->GetCatchPrediction(HandlerTable::UNCAUGHT)) { 981 case HandlerTable::UNCAUGHT: 982 prediction = "UNCAUGHT"; 983 break; 984 case HandlerTable::CAUGHT: 985 prediction = "CAUGHT"; 986 break; 987 case HandlerTable::DESUGARING: 988 prediction = "DESUGARING"; 989 break; 990 case HandlerTable::ASYNC_AWAIT: 991 prediction = "ASYNC_AWAIT"; 992 break; 993 case HandlerTable::PROMISE: 994 // Catch prediction resulting in promise rejections aren't 995 // parsed by the parser. 996 UNREACHABLE(); 997 } 998 Print(" %s\n", prediction); 999 if (node->scope()) { 1000 PrintLiteralWithModeIndented("CATCHVAR", node->scope()->catch_variable(), 1001 node->scope()->catch_variable()->raw_name()); 1002 } 1003 PrintIndentedVisit("CATCH", node->catch_block()); 1004 } 1005 1006 void AstPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) { 1007 IndentedScope indent(this, "TRY FINALLY", node->position()); 1008 PrintIndentedVisit("TRY", node->try_block()); 1009 PrintIndentedVisit("FINALLY", node->finally_block()); 1010 } 1011 1012 void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) { 1013 IndentedScope indent(this, "DEBUGGER", node->position()); 1014 } 1015 1016 1017 void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) { 1018 IndentedScope indent(this, "FUNC LITERAL", node->position()); 1019 PrintLiteralIndented("NAME", node->raw_name(), false); 1020 PrintLiteralIndented("INFERRED NAME", node->raw_inferred_name(), false); 1021 PrintParameters(node->scope()); 1022 // We don't want to see the function literal in this case: it 1023 // will be printed via PrintProgram when the code for it is 1024 // generated. 1025 // PrintStatements(node->body()); 1026 } 1027 1028 1029 void AstPrinter::VisitClassLiteral(ClassLiteral* node) { 1030 IndentedScope indent(this, "CLASS LITERAL", node->position()); 1031 PrintLiteralIndented("NAME", node->constructor()->raw_name(), false); 1032 if (node->extends() != nullptr) { 1033 PrintIndentedVisit("EXTENDS", node->extends()); 1034 } 1035 if (node->static_fields_initializer() != nullptr) { 1036 PrintIndentedVisit("STATIC FIELDS INITIALIZER", 1037 node->static_fields_initializer()); 1038 } 1039 if (node->instance_fields_initializer_function() != nullptr) { 1040 PrintIndentedVisit("INSTANCE FIELDS INITIALIZER", 1041 node->instance_fields_initializer_function()); 1042 } 1043 PrintClassProperties(node->properties()); 1044 } 1045 1046 void AstPrinter::VisitInitializeClassFieldsStatement( 1047 InitializeClassFieldsStatement* node) { 1048 IndentedScope indent(this, "INITIALIZE CLASS FIELDS", node->position()); 1049 PrintClassProperties(node->fields()); 1050 } 1051 1052 void AstPrinter::PrintClassProperties( 1053 ZonePtrList<ClassLiteral::Property>* properties) { 1054 for (int i = 0; i < properties->length(); i++) { 1055 ClassLiteral::Property* property = properties->at(i); 1056 const char* prop_kind = nullptr; 1057 switch (property->kind()) { 1058 case ClassLiteral::Property::METHOD: 1059 prop_kind = "METHOD"; 1060 break; 1061 case ClassLiteral::Property::GETTER: 1062 prop_kind = "GETTER"; 1063 break; 1064 case ClassLiteral::Property::SETTER: 1065 prop_kind = "SETTER"; 1066 break; 1067 case ClassLiteral::Property::PUBLIC_FIELD: 1068 prop_kind = "PUBLIC FIELD"; 1069 break; 1070 case ClassLiteral::Property::PRIVATE_FIELD: 1071 prop_kind = "PRIVATE FIELD"; 1072 break; 1073 } 1074 EmbeddedVector<char, 128> buf; 1075 SNPrintF(buf, "PROPERTY%s - %s", property->is_static() ? " - STATIC" : "", 1076 prop_kind); 1077 IndentedScope prop(this, buf.start()); 1078 PrintIndentedVisit("KEY", properties->at(i)->key()); 1079 PrintIndentedVisit("VALUE", properties->at(i)->value()); 1080 } 1081 } 1082 1083 1084 void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) { 1085 IndentedScope indent(this, "NATIVE FUNC LITERAL", node->position()); 1086 PrintLiteralIndented("NAME", node->raw_name(), false); 1087 } 1088 1089 1090 void AstPrinter::VisitDoExpression(DoExpression* node) { 1091 IndentedScope indent(this, "DO EXPRESSION", node->position()); 1092 PrintStatements(node->block()->statements()); 1093 } 1094 1095 1096 void AstPrinter::VisitConditional(Conditional* node) { 1097 IndentedScope indent(this, "CONDITIONAL", node->position()); 1098 PrintIndentedVisit("CONDITION", node->condition()); 1099 PrintIndentedVisit("THEN", node->then_expression()); 1100 PrintIndentedVisit("ELSE", node->else_expression()); 1101 } 1102 1103 1104 void AstPrinter::VisitLiteral(Literal* node) { 1105 PrintLiteralIndented("LITERAL", node, true); 1106 } 1107 1108 1109 void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) { 1110 IndentedScope indent(this, "REGEXP LITERAL", node->position()); 1111 PrintLiteralIndented("PATTERN", node->raw_pattern(), false); 1112 int i = 0; 1113 EmbeddedVector<char, 128> buf; 1114 if (node->flags() & RegExp::kGlobal) buf[i++] = 'g'; 1115 if (node->flags() & RegExp::kIgnoreCase) buf[i++] = 'i'; 1116 if (node->flags() & RegExp::kMultiline) buf[i++] = 'm'; 1117 if (node->flags() & RegExp::kUnicode) buf[i++] = 'u'; 1118 if (node->flags() & RegExp::kSticky) buf[i++] = 'y'; 1119 buf[i] = '\0'; 1120 PrintIndented("FLAGS "); 1121 Print("%s", buf.start()); 1122 Print("\n"); 1123 } 1124 1125 1126 void AstPrinter::VisitObjectLiteral(ObjectLiteral* node) { 1127 IndentedScope indent(this, "OBJ LITERAL", node->position()); 1128 PrintObjectProperties(node->properties()); 1129 } 1130 1131 void AstPrinter::PrintObjectProperties( 1132 ZonePtrList<ObjectLiteral::Property>* properties) { 1133 for (int i = 0; i < properties->length(); i++) { 1134 ObjectLiteral::Property* property = properties->at(i); 1135 const char* prop_kind = nullptr; 1136 switch (property->kind()) { 1137 case ObjectLiteral::Property::CONSTANT: 1138 prop_kind = "CONSTANT"; 1139 break; 1140 case ObjectLiteral::Property::COMPUTED: 1141 prop_kind = "COMPUTED"; 1142 break; 1143 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 1144 prop_kind = "MATERIALIZED_LITERAL"; 1145 break; 1146 case ObjectLiteral::Property::PROTOTYPE: 1147 prop_kind = "PROTOTYPE"; 1148 break; 1149 case ObjectLiteral::Property::GETTER: 1150 prop_kind = "GETTER"; 1151 break; 1152 case ObjectLiteral::Property::SETTER: 1153 prop_kind = "SETTER"; 1154 break; 1155 case ObjectLiteral::Property::SPREAD: 1156 prop_kind = "SPREAD"; 1157 break; 1158 } 1159 EmbeddedVector<char, 128> buf; 1160 SNPrintF(buf, "PROPERTY - %s", prop_kind); 1161 IndentedScope prop(this, buf.start()); 1162 PrintIndentedVisit("KEY", properties->at(i)->key()); 1163 PrintIndentedVisit("VALUE", properties->at(i)->value()); 1164 } 1165 } 1166 1167 1168 void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) { 1169 IndentedScope indent(this, "ARRAY LITERAL", node->position()); 1170 if (node->values()->length() > 0) { 1171 IndentedScope indent(this, "VALUES", node->position()); 1172 for (int i = 0; i < node->values()->length(); i++) { 1173 Visit(node->values()->at(i)); 1174 } 1175 } 1176 } 1177 1178 1179 void AstPrinter::VisitVariableProxy(VariableProxy* node) { 1180 EmbeddedVector<char, 128> buf; 1181 int pos = SNPrintF(buf, "VAR PROXY"); 1182 1183 if (!node->is_resolved()) { 1184 SNPrintF(buf + pos, " unresolved"); 1185 PrintLiteralWithModeIndented(buf.start(), nullptr, node->raw_name()); 1186 } else { 1187 Variable* var = node->var(); 1188 switch (var->location()) { 1189 case VariableLocation::UNALLOCATED: 1190 SNPrintF(buf + pos, " unallocated"); 1191 break; 1192 case VariableLocation::PARAMETER: 1193 SNPrintF(buf + pos, " parameter[%d]", var->index()); 1194 break; 1195 case VariableLocation::LOCAL: 1196 SNPrintF(buf + pos, " local[%d]", var->index()); 1197 break; 1198 case VariableLocation::CONTEXT: 1199 SNPrintF(buf + pos, " context[%d]", var->index()); 1200 break; 1201 case VariableLocation::LOOKUP: 1202 SNPrintF(buf + pos, " lookup"); 1203 break; 1204 case VariableLocation::MODULE: 1205 SNPrintF(buf + pos, " module"); 1206 break; 1207 } 1208 PrintLiteralWithModeIndented(buf.start(), var, node->raw_name()); 1209 } 1210 } 1211 1212 1213 void AstPrinter::VisitAssignment(Assignment* node) { 1214 IndentedScope indent(this, Token::Name(node->op()), node->position()); 1215 Visit(node->target()); 1216 Visit(node->value()); 1217 } 1218 1219 void AstPrinter::VisitCompoundAssignment(CompoundAssignment* node) { 1220 VisitAssignment(node); 1221 } 1222 1223 void AstPrinter::VisitYield(Yield* node) { 1224 EmbeddedVector<char, 128> buf; 1225 SNPrintF(buf, "YIELD"); 1226 IndentedScope indent(this, buf.start(), node->position()); 1227 Visit(node->expression()); 1228 } 1229 1230 void AstPrinter::VisitYieldStar(YieldStar* node) { 1231 EmbeddedVector<char, 128> buf; 1232 SNPrintF(buf, "YIELD_STAR"); 1233 IndentedScope indent(this, buf.start(), node->position()); 1234 Visit(node->expression()); 1235 } 1236 1237 void AstPrinter::VisitAwait(Await* node) { 1238 EmbeddedVector<char, 128> buf; 1239 SNPrintF(buf, "AWAIT"); 1240 IndentedScope indent(this, buf.start(), node->position()); 1241 Visit(node->expression()); 1242 } 1243 1244 void AstPrinter::VisitThrow(Throw* node) { 1245 IndentedScope indent(this, "THROW", node->position()); 1246 Visit(node->exception()); 1247 } 1248 1249 void AstPrinter::VisitProperty(Property* node) { 1250 EmbeddedVector<char, 128> buf; 1251 SNPrintF(buf, "PROPERTY"); 1252 IndentedScope indent(this, buf.start(), node->position()); 1253 1254 Visit(node->obj()); 1255 LhsKind property_kind = Property::GetAssignType(node); 1256 if (property_kind == NAMED_PROPERTY || 1257 property_kind == NAMED_SUPER_PROPERTY) { 1258 PrintLiteralIndented("NAME", node->key()->AsLiteral(), false); 1259 } else { 1260 DCHECK(property_kind == KEYED_PROPERTY || 1261 property_kind == KEYED_SUPER_PROPERTY); 1262 PrintIndentedVisit("KEY", node->key()); 1263 } 1264 } 1265 1266 void AstPrinter::VisitResolvedProperty(ResolvedProperty* node) { 1267 EmbeddedVector<char, 128> buf; 1268 SNPrintF(buf, "RESOLVED-PROPERTY"); 1269 IndentedScope indent(this, buf.start(), node->position()); 1270 1271 PrintIndentedVisit("RECEIVER", node->object()); 1272 PrintIndentedVisit("PROPERTY", node->property()); 1273 } 1274 1275 void AstPrinter::VisitCall(Call* node) { 1276 EmbeddedVector<char, 128> buf; 1277 SNPrintF(buf, "CALL"); 1278 IndentedScope indent(this, buf.start()); 1279 1280 Visit(node->expression()); 1281 PrintArguments(node->arguments()); 1282 } 1283 1284 1285 void AstPrinter::VisitCallNew(CallNew* node) { 1286 IndentedScope indent(this, "CALL NEW", node->position()); 1287 Visit(node->expression()); 1288 PrintArguments(node->arguments()); 1289 } 1290 1291 1292 void AstPrinter::VisitCallRuntime(CallRuntime* node) { 1293 EmbeddedVector<char, 128> buf; 1294 SNPrintF(buf, "CALL RUNTIME %s%s", node->debug_name(), 1295 node->is_jsruntime() ? " (JS function)" : ""); 1296 IndentedScope indent(this, buf.start(), node->position()); 1297 PrintArguments(node->arguments()); 1298 } 1299 1300 1301 void AstPrinter::VisitUnaryOperation(UnaryOperation* node) { 1302 IndentedScope indent(this, Token::Name(node->op()), node->position()); 1303 Visit(node->expression()); 1304 } 1305 1306 1307 void AstPrinter::VisitCountOperation(CountOperation* node) { 1308 EmbeddedVector<char, 128> buf; 1309 SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"), 1310 Token::Name(node->op())); 1311 IndentedScope indent(this, buf.start(), node->position()); 1312 Visit(node->expression()); 1313 } 1314 1315 1316 void AstPrinter::VisitBinaryOperation(BinaryOperation* node) { 1317 IndentedScope indent(this, Token::Name(node->op()), node->position()); 1318 Visit(node->left()); 1319 Visit(node->right()); 1320 } 1321 1322 void AstPrinter::VisitNaryOperation(NaryOperation* node) { 1323 IndentedScope indent(this, Token::Name(node->op()), node->position()); 1324 Visit(node->first()); 1325 for (size_t i = 0; i < node->subsequent_length(); ++i) { 1326 Visit(node->subsequent(i)); 1327 } 1328 } 1329 1330 void AstPrinter::VisitCompareOperation(CompareOperation* node) { 1331 IndentedScope indent(this, Token::Name(node->op()), node->position()); 1332 Visit(node->left()); 1333 Visit(node->right()); 1334 } 1335 1336 1337 void AstPrinter::VisitSpread(Spread* node) { 1338 IndentedScope indent(this, "SPREAD", node->position()); 1339 Visit(node->expression()); 1340 } 1341 1342 void AstPrinter::VisitStoreInArrayLiteral(StoreInArrayLiteral* node) { 1343 IndentedScope indent(this, "STORE IN ARRAY LITERAL", node->position()); 1344 PrintIndentedVisit("ARRAY", node->array()); 1345 PrintIndentedVisit("INDEX", node->index()); 1346 PrintIndentedVisit("VALUE", node->value()); 1347 } 1348 1349 void AstPrinter::VisitEmptyParentheses(EmptyParentheses* node) { 1350 IndentedScope indent(this, "()", node->position()); 1351 } 1352 1353 void AstPrinter::VisitGetIterator(GetIterator* node) { 1354 IndentedScope indent(this, "GET-ITERATOR", node->position()); 1355 Visit(node->iterable()); 1356 } 1357 1358 void AstPrinter::VisitGetTemplateObject(GetTemplateObject* node) { 1359 IndentedScope indent(this, "GET-TEMPLATE-OBJECT", node->position()); 1360 } 1361 1362 void AstPrinter::VisitTemplateLiteral(TemplateLiteral* node) { 1363 IndentedScope indent(this, "TEMPLATE-LITERAL", node->position()); 1364 const AstRawString* string = node->string_parts()->first(); 1365 if (!string->IsEmpty()) PrintLiteralIndented("SPAN", string, true); 1366 for (int i = 0; i < node->substitutions()->length();) { 1367 PrintIndentedVisit("EXPR", node->substitutions()->at(i++)); 1368 if (i < node->string_parts()->length()) { 1369 string = node->string_parts()->at(i); 1370 if (!string->IsEmpty()) PrintLiteralIndented("SPAN", string, true); 1371 } 1372 } 1373 } 1374 1375 void AstPrinter::VisitImportCallExpression(ImportCallExpression* node) { 1376 IndentedScope indent(this, "IMPORT-CALL", node->position()); 1377 Visit(node->argument()); 1378 } 1379 1380 void AstPrinter::VisitThisFunction(ThisFunction* node) { 1381 IndentedScope indent(this, "THIS-FUNCTION", node->position()); 1382 } 1383 1384 1385 void AstPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) { 1386 IndentedScope indent(this, "SUPER-PROPERTY-REFERENCE", node->position()); 1387 } 1388 1389 1390 void AstPrinter::VisitSuperCallReference(SuperCallReference* node) { 1391 IndentedScope indent(this, "SUPER-CALL-REFERENCE", node->position()); 1392 } 1393 1394 1395 void AstPrinter::VisitRewritableExpression(RewritableExpression* node) { 1396 Visit(node->expression()); 1397 } 1398 1399 1400 #endif // DEBUG 1401 1402 } // namespace internal 1403 } // namespace v8 1404