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