The objectives of this step are the following:
- Use a DSL workbench to create a language (MPS 2017.2)
- Uses a template-based code generation approach (TextGen)
The LED example, using MPS
Creating a new project
We start by creating a new project for a language named ArduinoML, associated with a sandbox solution (to write programs in ArduinoML) and a runtime solution (for test purposes).
Creating the concepts
Each concept of the ArduinoML abstract syntax tree is modelled as a concept in MPS.
- The
App,ActuatorandStateconcepts implement theINamedConceptinterface as one can use theirnameto reference it; - The
Appconcept is considered as aroot, as it is the entry point of the language; - The
SIGNALconcept is an Enumeration, containing theHIGHandLOWvalue. One can change the way the value is displayed using the presentation field; - Modelling concepts in MPS:
- Properties are used to model simple attributes (here the
SIGNALto send to a given actuator) - Children are used to modelling elements that are contained by the concept. An element can only be contained by a single container;
- References are used to link an element to another one.
- Properties are used to model simple attributes (here the

Right-click on the project name and select Make to synchronize the language with the other solutions (and do this operation each time the tool underlines your models stating that “generation is required”).
Creating Models
Using these concepts, one can create a program in ArduinoML. Right-click on the sandbox project and create a new App (proposed as it is defined as a root concept). In MPS, the syntax is made by projecting the AST, and a default project does exist in the tool.
It is important to notice that you are not editing text, but directly the AST, using a fill in the blanks (the red parts) approach. The LED example is modelled by filling these holes (we added an isInitial property in the State concept between the two screenshots).
Modifying the projections
The default project has the advantage of existing for free but is not really user-friendly. To create our own projects, we define Editors associated with the concepts.
MPS provides a DSL to model editors. The DSL relies on the definition of collections (horizontal or vertical) to assemble the attributes associated with a given concept in the proper way. This is a tabular approach (which is arguable in terms of design choices and defined syntax) where you need to think of your projection as imbricated boxes.
One must notice that automatic completion is mandatory (using CRTL-space) to find the right symbol while defining the projection.
[/…/]: vertical collection, all elements between these elements will be displayed in a vertical way;[>…<]: horizontal collection;[-…-]: horizontal collection supporting indentation, using--->to specify the indentation level;{x}: refers to the propertyxdefined in the current concept;(/ %x%…/): a vertical collection of children nodes defined inx.empty: an empty line
As we are defining a set of projections, building the language automatically update the LED model we defined previously.
Specifying Constraints
Constraints are specified as logical expressions evaluated on concept instances. For example, to specify an invariant stating that a pin associated with an actuator must be in [1,13], we associated a logical check on the Actuator concept.
A more interesting constraint is the unique property associated with the state names. To implement it, we add a constraint that looks inside the state parent node and checks for other states with the very same name
Constraints are hard properties. One can define more soft guidelines. For example, a single initial state should be defined in the FSM. This is done thanks to a checking rule in the type system definition.
Controlling Scope
Concept instances are linked together at the global level, as it is the default scope in MPS. As a consequence, if one creates a second App named led2 in the sandbox solution, it is possible to refer to actuators or states defined in led2 inside the led application.
MPS provides scoping mechanisms to support this task. To state that the State concept must not use the default global scope but a homemade one, we add a constraint to the State stating that when looking to fill the next reference with a State, it must inherit it from something defined in its containment hierarchy.
We use the App concept as our scope provider (it must then implements the ScopeProvider interface in addition to the INamedConcept one). We create a behaviour associated with the App concept and override (use the CTRL-O shortcut to open a list of overridable methods) the getScope method. The implementation is straightforward: if asking for a State, we return all the states defined in the App. We do something similar for the actuators and return null when asked for something else.
Generating Code
MPS supports a template-based generation mechanism named TextGen. It also supports language composition mechanisms, which are more expressive but also more complex. In this lab, we will rely on the simple TextGen.
For each concept, we define a TextGenComponent describing how the concept must be projected into plain text. For example, the actuator concept is projected by declaring an integer variable named like the actuator and containing the PIN number. We use the append keyword to add text to the generation buffer.
A root concept will also define the generated filename and extension. When appending a model element, TextGen will recursively call the associated template. The system can automatically iterate on a collection of objects, using the $list keyword.
Expected Work
- Adapt the language to support sensors and transitions associated with sensors;
- Identify the abstractions needed in the language to support the 7-segment display;
- Adapt the language to support it.
Feedback Questions
- What is the cost/benefits ratio of using a workbench?
- What are the limitations of such an approach?
- What about vendor lock-in?











