Pattern
The Pattern language
The pattern language has a single purpose - to define patterns of model structures. Those patterns form visual representations of nodes you want to match. A pattern matches a node if the node's property values are equal to those specified in the pattern, node's references point to the same targets that the ones of the pattern do and the corresponding children match the appropriate children of the pattern.
Also patterns may contain variables for nodes, references and properties, which then match any node/reference/property. On top of that the variables will hold the actual values upon a successful match.
PatternExpression
The single most important concept of the pattern language is PatternExpression. It contains a pattern as its single arbitrary node. Also, the node can specify the following variables:
#name - a node variable, a placeholder for a node. Stores the matching node
#name - a reference variable, a placeholder for a reference. Stores the reference's target, i.e. a node.
$name - a property variable, a placeholder for a property value. Stores the property value, i.e. a string.
*name - a list variable, a placeholder for nodes in the same role. Stores the list of nodes.
Antiquotations may be in particular useful when used inside a pattern, just like inside quotations (see Antiquotations).
Examples
1. The following pattern matches against any InstanceMethodDeclaration without parameters and a return type:
Captured variables:
$methodName | string | method's name |
#statementList | node<StatementList> | statements |
2. The following pattern matches against a ClassifierType with the actual classifier specified inside an antiquotation expression and with any quantity of any type parameters:
Captured variables:
*l | nlist<Type> | class type's parameters |
#ignored | node<Type> | used as wildcard, its contents is ignored. Means that parameters are arbitrary |
Using patterns
Match statement
Patterns are typically used as conditions in match statements. Pattern variables can be referenced from inside of the match statement.
For example:
This piece of code examines a node n and checks whether it satisfies the first or the second condition. Then the statement in the corresponding (matching) block is executed. A pattern variable $name is used in a first block to print out the name of a node. In our case the node holds a variable declaration.
Other usages
Patterns are also used in several other language constructs in MPS. They may appear:
as conditions on applicable nodes of typesystem/replacement/subtyping/other rules of typesystem language (See Inference rules)
as supertype patterns in coerce statement and coerce expression (See Coerce)
as conditions on node in generator rules
as pattern in TransformStatement used to define language migrations (See Migrations)
You can also use patterns in your own languages.
Basically what happens is that a class is generated from a PatternExpression and the expression itself is reduced to a constructor of this class. This class extends GeneratedMatcher and has a boolean method match(SNode), which returns a boolean value indicating whether the node matches the pattern. It also holds a method getFieldValue(String) to get the values stored in pattern variables after a successful match.
To develop your own language constructs using patterns, you can call these two methods in the generator template for your constructs.
Light patterns (pattern builders)
Pattern language, which allows the user to match code against a parametrized structure, is based on quotations and has its counterpart based on light quotations. Using light patterns helps to avoid problems like bootstrap dependency and confusing node editors. They have some additional advantages:
Light patterns are better integrated into baseLanguage. Nodes can be matched against light patterns via the pattern switch statement. Light patterns can be written directly in place inside the switch clause or declared independently as class members and then used from the switch clause.
Only those node properties and links should be mentioned that need to be checked during matching. If any value should match (wildcard behavior), the property or link can be omitted.
-
Pattern variables can be used inside the switch clauses to retrieve nodes and properties from the matched node. They can be used inside the pattern initializers as well, to create patterns matching self-referencing subtrees or duplicated property values. If there is no node to match with the variable, the variable may hold a null value.
If a list of nodes is defined in a light pattern then the order defined in the list is strictly followed during matching. While this is desired for ordered child collections, which is the default in MPS, it may give surprising results when matching against unordered collections, since the light pattern language always considers the order in its definition. An explanatory info message is shown to the user to indicate situations when matching against an unordered collection is detected.