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 | CallPrinter::CallPrinter(Isolate* isolate, bool is_user_js) |
21 | : builder_(new IncrementalStringBuilder(isolate)) { |
22 | isolate_ = isolate; |
23 | position_ = 0; |
24 | num_prints_ = 0; |
25 | found_ = false; |
26 | done_ = false; |
27 | is_call_error_ = false; |
28 | is_iterator_error_ = false; |
29 | is_async_iterator_error_ = false; |
30 | is_user_js_ = is_user_js; |
31 | function_kind_ = kNormalFunction; |
32 | InitializeAstVisitor(isolate); |
33 | } |
34 | |
35 | CallPrinter::~CallPrinter() = default; |
36 | |
37 | CallPrinter::ErrorHint CallPrinter::GetErrorHint() const { |
38 | if (is_call_error_) { |
39 | if (is_iterator_error_) return ErrorHint::kCallAndNormalIterator; |
40 | if (is_async_iterator_error_) return ErrorHint::kCallAndAsyncIterator; |
41 | } else { |
42 | if (is_iterator_error_) return ErrorHint::kNormalIterator; |
43 | if (is_async_iterator_error_) return ErrorHint::kAsyncIterator; |
44 | } |
45 | return ErrorHint::kNone; |
46 | } |
47 | |
48 | Handle<String> CallPrinter::Print(FunctionLiteral* program, int position) { |
49 | num_prints_ = 0; |
50 | position_ = position; |
51 | Find(program); |
52 | return builder_->Finish().ToHandleChecked(); |
53 | } |
54 | |
55 | |
56 | void CallPrinter::Find(AstNode* node, bool print) { |
57 | if (found_) { |
58 | if (print) { |
59 | int prev_num_prints = num_prints_; |
60 | Visit(node); |
61 | if (prev_num_prints != num_prints_) return; |
62 | } |
63 | Print("(intermediate value)" ); |
64 | } else { |
65 | Visit(node); |
66 | } |
67 | } |
68 | |
69 | void CallPrinter::Print(const char* str) { |
70 | if (!found_ || done_) return; |
71 | num_prints_++; |
72 | builder_->AppendCString(str); |
73 | } |
74 | |
75 | void CallPrinter::Print(Handle<String> str) { |
76 | if (!found_ || done_) return; |
77 | num_prints_++; |
78 | builder_->AppendString(str); |
79 | } |
80 | |
81 | void CallPrinter::VisitBlock(Block* node) { |
82 | FindStatements(node->statements()); |
83 | } |
84 | |
85 | |
86 | void CallPrinter::VisitVariableDeclaration(VariableDeclaration* node) {} |
87 | |
88 | |
89 | void CallPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) {} |
90 | |
91 | |
92 | void CallPrinter::VisitExpressionStatement(ExpressionStatement* node) { |
93 | Find(node->expression()); |
94 | } |
95 | |
96 | |
97 | void CallPrinter::VisitEmptyStatement(EmptyStatement* node) {} |
98 | |
99 | |
100 | void CallPrinter::VisitSloppyBlockFunctionStatement( |
101 | SloppyBlockFunctionStatement* node) { |
102 | Find(node->statement()); |
103 | } |
104 | |
105 | |
106 | void CallPrinter::VisitIfStatement(IfStatement* node) { |
107 | Find(node->condition()); |
108 | Find(node->then_statement()); |
109 | if (node->HasElseStatement()) { |
110 | Find(node->else_statement()); |
111 | } |
112 | } |
113 | |
114 | |
115 | void CallPrinter::VisitContinueStatement(ContinueStatement* node) {} |
116 | |
117 | |
118 | void CallPrinter::VisitBreakStatement(BreakStatement* node) {} |
119 | |
120 | |
121 | void CallPrinter::VisitReturnStatement(ReturnStatement* node) { |
122 | Find(node->expression()); |
123 | } |
124 | |
125 | |
126 | void CallPrinter::VisitWithStatement(WithStatement* node) { |
127 | Find(node->expression()); |
128 | Find(node->statement()); |
129 | } |
130 | |
131 | |
132 | void CallPrinter::VisitSwitchStatement(SwitchStatement* node) { |
133 | Find(node->tag()); |
134 | for (CaseClause* clause : *node->cases()) { |
135 | if (!clause->is_default()) Find(clause->label()); |
136 | FindStatements(clause->statements()); |
137 | } |
138 | } |
139 | |
140 | |
141 | void CallPrinter::VisitDoWhileStatement(DoWhileStatement* node) { |
142 | Find(node->body()); |
143 | Find(node->cond()); |
144 | } |
145 | |
146 | |
147 | void CallPrinter::VisitWhileStatement(WhileStatement* node) { |
148 | Find(node->cond()); |
149 | Find(node->body()); |
150 | } |
151 | |
152 | |
153 | void CallPrinter::VisitForStatement(ForStatement* node) { |
154 | if (node->init() != nullptr) { |
155 | Find(node->init()); |
156 | } |
157 | if (node->cond() != nullptr) Find(node->cond()); |
158 | if (node->next() != nullptr) Find(node->next()); |
159 | Find(node->body()); |
160 | } |
161 | |
162 | |
163 | void CallPrinter::VisitForInStatement(ForInStatement* node) { |
164 | Find(node->each()); |
165 | Find(node->subject()); |
166 | Find(node->body()); |
167 | } |
168 | |
169 | |
170 | void CallPrinter::VisitForOfStatement(ForOfStatement* node) { |
171 | Find(node->each()); |
172 | |
173 | // Check the subject's position in case there was a GetIterator error. |
174 | bool was_found = false; |
175 | if (node->subject()->position() == position_) { |
176 | is_async_iterator_error_ = node->type() == IteratorType::kAsync; |
177 | is_iterator_error_ = !is_async_iterator_error_; |
178 | was_found = !found_; |
179 | if (was_found) { |
180 | found_ = true; |
181 | } |
182 | } |
183 | Find(node->subject(), true); |
184 | if (was_found) { |
185 | done_ = true; |
186 | found_ = false; |
187 | } |
188 | |
189 | Find(node->body()); |
190 | } |
191 | |
192 | |
193 | void CallPrinter::VisitTryCatchStatement(TryCatchStatement* node) { |
194 | Find(node->try_block()); |
195 | Find(node->catch_block()); |
196 | } |
197 | |
198 | |
199 | void CallPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) { |
200 | Find(node->try_block()); |
201 | Find(node->finally_block()); |
202 | } |
203 | |
204 | |
205 | void CallPrinter::VisitDebuggerStatement(DebuggerStatement* node) {} |
206 | |
207 | |
208 | void CallPrinter::VisitFunctionLiteral(FunctionLiteral* node) { |
209 | FunctionKind last_function_kind = function_kind_; |
210 | function_kind_ = node->kind(); |
211 | FindStatements(node->body()); |
212 | function_kind_ = last_function_kind; |
213 | } |
214 | |
215 | |
216 | void CallPrinter::VisitClassLiteral(ClassLiteral* node) { |
217 | if (node->extends()) Find(node->extends()); |
218 | for (int i = 0; i < node->properties()->length(); i++) { |
219 | Find(node->properties()->at(i)->value()); |
220 | } |
221 | } |
222 | |
223 | void CallPrinter::( |
224 | InitializeClassMembersStatement* node) { |
225 | for (int i = 0; i < node->fields()->length(); i++) { |
226 | Find(node->fields()->at(i)->value()); |
227 | } |
228 | } |
229 | |
230 | void CallPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {} |
231 | |
232 | |
233 | void CallPrinter::VisitDoExpression(DoExpression* node) { Find(node->block()); } |
234 | |
235 | |
236 | void CallPrinter::VisitConditional(Conditional* node) { |
237 | Find(node->condition()); |
238 | Find(node->then_expression()); |
239 | Find(node->else_expression()); |
240 | } |
241 | |
242 | |
243 | void CallPrinter::VisitLiteral(Literal* node) { |
244 | // TODO(adamk): Teach Literal how to print its values without |
245 | // allocating on the heap. |
246 | PrintLiteral(node->BuildValue(isolate_), true); |
247 | } |
248 | |
249 | |
250 | void CallPrinter::VisitRegExpLiteral(RegExpLiteral* node) { |
251 | Print("/" ); |
252 | PrintLiteral(node->pattern(), false); |
253 | Print("/" ); |
254 | if (node->flags() & RegExp::kGlobal) Print("g" ); |
255 | if (node->flags() & RegExp::kIgnoreCase) Print("i" ); |
256 | if (node->flags() & RegExp::kMultiline) Print("m" ); |
257 | if (node->flags() & RegExp::kUnicode) Print("u" ); |
258 | if (node->flags() & RegExp::kSticky) Print("y" ); |
259 | } |
260 | |
261 | |
262 | void CallPrinter::VisitObjectLiteral(ObjectLiteral* node) { |
263 | Print("{" ); |
264 | for (int i = 0; i < node->properties()->length(); i++) { |
265 | Find(node->properties()->at(i)->value()); |
266 | } |
267 | Print("}" ); |
268 | } |
269 | |
270 | |
271 | void CallPrinter::VisitArrayLiteral(ArrayLiteral* node) { |
272 | Print("[" ); |
273 | for (int i = 0; i < node->values()->length(); i++) { |
274 | if (i != 0) Print("," ); |
275 | Expression* subexpr = node->values()->at(i); |
276 | Spread* spread = subexpr->AsSpread(); |
277 | if (spread != nullptr && !found_ && |
278 | position_ == spread->expression()->position()) { |
279 | found_ = true; |
280 | is_iterator_error_ = true; |
281 | Find(spread->expression(), true); |
282 | done_ = true; |
283 | return; |
284 | } |
285 | Find(subexpr, true); |
286 | } |
287 | Print("]" ); |
288 | } |
289 | |
290 | |
291 | void CallPrinter::VisitVariableProxy(VariableProxy* node) { |
292 | if (is_user_js_) { |
293 | PrintLiteral(node->name(), false); |
294 | } else { |
295 | // Variable names of non-user code are meaningless due to minification. |
296 | Print("(var)" ); |
297 | } |
298 | } |
299 | |
300 | |
301 | void CallPrinter::VisitAssignment(Assignment* node) { |
302 | Find(node->target()); |
303 | if (node->target()->IsArrayLiteral()) { |
304 | // Special case the visit for destructuring array assignment. |
305 | bool was_found = false; |
306 | if (node->value()->position() == position_) { |
307 | is_iterator_error_ = true; |
308 | was_found = !found_; |
309 | if (was_found) { |
310 | found_ = true; |
311 | } |
312 | } |
313 | Find(node->value(), true); |
314 | if (was_found) { |
315 | done_ = true; |
316 | found_ = false; |
317 | } |
318 | } else { |
319 | Find(node->value()); |
320 | } |
321 | } |
322 | |
323 | void CallPrinter::VisitCompoundAssignment(CompoundAssignment* node) { |
324 | VisitAssignment(node); |
325 | } |
326 | |
327 | void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); } |
328 | |
329 | void CallPrinter::VisitYieldStar(YieldStar* node) { |
330 | if (!found_ && position_ == node->expression()->position()) { |
331 | found_ = true; |
332 | if (IsAsyncFunction(function_kind_)) |
333 | is_async_iterator_error_ = true; |
334 | else |
335 | is_iterator_error_ = true; |
336 | Print("yield* " ); |
337 | } |
338 | Find(node->expression()); |
339 | } |
340 | |
341 | void CallPrinter::VisitAwait(Await* node) { Find(node->expression()); } |
342 | |
343 | void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); } |
344 | |
345 | |
346 | void CallPrinter::VisitProperty(Property* node) { |
347 | Expression* key = node->key(); |
348 | Literal* literal = key->AsLiteral(); |
349 | if (literal != nullptr && |
350 | literal->BuildValue(isolate_)->IsInternalizedString()) { |
351 | Find(node->obj(), true); |
352 | Print("." ); |
353 | // TODO(adamk): Teach Literal how to print its values without |
354 | // allocating on the heap. |
355 | PrintLiteral(literal->BuildValue(isolate_), false); |
356 | } else { |
357 | Find(node->obj(), true); |
358 | Print("[" ); |
359 | Find(key, true); |
360 | Print("]" ); |
361 | } |
362 | } |
363 | |
364 | void CallPrinter::VisitResolvedProperty(ResolvedProperty* node) {} |
365 | |
366 | void CallPrinter::VisitCall(Call* node) { |
367 | bool was_found = false; |
368 | if (node->position() == position_) { |
369 | is_call_error_ = true; |
370 | was_found = !found_; |
371 | } |
372 | 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 | if (!is_user_js_ && node->expression()->IsVariableProxy()) { |
376 | done_ = true; |
377 | return; |
378 | } |
379 | found_ = true; |
380 | } |
381 | Find(node->expression(), true); |
382 | if (!was_found && !is_iterator_error_) Print("(...)" ); |
383 | FindArguments(node->arguments()); |
384 | if (was_found) { |
385 | done_ = true; |
386 | found_ = false; |
387 | } |
388 | } |
389 | |
390 | |
391 | void CallPrinter::VisitCallNew(CallNew* node) { |
392 | bool was_found = false; |
393 | if (node->position() == position_) { |
394 | is_call_error_ = true; |
395 | was_found = !found_; |
396 | } |
397 | 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 | if (!is_user_js_ && node->expression()->IsVariableProxy()) { |
401 | done_ = true; |
402 | return; |
403 | } |
404 | found_ = true; |
405 | } |
406 | Find(node->expression(), was_found || is_iterator_error_); |
407 | FindArguments(node->arguments()); |
408 | if (was_found) { |
409 | done_ = true; |
410 | found_ = false; |
411 | } |
412 | } |
413 | |
414 | |
415 | void CallPrinter::VisitCallRuntime(CallRuntime* node) { |
416 | FindArguments(node->arguments()); |
417 | } |
418 | |
419 | |
420 | void CallPrinter::VisitUnaryOperation(UnaryOperation* node) { |
421 | Token::Value op = node->op(); |
422 | bool needsSpace = |
423 | op == Token::DELETE || op == Token::TYPEOF || op == Token::VOID; |
424 | Print("(" ); |
425 | Print(Token::String(op)); |
426 | if (needsSpace) Print(" " ); |
427 | Find(node->expression(), true); |
428 | Print(")" ); |
429 | } |
430 | |
431 | |
432 | void CallPrinter::VisitCountOperation(CountOperation* node) { |
433 | Print("(" ); |
434 | if (node->is_prefix()) Print(Token::String(node->op())); |
435 | Find(node->expression(), true); |
436 | if (node->is_postfix()) Print(Token::String(node->op())); |
437 | Print(")" ); |
438 | } |
439 | |
440 | |
441 | void CallPrinter::VisitBinaryOperation(BinaryOperation* node) { |
442 | Print("(" ); |
443 | Find(node->left(), true); |
444 | Print(" " ); |
445 | Print(Token::String(node->op())); |
446 | Print(" " ); |
447 | Find(node->right(), true); |
448 | Print(")" ); |
449 | } |
450 | |
451 | void CallPrinter::VisitNaryOperation(NaryOperation* node) { |
452 | Print("(" ); |
453 | Find(node->first(), true); |
454 | for (size_t i = 0; i < node->subsequent_length(); ++i) { |
455 | Print(" " ); |
456 | Print(Token::String(node->op())); |
457 | Print(" " ); |
458 | Find(node->subsequent(i), true); |
459 | } |
460 | Print(")" ); |
461 | } |
462 | |
463 | void CallPrinter::VisitCompareOperation(CompareOperation* node) { |
464 | Print("(" ); |
465 | Find(node->left(), true); |
466 | Print(" " ); |
467 | Print(Token::String(node->op())); |
468 | Print(" " ); |
469 | Find(node->right(), true); |
470 | Print(")" ); |
471 | } |
472 | |
473 | |
474 | void CallPrinter::VisitSpread(Spread* node) { |
475 | Print("(..." ); |
476 | Find(node->expression(), true); |
477 | Print(")" ); |
478 | } |
479 | |
480 | void CallPrinter::VisitStoreInArrayLiteral(StoreInArrayLiteral* node) { |
481 | Find(node->array()); |
482 | Find(node->index()); |
483 | Find(node->value()); |
484 | } |
485 | |
486 | void CallPrinter::VisitEmptyParentheses(EmptyParentheses* node) { |
487 | UNREACHABLE(); |
488 | } |
489 | |
490 | void CallPrinter::VisitGetTemplateObject(GetTemplateObject* node) {} |
491 | |
492 | void CallPrinter::VisitTemplateLiteral(TemplateLiteral* node) { |
493 | for (Expression* substitution : *node->substitutions()) { |
494 | Find(substitution, true); |
495 | } |
496 | } |
497 | |
498 | void CallPrinter::VisitImportCallExpression(ImportCallExpression* node) { |
499 | Print("ImportCall(" ); |
500 | Find(node->argument(), true); |
501 | Print(")" ); |
502 | } |
503 | |
504 | void CallPrinter::VisitThisExpression(ThisExpression* node) { Print("this" ); } |
505 | |
506 | void CallPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {} |
507 | |
508 | |
509 | void CallPrinter::VisitSuperCallReference(SuperCallReference* node) { |
510 | Print("super" ); |
511 | } |
512 | |
513 | |
514 | void CallPrinter::FindStatements(const ZonePtrList<Statement>* statements) { |
515 | if (statements == nullptr) return; |
516 | for (int i = 0; i < statements->length(); i++) { |
517 | Find(statements->at(i)); |
518 | } |
519 | } |
520 | |
521 | void CallPrinter::FindArguments(const ZonePtrList<Expression>* arguments) { |
522 | if (found_) return; |
523 | for (int i = 0; i < arguments->length(); i++) { |
524 | Find(arguments->at(i)); |
525 | } |
526 | } |
527 | |
528 | void CallPrinter::PrintLiteral(Handle<Object> value, bool quote) { |
529 | if (value->IsString()) { |
530 | if (quote) Print("\"" ); |
531 | Print(Handle<String>::cast(value)); |
532 | if (quote) Print("\"" ); |
533 | } else if (value->IsNull(isolate_)) { |
534 | Print("null" ); |
535 | } else if (value->IsTrue(isolate_)) { |
536 | Print("true" ); |
537 | } else if (value->IsFalse(isolate_)) { |
538 | Print("false" ); |
539 | } else if (value->IsUndefined(isolate_)) { |
540 | Print("undefined" ); |
541 | } else if (value->IsNumber()) { |
542 | Print(isolate_->factory()->NumberToString(value)); |
543 | } else if (value->IsSymbol()) { |
544 | // Symbols can only occur as literals if they were inserted by the parser. |
545 | PrintLiteral(handle(Handle<Symbol>::cast(value)->name(), isolate_), false); |
546 | } |
547 | } |
548 | |
549 | |
550 | void CallPrinter::PrintLiteral(const AstRawString* value, bool quote) { |
551 | PrintLiteral(value->string(), quote); |
552 | } |
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::( |
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 | } // namespace v8 |
1412 | |