4

私の現在のプロジェクトでは、xtextで記述されたDSL仕様と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.javaAttribute.javaSensor.java

このセマンティックモデルをファイルにリンクできることがはっきりとわかりStringTemplateます。StringTemplateファイルはクラスのオブジェクトを取ります。たとえば、StringTemplateファイルはTemperatureSensor(Sensorのインスタンス)を入力として受け取り、Javaコードを生成します。

私の質問は、セマンティックモデル(xTextによって生成される)をインスタンス化する方法と、StringTemplateファイルとリンクするために何をする必要があるかです。

4

1 に答える 1

7

Eclipse内からStringTemplateを使用してコードを生成する場合:

DSLのランタイムプロジェクトでジェネレータスタブを見つけます。IGeneratorインターフェースを実装するクラスが必要です。メソッド#doGeneratorは、リソースとIFileSystemAccessのインスタンスを使用して呼び出されます。リソースはEMFの概念であり、基本的にはオブジェクトの物理的な場所を抽象化したものです。getContentsを提供し、VocSpecのインスタンスのリストへのアクセスを提供します(文法スニペットが完了している場合)。これらのインスタンスは、出力を生成する文字列テンプレートに渡すことができます。出力は、IFileSystemAccess#generateFileを使用して書き込む必要があります

これをスタンドアロンプ​​ロセスとして実行する場合は、XtextFAQの手順に従う必要があります。EMFリソースをロードする方法を説明します。その後、Eclipseベースのソリューションとほぼ同じように実行できます。つまり、IGeneratorを実装し、結果をIFileSystemAccessに渡します。

簡単な例を挙げると、これは数分で開始するために実行する必要があることです。

まず、「GenerateMyDsl.mwe2」ワークフローファイルで次のコードスニペットを有効にして、ワークフローを実行する必要があります。

fragment = generator.GeneratorFragment {
    generateMwe = false
    generateJavaMain = true
}

ランタイムプロジェクトのパッケージに、接尾辞.generatorが付いた新しいアーティファクトがあります。つまり、「Main.java」ファイルです。

2番目のステップは、ジェネレーターを実装することです。次のスニペットは、「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ですばやく更新した後、ランタイムプロジェクトに単一のファイル「Sample.txt」を含む新しい「output」フォルダーが見つかります。

Generated with StringTemplate, Pankesh!

ところで:Xtextのドキュメントには、 Xtendを使用してコードを生成する方法に関するチュートリアルが含まれています-Eclipseや既存のJavaユーティリティと一見統合されていないため、StringTemplateよりも優れています。

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»!
        ''')
    }
}
于 2012-06-06T19:24:48.457 に答える