// 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 { ... } // // 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 AstTraversalVisitor : public AstVisitor { 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(const ZonePtrList* 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 AstTraversalVisitor::AstTraversalVisitor(Isolate* isolate, AstNode* root) : root_(root), depth_(0) { InitializeAstVisitor(isolate); } template AstTraversalVisitor::AstTraversalVisitor(uintptr_t stack_limit, AstNode* root) : root_(root), depth_(0) { InitializeAstVisitor(stack_limit); } template void AstTraversalVisitor::VisitDeclarations( Declaration::List* decls) { for (Declaration* decl : *decls) { RECURSE(Visit(decl)); } } template void AstTraversalVisitor::VisitStatements( const ZonePtrList* stmts) { for (int i = 0; i < stmts->length(); ++i) { Statement* stmt = stmts->at(i); RECURSE(Visit(stmt)); } } template void AstTraversalVisitor::VisitVariableDeclaration( VariableDeclaration* decl) { PROCESS_NODE(decl); } template void AstTraversalVisitor::VisitFunctionDeclaration( FunctionDeclaration* decl) { PROCESS_NODE(decl); RECURSE(Visit(decl->fun())); } template void AstTraversalVisitor::VisitBlock(Block* stmt) { PROCESS_NODE(stmt); if (stmt->scope() != nullptr) { RECURSE_EXPRESSION(VisitDeclarations(stmt->scope()->declarations())); } RECURSE(VisitStatements(stmt->statements())); } template void AstTraversalVisitor::VisitExpressionStatement( ExpressionStatement* stmt) { PROCESS_NODE(stmt); RECURSE(Visit(stmt->expression())); } template void AstTraversalVisitor::VisitEmptyStatement(EmptyStatement* stmt) {} template void AstTraversalVisitor::VisitSloppyBlockFunctionStatement( SloppyBlockFunctionStatement* stmt) { PROCESS_NODE(stmt); RECURSE(Visit(stmt->statement())); } template void AstTraversalVisitor::VisitIfStatement(IfStatement* stmt) { PROCESS_NODE(stmt); RECURSE(Visit(stmt->condition())); RECURSE(Visit(stmt->then_statement())); RECURSE(Visit(stmt->else_statement())); } template void AstTraversalVisitor::VisitContinueStatement( ContinueStatement* stmt) { PROCESS_NODE(stmt); } template void AstTraversalVisitor::VisitBreakStatement(BreakStatement* stmt) { PROCESS_NODE(stmt); } template void AstTraversalVisitor::VisitReturnStatement( ReturnStatement* stmt) { PROCESS_NODE(stmt); RECURSE(Visit(stmt->expression())); } template void AstTraversalVisitor::VisitWithStatement(WithStatement* stmt) { PROCESS_NODE(stmt); RECURSE(Visit(stmt->expression())); RECURSE(Visit(stmt->statement())); } template void AstTraversalVisitor::VisitSwitchStatement( SwitchStatement* stmt) { PROCESS_NODE(stmt); RECURSE(Visit(stmt->tag())); ZonePtrList* 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)); } const ZonePtrList* stmts = clause->statements(); RECURSE(VisitStatements(stmts)); } } template void AstTraversalVisitor::VisitDoWhileStatement( DoWhileStatement* stmt) { PROCESS_NODE(stmt); RECURSE(Visit(stmt->body())); RECURSE(Visit(stmt->cond())); } template void AstTraversalVisitor::VisitWhileStatement(WhileStatement* stmt) { PROCESS_NODE(stmt); RECURSE(Visit(stmt->cond())); RECURSE(Visit(stmt->body())); } template void AstTraversalVisitor::VisitForStatement(ForStatement* stmt) { PROCESS_NODE(stmt); if (stmt->init() != nullptr) { RECURSE(Visit(stmt->init())); } if (stmt->cond() != nullptr) { RECURSE(Visit(stmt->cond())); } if (stmt->next() != nullptr) { RECURSE(Visit(stmt->next())); } RECURSE(Visit(stmt->body())); } template void AstTraversalVisitor::VisitForInStatement(ForInStatement* stmt) { PROCESS_NODE(stmt); RECURSE(Visit(stmt->each())); RECURSE(Visit(stmt->subject())); RECURSE(Visit(stmt->body())); } template void AstTraversalVisitor::VisitForOfStatement(ForOfStatement* stmt) { PROCESS_NODE(stmt); RECURSE(Visit(stmt->each())); RECURSE(Visit(stmt->subject())); RECURSE(Visit(stmt->body())); } template void AstTraversalVisitor::VisitTryCatchStatement( TryCatchStatement* stmt) { PROCESS_NODE(stmt); RECURSE(Visit(stmt->try_block())); RECURSE(Visit(stmt->catch_block())); } template void AstTraversalVisitor::VisitTryFinallyStatement( TryFinallyStatement* stmt) { PROCESS_NODE(stmt); RECURSE(Visit(stmt->try_block())); RECURSE(Visit(stmt->finally_block())); } template void AstTraversalVisitor::VisitDebuggerStatement( DebuggerStatement* stmt) { PROCESS_NODE(stmt); } template void AstTraversalVisitor::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 void AstTraversalVisitor::VisitNativeFunctionLiteral( NativeFunctionLiteral* expr) { PROCESS_EXPRESSION(expr); } template void AstTraversalVisitor::VisitDoExpression(DoExpression* expr) { PROCESS_EXPRESSION(expr); RECURSE(VisitBlock(expr->block())); RECURSE(VisitVariableProxy(expr->result())); } template void AstTraversalVisitor::VisitConditional(Conditional* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->condition())); RECURSE_EXPRESSION(Visit(expr->then_expression())); RECURSE_EXPRESSION(Visit(expr->else_expression())); } template void AstTraversalVisitor::VisitVariableProxy(VariableProxy* expr) { PROCESS_EXPRESSION(expr); } template void AstTraversalVisitor::VisitLiteral(Literal* expr) { PROCESS_EXPRESSION(expr); } template void AstTraversalVisitor::VisitRegExpLiteral(RegExpLiteral* expr) { PROCESS_EXPRESSION(expr); } template void AstTraversalVisitor::VisitObjectLiteral(ObjectLiteral* expr) { PROCESS_EXPRESSION(expr); const ZonePtrList* 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 void AstTraversalVisitor::VisitArrayLiteral(ArrayLiteral* expr) { PROCESS_EXPRESSION(expr); const ZonePtrList* values = expr->values(); for (int i = 0; i < values->length(); ++i) { Expression* value = values->at(i); RECURSE_EXPRESSION(Visit(value)); } } template void AstTraversalVisitor::VisitAssignment(Assignment* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->target())); RECURSE_EXPRESSION(Visit(expr->value())); } template void AstTraversalVisitor::VisitCompoundAssignment( CompoundAssignment* expr) { VisitAssignment(expr); } template void AstTraversalVisitor::VisitYield(Yield* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->expression())); } template void AstTraversalVisitor::VisitYieldStar(YieldStar* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->expression())); } template void AstTraversalVisitor::VisitAwait(Await* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->expression())); } template void AstTraversalVisitor::VisitThrow(Throw* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->exception())); } template void AstTraversalVisitor::VisitProperty(Property* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->obj())); RECURSE_EXPRESSION(Visit(expr->key())); } template void AstTraversalVisitor::VisitResolvedProperty( ResolvedProperty* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(VisitVariableProxy(expr->object())); RECURSE_EXPRESSION(VisitVariableProxy(expr->property())); } template void AstTraversalVisitor::VisitCall(Call* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->expression())); const ZonePtrList* args = expr->arguments(); for (int i = 0; i < args->length(); ++i) { Expression* arg = args->at(i); RECURSE_EXPRESSION(Visit(arg)); } } template void AstTraversalVisitor::VisitCallNew(CallNew* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->expression())); const ZonePtrList* args = expr->arguments(); for (int i = 0; i < args->length(); ++i) { Expression* arg = args->at(i); RECURSE_EXPRESSION(Visit(arg)); } } template void AstTraversalVisitor::VisitCallRuntime(CallRuntime* expr) { PROCESS_EXPRESSION(expr); const ZonePtrList* args = expr->arguments(); for (int i = 0; i < args->length(); ++i) { Expression* arg = args->at(i); RECURSE_EXPRESSION(Visit(arg)); } } template void AstTraversalVisitor::VisitUnaryOperation(UnaryOperation* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->expression())); } template void AstTraversalVisitor::VisitCountOperation(CountOperation* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->expression())); } template void AstTraversalVisitor::VisitBinaryOperation( BinaryOperation* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->left())); RECURSE_EXPRESSION(Visit(expr->right())); } template void AstTraversalVisitor::VisitNaryOperation(NaryOperation* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->first())); for (size_t i = 0; i < expr->subsequent_length(); ++i) { RECURSE_EXPRESSION(Visit(expr->subsequent(i))); } } template void AstTraversalVisitor::VisitCompareOperation( CompareOperation* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->left())); RECURSE_EXPRESSION(Visit(expr->right())); } template void AstTraversalVisitor::VisitThisExpression(ThisExpression* expr) { PROCESS_EXPRESSION(expr); } template void AstTraversalVisitor::VisitClassLiteral(ClassLiteral* expr) { PROCESS_EXPRESSION(expr); if (expr->extends() != nullptr) { RECURSE_EXPRESSION(Visit(expr->extends())); } RECURSE_EXPRESSION(Visit(expr->constructor())); if (expr->static_fields_initializer() != nullptr) { RECURSE_EXPRESSION(Visit(expr->static_fields_initializer())); } if (expr->instance_members_initializer_function() != nullptr) { RECURSE_EXPRESSION(Visit(expr->instance_members_initializer_function())); } ZonePtrList* 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 void AstTraversalVisitor::VisitInitializeClassMembersStatement( InitializeClassMembersStatement* stmt) { PROCESS_NODE(stmt); ZonePtrList* props = stmt->fields(); for (int i = 0; i < props->length(); ++i) { ClassLiteralProperty* prop = props->at(i); if (!prop->key()->IsLiteral()) { RECURSE(Visit(prop->key())); } RECURSE(Visit(prop->value())); } } template void AstTraversalVisitor::VisitSpread(Spread* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->expression())); } template void AstTraversalVisitor::VisitStoreInArrayLiteral( StoreInArrayLiteral* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->array())); RECURSE_EXPRESSION(Visit(expr->index())); RECURSE_EXPRESSION(Visit(expr->value())); } template void AstTraversalVisitor::VisitEmptyParentheses( EmptyParentheses* expr) { PROCESS_EXPRESSION(expr); } template void AstTraversalVisitor::VisitGetTemplateObject( GetTemplateObject* expr) { PROCESS_EXPRESSION(expr); } template void AstTraversalVisitor::VisitTemplateLiteral( TemplateLiteral* expr) { PROCESS_EXPRESSION(expr); for (Expression* sub : *expr->substitutions()) { RECURSE_EXPRESSION(Visit(sub)); } } template void AstTraversalVisitor::VisitImportCallExpression( ImportCallExpression* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->argument())); } template void AstTraversalVisitor::VisitSuperPropertyReference( SuperPropertyReference* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(Visit(expr->home_object())); } template void AstTraversalVisitor::VisitSuperCallReference( SuperCallReference* expr) { PROCESS_EXPRESSION(expr); RECURSE_EXPRESSION(VisitVariableProxy(expr->new_target_var())); RECURSE_EXPRESSION(VisitVariableProxy(expr->this_function_var())); } #undef PROCESS_NODE #undef PROCESS_EXPRESSION #undef RECURSE_EXPRESSION #undef RECURSE } // namespace internal } // namespace v8 #endif // V8_AST_AST_TRAVERSAL_VISITOR_H_