- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
在我当前的项目中,我试图链接用 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.java
、Attribute.java
、等文件Sensor.java
等
我可以清楚地看到这个语义模型可以与 StringTemplate
文件链接起来。StringTemplate
文件采用类的对象。例如,StringTemplate
文件将 TemperatureSensor
(传感器实例)作为输入并生成 Java 代码。
我的问题是如何实例化语义模型(由 xText 生成)以及我需要做什么才能链接到 StringTemplate 文件?
最佳答案
如果您想从 Eclipse 中使用 StringTemplate 生成代码:
在 DSL 的运行时项目中找到生成器 stub 。那里应该是实现 IGenerator 接口(interface)的类。这#doGenerator 方法将使用资源和 IFileSystemAccess 的实例调用。资源是一个 EMF 概念——基本上是对对象物理位置的抽象。它提供 getContents ,后者将提供对 VocSpec 实例列表的访问(如果语法片段完整)。这些实例可以传递给将产生输出的字符串模板事物。输出应该通过 IFileSystemAccess#generateFile 的方式写入
如果您想将其作为一个独立的过程来执行,您应该按照 Xtext FAQ 中的步骤进行操作.他们解释了如何加载 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());
}
}
下一步必须更改 stub “Main.java”的内容以反射(reflect)输入文件的位置和预期的输出路径。
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.");
}
}
输入文件位于新创建的文件夹“输入”中的运行时项目中。文件“Sample.mydsl”的内容是
Hello Pankesh!
现在您可以运行主类,在 Eclipse 中快速刷新后,您会在我的运行时项目中找到新的“输出”文件夹和一个文件“Sample.txt”:
Generated with StringTemplate, Pankesh!
顺便说一句:Xtext 文档包含一个 tutorial关于如何使用 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»!
''')
}
}
关于java - 将 Xtext 与 StringTemplate 代码生成器链接起来,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10917386/
我正在尝试执行 vagrant up 但一直遇到此错误: ==> default: IOError: [Errno 13] Permission denied: '/usr/local/lib/pyt
我在容器 div 中有一系列动态创建的不同高度的 div。 Varying text... Varying text... Varying text... Varying text.
通过 cygwin 运行 vagrant up 时遇到以下错误。 stderr: /bin/bash: /home/vagrant/.ansible/tmp/ansible-tmp-14872260
今天要向小伙伴们介绍的是一个能够快速地把数据制作成可视化、交互页面的 Python 框架:Streamlit,分分钟让你的数据动起来! 犹记得我在做机器学习和数据分析方面的毕设时,
我是 vagrant 的新手,正在尝试将第二个磁盘添加到我正在用 vagrant 制作的虚拟机中。 我想出了如何在第一次启动虚拟机时连接磁盘,但是当我关闭机器时 然后再次备份(使用 'vagrant
我是一名优秀的程序员,十分优秀!