In my previous post about visitor pattern, C++: Visitor Pattern Dynamic vs. Static, I mentioned the Static Visitor pattern uses CRTP to do static dispatch to the corresponding method, And the business logic is implemented in that visit method, e.g. TypeCheck::visit(Add*). Therefore, the visitor not only responds for how to visit the structure, pre-order or post-order for tree, but also responds for what need to do on each visit.
When I read the code of Swift Compiler project, I found that, if I understand correctly, it seperates the visit logic and business logic in different classes. That is visitor is for visit logic, while walker for business logic.
The following code is from lib/AST/ASTWalker.cpp.
...
Expr * Traversal::doIt(Expr *E) {
// Do the pre-order visitation. If it returns false, we just
// skip entering subnodes of this tree.
auto Pre = Walker.walkToExprPre(E);
if (!Pre.first || !Pre.second)
return Pre.second;
// Otherwise, visit the children.
E = visit(Pre.second);
// If we didn't bail out, do post-order visitation.
if (E) E = Walker.walkToExprPost(E);
return E;
}
...
Expr *Traversal::visitSubscriptExpr(SubscriptExpr *E) {
if (Expr *Base = doIt(E->getBase()))
E->setBase(Base);
else
return nullptr;
if (Expr *Index = doIt(E->getIndex()))
E->setIndex(Index);
else
return nullptr;
return E;
}
...
From this code snippet, the Traversal is a subclass of ASTVisitor, which is implemented somehow like what we do in previous post. Therefore it has some visitXXX method for static dispatching, like what is showed above.
The Traversal::doIt() method is responded for visit logic, pre-order, post-order or both , just like its comments said. And the business logic, what actually needs to be done, is inside walker.walkToExprXXX() method.
This seperation enables reusing the same Traversal class for many different kinds of operations implemented in different classes, i.e. different subclasses of ASTWalker.