// 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_