Creating a simple language using JetBrains MPS
Tags: mps, languageengineering, tutorial, introduction
Published: 2017-12-15 18:21:23

---
title: Creating a simple language using JetBrains MPS
published: true
description: This article will help us with the creation of a mindmap language. We will go over most of the aspects that make up a domain specific language.
tags: MPS, Language engineering, tutorial, introduction
---


Presentation of the project
===========================

The objective of this project is to construct a language to define mindmaps. These mindmaps have multiple levels of topics and also include a potential marker for each topic. The mindmap file will be able to generate a LaTeXfile that will have section and subsections defined according to the mindmap’s topics. The UML diagram we will follow is this one:

<img alt="UML Diagram" src="https://thepracticaldev.s3.amazonaws.com/i/7swic009jrwmghnxs6ua.png" width="80%">
This tutorial is geared toward programmers with some experience using object-oriented languages and more specifically Java-like languages.

The tutorial can be used in conjunction with this [git repository](https://github.com/AntoineGagnon/MindMapMPS) to follow each step with each commit.

Initial setup
=============

Installation
------------

To install the program, the best way to make sure we have the latest stable version is to head on to the official [download page](https://www.jetbrains.com/mps/download) and download the version for our operating system. MPS is available on Windows, Mac and most flavors of Linux.

Creating the project
--------------------

After launching MPS choose the theme and shortcuts we want to use for our editor and click “Create new project”. In this article, we used the default IntelliJ theme and default shortcuts.

As we can see on the left side of the project creation window, we can either create a new language with the **Language project**, create a solution to use a DSL created with MPS with **Solution project** or create an empty project and build everything from scratch.

We will be creating a new language so click on **Language project**, chose a name for our project and a name for our language and make sure we click the **Create Sandbox Solution** check-box to be able to test our language along the way. Our menu should look like this:

<img alt="Project creation menu" src="https://thepracticaldev.s3.amazonaws.com/i/g7474lkdmozsnbwkbhj4.png" width="70%">
Now we simply have to click OK to create our project.


Navigating the logical view
---------------------------

![Logical view](https://thepracticaldev.s3.amazonaws.com/i/0t63nj1jy572rr0izrl5.png)

As we can see the logical view splits the sandbox where the language testing is done and the language module, here simply called **Mindmap** and identified by the L icon before its name. We will mostly focus on the language part, pay attention to the different aspects that are defined like **structure, editor, constraints…etc**.

Language creation
=================

We will now focus on language creation. We will edit the language module, and test the effects on the language using the sandbox provided by MPS.

Sandbox use
-----------

To be able to use the language in the sandbox, we need to make sure we rebuild the language after changes by right-clicking the language module and clicking **Rebuild Language MindMap**. After our first concept is created we will be able to create a new mindmap file by right-clicking on the **sandbox** model inside the **MindMap.sandbox** module and choosing **Newmindmap**.

Structure
---------

The structure of our language is the definition of properties and relations between concepts of our language. We will first start by creating a new concept by right-clicking on the **structure** aspect and selecting **NewConcept** thus creating an empty concept.

We will first create our root concept of a mindmap. As we can see if we open the concept file, the editing process is very different, this is because MPS is a projectional editor that directly edits the abstract syntax tree (AST) of our program. The main difference is that MPS won’t let us write anywhere we want and will guide us to fill the blanks in our file with elements that comply with its syntax.

Let’s change the name of our concept to *Mindmap* by editing the empty field, then change the **instance can be root** property to *true*. Our mindmap concept is now at the top of our abstract syntax tree and we can build elements from there.

Let’s add a name property to our mindmap by implem enting the *INamedConcept* interface, we can also use the <kbd>Ctrl</kbd> + <kbd>Space</kbd> shortcut to autocomplete the name and get a suggestion of different concept we can use. This interface that we can navigate to using <kbd>Ctrl</kbd> + <kbd>B</kbd> has a **name : string** property that will be implemented and also adds some functions and refactoring options to the property.

We can add an alias that will be used by default in the editor to define our concept and also a short description that will be shown in the tooltip when using the auto-completion and in other menus when trying to use the **Mindmap** concept.

Now we need to add topics to our mindmap, we will create a new **Topic** concept that all other types of topics will derive from. Once our concept is created, we give it its name and also use the <kbd>Alt</kbd> + <kbd>Enter</kbd> shortcut in the same field to access the class actions where we click the **Make abstract** option. Let’s also have this Topic implement the **INamedConcept** interface since we also need a name for our topics.

We also planned on being able to add a marker to our topics, so let’s create a new concept called **Marker** that simply implements the **INamedConcept** interface and has an alias and a description.
Now we can come back to our **Topic** concept and add a marker reference. To do so we start by typing the name of the property, here *marker*, then press to get to the next field and add the *Marker* class. We will leave the multiplicity at *\[0..1\]* since our topics can only have zero or one marker. We will also add a *markers* child to the **Mindmap** concept with a *\[0..n\]* multiplicity as we can define
multiple markers that will be referenced by our topics later on.

Now we are able to create topics that aren’t abstract and will be used in the mindmap. By following the UML diagram, we create a new concept called *CentralTopic* that will extends the *Topic* class instead of *BaseConcept*, we give it an alias and a short description.
We can then come back to our mindmap and add a child of the **CentralTopic** class that we will simply call *centralTopic* and that will have a *\[0..1\]* multiplicity.
By following the same pattern as for **CentralTopic** we will create a *MainTopic* concept and add it as a child of **CentralTopic** with a *\[0..n\]* multiplicity, as a central topic can have multiple main topics. We will also do the same with a *SubTopic* concept that is a child with *\[0..n\]* multiplicity of **MainTopic** but with a twist on its children as they are also of the **SubTopic** type and are called *subSubTopics*.

We now have a functional mindmap language that we can test in the sandbox. Although the syntax is rough and sometimes confusing, it lets us create topics at different levels, assign them markers created in the mindmap and give them names. We can also use the node explorer function by pressing <kbd>Alt</kbd> + <kbd>X</kbd> to watch the different elements composing our mindmap.

Behavior
--------

Behavior in MPS are mostly similar to methods and define functions for a concept. They also offer the possibility to modify the constructor, although the constructor function isn’t able to access the model as it is called before the node is linked to the tree.

In our project we will add an **equals** function to our **Marker** concept and a function to analyze the names of the marker in a mindmap and pick the highest one out of the markers using numbers as their names. This will be used to gradually increment the marker’s names when they are created.

To create a new behavior for our **Marker** concept, we go to its editor page and access the **Behavior** tab at the bottom of the editor, then we click **Click to create new aspect** and chose **Concept Behavior**. In the new aspect we just created, we can see we have access to the constructor, but here we will create a new method by clicking on **concept methods** and pressing . Our function will have a *boolean* type and will be called *equals*, it will also take a *node&lt;Marker&gt; otherMarker* as parameters. The body of the function will simply test if the two marker’s names are the same as shown here:

![Marker's behavior](https://thepracticaldev.s3.amazonaws.com/i/9zb1abpm2xmf1r160w6a.png)

We will now do the same behavior creation process for the **Mindmap** concept where we will create a function that will return an *integer* and will be called *getHighestMarkerNumber* but won’t have any parameter as it will analyze the calling node itself.

This method will go through all the children markers and try to parse their name as integers, if the name isn’t a number, the exception is caught and discarded while printing on the error pipe that it wasn’t parsed. If it is indeed a number, we compare the value with our max value variable created at the beginning and update our base value with the new one if it is bigger. We finally return the maximum value at the end of the function juste like this:

![Mindmap behavior](https://thepracticaldev.s3.amazonaws.com/i/9upuryzuql5hju41uf2g.png)

Constraints
-----------

Constraints are rules that define the way our nodes interact with each other and the properties they can have.

In our project, we will implement a constraint that says that two markers defined in the mindmap can’t have the same name. To do so we go in the **Marker** concept and access the **Constraints** tab at the bottom of the editor, we can then click **Click to create new aspect** and choose **Concept Constraints**. We will edit the **can be child** function, this function returns either true or false according to the rules defined inside. We can access the model from this function, and we have access to specific functions to help us in this regard. We will access all the marker’s *siblings* and loop over them with a *for loop* checking if the current node *node* and the sibling node *n* are the same using the **equals** behavior defined earlier and returning the value. The end code should look like this:

![Marker constraints function](https://thepracticaldev.s3.amazonaws.com/i/1xyl9bv9vcmjxydbanpy.png)

If we now try to create two markers with the same name, we will get an error saying these markers can’t be children of the mindmap.

Editor and actions
------------------

The editor is here to define the projection of the AST, it can be textual, visual, include a lot of different layouts and rules on what concrete syntax to use. In our case, we will focus on a simplistic indented textual syntax that is similar to the default one.

Similarly to the previous concepts we’re going to add a **Concept Editor** aspect to our **Mindmap** concept. For the cell layout we are going to use a **collection (indent)** layout that is triggered by the **\[-** keyword, or can be found using the <kbd>Ctrl</kbd> + <kbd>Space</kbd> shortcut. This layout allows us to add new lines for children nodes while increasing indentation.

Inside of our layout we can add the *mindmap* keyword followed by the *{name}* property that can be found using the <kbd>Ctrl</kbd> + <kbd>Space</kbd> shortcut again. We’ll now add the *with* keyword followed by the *%markers%* children and finally we can add the *about* keyword and the child *%centralTopic%* getting this line:

![Mindmap concrete syntax](https://thepracticaldev.s3.amazonaws.com/i/vah1uaym0k9o9k0z76tc.png)

The **CentralTopic** concept editor and the other topics are built in the following fashion while the marker editor isn’t modified. This concept editor will also use the indented layout, starting on the first line with the *{name}* property of the topic, with the *with* keyword and the *%marker%* reference, where the editor is asking us for a cell model, this is the way the markers will be displayed and we will choose to use the *{name}* property. This whole line will be followed by a left bracket before using the <kbd>Alt</kbd> + <kbd>Enter</kbd> shortcut to add a new line, then pressing to get on the new line before reusing the shortcut to add an indent. Now that we are on a new indented line, we can add the *%mainTopics%* children, add a new line again, press and finally add a right bracket and a new line to end our **CentralTopic** concrete syntax. The other topics are built the exact same way, only with different children, for instance, the **SubTopic** concept editor is built just like this:

![SubTopic editor](https://thepracticaldev.s3.amazonaws.com/i/tbcz8yobn0n9i5d000ul.png)

You can also use the <kbd>Alt</kbd> + <kbd>2</kbd> command on part of the editor to modify an elements properties, such as its background color by editing the **no base style** part and adding a *text-background-color* property. We did it on the name element of our **MainTopic** using the *\# B3FFCF* color and also on our **SubTopic** by using a small function that checks if the parent node is also a **SubTopic** or not to get an insight on how deep the topic, this function should end up looking something like this:

![Function to pick a color in the editor](https://thepracticaldev.s3.amazonaws.com/i/yir6jhwmjullajqrpk4g.png)

Another aspect that can be added is actions, they are functions that are used in the editor. They usually take the form of copy/paste functions wrapper, adding new functionalities to them, or simply make sure the copy/paste functions are working correctly since using a projectional editor can sometimes lead to some trouble using it. In our case we will be using the node factory action that regulates how nodes are created, by assigning them properties and such while being able to access the
model, compared to the **Behavior** aspect’s constructor that couldn’t.

We can go ahead and access the **Marker** concept and create a new **Node Factories** action aspect for it. This action will increment the marker’s name using the behavior function we defined in the mindmap, we will set its name to *IncrementMarker*. We will create a new **set-up** and set the *newNode’s name* that is the marker’s name to the string value of the *enclosing* mindmap node’s *getHighestMarkerNumber* function plus one. This will increase the name of the marker everytime we create a new one. The final line of code should look like this:

![Marker incrementation function](https://thepracticaldev.s3.amazonaws.com/i/ke85tud7s8mkzi7s3uau.png)

Now we have a fully functional mindmap editor, with colors, a nice layout, some added features and constraints to the editor. Although it is nice to have a way to create good mindmap file, the end goal is to be able to create a LaTeXfile to write about each topic.

Text generation
===============

Text generation in MPS allows us to use layouts, functions, a complete language to create the perfect text files combined with specific functions dedicated to text generation to append and indent our text. 

For our mindmap, we will focus on a relatively simple text generation in LaTeXand will simply use the append function and some conditions for the subtopics. If you don’t know anything about LaTeX, you can check out [this tutorial](https://www.sharelatex.com/learn/Learn_LaTeX_in_30_minutes) to get started and be able to follow the fields we’ll be using.

To do so, go into the **MindMap** concept and create a new **TextGen** aspect with a **Concept TextGenDeclaration**. All of the fields of our textgen can be filled by pressing to create the function it will use. We will set the file name to *node.name* and the extension to *“tex”*, we won’t change the encoding but feel free to do so if you use a special language that requires it. We don’t need context objects and we will directly edit the **use textgen of ancestor** field to edit it. We will use the append function to create the default lines of our latex document followed by new lines for each tag and we will set the title to be the *node.centralTopic.name* property, the content of our document will simply be an append of our *\${node.topic}*, with the end result looking like this:

![Mindmap base template for text generation](https://thepracticaldev.s3.amazonaws.com/i/mw1420e1302gtj86amog.png)

Now we can go on to our **CentralTopic** concept and create a textgen. Since this concept isn’t a root concept, we have a lot fewer elements we can modify, so we will simply edit the statement and since we’re already using the topic’s title in our mindmap textgen, here we will simply append the children main topics and a new line using *append \$list{node.mainTopics} \\n*.

We can now add a text gen to our **MainTopics** concept and edit the statement to append the text *\\\\section{* followed by the *\${node.name}* and finally the closing bracket *}* and a newline. On the next line, we can append the subTopics list.

Finally we can create a textgen for our **SubTopics** concept and add a condition that checks if the *parent node* is a SubTopic, creates a new *subsection* if it isn’t, and a new *paragraph* if it is. This condition is also followed by an append for the *subSubTopics* children as we can see here:

![Text generation of a SubTopic](https://thepracticaldev.s3.amazonaws.com/i/7a3xreoisba4o2dfoamb.png)

You can now create a mindmap file, edit it, create your new topic and press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>F9</kbd> or right-click and use **Preview generated text** to get access to your structured LaTeXfile !

We now have our fully functional language with a text generation that creates LaTeXfiles according to the elements we created.

What now ?
==========

If you want to get more information on how to create more complex languages, use code generation instead of the simple text generation or simply to get ideas on the capabilities of MPS, you can head on to the [https://www.jetbrains.com/mps/learn/](learn page of MPS).