| // 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(const ZonePtrList<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( |
| const ZonePtrList<Statement>* stmts) { |
| for (int i = 0; i < stmts->length(); ++i) { |
| Statement* stmt = stmts->at(i); |
| RECURSE(Visit(stmt)); |
| } |
| } |
| |
| 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); |
| if (stmt->scope() != nullptr) { |
| RECURSE_EXPRESSION(VisitDeclarations(stmt->scope()->declarations())); |
| } |
| 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())); |
| |
| ZonePtrList<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)); |
| } |
| const ZonePtrList<Statement>* stmts = clause->statements(); |
| RECURSE(VisitStatements(stmts)); |
| } |
| } |
| |
| 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() != 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 <class Subclass> |
| void AstTraversalVisitor<Subclass>::VisitForInStatement(ForInStatement* stmt) { |
| PROCESS_NODE(stmt); |
| RECURSE(Visit(stmt->each())); |
| RECURSE(Visit(stmt->subject())); |
| RECURSE(Visit(stmt->body())); |
| } |
| |
| template <class Subclass> |
| void AstTraversalVisitor<Subclass>::VisitForOfStatement(ForOfStatement* stmt) { |
| PROCESS_NODE(stmt); |
| RECURSE(Visit(stmt->each())); |
| RECURSE(Visit(stmt->subject())); |
| 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>::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); |
| const ZonePtrList<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); |
| const ZonePtrList<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>::VisitCompoundAssignment( |
| CompoundAssignment* expr) { |
| VisitAssignment(expr); |
| } |
| |
| template <class Subclass> |
| void AstTraversalVisitor<Subclass>::VisitYield(Yield* expr) { |
| PROCESS_EXPRESSION(expr); |
| RECURSE_EXPRESSION(Visit(expr->expression())); |
| } |
| |
| template <class Subclass> |
| void AstTraversalVisitor<Subclass>::VisitYieldStar(YieldStar* expr) { |
| PROCESS_EXPRESSION(expr); |
| RECURSE_EXPRESSION(Visit(expr->expression())); |
| } |
| |
| template <class Subclass> |
| void AstTraversalVisitor<Subclass>::VisitAwait(Await* expr) { |
| PROCESS_EXPRESSION(expr); |
| 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>::VisitOptionalChain(OptionalChain* expr) { |
| PROCESS_EXPRESSION(expr); |
| RECURSE_EXPRESSION(Visit(expr->expression())); |
| } |
| |
| 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())); |
| const ZonePtrList<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())); |
| const ZonePtrList<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); |
| const ZonePtrList<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>::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 <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>::VisitThisExpression(ThisExpression* 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())); |
| 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<ClassLiteral::Property>* private_members = |
| expr->private_members(); |
| for (int i = 0; i < private_members->length(); ++i) { |
| ClassLiteralProperty* prop = private_members->at(i); |
| RECURSE_EXPRESSION(Visit(prop->value())); |
| } |
| ZonePtrList<ClassLiteral::Property>* props = expr->public_members(); |
| 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>::VisitInitializeClassMembersStatement( |
| InitializeClassMembersStatement* stmt) { |
| PROCESS_NODE(stmt); |
| ZonePtrList<ClassLiteral::Property>* 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 <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>::VisitGetTemplateObject( |
| GetTemplateObject* expr) { |
| PROCESS_EXPRESSION(expr); |
| } |
| |
| template <class Subclass> |
| void AstTraversalVisitor<Subclass>::VisitTemplateLiteral( |
| TemplateLiteral* expr) { |
| PROCESS_EXPRESSION(expr); |
| for (Expression* sub : *expr->substitutions()) { |
| RECURSE_EXPRESSION(Visit(sub)); |
| } |
| } |
| |
| template <class Subclass> |
| void AstTraversalVisitor<Subclass>::VisitImportCallExpression( |
| ImportCallExpression* expr) { |
| PROCESS_EXPRESSION(expr); |
| RECURSE_EXPRESSION(Visit(expr->argument())); |
| } |
| |
| template <class Subclass> |
| void AstTraversalVisitor<Subclass>::VisitSuperPropertyReference( |
| SuperPropertyReference* expr) { |
| PROCESS_EXPRESSION(expr); |
| RECURSE_EXPRESSION(Visit(expr->home_object())); |
| } |
| |
| template <class Subclass> |
| void AstTraversalVisitor<Subclass>::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_ |