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
CallPrinter(Isolate * isolate,bool is_user_js)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
~CallPrinter()34 CallPrinter::~CallPrinter() {}
35
GetErrorHint() const36 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
Print(FunctionLiteral * program,int position)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
Find(AstNode * node,bool print)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
Print(const char * str)68 void CallPrinter::Print(const char* str) {
69 if (!found_ || done_) return;
70 num_prints_++;
71 builder_->AppendCString(str);
72 }
73
Print(Handle<String> str)74 void CallPrinter::Print(Handle<String> str) {
75 if (!found_ || done_) return;
76 num_prints_++;
77 builder_->AppendString(str);
78 }
79
VisitBlock(Block * node)80 void CallPrinter::VisitBlock(Block* node) {
81 FindStatements(node->statements());
82 }
83
84
VisitVariableDeclaration(VariableDeclaration * node)85 void CallPrinter::VisitVariableDeclaration(VariableDeclaration* node) {}
86
87
VisitFunctionDeclaration(FunctionDeclaration * node)88 void CallPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) {}
89
90
VisitExpressionStatement(ExpressionStatement * node)91 void CallPrinter::VisitExpressionStatement(ExpressionStatement* node) {
92 Find(node->expression());
93 }
94
95
VisitEmptyStatement(EmptyStatement * node)96 void CallPrinter::VisitEmptyStatement(EmptyStatement* node) {}
97
98
VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement * node)99 void CallPrinter::VisitSloppyBlockFunctionStatement(
100 SloppyBlockFunctionStatement* node) {
101 Find(node->statement());
102 }
103
104
VisitIfStatement(IfStatement * node)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
VisitContinueStatement(ContinueStatement * node)114 void CallPrinter::VisitContinueStatement(ContinueStatement* node) {}
115
116
VisitBreakStatement(BreakStatement * node)117 void CallPrinter::VisitBreakStatement(BreakStatement* node) {}
118
119
VisitReturnStatement(ReturnStatement * node)120 void CallPrinter::VisitReturnStatement(ReturnStatement* node) {
121 Find(node->expression());
122 }
123
124
VisitWithStatement(WithStatement * node)125 void CallPrinter::VisitWithStatement(WithStatement* node) {
126 Find(node->expression());
127 Find(node->statement());
128 }
129
130
VisitSwitchStatement(SwitchStatement * node)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
VisitDoWhileStatement(DoWhileStatement * node)140 void CallPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
141 Find(node->body());
142 Find(node->cond());
143 }
144
145
VisitWhileStatement(WhileStatement * node)146 void CallPrinter::VisitWhileStatement(WhileStatement* node) {
147 Find(node->cond());
148 Find(node->body());
149 }
150
151
VisitForStatement(ForStatement * node)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
VisitForInStatement(ForInStatement * node)162 void CallPrinter::VisitForInStatement(ForInStatement* node) {
163 Find(node->each());
164 Find(node->enumerable());
165 Find(node->body());
166 }
167
168
VisitForOfStatement(ForOfStatement * node)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
VisitTryCatchStatement(TryCatchStatement * node)178 void CallPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
179 Find(node->try_block());
180 Find(node->catch_block());
181 }
182
183
VisitTryFinallyStatement(TryFinallyStatement * node)184 void CallPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) {
185 Find(node->try_block());
186 Find(node->finally_block());
187 }
188
189
VisitDebuggerStatement(DebuggerStatement * node)190 void CallPrinter::VisitDebuggerStatement(DebuggerStatement* node) {}
191
192
VisitFunctionLiteral(FunctionLiteral * node)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
VisitClassLiteral(ClassLiteral * node)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
VisitInitializeClassFieldsStatement(InitializeClassFieldsStatement * node)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
VisitNativeFunctionLiteral(NativeFunctionLiteral * node)215 void CallPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {}
216
217
VisitDoExpression(DoExpression * node)218 void CallPrinter::VisitDoExpression(DoExpression* node) { Find(node->block()); }
219
220
VisitConditional(Conditional * node)221 void CallPrinter::VisitConditional(Conditional* node) {
222 Find(node->condition());
223 Find(node->then_expression());
224 Find(node->else_expression());
225 }
226
227
VisitLiteral(Literal * node)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
VisitRegExpLiteral(RegExpLiteral * node)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
VisitObjectLiteral(ObjectLiteral * node)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
VisitArrayLiteral(ArrayLiteral * node)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
VisitVariableProxy(VariableProxy * node)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
VisitAssignment(Assignment * node)286 void CallPrinter::VisitAssignment(Assignment* node) {
287 Find(node->target());
288 Find(node->value());
289 }
290
VisitCompoundAssignment(CompoundAssignment * node)291 void CallPrinter::VisitCompoundAssignment(CompoundAssignment* node) {
292 VisitAssignment(node);
293 }
294
VisitYield(Yield * node)295 void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); }
296
VisitYieldStar(YieldStar * node)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
VisitAwait(Await * node)309 void CallPrinter::VisitAwait(Await* node) { Find(node->expression()); }
310
VisitThrow(Throw * node)311 void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); }
312
313
VisitProperty(Property * node)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
VisitResolvedProperty(ResolvedProperty * node)332 void CallPrinter::VisitResolvedProperty(ResolvedProperty* node) {}
333
VisitCall(Call * node)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
VisitCallNew(CallNew * node)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
VisitCallRuntime(CallRuntime * node)383 void CallPrinter::VisitCallRuntime(CallRuntime* node) {
384 FindArguments(node->arguments());
385 }
386
387
VisitUnaryOperation(UnaryOperation * node)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
VisitCountOperation(CountOperation * node)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
VisitBinaryOperation(BinaryOperation * node)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
VisitNaryOperation(NaryOperation * node)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
VisitCompareOperation(CompareOperation * node)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
VisitSpread(Spread * node)442 void CallPrinter::VisitSpread(Spread* node) {
443 Print("(...");
444 Find(node->expression(), true);
445 Print(")");
446 }
447
VisitStoreInArrayLiteral(StoreInArrayLiteral * node)448 void CallPrinter::VisitStoreInArrayLiteral(StoreInArrayLiteral* node) {
449 Find(node->array());
450 Find(node->index());
451 Find(node->value());
452 }
453
VisitEmptyParentheses(EmptyParentheses * node)454 void CallPrinter::VisitEmptyParentheses(EmptyParentheses* node) {
455 UNREACHABLE();
456 }
457
VisitGetIterator(GetIterator * node)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
VisitGetTemplateObject(GetTemplateObject * node)475 void CallPrinter::VisitGetTemplateObject(GetTemplateObject* node) {}
476
VisitTemplateLiteral(TemplateLiteral * node)477 void CallPrinter::VisitTemplateLiteral(TemplateLiteral* node) {
478 for (Expression* substitution : *node->substitutions()) {
479 Find(substitution, true);
480 }
481 }
482
VisitImportCallExpression(ImportCallExpression * node)483 void CallPrinter::VisitImportCallExpression(ImportCallExpression* node) {
484 Print("ImportCall(");
485 Find(node->argument(), true);
486 Print(")");
487 }
488
VisitThisFunction(ThisFunction * node)489 void CallPrinter::VisitThisFunction(ThisFunction* node) {}
490
491
VisitSuperPropertyReference(SuperPropertyReference * node)492 void CallPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {}
493
494
VisitSuperCallReference(SuperCallReference * node)495 void CallPrinter::VisitSuperCallReference(SuperCallReference* node) {
496 Print("super");
497 }
498
499
VisitRewritableExpression(RewritableExpression * node)500 void CallPrinter::VisitRewritableExpression(RewritableExpression* node) {
501 Find(node->expression());
502 }
503
FindStatements(ZonePtrList<Statement> * statements)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
FindArguments(ZonePtrList<Expression> * arguments)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
PrintLiteral(Handle<Object> value,bool quote)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
PrintLiteral(const AstRawString * value,bool quote)540 void CallPrinter::PrintLiteral(const AstRawString* value, bool quote) {
541 PrintLiteral(value->string(), quote);
542 }
543
544
545 //-----------------------------------------------------------------------------
546
547
548 #ifdef DEBUG
549
Print(AstNode * node)550 const char* AstPrinter::Print(AstNode* node) {
551 Init();
552 Visit(node);
553 return output_;
554 }
555
Init()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
Print(const char * format,...)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
PrintLabels(ZonePtrList<const AstRawString> * labels)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
PrintLiteral(Literal * literal,bool quote)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
PrintLiteral(const AstRawString * value,bool quote)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
PrintLiteral(const AstConsString * value,bool quote)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:
IndentedScope(AstPrinter * printer,const char * txt)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
IndentedScope(AstPrinter * printer,const char * txt,int pos)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
~IndentedScope()685 virtual ~IndentedScope() {
686 ast_printer_->dec_indent();
687 }
688
689 private:
690 AstPrinter* ast_printer_;
691 };
692
693
694 //-----------------------------------------------------------------------------
695
AstPrinter(uintptr_t stack_limit)696 AstPrinter::AstPrinter(uintptr_t stack_limit)
697 : output_(nullptr), size_(0), pos_(0), indent_(0) {
698 InitializeAstVisitor(stack_limit);
699 }
700
~AstPrinter()701 AstPrinter::~AstPrinter() {
702 DCHECK_EQ(indent_, 0);
703 DeleteArray(output_);
704 }
705
706
PrintIndented(const char * txt)707 void AstPrinter::PrintIndented(const char* txt) {
708 for (int i = 0; i < indent_; i++) {
709 Print(". ");
710 }
711 Print("%s", txt);
712 }
713
PrintLiteralIndented(const char * info,Literal * literal,bool quote)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
PrintLiteralIndented(const char * info,const AstRawString * value,bool quote)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
PrintLiteralIndented(const char * info,const AstConsString * value,bool quote)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
PrintLiteralWithModeIndented(const char * info,Variable * var,const AstRawString * value)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
PrintLabelsIndented(ZonePtrList<const AstRawString> * labels,const char * prefix)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
PrintIndentedVisit(const char * s,AstNode * node)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
PrintProgram(FunctionLiteral * program)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
PrintOut(Isolate * isolate,AstNode * node)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
PrintDeclarations(Declaration::List * declarations)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
PrintParameters(DeclarationScope * scope)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
PrintStatements(ZonePtrList<Statement> * statements)816 void AstPrinter::PrintStatements(ZonePtrList<Statement>* statements) {
817 for (int i = 0; i < statements->length(); i++) {
818 Visit(statements->at(i));
819 }
820 }
821
PrintArguments(ZonePtrList<Expression> * arguments)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
VisitBlock(Block * node)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.
VisitVariableDeclaration(VariableDeclaration * node)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.
VisitFunctionDeclaration(FunctionDeclaration * node)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
VisitExpressionStatement(ExpressionStatement * node)855 void AstPrinter::VisitExpressionStatement(ExpressionStatement* node) {
856 IndentedScope indent(this, "EXPRESSION STATEMENT", node->position());
857 Visit(node->expression());
858 }
859
860
VisitEmptyStatement(EmptyStatement * node)861 void AstPrinter::VisitEmptyStatement(EmptyStatement* node) {
862 IndentedScope indent(this, "EMPTY", node->position());
863 }
864
865
VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement * node)866 void AstPrinter::VisitSloppyBlockFunctionStatement(
867 SloppyBlockFunctionStatement* node) {
868 Visit(node->statement());
869 }
870
871
VisitIfStatement(IfStatement * node)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
VisitContinueStatement(ContinueStatement * node)882 void AstPrinter::VisitContinueStatement(ContinueStatement* node) {
883 IndentedScope indent(this, "CONTINUE", node->position());
884 PrintLabelsIndented(node->target()->labels());
885 }
886
887
VisitBreakStatement(BreakStatement * node)888 void AstPrinter::VisitBreakStatement(BreakStatement* node) {
889 IndentedScope indent(this, "BREAK", node->position());
890 PrintLabelsIndented(node->target()->labels());
891 }
892
893
VisitReturnStatement(ReturnStatement * node)894 void AstPrinter::VisitReturnStatement(ReturnStatement* node) {
895 IndentedScope indent(this, "RETURN", node->position());
896 Visit(node->expression());
897 }
898
899
VisitWithStatement(WithStatement * node)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
VisitSwitchStatement(SwitchStatement * node)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
VisitDoWhileStatement(DoWhileStatement * node)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
VisitWhileStatement(WhileStatement * node)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
VisitForStatement(ForStatement * node)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
VisitForInStatement(ForInStatement * node)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
VisitForOfStatement(ForOfStatement * node)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
VisitTryCatchStatement(TryCatchStatement * node)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
VisitTryFinallyStatement(TryFinallyStatement * node)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
VisitDebuggerStatement(DebuggerStatement * node)1012 void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) {
1013 IndentedScope indent(this, "DEBUGGER", node->position());
1014 }
1015
1016
VisitFunctionLiteral(FunctionLiteral * node)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
VisitClassLiteral(ClassLiteral * node)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
VisitInitializeClassFieldsStatement(InitializeClassFieldsStatement * node)1046 void AstPrinter::VisitInitializeClassFieldsStatement(
1047 InitializeClassFieldsStatement* node) {
1048 IndentedScope indent(this, "INITIALIZE CLASS FIELDS", node->position());
1049 PrintClassProperties(node->fields());
1050 }
1051
PrintClassProperties(ZonePtrList<ClassLiteral::Property> * properties)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
VisitNativeFunctionLiteral(NativeFunctionLiteral * node)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
VisitDoExpression(DoExpression * node)1090 void AstPrinter::VisitDoExpression(DoExpression* node) {
1091 IndentedScope indent(this, "DO EXPRESSION", node->position());
1092 PrintStatements(node->block()->statements());
1093 }
1094
1095
VisitConditional(Conditional * node)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
VisitLiteral(Literal * node)1104 void AstPrinter::VisitLiteral(Literal* node) {
1105 PrintLiteralIndented("LITERAL", node, true);
1106 }
1107
1108
VisitRegExpLiteral(RegExpLiteral * node)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
VisitObjectLiteral(ObjectLiteral * node)1126 void AstPrinter::VisitObjectLiteral(ObjectLiteral* node) {
1127 IndentedScope indent(this, "OBJ LITERAL", node->position());
1128 PrintObjectProperties(node->properties());
1129 }
1130
PrintObjectProperties(ZonePtrList<ObjectLiteral::Property> * properties)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
VisitArrayLiteral(ArrayLiteral * node)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
VisitVariableProxy(VariableProxy * node)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
VisitAssignment(Assignment * node)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
VisitCompoundAssignment(CompoundAssignment * node)1219 void AstPrinter::VisitCompoundAssignment(CompoundAssignment* node) {
1220 VisitAssignment(node);
1221 }
1222
VisitYield(Yield * node)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
VisitYieldStar(YieldStar * node)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
VisitAwait(Await * node)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
VisitThrow(Throw * node)1244 void AstPrinter::VisitThrow(Throw* node) {
1245 IndentedScope indent(this, "THROW", node->position());
1246 Visit(node->exception());
1247 }
1248
VisitProperty(Property * node)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
VisitResolvedProperty(ResolvedProperty * node)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
VisitCall(Call * node)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
VisitCallNew(CallNew * node)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
VisitCallRuntime(CallRuntime * node)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
VisitUnaryOperation(UnaryOperation * node)1301 void AstPrinter::VisitUnaryOperation(UnaryOperation* node) {
1302 IndentedScope indent(this, Token::Name(node->op()), node->position());
1303 Visit(node->expression());
1304 }
1305
1306
VisitCountOperation(CountOperation * node)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
VisitBinaryOperation(BinaryOperation * node)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
VisitNaryOperation(NaryOperation * node)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
VisitCompareOperation(CompareOperation * node)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
VisitSpread(Spread * node)1337 void AstPrinter::VisitSpread(Spread* node) {
1338 IndentedScope indent(this, "SPREAD", node->position());
1339 Visit(node->expression());
1340 }
1341
VisitStoreInArrayLiteral(StoreInArrayLiteral * node)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
VisitEmptyParentheses(EmptyParentheses * node)1349 void AstPrinter::VisitEmptyParentheses(EmptyParentheses* node) {
1350 IndentedScope indent(this, "()", node->position());
1351 }
1352
VisitGetIterator(GetIterator * node)1353 void AstPrinter::VisitGetIterator(GetIterator* node) {
1354 IndentedScope indent(this, "GET-ITERATOR", node->position());
1355 Visit(node->iterable());
1356 }
1357
VisitGetTemplateObject(GetTemplateObject * node)1358 void AstPrinter::VisitGetTemplateObject(GetTemplateObject* node) {
1359 IndentedScope indent(this, "GET-TEMPLATE-OBJECT", node->position());
1360 }
1361
VisitTemplateLiteral(TemplateLiteral * node)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
VisitImportCallExpression(ImportCallExpression * node)1375 void AstPrinter::VisitImportCallExpression(ImportCallExpression* node) {
1376 IndentedScope indent(this, "IMPORT-CALL", node->position());
1377 Visit(node->argument());
1378 }
1379
VisitThisFunction(ThisFunction * node)1380 void AstPrinter::VisitThisFunction(ThisFunction* node) {
1381 IndentedScope indent(this, "THIS-FUNCTION", node->position());
1382 }
1383
1384
VisitSuperPropertyReference(SuperPropertyReference * node)1385 void AstPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {
1386 IndentedScope indent(this, "SUPER-PROPERTY-REFERENCE", node->position());
1387 }
1388
1389
VisitSuperCallReference(SuperCallReference * node)1390 void AstPrinter::VisitSuperCallReference(SuperCallReference* node) {
1391 IndentedScope indent(this, "SUPER-CALL-REFERENCE", node->position());
1392 }
1393
1394
VisitRewritableExpression(RewritableExpression * node)1395 void AstPrinter::VisitRewritableExpression(RewritableExpression* node) {
1396 Visit(node->expression());
1397 }
1398
1399
1400 #endif // DEBUG
1401
1402 } // namespace internal
1403 } // namespace v8
1404