MPS 2024.1 Help

Constraints

The Structure Language may sometimes be insufficient to express advanced constraints on the language structure. The Constraints aspect gives you a way to define such additional constraints.

Default concrete concept

For abstract concepts the Constraints aspect can be used to indicate, which concept should be used instead when a node of the abstract concept needs to be created.

image2018-9-12-15-43-19.png

For example, if a child collection is supposed to hold AbstractCommands and the user hits enter to insert a new child into the collection, a node of the EmptyLine concept is created and inserted.

Similarly. the smodel commands that create new nodes and accept the <default> parameter will correctly create nodes of the concrete concept instead of the abstract one.

image2018-9-12-15-50-5.png

Can be child/parent/ancestor/root

These are the first knobs to turn when defining constraints for a concept. They determine whether instances of this concept can be hooked as children (parents, ancestors) nodes of other nodes or root nodes in models. You specify them as boolean-returning closures, which MPS invokes each time when evaluating allowed possition for a node in the AST.

Constraintsx1.png

Languages to import

You will most likely need at least two languages imported in the constraints aspect in order to be able to define constraints - the j.m.baselanguage and j.m.lang.smodel languages.

can be child

Return false if an instance of the concept is not allowed to be a child of specific nodes.

parameter

description

node

the child node we are checking (instance of this concept)

parentNode

the parent node we are checking

childConcept

concept of the child node (can be a subconcept of this concept)

link

LinkDeclaration of the child node (child role can be taken from there)

can be parent

Return false if an instance of concept is not allowed to be a parent of specific concept node (in a given role).

parameter

description

childNode

the child node we are checking

node

the parent node we are checking (instance of this concept)

childConcept

the concept of the child node we are checking

link

LinkDeclaration of the child node

can be ancestor

Return false if an instance of the concept is not allowed to be an ancestor of specific nodes.

parameter

description

childNode

the child node we are checking

node

the ancestor node we are checking (instance of this concept)

childConcept

the concept of the descendant node

can be root

This constraint is available only for rootable concepts (instance can be root is true in the concept structure description). Return false if instance of concept cannot be a root in the given model.

parameter

description

model

model of the root

instance icon

Return an icon to represent nodes of the concept in the given context.

parameter

description

node

The node to draw an icon for.

Property constraints

Technically speaking, "pure" concept properties are not properties in its original meaning, but only public fields. Property constraints allow you to make them real properties. Using these constraints, the behavior of concept's properties can be customized. Each property constraint is applied to a single specified property.

property - the property to which this constraint is applied.

get - this method is executed to get property value every time property is accessed.

parameter

description

node

node to get property from

set - this method is executed to set property value on every write. The property value is guaranteed to be valid.

parameter

description

node

node to set property

propertyValue

new property value

is valid - this method should determine whether the value of the property is valid. This method is executed every time before changing the value, and if it returns false, the set() method is not executed.

parameter

description

node

node to check property

propertyValue

value to be checked

Example - customizing the description in the completion menu

The completion menu lists available nodes together with some additional descriptive information:

sd1.png

In order to customize the additional information and provide more details on the individual options listed in the completion menu, you can override the getter of the shortDescription property of the target concept:

sd2.png
sd3.png

Referent constraints

Constraints of this type help to add behavior to concept's links and make them look more properties-like.

referent set handler - if specified, this method is executed on every set of this link.

parameter

description

referenceNode

node that contains link.

oldReferentNode

old value of the reference.

newReferentNode

new value of the reference.

scope - defines the set of nodes to which this link can point. The method returns a Scope instance. For more information, refer to the Scopes documentation. There are two types of scope referent constraint:

  • inherited

  • reference

While inherited scope simply declares the target concept, the reference scope provides a function that calculates the scope on the fly from the parameters.

parameter

description

referenceNode

the node that contains the actual link. It can be null when a new node is being created for a concept with smart reference. In this situation smart reference is used to determine what type of node to create in the context of enclosingNode, so the search scope method is called with a null referenceNode.

contextNode

node with the reference or the closest not-null context node

containmentLink

SContainmentLink describing parent-child relationship between the contextNode and its non-existent child that is being created (if referenceNode exists then this parameter has no meaning)

linkTarget

the concept that this link can refer to. Usually it is a concept of the reference, so it is known statically. If we specialize reference in subconcept and do not define search scope for specialized reference, then linkTarget parameter can be used to determine what reference specialization is required.

position

the target index in contextRole

If scope is not set for the reference then default scope from the referenced concept is used. If the default scope is also not set then "global" scope is used: all instances of referent concept from all imported models.

presentation (deprecated - the editor aspect now specifies presentation of references, refer to Editor) - here you specify how the reference will look like in the editor and in the completion list. Sometimes it is convenient to show reference differently depending on context. For example, in Java all references to an instance field f should be shown as this.f, if the field is being shadowed by the local variable declaration with the same name. By default, if no presentation is set, the name of the reference node will be used as its presentation (provided it is an INamedConcept).

parameter

description

model

model of node containing reference

parameterNode

the node to be presented (referenceNode has a reference to parameterNode of type linkTarget)

position

target index in contextRole

exists

false when reference is being created

visible

true - presentation of existing node, false - for new node (to be created after selection in completion menu)

smartReference

true - node is presented in the smart reference

inEditor

true - presentation for editor, false - for completion menu

contextNode

node with the reference, or closest not-null context node

contextRole

target role in contextNode

referenceNode

enclosingNode

linkTarget

containingLink

deprecated

Default scope

Suppose we have a link pointing to an instance of concept C and we have no scope defined for this link in referent constraints. When you edit this link, all instances of concept C from all imported models are visible by default. If you want to restrict set of visible instances for all links to concept C you can set default scope for the concept. As in referent constraint you can set scope and presentation methods. All the parameters are the same.

For more information, refer to the Scopes documentation.

Additional methods

The additional methods section at the bottom allows the user to define utility methods that can be called from within the constraints definition to avoid repetition. The additional methods typically perform calculations or perform tasks that are needed in multiple places of the constraints definition. The additional methods must be private to only be visible from within the containing node.

Last modified: 11 February 2024