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