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