OLD | NEW |
| (Empty) |
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/prettyprinter.h" | |
6 | |
7 #include <stdarg.h> | |
8 | |
9 #include "src/ast-value-factory.h" | |
10 #include "src/base/platform/platform.h" | |
11 #include "src/scopes.h" | |
12 | |
13 namespace v8 { | |
14 namespace internal { | |
15 | |
16 CallPrinter::CallPrinter(Isolate* isolate) { | |
17 output_ = NULL; | |
18 size_ = 0; | |
19 pos_ = 0; | |
20 position_ = 0; | |
21 found_ = false; | |
22 done_ = false; | |
23 InitializeAstVisitor(isolate); | |
24 } | |
25 | |
26 | |
27 CallPrinter::~CallPrinter() { DeleteArray(output_); } | |
28 | |
29 | |
30 const char* CallPrinter::Print(FunctionLiteral* program, int position) { | |
31 Init(); | |
32 position_ = position; | |
33 Find(program); | |
34 return output_; | |
35 } | |
36 | |
37 | |
38 void CallPrinter::Find(AstNode* node, bool print) { | |
39 if (done_) return; | |
40 if (found_) { | |
41 if (print) { | |
42 int start = pos_; | |
43 Visit(node); | |
44 if (start != pos_) return; | |
45 } | |
46 Print("(intermediate value)"); | |
47 } else { | |
48 Visit(node); | |
49 } | |
50 } | |
51 | |
52 | |
53 void CallPrinter::Init() { | |
54 if (size_ == 0) { | |
55 DCHECK(output_ == NULL); | |
56 const int initial_size = 256; | |
57 output_ = NewArray<char>(initial_size); | |
58 size_ = initial_size; | |
59 } | |
60 output_[0] = '\0'; | |
61 pos_ = 0; | |
62 } | |
63 | |
64 | |
65 void CallPrinter::Print(const char* format, ...) { | |
66 if (!found_ || done_) return; | |
67 for (;;) { | |
68 va_list arguments; | |
69 va_start(arguments, format); | |
70 int n = VSNPrintF(Vector<char>(output_, size_) + pos_, format, arguments); | |
71 va_end(arguments); | |
72 | |
73 if (n >= 0) { | |
74 // there was enough space - we are done | |
75 pos_ += n; | |
76 return; | |
77 } else { | |
78 // there was not enough space - allocate more and try again | |
79 const int slack = 32; | |
80 int new_size = size_ + (size_ >> 1) + slack; | |
81 char* new_output = NewArray<char>(new_size); | |
82 MemCopy(new_output, output_, pos_); | |
83 DeleteArray(output_); | |
84 output_ = new_output; | |
85 size_ = new_size; | |
86 } | |
87 } | |
88 } | |
89 | |
90 | |
91 void CallPrinter::VisitBlock(Block* node) { | |
92 FindStatements(node->statements()); | |
93 } | |
94 | |
95 | |
96 void CallPrinter::VisitVariableDeclaration(VariableDeclaration* node) {} | |
97 | |
98 | |
99 void CallPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) {} | |
100 | |
101 | |
102 void CallPrinter::VisitImportDeclaration(ImportDeclaration* node) { | |
103 } | |
104 | |
105 | |
106 void CallPrinter::VisitExportDeclaration(ExportDeclaration* node) {} | |
107 | |
108 | |
109 void CallPrinter::VisitExpressionStatement(ExpressionStatement* node) { | |
110 Find(node->expression()); | |
111 } | |
112 | |
113 | |
114 void CallPrinter::VisitEmptyStatement(EmptyStatement* node) {} | |
115 | |
116 | |
117 void CallPrinter::VisitSloppyBlockFunctionStatement( | |
118 SloppyBlockFunctionStatement* node) { | |
119 Find(node->statement()); | |
120 } | |
121 | |
122 | |
123 void CallPrinter::VisitIfStatement(IfStatement* node) { | |
124 Find(node->condition()); | |
125 Find(node->then_statement()); | |
126 if (node->HasElseStatement()) { | |
127 Find(node->else_statement()); | |
128 } | |
129 } | |
130 | |
131 | |
132 void CallPrinter::VisitContinueStatement(ContinueStatement* node) {} | |
133 | |
134 | |
135 void CallPrinter::VisitBreakStatement(BreakStatement* node) {} | |
136 | |
137 | |
138 void CallPrinter::VisitReturnStatement(ReturnStatement* node) { | |
139 Find(node->expression()); | |
140 } | |
141 | |
142 | |
143 void CallPrinter::VisitWithStatement(WithStatement* node) { | |
144 Find(node->expression()); | |
145 Find(node->statement()); | |
146 } | |
147 | |
148 | |
149 void CallPrinter::VisitSwitchStatement(SwitchStatement* node) { | |
150 Find(node->tag()); | |
151 ZoneList<CaseClause*>* cases = node->cases(); | |
152 for (int i = 0; i < cases->length(); i++) Find(cases->at(i)); | |
153 } | |
154 | |
155 | |
156 void CallPrinter::VisitCaseClause(CaseClause* clause) { | |
157 if (!clause->is_default()) { | |
158 Find(clause->label()); | |
159 } | |
160 FindStatements(clause->statements()); | |
161 } | |
162 | |
163 | |
164 void CallPrinter::VisitDoWhileStatement(DoWhileStatement* node) { | |
165 Find(node->body()); | |
166 Find(node->cond()); | |
167 } | |
168 | |
169 | |
170 void CallPrinter::VisitWhileStatement(WhileStatement* node) { | |
171 Find(node->cond()); | |
172 Find(node->body()); | |
173 } | |
174 | |
175 | |
176 void CallPrinter::VisitForStatement(ForStatement* node) { | |
177 if (node->init() != NULL) { | |
178 Find(node->init()); | |
179 } | |
180 if (node->cond() != NULL) Find(node->cond()); | |
181 if (node->next() != NULL) Find(node->next()); | |
182 Find(node->body()); | |
183 } | |
184 | |
185 | |
186 void CallPrinter::VisitForInStatement(ForInStatement* node) { | |
187 Find(node->each()); | |
188 Find(node->enumerable()); | |
189 Find(node->body()); | |
190 } | |
191 | |
192 | |
193 void CallPrinter::VisitForOfStatement(ForOfStatement* node) { | |
194 Find(node->each()); | |
195 Find(node->iterable()); | |
196 Find(node->body()); | |
197 } | |
198 | |
199 | |
200 void CallPrinter::VisitTryCatchStatement(TryCatchStatement* node) { | |
201 Find(node->try_block()); | |
202 Find(node->catch_block()); | |
203 } | |
204 | |
205 | |
206 void CallPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) { | |
207 Find(node->try_block()); | |
208 Find(node->finally_block()); | |
209 } | |
210 | |
211 | |
212 void CallPrinter::VisitDebuggerStatement(DebuggerStatement* node) {} | |
213 | |
214 | |
215 void CallPrinter::VisitFunctionLiteral(FunctionLiteral* node) { | |
216 FindStatements(node->body()); | |
217 } | |
218 | |
219 | |
220 void CallPrinter::VisitClassLiteral(ClassLiteral* node) { | |
221 if (node->extends()) Find(node->extends()); | |
222 for (int i = 0; i < node->properties()->length(); i++) { | |
223 Find(node->properties()->at(i)->value()); | |
224 } | |
225 } | |
226 | |
227 | |
228 void CallPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) {} | |
229 | |
230 | |
231 void CallPrinter::VisitDoExpression(DoExpression* node) { Find(node->block()); } | |
232 | |
233 | |
234 void CallPrinter::VisitConditional(Conditional* node) { | |
235 Find(node->condition()); | |
236 Find(node->then_expression()); | |
237 Find(node->else_expression()); | |
238 } | |
239 | |
240 | |
241 void CallPrinter::VisitLiteral(Literal* node) { | |
242 PrintLiteral(node->value(), true); | |
243 } | |
244 | |
245 | |
246 void CallPrinter::VisitRegExpLiteral(RegExpLiteral* node) { | |
247 Print("/"); | |
248 PrintLiteral(node->pattern(), false); | |
249 Print("/"); | |
250 if (node->flags() & RegExp::kGlobal) Print("g"); | |
251 if (node->flags() & RegExp::kIgnoreCase) Print("i"); | |
252 if (node->flags() & RegExp::kMultiline) Print("m"); | |
253 if (node->flags() & RegExp::kUnicode) Print("u"); | |
254 if (node->flags() & RegExp::kSticky) Print("y"); | |
255 } | |
256 | |
257 | |
258 void CallPrinter::VisitObjectLiteral(ObjectLiteral* node) { | |
259 for (int i = 0; i < node->properties()->length(); i++) { | |
260 Find(node->properties()->at(i)->value()); | |
261 } | |
262 } | |
263 | |
264 | |
265 void CallPrinter::VisitArrayLiteral(ArrayLiteral* node) { | |
266 Print("["); | |
267 for (int i = 0; i < node->values()->length(); i++) { | |
268 if (i != 0) Print(","); | |
269 Find(node->values()->at(i), true); | |
270 } | |
271 Print("]"); | |
272 } | |
273 | |
274 | |
275 void CallPrinter::VisitVariableProxy(VariableProxy* node) { | |
276 PrintLiteral(node->name(), false); | |
277 } | |
278 | |
279 | |
280 void CallPrinter::VisitAssignment(Assignment* node) { | |
281 Find(node->target()); | |
282 Find(node->value()); | |
283 } | |
284 | |
285 | |
286 void CallPrinter::VisitYield(Yield* node) { Find(node->expression()); } | |
287 | |
288 | |
289 void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); } | |
290 | |
291 | |
292 void CallPrinter::VisitProperty(Property* node) { | |
293 Expression* key = node->key(); | |
294 Literal* literal = key->AsLiteral(); | |
295 if (literal != NULL && literal->value()->IsInternalizedString()) { | |
296 Find(node->obj(), true); | |
297 Print("."); | |
298 PrintLiteral(literal->value(), false); | |
299 } else { | |
300 Find(node->obj(), true); | |
301 Print("["); | |
302 Find(key, true); | |
303 Print("]"); | |
304 } | |
305 } | |
306 | |
307 | |
308 void CallPrinter::VisitCall(Call* node) { | |
309 bool was_found = !found_ && node->position() == position_; | |
310 if (was_found) found_ = true; | |
311 Find(node->expression(), true); | |
312 if (!was_found) Print("(...)"); | |
313 FindArguments(node->arguments()); | |
314 if (was_found) done_ = true; | |
315 } | |
316 | |
317 | |
318 void CallPrinter::VisitCallNew(CallNew* node) { | |
319 bool was_found = !found_ && node->position() == position_; | |
320 if (was_found) found_ = true; | |
321 Find(node->expression(), was_found); | |
322 FindArguments(node->arguments()); | |
323 if (was_found) done_ = true; | |
324 } | |
325 | |
326 | |
327 void CallPrinter::VisitCallRuntime(CallRuntime* node) { | |
328 if (!node->is_jsruntime() && | |
329 node->function() == | |
330 Runtime::FunctionForId(Runtime::kInlineDefaultConstructorCallSuper)) { | |
331 found_ = true; | |
332 Print("super"); | |
333 done_ = true; | |
334 return; | |
335 } | |
336 FindArguments(node->arguments()); | |
337 } | |
338 | |
339 | |
340 void CallPrinter::VisitUnaryOperation(UnaryOperation* node) { | |
341 Token::Value op = node->op(); | |
342 bool needsSpace = | |
343 op == Token::DELETE || op == Token::TYPEOF || op == Token::VOID; | |
344 Print("(%s%s", Token::String(op), needsSpace ? " " : ""); | |
345 Find(node->expression(), true); | |
346 Print(")"); | |
347 } | |
348 | |
349 | |
350 void CallPrinter::VisitCountOperation(CountOperation* node) { | |
351 Print("("); | |
352 if (node->is_prefix()) Print("%s", Token::String(node->op())); | |
353 Find(node->expression(), true); | |
354 if (node->is_postfix()) Print("%s", Token::String(node->op())); | |
355 Print(")"); | |
356 } | |
357 | |
358 | |
359 void CallPrinter::VisitBinaryOperation(BinaryOperation* node) { | |
360 Print("("); | |
361 Find(node->left(), true); | |
362 Print(" %s ", Token::String(node->op())); | |
363 Find(node->right(), true); | |
364 Print(")"); | |
365 } | |
366 | |
367 | |
368 void CallPrinter::VisitCompareOperation(CompareOperation* node) { | |
369 Print("("); | |
370 Find(node->left(), true); | |
371 Print(" %s ", Token::String(node->op())); | |
372 Find(node->right(), true); | |
373 Print(")"); | |
374 } | |
375 | |
376 | |
377 void CallPrinter::VisitSpread(Spread* node) { | |
378 Print("(..."); | |
379 Find(node->expression(), true); | |
380 Print(")"); | |
381 } | |
382 | |
383 | |
384 void CallPrinter::VisitEmptyParentheses(EmptyParentheses* node) { | |
385 UNREACHABLE(); | |
386 } | |
387 | |
388 | |
389 void CallPrinter::VisitThisFunction(ThisFunction* node) {} | |
390 | |
391 | |
392 void CallPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {} | |
393 | |
394 | |
395 void CallPrinter::VisitSuperCallReference(SuperCallReference* node) { | |
396 Print("super"); | |
397 } | |
398 | |
399 | |
400 void CallPrinter::FindStatements(ZoneList<Statement*>* statements) { | |
401 if (statements == NULL) return; | |
402 for (int i = 0; i < statements->length(); i++) { | |
403 Find(statements->at(i)); | |
404 } | |
405 } | |
406 | |
407 | |
408 void CallPrinter::FindArguments(ZoneList<Expression*>* arguments) { | |
409 if (found_) return; | |
410 for (int i = 0; i < arguments->length(); i++) { | |
411 Find(arguments->at(i)); | |
412 } | |
413 } | |
414 | |
415 | |
416 void CallPrinter::PrintLiteral(Handle<Object> value, bool quote) { | |
417 Object* object = *value; | |
418 if (object->IsString()) { | |
419 String* string = String::cast(object); | |
420 if (quote) Print("\""); | |
421 for (int i = 0; i < string->length(); i++) { | |
422 Print("%c", string->Get(i)); | |
423 } | |
424 if (quote) Print("\""); | |
425 } else if (object->IsNull()) { | |
426 Print("null"); | |
427 } else if (object->IsTrue()) { | |
428 Print("true"); | |
429 } else if (object->IsFalse()) { | |
430 Print("false"); | |
431 } else if (object->IsUndefined()) { | |
432 Print("undefined"); | |
433 } else if (object->IsNumber()) { | |
434 Print("%g", object->Number()); | |
435 } | |
436 } | |
437 | |
438 | |
439 void CallPrinter::PrintLiteral(const AstRawString* value, bool quote) { | |
440 PrintLiteral(value->string(), quote); | |
441 } | |
442 | |
443 | |
444 //----------------------------------------------------------------------------- | |
445 | |
446 | |
447 #ifdef DEBUG | |
448 | |
449 // A helper for ast nodes that use FeedbackVectorSlots. | |
450 static int FormatSlotNode(Vector<char>* buf, Expression* node, | |
451 const char* node_name, FeedbackVectorSlot slot) { | |
452 int pos = SNPrintF(*buf, "%s", node_name); | |
453 if (!slot.IsInvalid()) { | |
454 pos = SNPrintF(*buf + pos, " Slot(%d)", slot.ToInt()); | |
455 } | |
456 return pos; | |
457 } | |
458 | |
459 | |
460 PrettyPrinter::PrettyPrinter(Isolate* isolate) { | |
461 output_ = NULL; | |
462 size_ = 0; | |
463 pos_ = 0; | |
464 InitializeAstVisitor(isolate); | |
465 } | |
466 | |
467 | |
468 PrettyPrinter::~PrettyPrinter() { | |
469 DeleteArray(output_); | |
470 } | |
471 | |
472 | |
473 void PrettyPrinter::VisitBlock(Block* node) { | |
474 if (!node->ignore_completion_value()) Print("{ "); | |
475 PrintStatements(node->statements()); | |
476 if (node->statements()->length() > 0) Print(" "); | |
477 if (!node->ignore_completion_value()) Print("}"); | |
478 } | |
479 | |
480 | |
481 void PrettyPrinter::VisitVariableDeclaration(VariableDeclaration* node) { | |
482 Print("var "); | |
483 PrintLiteral(node->proxy()->name(), false); | |
484 Print(";"); | |
485 } | |
486 | |
487 | |
488 void PrettyPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) { | |
489 Print("function "); | |
490 PrintLiteral(node->proxy()->name(), false); | |
491 Print(" = "); | |
492 PrintFunctionLiteral(node->fun()); | |
493 Print(";"); | |
494 } | |
495 | |
496 | |
497 void PrettyPrinter::VisitImportDeclaration(ImportDeclaration* node) { | |
498 Print("import "); | |
499 PrintLiteral(node->proxy()->name(), false); | |
500 Print(" from "); | |
501 PrintLiteral(node->module_specifier()->string(), true); | |
502 Print(";"); | |
503 } | |
504 | |
505 | |
506 void PrettyPrinter::VisitExportDeclaration(ExportDeclaration* node) { | |
507 Print("export "); | |
508 PrintLiteral(node->proxy()->name(), false); | |
509 Print(";"); | |
510 } | |
511 | |
512 | |
513 void PrettyPrinter::VisitExpressionStatement(ExpressionStatement* node) { | |
514 Visit(node->expression()); | |
515 Print(";"); | |
516 } | |
517 | |
518 | |
519 void PrettyPrinter::VisitEmptyStatement(EmptyStatement* node) { | |
520 Print(";"); | |
521 } | |
522 | |
523 | |
524 void PrettyPrinter::VisitSloppyBlockFunctionStatement( | |
525 SloppyBlockFunctionStatement* node) { | |
526 Visit(node->statement()); | |
527 } | |
528 | |
529 | |
530 void PrettyPrinter::VisitIfStatement(IfStatement* node) { | |
531 Print("if ("); | |
532 Visit(node->condition()); | |
533 Print(") "); | |
534 Visit(node->then_statement()); | |
535 if (node->HasElseStatement()) { | |
536 Print(" else "); | |
537 Visit(node->else_statement()); | |
538 } | |
539 } | |
540 | |
541 | |
542 void PrettyPrinter::VisitContinueStatement(ContinueStatement* node) { | |
543 Print("continue"); | |
544 ZoneList<const AstRawString*>* labels = node->target()->labels(); | |
545 if (labels != NULL) { | |
546 Print(" "); | |
547 DCHECK(labels->length() > 0); // guaranteed to have at least one entry | |
548 PrintLiteral(labels->at(0), false); // any label from the list is fine | |
549 } | |
550 Print(";"); | |
551 } | |
552 | |
553 | |
554 void PrettyPrinter::VisitBreakStatement(BreakStatement* node) { | |
555 Print("break"); | |
556 ZoneList<const AstRawString*>* labels = node->target()->labels(); | |
557 if (labels != NULL) { | |
558 Print(" "); | |
559 DCHECK(labels->length() > 0); // guaranteed to have at least one entry | |
560 PrintLiteral(labels->at(0), false); // any label from the list is fine | |
561 } | |
562 Print(";"); | |
563 } | |
564 | |
565 | |
566 void PrettyPrinter::VisitReturnStatement(ReturnStatement* node) { | |
567 Print("return "); | |
568 Visit(node->expression()); | |
569 Print(";"); | |
570 } | |
571 | |
572 | |
573 void PrettyPrinter::VisitWithStatement(WithStatement* node) { | |
574 Print("with ("); | |
575 Visit(node->expression()); | |
576 Print(") "); | |
577 Visit(node->statement()); | |
578 } | |
579 | |
580 | |
581 void PrettyPrinter::VisitSwitchStatement(SwitchStatement* node) { | |
582 PrintLabels(node->labels()); | |
583 Print("switch ("); | |
584 Visit(node->tag()); | |
585 Print(") { "); | |
586 ZoneList<CaseClause*>* cases = node->cases(); | |
587 for (int i = 0; i < cases->length(); i++) | |
588 Visit(cases->at(i)); | |
589 Print("}"); | |
590 } | |
591 | |
592 | |
593 void PrettyPrinter::VisitCaseClause(CaseClause* clause) { | |
594 if (clause->is_default()) { | |
595 Print("default"); | |
596 } else { | |
597 Print("case "); | |
598 Visit(clause->label()); | |
599 } | |
600 Print(": "); | |
601 PrintStatements(clause->statements()); | |
602 if (clause->statements()->length() > 0) | |
603 Print(" "); | |
604 } | |
605 | |
606 | |
607 void PrettyPrinter::VisitDoWhileStatement(DoWhileStatement* node) { | |
608 PrintLabels(node->labels()); | |
609 Print("do "); | |
610 Visit(node->body()); | |
611 Print(" while ("); | |
612 Visit(node->cond()); | |
613 Print(");"); | |
614 } | |
615 | |
616 | |
617 void PrettyPrinter::VisitWhileStatement(WhileStatement* node) { | |
618 PrintLabels(node->labels()); | |
619 Print("while ("); | |
620 Visit(node->cond()); | |
621 Print(") "); | |
622 Visit(node->body()); | |
623 } | |
624 | |
625 | |
626 void PrettyPrinter::VisitForStatement(ForStatement* node) { | |
627 PrintLabels(node->labels()); | |
628 Print("for ("); | |
629 if (node->init() != NULL) { | |
630 Visit(node->init()); | |
631 Print(" "); | |
632 } else { | |
633 Print("; "); | |
634 } | |
635 if (node->cond() != NULL) Visit(node->cond()); | |
636 Print("; "); | |
637 if (node->next() != NULL) { | |
638 Visit(node->next()); // prints extra ';', unfortunately | |
639 // to fix: should use Expression for next | |
640 } | |
641 Print(") "); | |
642 Visit(node->body()); | |
643 } | |
644 | |
645 | |
646 void PrettyPrinter::VisitForInStatement(ForInStatement* node) { | |
647 PrintLabels(node->labels()); | |
648 Print("for ("); | |
649 Visit(node->each()); | |
650 Print(" in "); | |
651 Visit(node->enumerable()); | |
652 Print(") "); | |
653 Visit(node->body()); | |
654 } | |
655 | |
656 | |
657 void PrettyPrinter::VisitForOfStatement(ForOfStatement* node) { | |
658 PrintLabels(node->labels()); | |
659 Print("for ("); | |
660 Visit(node->each()); | |
661 Print(" of "); | |
662 Visit(node->iterable()); | |
663 Print(") "); | |
664 Visit(node->body()); | |
665 } | |
666 | |
667 | |
668 void PrettyPrinter::VisitTryCatchStatement(TryCatchStatement* node) { | |
669 Print("try "); | |
670 Visit(node->try_block()); | |
671 Print(" catch ("); | |
672 const bool quote = false; | |
673 PrintLiteral(node->variable()->name(), quote); | |
674 Print(") "); | |
675 Visit(node->catch_block()); | |
676 } | |
677 | |
678 | |
679 void PrettyPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) { | |
680 Print("try "); | |
681 Visit(node->try_block()); | |
682 Print(" finally "); | |
683 Visit(node->finally_block()); | |
684 } | |
685 | |
686 | |
687 void PrettyPrinter::VisitDebuggerStatement(DebuggerStatement* node) { | |
688 Print("debugger "); | |
689 } | |
690 | |
691 | |
692 void PrettyPrinter::VisitFunctionLiteral(FunctionLiteral* node) { | |
693 Print("("); | |
694 PrintFunctionLiteral(node); | |
695 Print(")"); | |
696 } | |
697 | |
698 | |
699 void PrettyPrinter::VisitClassLiteral(ClassLiteral* node) { | |
700 Print("(class "); | |
701 PrintLiteral(node->name(), false); | |
702 if (node->extends()) { | |
703 Print(" extends "); | |
704 Visit(node->extends()); | |
705 } | |
706 Print(" { "); | |
707 for (int i = 0; i < node->properties()->length(); i++) { | |
708 PrintObjectLiteralProperty(node->properties()->at(i)); | |
709 } | |
710 Print(" })"); | |
711 } | |
712 | |
713 | |
714 void PrettyPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) { | |
715 Print("("); | |
716 PrintLiteral(node->name(), false); | |
717 Print(")"); | |
718 } | |
719 | |
720 | |
721 void PrettyPrinter::VisitDoExpression(DoExpression* node) { | |
722 Print("(do {"); | |
723 PrintStatements(node->block()->statements()); | |
724 Print("})"); | |
725 } | |
726 | |
727 | |
728 void PrettyPrinter::VisitConditional(Conditional* node) { | |
729 Visit(node->condition()); | |
730 Print(" ? "); | |
731 Visit(node->then_expression()); | |
732 Print(" : "); | |
733 Visit(node->else_expression()); | |
734 } | |
735 | |
736 | |
737 void PrettyPrinter::VisitLiteral(Literal* node) { | |
738 PrintLiteral(node->value(), true); | |
739 } | |
740 | |
741 | |
742 void PrettyPrinter::VisitRegExpLiteral(RegExpLiteral* node) { | |
743 Print(" RegExp("); | |
744 PrintLiteral(node->pattern(), false); | |
745 Print(","); | |
746 if (node->flags() & RegExp::kGlobal) Print("g"); | |
747 if (node->flags() & RegExp::kIgnoreCase) Print("i"); | |
748 if (node->flags() & RegExp::kMultiline) Print("m"); | |
749 if (node->flags() & RegExp::kUnicode) Print("u"); | |
750 if (node->flags() & RegExp::kSticky) Print("y"); | |
751 Print(") "); | |
752 } | |
753 | |
754 | |
755 void PrettyPrinter::VisitObjectLiteral(ObjectLiteral* node) { | |
756 Print("{ "); | |
757 for (int i = 0; i < node->properties()->length(); i++) { | |
758 if (i != 0) Print(","); | |
759 PrintObjectLiteralProperty(node->properties()->at(i)); | |
760 } | |
761 Print(" }"); | |
762 } | |
763 | |
764 | |
765 void PrettyPrinter::PrintObjectLiteralProperty( | |
766 ObjectLiteralProperty* property) { | |
767 // TODO(arv): Better printing of methods etc. | |
768 Print(" "); | |
769 Visit(property->key()); | |
770 Print(": "); | |
771 Visit(property->value()); | |
772 } | |
773 | |
774 | |
775 void PrettyPrinter::VisitArrayLiteral(ArrayLiteral* node) { | |
776 Print("[ "); | |
777 Print(" literal_index = %d", node->literal_index()); | |
778 for (int i = 0; i < node->values()->length(); i++) { | |
779 if (i != 0) Print(","); | |
780 Visit(node->values()->at(i)); | |
781 } | |
782 Print(" ]"); | |
783 } | |
784 | |
785 | |
786 void PrettyPrinter::VisitVariableProxy(VariableProxy* node) { | |
787 PrintLiteral(node->name(), false); | |
788 } | |
789 | |
790 | |
791 void PrettyPrinter::VisitAssignment(Assignment* node) { | |
792 Visit(node->target()); | |
793 Print(" %s ", Token::String(node->op())); | |
794 Visit(node->value()); | |
795 } | |
796 | |
797 | |
798 void PrettyPrinter::VisitYield(Yield* node) { | |
799 Print("yield "); | |
800 Visit(node->expression()); | |
801 } | |
802 | |
803 | |
804 void PrettyPrinter::VisitThrow(Throw* node) { | |
805 Print("throw "); | |
806 Visit(node->exception()); | |
807 } | |
808 | |
809 | |
810 void PrettyPrinter::VisitProperty(Property* node) { | |
811 Expression* key = node->key(); | |
812 Literal* literal = key->AsLiteral(); | |
813 if (literal != NULL && literal->value()->IsInternalizedString()) { | |
814 Print("("); | |
815 Visit(node->obj()); | |
816 Print(")."); | |
817 PrintLiteral(literal->value(), false); | |
818 } else { | |
819 Visit(node->obj()); | |
820 Print("["); | |
821 Visit(key); | |
822 Print("]"); | |
823 } | |
824 } | |
825 | |
826 | |
827 void PrettyPrinter::VisitCall(Call* node) { | |
828 Visit(node->expression()); | |
829 PrintArguments(node->arguments()); | |
830 } | |
831 | |
832 | |
833 void PrettyPrinter::VisitCallNew(CallNew* node) { | |
834 Print("new ("); | |
835 Visit(node->expression()); | |
836 Print(")"); | |
837 PrintArguments(node->arguments()); | |
838 } | |
839 | |
840 | |
841 void PrettyPrinter::VisitCallRuntime(CallRuntime* node) { | |
842 Print("%%%s\n", node->debug_name()); | |
843 PrintArguments(node->arguments()); | |
844 } | |
845 | |
846 | |
847 void PrettyPrinter::VisitUnaryOperation(UnaryOperation* node) { | |
848 Token::Value op = node->op(); | |
849 bool needsSpace = | |
850 op == Token::DELETE || op == Token::TYPEOF || op == Token::VOID; | |
851 Print("(%s%s", Token::String(op), needsSpace ? " " : ""); | |
852 Visit(node->expression()); | |
853 Print(")"); | |
854 } | |
855 | |
856 | |
857 void PrettyPrinter::VisitCountOperation(CountOperation* node) { | |
858 Print("("); | |
859 if (node->is_prefix()) Print("%s", Token::String(node->op())); | |
860 Visit(node->expression()); | |
861 if (node->is_postfix()) Print("%s", Token::String(node->op())); | |
862 Print(")"); | |
863 } | |
864 | |
865 | |
866 void PrettyPrinter::VisitBinaryOperation(BinaryOperation* node) { | |
867 Print("("); | |
868 Visit(node->left()); | |
869 Print(" %s ", Token::String(node->op())); | |
870 Visit(node->right()); | |
871 Print(")"); | |
872 } | |
873 | |
874 | |
875 void PrettyPrinter::VisitCompareOperation(CompareOperation* node) { | |
876 Print("("); | |
877 Visit(node->left()); | |
878 Print(" %s ", Token::String(node->op())); | |
879 Visit(node->right()); | |
880 Print(")"); | |
881 } | |
882 | |
883 | |
884 void PrettyPrinter::VisitSpread(Spread* node) { | |
885 Print("(..."); | |
886 Visit(node->expression()); | |
887 Print(")"); | |
888 } | |
889 | |
890 | |
891 void PrettyPrinter::VisitEmptyParentheses(EmptyParentheses* node) { | |
892 Print("()"); | |
893 } | |
894 | |
895 | |
896 void PrettyPrinter::VisitThisFunction(ThisFunction* node) { | |
897 Print("<this-function>"); | |
898 } | |
899 | |
900 | |
901 void PrettyPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) { | |
902 Print("<super-property-reference>"); | |
903 } | |
904 | |
905 | |
906 void PrettyPrinter::VisitSuperCallReference(SuperCallReference* node) { | |
907 Print("<super-call-reference>"); | |
908 } | |
909 | |
910 | |
911 const char* PrettyPrinter::Print(AstNode* node) { | |
912 Init(); | |
913 Visit(node); | |
914 return output_; | |
915 } | |
916 | |
917 | |
918 const char* PrettyPrinter::PrintExpression(FunctionLiteral* program) { | |
919 Init(); | |
920 ExpressionStatement* statement = | |
921 program->body()->at(0)->AsExpressionStatement(); | |
922 Visit(statement->expression()); | |
923 return output_; | |
924 } | |
925 | |
926 | |
927 const char* PrettyPrinter::PrintProgram(FunctionLiteral* program) { | |
928 Init(); | |
929 PrintStatements(program->body()); | |
930 Print("\n"); | |
931 return output_; | |
932 } | |
933 | |
934 | |
935 void PrettyPrinter::PrintOut(Isolate* isolate, AstNode* node) { | |
936 PrettyPrinter printer(isolate); | |
937 PrintF("%s\n", printer.Print(node)); | |
938 } | |
939 | |
940 | |
941 void PrettyPrinter::Init() { | |
942 if (size_ == 0) { | |
943 DCHECK(output_ == NULL); | |
944 const int initial_size = 256; | |
945 output_ = NewArray<char>(initial_size); | |
946 size_ = initial_size; | |
947 } | |
948 output_[0] = '\0'; | |
949 pos_ = 0; | |
950 } | |
951 | |
952 | |
953 void PrettyPrinter::Print(const char* format, ...) { | |
954 for (;;) { | |
955 va_list arguments; | |
956 va_start(arguments, format); | |
957 int n = VSNPrintF(Vector<char>(output_, size_) + pos_, | |
958 format, | |
959 arguments); | |
960 va_end(arguments); | |
961 | |
962 if (n >= 0) { | |
963 // there was enough space - we are done | |
964 pos_ += n; | |
965 return; | |
966 } else { | |
967 // there was not enough space - allocate more and try again | |
968 const int slack = 32; | |
969 int new_size = size_ + (size_ >> 1) + slack; | |
970 char* new_output = NewArray<char>(new_size); | |
971 MemCopy(new_output, output_, pos_); | |
972 DeleteArray(output_); | |
973 output_ = new_output; | |
974 size_ = new_size; | |
975 } | |
976 } | |
977 } | |
978 | |
979 | |
980 void PrettyPrinter::PrintStatements(ZoneList<Statement*>* statements) { | |
981 if (statements == NULL) return; | |
982 for (int i = 0; i < statements->length(); i++) { | |
983 if (i != 0) Print(" "); | |
984 Visit(statements->at(i)); | |
985 } | |
986 } | |
987 | |
988 | |
989 void PrettyPrinter::PrintLabels(ZoneList<const AstRawString*>* labels) { | |
990 if (labels != NULL) { | |
991 for (int i = 0; i < labels->length(); i++) { | |
992 PrintLiteral(labels->at(i), false); | |
993 Print(": "); | |
994 } | |
995 } | |
996 } | |
997 | |
998 | |
999 void PrettyPrinter::PrintArguments(ZoneList<Expression*>* arguments) { | |
1000 Print("("); | |
1001 for (int i = 0; i < arguments->length(); i++) { | |
1002 if (i != 0) Print(", "); | |
1003 Visit(arguments->at(i)); | |
1004 } | |
1005 Print(")"); | |
1006 } | |
1007 | |
1008 | |
1009 void PrettyPrinter::PrintLiteral(Handle<Object> value, bool quote) { | |
1010 Object* object = *value; | |
1011 if (object->IsString()) { | |
1012 String* string = String::cast(object); | |
1013 if (quote) Print("\""); | |
1014 for (int i = 0; i < string->length(); i++) { | |
1015 Print("%c", string->Get(i)); | |
1016 } | |
1017 if (quote) Print("\""); | |
1018 } else if (object->IsNull()) { | |
1019 Print("null"); | |
1020 } else if (object->IsTrue()) { | |
1021 Print("true"); | |
1022 } else if (object->IsFalse()) { | |
1023 Print("false"); | |
1024 } else if (object->IsUndefined()) { | |
1025 Print("undefined"); | |
1026 } else if (object->IsNumber()) { | |
1027 Print("%g", object->Number()); | |
1028 } else if (object->IsJSObject()) { | |
1029 // regular expression | |
1030 if (object->IsJSFunction()) { | |
1031 Print("JS-Function"); | |
1032 } else if (object->IsJSArray()) { | |
1033 Print("JS-array[%u]", JSArray::cast(object)->length()); | |
1034 } else if (object->IsJSObject()) { | |
1035 Print("JS-Object"); | |
1036 } else { | |
1037 Print("?UNKNOWN?"); | |
1038 } | |
1039 } else if (object->IsFixedArray()) { | |
1040 Print("FixedArray"); | |
1041 } else { | |
1042 Print("<unknown literal %p>", object); | |
1043 } | |
1044 } | |
1045 | |
1046 | |
1047 void PrettyPrinter::PrintLiteral(const AstRawString* value, bool quote) { | |
1048 PrintLiteral(value->string(), quote); | |
1049 } | |
1050 | |
1051 | |
1052 void PrettyPrinter::PrintParameters(Scope* scope) { | |
1053 Print("("); | |
1054 for (int i = 0; i < scope->num_parameters(); i++) { | |
1055 if (i > 0) Print(", "); | |
1056 PrintLiteral(scope->parameter(i)->name(), false); | |
1057 } | |
1058 Print(")"); | |
1059 } | |
1060 | |
1061 | |
1062 void PrettyPrinter::PrintDeclarations(ZoneList<Declaration*>* declarations) { | |
1063 for (int i = 0; i < declarations->length(); i++) { | |
1064 if (i > 0) Print(" "); | |
1065 Visit(declarations->at(i)); | |
1066 } | |
1067 } | |
1068 | |
1069 | |
1070 void PrettyPrinter::PrintFunctionLiteral(FunctionLiteral* function) { | |
1071 Print("function "); | |
1072 PrintLiteral(function->name(), false); | |
1073 PrintParameters(function->scope()); | |
1074 Print(" { "); | |
1075 PrintDeclarations(function->scope()->declarations()); | |
1076 PrintStatements(function->body()); | |
1077 Print(" }"); | |
1078 } | |
1079 | |
1080 | |
1081 //----------------------------------------------------------------------------- | |
1082 | |
1083 class IndentedScope BASE_EMBEDDED { | |
1084 public: | |
1085 IndentedScope(AstPrinter* printer, const char* txt) | |
1086 : ast_printer_(printer) { | |
1087 ast_printer_->PrintIndented(txt); | |
1088 ast_printer_->Print("\n"); | |
1089 ast_printer_->inc_indent(); | |
1090 } | |
1091 | |
1092 IndentedScope(AstPrinter* printer, const char* txt, int pos) | |
1093 : ast_printer_(printer) { | |
1094 ast_printer_->PrintIndented(txt); | |
1095 ast_printer_->Print(" at %d\n", pos); | |
1096 ast_printer_->inc_indent(); | |
1097 } | |
1098 | |
1099 virtual ~IndentedScope() { | |
1100 ast_printer_->dec_indent(); | |
1101 } | |
1102 | |
1103 private: | |
1104 AstPrinter* ast_printer_; | |
1105 }; | |
1106 | |
1107 | |
1108 //----------------------------------------------------------------------------- | |
1109 | |
1110 | |
1111 AstPrinter::AstPrinter(Isolate* isolate) : PrettyPrinter(isolate), indent_(0) {} | |
1112 | |
1113 | |
1114 AstPrinter::~AstPrinter() { | |
1115 DCHECK(indent_ == 0); | |
1116 } | |
1117 | |
1118 | |
1119 void AstPrinter::PrintIndented(const char* txt) { | |
1120 for (int i = 0; i < indent_; i++) { | |
1121 Print(". "); | |
1122 } | |
1123 Print(txt); | |
1124 } | |
1125 | |
1126 | |
1127 void AstPrinter::PrintLiteralIndented(const char* info, | |
1128 Handle<Object> value, | |
1129 bool quote) { | |
1130 PrintIndented(info); | |
1131 Print(" "); | |
1132 PrintLiteral(value, quote); | |
1133 Print("\n"); | |
1134 } | |
1135 | |
1136 | |
1137 void AstPrinter::PrintLiteralWithModeIndented(const char* info, | |
1138 Variable* var, | |
1139 Handle<Object> value) { | |
1140 if (var == NULL) { | |
1141 PrintLiteralIndented(info, value, true); | |
1142 } else { | |
1143 EmbeddedVector<char, 256> buf; | |
1144 int pos = SNPrintF(buf, "%s (mode = %s", info, | |
1145 Variable::Mode2String(var->mode())); | |
1146 SNPrintF(buf + pos, ")"); | |
1147 PrintLiteralIndented(buf.start(), value, true); | |
1148 } | |
1149 } | |
1150 | |
1151 | |
1152 void AstPrinter::PrintLabelsIndented(ZoneList<const AstRawString*>* labels) { | |
1153 if (labels == NULL || labels->length() == 0) return; | |
1154 PrintIndented("LABELS "); | |
1155 PrintLabels(labels); | |
1156 Print("\n"); | |
1157 } | |
1158 | |
1159 | |
1160 void AstPrinter::PrintIndentedVisit(const char* s, AstNode* node) { | |
1161 IndentedScope indent(this, s, node->position()); | |
1162 Visit(node); | |
1163 } | |
1164 | |
1165 | |
1166 const char* AstPrinter::PrintProgram(FunctionLiteral* program) { | |
1167 Init(); | |
1168 { IndentedScope indent(this, "FUNC", program->position()); | |
1169 PrintLiteralIndented("NAME", program->name(), true); | |
1170 PrintLiteralIndented("INFERRED NAME", program->inferred_name(), true); | |
1171 PrintParameters(program->scope()); | |
1172 PrintDeclarations(program->scope()->declarations()); | |
1173 PrintStatements(program->body()); | |
1174 } | |
1175 return Output(); | |
1176 } | |
1177 | |
1178 | |
1179 void AstPrinter::PrintDeclarations(ZoneList<Declaration*>* declarations) { | |
1180 if (declarations->length() > 0) { | |
1181 IndentedScope indent(this, "DECLS"); | |
1182 for (int i = 0; i < declarations->length(); i++) { | |
1183 Visit(declarations->at(i)); | |
1184 } | |
1185 } | |
1186 } | |
1187 | |
1188 | |
1189 void AstPrinter::PrintParameters(Scope* scope) { | |
1190 if (scope->num_parameters() > 0) { | |
1191 IndentedScope indent(this, "PARAMS"); | |
1192 for (int i = 0; i < scope->num_parameters(); i++) { | |
1193 PrintLiteralWithModeIndented("VAR", scope->parameter(i), | |
1194 scope->parameter(i)->name()); | |
1195 } | |
1196 } | |
1197 } | |
1198 | |
1199 | |
1200 void AstPrinter::PrintStatements(ZoneList<Statement*>* statements) { | |
1201 for (int i = 0; i < statements->length(); i++) { | |
1202 Visit(statements->at(i)); | |
1203 } | |
1204 } | |
1205 | |
1206 | |
1207 void AstPrinter::PrintArguments(ZoneList<Expression*>* arguments) { | |
1208 for (int i = 0; i < arguments->length(); i++) { | |
1209 Visit(arguments->at(i)); | |
1210 } | |
1211 } | |
1212 | |
1213 | |
1214 void AstPrinter::VisitBlock(Block* node) { | |
1215 const char* block_txt = | |
1216 node->ignore_completion_value() ? "BLOCK NOCOMPLETIONS" : "BLOCK"; | |
1217 IndentedScope indent(this, block_txt, node->position()); | |
1218 PrintStatements(node->statements()); | |
1219 } | |
1220 | |
1221 | |
1222 // TODO(svenpanne) Start with IndentedScope. | |
1223 void AstPrinter::VisitVariableDeclaration(VariableDeclaration* node) { | |
1224 PrintLiteralWithModeIndented(Variable::Mode2String(node->mode()), | |
1225 node->proxy()->var(), | |
1226 node->proxy()->name()); | |
1227 } | |
1228 | |
1229 | |
1230 // TODO(svenpanne) Start with IndentedScope. | |
1231 void AstPrinter::VisitFunctionDeclaration(FunctionDeclaration* node) { | |
1232 PrintIndented("FUNCTION "); | |
1233 PrintLiteral(node->proxy()->name(), true); | |
1234 Print(" = function "); | |
1235 PrintLiteral(node->fun()->name(), false); | |
1236 Print("\n"); | |
1237 } | |
1238 | |
1239 | |
1240 void AstPrinter::VisitImportDeclaration(ImportDeclaration* node) { | |
1241 IndentedScope indent(this, "IMPORT", node->position()); | |
1242 PrintLiteralIndented("NAME", node->proxy()->name(), true); | |
1243 PrintLiteralIndented("FROM", node->module_specifier()->string(), true); | |
1244 } | |
1245 | |
1246 | |
1247 void AstPrinter::VisitExportDeclaration(ExportDeclaration* node) { | |
1248 IndentedScope indent(this, "EXPORT", node->position()); | |
1249 PrintLiteral(node->proxy()->name(), true); | |
1250 } | |
1251 | |
1252 | |
1253 void AstPrinter::VisitExpressionStatement(ExpressionStatement* node) { | |
1254 IndentedScope indent(this, "EXPRESSION STATEMENT", node->position()); | |
1255 Visit(node->expression()); | |
1256 } | |
1257 | |
1258 | |
1259 void AstPrinter::VisitEmptyStatement(EmptyStatement* node) { | |
1260 IndentedScope indent(this, "EMPTY", node->position()); | |
1261 } | |
1262 | |
1263 | |
1264 void AstPrinter::VisitSloppyBlockFunctionStatement( | |
1265 SloppyBlockFunctionStatement* node) { | |
1266 Visit(node->statement()); | |
1267 } | |
1268 | |
1269 | |
1270 void AstPrinter::VisitIfStatement(IfStatement* node) { | |
1271 IndentedScope indent(this, "IF", node->position()); | |
1272 PrintIndentedVisit("CONDITION", node->condition()); | |
1273 PrintIndentedVisit("THEN", node->then_statement()); | |
1274 if (node->HasElseStatement()) { | |
1275 PrintIndentedVisit("ELSE", node->else_statement()); | |
1276 } | |
1277 } | |
1278 | |
1279 | |
1280 void AstPrinter::VisitContinueStatement(ContinueStatement* node) { | |
1281 IndentedScope indent(this, "CONTINUE", node->position()); | |
1282 PrintLabelsIndented(node->target()->labels()); | |
1283 } | |
1284 | |
1285 | |
1286 void AstPrinter::VisitBreakStatement(BreakStatement* node) { | |
1287 IndentedScope indent(this, "BREAK", node->position()); | |
1288 PrintLabelsIndented(node->target()->labels()); | |
1289 } | |
1290 | |
1291 | |
1292 void AstPrinter::VisitReturnStatement(ReturnStatement* node) { | |
1293 IndentedScope indent(this, "RETURN", node->position()); | |
1294 Visit(node->expression()); | |
1295 } | |
1296 | |
1297 | |
1298 void AstPrinter::VisitWithStatement(WithStatement* node) { | |
1299 IndentedScope indent(this, "WITH", node->position()); | |
1300 PrintIndentedVisit("OBJECT", node->expression()); | |
1301 PrintIndentedVisit("BODY", node->statement()); | |
1302 } | |
1303 | |
1304 | |
1305 void AstPrinter::VisitSwitchStatement(SwitchStatement* node) { | |
1306 IndentedScope indent(this, "SWITCH", node->position()); | |
1307 PrintLabelsIndented(node->labels()); | |
1308 PrintIndentedVisit("TAG", node->tag()); | |
1309 for (int i = 0; i < node->cases()->length(); i++) { | |
1310 Visit(node->cases()->at(i)); | |
1311 } | |
1312 } | |
1313 | |
1314 | |
1315 void AstPrinter::VisitCaseClause(CaseClause* clause) { | |
1316 if (clause->is_default()) { | |
1317 IndentedScope indent(this, "DEFAULT", clause->position()); | |
1318 PrintStatements(clause->statements()); | |
1319 } else { | |
1320 IndentedScope indent(this, "CASE", clause->position()); | |
1321 Visit(clause->label()); | |
1322 PrintStatements(clause->statements()); | |
1323 } | |
1324 } | |
1325 | |
1326 | |
1327 void AstPrinter::VisitDoWhileStatement(DoWhileStatement* node) { | |
1328 IndentedScope indent(this, "DO", node->position()); | |
1329 PrintLabelsIndented(node->labels()); | |
1330 PrintIndentedVisit("BODY", node->body()); | |
1331 PrintIndentedVisit("COND", node->cond()); | |
1332 } | |
1333 | |
1334 | |
1335 void AstPrinter::VisitWhileStatement(WhileStatement* node) { | |
1336 IndentedScope indent(this, "WHILE", node->position()); | |
1337 PrintLabelsIndented(node->labels()); | |
1338 PrintIndentedVisit("COND", node->cond()); | |
1339 PrintIndentedVisit("BODY", node->body()); | |
1340 } | |
1341 | |
1342 | |
1343 void AstPrinter::VisitForStatement(ForStatement* node) { | |
1344 IndentedScope indent(this, "FOR", node->position()); | |
1345 PrintLabelsIndented(node->labels()); | |
1346 if (node->init()) PrintIndentedVisit("INIT", node->init()); | |
1347 if (node->cond()) PrintIndentedVisit("COND", node->cond()); | |
1348 PrintIndentedVisit("BODY", node->body()); | |
1349 if (node->next()) PrintIndentedVisit("NEXT", node->next()); | |
1350 } | |
1351 | |
1352 | |
1353 void AstPrinter::VisitForInStatement(ForInStatement* node) { | |
1354 IndentedScope indent(this, "FOR IN", node->position()); | |
1355 PrintIndentedVisit("FOR", node->each()); | |
1356 PrintIndentedVisit("IN", node->enumerable()); | |
1357 PrintIndentedVisit("BODY", node->body()); | |
1358 } | |
1359 | |
1360 | |
1361 void AstPrinter::VisitForOfStatement(ForOfStatement* node) { | |
1362 IndentedScope indent(this, "FOR OF", node->position()); | |
1363 PrintIndentedVisit("FOR", node->each()); | |
1364 PrintIndentedVisit("OF", node->iterable()); | |
1365 PrintIndentedVisit("BODY", node->body()); | |
1366 } | |
1367 | |
1368 | |
1369 void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) { | |
1370 IndentedScope indent(this, "TRY CATCH", node->position()); | |
1371 PrintIndentedVisit("TRY", node->try_block()); | |
1372 PrintLiteralWithModeIndented("CATCHVAR", | |
1373 node->variable(), | |
1374 node->variable()->name()); | |
1375 PrintIndentedVisit("CATCH", node->catch_block()); | |
1376 } | |
1377 | |
1378 | |
1379 void AstPrinter::VisitTryFinallyStatement(TryFinallyStatement* node) { | |
1380 IndentedScope indent(this, "TRY FINALLY", node->position()); | |
1381 PrintIndentedVisit("TRY", node->try_block()); | |
1382 PrintIndentedVisit("FINALLY", node->finally_block()); | |
1383 } | |
1384 | |
1385 | |
1386 void AstPrinter::VisitDebuggerStatement(DebuggerStatement* node) { | |
1387 IndentedScope indent(this, "DEBUGGER", node->position()); | |
1388 } | |
1389 | |
1390 | |
1391 void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) { | |
1392 IndentedScope indent(this, "FUNC LITERAL", node->position()); | |
1393 PrintLiteralIndented("NAME", node->name(), false); | |
1394 PrintLiteralIndented("INFERRED NAME", node->inferred_name(), false); | |
1395 PrintParameters(node->scope()); | |
1396 // We don't want to see the function literal in this case: it | |
1397 // will be printed via PrintProgram when the code for it is | |
1398 // generated. | |
1399 // PrintStatements(node->body()); | |
1400 } | |
1401 | |
1402 | |
1403 void AstPrinter::VisitClassLiteral(ClassLiteral* node) { | |
1404 IndentedScope indent(this, "CLASS LITERAL", node->position()); | |
1405 if (node->raw_name() != nullptr) { | |
1406 PrintLiteralIndented("NAME", node->name(), false); | |
1407 } | |
1408 if (node->extends() != nullptr) { | |
1409 PrintIndentedVisit("EXTENDS", node->extends()); | |
1410 } | |
1411 PrintProperties(node->properties()); | |
1412 } | |
1413 | |
1414 | |
1415 void AstPrinter::PrintProperties( | |
1416 ZoneList<ObjectLiteral::Property*>* properties) { | |
1417 for (int i = 0; i < properties->length(); i++) { | |
1418 ObjectLiteral::Property* property = properties->at(i); | |
1419 const char* prop_kind = nullptr; | |
1420 switch (property->kind()) { | |
1421 case ObjectLiteral::Property::CONSTANT: | |
1422 prop_kind = "CONSTANT"; | |
1423 break; | |
1424 case ObjectLiteral::Property::COMPUTED: | |
1425 prop_kind = "COMPUTED"; | |
1426 break; | |
1427 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | |
1428 prop_kind = "MATERIALIZED_LITERAL"; | |
1429 break; | |
1430 case ObjectLiteral::Property::PROTOTYPE: | |
1431 prop_kind = "PROTOTYPE"; | |
1432 break; | |
1433 case ObjectLiteral::Property::GETTER: | |
1434 prop_kind = "GETTER"; | |
1435 break; | |
1436 case ObjectLiteral::Property::SETTER: | |
1437 prop_kind = "SETTER"; | |
1438 break; | |
1439 } | |
1440 EmbeddedVector<char, 128> buf; | |
1441 SNPrintF(buf, "PROPERTY%s - %s", property->is_static() ? " - STATIC" : "", | |
1442 prop_kind); | |
1443 IndentedScope prop(this, buf.start()); | |
1444 PrintIndentedVisit("KEY", properties->at(i)->key()); | |
1445 PrintIndentedVisit("VALUE", properties->at(i)->value()); | |
1446 } | |
1447 } | |
1448 | |
1449 | |
1450 void AstPrinter::VisitNativeFunctionLiteral(NativeFunctionLiteral* node) { | |
1451 IndentedScope indent(this, "NATIVE FUNC LITERAL", node->position()); | |
1452 PrintLiteralIndented("NAME", node->name(), false); | |
1453 } | |
1454 | |
1455 | |
1456 void AstPrinter::VisitDoExpression(DoExpression* node) { | |
1457 IndentedScope indent(this, "DO EXPRESSION", node->position()); | |
1458 PrintStatements(node->block()->statements()); | |
1459 } | |
1460 | |
1461 | |
1462 void AstPrinter::VisitConditional(Conditional* node) { | |
1463 IndentedScope indent(this, "CONDITIONAL", node->position()); | |
1464 PrintIndentedVisit("CONDITION", node->condition()); | |
1465 PrintIndentedVisit("THEN", node->then_expression()); | |
1466 PrintIndentedVisit("ELSE", node->else_expression()); | |
1467 } | |
1468 | |
1469 | |
1470 // TODO(svenpanne) Start with IndentedScope. | |
1471 void AstPrinter::VisitLiteral(Literal* node) { | |
1472 PrintLiteralIndented("LITERAL", node->value(), true); | |
1473 } | |
1474 | |
1475 | |
1476 void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) { | |
1477 IndentedScope indent(this, "REGEXP LITERAL", node->position()); | |
1478 EmbeddedVector<char, 128> buf; | |
1479 SNPrintF(buf, "literal_index = %d\n", node->literal_index()); | |
1480 PrintIndented(buf.start()); | |
1481 PrintLiteralIndented("PATTERN", node->pattern(), false); | |
1482 int i = 0; | |
1483 if (node->flags() & RegExp::kGlobal) buf[i++] = 'g'; | |
1484 if (node->flags() & RegExp::kIgnoreCase) buf[i++] = 'i'; | |
1485 if (node->flags() & RegExp::kMultiline) buf[i++] = 'm'; | |
1486 if (node->flags() & RegExp::kUnicode) buf[i++] = 'u'; | |
1487 if (node->flags() & RegExp::kSticky) buf[i++] = 'y'; | |
1488 buf[i] = '\0'; | |
1489 PrintIndented("FLAGS "); | |
1490 Print(buf.start()); | |
1491 Print("\n"); | |
1492 } | |
1493 | |
1494 | |
1495 void AstPrinter::VisitObjectLiteral(ObjectLiteral* node) { | |
1496 IndentedScope indent(this, "OBJ LITERAL", node->position()); | |
1497 EmbeddedVector<char, 128> buf; | |
1498 SNPrintF(buf, "literal_index = %d\n", node->literal_index()); | |
1499 PrintIndented(buf.start()); | |
1500 PrintProperties(node->properties()); | |
1501 } | |
1502 | |
1503 | |
1504 void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) { | |
1505 IndentedScope indent(this, "ARRAY LITERAL", node->position()); | |
1506 | |
1507 EmbeddedVector<char, 128> buf; | |
1508 SNPrintF(buf, "literal_index = %d\n", node->literal_index()); | |
1509 PrintIndented(buf.start()); | |
1510 if (node->values()->length() > 0) { | |
1511 IndentedScope indent(this, "VALUES", node->position()); | |
1512 for (int i = 0; i < node->values()->length(); i++) { | |
1513 Visit(node->values()->at(i)); | |
1514 } | |
1515 } | |
1516 } | |
1517 | |
1518 | |
1519 void AstPrinter::VisitVariableProxy(VariableProxy* node) { | |
1520 Variable* var = node->var(); | |
1521 EmbeddedVector<char, 128> buf; | |
1522 int pos = | |
1523 FormatSlotNode(&buf, node, "VAR PROXY", node->VariableFeedbackSlot()); | |
1524 | |
1525 switch (var->location()) { | |
1526 case VariableLocation::UNALLOCATED: | |
1527 break; | |
1528 case VariableLocation::PARAMETER: | |
1529 SNPrintF(buf + pos, " parameter[%d]", var->index()); | |
1530 break; | |
1531 case VariableLocation::LOCAL: | |
1532 SNPrintF(buf + pos, " local[%d]", var->index()); | |
1533 break; | |
1534 case VariableLocation::CONTEXT: | |
1535 SNPrintF(buf + pos, " context[%d]", var->index()); | |
1536 break; | |
1537 case VariableLocation::GLOBAL: | |
1538 SNPrintF(buf + pos, " global[%d]", var->index()); | |
1539 break; | |
1540 case VariableLocation::LOOKUP: | |
1541 SNPrintF(buf + pos, " lookup"); | |
1542 break; | |
1543 } | |
1544 PrintLiteralWithModeIndented(buf.start(), var, node->name()); | |
1545 } | |
1546 | |
1547 | |
1548 void AstPrinter::VisitAssignment(Assignment* node) { | |
1549 IndentedScope indent(this, Token::Name(node->op()), node->position()); | |
1550 Visit(node->target()); | |
1551 Visit(node->value()); | |
1552 } | |
1553 | |
1554 | |
1555 void AstPrinter::VisitYield(Yield* node) { | |
1556 IndentedScope indent(this, "YIELD", node->position()); | |
1557 Visit(node->expression()); | |
1558 } | |
1559 | |
1560 | |
1561 void AstPrinter::VisitThrow(Throw* node) { | |
1562 IndentedScope indent(this, "THROW", node->position()); | |
1563 Visit(node->exception()); | |
1564 } | |
1565 | |
1566 | |
1567 void AstPrinter::VisitProperty(Property* node) { | |
1568 EmbeddedVector<char, 128> buf; | |
1569 FormatSlotNode(&buf, node, "PROPERTY", node->PropertyFeedbackSlot()); | |
1570 IndentedScope indent(this, buf.start(), node->position()); | |
1571 | |
1572 Visit(node->obj()); | |
1573 Literal* literal = node->key()->AsLiteral(); | |
1574 if (literal != NULL && literal->value()->IsInternalizedString()) { | |
1575 PrintLiteralIndented("NAME", literal->value(), false); | |
1576 } else { | |
1577 PrintIndentedVisit("KEY", node->key()); | |
1578 } | |
1579 } | |
1580 | |
1581 | |
1582 void AstPrinter::VisitCall(Call* node) { | |
1583 EmbeddedVector<char, 128> buf; | |
1584 FormatSlotNode(&buf, node, "CALL", node->CallFeedbackICSlot()); | |
1585 IndentedScope indent(this, buf.start()); | |
1586 | |
1587 Visit(node->expression()); | |
1588 PrintArguments(node->arguments()); | |
1589 } | |
1590 | |
1591 | |
1592 void AstPrinter::VisitCallNew(CallNew* node) { | |
1593 IndentedScope indent(this, "CALL NEW", node->position()); | |
1594 Visit(node->expression()); | |
1595 PrintArguments(node->arguments()); | |
1596 } | |
1597 | |
1598 | |
1599 void AstPrinter::VisitCallRuntime(CallRuntime* node) { | |
1600 EmbeddedVector<char, 128> buf; | |
1601 SNPrintF(buf, "CALL RUNTIME %s", node->debug_name()); | |
1602 IndentedScope indent(this, buf.start(), node->position()); | |
1603 PrintArguments(node->arguments()); | |
1604 } | |
1605 | |
1606 | |
1607 void AstPrinter::VisitUnaryOperation(UnaryOperation* node) { | |
1608 IndentedScope indent(this, Token::Name(node->op()), node->position()); | |
1609 Visit(node->expression()); | |
1610 } | |
1611 | |
1612 | |
1613 void AstPrinter::VisitCountOperation(CountOperation* node) { | |
1614 EmbeddedVector<char, 128> buf; | |
1615 SNPrintF(buf, "%s %s", (node->is_prefix() ? "PRE" : "POST"), | |
1616 Token::Name(node->op())); | |
1617 IndentedScope indent(this, buf.start(), node->position()); | |
1618 Visit(node->expression()); | |
1619 } | |
1620 | |
1621 | |
1622 void AstPrinter::VisitBinaryOperation(BinaryOperation* node) { | |
1623 IndentedScope indent(this, Token::Name(node->op()), node->position()); | |
1624 Visit(node->left()); | |
1625 Visit(node->right()); | |
1626 } | |
1627 | |
1628 | |
1629 void AstPrinter::VisitCompareOperation(CompareOperation* node) { | |
1630 IndentedScope indent(this, Token::Name(node->op()), node->position()); | |
1631 Visit(node->left()); | |
1632 Visit(node->right()); | |
1633 } | |
1634 | |
1635 | |
1636 void AstPrinter::VisitSpread(Spread* node) { | |
1637 IndentedScope indent(this, "...", node->position()); | |
1638 Visit(node->expression()); | |
1639 } | |
1640 | |
1641 | |
1642 void AstPrinter::VisitEmptyParentheses(EmptyParentheses* node) { | |
1643 IndentedScope indent(this, "()", node->position()); | |
1644 } | |
1645 | |
1646 | |
1647 void AstPrinter::VisitThisFunction(ThisFunction* node) { | |
1648 IndentedScope indent(this, "THIS-FUNCTION", node->position()); | |
1649 } | |
1650 | |
1651 | |
1652 void AstPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) { | |
1653 IndentedScope indent(this, "SUPER-PROPERTY-REFERENCE", node->position()); | |
1654 } | |
1655 | |
1656 | |
1657 void AstPrinter::VisitSuperCallReference(SuperCallReference* node) { | |
1658 IndentedScope indent(this, "SUPER-CALL-REFERENCE", node->position()); | |
1659 } | |
1660 | |
1661 | |
1662 #endif // DEBUG | |
1663 | |
1664 } // namespace internal | |
1665 } // namespace v8 | |
OLD | NEW |