Создание простого предметно-ориентированного языка с использованием xtext-xbase-xtend toolchain
Это для проекта класса для создания предметно-ориентированного языка (DSL). Ничего особенного, чтобы рассмотреть. Для себя я поставил этот проект как упражнение на изучение этапов.
Используемые файлы (с прикрепленными файлами кода):
1) грамматика в Xtext (entity.xtext)
grammar org.example.xbase.entities.Entities with org.eclipse.xtext.xbase.Xbase
generate entities "http://www.example.org/xbase/entities/Entities"
Model:
entities+=Entity*;
Entity:
'entity' name=ID ('extends'
superType=JvmParameterizedTypeReference)?
'{'
attributes+=Attribute*
operations+=Operation*
'}';
Attribute:
'attr'(type=JvmTypeReference)? name=ID
('=' initexpression=XExpression)? ';';
Operation:
'op'(type=JvmTypeReference)? name=ID
'(' (params+=FullJvmFormalParameter (','
params+=FullJvmFormalParameter)*)? ')'
body=XBlockExpression;
2) JvmModelInferrer в xtend (entityJvmModelInferrer.xtend)
package org.example.xbase.entities.jvmmodel
import com.google.inject.Inject
import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder
import org.eclipse.xtext.naming.IQualifiedNameProvider
import org.example.xbase.entities.entities.Entity
class EntitiesJvmModelInferrer extends AbstractModelInferrer {
@Inject extension JvmTypesBuilder
@Inject extension IQualifiedNameProvider
def dispatch void infer(Entity entity, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
acceptor.accept(entity.toClass("Animals."+entity.name)).
initializeLater[
documentation= entity.documentation
if(entity.superType !=null)
superTypes += entity.superType.cloneWithProxies
//Create fields for each attribute in the entity
entity.attributes.forEach[
a | val type = a.type ?: a.initexpression?.inferredType
members += a.toField(a.name,type) [
documentation=a.documentation
if(a.initexpression !=null)
initializer = a.initexpression
]
//create getter method
members +=a.toGetter(a.name,type)
//create setter method
members +=a.toSetter(a.name,type)
]
//Create method for each operation in the entity
entity.operations.forEach[
op|
members+= op.toMethod(op.name,op.type?:inferredType)[
documentation=op.documentation
for (p:op.params){
parameters +=p.toParameter(p.name,p.parameterType)
}
//create a main method in one of the classes, when called. Make sure it is also static!!!
if(op.name.equals('main')){
static=true
}
body=op.body
]
]
]
}
}
3) Исходные файлы на новом языке (Animal.xentities и Main.xentities). Расширения.xentities относятся к файлам для этого проекта DSL. - Main.xentities
entity Main{
//define an instance of Animal
attr me=new Animal;
op main(){
println('main-func')
}
}
-генерированный Main.java
package Animals;
import Animals.Animal;
import org.eclipse.xtext.xbase.lib.Functions.Function0;
import org.eclipse.xtext.xbase.lib.InputOutput;
@SuppressWarnings("all")
public class Main {
private Animal me = new Function0<Animal>() {
public Animal apply() {
Animal _animal = new Animal();
return _animal;
}
}.apply();
public Animal getMe() {
return this.me;
}
public void setMe(final Animal me) {
this.me = me;
}
public static String main() {
//This is the main function I created to
//have an entry point for program execution
String _println = InputOutput.<String>println("main-func");
return _println;
}
}
-Animal.xentities
entity Animal{
//define an equivalent class in my domain-specific language
attr int nlegs;
op printAnimalSound(){
println('I grunt and sniff')
}
}
-Генерированный код Animal.java
package Animals;
import org.eclipse.xtext.xbase.lib.InputOutput;
@SuppressWarnings("all")
public class Animal {
private int nlegs;
public int getNlegs() {
return this.nlegs;
}
public void setNlegs(final int nlegs) {
this.nlegs = nlegs;
}
public String printAnimalSound() {
String _println = InputOutput.<String>println("I grunt and sniff");
return _println;
}
}
Моя цель:: Я хочу разработать базовую инфраструктуру рабочего процесса, чтобы я мог определять классы со связанными функциями и атрибутами. Тогда я хочу быть в состоянии выполнить их.
Моя проблема:: Постоянно получаю сообщение о том, что "выбор не содержит основного типа".
Моя попытка: в сущности (классе) 'Main.xentities' я создаю функцию 'op main()'. В сгенерированном коде.java это будет отображаться как публичная статическая функция String main(). Я думал, что это будет работать. Однако это не так. Я не знаю, чего не хватает. Любая помощь приветствуется.
1 ответ
Конечно, это не сработает!! Метод main должен возвращать void и принимать аргументы типа String[] args; или же
public static void main(String[] args){ ...}
Мне нужно будет изменить файл JvmModelInferrer, чтобы это произошло.