Index: src/ast/ast-traversal-visitor.h |
diff --git a/src/ast/ast-traversal-visitor.h b/src/ast/ast-traversal-visitor.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c8284b771e7b8de9df0b7c52652524c54974b97d |
--- /dev/null |
+++ b/src/ast/ast-traversal-visitor.h |
@@ -0,0 +1,504 @@ |
+// Copyright 2016 the V8 project authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef V8_AST_AST_TRAVERSAL_VISITOR_H_ |
+#define V8_AST_AST_TRAVERSAL_VISITOR_H_ |
+ |
+#include "src/ast/ast.h" |
+#include "src/ast/scopes.h" |
+ |
+namespace v8 { |
+namespace internal { |
+ |
+// ---------------------------------------------------------------------------- |
+// Traversal visitor |
+// - fully traverses the entire AST. |
+// |
+// Sub-class should parametrize AstTraversalVisitor with itself, e.g.: |
+// class SpecificVisitor : public AstTraversalVisitor<SpecificVisitor> { ... } |
+// |
+// It invokes VisitNode on each AST node, before proceeding with its subtrees. |
+// It invokes VisitExpression (after VisitNode) on each AST node that is an |
+// expression, before proceeding with its subtrees. |
+// It proceeds with the subtrees only if these two methods return true. |
+// Sub-classes may override VisitNode and VisitExpressions, whose implementation |
+// is dummy here. Or they may override the specific Visit* methods. |
+ |
+template <class Subclass> |
+class AstTraversalVisitor : public AstVisitor<Subclass> { |
+ public: |
+ explicit AstTraversalVisitor(Isolate* isolate, AstNode* root = nullptr); |
+ explicit AstTraversalVisitor(uintptr_t stack_limit, AstNode* root = nullptr); |
+ |
+ void Run() { |
+ DCHECK_NOT_NULL(root_); |
+ Visit(root_); |
+ } |
+ |
+ bool VisitNode(AstNode* node) { return true; } |
+ bool VisitExpression(Expression* node) { return true; } |
+ |
+ // Iteration left-to-right. |
+ void VisitDeclarations(ZoneList<Declaration*>* declarations); |
+ void VisitStatements(ZoneList<Statement*>* statements); |
+ |
+// Individual nodes |
+#define DECLARE_VISIT(type) void Visit##type(type* node); |
+ AST_NODE_LIST(DECLARE_VISIT) |
+#undef DECLARE_VISIT |
+ |
+ protected: |
+ int depth() const { return depth_; } |
+ |
+ private: |
+ DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); |
+ |
+ AstNode* root_; |
+ int depth_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(AstTraversalVisitor); |
+}; |
+ |
+// ---------------------------------------------------------------------------- |
+// Implementation of AstTraversalVisitor |
+ |
+#define PROCESS_NODE(node) do { \ |
+ if (!(this->impl()->VisitNode(node))) return; \ |
+ } while (false) |
+ |
+#define PROCESS_EXPRESSION(node) do { \ |
+ PROCESS_NODE(node); \ |
+ if (!(this->impl()->VisitExpression(node))) return; \ |
+ } while (false) |
+ |
+#define RECURSE(call) \ |
+ do { \ |
+ DCHECK(!HasStackOverflow()); \ |
+ this->impl()->call; \ |
+ if (HasStackOverflow()) return; \ |
+ } while (false) |
+ |
+#define RECURSE_EXPRESSION(call) \ |
+ do { \ |
+ DCHECK(!HasStackOverflow()); \ |
+ ++depth_; \ |
+ this->impl()->call; \ |
+ --depth_; \ |
+ if (HasStackOverflow()) return; \ |
+ } while (false) |
+ |
+template <class Subclass> |
+AstTraversalVisitor<Subclass>::AstTraversalVisitor(Isolate* isolate, |
+ AstNode* root) |
+ : root_(root), depth_(0) { |
+ InitializeAstVisitor(isolate); |
+} |
+ |
+template <class Subclass> |
+AstTraversalVisitor<Subclass>::AstTraversalVisitor(uintptr_t stack_limit, |
+ AstNode* root) |
+ : root_(root), depth_(0) { |
+ InitializeAstVisitor(stack_limit); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitDeclarations( |
+ ZoneList<Declaration*>* decls) { |
+ for (int i = 0; i < decls->length(); ++i) { |
+ Declaration* decl = decls->at(i); |
+ RECURSE(Visit(decl)); |
+ } |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitStatements( |
+ ZoneList<Statement*>* stmts) { |
+ for (int i = 0; i < stmts->length(); ++i) { |
+ Statement* stmt = stmts->at(i); |
+ RECURSE(Visit(stmt)); |
+ if (stmt->IsJump()) break; |
+ } |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitVariableDeclaration( |
+ VariableDeclaration* decl) { |
+ PROCESS_NODE(decl); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitFunctionDeclaration( |
+ FunctionDeclaration* decl) { |
+ PROCESS_NODE(decl); |
+ RECURSE(Visit(decl->fun())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitBlock(Block* stmt) { |
+ PROCESS_NODE(stmt); |
+ RECURSE(VisitStatements(stmt->statements())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitExpressionStatement( |
+ ExpressionStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+ RECURSE(Visit(stmt->expression())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitEmptyStatement(EmptyStatement* stmt) {} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitSloppyBlockFunctionStatement( |
+ SloppyBlockFunctionStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+ RECURSE(Visit(stmt->statement())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitIfStatement(IfStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+ RECURSE(Visit(stmt->condition())); |
+ RECURSE(Visit(stmt->then_statement())); |
+ RECURSE(Visit(stmt->else_statement())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitContinueStatement( |
+ ContinueStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitBreakStatement(BreakStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitReturnStatement( |
+ ReturnStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+ RECURSE(Visit(stmt->expression())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitWithStatement(WithStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+ RECURSE(Visit(stmt->expression())); |
+ RECURSE(Visit(stmt->statement())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitSwitchStatement( |
+ SwitchStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+ RECURSE(Visit(stmt->tag())); |
+ |
+ ZoneList<CaseClause*>* clauses = stmt->cases(); |
+ for (int i = 0; i < clauses->length(); ++i) { |
+ CaseClause* clause = clauses->at(i); |
+ if (!clause->is_default()) { |
+ Expression* label = clause->label(); |
+ RECURSE(Visit(label)); |
+ } |
+ ZoneList<Statement*>* stmts = clause->statements(); |
+ RECURSE(VisitStatements(stmts)); |
+ } |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitCaseClause(CaseClause* clause) { |
+ UNREACHABLE(); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitDoWhileStatement( |
+ DoWhileStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+ RECURSE(Visit(stmt->body())); |
+ RECURSE(Visit(stmt->cond())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitWhileStatement(WhileStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+ RECURSE(Visit(stmt->cond())); |
+ RECURSE(Visit(stmt->body())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitForStatement(ForStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+ if (stmt->init() != NULL) { |
+ RECURSE(Visit(stmt->init())); |
+ } |
+ if (stmt->cond() != NULL) { |
+ RECURSE(Visit(stmt->cond())); |
+ } |
+ if (stmt->next() != NULL) { |
+ RECURSE(Visit(stmt->next())); |
+ } |
+ RECURSE(Visit(stmt->body())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitForInStatement(ForInStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+ RECURSE(Visit(stmt->enumerable())); |
+ RECURSE(Visit(stmt->body())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitForOfStatement(ForOfStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+ RECURSE(Visit(stmt->assign_iterator())); |
+ RECURSE(Visit(stmt->next_result())); |
+ RECURSE(Visit(stmt->result_done())); |
+ RECURSE(Visit(stmt->assign_each())); |
+ RECURSE(Visit(stmt->body())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitTryCatchStatement( |
+ TryCatchStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+ RECURSE(Visit(stmt->try_block())); |
+ RECURSE(Visit(stmt->catch_block())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitTryFinallyStatement( |
+ TryFinallyStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+ RECURSE(Visit(stmt->try_block())); |
+ RECURSE(Visit(stmt->finally_block())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitDebuggerStatement( |
+ DebuggerStatement* stmt) { |
+ PROCESS_NODE(stmt); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitFunctionLiteral( |
+ FunctionLiteral* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ Scope* scope = expr->scope(); |
+ RECURSE_EXPRESSION(VisitDeclarations(scope->declarations())); |
+ RECURSE_EXPRESSION(VisitStatements(expr->body())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitNativeFunctionLiteral( |
+ NativeFunctionLiteral* expr) { |
+ PROCESS_EXPRESSION(expr); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitDoExpression(DoExpression* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE(VisitBlock(expr->block())); |
+ RECURSE(VisitVariableProxy(expr->result())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitConditional(Conditional* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(Visit(expr->condition())); |
+ RECURSE_EXPRESSION(Visit(expr->then_expression())); |
+ RECURSE_EXPRESSION(Visit(expr->else_expression())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitVariableProxy(VariableProxy* expr) { |
+ PROCESS_EXPRESSION(expr); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitLiteral(Literal* expr) { |
+ PROCESS_EXPRESSION(expr); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitRegExpLiteral(RegExpLiteral* expr) { |
+ PROCESS_EXPRESSION(expr); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitObjectLiteral(ObjectLiteral* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ ZoneList<ObjectLiteralProperty*>* props = expr->properties(); |
+ for (int i = 0; i < props->length(); ++i) { |
+ ObjectLiteralProperty* prop = props->at(i); |
+ RECURSE_EXPRESSION(Visit(prop->key())); |
+ RECURSE_EXPRESSION(Visit(prop->value())); |
+ } |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitArrayLiteral(ArrayLiteral* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ ZoneList<Expression*>* values = expr->values(); |
+ for (int i = 0; i < values->length(); ++i) { |
+ Expression* value = values->at(i); |
+ RECURSE_EXPRESSION(Visit(value)); |
+ } |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitAssignment(Assignment* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(Visit(expr->target())); |
+ RECURSE_EXPRESSION(Visit(expr->value())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitYield(Yield* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(Visit(expr->generator_object())); |
+ RECURSE_EXPRESSION(Visit(expr->expression())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitThrow(Throw* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(Visit(expr->exception())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitProperty(Property* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(Visit(expr->obj())); |
+ RECURSE_EXPRESSION(Visit(expr->key())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitCall(Call* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(Visit(expr->expression())); |
+ ZoneList<Expression*>* args = expr->arguments(); |
+ for (int i = 0; i < args->length(); ++i) { |
+ Expression* arg = args->at(i); |
+ RECURSE_EXPRESSION(Visit(arg)); |
+ } |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitCallNew(CallNew* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(Visit(expr->expression())); |
+ ZoneList<Expression*>* args = expr->arguments(); |
+ for (int i = 0; i < args->length(); ++i) { |
+ Expression* arg = args->at(i); |
+ RECURSE_EXPRESSION(Visit(arg)); |
+ } |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitCallRuntime(CallRuntime* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ ZoneList<Expression*>* args = expr->arguments(); |
+ for (int i = 0; i < args->length(); ++i) { |
+ Expression* arg = args->at(i); |
+ RECURSE_EXPRESSION(Visit(arg)); |
+ } |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitUnaryOperation(UnaryOperation* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(Visit(expr->expression())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitCountOperation(CountOperation* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(Visit(expr->expression())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitBinaryOperation( |
+ BinaryOperation* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(Visit(expr->left())); |
+ RECURSE_EXPRESSION(Visit(expr->right())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitCompareOperation( |
+ CompareOperation* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(Visit(expr->left())); |
+ RECURSE_EXPRESSION(Visit(expr->right())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitThisFunction(ThisFunction* expr) { |
+ PROCESS_EXPRESSION(expr); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitClassLiteral(ClassLiteral* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ if (expr->extends() != nullptr) { |
+ RECURSE_EXPRESSION(Visit(expr->extends())); |
+ } |
+ RECURSE_EXPRESSION(Visit(expr->constructor())); |
+ ZoneList<ObjectLiteralProperty*>* props = expr->properties(); |
+ for (int i = 0; i < props->length(); ++i) { |
+ ObjectLiteralProperty* prop = props->at(i); |
+ if (!prop->key()->IsLiteral()) { |
+ RECURSE_EXPRESSION(Visit(prop->key())); |
+ } |
+ RECURSE_EXPRESSION(Visit(prop->value())); |
+ } |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitSpread(Spread* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(Visit(expr->expression())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitEmptyParentheses( |
+ EmptyParentheses* expr) { |
+ PROCESS_EXPRESSION(expr); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitSuperPropertyReference( |
+ SuperPropertyReference* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(VisitVariableProxy(expr->this_var())); |
+ RECURSE_EXPRESSION(Visit(expr->home_object())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitSuperCallReference( |
+ SuperCallReference* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE_EXPRESSION(VisitVariableProxy(expr->this_var())); |
+ RECURSE_EXPRESSION(VisitVariableProxy(expr->new_target_var())); |
+ RECURSE_EXPRESSION(VisitVariableProxy(expr->this_function_var())); |
+} |
+ |
+template <class Subclass> |
+void AstTraversalVisitor<Subclass>::VisitRewritableExpression( |
+ RewritableExpression* expr) { |
+ PROCESS_EXPRESSION(expr); |
+ RECURSE(Visit(expr->expression())); |
+} |
+ |
+#undef PROCESS_NODE |
+#undef PROCESS_EXPRESSION |
+#undef RECURSE_EXPRESSION |
+#undef RECURSE |
+ |
+} // namespace internal |
+} // namespace v8 |
+ |
+#endif // V8_AST_AST_TRAVERSAL_VISITOR_H_ |