-
Notifications
You must be signed in to change notification settings - Fork 1
2016_xtext
homesite: https://eclipse.org/Xtext/
Install Xtext 2.9 using the releases update site: http://download.eclipse.org/modeling/tmf/xtext/updates/composite/releases/
(You can find the link here: https://eclipse.org/Xtext/download.html)
Click Help > Install New Software and complete with next, next finish.
As you can see, we will need Xtend as well.
- Create a new Xtext project with the following name:
hu.bme.mit.mdsd.erdiagram.text
. Name of the language will behu.bme.mit.mdsd.erdiagram.text.ERDiagramDsl
. It should conform to a fully qualified class name. Extension will beer
.
You can hit finish, or on the next page you can disable the "Testing support" as we won't need that. This will produce a simple Hello
language with greetings messages. It is worth to check this language.
-
Declare our language
grammar hu.bme.mit.mdsd.erdiagram.text.ERDiagramDsl with org.eclipse.xtext.common.Terminals generate eRDiagramDSL "http://www.bme.hu/mit/mdsd/erdiagram/text/ERDiagramDsl"
The
grammar
keyword declares the name of our language. Thewith
keyword defines an inheritance from an other language. In this case, we are inherited from the Terminals language which enables us to use theID
rule.generate
keyword is responsible for generating AST metamodel from the language definition. Package name will be eRDiagramDsl and ns uri will be http://www.bme.hu/mit/mdsd/erdiagram/text/ERDiagramDsl. Name of the EClasses will be the same as the name of the rules. -
Entry rule
Each Xtext language is built up from rules. The entry (or main) rule is the first defined rule which will be the
ERDiagram
in our case:ERDiagram: entities+=Entity+ relations+=Relation* ;
Syntax: rule name ':' ... ';'
This rule states that our language consists of one or more
Entity
object and zero or moreRelation
objects (rules). The output of a rule can be stored in AST. To do this, we can define references for AST which will be entities and relations in this case.' ' -> exatly one '*' -> zero, one or more '+' -> one or more '?' -> zero or one _reference_ = _eclass_ -> zero or one reference _reference_ += _eclass_ -> zero, one or more reference _reference_ ?= _keyword_ -> boolean reference
Note: in this case, 'eClass' equals with a rule name, because the generated AST uses rule names as type names (eClass names).
-
Attribute type as an enumeration:
enum AttributeType: INT = 'int' | DOUBLE = 'double' | STRING = 'string' | BOOLEAN = 'boolean' | DATETIME = 'datetime' ;
We can define enumerable rules which is mapped to an EMF enumeration in the generated AST. It starts with
enum
keyword. The key-value pairs are separated by '|' character. -
'ID' terminal.
First definition of Entity rule:
Entity: 'entity' name=ID ';'? ;
Between apostrophe characters, we can define terminals (or keywords) for our language. The 'ID' terminal comes from the Terminals language, and defines a unique identifier rule. An
Entity
rule starts with theentity
keyword, than a string comforming to the 'ID' terminal comes from the Terminals language, whic is stored in a name attribute, and finally an optional ';' character (keyword) comes. -
Reference an instance of a rule with
[...]
. Group expressions.Definition of Entity and Attribute rules:
Entity: 'entity' name=ID ('isA' isA+=[Entity])* ('{' (attributes+=Attribute) (',' attributes+=Attribute)* '}')? ; Attribute: name=ID ':' type=AttributeType (isKey?='key')? ;
If we omit the square brackets (
isA+=Entity
instead ofisA+=[Entity]
), then we would have to apply the rule again starting withentity
keyword, when we would try to use the language. With the square brackets we declare that only a reference is needed to a rule instance: '[' eclass ']'.Note: in this case, 'eclass' equals with a rule name, because the generated AST uses rule names as type names.
We can group expressions with brackets to add cardinality character to the complex grouped expression similarly to the body of the entity we defined: if an entity doesn't have any attribute, then the curly braces can be omitted.
-
Unordered expressions.
Relation: leftEnding=RelationEnding 'is related with' rightEnding=RelationEnding ; RelationEnding: (multiplicity=Multiplicity & (nullable?='nullable')?) target=[Entity] ; enum Multiplicity: One = "one" | Many = "many" ;
The '&' character defines an unordered list of the rules. In this case, the following solutions are applicable before the entity reference:
- one nullable
- nullable one
- many nullable
- nullable many
- one
- many
-
The full Xtext code
grammar hu.bme.mit.mdsd.erdiagram.text.ERDiagramDsl with org.eclipse.xtext.common.Terminals generate eRDiagramDsl "http://www.bme.hu/mit/mdsd/erdiagram/text/ERDiagramDsl" //Entry rule ERDiagram: entities+=Entity* relation+=Relation* ; Entity: 'entity' name=ID ('isA' isA+=[Entity])* ('{' attributes+=Attribute (',' attributes+=Attribute)* '}')? ; Attribute: name=ID ':' type=AttributeType (isKey?='key')? ; enum AttributeType: INT = 'int' | DOUBLE = 'double' | STRING = 'string' | BOOLEAN = 'boolean' | DATETIME = 'datetime' ; Relation: leftEnding=RelationEnding 'is related with' rightEnding=RelationEnding ; RelationEnding: (multiplicity=MultiplicityType & (nullable?='nullable')?) target=[Entity] ; enum MultiplicityType: One = 'one' | Many = 'many' ;
When you modify your xtext files, you have to build the infrastructure for your language. The following figure shows where to click to generate.
-
Start a runtime Eclipse.
-
Create a general project
New->Project...->General->Project Name: hu.bme.mit.mdsd.erdiagram.text.example
-
Create a file with 'er' extension
New->File Name: example.er
Add xtex nature in the pop-up window.
-
(Optional, if you missed the pop-up window) Add Xtext nature
Right click on project -> Configuration -> Add Xtext nature
-
Now, you can try out the language. Notice that you can use auto completion and quick fixes as well.
-
Create an example file with 'er' extension and fill it with the following content:
entity person { name : string, id : int key } entity driver isA person { licence : string } entity car { numberPlate : string key } one person is related with nullable many car
-
Open with Simple Ecore Model Editor
Right click on the file -> Open -> Open with... -> Simple Ecore Model Editor
This will show you the AST built from the text.
Scoping defines which elements are referable by a given reference. For instance, we don't want to enable self inheritance.
-
Open our scope provider
-
Create the following method:
class ERDiagramDslScopeProvider extends AbstractERDiagramDslScopeProvider { override IScope getScope(EObject context, EReference reference) { if (context instanceof Entity) { return Scopes.scopeFor( (context.eContainer as ERDiagram) .entities.filter[x | x != context] ) } return super.getScope(context, reference) } }
This scope restrict the available objects for the isA reference of all the Entity EClass. The
Scopes
class contains static methods to create scope descriptions from a list of EObjects.Note: This is an Xtend file, simple Java code is generated under the xtend-gen folder (further description about the language can be found here: http://eclipse.org/xtend/)
-
Check out in our example (Runtime Eclipse, example.er file).
Static analysis is always required for any language. In this example, we want to raise an error if a cycle occurs in the inheritance graph.
-
Open the validator Xtend file (ERDiagramDslValidator.xtend).
-
A validation method for given type requires the following things:
@Check
annotation, one parameter with the correct type, using theerror
,warning
orinfo
methods to create markers on the editor.class ERDiagramDslValidator extends AbstractERDiagramDslValidator { Set<Entity> entitiesAlreadyChecked = new HashSet @Check def checkCyclicInheritance(Entity entity) { checkCyclicInheritance2(entity) entitiesAlreadyChecked.clear } def checkCyclicInheritance2(Entity entity) { entitiesAlreadyChecked += entity for (parent : entity.isA) { if (entitiesAlreadyChecked.contains(parent)) { error("Cyclic inheritance is not allowed.", ERDiagramDslPackage.Literals.ENTITY__IS_A) return; } checkCyclicInheritance2(parent) } } }
Note: in a real project much more validation would be needed.
-
Check out in our example (Runtime Eclipse, example.er file)
-
Open the ERDiagramDslGenerator.xtend file.
-
Create the following method:
class ERDiagramDslGenerator extends AbstractGenerator { override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { fsa.generateFile('entities.txt', 'Entities: ' + resource.allContents .filter(typeof(Entity)) .map[name] .join(', ')) } }
The will generate the an entities.txt file after modifying and building the example ERDiagram model containing the name of each entities.
-
Check it out.
You may have noticed the model folder in the Xtext project, which contains a generated ecore and genmodel file. Xtext uses EMF under the hood. Xtext can also work with existing ecore models and can generate a basic json like language.
To make it work you either generate a new xtext project along with a new grammer from the existing ecore model or change your grammer int the following two points: (1) instead of generate
you have to import
the ecore model and (2) rules must be accompanied with a returns <existing EClass>
.
In this tutorial, we will generate a new language based on the previously create erdiagram and will highlight the differences.
-
Clone and check out any branch from this repository, then import the project with the erdiagram ecore model in it.
-
Create a new Xtext Project From Existing Ecore Models
-
Choose the existing ecore model and select the root element as the entry rule.
-
On the next page you can give the project name, extension, etc. As for this tutorial you can leave everything on default.
-
You may have to add Xtext nature to the
*.erdiagram
project. -
Examine the generated grammar (MyDsl.xtext). Header and entry rule:
// automatically generated by Xtext grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals import "hu.bme.mit.mdsd.erdiagram" import "http://www.eclipse.org/emf/2002/Ecore" as ecore EntityRelationDiagram returns EntityRelationDiagram: {EntityRelationDiagram} 'EntityRelationDiagram' name=EString '{' ('entities' '{' entities+=Entity ( "," entities+=Entity)* '}' )? ('relations' '{' relations+=Relation ( "," relations+=Relation)* '}' )? ('temporalAttributes' '{' temporalAttributes+=Attribute ( "," temporalAttributes+=Attribute)* '}' )? '}';
- detailed documentation: https://eclipse.org/Xtext/documentation/
- Eclipse basics
- EMF (incl. advanced topics)
- VIATRA Query
- Sirius
- Xtext+Xtend
- M2M
- Eclipse basics
- EMF (incl. advanced topics)
- VIATRA Query
- Sirius
- Xtext
- M2M
(Gradually replaced with updated content)
- Eclipse basics
- EGit
- EMF (incl. advanced topics)
- VIATRA Query
- Sirius
- Xtext
- M2M (VIATRA)
- Eclipse basics
- EGit
- EMF (incl. advanced topics)
- VIATRA Query
- Sirius
- Xtext
- M2M (VIATRA)