I have a simple grammar rule:
expr : expr (EQUALS | NOT_EQUALS) expr
| literal;
literal : ...; // omitted here
The lexer recognizes EQUALS
and NOT_EQUALS
:
EQUALS : '=';
NOT_EQUALS : '!=';
In my code, I want to differentiate between the equals and not equals case. I am wondering how to do this efficiently. Currently, I implement the visitor as following:
public Expression visitExpr(ExprContext ctx) {
if (ctx.EQUALS() != null) {
return EqualsExpression.construct(ctx.expr());
} else if (ctx.NOT_EQUALS() != null) {
return NotEqualsExpression.construct(ctx.expr());
} else if (ctx.literal() != null) {
return LiteralExpression.construct(ctx.literal());
}
throw new IllegalStateException();
}
I am not sure if this is very efficient, since EQUALS()
/NOT_EQUALS()
calls getToken()
, which basically loops through all children. This is done multiple times, so I am not sure if this is smart. Also, I call literal()
twice. Regarding the latter, I know I could cache in a local variable, but this will end up in pretty ugly code rather quickly if there are multiple children rules to be considered.
Is there a way to do this more efficiently? A switch/case statement based on some kind of token identifier or branch identifier would be more ideal?
sidenote
I could split the expr
rule into multiple rules as following:
expr : expr_eq | expr_not_eq | expr_literal
expr_eq : expr EQUALS expr
expr_not_eq : expr NOT_EQUALS expr
expr_literal : literal
Now, every possible branch will be visited separately by the visitor:
public Expression visitExprEx(ExprEqContext ctx) {
return EqualsExpression.construct(ctx.expr());
}
public Expression visitExprNotEq(ExprNotEqContext ctx) {
return NotEqualsExpression.construct(ctx.expr());
}
public Expression visitExprLiteral(ExprLiteralContext ctx) {
return LiteralExpression.construct(ctx.literal());
}
But looking at the G4 grammars on Github (https://github.com/antlr/grammars-v4), this is rarely done. So I am not sure if this is the way to go forward.