v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
ast-traversal-visitor.h
Go to the documentation of this file.
1// Copyright 2016 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_AST_AST_TRAVERSAL_VISITOR_H_
6#define V8_AST_AST_TRAVERSAL_VISITOR_H_
7
8#include "src/ast/ast.h"
9#include "src/ast/scopes.h"
11
12namespace v8 {
13namespace internal {
14
15// ----------------------------------------------------------------------------
16// Traversal visitor
17// - fully traverses the entire AST.
18//
19// Sub-class should parametrize AstTraversalVisitor with itself, e.g.:
20// class SpecificVisitor : public AstTraversalVisitor<SpecificVisitor> { ... }
21//
22// It invokes VisitNode on each AST node, before proceeding with its subtrees.
23// It invokes VisitExpression (after VisitNode) on each AST node that is an
24// expression, before proceeding with its subtrees.
25// It proceeds with the subtrees only if these two methods return true.
26// Sub-classes may override VisitNode and VisitExpressions, whose implementation
27// is dummy here. Or they may override the specific Visit* methods.
28
29template <class Subclass>
30class AstTraversalVisitor : public AstVisitor<Subclass> {
31 public:
32 explicit AstTraversalVisitor(Isolate* isolate, AstNode* root = nullptr);
33 explicit AstTraversalVisitor(uintptr_t stack_limit, AstNode* root = nullptr);
36
37 void Run() {
39 Visit(root_);
40 }
41
42 bool VisitNode(AstNode* node) { return true; }
43 bool VisitExpression(Expression* node) { return true; }
44
45 // Iteration left-to-right.
47 void VisitStatements(const ZonePtrList<Statement>* statements);
48
49// Individual nodes
50#define DECLARE_VISIT(type) void Visit##type(type* node);
52#undef DECLARE_VISIT
53
54 protected:
55 int depth() const { return depth_; }
56
57 private:
59
61 int depth_;
62};
63
64// ----------------------------------------------------------------------------
65// Implementation of AstTraversalVisitor
66
67#define PROCESS_NODE(node) do { \
68 if (!(this->impl()->VisitNode(node))) return; \
69 } while (false)
70
71#define PROCESS_EXPRESSION(node) do { \
72 PROCESS_NODE(node); \
73 if (!(this->impl()->VisitExpression(node))) return; \
74 } while (false)
75
76#define RECURSE(call) \
77 do { \
78 DCHECK(!HasStackOverflow()); \
79 this->impl()->call; \
80 if (HasStackOverflow()) return; \
81 } while (false)
82
83#define RECURSE_EXPRESSION(call) \
84 do { \
85 DCHECK(!HasStackOverflow()); \
86 ++depth_; \
87 this->impl()->call; \
88 --depth_; \
89 if (HasStackOverflow()) return; \
90 } while (false)
91
92template <class Subclass>
94 AstNode* root)
95 : root_(root), depth_(0) {
96 InitializeAstVisitor(isolate);
97}
98
99template <class Subclass>
101 AstNode* root)
102 : root_(root), depth_(0) {
103 InitializeAstVisitor(stack_limit);
104}
105
106template <class Subclass>
108 Declaration::List* decls) {
109 for (Declaration* decl : *decls) {
110 RECURSE(Visit(decl));
111 }
112}
113
114template <class Subclass>
116 const ZonePtrList<Statement>* stmts) {
117 for (int i = 0; i < stmts->length(); ++i) {
118 Statement* stmt = stmts->at(i);
119 RECURSE(Visit(stmt));
120 }
121}
122
123template <class Subclass>
125 VariableDeclaration* decl) {
126 PROCESS_NODE(decl);
127}
128
129template <class Subclass>
130void AstTraversalVisitor<Subclass>::VisitFunctionDeclaration(
131 FunctionDeclaration* decl) {
132 PROCESS_NODE(decl);
133 RECURSE(Visit(decl->fun()));
134}
135
136template <class Subclass>
137void AstTraversalVisitor<Subclass>::VisitBlock(Block* stmt) {
138 PROCESS_NODE(stmt);
139 if (stmt->scope() != nullptr) {
140 RECURSE_EXPRESSION(VisitDeclarations(stmt->scope()->declarations()));
141 }
142 RECURSE(VisitStatements(stmt->statements()));
143}
144
145template <class Subclass>
146void AstTraversalVisitor<Subclass>::VisitExpressionStatement(
147 ExpressionStatement* stmt) {
148 PROCESS_NODE(stmt);
149 RECURSE(Visit(stmt->expression()));
150}
151
152template <class Subclass>
153void AstTraversalVisitor<Subclass>::VisitEmptyStatement(EmptyStatement* stmt) {}
154
155template <class Subclass>
156void AstTraversalVisitor<Subclass>::VisitSloppyBlockFunctionStatement(
157 SloppyBlockFunctionStatement* stmt) {
158 PROCESS_NODE(stmt);
159 RECURSE(Visit(stmt->statement()));
160}
161
162template <class Subclass>
163void AstTraversalVisitor<Subclass>::VisitIfStatement(IfStatement* stmt) {
164 PROCESS_NODE(stmt);
165 RECURSE(Visit(stmt->condition()));
166 RECURSE(Visit(stmt->then_statement()));
167 RECURSE(Visit(stmt->else_statement()));
168}
169
170template <class Subclass>
171void AstTraversalVisitor<Subclass>::VisitContinueStatement(
172 ContinueStatement* stmt) {
173 PROCESS_NODE(stmt);
174}
175
176template <class Subclass>
177void AstTraversalVisitor<Subclass>::VisitBreakStatement(BreakStatement* stmt) {
178 PROCESS_NODE(stmt);
179}
180
181template <class Subclass>
182void AstTraversalVisitor<Subclass>::VisitReturnStatement(
183 ReturnStatement* stmt) {
184 PROCESS_NODE(stmt);
185 RECURSE(Visit(stmt->expression()));
186}
187
188template <class Subclass>
189void AstTraversalVisitor<Subclass>::VisitWithStatement(WithStatement* stmt) {
190 PROCESS_NODE(stmt);
191 RECURSE(Visit(stmt->expression()));
192 RECURSE(Visit(stmt->statement()));
193}
194
195template <class Subclass>
196void AstTraversalVisitor<Subclass>::VisitSwitchStatement(
197 SwitchStatement* stmt) {
198 PROCESS_NODE(stmt);
199 RECURSE(Visit(stmt->tag()));
200
201 ZonePtrList<CaseClause>* clauses = stmt->cases();
202 for (int i = 0; i < clauses->length(); ++i) {
203 CaseClause* clause = clauses->at(i);
204 if (!clause->is_default()) {
205 Expression* label = clause->label();
206 RECURSE(Visit(label));
207 }
208 const ZonePtrList<Statement>* stmts = clause->statements();
209 RECURSE(VisitStatements(stmts));
210 }
211}
212
213template <class Subclass>
214void AstTraversalVisitor<Subclass>::VisitDoWhileStatement(
215 DoWhileStatement* stmt) {
216 PROCESS_NODE(stmt);
217 RECURSE(Visit(stmt->body()));
218 RECURSE(Visit(stmt->cond()));
219}
220
221template <class Subclass>
222void AstTraversalVisitor<Subclass>::VisitWhileStatement(WhileStatement* stmt) {
223 PROCESS_NODE(stmt);
224 RECURSE(Visit(stmt->cond()));
225 RECURSE(Visit(stmt->body()));
226}
227
228template <class Subclass>
229void AstTraversalVisitor<Subclass>::VisitForStatement(ForStatement* stmt) {
230 PROCESS_NODE(stmt);
231 if (stmt->init() != nullptr) {
232 RECURSE(Visit(stmt->init()));
233 }
234 if (stmt->cond() != nullptr) {
235 RECURSE(Visit(stmt->cond()));
236 }
237 if (stmt->next() != nullptr) {
238 RECURSE(Visit(stmt->next()));
239 }
240 RECURSE(Visit(stmt->body()));
241}
242
243template <class Subclass>
244void AstTraversalVisitor<Subclass>::VisitForInStatement(ForInStatement* stmt) {
245 PROCESS_NODE(stmt);
246 RECURSE(Visit(stmt->each()));
247 RECURSE(Visit(stmt->subject()));
248 RECURSE(Visit(stmt->body()));
249}
250
251template <class Subclass>
252void AstTraversalVisitor<Subclass>::VisitForOfStatement(ForOfStatement* stmt) {
253 PROCESS_NODE(stmt);
254 RECURSE(Visit(stmt->each()));
255 RECURSE(Visit(stmt->subject()));
256 RECURSE(Visit(stmt->body()));
257}
258
259template <class Subclass>
260void AstTraversalVisitor<Subclass>::VisitTryCatchStatement(
261 TryCatchStatement* stmt) {
262 PROCESS_NODE(stmt);
263 RECURSE(Visit(stmt->try_block()));
264 RECURSE(Visit(stmt->catch_block()));
265}
266
267template <class Subclass>
268void AstTraversalVisitor<Subclass>::VisitTryFinallyStatement(
269 TryFinallyStatement* stmt) {
270 PROCESS_NODE(stmt);
271 RECURSE(Visit(stmt->try_block()));
272 RECURSE(Visit(stmt->finally_block()));
273}
274
275template <class Subclass>
276void AstTraversalVisitor<Subclass>::VisitDebuggerStatement(
277 DebuggerStatement* stmt) {
278 PROCESS_NODE(stmt);
279}
280
281template <class Subclass>
282void AstTraversalVisitor<Subclass>::VisitFunctionLiteral(
283 FunctionLiteral* expr) {
284 PROCESS_EXPRESSION(expr);
285 DeclarationScope* scope = expr->scope();
286 RECURSE_EXPRESSION(VisitDeclarations(scope->declarations()));
287 // A lazily parsed function literal won't have a body.
288 if (expr->scope()->was_lazily_parsed()) return;
289 RECURSE_EXPRESSION(VisitStatements(expr->body()));
290}
291
292template <class Subclass>
293void AstTraversalVisitor<Subclass>::VisitNativeFunctionLiteral(
294 NativeFunctionLiteral* expr) {
295 PROCESS_EXPRESSION(expr);
296}
297
298template <class Subclass>
299void AstTraversalVisitor<Subclass>::VisitConditionalChain(
300 ConditionalChain* expr) {
301 PROCESS_EXPRESSION(expr);
302 for (size_t i = 0; i < expr->conditional_chain_length(); ++i) {
303 RECURSE_EXPRESSION(Visit(expr->condition_at(i)));
304 RECURSE_EXPRESSION(Visit(expr->then_expression_at(i)));
305 }
306 RECURSE(Visit(expr->else_expression()));
307}
308
309template <class Subclass>
310void AstTraversalVisitor<Subclass>::VisitConditional(Conditional* expr) {
311 PROCESS_EXPRESSION(expr);
312 RECURSE_EXPRESSION(Visit(expr->condition()));
313 RECURSE_EXPRESSION(Visit(expr->then_expression()));
314 RECURSE_EXPRESSION(Visit(expr->else_expression()));
315}
316
317template <class Subclass>
318void AstTraversalVisitor<Subclass>::VisitVariableProxy(VariableProxy* expr) {
319 PROCESS_EXPRESSION(expr);
320}
321
322template <class Subclass>
323void AstTraversalVisitor<Subclass>::VisitLiteral(Literal* expr) {
324 PROCESS_EXPRESSION(expr);
325}
326
327template <class Subclass>
328void AstTraversalVisitor<Subclass>::VisitRegExpLiteral(RegExpLiteral* expr) {
329 PROCESS_EXPRESSION(expr);
330}
331
332template <class Subclass>
333void AstTraversalVisitor<Subclass>::VisitObjectLiteral(ObjectLiteral* expr) {
334 PROCESS_EXPRESSION(expr);
335 const ZonePtrList<ObjectLiteralProperty>* props = expr->properties();
336 for (int i = 0; i < props->length(); ++i) {
337 ObjectLiteralProperty* prop = props->at(i);
338 RECURSE_EXPRESSION(Visit(prop->key()));
339 RECURSE_EXPRESSION(Visit(prop->value()));
340 }
341}
342
343template <class Subclass>
344void AstTraversalVisitor<Subclass>::VisitArrayLiteral(ArrayLiteral* expr) {
345 PROCESS_EXPRESSION(expr);
346 const ZonePtrList<Expression>* values = expr->values();
347 for (int i = 0; i < values->length(); ++i) {
348 Expression* value = values->at(i);
349 RECURSE_EXPRESSION(Visit(value));
350 }
351}
352
353template <class Subclass>
354void AstTraversalVisitor<Subclass>::VisitAssignment(Assignment* expr) {
355 PROCESS_EXPRESSION(expr);
356 RECURSE_EXPRESSION(Visit(expr->target()));
357 RECURSE_EXPRESSION(Visit(expr->value()));
358}
359
360template <class Subclass>
361void AstTraversalVisitor<Subclass>::VisitCompoundAssignment(
362 CompoundAssignment* expr) {
363 VisitAssignment(expr);
364}
365
366template <class Subclass>
367void AstTraversalVisitor<Subclass>::VisitYield(Yield* expr) {
368 PROCESS_EXPRESSION(expr);
369 RECURSE_EXPRESSION(Visit(expr->expression()));
370}
371
372template <class Subclass>
373void AstTraversalVisitor<Subclass>::VisitYieldStar(YieldStar* expr) {
374 PROCESS_EXPRESSION(expr);
375 RECURSE_EXPRESSION(Visit(expr->expression()));
376}
377
378template <class Subclass>
379void AstTraversalVisitor<Subclass>::VisitAwait(Await* expr) {
380 PROCESS_EXPRESSION(expr);
381 RECURSE_EXPRESSION(Visit(expr->expression()));
382}
383
384template <class Subclass>
385void AstTraversalVisitor<Subclass>::VisitThrow(Throw* expr) {
386 PROCESS_EXPRESSION(expr);
387 RECURSE_EXPRESSION(Visit(expr->exception()));
388}
389
390template <class Subclass>
391void AstTraversalVisitor<Subclass>::VisitOptionalChain(OptionalChain* expr) {
392 PROCESS_EXPRESSION(expr);
393 RECURSE_EXPRESSION(Visit(expr->expression()));
394}
395
396template <class Subclass>
397void AstTraversalVisitor<Subclass>::VisitProperty(Property* expr) {
398 PROCESS_EXPRESSION(expr);
399 RECURSE_EXPRESSION(Visit(expr->obj()));
400 RECURSE_EXPRESSION(Visit(expr->key()));
401}
402
403template <class Subclass>
404void AstTraversalVisitor<Subclass>::VisitCall(Call* expr) {
405 PROCESS_EXPRESSION(expr);
406 RECURSE_EXPRESSION(Visit(expr->expression()));
407 const ZonePtrList<Expression>* args = expr->arguments();
408 for (int i = 0; i < args->length(); ++i) {
409 Expression* arg = args->at(i);
410 RECURSE_EXPRESSION(Visit(arg));
411 }
412}
413
414template <class Subclass>
415void AstTraversalVisitor<Subclass>::VisitCallNew(CallNew* expr) {
416 PROCESS_EXPRESSION(expr);
417 RECURSE_EXPRESSION(Visit(expr->expression()));
418 const ZonePtrList<Expression>* args = expr->arguments();
419 for (int i = 0; i < args->length(); ++i) {
420 Expression* arg = args->at(i);
421 RECURSE_EXPRESSION(Visit(arg));
422 }
423}
424
425template <class Subclass>
426void AstTraversalVisitor<Subclass>::VisitCallRuntime(CallRuntime* expr) {
427 PROCESS_EXPRESSION(expr);
428 const ZonePtrList<Expression>* args = expr->arguments();
429 for (int i = 0; i < args->length(); ++i) {
430 Expression* arg = args->at(i);
431 RECURSE_EXPRESSION(Visit(arg));
432 }
433}
434
435template <class Subclass>
436void AstTraversalVisitor<Subclass>::VisitUnaryOperation(UnaryOperation* expr) {
437 PROCESS_EXPRESSION(expr);
438 RECURSE_EXPRESSION(Visit(expr->expression()));
439}
440
441template <class Subclass>
442void AstTraversalVisitor<Subclass>::VisitCountOperation(CountOperation* expr) {
443 PROCESS_EXPRESSION(expr);
444 RECURSE_EXPRESSION(Visit(expr->expression()));
445}
446
447template <class Subclass>
448void AstTraversalVisitor<Subclass>::VisitBinaryOperation(
449 BinaryOperation* expr) {
450 PROCESS_EXPRESSION(expr);
451 RECURSE_EXPRESSION(Visit(expr->left()));
452 RECURSE_EXPRESSION(Visit(expr->right()));
453}
454
455template <class Subclass>
456void AstTraversalVisitor<Subclass>::VisitNaryOperation(NaryOperation* expr) {
457 PROCESS_EXPRESSION(expr);
458 RECURSE_EXPRESSION(Visit(expr->first()));
459 for (size_t i = 0; i < expr->subsequent_length(); ++i) {
460 RECURSE_EXPRESSION(Visit(expr->subsequent(i)));
461 }
462}
463
464template <class Subclass>
465void AstTraversalVisitor<Subclass>::VisitCompareOperation(
466 CompareOperation* expr) {
467 PROCESS_EXPRESSION(expr);
468 RECURSE_EXPRESSION(Visit(expr->left()));
469 RECURSE_EXPRESSION(Visit(expr->right()));
470}
471
472template <class Subclass>
473void AstTraversalVisitor<Subclass>::VisitThisExpression(ThisExpression* expr) {
474 PROCESS_EXPRESSION(expr);
475}
476
477template <class Subclass>
478void AstTraversalVisitor<Subclass>::VisitClassLiteral(ClassLiteral* expr) {
479 PROCESS_EXPRESSION(expr);
480 if (expr->extends() != nullptr) {
481 RECURSE_EXPRESSION(Visit(expr->extends()));
482 }
483 RECURSE_EXPRESSION(Visit(expr->constructor()));
484 if (expr->static_initializer() != nullptr) {
485 RECURSE_EXPRESSION(Visit(expr->static_initializer()));
486 }
487 if (expr->instance_members_initializer_function() != nullptr) {
488 RECURSE_EXPRESSION(Visit(expr->instance_members_initializer_function()));
489 }
490 ZonePtrList<ClassLiteral::Property>* private_members =
491 expr->private_members();
492 for (int i = 0; i < private_members->length(); ++i) {
493 ClassLiteralProperty* prop = private_members->at(i);
494 RECURSE_EXPRESSION(Visit(prop->value()));
495 }
496 ZonePtrList<ClassLiteral::Property>* props = expr->public_members();
497 for (int i = 0; i < props->length(); ++i) {
498 ClassLiteralProperty* prop = props->at(i);
499 if (!prop->key()->IsLiteral()) {
500 RECURSE_EXPRESSION(Visit(prop->key()));
501 }
502 RECURSE_EXPRESSION(Visit(prop->value()));
503 }
504}
505
506template <class Subclass>
507void AstTraversalVisitor<Subclass>::VisitInitializeClassMembersStatement(
508 InitializeClassMembersStatement* stmt) {
509 PROCESS_NODE(stmt);
510 ZonePtrList<ClassLiteral::Property>* props = stmt->fields();
511 for (int i = 0; i < props->length(); ++i) {
512 ClassLiteralProperty* prop = props->at(i);
513 if (!prop->key()->IsLiteral()) {
514 RECURSE(Visit(prop->key()));
515 }
516 RECURSE(Visit(prop->value()));
517 }
518}
519
520template <class Subclass>
521void AstTraversalVisitor<Subclass>::VisitInitializeClassStaticElementsStatement(
522 InitializeClassStaticElementsStatement* stmt) {
523 PROCESS_NODE(stmt);
524 ZonePtrList<ClassLiteral::StaticElement>* elements = stmt->elements();
525 for (int i = 0; i < elements->length(); ++i) {
526 ClassLiteral::StaticElement* element = elements->at(i);
527 switch (element->kind()) {
529 ClassLiteral::Property* prop = element->property();
530 if (!prop->key()->IsLiteral()) {
531 RECURSE(Visit(prop->key()));
532 }
533 RECURSE(Visit(prop->value()));
534 break;
535 }
537 RECURSE(Visit(element->static_block()));
538 break;
539 }
540 }
541}
542
543template <class Subclass>
544void AstTraversalVisitor<Subclass>::VisitAutoAccessorGetterBody(
545 AutoAccessorGetterBody* stmt) {
546 PROCESS_NODE(stmt);
547}
548
549template <class Subclass>
550void AstTraversalVisitor<Subclass>::VisitAutoAccessorSetterBody(
551 AutoAccessorSetterBody* stmt) {
552 PROCESS_NODE(stmt);
553}
554
555template <class Subclass>
556void AstTraversalVisitor<Subclass>::VisitSpread(Spread* expr) {
557 PROCESS_EXPRESSION(expr);
558 RECURSE_EXPRESSION(Visit(expr->expression()));
559}
560
561template <class Subclass>
562void AstTraversalVisitor<Subclass>::VisitEmptyParentheses(
563 EmptyParentheses* expr) {
564 PROCESS_EXPRESSION(expr);
565}
566
567template <class Subclass>
568void AstTraversalVisitor<Subclass>::VisitGetTemplateObject(
569 GetTemplateObject* expr) {
570 PROCESS_EXPRESSION(expr);
571}
572
573template <class Subclass>
574void AstTraversalVisitor<Subclass>::VisitTemplateLiteral(
575 TemplateLiteral* expr) {
576 PROCESS_EXPRESSION(expr);
577 for (Expression* sub : *expr->substitutions()) {
578 RECURSE_EXPRESSION(Visit(sub));
579 }
580}
581
582template <class Subclass>
583void AstTraversalVisitor<Subclass>::VisitImportCallExpression(
584 ImportCallExpression* expr) {
585 PROCESS_EXPRESSION(expr);
586 RECURSE_EXPRESSION(Visit(expr->specifier()));
587 if (expr->import_options()) {
588 RECURSE_EXPRESSION(Visit(expr->import_options()));
589 }
590}
591
592template <class Subclass>
593void AstTraversalVisitor<Subclass>::VisitSuperPropertyReference(
594 SuperPropertyReference* expr) {
595 PROCESS_EXPRESSION(expr);
596}
597
598template <class Subclass>
599void AstTraversalVisitor<Subclass>::VisitSuperCallReference(
600 SuperCallReference* expr) {
601 PROCESS_EXPRESSION(expr);
602 RECURSE_EXPRESSION(VisitVariableProxy(expr->new_target_var()));
603 RECURSE_EXPRESSION(VisitVariableProxy(expr->this_function_var()));
604}
605
606template <class Subclass>
607void AstTraversalVisitor<Subclass>::VisitSuperCallForwardArgs(
608 SuperCallForwardArgs* expr) {
609 PROCESS_EXPRESSION(expr);
610 RECURSE_EXPRESSION(Visit(expr->expression()));
611}
612
613#undef PROCESS_NODE
614#undef PROCESS_EXPRESSION
615#undef RECURSE_EXPRESSION
616#undef RECURSE
617
618} // namespace internal
619} // namespace v8
620
621#endif // V8_AST_AST_TRAVERSAL_VISITOR_H_
#define RECURSE(call)
Definition asm-parser.cc:68
#define PROCESS_NODE(node)
#define PROCESS_EXPRESSION(node)
#define DECLARE_VISIT(type)
#define RECURSE_EXPRESSION(call)
#define AST_NODE_LIST(V)
Definition ast.h:121
void VisitDeclarations(Declaration::List *declarations)
void VisitStatements(const ZonePtrList< Statement > *statements)
AstTraversalVisitor(uintptr_t stack_limit, AstNode *root=nullptr)
AstTraversalVisitor(Isolate *isolate, AstNode *root=nullptr)
AstTraversalVisitor & operator=(const AstTraversalVisitor &)=delete
AstTraversalVisitor(const AstTraversalVisitor &)=delete
void Visit(AstNode *node)
Definition ast.h:2936
ClassLiteralProperty Property
Definition ast.h:2703
ClassLiteralStaticElement StaticElement
Definition ast.h:2704
V8_INLINE int length() const
Definition zone-list.h:101
T & at(int i) const
Definition zone-list.h:88
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
Label label
ZoneList< T * > ZonePtrList
#define DCHECK_NOT_NULL(val)
Definition logging.h:492