// 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(Declaration::List* 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( Declaration::List* decls) { for (Declaration* decl : *decls) { 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); DeclarationScope* scope = expr->scope(); RECURSE_EXPRESSION(VisitDeclarations(scope->declarations())); // A lazily parsed function literal won't have a body. if (expr->scope()->was_lazily_parsed()) return; 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<ClassLiteralProperty*>* props = expr->properties(); for (int i = 0; i < props->length(); ++i) { ClassLiteralProperty* 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>::VisitGetIterator(GetIterator* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->iterable())); } 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_