-
Notifications
You must be signed in to change notification settings - Fork 4
Grammar Overview
The grammar can be divided in five sections header, service and root, data types, literals, and tokens.
As most Xtext grammars, the IRL grammar imports the terminals grammar for some basic setup. The IRL generates its own meta-model and it incorporates the ecore meta-model.
grammar kieker.develop.rl.RecordLang with org.eclipse.xtext.common.Terminals
generate recordLang "http://www.cau.de/cs/se/instrumentation/rl/RecordLang"
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
import "http://www.kieker-monitoring.net/kieker/develop/semantic-annotations" as semantics
The document root is represented by a model class. The name of the model is a package qualifier which corresponds to a Java package structure in Java projects. The import rule allows to import entity and template types from other packages into the namespace of the present model. The package rule allows to import other meta-models. Their types can then be used in the IRL as property types. However, as it is necessary for monitoring data types to be as small as possible, for such structured meta-model types, each property of such type must be specifically marked to be serialized.
Model:
'package' name = QualifiedName
(imports += Import)*
(types += ComplexType |
modelTypes += ModelType )*
;
Import:
'import' importedNamespace = QualifiedNameWithWildcard
;
```antlr
Package:
'use' name=ID package=[ecore::EPackage|STRING]
;
The Kieker IRL has a rich type system including base types, complex types, and model types which allow to extend complex types in groups.
The following two rules are used to create metamodel classes for the base type. Complex types are event/entity types which can be instantiated and template types which can be used to compose types. Base types are the atomic types, like int, short, string etc.
Type:
ComplexType | BaseType
;
BaseType:
name=ID
;
A ModelType' is essential a collection of
ComplexType's. They are defined by specifying a sequence of complex types, i.e., EventType',
TemplateType', and ModelSubType'. As
ModelSubType's are also ComplexType's, they allow to extend previously extended
ModelType's.
All types which are derived from these types are also included in the ModelType'. Each
ModelType' can have (and should have) an author and since annotation to specify who and when that type was first defined. A `ModelType' has also a name to be able to reference it.
ModelType:
('@author' author=STRING)?
('@since' since=STRING)?
'model' name=ID types+=[ComplexType|QualifiedName] (',' types+=[ComplexType|QualifiedName])* ;
To use a ModelType', a model sub type must be created. A
ModelSubType' is in essence the method to extend all types collected in a ModelType'. A
ModelSubType' can have an author and since annotation (recommended), as well as, a name. The name is used as a prefix for the composed types.
A ModelSubType' refers to a
ModelType' to indicate which `ModelType' should be extended. Then it is possible to either specify a set of properties and constants to extend the types, or to provide a list of templates.
ModelSubType:
('@author' author=STRING)?
('@since' since=STRING)?
'sub' name=ID modelType=[ModelType|QualifiedName] (
('{' (properties+=Property | constants+=Constant)* '}') |
(':' extensions+=[TemplateType|QualifiedName] (',' extensions+=[TemplateType|QualifiedName])*)
)
;
The IRL has two major structured types called entities and templates. They are realized by the two rules EventType' and
TemplateType'. In addition, the `ModelSubType' is also a complex type.
ComplexType:
EventType | TemplateType | ModelSubType
;
For each type two annotations are supported which define the author name and the revision string for the specified type. Each template type has a name and may have multiple parent templates.
TemplateType:
('@author' author=STRING)?
('@since' since=STRING)?
'template' name=ID (':' parents+=[TemplateType|QualifiedName] (',' parents+=[TemplateType|QualifiedName])*)?
('{'
(properties+=Property | constants+=Constant)*
'}')?
;
The EventType
is very similar. However, has two distinctions. First, it can also inherit from record types, but only from one record type, it can be abstract, which results in Java in an abstract type, in C and Perl in no type at all.
EventType:
('@author' author=STRING)?
('@since' since=STRING)?
(abstract?='abstract')? ('event'|'entity') name=ID
('extends' parent=[EventType|QualifiedName])?
(':' inherits+=[TemplateType|QualifiedName] (',' inherits+=[TemplateType|QualifiedName])*)?
('{'
(properties+=Property | constants+=Constant)*
'}')?
;
In both types, constants can be defined which assign a name to a value.
Constant:
'const' type=Classifier name=ID '=' value=Literal
;
Properties are a complex structure. They start with an optional set of modifiers, followed by a ForeignKey', a
Classifier', or and alias to another property.
- Type by classifier: The basic way to specify a property is with a
Classifier
(type), followed by a name and an optional value literal. - Type by alias: the type of the property is inherited from the aliased property.
- ForeignKey: the type of the property is inherited from a property defined in another type, which is considered a primary key.
Property:
(modifiers+=PropertyModifier)* (
foreignKey=ForeignKey |
type=Classifier |
'alias' referTo=[Property|ID] 'as'
) name=ID (':' semantics=[semantics::Annotation|ID])?
('=' value=Literal)?
;
A classifier is always a BaseType' followed by an optional
ArraySize' specification. This allows to define multi dimensional arrays. If no size is specified, the size is flexible.
Classifier:
type=[BaseType|ID] (sizes+=ArraySize)*
;
ArraySize: {ArraySize}
'[' (size=INT)? ']'
;
A ForeignKey' is always in an
EventType'.
ForeignKey:
'grouped' 'by' eventType=[EventType|ID] '.' propertyRef=[Property|ID]
;
The IRL support three `PropertyModifier' which provide different semantics for the properties.
- `transient' = the property is not serialized
- `auto-increment' = the property is automatically incremented when property is read
-
changeable' = the property can be altered in an analysis; often it is not necessary to change values during analysis. Therefore, values can be used in memory instead of variables, which can have a performance benefit. However, in some rare cases, values are too limiting. Then you can set the property as
changeable'.
enum PropertyModifier:
TRANSIENT = 'transient' |
INCREMENT = 'auto-increment' |
CHANGEABLE = 'changeable'
;
The IRL supports various literal values, which correspond with the types of the language. However, there is only one integer literal and one float literal.
Literal:
StringLiteral | IntLiteral | FloatLiteral | BooleanLiteral |
ConstantLiteral | ArrayLiteral | BuiltInValueLiteral
;
ArrayLiteral:
'{' literals+=Literal (',' literals+=Literal)* '}'
;
StringLiteral:
value=STRING
;
IntLiteral:
value=INT
;
FloatLiteral:
value=FLOAT
;
BooleanLiteral:
value=BOOLEAN
;
ConstantLiteral:
value=[Constant|ID]
;
BuiltInValueLiteral: {BuiltInValueLiteral}
value='KIEKER_VERSION'
;
QualifiedName:
ID (=>'.' ID)*;
QualifiedNameWithWildcard:
QualifiedName ('.' '*')?
;
// terminals
terminal fragment NUMBER :
'0'..'9';
// redefine INT terminal to allow negative numbers
terminal INT returns ecore::EInt:
'-'? NUMBER+;
// make sure the Float rule does not shadow the INT rule
terminal FLOAT returns ecore::EFloatObject :
'-'? NUMBER+ ('.' NUMBER*) (("e"|"E") ("+"|"-")? NUMBER+)? 'f'? |
'-'? NUMBER+ 'f';
// introduce boolean values
terminal BOOLEAN returns ecore::EBooleanObject :
'true' | 'false';