Generated accessors of parse tree context nodes do not conform getProperty()/isProperty()/hasProperty() standard. As a result, ST can’t be applied to the parse tree directly. There seems to be 3 alternatives to apply ST to the generated parse trees:
Is there an Antlr4 option that generates accessors of parse tree context nodes that conform getProperty()/isProperty()/hasProperty() standard? Or is there an ST4 option that allows it accessing property() instead of looking for getProperty()?
It would be nice to simply instantiate an ST template with a root context node as a parameter and let ST traverse the tree.
Just wanted to share a solution that almost avoids duplicate work while using approach #1 from my question.
Step 1: create a model adaptor that uses reflection to call a method that does not conform getProperty()/isProperty()/hasProperty() standard.
private static class MyModelAdaptor extends ObjectModelAdaptor {
@Override
public synchronized Object getProperty(Interpreter interp, ST self, Object o, Object property, String propertyName) throws STNoSuchPropertyException {
try {
return super.getProperty(interp, self, o, property, propertyName);
} catch (STNoSuchPropertyException noProperty) {
final Class<?> cls = o.getClass();
try {
return cls.getMethod(propertyName).invoke(o);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw noProperty;
}
}
}
}
Step 2: Register model adaptors
public static STGroup registerAdaptors(STGroup stg) {
final MyModelAdaptor adaptor = new MyModelAdaptor();
for (final Class<?> cls : MyParser.class.getDeclaredClasses()) {
if (isSubclassOf(cls, ParserRuleContext.class)) {
stg.registerModelAdaptor(cls, adaptor);
}
}
return stg;
}
Step 3: implement isSubclassOf() method so that registerAdaptors() compiles:
private static boolean isSubclassOf(Class<?> cls, Class<?> superCls) {
while (cls != null) {
if (cls == superCls) {
return true;
}
cls = cls.getSuperclass();
}
return false;
}