5

I've defined a simple Xtext grammar which looks like this (simplified):

grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals
generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"
import "http://www.eclipse.org/emf/2002/Ecore" as ecore

System:
   'Define System'
   (
     'Define Components' '{' components+=Component+ '}'
   )
   'End'
;

Component:
    'Component' name=ID 'Value' value=Double ';'
;

Double returns ecore::EDouble:
    '-'? INT? '.' INT
;

The problem I like to solve is - how can I convert a simple Java Object to a valid xtext file?

To simplify my problem, lets say we create a list of components in Java:

List<Component> components = new ArrayList<Component>();
components.add(new Component("FirstComponent", 1.0));
components.add(new Component("SecondComponent", 2.0));
components.add(new Component("ThirdComponent", 3.0));

The output-file I like to create should look like this:

Define System
   Define Components { 
       Component FirstComponent Value 1.0;
       Component SecondComponent Value 2.0;
       Component ThirdComponent Value 3.0;
   }
End

It is important that this file is checked by the xtext grammar, so that it's valid. I Hope you have any ideas for me. Here are some of mine, but so far I don't know how to implement them:

Idea #1: I know how to read and write a file. In my head one solution could look like this: I have the list in my Java code, now I like to write a file which looks like the output-file above. Afterwards I like to read this file and check for errors by the grammar. How can I do this?

Idea #2: If I imagine I would create a xml file out of Java code using JDOM, I wish I could do the same in xtext. Just define a parent "Define System" which ends with "End" (see my output-file) and then add a child "Define Components {" which ends with "}" and then add the children to this, e.g. "Component FirstComponent Value 1.0;". I hope this isn't confusing :-)

Idea #3: I could use a template like the following and add children between the braces "{" ... "}":

Define System
   Define Components { ... }
End

Btw: I already tried Linking Xtext with StringTemplate code generator, but it is kind of another problem. Hope you have any ideas.

2 Answers 2

5

You can use Xtext's serialization for this. Unlike Java's default Serialization API, Xtext's implementation creates the DSL.

The code would look like so:

Injector injector = Guice.createInjector(new  my.dsl.MyDslRuntimeModule());  
Serializer serializer = injector.getInstance(Serializer.class);  
String s = serializer.serialize(eobj);  

where eobj is an instance of System.

If you have written a formatter for your DSL, the output will also look nice.

Related blog post: Implement toString with Xtext's Serializer

4
  • Thanks for your fast reply! I didn't thought about serialization but it seams to be best solution. I will implement it asap and let you know if it solved my problem :)
    – Michael
    Commented Sep 7, 2012 at 10:58
  • Before using your solution I had to set up a resource like Zoltán Ujhelyi reported, see below in my comment. However I did not figured out how to use his resource.save() method because it needs parameters of a Map. I marked your answer as correct because it helped me the most and the formatter was pretty interesting :) Thank you! codeSystem system = ...; // getting my System by using the generated factory.createSystem() ResourceSet set = new ResourceSetImpl(); Resource resource = set.createResource(URI.create...URI("filename")); resource.getContents.add(system);
    – Michael
    Commented Sep 13, 2012 at 6:19
  • You can either pass null or an empty map to resource.save() but it would create a file on the file system while my solution gets you a String without any temporary files. Commented Sep 13, 2012 at 6:57
  • I use the serialized string to save it to a file. Actually I don't need the string, I just need to save it to a file, but it has to be formatted like in the tutorial. Thanks for all your help.
    – Michael
    Commented Sep 13, 2012 at 11:48
3

Xtext provides an EMF-based AST for you. This AST features classes like System and Component together with their corresponding attributes, such as the Value attribute of Component. These classes are available in the src-gen folder of your language project.

To instantiate these objects, you have to use a factory class, also available in the same package.

To serialize such an AST, it is possible to reuse standard EMF tooling by creating a resource, and saving the contents. During serialization the AST is validated.

System system = ...; //Creating the AST programmatically
ResourceSet set = new ResourceSetImpl();
Resource resource = set.createResource(URI.create...URI("filename")); //Initializing an EMF resource that represents a file
resource.getContents.add(system); //adding your AST to the file resource
resource.save();

Minor remark: if you are not developing an Eclipse plug-in, you have to initialize the Xtext tooling by calling generated «YourLanguage»StandaloneSetup.doSetup() static method.

For other programmatic validation options, you can have a look at the ParseHelper and ValidatorTester classes used by the Xtext test framework.

3
  • Thanks for your reply, it helped me a little. The method resource.save() does not exist without parameters - how could you setup the "Map options" parameter? I guess it should work by using XTextResource?
    – Michael
    Commented Sep 13, 2012 at 6:35
  • You can use an empty map if you need no special options. Commented Sep 13, 2012 at 8:19
  • What if you receive here: ` java.lang.NullPointerException: Invalid context: Model returns System`? Any idea ?
    – davidmpaz
    Commented May 16, 2020 at 15:35

Not the answer you're looking for? Browse other questions tagged or ask your own question.