Child pages
  • SModel language Queries
Skip to end of metadata
Go to start of metadata

Queries

Features access

The SModel language can be used to access the following features:

  • children
  • properties
  • references
  • concept properties
  • concept references

To access them, the following syntax is used:

If the feature is a property, then the type of whole expression is the property's type. If the feature is a reference or a child of 0..1 or 1 cardinality, then the type of this expression is node<LinkTarget>, where LinkTarget is the target concept in the reference or child declaration. If the feature is a child of 0..n cardinality, then the type of this expression is nlist<LinkTarget>.

You can use so-called implicit select to access features of the child nodes. For example, the following query:

will be automatically transformed by MPS to something like:

resulting in a plain collection of all non-null model elements accessible through the specified chain of link declarations.

Null checks

Since nulls are treated liberally in MPS, we need a way to check for null values. The isNull and isNotNull operations are our friends here.

IsInstanceOf check and type casts

Often, we need to check whether a node is an instance of a particular concept. We can't use Java's instanceof operator since it only understands java objects, not our MPS nodes. To perform this type of check, the following syntax should be used:

Also, there's the isExactly operation, which checks whether a node's concept is exactly the one specified by a user.

Once we've checked a node's type against a concept, we usually want to cast an expression to a concept instance and access some of this concept's features. To do so, the following syntax should be used:


Another way to cast node to particular concept instance is by using as cast expression:

The difference between the regular cast (using colon) and the as cast is in a way it handles the situation when the result of the left-side expression cannot be safely cast to the specified Concept instance: A NullPointer exception will be thrown by the regular cast in this case, while null will be returned by the as cast.

Combine this with the null-safe dot operator in the smodel language and you get a very convenient way to navigate around the model:

Icon

Intention are available to easily migrate from one type of cast expression to the other:

Parent

In order to find a node's parent, the parent operation is available on every node.

Children

The children operation can be used to access all direct child nodes of the current node. This operation has an optional parameter linkQualifier. With this parameter result of children<linkQualifier> operation is equivalent to node.linkQualifier operation call and so will recall only the children belonging to the linkQualifier group/role. E.g. classDef.children<annotation, member>

Sibling queries

When you manipulate the AST, you will often want to access a node's siblings (that is, nodes with the same role and parent as the node under consideration). For this task we have the following operations:

  • next-sibling/prev-sibling - returns next/previous sibling of a node. If there is no such sibling, null is returned.
  • next-siblings/prev-siblings - returns nlist of next/previous siblings of a node. These operations have an optional parameter that specifies whether to include the current node.
  • siblings - returns nlist of all siblings of a node. These operations have an optional parameter that specifies whether to include the current node.

Ancestors

During model manipulation, it's common to find all ancestors (parent, parent of a parent, parent of a parent of a parent, etc) of a specified node. For such cases we have two operations:

  • ancestor - return a single ancestor of the node
  • ancestors - returns all ancestors of the node
    Both of them have the following parameters to narrow down the list:
  • concept type constraint: concept=Concept, concept in [ConceptList]
  • a flag indicating whether to include the current node: +

E.g. myNode.ancestors<concept = InstanceMethodDeclaration, +>

Descendants

It's also useful to find all descendants (direct children, children of children etc) of a specified node. We have the descendants operation for such purposes. It has the following parameters:

  • concept type constraint: concept=Concept, concept in [ConceptList]
  • a flag indicating whether to include current node: +

E.g. myNode.descendants<concept = InstanceMethodDeclaration>

Containing root and model

To access top-most ancestor node of a specified node you can make use of containing root operation. Containing model is available as a result of the model operation.

For example,

  • node<> containingRoot = myNode.containing root
  • model owningModel = myNode.model

Model queries

Often we want to find all nodes in a model which satisfy a particular condition. We have several operations that are applicable to expressions of model type:

  • roots(Concept) - returns all roots in a model, which are instances of the specified Concept
  • nodes(Concept) - returns all nodes in a model, which are instances of the specified Concept

E.g. model.roots(<all>) or model.nodes(IfStatement)

Search scope queries

In some situations, we want to find out, which references can be set on a specified node. For such cases we have the search scope operation. It can be invoked with the following syntax:

The Concept literal

Often we want to have a reference to a specified concept. For this task we have the concept literal. It has the following syntax:

E.g. concept<IfStatement> concept = concept/IfStatement/

Concept operation

If you want to find the concept of a specified node, you can call the concept operation on the node.

E.g. concept<IfStatement> concept = myNode.concept

Migrating away from deprecated types

The conceptNode<> type as well as the conceptNode operation have been deprecated. The asConcept operation will convert a conceptNode<> to a concept<>. The asNode operation, on the other hand, will do the opposite conversion and will return a node<AbstractConceptDeclaration> for a concept<>.

Icon

The conceptNode<> type was called concept<> in MPS 3.1. The conceptNode operation was called concept in MPS 3.1.

Concept hierarchy queries

We can query super/sub-concepts of expression with the concept type. The following operations are at your disposal:

  • super-concepts/all - returns all super-concepts of the specified concept. There is an option to include/exclude the current concept - super-concepts/all<+>
  • super-concepts/direct - returns all direct super-concepts of the specified concept. Again, there is an option to include/exclude the current concept - super-concepts/direct<+>
  • sub-concepts - returns sub-concepts

For example:

concept<IfStatement> concept = myNode.concept; 
list<concept<>> superConceptsAll = concept.super-concepts/all; 
concept.super-concepts/direct<+>; 
concept.sub-concepts(model);
concept<IfStatement> concept = myNode.concept; 
list<concept<>> superConceptsAll = concept.super-concepts/all; 
concept.super-concepts/direct<+>; 
concept.sub-concepts(model, myScope);

Is Role operation

Sometimes we may want to check whether a node has a particular role. For this we have the following syntax:

For example,

myNode.hasRole(IfStatement : elsifClauses) 

Containing link queries

If one node was added to another one (parent) using the following expression:

then you can call the following operations to access the containment relationship information:

  • containingRole - returns a string representing the child role of the parent node containing this node ("childLinkRole" in above case)
  • containingLink - returns node<LinkDeclaration> representing a link declaration of the parent node containing this node
  • index - returns int value representing index of this node in a list of children with corresponding role. Identical to the following query upon the model represented above:

Reference operations

Accessing references

Following operation were created co access reference instance representing a reference from source node to target one. Operations are applicable on source node:

  • reference< > - returns an instance of reference type representing specified reference. This operation requires "linkQuelifier" parameter used as reference specification. Parameter can be either link declaration of source node's concept or expression returning node<LinkDeclaration> as a result
  • references - returns sequence<reference> representing all references specified in source node.

Working with

Having an instance of reference type you can call following operations on it:

  • linkDeclaration - returns node<LinkDeclaration> representing this reference
  • resolveInfo - returns string resolve info object
  • role - returns reference role - similar to reference.linkDeclaration.role;
  • target - returns node<> representing reference target is it was specified and located in model(s)

Downcast to lower semantic level

SModel language generates code that works with raw MPS classes. These classes are quite low-level for the usual work, but in some exceptional cases we may still need to access them. To access the low-level objects, you should use the downcast to lower semantic level construct. It has the following syntax:

For example,

myNode/.getConcept().findProperty("name")

  • No labels