Skip to content

Metamodel plugin

Defines the structure of a domain: classes, properties, enums, inheritance and associations. Every other modelling language in the platform is written against a metamodel, which makes this the plugin you enable first.

At a glance

Plugin idmetamodel-service
Display nameMetamodel
DescriptionLanguage support for metamodel definitions (.mm files)
Default URL/plugin/metamodel
Sourceapp/packages/service-metamodel, app/packages/language-metamodel, app/packages/editor-metamodel
Depends onNothing

Languages contributed

Language idNameExtensionTextual editorGraphical editorGenerated
metamodelMetamodel.mm

The metamodel language

A .mm file declares enums, classes and associations at the top level, in any order.

mm
// Enumerations, abstract classes, inheritance, primitive types and multiplicities.

enum Colour {
    RED
    GREEN
    BLUE
}

abstract class Shape {
    name: string
    visible: boolean
    colour: Colour
    tags: string[*]
}

class Rectangle extends Shape {
    width: double
    height: double
}

class Circle extends Shape {
    radius: double
}

class Canvas {
    title: string
    revision: long
}

class Layer {
    index: int
}

class Annotation {
    text: string
}

// A canvas owns at least one layer; both ends are navigable.
Canvas.layers[1..*] *--> Layer.canvas

// A layer owns any number of shapes.
Layer.shapes[*] *--> Shape.layer

// Shapes and annotations reference each other.
Shape.annotations[*] <--> Annotation.shape

Classes and properties

mm
abstract class Shape {
    name: string
    tags: string[*]
}

class Circle extends Shape {
    radius: double
}
  • abstract marks a class that cannot be instantiated.
  • extends takes a comma-separated list, so multiple inheritance is allowed.
  • A property is name: type with an optional multiplicity in brackets.

The primitive types are int, long, float, double, string and boolean. A property may also have an enum type.

Multiplicities

FormMeaning
(omitted)Exactly one
[*]Any number
[+]At least one
[?]Zero or one
[n]Exactly n
[n..m]Between n and m
[n..*]At least n

Enums

mm
enum Colour {
    RED
    GREEN
    BLUE
}

Associations

Associations are declared at the top level, not inside a class. An end is a class, optionally followed by a property name and a multiplicity. A class only gets a property for an end that carries a name, and which ends may carry a name is determined by the operator:

OperatorMeaningProperty on the leftProperty on the right
-->Navigable from left to rightrequiredforbidden
<--Navigable from right to leftforbiddenrequired
<-->Navigable in both directionsrequiredrequired
*-->Composition, whole on the left, navigable both waysrequiredrequired
*--Composition, whole on the left, navigable from the partforbiddenrequired
<--*Composition, whole on the right, navigable both waysrequiredrequired
--*Composition, whole on the right, navigable from the partrequiredforbidden

One example of each:

mm
// One example per association operator. A class only gets a property for an end that
// carries a name, and the star always sits on the side that owns (contains) the other one.

class Whole {
    id: string
}

class Part {
    id: string
}

// Plain association, navigable from source to target only.
Whole.partsA[*] --> Part

// Plain association, navigable from target to source only.
Whole <-- Part.wholeB

// Plain association, navigable in both directions.
Whole.partsC[*] <--> Part.wholeC

// Composition with the whole on the left, navigable in both directions.
Whole.partsD[*] *--> Part.wholeD

// Composition with the whole on the left, navigable from the part only.
Whole *-- Part.wholeE

// Composition with the whole on the right, navigable in both directions.
Part.wholeF <--* Whole.partsF[*]

// Composition with the whole on the right, navigable from the part only.
Part.wholeG --* Whole

Composition means containment: an object may have at most one container, so the multiplicity on the end that points at the whole cannot be * or +, and must be optional when several compositions can contain the same class.

Splitting a metamodel across files

mm
import "./shapes.mm"

import makes every class and enum of the imported file — and of the files it imports — visible. Association ends may only carry a property name for classes declared in the current file:

mm
// A metamodel can be split across files. `import` pulls in every class and enum of the
// imported file, including the ones it imports itself.
import "./shapes.mm"

class Sticker extends Shape {
    url: string
}

// An association end may only carry a property name for a class declared in this file,
// so the imported `Layer` stays unnamed here.
Sticker.placedOn --> Layer

Graphical editor

.mm files open in a class-diagram editor as well as in the text editor. The palette creates classes, enums and associations; the connection type is chosen before drawing an edge, and labels are edited in place. Layout is computed with ELK.

Contribution plugins contributed

Target languageWhat it adds
configMetamodel type exports

Metamodel types for the config language

The metamodel plugin contributes no syntax to the config language. What it contributes is its AST types — Class, Property, Enum, Association, AssociationEnd, the multiplicity types, PrimitiveType, EnumTypeReference, EnumEntry, ClassExtension, ClassExtensions and FileImport.

Contribution plugins that do add syntax can then declare a dependency on this one and write grammar rules that reference metamodel classes. That is how Config Optimization can resolve refine Canvas.layers[1..4] against your metamodel, and how Config MDEO can resolve create Annotation inside a mutations block.

Contribution plugin idconfig-metamodel
Short namemetamodel
Sectionsnone
Exported types13 metamodel AST interfaces

Server-side capabilities

File data keyContents
astThe serialised AST of the metamodel
metamodelMetamodel-specific derived data used by dependent languages

The plugin has no execution handler: metamodels are not run, they are referenced.

Released under the terms of the repository licence.