-
Notifications
You must be signed in to change notification settings - Fork 1
2015_xtext
homesite: https://eclipse.org/Xtext/
Install from eclipse market place: search for Xtext -> Click Install -> etc.
Note: This will also install the Xtend packages.
- 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
.
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: attributeTypes+=AttributeType* entities+=Entity+ relations+=Relation* ;
Syntax: rule name ':' ... ';'
This rule states that our language consists of zero or more
AttributyType
object, one or moreEntity
object and zero or moreRelation
object. The output of a rule can be stored in AST. To do this, we can define references for AST which will be: attributeTypes, entities, relations.'*' -> 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.
-
'ID' terminal.
Definition of AttributeType rule:
AttributeType: 'type' 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
AttributeType
rule starts with thetype
keyword, than an identifies that is stored in a name attribute, and finally an optional ';' character comes.- Reference an instance of a rule
Definition of Entity and Attribute rules:
Entity: 'entity' name=ID ('isA' isA=[Entity])? '{' ((attributes+=Attribute) (',' attributes+=Attribute)*)? '}' ; Attribute: name=ID ':' type=[AttributeType] (isKey?='key')? ;
With the previous rules, we could declare variables, but these rules reference already declared variables. To achieve this, use the following syntax: '[' eclass ']'
Note: in this case, 'eclass' equals with a rule name, because the generated AST uses rule names as type names.
-
Enumeration, grouping expressions, unordered expressions, boolean expression
Relation: 'relation' leftEnding=RelationEnding rightEnding=RelationEnding ; RelationEnding: target=[Entity] '(' (multiplicity=Multiplicity & (nullable?='nullable')? ) ')' ; enum Multiplicity: One = "one" | Many = "many" ;
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. We can group expressions with brackets to add cardinality character to the complex grouped expression. The '&' character defines an unordered list of the rules. In this case, the following solutions are applicable:- one nullable
- nullable one
- many nullable
- nullable many
- one
- many
The last two example is valid because of the (...)? expression around the 'nullable' case.
-
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: attributeTypes+=AttributeType* entities+=Entity+ relations+=Relation* ; // Attribute type rule AttributeType: 'type' name=ID ';'? ; //Entity rules Entity: 'entity' name=ID ('isA' isA=[Entity])? '{' ((attributes+=Attribute) (',' attributes+=Attribute)*)? '}' ; Attribute: name=ID ':' type=[AttributeType] (isKey?='key')? ; //Relation rules Relation: 'relation' leftEnding=RelationEnding rightEnding=RelationEnding ; RelationEnding: target=[Entity] '(' (multiplicity=Multiplicity & (nullable?='nullable')? ) ')' ; enum Multiplicity: One = "one" | Many = "many" ;
When you modifies your xtext files, you have to build the infrastructure for your language. The following figure shows where click to generate.
The generation may fail due to a missing plug-in. To solve this problem, add the org.eclipse.equinox.common plug-in to the MANIFEST.MF file.
-
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 have a working language.
-
Create an example file with 'er' extension and fill it with the following content:
type String type Int entity person isA car { name : String, id : String key } entity car { numberPlate : String key } relation car (one) person (many nullable)
-
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.
-
Import the projects from here.
-
Switch the AST line
From (this line implies to generate AST metamodel):
generate eRDiagramDSL "http://www.bme.hu/mit/mdsd/erdiagram/text/ERDiagramDSL"
To (this line imports our metamodel):
import "platform:/resource/hu.bme.mit.mdsd.erdiagram/model/erdiagram.ecore" as er
The metamodel can be access via er:: prefix.
-
Change return values of rules and correct the reference and attribute names:
grammar hu.bme.mit.mdsd.erdiagram.text.ERDiagramDSL with org.eclipse.xtext.common.Terminals import "platform:/resource/hu.bme.mit.mdsd.erdiagram/model/erdiagram.ecore" as er ERDiagram returns er::EntityRelationDiagram: attributetypes+=AttributeType* entities+=Entity+ relations+=Relation* ; Relation returns er::Relation: 'relation' leftEnding=RelationEnding rightEnding=RelationEnding ; RelationEnding returns er::RelationEnding: target=[er::Entity] '(' (multiplicity=Multiplicity & (nullable?='nullable')? ) ')' ; enum Multiplicity returns er::MultiplicityType: One = "One" | Many = "Many" ; Entity returns er::Entity: 'entity' name=ID ('isA' isA+=[er::Entity])? '{' ((attributes+=Attribute) (',' attributes+=Attribute)*)? '}' ; Attribute returns er::Attribute: name=ID ':' type=[er::AttributeType] (isKey?='key')? ; AttributeType returns er::AttributeType: 'type' name=ID ';'? ;
-
Do not forget to delete the exported packages in the MANIFEST.MF and to rebuild the infrastructure
-
Finished From now, the language uses our metamodel to build AST
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 AbstractDeclarativeScopeProvider { def scope_Entity_isA(Entity ctx, EReference ref){ Scopes::scopeFor((ctx.eContainer as EntityRelationDiagram).entities.filter[x | x != ctx]); } }
A scope method follows the
scope_[EClass]_[EStructuralFeature](EClass param1, EReference ref)
syntax. This scope restrict the available objects for the isA reference of all the Entity EClass. TheScopes
class contains static methods to create scope descriptions from a list of EObjects.Note: This is an Xtend file (further description: 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 our validator
-
Create the following method with
@Check
annotationclass ERDiagramDSLValidator extends AbstractERDiagramDSLValidator { public static val CYCLE = "CYCLE"; @Check def checkCycleInInheritance(Entity ctx) { checkCycleInInheritance(ctx, ctx.isA) } def checkCycleInInheritance(Entity ctx, Collection<Entity> parents) { if (parents.contains(ctx)) { error("Cycle in the inheritance graph", ERDiagramPackage.Literals.ENTITY__IS_A,CYCLE); return; } for (parent : parents) { checkCycleInInheritance(ctx, ctx.isA); } } }
Note: not all cases are covered with this code, so don't use it a real project.
-
Check out in our example (Runtime Eclipse, example.er file)
- 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)