Xtext Reference

Introduction
Installation
Migrating from a prior version to Xtext 4.3.1
Getting started
The Grammar Language
Lexer Rules
The Generator
Pimping the editor
Cookbook
Experimental Features

Introduction

Does this sound familiar to you?

Oh, I need to rename this misspelled property within our domain model. Ok, so let's startup this big UML tool... and by the way let's get a new cup of coffee. Cool, it has been started up already. Grabbing the mouse, clicking through the different diagrams and graph visualizations... Ahhh, there is the name of the property right down there in the properties view. Let's change it, export it to XMI (...drinking coffee), starting the oAW generator (in a jiffy ;-)). Oh, it's not allowed for the property to be named that way, a constraint says that properties names should start with a lower case letter. Ok, let's change that and again reexport...

Some moments later, everything seems to works (tests are green). Ok let's check it in!

Oh someone else has also modified the model! Aaarrrgggh....

Think of this:

Want to change a properties name? Ok, open the respective text file, rename the properties name and save it. The editor complains about a violated constraint. Ok fix the issue, save again and generate. Check the changes into SVN (CVS). Oh, there is a conflict, ok, let's simply merge it using Diff.

And now? Let's have a cup of coffee :-)

Xtext is a textual DSL development framework. Providing the ability to describe your DSL using a simple EBNF notation. Xtext will create a parser, a metamodel and a specific Eclipse text editor for you!

Installation

