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