When antlr generates java code for visitor pattern, we get a base visitor class.
public class YxBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements YxVisitor<T> {
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitProgram(YxParser.ProgramContext ctx) { return visitChildren(ctx); }
}
I have a derived class called ASTBuilder
from YxBaseVisitor
. So when I need to use the ASTBuilder
to visit the ParseTree
node, I will call function
ParseTree parseTreeRoot = parser.program();
ASTBuilder astBuilder = new ASTBuilder(gScope);
ASTRoot = (RootNode)astBuilder.visit(parseTreeRoot);
This piece of code calls the visit
method of ASTBuilder
, but ASTBuilder
didn't define visit
method, instead, it inherit visit
from AbstractParseTreeVisitor
, which is also generated by antlr.
However, the visit
is define with return null;
, and I didn't find other override of visit to distribute different types of ParseTree
node.
How did the visit pattern work?
it inherit visit from AbstractParseTreeVisitor, which is also generated by antlr.
AbstractParseTreeVisitor
is not generated, it's part of the runtime library. YxVisitor
and YxBaseVisitor
are the ones that are being generated.
However, the
visit
is define withreturn null;
I'm not sure how you came to that conclusion, but that's not true. It's actually defined as return tree.accept(this);
(source).
Now, the accept
method that's being called here will be overridden in each of the generated tree classes to call the corresponding visitFoo
method in YxVisitor
, e.g. ProgramContext.accept
will be overridden to call YxVisitor.visitProgram(this)
and that's how your visitProgram
method ends up being called.