Связывание 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 file принимает TemperatureSensor (экземпляр Sensor) в качестве входных данных и генерирует код Java.

Мой вопрос в том, как я могу создать семантическую модель (сгенерированную xText) и что мне нужно сделать, чтобы связать с файлами StringTemplate?


person Pankesh    schedule 06.06.2012    source источник


Ответы (1)


Если вы хотите сгенерировать код с помощью StringTemplate из Eclipse:

Найдите заглушку генератора в рабочем проекте вашего DSL. Должен быть класс, реализующий интерфейс IGenerator. Метод #doGenerator будет вызываться с ресурсом и экземпляром IFileSystemAccess. Ресурс - это концепция EMF - в основном абстракция физического местоположения ваших объектов. Он предлагает getContents, который, в свою очередь, предоставит доступ к списку экземпляров VocSpec (если фрагмент грамматики завершен). Эти экземпляры могут быть переданы в ваш строковый шаблон, который будет производить вывод. Вывод должен быть записан с помощью IFileSystemAccess # generateFile.

Если вы хотите сделать это как отдельный процесс, вам следует выполнить шаги, указанные в FAQ по Xtext. Они объясняют, как загрузить ресурс EMF. После этого вы можете делать почти то же самое, что и в решении на основе Eclipse. То есть реализуйте IGenerator и передайте результат в IFileSystemAccess.

Вкратце, вот что нужно сделать, чтобы начать работу через несколько минут:

Сначала вы должны включить следующий фрагмент кода в файле рабочего процесса GenerateMyDsl.mwe2 и запустить рабочий процесс.

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 вы найдете новую папку output в моем проекте времени выполнения с одним файлом 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»!
        ''')
    }
}
person Sebastian Zarnekow    schedule 06.06.2012
comment
Спасибо, Себастьян. Я хотел бы написать свой генератор кода с помощью xtend. Но проблема в том, что наш генератор кода написан с использованием файлов строковых шаблонов. Спасибо за совет. Я попробую ваш подход. Если ничего не получится, я воспользуюсь поддержкой редактора xtext и дам им для анализа грамматику ANTLR. - person Pankesh; 06.06.2012
comment
Уважаемый Себастьян, не могли бы вы уточнить свое объяснение на примере? - person Pankesh; 07.06.2012
comment
Уважаемый Себастьян, будьте любезны пояснить ваше предложение. Он предлагает getContents, который, в свою очередь, предоставит доступ к списку экземпляров VocSpec (если фрагмент грамматики завершен). Я написал выше грамматику. вы имеете в виду, что приведенная выше грамматика не является полной для создания экземпляров? - person Pankesh; 07.06.2012
comment
Панкеш, спасибо за предложение. Я обновил ответ и добавил много фрагментов кода. - person Sebastian Zarnekow; 07.06.2012