1// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdarg.h>
29
30#include "v8.h"
31
32#include "prettyprinter.h"
33#include "scopes.h"
34#include "platform.h"
35
36namespace v8 {
37namespace internal {
38
39#ifdef DEBUG
40
41PrettyPrinter::PrettyPrinter() {
42  output_ = NULL;
43  size_ = 0;
44  pos_ = 0;
45}
46
47
48PrettyPrinter::~PrettyPrinter() {
49  DeleteArray(output_);
50}
51
52
53void PrettyPrinter::VisitBlock(Block* node) {
54  if (!node->is_initializer_block()) Print("{ ");
55  PrintStatements(node->statements());
56  if (node->statements()->length() > 0) Print(" ");
57  if (!node->is_initializer_block()) Print("}");
58}
59
60
61void PrettyPrinter::VisitDeclaration(Declaration* node) {
62  Print("var ");
63  PrintLiteral(node->proxy()->name(), false);
64  if (node->fun() != NULL) {
65    Print(" = ");
66    PrintFunctionLiteral(node->fun());
67  }
68  Print(";");
69}
70
71
72void PrettyPrinter::VisitExpressionStatement(ExpressionStatement* node) {
73  Visit(node->expression());
74  Print(";");
75}
76
77
78void PrettyPrinter::VisitEmptyStatement(EmptyStatement* node) {
79  Print(";");
80}
81
82
83void PrettyPrinter::VisitIfStatement(IfStatement* node) {
84  Print("if (");
85  Visit(node->condition());
86  Print(") ");
87  Visit(node->then_statement());
88  if (node->HasElseStatement()) {
89    Print(" else ");
90    Visit(node->else_statement());
91  }
92}
93
94
95void PrettyPrinter::VisitContinueStatement(ContinueStatement* node) {
96  Print("continue");
97  ZoneStringList* labels = node->target()->labels();
98  if (labels != NULL) {
99    Print(" ");
100    ASSERT(labels->length() > 0);  // guaranteed to have at least one entry
101    PrintLiteral(labels->at(0), false);  // any label from the list is fine
102  }
103  Print(";");
104}
105
106
107void PrettyPrinter::VisitBreakStatement(BreakStatement* node) {
108  Print("break");
109  ZoneStringList* labels = node->target()->labels();
110  if (labels != NULL) {
111    Print(" ");
112    ASSERT(labels->length() > 0);  // guaranteed to have at least one entry
113    PrintLiteral(labels->at(0), false);  // any label from the list is fine
114  }
115  Print(";");
116}
117
118
119void PrettyPrinter::VisitReturnStatement(ReturnStatement* node) {
120  Print("return ");
121  Visit(node->expression());
122  Print(";");
123}
124
125
126void PrettyPrinter::VisitWithEnterStatement(WithEnterStatement* node) {
127  Print("<enter with> (");
128  Visit(node->expression());
129  Print(") ");
130}
131
132
133void PrettyPrinter::VisitWithExitStatement(WithExitStatement* node) {
134  Print("<exit with>");
135}
136
137
138void PrettyPrinter::VisitSwitchStatement(SwitchStatement* node) {
139  PrintLabels(node->labels());
140  Print("switch (");
141  Visit(node->tag());
142  Print(") { ");
143  ZoneList<CaseClause*>* cases = node->cases();
144  for (int i = 0; i < cases->length(); i++)
145    PrintCaseClause(cases->at(i));
146  Print("}");
147}
148
149
150void PrettyPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
151  PrintLabels(node->labels());
152  Print("do ");
153  Visit(node->body());
154  Print(" while (");
155  Visit(node->cond());
156  Print(");");
157}
158
159
160void PrettyPrinter::VisitWhileStatement(WhileStatement* node) {
161  PrintLabels(node->labels());
162  Print("while (");
163  Visit(node->cond());
164  Print(") ");
165  Visit(node->body());
166}
167
168
169void PrettyPrinter::VisitForStatement(ForStatement* node) {
170  PrintLabels(node->labels());
171  Print("for (");
172  if (node->init() != NULL) {
173    Visit(node->init());
174    Print(" ");
175  } else {
176    Print("; ");
177  }
178  if (node->cond() != NULL) Visit(node->cond());
179  Print("; ");
180  if (node->next() != NULL) {
181    Visit(node->next());  // prints extra ';', unfortunately
182    // to fix: should use Expression for next
183  }
184  Print(") ");
185  Visit(node->body());
186}
187
188
189void PrettyPrinter::VisitForInStatement(ForInStatement* node) {
190  PrintLabels(node->labels());
191  Print("for (");
192  Visit(node->each());
193  Print(" in ");
194  Visit(node->enumerable());
195  Print(") ");
196  Visit(node->body());
197}
198
199
200void PrettyPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
201  Print("try ");
202  Visit(node->try_block());
203  Print(" catch (");
204  Visit(node->catch_var());
205  Print(") ");
206  Visit(node->catch_block());
207}
208
209
210void PrettyPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) {
211  Print("try ");
212  Visit(node->try_block());
213  Print(" finally ");
214  Visit(node->finally_block());
215}
216
217
218void PrettyPrinter::VisitDebuggerStatement(DebuggerStatement* node) {
219  Print("debugger ");
220}
221
222
223void PrettyPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
224  Print("(");
225  PrintFunctionLiteral(node);
226  Print(")");
227}
228
229
230void PrettyPrinter::VisitFunctionBoilerplateLiteral(
231    FunctionBoilerplateLiteral* node) {
232  Print("(");
233  PrintLiteral(node->boilerplate(), true);
234  Print(")");
235}
236
237
238void PrettyPrinter::VisitConditional(Conditional* node) {
239  Visit(node->condition());
240  Print(" ? ");
241  Visit(node->then_expression());
242  Print(" : ");
243  Visit(node->else_expression());
244}
245
246
247void PrettyPrinter::VisitLiteral(Literal* node) {
248  PrintLiteral(node->handle(), true);
249}
250
251
252void PrettyPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
253  Print(" RegExp(");
254  PrintLiteral(node->pattern(), false);
255  Print(",");
256  PrintLiteral(node->flags(), false);
257  Print(") ");
258}
259
260
261void PrettyPrinter::VisitObjectLiteral(ObjectLiteral* node) {
262  Print("{ ");
263  for (int i = 0; i < node->properties()->length(); i++) {
264    if (i != 0) Print(",");
265    ObjectLiteral::Property* property = node->properties()->at(i);
266    Print(" ");
267    Visit(property->key());
268    Print(": ");
269    Visit(property->value());
270  }
271  Print(" }");
272}
273
274
275void PrettyPrinter::VisitArrayLiteral(ArrayLiteral* node) {
276  Print("[ ");
277  for (int i = 0; i < node->values()->length(); i++) {
278    if (i != 0) Print(",");
279    Visit(node->values()->at(i));
280  }
281  Print(" ]");
282}
283
284
285void PrettyPrinter::VisitCatchExtensionObject(CatchExtensionObject* node) {
286  Print("{ ");
287  Visit(node->key());
288  Print(": ");
289  Visit(node->value());
290  Print(" }");
291}
292
293
294void PrettyPrinter::VisitSlot(Slot* node) {
295  switch (node->type()) {
296    case Slot::PARAMETER:
297      Print("parameter[%d]", node->index());
298      break;
299    case Slot::LOCAL:
300      Print("frame[%d]", node->index());
301      break;
302    case Slot::CONTEXT:
303      Print(".context[%d]", node->index());
304      break;
305    case Slot::LOOKUP:
306      Print(".context[");
307      PrintLiteral(node->var()->name(), false);
308      Print("]");
309      break;
310    default:
311      UNREACHABLE();
312  }
313}
314
315
316void PrettyPrinter::VisitVariableProxy(VariableProxy* node) {
317  PrintLiteral(node->name(), false);
318}
319
320
321void PrettyPrinter::VisitAssignment(Assignment* node) {
322  Visit(node->target());
323  Print(" %s ", Token::String(node->op()));
324  Visit(node->value());
325}
326
327
328void PrettyPrinter::VisitThrow(Throw* node) {
329  Print("throw ");
330  Visit(node->exception());
331}
332
333
334void PrettyPrinter::VisitProperty(Property* node) {
335  Expression* key = node->key();
336  Literal* literal = key->AsLiteral();
337  if (literal != NULL && literal->handle()->IsSymbol()) {
338    Print("(");
339    Visit(node->obj());
340    Print(").");
341    PrintLiteral(literal->handle(), false);
342  } else {
343    Visit(node->obj());
344    Print("[");
345    Visit(key);
346    Print("]");
347  }
348}
349
350
351void PrettyPrinter::VisitCall(Call* node) {
352  Visit(node->expression());
353  PrintArguments(node->arguments());
354}
355
356
357void PrettyPrinter::VisitCallNew(CallNew* node) {
358  Print("new (");
359  Visit(node->expression());
360  Print(")");
361  PrintArguments(node->arguments());
362}
363
364
365void PrettyPrinter::VisitCallRuntime(CallRuntime* node) {
366  Print("%%");
367  PrintLiteral(node->name(), false);
368  PrintArguments(node->arguments());
369}
370
371
372void PrettyPrinter::VisitUnaryOperation(UnaryOperation* node) {
373  Print("(%s", Token::String(node->op()));
374  Visit(node->expression());
375  Print(")");
376}
377
378
379void PrettyPrinter::VisitCountOperation(CountOperation* node) {
380  Print("(");
381  if (node->is_prefix()) Print("%s", Token::String(node->op()));
382  Visit(node->expression());
383  if (node->is_postfix()) Print("%s", Token::String(node->op()));
384  Print(")");
385}
386
387
388void PrettyPrinter::VisitBinaryOperation(BinaryOperation* node) {
389  Print("(");
390  Visit(node->left());
391  Print("%s", Token::String(node->op()));
392  Visit(node->right());
393  Print(")");
394}
395
396
397void PrettyPrinter::VisitCompareOperation(CompareOperation* node) {
398  Print("(");
399  Visit(node->left());
400  Print("%s", Token::String(node->op()));
401  Visit(node->right());
402  Print(")");
403}
404
405
406void PrettyPrinter::VisitThisFunction(ThisFunction* node) {
407  Print("<this-function>");
408}
409
410
411const char* PrettyPrinter::Print(AstNode* node) {
412  Init();
413  Visit(node);
414  return output_;
415}
416
417
418const char* PrettyPrinter::PrintExpression(FunctionLiteral* program) {
419  Init();
420  ExpressionStatement* statement =
421    program->body()->at(0)->AsExpressionStatement();
422  Visit(statement->expression());
423  return output_;
424}
425
426
427const char* PrettyPrinter::PrintProgram(FunctionLiteral* program) {
428  Init();
429  PrintStatements(program->body());
430  Print("\n");
431  return output_;
432}
433
434
435void PrettyPrinter::PrintOut(AstNode* node) {
436  PrettyPrinter printer;
437  PrintF("%s", printer.Print(node));
438}
439
440
441void PrettyPrinter::Init() {
442  if (size_ == 0) {
443    ASSERT(output_ == NULL);
444    const int initial_size = 256;
445    output_ = NewArray<char>(initial_size);
446    size_ = initial_size;
447  }
448  output_[0] = '\0';
449  pos_ = 0;
450}
451
452
453void PrettyPrinter::Print(const char* format, ...) {
454  for (;;) {
455    va_list arguments;
456    va_start(arguments, format);
457    int n = OS::VSNPrintF(Vector<char>(output_, size_) + pos_,
458                          format,
459                          arguments);
460    va_end(arguments);
461
462    if (n >= 0) {
463      // there was enough space - we are done
464      pos_ += n;
465      return;
466    } else {
467      // there was not enough space - allocate more and try again
468      const int slack = 32;
469      int new_size = size_ + (size_ >> 1) + slack;
470      char* new_output = NewArray<char>(new_size);
471      memcpy(new_output, output_, pos_);
472      DeleteArray(output_);
473      output_ = new_output;
474      size_ = new_size;
475    }
476  }
477}
478
479
480void PrettyPrinter::PrintStatements(ZoneList<Statement*>* statements) {
481  for (int i = 0; i < statements->length(); i++) {
482    if (i != 0) Print(" ");
483    Visit(statements->at(i));
484  }
485}
486
487
488void PrettyPrinter::PrintLabels(ZoneStringList* labels) {
489  if (labels != NULL) {
490    for (int i = 0; i < labels->length(); i++) {
491      PrintLiteral(labels->at(i), false);
492      Print(": ");
493    }
494  }
495}
496
497
498void PrettyPrinter::PrintArguments(ZoneList<Expression*>* arguments) {
499  Print("(");
500  for (int i = 0; i < arguments->length(); i++) {
501    if (i != 0) Print(", ");
502    Visit(arguments->at(i));
503  }
504  Print(")");
505}
506
507
508void PrettyPrinter::PrintLiteral(Handle<Object> value, bool quote) {
509  Object* object = *value;
510  if (object->IsString()) {
511    String* string = String::cast(object);
512    if (quote) Print("\"");
513    for (int i = 0; i < string->length(); i++) {
514      Print("%c", string->Get(i));
515    }
516    if (quote) Print("\"");
517  } else if (object == Heap::null_value()) {
518    Print("null");
519  } else if (object == Heap::true_value()) {
520    Print("true");
521  } else if (object == Heap::false_value()) {
522    Print("false");
523  } else if (object == Heap::undefined_value()) {
524    Print("undefined");
525  } else if (object->IsNumber()) {
526    Print("%g", object->Number());
527  } else if (object->IsJSObject()) {
528    // regular expression
529    if (object->IsJSFunction()) {
530      Print("JS-Function");
531    } else if (object->IsJSArray()) {
532      Print("JS-array[%u]", JSArray::cast(object)->length());
533    } else if (object->IsJSObject()) {
534      Print("JS-Object");
535    } else {
536      Print("?UNKNOWN?");
537    }
538  } else if (object->IsFixedArray()) {
539    Print("FixedArray");
540  } else {
541    Print("<unknown literal %p>", object);
542  }
543}
544
545
546void PrettyPrinter::PrintParameters(Scope* scope) {
547  Print("(");
548  for (int i = 0; i < scope->num_parameters(); i++) {
549    if (i  > 0) Print(", ");
550    PrintLiteral(scope->parameter(i)->name(), false);
551  }
552  Print(")");
553}
554
555
556void PrettyPrinter::PrintDeclarations(ZoneList<Declaration*>* declarations) {
557  for (int i = 0; i < declarations->length(); i++) {
558    if (i > 0) Print(" ");
559    Visit(declarations->at(i));
560  }
561}
562
563
564void PrettyPrinter::PrintFunctionLiteral(FunctionLiteral* function) {
565  Print("function ");
566  PrintLiteral(function->name(), false);
567  PrintParameters(function->scope());
568  Print(" { ");
569  PrintDeclarations(function->scope()->declarations());
570  PrintStatements(function->body());
571  Print(" }");
572}
573
574
575void PrettyPrinter::PrintCaseClause(CaseClause* clause) {
576  if (clause->is_default()) {
577    Print("default");
578  } else {
579    Print("case ");
580    Visit(clause->label());
581  }
582  Print(": ");
583  PrintStatements(clause->statements());
584  if (clause->statements()->length() > 0)
585    Print(" ");
586}
587
588
589//-----------------------------------------------------------------------------
590
591class IndentedScope BASE_EMBEDDED {
592 public:
593  IndentedScope() {
594    ast_printer_->inc_indent();
595  }
596
597  explicit IndentedScope(const char* txt, AstNode* node = NULL) {
598    ast_printer_->PrintIndented(txt);
599    if (node != NULL && node->AsExpression() != NULL) {
600      Expression* expr = node->AsExpression();
601      bool printed_first = false;
602      if ((expr->type() != NULL) && (expr->type()->IsKnown())) {
603        ast_printer_->Print(" (type = ");
604        ast_printer_->Print(StaticType::Type2String(expr->type()));
605        printed_first = true;
606      }
607      if (expr->num() != Expression::kNoLabel) {
608        ast_printer_->Print(printed_first ? ", num = " : " (num = ");
609        ast_printer_->Print("%d", expr->num());
610        printed_first = true;
611      }
612      if (printed_first) ast_printer_->Print(")");
613    }
614    ast_printer_->Print("\n");
615    ast_printer_->inc_indent();
616  }
617
618  virtual ~IndentedScope() {
619    ast_printer_->dec_indent();
620  }
621
622  static void SetAstPrinter(AstPrinter* a) { ast_printer_ = a; }
623
624 private:
625  static AstPrinter* ast_printer_;
626};
627
628
629AstPrinter* IndentedScope::ast_printer_ = NULL;
630
631
632//-----------------------------------------------------------------------------
633
634int AstPrinter::indent_ = 0;
635
636
637AstPrinter::AstPrinter() {
638  ASSERT(indent_ == 0);
639  IndentedScope::SetAstPrinter(this);
640}
641
642
643AstPrinter::~AstPrinter() {
644  ASSERT(indent_ == 0);
645  IndentedScope::SetAstPrinter(NULL);
646}
647
648
649void AstPrinter::PrintIndented(const char* txt) {
650  for (int i = 0; i < indent_; i++) {
651    Print(". ");
652  }
653  Print(txt);
654}
655
656
657void AstPrinter::PrintLiteralIndented(const char* info,
658                                      Handle<Object> value,
659                                      bool quote) {
660  PrintIndented(info);
661  Print(" ");
662  PrintLiteral(value, quote);
663  Print("\n");
664}
665
666
667void AstPrinter::PrintLiteralWithModeIndented(const char* info,
668                                              Variable* var,
669                                              Handle<Object> value,
670                                              StaticType* type,
671                                              int num) {
672  if (var == NULL) {
673    PrintLiteralIndented(info, value, true);
674  } else {
675    EmbeddedVector<char, 256> buf;
676    int pos = OS::SNPrintF(buf, "%s (mode = %s", info,
677                           Variable::Mode2String(var->mode()));
678    if (type->IsKnown()) {
679      pos += OS::SNPrintF(buf + pos, ", type = %s",
680                          StaticType::Type2String(type));
681    }
682    if (num != Expression::kNoLabel) {
683      pos += OS::SNPrintF(buf + pos, ", num = %d", num);
684    }
685    OS::SNPrintF(buf + pos, ")");
686    PrintLiteralIndented(buf.start(), value, true);
687  }
688}
689
690
691void AstPrinter::PrintLabelsIndented(const char* info, ZoneStringList* labels) {
692  if (labels != NULL && labels->length() > 0) {
693    if (info == NULL) {
694      PrintIndented("LABELS ");
695    } else {
696      PrintIndented(info);
697      Print(" ");
698    }
699    PrintLabels(labels);
700  } else if (info != NULL) {
701    PrintIndented(info);
702  }
703  Print("\n");
704}
705
706
707void AstPrinter::PrintIndentedVisit(const char* s, AstNode* node) {
708  IndentedScope indent(s, node);
709  Visit(node);
710}
711
712
713const char* AstPrinter::PrintProgram(FunctionLiteral* program) {
714  Init();
715  { IndentedScope indent("FUNC");
716    PrintLiteralIndented("NAME", program->name(), true);
717    PrintLiteralIndented("INFERRED NAME", program->inferred_name(), true);
718    PrintParameters(program->scope());
719    PrintDeclarations(program->scope()->declarations());
720    PrintStatements(program->body());
721  }
722  return Output();
723}
724
725
726void AstPrinter::PrintDeclarations(ZoneList<Declaration*>* declarations) {
727  if (declarations->length() > 0) {
728    IndentedScope indent("DECLS");
729    for (int i = 0; i < declarations->length(); i++) {
730      Visit(declarations->at(i));
731    }
732  }
733}
734
735
736void AstPrinter::PrintParameters(Scope* scope) {
737  if (scope->num_parameters() > 0) {
738    IndentedScope indent("PARAMS");
739    for (int i = 0; i < scope->num_parameters(); i++) {
740      PrintLiteralWithModeIndented("VAR", scope->parameter(i),
741                                   scope->parameter(i)->name(),
742                                   scope->parameter(i)->type(),
743                                   Expression::kNoLabel);
744    }
745  }
746}
747
748
749void AstPrinter::PrintStatements(ZoneList<Statement*>* statements) {
750  for (int i = 0; i < statements->length(); i++) {
751    Visit(statements->at(i));
752  }
753}
754
755
756void AstPrinter::PrintArguments(ZoneList<Expression*>* arguments) {
757  for (int i = 0; i < arguments->length(); i++) {
758    Visit(arguments->at(i));
759  }
760}
761
762
763void AstPrinter::PrintCaseClause(CaseClause* clause) {
764  if (clause->is_default()) {
765    IndentedScope indent("DEFAULT");
766    PrintStatements(clause->statements());
767  } else {
768    IndentedScope indent("CASE");
769    Visit(clause->label());
770    PrintStatements(clause->statements());
771  }
772}
773
774
775void AstPrinter::VisitBlock(Block* node) {
776  const char* block_txt = node->is_initializer_block() ? "BLOCK INIT" : "BLOCK";
777  IndentedScope indent(block_txt);
778  PrintStatements(node->statements());
779}
780
781
782void AstPrinter::VisitDeclaration(Declaration* node) {
783  if (node->fun() == NULL) {
784    // var or const declarations
785    PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()),
786                                 node->proxy()->AsVariable(),
787                                 node->proxy()->name(),
788                                 node->proxy()->AsVariable()->type(),
789                                 Expression::kNoLabel);
790  } else {
791    // function declarations
792    PrintIndented("FUNCTION ");
793    PrintLiteral(node->proxy()->name(), true);
794    Print(" = function ");
795    PrintLiteral(node->fun()->name(), false);
796    Print("\n");
797  }
798}
799
800
801void AstPrinter::VisitExpressionStatement(ExpressionStatement* node) {
802  Visit(node->expression());
803}
804
805
806void AstPrinter::VisitEmptyStatement(EmptyStatement* node) {
807  PrintIndented("EMPTY\n");
808}
809
810
811void AstPrinter::VisitIfStatement(IfStatement* node) {
812  PrintIndentedVisit("IF", node->condition());
813  PrintIndentedVisit("THEN", node->then_statement());
814  if (node->HasElseStatement()) {
815    PrintIndentedVisit("ELSE", node->else_statement());
816  }
817}
818
819
820void AstPrinter::VisitContinueStatement(ContinueStatement* node) {
821  PrintLabelsIndented("CONTINUE", node->target()->labels());
822}
823
824
825void AstPrinter::VisitBreakStatement(BreakStatement* node) {
826  PrintLabelsIndented("BREAK", node->target()->labels());
827}
828
829
830void AstPrinter::VisitReturnStatement(ReturnStatement* node) {
831  PrintIndentedVisit("RETURN", node->expression());
832}
833
834
835void AstPrinter::VisitWithEnterStatement(WithEnterStatement* node) {
836  PrintIndentedVisit("WITH ENTER", node->expression());
837}
838
839
840void AstPrinter::VisitWithExitStatement(WithExitStatement* node) {
841  PrintIndented("WITH EXIT\n");
842}
843
844
845void AstPrinter::VisitSwitchStatement(SwitchStatement* node) {
846  IndentedScope indent("SWITCH");
847  PrintLabelsIndented(NULL, node->labels());
848  PrintIndentedVisit("TAG", node->tag());
849  for (int i = 0; i < node->cases()->length(); i++) {
850    PrintCaseClause(node->cases()->at(i));
851  }
852}
853
854
855void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) {
856  IndentedScope indent("DO");
857  PrintLabelsIndented(NULL, node->labels());
858  PrintIndentedVisit("BODY", node->body());
859  PrintIndentedVisit("COND", node->cond());
860}
861
862
863void AstPrinter::VisitWhileStatement(WhileStatement* node) {
864  IndentedScope indent("WHILE");
865  PrintLabelsIndented(NULL, node->labels());
866  PrintIndentedVisit("COND", node->cond());
867  PrintIndentedVisit("BODY", node->body());
868}
869
870
871void AstPrinter::VisitForStatement(ForStatement* node) {
872  IndentedScope indent("FOR");
873  PrintLabelsIndented(NULL, node->labels());
874  if (node->init()) PrintIndentedVisit("INIT", node->init());
875  if (node->cond()) PrintIndentedVisit("COND", node->cond());
876  PrintIndentedVisit("BODY", node->body());
877  if (node->next()) PrintIndentedVisit("NEXT", node->next());
878}
879
880
881void AstPrinter::VisitForInStatement(ForInStatement* node) {
882  IndentedScope indent("FOR IN");
883  PrintIndentedVisit("FOR", node->each());
884  PrintIndentedVisit("IN", node->enumerable());
885  PrintIndentedVisit("BODY", node->body());
886}
887
888
889void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) {
890  IndentedScope indent("TRY CATCH");
891  PrintIndentedVisit("TRY", node->try_block());
892  PrintIndentedVisit("CATCHVAR", node->catch_var());
893  PrintIndentedVisit("CATCH", node->catch_block());
894}
895
896
897void AstPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) {
898  IndentedScope indent("TRY FINALLY");
899  PrintIndentedVisit("TRY", node->try_block());
900  PrintIndentedVisit("FINALLY", node->finally_block());
901}
902
903
904void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) {
905  IndentedScope indent("DEBUGGER");
906}
907
908
909void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
910  IndentedScope indent("FUNC LITERAL");
911  PrintLiteralIndented("NAME", node->name(), false);
912  PrintLiteralIndented("INFERRED NAME", node->inferred_name(), false);
913  PrintParameters(node->scope());
914  // We don't want to see the function literal in this case: it
915  // will be printed via PrintProgram when the code for it is
916  // generated.
917  // PrintStatements(node->body());
918}
919
920
921void AstPrinter::VisitFunctionBoilerplateLiteral(
922    FunctionBoilerplateLiteral* node) {
923  IndentedScope indent("FUNC LITERAL");
924  PrintLiteralIndented("BOILERPLATE", node->boilerplate(), true);
925}
926
927
928void AstPrinter::VisitConditional(Conditional* node) {
929  IndentedScope indent("CONDITIONAL");
930  PrintIndentedVisit("?", node->condition());
931  PrintIndentedVisit("THEN", node->then_expression());
932  PrintIndentedVisit("ELSE", node->else_expression());
933}
934
935
936void AstPrinter::VisitLiteral(Literal* node) {
937  PrintLiteralIndented("LITERAL", node->handle(), true);
938}
939
940
941void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
942  IndentedScope indent("REGEXP LITERAL");
943  PrintLiteralIndented("PATTERN", node->pattern(), false);
944  PrintLiteralIndented("FLAGS", node->flags(), false);
945}
946
947
948void AstPrinter::VisitObjectLiteral(ObjectLiteral* node) {
949  IndentedScope indent("OBJ LITERAL");
950  for (int i = 0; i < node->properties()->length(); i++) {
951    const char* prop_kind = NULL;
952    switch (node->properties()->at(i)->kind()) {
953      case ObjectLiteral::Property::CONSTANT:
954        prop_kind = "PROPERTY - CONSTANT";
955        break;
956      case ObjectLiteral::Property::COMPUTED:
957        prop_kind = "PROPERTY - COMPUTED";
958        break;
959      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
960        prop_kind = "PROPERTY - MATERIALIZED_LITERAL";
961        break;
962      case ObjectLiteral::Property::PROTOTYPE:
963        prop_kind = "PROPERTY - PROTOTYPE";
964        break;
965      case ObjectLiteral::Property::GETTER:
966        prop_kind = "PROPERTY - GETTER";
967        break;
968      case ObjectLiteral::Property::SETTER:
969        prop_kind = "PROPERTY - SETTER";
970        break;
971      default:
972        UNREACHABLE();
973    }
974    IndentedScope prop(prop_kind);
975    PrintIndentedVisit("KEY", node->properties()->at(i)->key());
976    PrintIndentedVisit("VALUE", node->properties()->at(i)->value());
977  }
978}
979
980
981void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) {
982  IndentedScope indent("ARRAY LITERAL");
983  if (node->values()->length() > 0) {
984    IndentedScope indent("VALUES");
985    for (int i = 0; i < node->values()->length(); i++) {
986      Visit(node->values()->at(i));
987    }
988  }
989}
990
991
992void AstPrinter::VisitCatchExtensionObject(CatchExtensionObject* node) {
993  IndentedScope indent("CatchExtensionObject");
994  PrintIndentedVisit("KEY", node->key());
995  PrintIndentedVisit("VALUE", node->value());
996}
997
998
999void AstPrinter::VisitSlot(Slot* node) {
1000  PrintIndented("SLOT ");
1001  switch (node->type()) {
1002    case Slot::PARAMETER:
1003      Print("parameter[%d]", node->index());
1004      break;
1005    case Slot::LOCAL:
1006      Print("frame[%d]", node->index());
1007      break;
1008    case Slot::CONTEXT:
1009      Print(".context[%d]", node->index());
1010      break;
1011    case Slot::LOOKUP:
1012      Print(".context[");
1013      PrintLiteral(node->var()->name(), false);
1014      Print("]");
1015      break;
1016    default:
1017      UNREACHABLE();
1018  }
1019  Print("\n");
1020}
1021
1022
1023void AstPrinter::VisitVariableProxy(VariableProxy* node) {
1024  PrintLiteralWithModeIndented("VAR PROXY", node->AsVariable(), node->name(),
1025                               node->type(), node->num());
1026  Variable* var = node->var();
1027  if (var != NULL && var->rewrite() != NULL) {
1028    IndentedScope indent;
1029    Visit(var->rewrite());
1030  }
1031}
1032
1033
1034void AstPrinter::VisitAssignment(Assignment* node) {
1035  IndentedScope indent(Token::Name(node->op()), node);
1036  Visit(node->target());
1037  Visit(node->value());
1038}
1039
1040
1041void AstPrinter::VisitThrow(Throw* node) {
1042  PrintIndentedVisit("THROW", node->exception());
1043}
1044
1045
1046void AstPrinter::VisitProperty(Property* node) {
1047  IndentedScope indent("PROPERTY", node);
1048  Visit(node->obj());
1049  Literal* literal = node->key()->AsLiteral();
1050  if (literal != NULL && literal->handle()->IsSymbol()) {
1051    PrintLiteralIndented("NAME", literal->handle(), false);
1052  } else {
1053    PrintIndentedVisit("KEY", node->key());
1054  }
1055}
1056
1057
1058void AstPrinter::VisitCall(Call* node) {
1059  IndentedScope indent("CALL");
1060  Visit(node->expression());
1061  PrintArguments(node->arguments());
1062}
1063
1064
1065void AstPrinter::VisitCallNew(CallNew* node) {
1066  IndentedScope indent("CALL NEW");
1067  Visit(node->expression());
1068  PrintArguments(node->arguments());
1069}
1070
1071
1072void AstPrinter::VisitCallRuntime(CallRuntime* node) {
1073  PrintLiteralIndented("CALL RUNTIME ", node->name(), false);
1074  IndentedScope indent;
1075  PrintArguments(node->arguments());
1076}
1077
1078
1079void AstPrinter::VisitUnaryOperation(UnaryOperation* node) {
1080  PrintIndentedVisit(Token::Name(node->op()), node->expression());
1081}
1082
1083
1084void AstPrinter::VisitCountOperation(CountOperation* node) {
1085  EmbeddedVector<char, 128> buf;
1086  if (node->type()->IsKnown()) {
1087    OS::SNPrintF(buf, "%s %s (type = %s)",
1088                 (node->is_prefix() ? "PRE" : "POST"),
1089                 Token::Name(node->op()),
1090                 StaticType::Type2String(node->type()));
1091  } else {
1092    OS::SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"),
1093                 Token::Name(node->op()));
1094  }
1095  PrintIndentedVisit(buf.start(), node->expression());
1096}
1097
1098
1099void AstPrinter::VisitBinaryOperation(BinaryOperation* node) {
1100  IndentedScope indent(Token::Name(node->op()), node);
1101  Visit(node->left());
1102  Visit(node->right());
1103}
1104
1105
1106void AstPrinter::VisitCompareOperation(CompareOperation* node) {
1107  IndentedScope indent(Token::Name(node->op()), node);
1108  Visit(node->left());
1109  Visit(node->right());
1110}
1111
1112
1113void AstPrinter::VisitThisFunction(ThisFunction* node) {
1114  IndentedScope indent("THIS-FUNCTION");
1115}
1116
1117
1118TagScope::TagScope(JsonAstBuilder* builder, const char* name)
1119    : builder_(builder), next_(builder->tag()), has_body_(false) {
1120  if (next_ != NULL) {
1121    next_->use();
1122    builder->Print(",\n");
1123  }
1124  builder->set_tag(this);
1125  builder->PrintIndented("[");
1126  builder->Print("\"%s\"", name);
1127  builder->increase_indent(JsonAstBuilder::kTagIndentSize);
1128}
1129
1130
1131TagScope::~TagScope() {
1132  builder_->decrease_indent(JsonAstBuilder::kTagIndentSize);
1133  if (has_body_) {
1134    builder_->Print("\n");
1135    builder_->PrintIndented("]");
1136  } else {
1137    builder_->Print("]");
1138  }
1139  builder_->set_tag(next_);
1140}
1141
1142
1143AttributesScope::AttributesScope(JsonAstBuilder* builder)
1144    : builder_(builder), attribute_count_(0) {
1145  builder->set_attributes(this);
1146  builder->tag()->use();
1147  builder->Print(",\n");
1148  builder->PrintIndented("{");
1149  builder->increase_indent(JsonAstBuilder::kAttributesIndentSize);
1150}
1151
1152
1153AttributesScope::~AttributesScope() {
1154  builder_->decrease_indent(JsonAstBuilder::kAttributesIndentSize);
1155  if (attribute_count_ > 1) {
1156    builder_->Print("\n");
1157    builder_->PrintIndented("}");
1158  } else {
1159    builder_->Print("}");
1160  }
1161  builder_->set_attributes(NULL);
1162}
1163
1164
1165const char* JsonAstBuilder::BuildProgram(FunctionLiteral* program) {
1166  Init();
1167  Visit(program);
1168  Print("\n");
1169  return Output();
1170}
1171
1172
1173void JsonAstBuilder::AddAttributePrefix(const char* name) {
1174  if (attributes()->is_used()) {
1175    Print(",\n");
1176    PrintIndented("\"");
1177  } else {
1178    Print("\"");
1179  }
1180  Print("%s\":", name);
1181  attributes()->use();
1182}
1183
1184
1185void JsonAstBuilder::AddAttribute(const char* name, Handle<String> value) {
1186  SmartPointer<char> value_string = value->ToCString();
1187  AddAttributePrefix(name);
1188  Print("\"%s\"", *value_string);
1189}
1190
1191
1192void JsonAstBuilder::AddAttribute(const char* name, const char* value) {
1193  AddAttributePrefix(name);
1194  Print("\"%s\"", value);
1195}
1196
1197
1198void JsonAstBuilder::AddAttribute(const char* name, int value) {
1199  AddAttributePrefix(name);
1200  Print("%d", value);
1201}
1202
1203
1204void JsonAstBuilder::AddAttribute(const char* name, bool value) {
1205  AddAttributePrefix(name);
1206  Print(value ? "true" : "false");
1207}
1208
1209
1210void JsonAstBuilder::VisitBlock(Block* stmt) {
1211  TagScope tag(this, "Block");
1212  VisitStatements(stmt->statements());
1213}
1214
1215
1216void JsonAstBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
1217  TagScope tag(this, "ExpressionStatement");
1218  Visit(stmt->expression());
1219}
1220
1221
1222void JsonAstBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
1223  TagScope tag(this, "EmptyStatement");
1224}
1225
1226
1227void JsonAstBuilder::VisitIfStatement(IfStatement* stmt) {
1228  TagScope tag(this, "IfStatement");
1229  Visit(stmt->condition());
1230  Visit(stmt->then_statement());
1231  Visit(stmt->else_statement());
1232}
1233
1234
1235void JsonAstBuilder::VisitContinueStatement(ContinueStatement* stmt) {
1236  TagScope tag(this, "ContinueStatement");
1237}
1238
1239
1240void JsonAstBuilder::VisitBreakStatement(BreakStatement* stmt) {
1241  TagScope tag(this, "BreakStatement");
1242}
1243
1244
1245void JsonAstBuilder::VisitReturnStatement(ReturnStatement* stmt) {
1246  TagScope tag(this, "ReturnStatement");
1247  Visit(stmt->expression());
1248}
1249
1250
1251void JsonAstBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
1252  TagScope tag(this, "WithEnterStatement");
1253  Visit(stmt->expression());
1254}
1255
1256
1257void JsonAstBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
1258  TagScope tag(this, "WithExitStatement");
1259}
1260
1261
1262void JsonAstBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
1263  TagScope tag(this, "SwitchStatement");
1264}
1265
1266
1267void JsonAstBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
1268  TagScope tag(this, "DoWhileStatement");
1269  Visit(stmt->body());
1270  Visit(stmt->cond());
1271}
1272
1273
1274void JsonAstBuilder::VisitWhileStatement(WhileStatement* stmt) {
1275  TagScope tag(this, "WhileStatement");
1276  Visit(stmt->cond());
1277  Visit(stmt->body());
1278}
1279
1280
1281void JsonAstBuilder::VisitForStatement(ForStatement* stmt) {
1282  TagScope tag(this, "ForStatement");
1283  if (stmt->init() != NULL) Visit(stmt->init());
1284  if (stmt->cond() != NULL) Visit(stmt->cond());
1285  Visit(stmt->body());
1286  if (stmt->next() != NULL) Visit(stmt->next());
1287}
1288
1289
1290void JsonAstBuilder::VisitForInStatement(ForInStatement* stmt) {
1291  TagScope tag(this, "ForInStatement");
1292  Visit(stmt->each());
1293  Visit(stmt->enumerable());
1294  Visit(stmt->body());
1295}
1296
1297
1298void JsonAstBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
1299  TagScope tag(this, "TryCatchStatement");
1300  Visit(stmt->try_block());
1301  Visit(stmt->catch_var());
1302  Visit(stmt->catch_block());
1303}
1304
1305
1306void JsonAstBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1307  TagScope tag(this, "TryFinallyStatement");
1308  Visit(stmt->try_block());
1309  Visit(stmt->finally_block());
1310}
1311
1312
1313void JsonAstBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
1314  TagScope tag(this, "DebuggerStatement");
1315}
1316
1317
1318void JsonAstBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
1319  TagScope tag(this, "FunctionLiteral");
1320  {
1321    AttributesScope attributes(this);
1322    AddAttribute("name", expr->name());
1323  }
1324  VisitDeclarations(expr->scope()->declarations());
1325  VisitStatements(expr->body());
1326}
1327
1328
1329void JsonAstBuilder::VisitFunctionBoilerplateLiteral(
1330    FunctionBoilerplateLiteral* expr) {
1331  TagScope tag(this, "FunctionBoilerplateLiteral");
1332}
1333
1334
1335void JsonAstBuilder::VisitConditional(Conditional* expr) {
1336  TagScope tag(this, "Conditional");
1337}
1338
1339
1340void JsonAstBuilder::VisitSlot(Slot* expr) {
1341  TagScope tag(this, "Slot");
1342  {
1343    AttributesScope attributes(this);
1344    switch (expr->type()) {
1345      case Slot::PARAMETER:
1346        AddAttribute("type", "PARAMETER");
1347        break;
1348      case Slot::LOCAL:
1349        AddAttribute("type", "LOCAL");
1350        break;
1351      case Slot::CONTEXT:
1352        AddAttribute("type", "CONTEXT");
1353        break;
1354      case Slot::LOOKUP:
1355        AddAttribute("type", "LOOKUP");
1356        break;
1357    }
1358    AddAttribute("index", expr->index());
1359  }
1360}
1361
1362
1363void JsonAstBuilder::VisitVariableProxy(VariableProxy* expr) {
1364  if (expr->var()->rewrite() == NULL) {
1365    TagScope tag(this, "VariableProxy");
1366    {
1367      AttributesScope attributes(this);
1368      AddAttribute("name", expr->name());
1369      AddAttribute("mode", Variable::Mode2String(expr->var()->mode()));
1370    }
1371  } else {
1372    Visit(expr->var()->rewrite());
1373  }
1374}
1375
1376
1377void JsonAstBuilder::VisitLiteral(Literal* expr) {
1378  TagScope tag(this, "Literal");
1379  {
1380    AttributesScope attributes(this);
1381    Handle<Object> handle = expr->handle();
1382    if (handle->IsString()) {
1383      AddAttribute("handle", Handle<String>(String::cast(*handle)));
1384    } else if (handle->IsSmi()) {
1385      AddAttribute("handle", Smi::cast(*handle)->value());
1386    }
1387  }
1388}
1389
1390
1391void JsonAstBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
1392  TagScope tag(this, "RegExpLiteral");
1393}
1394
1395
1396void JsonAstBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
1397  TagScope tag(this, "ObjectLiteral");
1398}
1399
1400
1401void JsonAstBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
1402  TagScope tag(this, "ArrayLiteral");
1403}
1404
1405
1406void JsonAstBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
1407  TagScope tag(this, "CatchExtensionObject");
1408  Visit(expr->key());
1409  Visit(expr->value());
1410}
1411
1412
1413void JsonAstBuilder::VisitAssignment(Assignment* expr) {
1414  TagScope tag(this, "Assignment");
1415  {
1416    AttributesScope attributes(this);
1417    AddAttribute("op", Token::Name(expr->op()));
1418  }
1419  Visit(expr->target());
1420  Visit(expr->value());
1421}
1422
1423
1424void JsonAstBuilder::VisitThrow(Throw* expr) {
1425  TagScope tag(this, "Throw");
1426  Visit(expr->exception());
1427}
1428
1429
1430void JsonAstBuilder::VisitProperty(Property* expr) {
1431  TagScope tag(this, "Property");
1432  {
1433    AttributesScope attributes(this);
1434    AddAttribute("type", expr->is_synthetic() ? "SYNTHETIC" : "NORMAL");
1435  }
1436  Visit(expr->obj());
1437  Visit(expr->key());
1438}
1439
1440
1441void JsonAstBuilder::VisitCall(Call* expr) {
1442  TagScope tag(this, "Call");
1443  Visit(expr->expression());
1444  VisitExpressions(expr->arguments());
1445}
1446
1447
1448void JsonAstBuilder::VisitCallNew(CallNew* expr) {
1449  TagScope tag(this, "CallNew");
1450  Visit(expr->expression());
1451  VisitExpressions(expr->arguments());
1452}
1453
1454
1455void JsonAstBuilder::VisitCallRuntime(CallRuntime* expr) {
1456  TagScope tag(this, "CallRuntime");
1457  {
1458    AttributesScope attributes(this);
1459    AddAttribute("name", expr->name());
1460  }
1461  VisitExpressions(expr->arguments());
1462}
1463
1464
1465void JsonAstBuilder::VisitUnaryOperation(UnaryOperation* expr) {
1466  TagScope tag(this, "UnaryOperation");
1467  {
1468    AttributesScope attributes(this);
1469    AddAttribute("op", Token::Name(expr->op()));
1470  }
1471  Visit(expr->expression());
1472}
1473
1474
1475void JsonAstBuilder::VisitCountOperation(CountOperation* expr) {
1476  TagScope tag(this, "CountOperation");
1477  {
1478    AttributesScope attributes(this);
1479    AddAttribute("is_prefix", expr->is_prefix());
1480    AddAttribute("op", Token::Name(expr->op()));
1481  }
1482  Visit(expr->expression());
1483}
1484
1485
1486void JsonAstBuilder::VisitBinaryOperation(BinaryOperation* expr) {
1487  TagScope tag(this, "BinaryOperation");
1488  {
1489    AttributesScope attributes(this);
1490    AddAttribute("op", Token::Name(expr->op()));
1491  }
1492  Visit(expr->left());
1493  Visit(expr->right());
1494}
1495
1496
1497void JsonAstBuilder::VisitCompareOperation(CompareOperation* expr) {
1498  TagScope tag(this, "CompareOperation");
1499  {
1500    AttributesScope attributes(this);
1501    AddAttribute("op", Token::Name(expr->op()));
1502  }
1503  Visit(expr->left());
1504  Visit(expr->right());
1505}
1506
1507
1508void JsonAstBuilder::VisitThisFunction(ThisFunction* expr) {
1509  TagScope tag(this, "ThisFunction");
1510}
1511
1512
1513void JsonAstBuilder::VisitDeclaration(Declaration* decl) {
1514  TagScope tag(this, "Declaration");
1515  {
1516    AttributesScope attributes(this);
1517    AddAttribute("mode", Variable::Mode2String(decl->mode()));
1518  }
1519  Visit(decl->proxy());
1520  if (decl->fun() != NULL) Visit(decl->fun());
1521}
1522
1523
1524#endif  // DEBUG
1525
1526} }  // namespace v8::internal
1527