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