Peter Friese is a software engineer with 15+ years hands-on experience in software development, technical writing and public speaking. Peter works as a software engineering consultant at Zühlke Engineering. Having worked on a host of industry projects in diverse domains and being an active committer on a number of open source projects, he has in-depth knowledge in a broad range of technologies. His main areas of expertise are model-driven software development, cross-platform mobile development (iPhone, Android, Windows Phone 7, and mobile web) and Eclipse tooling. Peter blogs at http://www.peterfriese.de and tweets at @peterfriese. Peter is a DZone MVB and is not an employee of DZone and has posted 29 posts at DZone. View Full User Profile

Getting Started with Xtext

06.30.2009
| 19656 views |
  • submit to reddit

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 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.

From http://www.peterfriese.de/

 

Published at DZone with permission of Peter Friese, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)