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