The meta model of a textual language describes the structure of its abstract syntax trees (AST).
Xtext uses Ecore EPackages to define meta models. Meta models are declared to be either inferred (generated) from the grammar or imported. By using the ‘generate’ directive, one tells Xtext to derive an EPackage from the grammar.
Xtext creates
an EPackage
for each generated package declaration. After the directive '‘generate’‘ a list of parameters follows. The ’‘name’‘ of the EPackage will be set to the first parameter, its ’‘nsURI’' to the second parameter. An optional alias as the third parameter allows to distinguish generated EPackages later. Only one generated package declaration per alias is allowed.
an EClass
for each return type of a parser rule. If a parser rule does not define a return type, an implicit one with the same name is assumed. You can specify more than one rule that return the same type but only one EClass will be generated.
for each type defined in an action or a cross-reference.
an EEnum
for each return type of an enum rule.
an EDatatype
for each return type of a terminal rule or a datatype rule.
All EClasses, EEnums and EDatatypes are added to the EPackage referred to by the alias provided in the type reference they were created from.
While walking through the grammar, the algorithm keeps track of a set of the currently possible return types to add features to.
Entering a parser rule the set contains only the return type of the rule.
Entering a group in an alternative the set is reset to the same state it was in when entering the first group of this alternative.
Leaving an alternative the set contains the union of all types at the end of each of its groups.
After an optional element, the set is reset to the same state it was before entering it.
After a mandatory (non-optional) rule call or mandatory action the set contains only the return type of the called rule or action.
An optional rule call does not modify the set.
A rule call is optional, if its cardinality is ‘?’ or ‘*’.
While iterating the parser rules Xtext creates
an EAttribute in each current return type
of type EBoolean for each feature assignment using the ‘?=’ operator. No further EReferences or EAttributes will be generated from this assignment.
for each assignment with the ‘=’ or ‘+=’ operator calling a terminal rule. Its type will be the return type of the called rule.
an EReference in each current return type
for each assignment with the ‘=’ or ‘+=’ operator in a parser rule calling a parser rule. The EReference type will be the return type of the called parser rule.
for each action. The reference’s type will be set to the return type of the current calling rule.
Each EAttribute or EReference takes its name from the assignment/action that caused it. Multiplicities will be 0...1 for assignments with the ‘=’ operator and 0...* for assignments with the ‘+=’ operator.
Furthermore, each type that is added to the currently possible return types automatically inherits from the current return type of the parser rule. You can specify additional common supertypes by means of “artificial” parser rules, that are never called, e.g.
CommonSuperType:
SubTypeA | SubTypeB | SubTypeC;
For each alternative defined in an enum rule, the transformer creates an enum literal, when another with the same name cannot be found. The ‘literal’ property of the generated enum literal is set to the right hand side of the declaration. If it is ommitted, you’ll get an enum literal with equal ‘name’ and ‘literal’ attributes.
enum MyGeneratedEnum:
NAME = 'literal' | EQUAL_NAME_AND_LITERAL;
Next the generator examines all generated EClasses and lifts up similar features to supertypes if there is more than one subtype and the feature is defined in every subtypes. This does even work for multiple supertypes.
As a last step, the generator invokes the post processor for every generated meta model. The post processor expects an Xtend file with name
MyDslPostProcessor.ext
(if the name of the grammar file is
MyDsl.xtext
) in the same folder as the grammar file. Further, for a successful invocation, the Xtend file must declare an extension with signature
process(xtext::GeneratedMetamodel)
. E.g.
process(xtext::GeneratedMetamodel this) :
process(ePackage)
;
process(ecore::EPackage this) :
...
;
The invoked extension can then augment the generated Ecore model in place. Some typical use cases are to:
set default values for attributes
add container references as opposites of existing containment references
add operations with implementation (using a body annotation)
Great care must be taken not to modify the meta model in a way preventing the Xtext parser from working correctly (e.g. removing or renaming model elements).
The following conditions cause an error
An EAttribute or EReference has two different types or different cardinality.
There are an EAttribute and an EReference with the same name in the same EClass.
There is a cycle in the type hierarchy.
An new EAttribute, EReference or supertype is added to an imported type.
An EClass is added to an imported EPackage.
An undeclared alias is used.
An imported metamodel cannot be loaded.