Xtext is part of the openArchitectureWare SDK. An easy way to install is to download and unzip the "Eclipse 3.3 for RCP/Plug-in Developers" from the download site of Eclipse (http://www.eclipse.org/downloads/).

Afterwards, download the org.openarchitectureware.all_in_one_feature-4.3.1.*.zip release from our website and extract it to the directory where you have unzipped the Eclipse release (i.e. the Eclipse installation directory).

Make sure that you start Eclipse with a Java VM Version greater than 5.0.

Migrating from a prior version to Xtext 4.3.1

If you have been using Xtext prior to version 4.3, you need to re-generate your DSL editors in order to use the updated version 4.3. To do this, please perform the followng steps:

  • In your DSL project, open generate.properties and enable overwriting of plug-in resource by setting overwrite.pluginresources to true

  • Open your grammar definition. From the context menu, select Generate Xtext Artifacts in order to re-generate the DSL and the DSL editor.

  • Finally, open the context menu of your DSL project and select PDE Tools > Update classpath.... Tick all your DSL projects and click Finish.

Since 4.3.1 we allow URIs pointing to other models to be classpath relative, which is a well-established method to access resources uniformly from within a workspace, an Eclipse plug-in or a standalone Java application. The URI resolution happens inside a special XtextResourceSet. As the classpath can be different for each project, each editor instance now manages its own XtextResourceSet.

To provide the classpath context, we had to change the signature of org::openarchitectureware::xtext::registry::Modelloader::load to load(String uri, EObject contextElement) where the resource set for the new resource is the resource set the contextElement is stored in. If you are using cross-references to other models, you have to regenerate existing Xtext artifacts.

A further extension load(String uri, EObject contextElement, boolean forceLinking) allows you to switch off linking of the loaded resource. This is used by the editor to avoid recursive loading of cross-referenced resources. Note that a resource loaded without linking will not have any cross-references set.

Getting started

If you didn't already do so, you should have a look at the ???. This will give you a good overview of how Xtext basically works. Come back to this document to find out about additional details.

The Grammar Language

At the heart of Xtext lies its grammar language. It is a lot like an extended Backus-Naur-Form, but it not only describes the concrete syntax, but can also be used to describe the abstract syntax (metamodel).

A grammar file consists of a list of so called Rules.

Example

This is an example of a rule, describing something called an entity:

Entity :
  "entity" name=ID "{"
    (features+=Feature)+
  "}";

Entity is both the name of the rule and the name of the metatype corresponding to this rule. After the colon, the description of the rule follows. A description is made up of tokens. The first token is a keyword token which says that a description of an entity starts with the keyword entity. A so-called Assignment follows (name=ID).

The left-hand side refers to a property of the metatype (in this case it is the property name of type Entity). The right-hand side is a call to the built-in token ID. Which means Identifier and allows character sequences of the form ('a-zA-Z_' ('a-zA-Z_0-9)*). The parser will assign ('=') the Identifier to the specified property (name).

Then (enclosed in curly brackets, both are essentially keyword tokens) one or more features can be declared (features+=Feature)+. This one, again, is an assignment. This time, the token points to another rule (called Feature) and each feature is added (note += operator) to the reference of the entity called features.

The Feature rule itself could be described like this:

Feature :
  type=ID name=ID ";";

so, that the following description of an entity would be valid according to the grammar:

entity Customer {
  String name;
  String street;
  Integer age;
  Boolean isPremiumCustomer;
}

Note that the types (String, Integer, Boolean) used in this description of a customer, are simple identifiers, they do not have been mapped to e.g. Java types or something else. So, according to the grammar, this would also be valid, so far:

entity X {
  X X;
  X X;
  X X;
  cjbdlfjerifuerfijerf dkjdhferifheirhf;
}

How the parsers work in general

As stated before, the grammar is not only used as input for the parser generator, but it is also used to compute a metamodel for your DSL. We will first talk about how an Xtext parser works in general, before we look at how a metamodel is being constructed.

The analysis of text is divided in two separate tasks: the lexing and the parsing.

The lexer is responsible of creating a sequence of tokens from a character stream. Such tokens are identifiers, keywords, whitespace, comments, operators, etc. Xtext comes with a set of built-in lexer rules which can be extended or overwritten if necessary. You have already seen some of them (e.g. ID).

The parser gets the stream of tokens and creates a parse tree out of them. The type rules from the example are essentially parser rules.

Now, let us have a look at how the metamodel is constructed.

Type Rules

We have already seen, how type rules work in general. The name of the rule is used as name for the metatype generated by Xtext.

Assignment tokens / Properties

Each assignment token within an Xtext grammar is not only used to create a corresponding assignment action in the parser but also to compute the properties of the current metatype.

Properties can refer to the simple types such as String, Boolean or Integer as well as to other complex metatypes (i.e. other rules). It depends on the assignment operator and the type of the token on the right, what the type actually is.

There are three different assignment operators:

  • Standard assignment '=' : The type will be computed from the token on the right.

  • Boolean assignment '?=' : The type will be Boolean.

  • Add assignment '+=' : The type will be List. The inner type of the list depends on the type returned by the token on the right.

Example:

Entity :
  (isAbstract?="abstract")? "entity" name=ID "{"
     (features+=Feature)*
  "}";
 

The metatype Entity will have three properties:

  1. Boolean isAbstract

  2. String name

  3. List[Feature] features

Cross References

Parsers construct parse trees not graphs. This means that the outcome of a parser has no crossreferences only so called containment references (composition).

In order to implement crosslinks in the model, one usually has to add third task: the linking. However, Xtext supports specifying the linking information in the grammar, so that the metamodel contains cross references and the generated linker links the model elements automatically (for most cases). Linking semantic can be arbitrary complex. Xtext generates a default semantic (find by id) which can be selectively overwritten. We will see, how this can be done, later in this document.

Let us now see in detail, what the grammar language supports:

Entity :
  "entity" name=ID ("extends" superType=[Entity])?
  "{"
     (features+=Feature)*
  "}";

Have a look at the optional extends clause. The rule name Entity on the right is surrounded by squared parenthesis. That's it.

By default, the parser expects an ID to point to the referred element. If you want another kind of token to act as a reference, you can optionally specify the type of token you want to use, separated by a vertical bar:

 ... ("extends" superType=[Entity|MyComplexTokenRule])? ...

Where MyComplexTokenRule must be either a NativeLexerRule or a StringRule (explanation follows).

Metatype Inheritance

We have seen how to define simple concrete metatypes and its features. One can also define type hierarchies using the grammar language of Xtext. Sometimes you want to abstract rules, in order to let a feature contain elements of different types.

We have seen the Feature rule in the example. If you would like to have two different kinds of Feature (e.g. Attribute and Reference), you could create an abstract type rule like this:

Feature :
  Attribute | Reference;

Attribute :
  type=ID name=ID ";";

Reference :
  "ref" (containment?="+")? type=ID name=ID ("<->" oppositeName=ID)? ";";

The transformation creating the metamodel automatically normalizes the type hierarchy. This means that properties defined in all subtypes will automatically be moved to the common supertype. In this case, the abstract type Feature would be created containing the two features (name and type). Attribute and Reference would be subtypes of Feature, inheriting those properties.

It is also possible to define concrete supertypes like this:

Feature :
  type=ID name=ID ";" | Reference;

Reference :
  "ref" (containment?="+")? type=ID name=ID ("<->" oppositeName=ID)? ";";
 

In this case Feature would not be abstract, but it would be the supertype of Reference.

If you need multiple inheritance you can simply add an abstract rule. Such a rule must not be called from another rule.

Example:

Model : TypeA TypeA TypeC;

TypeA : "A" | TypeB;
TypeB : "B";
TypeC : "C";

CommonSuper : TypeB | TypeC; // just for the type hierarchy
 

The resulting type hierarchy will look like this:

- Model

- TypeA

- TypeB extends TypeA, CommonSuper

- TypeC extends CommonSuper

- CommonSuper

Enum Rule

The enum rule is used to define enumerations. For example, if you would like to hardwire the possible data types for attributes into the language, you could just write:

Attribute :
  type=DataType name=ID ";";

Enum DataType :
  String="string" | Integer="int" | Boolean="bool";
 

In this case, this would be valid:

entity Customer {
  string name;
  string street;
  int age;
  bool isPremiumCustomer;
}

However, this would not be valid:

entity Customer {
  X name; // type X is not known
  String street; // type String is not known (case sensitivity!)
}

String Rule

Xtext provides built-in tokens. We have already seen the IdentifierToken and the KeywordToken.

Sometimes, this is not sufficient, so we might want to create our own tokens. Therefore, we have the so-called String rule , which is implemented as a parser rule (it is not a lexer rule).

Example

String JavaIdentifier :
  ID ("." ID)*;

The contents of the String rule is simply concatenated and returned as a string. One can refer to a String rule in the same manner we refer to any other rule.

So, just in case you want to declare data types using your DSL and therein specify how it is mapped to Java (not platform independent, of course, but expressive and pragmatic), you could do so using the following rules:

Attribute :
  type=DataType name=ID ";";

DataType :
  "datatype" name=ID "mappedto" javaType=JavaIdentifier;

String JavaIdentifier :
  ID ("." ID)*;

A respective model could look like this:

entity Customer {
  string name;
  string street;
  int age;
  bool isPremiumCustomer;
}

datatype string mappedto java.util.String
datatype int mappedto int
datatype bool mappedto boolean

You could of course point to a custom type mapping implementation, if you need to support multiple platforms (like e.g. SQL, WSDL, Java,...). Additionally, you should consider to define the data types in a separate file, so the users of your DSL can import and use them.

Lexer Rules

As mentioned before we Xtext provides some common built-in lexer rules. Let us start with the two simplest ones.

Keyword Tokens

All static characters or words, known as keywords, can be specified directly in the grammar using the usual string literal syntax. We never need the value of keyword because we already know it since it is static. But sometimes, there are optional keywords like e.g. the modifiers in Java. The existence of a keyword can be assigned using the boolean assignment operator "?=". However, if you want to assign the value of the keyword to a property just use the assignment operator '='.

Example:

Entity :
  (abstract?="abstract")? "entity" name=ID ("<" extends=ID)?
  "{"
    (features+=Feature)*
  "}";

With this the type Entity will have the boolean property abstract, which is set to true if the respective keyword has been specified for an entity. (The extends part is added, because an abstract entity would not make sense without inheritance).

Note that operators such as '<' in the example are keywords, too.

The ID Token

We also have seen the identifier token (ID). This is the token rule expressed in AntLR grammar syntax:

('^')?('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*

So, an identifier is a word starting with a character or an underscore, optionally followed by further characters, underscores, or digits. The return value of the ID token is a String. So, if you use the usual assignment operator "=", the feature the value is assigned to will be of type String. You could also use the boolean operator (?=) and the type will be Boolean.

If an identifier conflicts with a keyword or another lexer rule, it can be escaped with the " ^ " character.

The String Token

There is also a built-in String Token. Here is an example:

Attribute :
   type=DataType name=ID (description=STRING)? ";";

With this token, one can optionally specify a description for an entity like this:

entity Customer {
  string name ;
  string street "should include the street number, too.";
  int age;
  bool isPremiumCustomer;
}

By default, the two string literal syntaxes "my text" and 'my text' are supported. Note that, unlike in Java, also multi-line strings are supported:

entity Customer {
  string name ;
  string street "should include the street number, too.
                 And if you do not want to specify it, you
                 should consider specifying it somewhere else.";
  int age;
  bool isPremiumCustomer;
}

The INT Token

Sometimes, you want to assign Integers. Xtext supports it with the built-in lexer rule INT.

Index:
  "#" index=INT;

The default pattern is:

('-')?('0'..'9')+

It can be overwritten (see next section), but you have to take care, that the coercion (Integer.valueOf(String) is used) works.

The URI Token

If you want to allow inclusion of and references to other models, use the URI token, e.g.

Import: 
     'import' model=URI ';';

From the parser's point of view, an URI token is just a String literal enclosed in quotes. The Runtime interprets this string as the Uniform Resource Identifier (URI) of another model file whose elements can be referenced from the importing model. With the above grammar rule example, you can allow references to elements of the model file refModel.model by adding a line

import "platform:/resource/myproject/model/refModel.model";

in your model. See the section called “Cross-References to Models of the Same DSL/Metamodel” and the section called “Cross-references to Models of a Different DSL/Metamodel” for examples on model import.

Comments

There are two different kinds of comments automatically available in any Xtext language.

 // single-line comments and

  /*
    mutli-line comments
  */

Note that those comments are ignored by the language parser by default (i.e. they are not contained in the AST returned from the parser).

If you do not want ignored comments, or you want to have a different syntax, you need to overwrite the default implementation (The name of the corresponding comment rule is SL_COMMENT for single-line comments, i.e. ML_COMMENT for multi-line comments).

Whitespace

Every textual model contains whitespace. As most languages simply ignore whitespace, Xtext does so by default, too. If you want to have semantic whitespace in your language (like e.g. Python), you have to overwrite the built-in whitespace rule (its name is WS).

Native rules / Overwriting built-in lexer rules

If you want to overwrite one or more of the built-in lexer rules or add an additional one, the so-called native rule is your friend.

Example:

// overwriting SL_COMMENTS we do not want Java syntax (//) but bash syntax (#)
Native SL_COMMENT :
  "'#' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}";

// fully qualified names as a lexer rule
Native FQN :
  "ID ('.' ID)*";

The syntax is :

"Native" ID ":"
   STRING // The string contains a valid ANTLR 3 lexer rule expression 
   ";"    // (see http://www.antlr.org/wiki/display/ANTLR3/ANTLR+v3+documentation)

The Generator

It is assumed that you have used the Xtext project wizard, and that you have successfully written an Xtext grammar file describing your little language. Next up you need to start the generator of Xtext in order to get a parser, a metamodel and an editor. To do so. just right-click the workflow file (*.oaw) located next to the grammar file and choose Run As+oAW workflow (in Eclipse, of course). The generator will read the grammar file in and create a bunch of files. Some of them located in the src-gen directories others located in the src directory.

Important

IMPORTANT : You should now (after first generation) open the *.properties file and set the "overwritePluginRes=true" option to false!

Configuring the Generator

The generator can be configured with the following properties defined in generate.properties:

property name (default)description
grammarThe grammar file to generate the code from.
debug.grammar (false)Specifies whether a debug grammar should be generated. A debug grammar is an AntLR grammar without any action code, so it can be interpreted within AntLRWorks.
language.nameThe name of the DSL. Is used throughout the generated code
language.nsURI ("http://www.oaw.org/xtext/dsl/${language.name}")A unique URI used within the derived ecore package.
language.fileextension ("${language.name}")The file extension the generated editor is configured for.
overwrite.pluginresources ("false")If this is set to true the plugin resources (META-INF/MANIFEST.MF, plugin.xml) will be overwritten by the generator!!!
wipeout.src-gen ("true")Specifies whether the src-gen folders should be deleted before generation.
generator.project.name ("")If this property is set to something, a project wizard will be generated referencing the generator project.
workspace.dirThe root of the workspace.
core.project.namename of the main project
core.project.src ("src/")src folder of the main project
core.project.src.gen ("src-gen/")src-gen folder of the main project
editor.generate ("true")should an editor be generated at all
editor.project.name ("${core.project.name}.editor")name of the editor project
editor.project.src ("${core.project.src}")src folder of the editor project
editor.project.src.gen ("${core.project.src.gen}")src-gen folder of the editor project

Generated and manual code

Any textual artifacts located in the src directory (of any project) will always stay untouched. The generator just creates them the first time when they do not exist.

Files generated to the src-gen directory should never be touched! The whole directory will be wiped out the next time one starts the generator.

The different projects and artifacts

Xtext generates artifact into two different projects.

The main project

The name of the main project can be specified in the wizard. This project contains the main language artifacts and is 100% eclipse independent. The default locations of the most important resources are:

Table 23. Resources of the main project

LocationDescription

src/[dslname].xtxt

The grammar file, containing the grammar rules describing your DSL

src/generate.oaw

The workflow file for the Xtext generator.

src/generator.properties

Properties passed to the Xtext generator

src/[base.package.name]/Checks.chk

The Check-file used by the parser and within the editor. Used to add semantic constraints to your language.

src-gen/[base.package.name]/GenChecks.chk

The generated Check-file contains checks automatically derived from the grammar.

src/[base.package.name]/Extensions.ext

The Extension-file is used (imported) by all another extensions and check files. It reexports the extensions from GenExtensions.ext (contained in src-gen/). You can specify (use more concrete parameter types) or overwrite (use the same signature) the extensions from GenExtensions.ext here.

src-gen/[base.package.name]/GenExtensions.ext

generated extensions (reexported by Extensions.ext).

src/[base.package.name]/Linking.ext

Used by Linker.ext from src-gen/[base.package.name]/parser/Linker.ext Default linking semantic is generated in GenLinking.ext (src.gen/) and can be overwritten here.

src-gen/[base.package.name]/GenLinking.ext

Contains the default linking semantic for each cross reference.

Example:

  Void link_featureName(my::MetaType this) :
     (let ents = this.allVisibleElements().typeSelect(my::ReferredType) :
     this.setFeatureName(ents.select(e|e.id()
       == this.parsed_featureName).first()) );

This code means the following:

Get all instances of the referred type using the allVisibleElements() extension. Select the first one where the id() equals the parsed value (by default an identifier).

Both extensions, id() and allVisibleElements()) can be overwritten or specialized in the Extensions.ext file. The link_[featurename]() extension can be overwritten in Linking.ext

src-gen/[base.package.name]/[dslname].ecore

Metamodel derived from the grammar

src-gen/[base.package.name]/parser/*

Generated AntLR parser artifacts


The editor project

The name of the editor project is derived from the name of the main project by appending the suffix .editor to it. The editor project contains the informations specific to the Eclipse text editor. Note that it uses a generic xtext.editor plugin, which does most of the job. These are the most important resources:

Table 24. Resources of the editor

LocationDescription

src/[base.package.name]/[dslname]EditorExtensions.ext

The Xtend-file is used by the outline view. If you want to customize the labels of the outline view, you can do that here.

src-gen/[base.package.name]/[dslname]Utilities.java

Contains all the important DSL-specific information. You should subclass it in order to overwrite the default behaviours.

src/[base.package.name]/[dslname]EditorPlugin.java

If you have subclassed the *Utilities class, make sure to change the respective instantiation here.


The generator project

The name of the generator project is derived from the name of the main project by appending the suffix .generator to it. The generator project is intended to contain all needed generator resources such as Xpand templates, platform-specific Xtend files etc..

These are the most important resources:

Table 25. Resources of the generator

LocationDescription

src/[base.package.name]/generator.oaw

The generators workflow preconfigured with the generated DSL parser and the Xpand component. As this is just a proposal, feel free to change/add the workflow as you see fit.

src-gen/[base.package.name]/Main.xpt

The proposed Xpand template file.


Pimping the editor

The generated editor supports a number of features known from other eclipse editors. Although most of them have a decent default implementation, we will see how to tweak and enhance each of them.

Code Completion

Code Completion is controlled using oAW extensions. The default implementation provides keyword proposals as well as proposals for cross references.

Have a look at the extension file ContentAssist.ext. A comment in this file describes how to customize the default behaviour:

/*
 * There are two types of extensions one can define
 *
 * 1) completeMetaType_feature(ModelElement ele, String prefix)
 * This one is called for assignments only. It gets the underlying Modelelement and the current
 * prefix passed in.
 *
 * 2) completeMetaType(xtext::Element grammarEle, ModelElement ele, String prefix)
 * This one gets the grammarElement which should be completed passed in as the first parameter.
 * an xtext::Element can be of the following types :
 *  - xtext::RuleName (a call to a lexer rule (e.g. ID)),
 *  - xtext::Keyword,
 *  - xtext::Assignment
 *
 * Overwrite rules are as follows:
 * 1) if the first one returns null for a given xtext::Assignment or does not exist the second one
 *    is called.
 * 2) if the second one returns null for a given xtext::Keyword or does not exist a default keyword
 *    proposal will be added.
 *
 * Note that only propals with wich match (case-in-sensitive) the current prefix will be proposed
 * in the editor
 */

Navigation

The implementation for the navigation actions is implemented via extensions, too. As for Code completion the same pattern applies: There is a GenNavigation.ext extension file in the src-gen folder which can be overwritten or specialized using the Navigation.ext file in the src folder (reexporting the generated extensions).

There are two different actions supported by Xtext:

Find References

This action can be invoked via Ctrl-Shift-G or via the corresponding action context menu. The default implementation returns the cross references for a model element.

The signature to overwrite / specialize is:

List[UIContentNode] findReferences(String s, Object grammarelement, Object element) : ...;

A UIContentNode is a metaclass used by Xtext. An UIContentNode represents an element visualized in Eclipse.

Here is the declaration of UIContentNode (pseudo code):

package tree;

eclass UIContentNode {
   UIContentNode parent;
   UIContentNode[] children;
   String label;
   String image;
   emf::EObject context;
}

A content node can have children and / or a parent (the tree structure is not used for find references). The label is used for the label in Eclipse, and the image points to an image relative to the icons folder in the editor project. The icon instances are automatically cached and managed.

The context points to the actual model element. This is used to get the file, line and offset of the declaration. If you do not fill it, you cannot click on the item, in order to get to it.

Go to Declaration

This action can be invoked via F3 as well as by holding CTRL, hovering over an identifier and left click the mouse.

The default implementation goes to the declaration of a cross reference. You can implement or overwrite this action for all grammar elements.

emf::EObject findDeclaration(String identifier, emf::EObject grammarElement,
   emf::EObject modelElement) : ...;

Have a look at the generated extensions, to see how it works.

Outline View

The outline view is constructed using a tree of UIContentNode objects (see above).

Each time the outline view is created, the following extension is called:

UIContentNode outlineTree(emf::EObject model)

It is expected to be declared in Outline.ext, which by default exports a generic implementation from GenOutline.ext (the same pattern again).

You can either reuse the generic extension and just provide a label() and image() extension for your model elements (should be added in EditorExtensions.ext).

However, if you want to control the structure of the outline tree you can overwrite the extension outlineTree(emf::EObject model) in Outline.ext.

You can define multiple outlines for a single DSL, each representing a different viewpoint on your model. Each viewpoint needs has a unique name. Override the getViewpoints() extension to return a list of all viewpoint names. You can customize each viewpoint using the same extensions as above suffixed with the viewpoint's name (spaces are replaced by underscores. Example:

List[String] viewpoints() : { "Entities Only" };

UIContentNode outlineTree_Entities_Only(emf::EObject model) :
  let x = model.createContentNode() : 
    x.children.addAll(model.eContents.outlineTree_Entities_Only())
    // return the node, not its children
    -> x;  

UIContentNode outlineTree_Entities_Only(Model model) :
  let x = model.createContentNode() :
    // add child nodes for elements of type Entity only  
    x.children.addAll(model.types.typeSelect(Entity).outlineTree_Entities())
    -> x;

create UIContentNode createContentNode(emf::EObject model) :
  setLabel(model.label()) ->
  setImage(model.image()) ->
  setContext(model);

You can switch the viewpoints in the running editor by means of the drop-down menu behind the small triangle symbol in the action bar of the outline view.

Syntax Highlighting

The default syntax highlighting distinguishes between comments, string literals, keywords, and the rest.

You can adjust the specific display styles for keywords with regard to the context they appear in by overriding the fontstyle(String keyword, EObject metaClassName) extension in the Style.ext extension file. The predefined method createFontstyle will help you creating the FontStyle object, e.g.

FontStyle fontstyle(String keyword, Node node) :
  node.eContainer.metaType==Node 
    ? createFontStyle(true, false, false, false, 
      createColor(200,200,200), createColor(255,255,255))
    : createFontStyle(true, false, false, false, 
      createColor(255,0,0), createColor(255,255,255))
;

If you just want to specify which words to be coloured as keywords you can extend the [basepackage.][Languagename]Utilities.java class from the editor plugin. You need to overwrite the following method.

public String[] allKeywords()

Important

Do not change the Utilities class directly, because it will be overwritten the next time your start the generator.

Each String returned by the method represents a keyword.

The utilities method is created within the [LanguageName]EditorPlugin.java. So, make sure that you change the following lines, as well:

 // OLD -> private MyLangUtilities utilities = new MyLangUtilities();
  private MyCustomUtilities utilities = new MyCustomUtilities();
  public LanguageUtilities getUtilities() {
      return utilities;
  }

Cookbook

This part of the documentation deals with the discussion and solution of different requirements and problems.

Cross-References to Models of the Same DSL/Metamodel

Since version 4.3, Xtext provides first class support for cross-references to elements in other model files. This allows to spread a single model across several files or to reuse parts of a model by referencing it. The former mechanism using the built-in model registry does not work any longer.

The following example illustrates how to implement cross-resource references to models of the same DSL. Referencing elements of a foreign DSLs is shown in the section called “Cross-references to Models of a Different DSL/Metamodel”. First of all, you have to enable model import in your DSLs grammar. This is achieved by declaring a rule that matches the URI token.

Model:
  (imports+=Import)* 
  (elements+=Element)*;
    
// declare an import statement by means of a rule matching the URI token
Import:   
  'import' model=URI;

Element:
  'element' name=ID '{' 
    (ref+=Reference)*
  '}';
    
Reference:
  'ref' element=[Element];

This way, we can use the import keyword followed by a URI in our models to enable referencing. Note that import is just an arbitrary keyword and all the magic comes with the URI Token. It loads all elements from the given model and makes them available in the allVisibleElements() extension. And how does it look like on the model level? Consider the following model file:

// refModel.dsl
Element externalElement {
} 

To reference the element externalElement in another file you'll just have to import the refModel.dsl and then reference

// model.dsl
// import the model to be referenced by matching the URI token 
import "platform:/resource/myplugin/model/refModel.dsl"

Element internalElement {
}

Element myElement {
  ref internalElement  // reference by ID 
  ref externalElement  // reference by ID, as if it was in the same file
} 

Experimental Features

The features described in this section are mainly intended for advanced users. They are likely to change in the future.

Instantiate Existing Metamodels

In some cases you may want to use Xtext to create a new concrete textual syntax for an existing Ecore model. You'll have to provide a way to make Xtext's rules instantiate existing EClasses rather than the generated ones.

The Ecore model to be referenced must reside in a plug-in that is deployed in your eclipse. This plug-in must register the Ecore model to the org.eclipse.emf.ecore.generated_package or org.eclipse.emf.ecore.dynamic_package extension. Additionally, load the imported metamodel to the generation workflow using the StandaloneSetup component:

<workflow>
   <property file='generate.properties'/>
   <bean class="org.eclipse.mwe.emf.StandaloneSetup">
      <registerGeneratedEPackage value="my.MyPackage"/>
   </bean>
   <component file='org/openarchitectureware/xtext/Generator.oaw' inheritAll='true'/>
</workflow>
    

The next step is to make the existing Ecore model available to your Xtext plug-in. Use the importModel statement followed by the nsURI of the model for that purpose, e.g.

importMetamodel "http://www.oaw.org/entity" as refModel;

imports entity and makes its elements available in the namespace alias refModel.

Now you make a parser rule instantiate an EClass from the imported model by adding the qualified class name in brackets after the rule name. Assuming you want to instantiate an EClass named Entity which has an attribute name, simply write

MyRule [refModel::Entity] :
  name=ID;

If all rules in your grammar instantiate foreign EClasses, the automatic generation of the Ecore model becomes obsolete. Switch it off using the preventMMGeneration directive at the beginning of your grammar file:

preventMMGeneration
importMetamodel "http://www.oaw.org/entity" as refModel;
    

Cross-references to Models of a Different DSL/Metamodel

These are the steps to take, if you want to implement cross-references to models that comply to a DSL that is different from the referencing model's DSL.

Follow the above instructions to make the referenced metamodel/DSL available in your grammar. The outgoing reference is defined - analogous to the instantiation of foreign model element - using brackets, e.g.

Referer :
  (entities+=[refModel::Entity])*;
    

Extension/Partitioning of Grammars

If you want to extend an existing grammar or split a large grammar into multiple pieces, you can use the importGrammar statement, e.g.

importGrammar "platform:/resouce/my.dsl/src/mydsl.xtxt"

Imported rules can be overridden simply by redefinition. Note that for the Xtext artifact generation to succeed, the input grammar combined with its imported grammars must not contain unused rules.