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