Getting Started with Xtext

Xtext has been released as a part of the Eclipse Galileo release train on June 24th, 2009. Xtext is a framework for building DLSs (domain specific languages). In fact, it can be seen as a DSL for defining DSLs.

In this article, we will develop a small DSL for defining entities.

Download and Install

Hop over to http://xtext.itemis.com and download an Xtext distribution matching your platform. We've got all major platforms: Windows, Mac OSX Carbon, Mac OSX Cocoa 64, Mac OSX Cocoa 32, Linux Gtk 64, Linux Gtk 32.

To install, unzip the distribution file to a directory of your liking.

Windows users, please make sure you unzip to a directory near to your filesystem root! Eclipse contains files and folders with long names that might be hard to handle for Windows.

Create a new project

After launching Eclipse and creating a new workspace (or using an existing one), create a new Xtext project by selecting File -> New... Project... -> Xtext Project. In this article, we're creating a DSL for describing entities, so let's go with the following settings:

  • Main project name: org.xtext.example.entity
  • Language name: org.xtext.example.Entity
  • DSL-File extension: entity
  • Create generator project: yes

Click Finish to let Xtext create the three projects that make up your DSL:

  • org.xtext.example.entity - this project contains the DSL itself, including all back end infrastructure like the parser and the meta model.
  • org.xtext.example.entity.ui - as the name implies, this project contains all UI centric code of the DSL: the editor, the outline, content assist and so forth
  • org.xtext.example.entity.generator - this project contains a code generator which will transform the DSL scripts (aka models) you write in your DSL into something useful. In our example, we will create some POJOs and DAOs from our models.

Upon finishing creating these three projects, Xtext opens a file Entity.xtext, which contains a sample grammar, which we will change in a second.

Define the grammar for your DSL

Next up, we need to define the grammar for our DSL. To make things easier for us, let's first write down a sample model. Please open org.xtext.example.entity.generator/src/model/MyModel.entity and key in the following text:

typedef String
typedef Integer
typedef Date mapsto java.util.Date

entity Person {
  String name
  String surName
  Date birthDay
  Address home
  Address work
}

entity Boss extends Person {
  Person* employees
}

entity Address {
  String street
  String number
  String city
  String ZIP
}

Most of this model should be pretty obvious, but there are two things worth noting:

  • We define our own list of data types to gain a certain degree of flexibilty, i.e. to map them to different types in the host language, as can be seen for the Date data type, which gets mapped to java.util.Date (we might also decide to map it to java.sql.Date)
  • The star (*) denotes multiplicity. We might also have chosen square brackets (Person[] employees) or something completely different - it's largely a matter of taste.

Let's derive the grammar for this model. Open org.xtext.example.entity/src/org/xtext/example/Entity.xtext, erase its entire contents and enter the following:

grammar org.xtext.example.Entity with org.eclipse.xtext.common.Terminals
generate entity "http://www.xtext.org/example/Entity"

The first line indicates we want the new grammar to be derived from the (built-in) grammar Terminals, which defines some basic terminal rules (like STRING, ID and so forth). If you're interested, CTRL+Click on the language name to navigate to its definition.

The second line defines the name and namespace URI for our own grammar.

Let's now define that our DSL supports types. Add the following lines:

Model:
  (types+=Type)*;

Type:
  TypeDef | Entity;

This tells Xtext that our Model contains any number (i.e. 0..N, as declared by the *) of Types. What exactly a Type is needs to be specified. Apparently, a Type can be either a TypeDef or an Entity:

TypeDef:
  "typedef" name=ID ("mapsto" mappedType=JAVAID)?;

A TypeDef starts with the keyword typedef, followed by an ID making up its name. Following the name, we can optionally (hence the question mark at the end) add a mapsto clause. The fragment mappedType=JAVAID specifies that the TypeDef will later have an attribute named mappedType of type JAVAID. As JAVAID is not yet defined, we need to do so:

JAVAID:
  name=ID("." ID)*;

So, a JAVAID is a sequence of IDs and dots, making up a qualified Java type name, such as java.util.Date.

Next, let's define how to model entities:

Entity:
  "entity" name=ID ("extends" superEntity=[Entity])?
  "{"
    (attributes+=Attribute)*
  "}";

As you might have guessed, Entitys start with the keyword entity, followed by an ID as their name. They may optionally extends another entity. Surrounding a rule call with square brackets means "this is a cross reference", i.e. a reference to an already existing element.

Entitys do have Attributes (any number, to be precise), thus we have to define how Attributes look like:

Attribute:
  type=[Type] (many?="*")? name=ID;

By now, you should be able to read this rule: an Attribute has a type which is a cross reference to a Type (which is either a TypeDef or an Entity), it has an optional multiplicity indicator (the star) and - of course - if has a name.

Your grammar should look like this by now:

grammar org.xtext.example.Entity with org.eclipse.xtext.common.Terminals

generate entity "http://www.xtext.org/example/Entity"

Model:
  (types+=Type)*;

Type:
  TypeDef | Entity;

