Вопрос по xtext, stringtemplate, java – Связывание Xtext с генератором кода StringTemplate
В моем текущем проекте я пытаюсь связать спецификацию DSL, написанную на xtext, и генератор кода, написанный на StringTemplate.
например, синтаксис моей спецификации DSL следующий. Я ввожу эту информацию через удобные средства редактирования, предоставляемые xText.
structs:
TempStruct
tempValue : double;
unitOfMeasurement : String;
abilities :
sensors:
TemperatureSensor
generate tempMeasurement : TempStruct;
attribute responseFormat : String;
Грамматика вышеупомянутой спецификации DSL выглядит следующим образом:
VocSpec:
'structs' ':'
(structs += Struct)+
'abilities' ':'
('sensors' ':' (sensors += Sensor)+ )+
;
Sensor:
name = ID
((attributes += Attributes ) |
(sources += Sources))*
;
Sources:
'generate' name=ID ':' type = Type ';'
;
Attributes:
'attribute' name=ID ':' type = Type ';'
;
Struct:
name = ID
(fields += Field)+
;
Field:
name=ID ':' type += Type ';'
;
XText генерирует семантическую модель, соответствующую вышеупомянутой спецификации. В нашем примере xText генерирует семантическую модель, которая содержит файлы, такие какstruct.java
, Field.java
, Attribute.java
, Sensor.java
, так далее.
Я ясно вижу, что эта семантическая модель может быть связана сStringTemplate
файл.
StringTemplate
Файл принимает объект класса. Например,StringTemplate
файл занимаетTemperatureSensor
(экземпляр датчика) в качестве ввода и генерировать код Java.
Мой вопрос заключается в том, как мне создать экземпляр семантической модели (сгенерированной xText) и что мне нужно сделать, чтобы связать файлы StringTemplate?
Найдите заглушку генератора в исполняемом проекте вашего DSL. Там должен быть класс, который реализует интерфейс IGenerator. Метод #doGenerator будет вызываться с ресурсом и экземпляром IFileSystemAccess. Ресурс представляет собой концепцию EMF - в основном абстракцию над физическим местоположением ваших объектов. Он предлагает getContents, который, в свою очередь, предоставит доступ к списку экземпляров VocSpec (если фрагмент грамматики завершен). Эти экземпляры могут быть переданы вашему шаблону строки, который будет производить вывод. Вывод должен быть написан с помощью IFileSystemAccess # generateFile
Если вы хотите сделать это как самостоятельный процесс, вы должны следовать инструкциям вXtext FAQ, Они объясняют, как загрузить ресурс EMF. После этого вы можете сделать то же самое, что и в решении на основе Eclipse. То есть внедрить IGenerator и передать результат в IFileSystemAccess.
Чтобы дать вам краткий пример, вот что нужно сделать, чтобы начать работу через несколько минут:
Сначала вы должны включить следующий фрагмент кода в & apos; GenerateMyDsl.mwe2 & apos; файл рабочего процесса и запустить рабочий процесс.
fragment = generator.GeneratorFragment {
generateMwe = false
generateJavaMain = true
}
Вы найдете новый артефакт в пакете исполняемого проекта с суффиксом .generator. А именно «Main.java»; файл.
Второй шаг заключается в реализации генератора. Следующий фрагмент может быть использован в «MyDslGenerator.xtend». учебный класс:
package org.xtext.example.mydsl.generator
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.xtext.generator.IGenerator
import org.eclipse.xtext.generator.IFileSystemAccess
import org.antlr.stringtemplate.StringTemplate
import org.antlr.stringtemplate.language.DefaultTemplateLexer
import org.xtext.example.mydsl.myDsl.Model
class MyDslGenerator implements IGenerator {
override void doGenerate(Resource resource, IFileSystemAccess fsa) {
val hello = new StringTemplate("Generated with StringTemplate, $greeting.name$!", typeof(DefaultTemplateLexer))
val model = resource.contents.head as Model
hello.setAttribute("greeting", model.greetings.head)
fsa.generateFile("Sample.txt", hello.toString())
}
}
Эквивалент Java будет что-то вроде этого:
package org.xtext.example.mydsl.generator;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.language.DefaultTemplateLexer;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.generator.IFileSystemAccess;
import org.eclipse.xtext.generator.IGenerator;
import org.xtext.example.mydsl.myDsl.Model;
public class StringTemplateGenerator implements IGenerator {
public void doGenerate(Resource input, IFileSystemAccess fsa) {
StringTemplate hello = new StringTemplate("Generated with StringTemplate, $greeting.name$!", DefaultTemplateLexer.class);
Model model = (Model) input.getContents().get(0);
hello.setAttribute("greeting", model.getGreetings().get(0));
fsa.generateFile("Sample.txt", hello.toString());
}
}
Затем необходимо изменить содержимое заглушки «Main.java». чтобы отразить местоположение входного файла и ожидаемый выходной путь.
package org.xtext.example.mydsl.generator;
import java.util.List;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.xtext.generator.IGenerator;
import org.eclipse.xtext.generator.JavaIoFileSystemAccess;
import org.eclipse.xtext.util.CancelIndicator;
import org.eclipse.xtext.validation.CheckMode;
import org.eclipse.xtext.validation.IResourceValidator;
import org.eclipse.xtext.validation.Issue;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Provider;
public class Main {
public static void main(String[] args) {
Injector injector = new MyDslStandaloneSetupGenerated().createInjectorAndDoEMFRegistration();
Main main = injector.getInstance(Main.class);
main.runGenerator("input/Sample.mydsl");
}
@Inject
private Provider<ResourceSet> resourceSetProvider;
@Inject
private IResourceValidator validator;
@Inject
private IGenerator generator;
@Inject
private JavaIoFileSystemAccess fileAccess;
protected void runGenerator(String string) {
// load the resource
ResourceSet set = resourceSetProvider.get();
Resource resource = set.getResource(URI.createURI(string), true);
// validate the resource
List<Issue> list = validator.validate(resource, CheckMode.ALL, CancelIndicator.NullImpl);
if (!list.isEmpty()) {
for (Issue issue : list) {
System.err.println(issue);
}
return;
}
// configure and start the generator
fileAccess.setOutputPath("output/");
generator.doGenerate(resource, fileAccess);
System.out.println("Code generation finished.");
}
}
Входной файл находится во время выполнения проекта во вновь созданной папке «input». Содержимое файла "Sample.mydsl" является
Hello Pankesh!
Теперь вы можете запустить основной класс, и после быстрого обновления в Eclipse вы обнаружите новый & quot; выходной & apos; папка в моем исполняемом проекте с одним файлом «Sample.txt»:
Generated with StringTemplate, Pankesh!
Кстати, документация Xtext содержитруководство о том, как генерировать код с помощью Xtend - это лучше, чем StringTemplate, потому что он, кажется, без проблем интегрируется с Eclipse и существующими утилитами Java:
package org.xtext.example.mydsl.generator
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.xtext.generator.IFileSystemAccess
import org.eclipse.xtext.generator.IGenerator
import org.xtext.example.mydsl.myDsl.Model
class MyDslGenerator implements IGenerator {
override void doGenerate(Resource resource, IFileSystemAccess fsa) {
val model = resource.contents.head as Model
fsa.generateFile("Sample.txt", '''
Generated with Xtend, «model.greetings.head»!
''')
}
}