Применение ST к деревьям разбора, генерируемым Antlr4
Сгенерированные методы доступа узлов контекста дерева разбора не соответствуют стандарту getProperty()/isProperty()/hasProperty(). В результате ST не может быть применен непосредственно к дереву разбора. Кажется, есть 3 варианта применения ST к сгенерированным деревьям разбора:
- Создайте классы адаптера модели ST для каждого сгенерированного узла контекста. Затем ST может быть применен непосредственно к сгенерированному дереву разбора. Двойная работа здесь - создание моделей адаптеров.
- Для каждого узла дерева разбора создайте узел-оболочку, соответствующий стандарту getProperty()/isProperty()/hasProperty(). Затем ST может быть применен к узлам-оберткам. Двойная работа здесь - создание узлов-обёрток. (В этом случае дерево синтаксического анализа даже не требуется; построение дерева автоматического синтаксического анализа может быть отключено, а узлы-оболочки (AST) могут быть созданы в действиях грамматики).
- Создать посетителя. Каждое посещение *() создает экземпляр ST, специфичный для посещаемого узла контекста, устанавливает параметры (которые могут быть ST, возвращенными при посещении дочерних узлов или простых строк) и возвращает ST. Это опция, которую я сейчас использую. Двойная работа здесь - это создание посетителя и назначение параметров шаблона в коде.
Есть ли опция Antlr4, которая генерирует средства доступа узлов контекста дерева разбора, которые соответствуют стандарту getProperty()/isProperty()/hasProperty()? Или есть опция ST4, которая позволяет ему обращаться к свойству () вместо поиска getProperty()?
Было бы неплохо просто создать экземпляр шаблона ST с корневым контекстным узлом в качестве параметра и позволить ST пройти по дереву.
1 ответ
Просто хотел поделиться решением, которое почти избегает дублирования работы при использовании подхода № 1 из моего вопроса.
Шаг 1: создайте адаптер модели, который использует отражение для вызова метода, который не соответствует стандарту getProperty()/isProperty()/hasProperty().
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;
}
}
}
}
Шаг 2: Зарегистрируйте модели адаптеров
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;
}
Шаг 3: реализовать метод isSubclassOf(), чтобы registerAdaptors() компилировала:
private static boolean isSubclassOf(Class<?> cls, Class<?> superCls) {
while (cls != null) {
if (cls == superCls) {
return true;
}
cls = cls.getSuperclass();
}
return false;
}