Reference manual
Build date: 9-April-2008
$Date: 2008/02/26 16:34:38 $
Abstract
This manual presents the various aspects of the Kermeta language. This is the reference manual for anybody who want to use Kermeta.
Table of Contents
- Preface
- 1. Introduction to the language
- 2. Reference
- 2.1. Comments
- 2.2. Escaping reserved keywords
- 2.3. Operators
- 2.4. Statements : block, condition, loop
- 2.5. File dependency : structuring code
- 2.6. Using Variables
- 2.7. Basic types
- 2.8. Classes and methods
- 2.9. Inheritance
- 2.10. Genericity
- 2.11. Exception handling
- 2.12. Loading and saving models
- 2.13. Packages
- 2.14. Collections
- 2.15. Class properties
- 2.16. Objects comparison
- 2.17. Lambda Expressions and functions
- 2.18. Dynamic evaluation of Kermeta expressions
- 2.19. Design by contract (pre, post, inv contraints)
- 2.20. Weaving kermeta code
- 2.21. Model type
- 2.22. Using existing java code in Kermeta
- 2.23. Cloning objects
- 3. Kermeta Metamodel
- 4. Kermeta framework
- A. Language keywords
Kermeta is a Domain Specific Language dedicated to metamodel engineering. It fills the gap let by MOF which defines only the structure of meta-models, by adding a way to specify static semantic (similar to OCL) and dynamic semantic (using operational semantic in the operation of the metamodel). Kermeta uses the object-oriented paradigm like Java or Eiffel.
This document gives beginners an introduction to the Kermeta language, then it offers a reference of all the aspects of the language, including the textual syntax, the metamodeling features and some more advanced features. Two other chapters present the Kermeta Metamodel and the Kermeta framework.
![]() | Important |
|---|---|
Kermeta is an evolving software and despite that we put a lot of attention to this document, it may contain errors (more likely in the code samples). If you find any error or have some information that improves this document, please send it to us using the bug tracker in the forge: http://gforge.inria.fr/tracker/?group_id=32 or using the developer mailing list (kermeta-developers@lists.gforge.inria.fr) Last check: v1.0.0 |
![]() | Tip |
|---|---|
The most update version of this document is available on line from http://www.kermeta.org . |
This chapter aims to help you to have a quick overview of most of the features of Kermeta. Then, it gives the pointers to the detailled sections in the reference chapter. It also gives some small examples that should help you to understand the basis of the concepts without having to jump to the corresponding detailled section.
Kermeta is a metamodeling language which allows describing both the structure and the behavior of models. It has been designed to be compliant with the OMG metamodeling language EMOF (part of the MOF 2.0 specification) and Ecore (from Eclipse). It provides an action language for specifying the behavior of models.
Kermeta is intended to be used as the core language of a model oriented platform. It has been designed to be a common basis to implement Metadata languages, action languages, constraint languages or transformation language.
In a nutshell, Kermeta is :
MOF compliant (EMOF compliant to be precise)
Model oriented
Imperative
Object-Oriented
Statically Typed (100% typesafe)
In addition to these characteristics, it includes some typically model-oriented concepts like associations, multiplicities or object containment management.
This chapter presents the main features of the Kermeta language. Section 2 presents the general syntax of the language, sections 3 & 4 give details about the object-oriented and model-oriented features of the language and finally section 4 provides information about some extra concepts in Kermeta.
Kermeta is an imperative language for modeling, with a basic syntax inspired from Eiffel. Code is statically type checked, and execution is made by an interpreter (a compiler is on the way, for exhausted performances).
Even if it is not very useful in our context, since it doesn't show the really interresting structures of the language, here is the traditional " Hello world " example you can find in every programming book.
@mainClass "helloworld::HelloworldExample" @mainOperation "sayHello" package helloworld; require kermeta using kermeta::standard class HelloworldExample { operation sayHello() is do stdio.writeln("Hello world, ...") end }
Kermeta language includes usual statements like blocks and loops, comments,...
do
// a loop for getting a text from an user
var s : kermeta::standard::String
from var found : kermeta::standard::Boolean init false
until found
loop
s := stdio.read("Enter a text:\n --> ")
if s.size > 0 then
found := true
else
stdio.writeln("ERROR - Empty text!")
end
end
stdio.writeln("\n You entered: " + s)
end
All these "classic" imperative features and their syntaxes are described in Chapter 2, Reference. More precisely in
Users of modern l programming languages, like Java, would feel easy with object-oriented features in Kermeta: classes, inheritance, exceptions, and even genericity.
// persons who write documents class Writer { attribute name : kermeta::standard::String } // generic concept for every document abstract class Document { reference author : Writer attribute text : kermeta::standard::String } // a "Document" from the real world class Book inherits Document {} // a specialized "Book" class ChildBook inherits Book { attribute minimalAge : kermeta::standard::Integer }
Such classes can be used for verifications:
// a specialized Exception class AgeException inherits kermeta::exceptions::Exception {} abstract class Reader { operation read(book : ChildBook) : Void is abstract } class Child inherits Reader { attribute age : kermeta::standard::Integer operation initialize(age : kermeta::standard::Integer) : Void is do self.age := age end // an action which triggers an Exception... operation read(book : ChildBook) : Void is do if age < book.minimalAge then raise AgeException.new end end }
You can get more informations about Kermeta object-oriented features in Chapter 2, Reference. More precisely in
As explained in the Preface and in Architecture, Kermeta extends the MOF. It intends to provide useful models manipulation tools.
MOF defines the concept of "Property" which generalizes the notions of attributes, and associations (composite or not) that you can find in UML. Kermeta syntax also distinguishes these two notions as introduced in Section 2.15, “Class properties”.
As a reminder, the attribute keyword defines
a link with containment (a composite association) whereas the
reference keyword just defines an association. As
you can see, property declarations are very close to variable
declarations introduced in Section 2.6, “Using
Variables”).
Each reference may be explicitly linked to another reference (it is
the opposite concept in MOF terminology – see also
section Section 2.15.1, “Attributes
(attribute), references
(reference) ”).
class Library { attribute books : set Book[0..*] } class Book { attribute title : String attribute subtitle : String reference authors : oset Author[1..*]#works } class Author { attribute name : String attribute lastName : String reference works : set Books[0..*]#authors }
If we represent our Kermeta model in a graphical syntax we obtain the following diagram (Figure 1.2, “A concrete example : a library”).
Using Eclipse Modeling Framework (EMF), Kermeta can load and save models done with other EMF tools.
/* Initialize the EMF repository */ var repository : EMFRepository init EMFRepository.new /* Create an EMF Resource, given model and metamodel URIs as String */ var resource : Resource init repository.createResource(myModelURI, itsMetamodelURI) /* Load the resource */ resource.load // get elements from the resource // in this sample, you know that your root element is always a Library, // so you can directly get the first one var aLibrary : Libray aLibrary ?= resource.one // note the conditionnal assignment using the ?=, if not a Library you'll get Void
In the same way, you can serialize a model, or load, change and save an existing model.
![]() | Caution |
|---|---|
Your model URI MUST be of the form "platform:/resource/myProject/myModel" or "platform:/plugin/myProject/myModel". Your metamodel URI MUST be of the form "platform:/resource/myProject/myModel" or "platform:/plugin/myProject/myModel" or an URI registered in the EMF registry. |
![]() | Caution |
|---|---|
Be aware that you CANNOT load kermeta text files. Only xmi files are allowed to be loaded. |
Actually, navigating in a model is as simple as using objects in an Object Oriented program. However, several features have been added in order to ease this activity.
For example, thanks to the lambda expressions, the collections of the language are easily manipulated using lexical closure (select, collect, each, ...). This applies to all the collections of the language, the one you may define directly but also the one which are used when an Attribute or Reference has a multiplicity greater than 1.
TODO : a simple example of navigation (applying visitor pattern ???)
In order to improve reuse of existing code between metamodel variants, the language introduces the notion of ModelType. It is based on the notion of conformance between two metamodels. This allows to write behavior that is valid for a given metamodel and that will also work for any conformant metamodel.
In order to improve reuse of existing code between metamodel variants, the language introduces the notion of ModelType. It is based on the notion of conformance between two metamodels. This allows to write behavior that is valid for a given metamodel and that will also work for any conformant metamodel.
TODO write a small illustrative example of a simple printer based on a ModelType : a subset of class diagram of UML
Kermeta has been developed, using MDE principles so it also provides its own metamodel (reflectiveley available). Details of Kermeta metamodel is available in Chapter 3, Kermeta Metamodel
You can get more informations about all Kermeta model-oriented features in the Chapter 2, Reference. More precisely in
Kermeta implements several "less common" or advanced features that helps in many situations.
Typically, lambda expressions/functions is a well known concept, very useful in almost all kermeta code. Even, if you will probably not write your own function, you'll certainly use the existing one defined on collections.
In order to implement and statically type check OCL-like iterators, Kermeta includes some limited functional features by implementing lambda expressions.
This is typically used on Collection which
provides functions like : each,
select, forAll,
detect, ...
Example 1: the following code will build a collection of names of the operations that start with "test".
var names : Collection<String> names := self.getMetaClass.classDefinition.ownedOperation .select{ op | op.name.indexOf("test") == 0} .collect{ op | op.name }
Example 2: Providing a time function on Integer
operation times(body : <Integer->Object>) : Void is do from var i : Integer init 0 until i == self loop body(i) i := i + 1 end end
this allows to write code like :
var res : Integer 10.times { i | stdio.writeln(i.toString + ": Hello") } // Say 10 times Hello
See sections "Lambda Expressions and functions" and Lambda Expression for detailed informations.
Kermeta most recent versions embed avanced concepts like Lambda Expressions and functions, Dynamic evaluation of Kermeta expressions, Design by contract (pre, post, inv contraints) or Weaving kermeta code.
As Kermeta language is implemented upon Eclipse and Java, you can call Java code inside Kermeta code.(see Section 2.22, “Using existing java code in Kermeta”)
TODO : a simple sample of Java code in Kermeta
There is some special behavior regarding object comparison or cloning.
The reference sections are ordered in four parts: the imperative syntax (1-6), the object-oriented (7-10) and the model-oriented (11-15) features, the advanced concepts (16-21).
![]() | Warning |
|---|---|
Comments are a little bit particular in the Kermeta language because they are not all ignored by the interpreter. There are two kinds of comments: the first (syntax : // foo , /* bar * /) is only associated to the text editor view in which the user edits his Kermeta file, and the second one(syntax : /** foo */ or @tag_name "tag value") is translated into a MOF tag linked to structures described in the Kermeta model. |
Like in many languages, Kermeta provides two ways to add comments in your models:
simple line comments, i.e text line beginning with //
// This is a single line comment
multi-line comments, i.e text between /* */. Be careful with this notation : the opening syntax must not have juxtaposed stars ("/**"), otherwise it will be considered as a linked comment (see Section 2.1.2, “Linked comments”), i.e a comment that is part of the Kermeta program as a model.
/* This a multi line comment all these lines are comments this line too. */
Kermeta provides a way to define named and unnamed annotations,
that have to be defined just above any model element among
Package, ClassDefinition,
Property, Operation. Such
annotations correspond to MOF tags, and are linked to the elements
which immediately follows.
To define a named annotation, you have to use a special symbol "@", whereas an anonymous annotation has to be written between /** and */
Example 1: you can define an annotation to describe the role of a property
@usage "count the number of ..."
reference myCounter : Integer Example 2: you can document your classes and operation using /** ... */
/** * This is a documentation tag for the class "myClass" */ class MyClass { /** This is a documentation tag for myOperation */ operation myOperation() is do // Unlinked comment end @desc "This is a named annotation for thisOperation" operation thisOperation() is do /* This is an unlinked comment */ end }
Kermeta textual syntax uses several keywords like
class, attribute,
reference, result, etc. (Please
see Appendix A, Language keywords at the end of this
document to get the complete list of Kermeta keywords.)
This doesn't mean you cannot use these words for your own model. Moreover, this is only a textual syntax limitation.
So Kermeta syntax allows you to use the word you want, you simply have to prefix it with a tilda ~.
This example is valid even if we use "class" and "attribute" which are keywords in the language:
class ~class { attribute ~attribute : kermeta::standard::String attribute ~class : kermeta::standard::String }
Priority | Operator | Operand types | Semantic |
|---|---|---|---|
1 | | Numeric String | Add two numeric values Concatenate two strings |
1 | | Numeric | Subtract two numerous values |
2 | | Numeric | Multiply two numeric values |
2 | | Numeric | Divide the first operand by the second |
Notice that most of these arithmetic operators are only defined for numeric primitive types like Integer. Except the + operator which is a concatenation operator for String, they are not applicable on String, Boolean nor collections
Priority | Operators | Operand Types | Semantics |
|---|---|---|---|
3 | | All | True, if op1 value's is the same that op2 value's |
3 | | All | True if op1 value's is different of op2 value's |
3 |
| Numeric | True if op1value's is strictly smaller than op2 value's |
3 |
| Numeric | True if op1 value's is smaller or equals than op2 value's |
3 |
| Numeric | True if op1 value's is strictly greater than op2 value's |
3 |
| Numeric | True if op1 value's is greater or equals than op2 value's |
Priority | Operators | Operands Types | Semantics |
|---|---|---|---|
4 | | Boolean | True if op1 and op2 are evaluated to true |
4 | | Boolean | True if one of the operators is evaluated to true |
4 | | Boolean | True if op is false. |
![]() | Note |
|---|---|
The See Section 2.16, “Objects comparison” for more details about object comparison. |
Kermeta provides a block notion to manage scope of variable.
Instruction of the block have to be inserted between
do and end keywords. Theses two
keywords may be omitted for the conditional and for the loop
structures.
A variable could only be accessed in the block where it was defined and in its sub blocks:
do var v1 : Integer init 3 var v2 : Integer init 2 do var v3 : Integer v3 := v1 + v2
var v2 : Integer // error : v2 is already declared in the upper block end var v4 : Integer init v3 // error : v3 is unknown here end
Kermeta's conditional statement is composed of at least two
elements : a boolean expression and a block that is executed if the
boolean is evaluated to true. You can add a third
element, with the else keyword, that is executed if
the boolean expression is evaluated to
false.
Example 1: if..then..else block
var v1 : Integer init 2 var v2 : String init "blah" if v1 > 5 then v1 := v1-5 if v1 == 2 then v2 := v1 v1 := v2 + v1 else v1 := 0 end
The if statement is an expression (see Chapter 3, Kermeta Metamodel). As any expression in
Kermeta, it can return a value. The return type of the
if statement must be a super type of the values
"returned" by both then and else
blocks (otherwise the type checker will send an error). The values
considered as the result of the evaluation (the "returned" values) of
the if statement are the last evaluated statement
inside then or else block
Example 2: conditional is an expression
var s : String s := if false then "a" else "b" end
Example 3: a more complex conditional
var x : String var y : Integer init 5 x := if y < 3 then stdio.writeln("hello") "a" else "b" "c" end // The String "c" will be the value of x
Here is a sample of a typical loop in Kermeta.
var v1 : Integer init 3 var v2 : Integer init 6 from var i : Integer init 0 until i == 10 loop i := i + 1 end
![]() | Note |
|---|---|
Unlike Java, there is no exit, break or continue function in Kermeta. |
See Section 2.14, “Collections” for functions offering iterator-like scanning.
Kermeta code can be quite large, and invloves many classes in
different metamodels. The main mecanism used to organise your code is
the require statement.
When you need to refer explicitly another entity defined in
another file, you have to use the require
primitive. It allows loading definitions of an other Kermeta file when
file is processed. In the following example, we define a class C which
inherits from the A class previously defined.
// file : MyPackage-part1.kmt package subPackage1; class A { // ... }
// file : MyPackage-part2.kmt package MyPackage; require "MyPackage-part1.kmt" class C inherits subPackage1::A { // ... }
![]() | Note |
|---|---|
In most case, the order of the declaration in not important. The only exception is a very rare situation related to aspects (see Section 2.20, “Weaving kermeta code” ). |
![]() | Note |
|---|---|
You can create cyclic dependencies of files, the environment will deal with that. |
You can require different kind of
entity
Obvioulsy, you can require Kermeta textual
syntax, ie. *.kmt files
You can require Kermeta models, ie. *.km files.
You can require Ecore models, ie. *.ecore files. These models can then be used
as if they were written in Kermeta. In order to add behavior to the
classes defined in .ecore files you may : use the weaving to dynamically weave
behavior to the ecore, or roundtrip using the button action in the
workbench (ecore->kmt->ecore) to statically add the behavior (as
EAnnotations) into the ecore file.
A variant of requiring an ecore file is to require registered EPackage. When Eclipse deploys an
ecore model plugin, it also registers the EPackage using a unique
identifier (nsuri) in order to retreive it quickly. In Kermeta you can
also use this nsuri into the require statement. This approach is
useful becauseyou can be sure that you require the very same model as
eclispe use to load and save models of that sort. For example, instead
of requiring ecore.ecore you may use require
"http://www.eclipse.org/emf/2002/Ecore". This also works for
all other registered metamodels (Your own registered metamodel, UML
metamodel, etc ...). Kermeta user
interface provides a view that display all registered
EPackages and their nsuri.
In order to use the seamless java import (still prototype in v0.4.2), you can require a jar file. It will automatically convert the java into a Kermeta representation in order to be able to call java code as if it was written in Kermeta. see Section 2.22, “Using existing java code in Kermeta” for more details.
Kermeta lets you organise your code the way you prefer. There is no predefined organisation of your code, but the language and the workbench proposes various mecanisms and tools to structure it according to your needs and the style you wish for your code. Typically if you use kermeta internal weaver (see Section 2.20, “Weaving kermeta code”), manually transform your ecore into Kermeta, eventually weaving the ecore using the merge button available on the worbench.
For example, you can put all your classes into a single file
(like in Ecore, every classes is in the .ecore file) or you may create
a file for each of them and then use the require to
indicates that they must know each other You can also use an
organisation like java, with a file per class and a directory per
package...
Whenever you need a data locally to a block because it doesn't goes into a class attribute or reference, you can use a local variable.
A variable is defined by a name and by a type. If needed, the name of the variable can be escaped using the tilda (~)
Declaring a variable:
var foo : String // This is a variable declaration
In the following example, we define 3 variables of type integer. The first is initialized with the "14" literal value, the second is initialized with an expression using v1. For the last variable, we use a multiplicity notation to specify an ordered set of integer (see Section 2.14, “Collections” and Section 2.15, “Class properties” for more information on sets).
do var v1 : Integer init 14 var v2 : Integer init 145 * v1 var tab : Integer[0..*] init kermeta::standard::OrderedSet<Integer>.new v1 := v2/v1 end
Be careful to the multiplicity, when you create a variable with
multiplicity, you have to initialize it with a collection. Then to use its
content, you need to use the collection operation like add, addAll,
remove, select, etc. If you use the assignment := it
will replace your collection ...
Kermeta implements a few primitive types. By primitive types, we mean types that are basic to any language, i.e integer, and that have a "literal" value. See below table.
Name | Description | Literal Example |
|---|---|---|
Integer | Represents integer numeric value like 10 or 12. (« int » data type in Java) | 101, 12, 14, -45, -123 |
String | Represents a string of like « helloworld » (« String » data type in Java) | "helloworld", "this is a string !!!" |
Boolean | Represents a true/false value. (« boolean » data type in Java) | true, false |
// Simple datatypes examples var myVar1 : Integer init 10 var myVar2 : Integer var myVar4 : String init "a new string value" var myVar5 : boolean
Kermeta also supports some other primitive types like Float and Character, but they currently don't have a surface syntax for their literals. The way to get them is to use the convertion methods available on String (for both of them) or Integer (for Float).
You can define enumeration types by using the following syntax. Note that each enumeration literal must end with a ";".
enumeration Size { small; normal; big; huge; } You can manipulate enumerated variables and literals with classical operators such as in the following example.
var mySize : Size if ( mySize == Size.small ) then stdio.writeln("This is small !") end
![]() | Note |
|---|---|
Enumeration are concept of the same level as classes, they must be defined in a package. |
In Kermeta, you can define your own datatype based on existing types without a hard dependency like inheritance.
This is done using the alias syntax.
Ex:
alias MyString : kermeta::standard::String;In this sample, MyString has all the behavior of kermeta::standard::String but is declared locally. This means that you don't have any dependency to the framework, even to the String in the framework.
Obviously you can reuse existing type names :
alias String : kermeta::standard::String;This will create a new type String in your package with the behavior of String in the framework.
The definition of an alias is different from the use of "using" statement (as defined in Section 2.13.3, “Syntaxic sugars”), when you write
using kermeta::standard
you simply defined a syntactical shortcut allowing you to access any definition in this package from within this file.
Wheras defining an alias allows you to access this new definition from another package if needed.
![]() | Tip |
|---|---|
It is interesting to redefine your own datatype for all the standard type you use in your metamodel, so when you convert the file into ecore in order to have serialisation, you won't have any dependency to framework.ecore (which is the ecore version of the framework where kermeta standard type) This allow a lazy coupling of the type definitions. |
As introduced in the "Hello world" example (see Section 1.2.1, “First Program”), Kermeta is an object-oriented language and operations are part of classes. Kermeta provides all MOF concepts like properties, attributes, package.
Classes and abstract classes can be defined in a Java-like way. Class definition must be placed into brackets as it is in the following example.
// an empty simple class class myFirstClass { } // a simple abstract class abstract class MyAbstractClass { }
Additionally, for better code robustness, and more user-friendly programming, classes can use the genericity mechanisms (see Section 2.10, “Genericity” for more information).
// This is a parametric class class A<G> { } // This is the type variable binding : G is binded with Integer var a : A<Integer> a := A<Integer>.new
There are some limitations in regards to Java. For example, you cannot define nested classes in Kermeta. Kermeta offers the same structural concepts than MOF language.
Kermeta provides a way to add operational (==action) semantics to your metamodels. For that, you can define operations with their body, as in a classical programming language. You can also specify abstract operations (they have no body). Kermeta requires that every class that contains an abstract operation must be declared as an abstract class.
In the following example, we define some operations, based on a visitor pattern implementation
class Inventory { operation visitLibrary(l : Library) is do writeln("Inventory : "); l.books.each(b : Book | b.ac
![[Important]](http://www.kermeta.org/docs/html.single/KerMeta-Manual/gfx/admonitions/important.gif)
![[Tip]](http://www.kermeta.org/docs/html.single/KerMeta-Manual/gfx/admonitions/tip.gif)


![[Caution]](http://www.kermeta.org/docs/html.single/KerMeta-Manual/gfx/admonitions/caution.gif)
![[Warning]](http://www.kermeta.org/docs/html.single/KerMeta-Manual/gfx/admonitions/warning.gif)
![[Note]](http://www.kermeta.org/docs/html.single/KerMeta-Manual/gfx/admonitions/note.gif)