TypeDef:
  "typedef" name=ID ("mapsto" mappedType=JAVAID)?;

JAVAID:
  name=ID("." ID)*;

Entity:
  "entity" name=ID ("extends" superEntity=[Entity])?
  "{"
    (attributes+=Attribute)*
  "}";

Attribute:
  type=[Type] (many?="*")? name=ID;

Compiling the DSL

Now it is time to see the fruits of our labor. But first, we need to compile our grammar. Xtext will create:

  • a parser
  • a serializer
  • an Ecore meta model
  • a full blown Eclipse editor

from this grammar. To make this happen, please select org.xtext.example.entity/src/org/xtext/example/GenerateEntity.mwe and select Run As -> MWE Workflow from the context menu. Xtext will now generate the entire infrastructure for your DSL and after a few seconds you should have a shiny new DSL including a great editor.

Taking it for a spin

Seeing is believing, so let's take the DSL editor for a test drive. Select the DSL project org.xtext.example.entity and, from the context menu, select Run As -> Eclipse Application. A second instance of Eclipse will be started.

In this new instance, create a new, empty project (File -> New -> Project... -> General -> Project. Create a new file Sample.entity in the new project.

You can now insert the model we designed above or enter a new model:

Getting Started With Xtext

Leveraging the model

Now that we've got a fancy editor for our DSL, we want to transform the models we can create with this editor into something meaningful. This, however, will be the topic of the next installment.

More info

Feel free to discuss this article in the comments section of my blog. Should you have any technical questions regarding Xtext, we've got an excellent newsgroup where the committers answer your questions. We (itemis) also offer professional (commercial) support, i.e. customized trainings to get your team up to speed. Just drop us a note, we're happy to discuss the details with you.

Download the code

You can check out the code from this SVN repository location.

  1. The problem with using a person/address model is that people will instinctively feel that this kind of thing should be in a database, not a flat file format. It would be good to come up with a model that doesnt use “traditional” data.

    I thought the chess example was excellent for this. Another would be decoding the METARs for weather forecasts for flying, but that is probably a little too narrow. :-)

    I could also see it being useful to represent a ( static) website, with child pages and a navbar computed automatically (and generated with the right styles etc). I’m not sure how you’d mix an HTML snippet into the mix, or whether the DSL would contain a pointer/uri for the HTML content to be included verbatim.

    Perhaps a cut down example could use a blog, and then use the model to create an atom feed, an rss feed, and the “archive” links.

    Alex

  2. @Alex: thanks for your feedback! We’re always looking for good examples. I like the idea of a DSL for web UI flow – in fact, I’ve been using it in some tutorials I gave. I’m currently working on a DSL for UI design, this might also be a good example. Maybe you will like the entity sample better as soon as I show how to create a code generator for beans and DAOs.

    • Uli
    • June 30th, 2009

    Hi Peter,

    I tried your example, but get the following errors:

    1250 [main] ERROR eclipse.emf.mwe.core.WorkflowRunner – [ERROR]: Class not found: ‘org.xtext.example.EntityStandaloneSetup’(Element: bean register class=’org.xtext.example.EntityStandaloneSetup’ in D:/$galileo-Xtext/ws090630/org.xtext.example.entity.generator/src/workflow/EntityGenerator.mwe:8; Reported by: -UNKNOWN-)
    1250 [main] ERROR eclipse.emf.mwe.core.WorkflowRunner – Workflow interrupted because of configuration errors.

    The MWE reads as:

    I think it is a small typo somewhere, but I can not find it. Pklease help, Uli

    • Uli
    • June 30th, 2009

    the mwe reads (without the tags):
    register class=”org.xtext.example.EntityStandaloneSetup”/

  3. @Uli: running /org.xtext.example.entity.generator/src/workflow/EntityGenerator.mwe does not (yet) make sense, as we do not yet have a generator to transform the textual model into beans and DAOs. I will show how to create this code generator in a later article on this blog.

    You need to run /org.xtext.example.entity/src/org/xtext/example/GenerateEntity.mwe in order to generate the DSL editor.

    • Uli
    • June 30th, 2009

    Thanks for your hint, my fault.
    Please delete my comments, if possible

    SUccess, Uli

  4. Thank you for this post, Peter. You cannot have enough tutorials to get the people in touch with Xtext.

    To everybody who does not know what Alex meant with “the chess example” in the first comment: He refers to a talk in London I blogged about.

    • Alexander
    • July 8th, 2009

    Hi, Peter
    Great intro to Xtext!

    It has prompted me to look into using it for a project I’m currently working on… I just wondered when the next installment might be posted as I look forward to reading it.

    Thanks,
    Alex

    • DR
    • October 5th, 2009

    @Alex: thanks for your feedback! We’re always looking for good examples. I like the idea of a DSL for web UI flow – in fact, I’ve been using it in some tutorials I gave. I’m currently working on a DSL for UI design, this might also be a good example. Maybe you will like the entity sample better as soon as I show how to create a code generator for beans and DAOs.

  1. July 11th, 2009
  2. July 20th, 2009