Я использую Xtext 2.15 для создания языка, который, помимо прочего, обрабатывает асинхронные вызовы таким образом, что они выглядят синхронно.
Например, следующий код на моем языке:
int a = 1;
int b = 2;
boolean sleepSuccess = doSleep(2000); // sleep two seconds
int c = 3;
int d = 4;
сгенерирует следующий код Java:
int a = 1;
int b = 2;
doSleep(2000, new DoSleepCallback() {
public void onTrigger(boolean rc) {
boolean sleepSuccess = rc;
int c = 3;
int d = 4;
}
});
Для достижения этой цели я определил грамматику следующим образом:
grammar org.qedlang.qed.QED with jbase.Jbase // Jbase inherits Xbase
...
FunctionDeclaration return XExpression:
=>({FunctionDeclaration} type=JvmTypeReference name=ValidID '(')
(params+=FullJvmFormalParameter (',' params+=FullJvmFormalParameter)*)?
')' block=XBlockExpression
;
Правило FunctionDeclaration используется для определения асинхронных вызовов.В моей языковой библиотеке я бы имел системный вызов:
boolean doSleep(int millis) {} // async FunctionDeclaration element stub
Базовая реализация Java была бы:
public abstract class DoSleepCallback {
public abstract void onTrigger(boolean rc);
}
public void doSleep(int millis, DoSleepCallback callback) {
<perform sleep and call callback.onTrigger(<success>)>
}
Итак, используя вывод, тип компьютера и компилятор, какидентифицировать вызовы элементов FunctionDeclaration, добавить параметр обратного вызова и обработать остальную часть тела во внутреннем классе?
Я мог бы, например, переопределить appendFeatureCall в компиляторе языка, это сработает?Есть еще часть, которую я не знаю, как сделать ...
override appendFeatureCall(XAbstractFeatureCall call, ITreeAppendable b) {
...
val feature = call.feature
...
if (feature instanceof JvmExecutable) {
b.append('(')
val arguments = call.actualArguments
if (!arguments.isEmpty) {
...
arguments.appendArguments(b, shouldBreakFirstArgument)
// HERE IS THE PART I DON'T KNOW HOW TO DO
<IF feature IS A FunctionDeclaration>
<argument.appendArgument(NEW GENERATED CALLBACK PARAMETER)>
<INSERT REST OF XBlockExpression body INSIDE CALLBACK INSTANCE>
<ENDIF>
}
b.append(');')
}
}
Итак, в принципе, как определить, указывает ли "функция" на FunctionDeclaration?Остальное, я могу сделать это ...
Относительно другой записи StackOverflow , у меня была идея реализовать FunctionDeclaration в логическом элементе как класс, а не как метод:
def void inferExpressions(JvmDeclaredType it, FunctionDeclaration function) {
// now let's go over the features
for ( f : (function.block as XBlockExpression).expressions ) {
if (f instanceof FunctionDeclaration) {
members += f.toClass(f.fullyQualifiedName) [
inferVariables(f)
superTypes += typeRef(FunctionDeclarationObject)
// let's add a default constructor
members += f.toConstructor [
for (p : f.params)
parameters += p.toParameter(p.name, p.parameterType)
body = f.block
]
inferExpressions(f)
]
}
}
}
Сгенерированный класс расширит FunctionDeclarationObject, поэтому я подумал, что есть способ идентифицировать FunctionDeclaration как подклассы FunctionDeclarationObject.Но тогда мне нужно было бы расширить область видимости по умолчанию XFeatureCall, чтобы включить классы, чтобы заставить ее работать ...
Я полностью понимаю, что вопрос не очевиден, извините ...
Спасибо,
Martin
EDIT: изменено объявление DoSleepCallback со статического на абстрактное (было ошибочным)