Professional Documents
Culture Documents
1 Introduction
This report explains the use of Eclipse and the Xtext plug-ins for the definition and use of a Domain
Specific Language (DSL). Section 2 describes the steps needed to install Eclipse and all required plugins. The creation of a new DSL is explained in Section 3. Section 4 demonstrates how an existing DSL
can be loaded and adapted. Section 5 contains a small example illustrating the extension of scoping
rules. Background information and various small topics can be found in Section 6. The creation and
use of plug-ins is described in Section 7. Finally, Section 8 contains a number of useful commands
and shortcuts.
Note that a number of screenshots are based on earlier Eclipse versions and might be slightly
different from the current version.
2
5.
Install Ecore Tools SDK (Help > Install new software > Work with (pull-down menu): select
Kepler - http://download.eclipse.org/releases/kepler
Wait till everything is loaded under Name ,
open Modelling, select Diagram Editor for Ecore (SDK) and Xtext SDK
open Programming Languages, select Xtend SDK
Click Next (2 times), accept license agreement, and Finish; restart Eclipse when asked.
Eclipse also offers an export mechanism via File > Export > General > Archive file, which includes the
metadata. Smaller archive files can be obtained by compressing all folders except the .metadata
folder. Section 4 explains how to import archive files.
This defines a grammar to describe robot applications by means of a number of production rules:
The production rule for Robot allows a repeated (indicated by *) choice (indicated by |)
between messages and tasks. The notation += indicates a list of elements. Note that Robot
may be empty, if we prefer at least one message or type then we should replace * by +.
A message starts with the terminal string Display and then defines attribute msg.
A task starts with terminal string Task name, then a name attribute is defined, followed by
an optional (indicated by ?) attribute frequency, and next a positive number (indicated by
+) of moves can be added.
Similarly, the production rule for a move is defined.
Finally, a condition is defined as an enumeration.
6
Note that after the first generation of the infrastructure, the application is available in the pull-down
menu right of the green play button:
Observe that the ecore model is more liberal than the concrete syntax by allowing a Task with zero
Moves.
View diagram of Xtext grammar:
Open the .xtext file and select: Window > Show View > Other... > Xtext > Xtext Syntax Graph. This
leads to a graphical representation of the syntax, as depicted in Figure 6.
Double-click on an element in the diagram to jump to the corresponding part in the Xtext syntax.
8
Edit spec1.dsl
o During editing, Ctrl-Space gives possible completions or inserts a keyword if there
is no choice.
To view this model as an instance of the ecore model, right click on spec1.dsl, select Open With /
Other , choose (from Internal editors): Sample Ecore Model Editor. Right click on an element and
select Show Properties View to inspect details, such as the value of Speed attribute.
To return to the DSL view, right click on spec1.dsl and select Open With / MyDsl editor.
Change this file into the text depicted in Figure 9 and Figure 10, taking the following notes account:
The three imports of nl.text. have been added automatically using hints on errors; when
an error occurs, hover over the erroneous text and select a suggestion to add an import
from nl.xtext.demo.myDsl.
The brackets << >> can be obtained by typing ctrl-space (pressing both keys
simultaneously).
The first editing step is to implement the doGenerate method. We start with the definition of the
path where the generated file should be placed. Note that resource.getURI().lastSegment yields
the last part of the name of the URI of the resource, which is in this case the name of the source file.
Next we define the name of the generated file and use a function toText to transform the resource
to sequence of characters. In Eclipse, a resource is a project, a folder, or a file.
Function toText is defined using a so-called rich string (the part between the triple quotes . ).
Note that the text on the blue background occurs in the generated file, including all spaces, together
with the values of the attributes specified between the angle brackets <<>>.
Since the function toText for resources refers to a similar function for Robots, we continue with
the definition of this function and a few other auxiliary definitions, as show in Figure 10.
Note that non-existing optional attributes of type INT have the default value 0, whereas non-existing
references have the null value.
10
11
12
13
In this mode it is possible to place breakpoints in files of the meta-level workspace. For instance, in
the MyDslGenerator.xtend file which defines the model transformation. When, after a Project >
Clean or a change and save in the runtime workspace, a breakpoint is hit, there will be a question at
the meta-level workspace whether the Debug perspective has to be opened; answer yes. In this
perspective, for instance, tracing information and values of variables can be inspected.
In the debug mode, changes in the body of methods are immediately available at the runtime level.
So avoids time-consuming restarts of the runtime workspace. This is still needed for larger changes,
e.g., when adding methods, but then the user is warned to restart.
To return to the usual view, select the JavaEE perspective.
Disadvantage of this grammar is that if the optional attributes start and end are no longer null
when they are not specified. Unspecified attributes obtain value border which corresponds to 0,
the value of the first field of the enum type Condition. Hence it is impossible to distinguish an
unspecified attribute from one with value border.
A possible solution could be to add a new first default value to the enum type and test on this value
in the MyDslGenerator.xtend file. A more general approach is to ensure that optional fields always
refer to a non-enum type. Then the xtend file for the generation can always test on null for
optional attributes. This approach has been used in Section 3.1.3. An alternative is to remove the
enumeration type completely, as shown in Section 3.7.
14
Figure 14 Alternative grammar for the choice between Messages and Tasks
The grammar leads to error: An unassigned rule call is not allowed, when the 'current' was already
created." The problem is that in parser rules it is not allowed to call other parser rules without
assigning the outcome to something. Note that each rule leads to class in the meta model, and
classes have to be linked somehow; in the grammar above no link is specified between Robot and
the classes Messages and Tasks.
A correct alternative with the choice between Messages and Tasks is shown in Figure 15. It
introduces an intermediate type Element.
15
This leads to the ecore diagram of the meta model of Figure 16 (after some minimal editing). Note
that the fact that an Elements is a Message of a Task is represented by inheritance.
leads to a warning: The entry rule 'Robot' may consume non empty input without object
instantiation. Add an action to ensure object creation, e.g. '{Robot}'.
The warning disappears indeed by adding the action (or removing the key word):
These actions can also be used to create subtypes. For instance, consider the alternative definition
of Condition of Figure 17.
16
Note that the same meta model is obtained by the following grammar:
The subtypes of Condition can be used to obtain polymorphic behavior using the ``dispatch feature
of xtend. For instance, in MyDslGenerator.xtend the conditions can be transformed to text as
follows:
17
18
19
20
Note that this example uses the notation [State | ID] to define a reference to an instance of type
State, using predefined terminal ID. This terminal is the name of the state, which is used to identify
the State instance. It is recommended to make sure that the type to which the reference is made has
an attribute name. Note the difference with attributes of type State, such as in the following
fragment:
This leads to an ecore diagram with a containment relation, as shown in the next figure:
21
then we obtain the following ecore diagram:
The example also contains a definition of expressions; more explanation can be found in Section
6.2.1. Finally, the Xtext file shows the definition of a terminal type for booleans. See Section 6.2 for
more information about Xtext.
Model transformation using Xtend
The code generation is specified as model transformations in the file MySDGenerator.xtend in
statediag.example.jh/src/statediag.example.generator. This example shows the generation of
multiple files, a few auxiliary functions which show alternative ways to obtain instances of attributes,
and the translation of expressions.
Section 6.3 contains some background information about Xtend.
The MySDGenerator.xtend file is translated to Java file MySDGenerator.java in folder xtend-gen,
package statediag.example.generator. Observe, for instance, how the dispatch mechanism of Xtend
(applied to expressions) is translated to Java.
Note that a diagram can be generated by right-clicking on ecore model and selecting
"Initialize ecore_diagram diagram file"; Finish. Using the defaults this leads to a model
MySD.ecorediag in src-gen. This option might help to understand the DSL definition; the
diagram is not used in the remainder of this section.
22
4.3.3 Validation
Starting point of validation is the file <LanguageName>JavaValidator.java in subpackage validation.
This file is generated automatically. To distribute the validation over a number of files or to be able
to use the Xtend language to define validation checks, proceed as follows:
Note that Xtend and Java files can be mixed, but the starting point should be the generated Java file.
In our current example, this leads to the following files:
A validation class consists of a number of methods, which in Java have the form:
@Check
public void anyName(SomeClassFromYourMetaModel instance) {
}
In Xtend these methods have the following form:
@Check
def anyName(SomeClassFromYourMetaModel instance) {
}
The method name anyName is completely free; the @Check takes care that the method is called
on every instance of type SomeClassFromYourMetaModel.
Since validation takes place while the user is typing a concrete model instance, it is important to take
into account that most types may have the null value (this does not hold for lists). For these types,
always test on null values in the validation checks to avoid exceptions on the console. See, for
instance, method checkTypeTransitionGuard in Validate3TypeChecking.xtend. Also cyclic relations
23
(e.g., a parent relation) may give problems (call stack overflow), so it is good practice to be robust
w.r.t. cyclic relations.
To report [potential] faults to the user, in the body of a validation check three pre-defined methods
can be called (using the standard inheritance relation with Abstract<LanguageName>JavaValidator):
warning(...): leads to a yellow exclamation mark in the margin and text in the instance is
underlined yellow;
error(...): leads to a red cross in the margin and text in the instance editor is underlined red;
this also ensures that no code can be generated.
Concerning the parameters of these three methods, there are a number of patterns to indicate the
location in the instance editor. We list a number of convenient parameters:
Combinations of the above patterns and many other possibilities are also available.
To obtain fragments such as Literals.SOME_CLASS_FROM_YOUR_META_MODEL__SOME_FIELD:
Add an import, depending on the language used:
o In an Xtend file: add an import of the form: <LanguageName>Package$Literals;
in our example: import statediag.example.mySD.MySDPackage$Literals
o In a Java file: add an import of the form: <LanguageName>Package.Literals; in
our example: import statediag.example.mySD.MySDPackage.Literals
On the place where the literal is needed, type Literals. and use content assist (<CTRL><SPACE>) to select one of the options of type EReference. (For instance, in our example:
Literals.ACTION__LAMP)
In our example, Literals can be found in src-gen/statediag.example.mySD/MySDPackage.java/
Literals.
24
After changes in .xtext file or the .mwe2 file, regenerate the language infrastructure and
restart the runtime workspace:
o Click the down arrow right of the green "Run" button
o Select Generate Language Infrastructure (statediag.example.jh)
o Restart the runtime workspace
After changes in .xtend file, restart the runtime workspace
25
File > Export
Select General > Archive File; Next
Select all projects
Browse to specify archive file at appropriate location
Finish
Similarly, an archive of the runtime workspace can be generated.
5 Example Scoping
This example is based on three files: MyDsl.xtext, MyDslScopeProvider.xtend, and test.mydsl. The
text of these files can be found in file ScopingFiles.txt and can be copied from this file.
Generate the language infrastructure by Run > Run Configurations ; click on + before Mwe
Launch and click on Generate Language Infrastructure (see Figure 3 in section 4.1).
Answer y to question about download of ANTLR 3 parser generator.
Note that this grammar contains references to earlier defined rules: the extends attribute of a
Model may be a reference to a Model and the variable attribute of VariableUse may refer to a
26
Variable. This can also be seen in the Ecore diagram that can be generated by right-clicking on the
MyDsl.ecore file in nl.xtext.scoping.mydsl/model/generated and selecting Initialize Ecore Diagram
File. See Figure 23, which has be edited slightly:
27
Note there is an error Couldnt resolve reference to Variable x. Use ctrl-space after
occurrences of use in the file to observe which variables are in scope.
28
Open the runtime workspace by Launch Runtime Eclipse in the pull-down menu right of
the green button.
Execute Project > Clean
Observe that the error is no longer available in test.mydsl and by Ctrl-space one can observe
which variables are in scope.
6 Background information
6.1 Ecore information
The Eclipse Modeling Framework (EMF) is a modeling framework and code generation facility for
building tools and other applications based on a structured data model. The core EMF framework
includes a meta model (Ecore) for describing models. A meta model is a model of models, that is,
instances of the meta model are models.
29
The Ecore model allows the definition of a number of elements such as:
EClass : represents a class, with zero or more attributes and zero or more references.
EReference : represents one end of an association between two classes. It has flag to
indicate if it represents a containment and a reference class to which it points.
Note that EMF also contains a meta model called Genmodel which contains additional information
for the code generation, e.g. the path and file information.
Info:
Assignments are used to assign the consumed information to a feature of the currently produced
object. The type of the current object, its EClass, is specified by the return type of the parser rule. If
it is not explicitly stated it is implied that the type's name equals the rule's name. The type of the
assigned feature is inferred from the right hand side of the assignment.
There are three different assignment operators for features, each with different semantics.
The simple equal sign = is the straight forward assignment, and used for features which take
only one element.
The += sign (the add operator) is used for a multi-valued feature (i.e., a list of values) and
adds the value on the right hand to that feature. Since attribute_name += ... is translated
in the meta model to a list, it is convenient to use a plural term (e.g., values) for
attribute_name. Similarly, it is a good convention to use a singular term (e.g., name) for
the attribute_name in grammar fragment attribute_name = ....
The ?= sign (boolean assignment operator) is used for a feature of type Boolean.
30
"&&" right=ExpressionLevel2)
"||" right=ExpressionLevel2)
"&&" right=ExpressionLevel1)
"||" right=ExpressionLevel1)
"&&" right=ExpressionLevel2)
"||" right=ExpressionLevel2)
6.3 Parsing
Xtext uses ANTLR (http://www.antlr.org/) which is a LL(*) recursive-descent parser generator. See,
e.g., http://en.wikipedia.org/wiki/LL_parser . LL parsers do not allow left recursive grammars, see
the Xtext 2.3 documentation: p 67 on Assigned Actions and p 72, section 6.2.8.
Syntactic analysis takes place in three phases:
1. Lexing: a sequence of characters (the text input) is transformed into a sequence of so called
tokens (such as ID, INTEGER, REAL, etc.);
2. Parsing: a sequence of tokens is transformed into a parse tree;
3. Linking: the parse tree is converted into a graph based on the cross-references.
31
These phases are executed sequentially and, hence, earlier phases cannot use knowledge of later
phases:
lexing has no information about the tokes that are expected by the parser;
parsing cannot use knowledge about possible cross references.
An example of an ambiguity in lexing, consider a grammar contains the following:
terminal INTEGER
returns ecore::EInt:
('0'..'9')+;
terminal REAL
returns ecore::EFloat:
('0'..'9')+ '.' ('0'..'9')+
the grammar uses . in another rule (which means that this also becomes a token)
This is ambiguous, because input 3.4 can be tokenized in two ways (even if the grammar rules out
certain combinations): as one token (REAL) or as three tokens (INTEGER; .; INTEGER). Xtext does
not give a warning in this case; it will be tokenized as a REAL. More problematic is the input 3.,
which will be parsed as a REAL (no backtracking) and hence yields an error.
As an example of an ambiguity in the parsing, consider:
Expression:
ExpressionConstant | ExpressionVariable;
ExpressionConstant:
variable = [Constant|ID] ;
ExpressionVariable:
method = [Variable|ID] ;
This is ambiguous because token input ID can be parsed in two ways, even if the declaration of the
ID clearly indicates, for instance, that it is a constant (so cross-referencing would excludes one of the
possibilities). In general, ambiguity of a grammar is undecidable. If backtracking is not enabled (see
section 6.5.1), there are limitations on the grammars and often Xtext reports ambiguities after
performing Generate Language Infrastructure. Since backtracking can have a negative impact on
performance and the clarity of error messages, it is advisable to avoid backtracking as much as
possible.
http://www.eclipse.org/xtend/
32
6.5 Miscellaneous
6.5.1 Options in the .mwe2 file
A number of options can be enabled/disables in the .mwe2 file which can be found in the src
folder, in the package where also the .xtext file is located. We list a few options which are disabled
by default; they can be enabled by uncommenting the corresponding lines.
Backtracking (enable only if really needed, see also section 6.3), below the line
fragment = parser.antlr.XtextAntlrGeneratorFragment {
// options = {
// backtrack = true
// }
It is also needed to add these lines to
parser.antlr.XtextAntlrUiGeneratorFragment{}
33
34
Generating the target plug-in for distribution to the users of the DSL:
1. Start with a completed Xtext project. Note that it contains a project ending with .sdk. In
this project, there is a file feature.xml. Open this file and inspect the properties. Note that
tab Information allows entering description, license and copyright information.
2. Click on Update Site project under Publishing in the Overview tab of feature.xml
mentioned in the previous step. [Or create an update site project using: File > New > Other
> Plug-in Development > Update Site Project Next ]
Give project a name, for instance, MyDsl-Update-Site Finish
3. This will open site.xml (of map My-Update-Site) in the Site Map editor.
Choose New Category and give it a name, e.g. My Dsl with ID: my_dsl
[This step is optional, without it, the feature will be Uncategorized.]
Select category my_dsl. Choose Add Feature, scroll through the list and add
your dsl project package ending with sdk ; select Ok.
Select Build All - as an example, see Figure 26.
This will package your dsl project plug-ins inside this update site project MyDsl-Update-Site. This
folder MyDsl-Update-Site can now be used directly as a local update site for your eclipse users.
Alternatively, the folder can be put on a web-site.
Using the plug-in:
1. Create a new folder for the runtime workspace (e.g. ExprDevelopment)
2. Open Eclipse with this workspace
3. In Eclipse, go to Help > Install New Software
In Work with: , click the Add button. The Add Repository dialog box appears:
35
Two options:
1. Click Local and select the directory of the update site, and then click OK.
The path of the directory appears in the Location field. Leave the Name
field empty.
2. Type in Location the URL of the update site and click OK.
From the display select My Dsl (or Uncategorized if no category was made).
Click Next and then Finish to complete the installation.
Click OK on security warning
When asked, restart Eclipse.
4. Generate a new project, folder, and start creating new Dsl models
8.2 Navigation
Outline view:
o Window -> Show view -> Outline
o <CTRL>-O
opens a quick outline that is searchable (including wildcards)
Hyper-linking to referenced elements:
o <F3> while the cursor position is at a cross-reference
o <CTRL>-click on a cross-reference
Find references:
o <CTRL>-<SHIFT>-<G>
Label (with extra information):
o Point at a cross-reference
36
8.3 Editing
Content assist:
(including templates for system and data/process/cluster classes)
o <CTRL>-<SPACE>
Rename element:
(including any cross-references)
o <ALT>-<SHIFT>-R
Automatic formatting: (pretty printing)
o <CTRL>-<SHIFT>-F
Validation:
Automatically upon changes and upon saving
Revalidate all files:
o Project -> Clean...
Validation results:
o error:
icon: cross in a red box
o warning:
icon: exclamation mark in a yellow triangle
Quick fix
(available if a light bulb is displayed next to the validation icon)
o <CTRL>-<1>