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