How to Start Programming with MPS
Right-click the HelloWorld language in the project explorer and select Language Properties.
This opens the Language Properties dialog for the HelloWorld language.
In the Generators section, create a new generator by pressing Ctrl-Enter. Give the generator a name, such as 'javaGenerator'. In the 'Target language' field, choose jetbrains.mps.baseLanguage. In the 'Templates model' field, choose 'new template model'. It asks for the template model suffix. Enter ' baseLanguage' and press OK.
The finished dialog should look like this. Press OK.
Expand the new Generator folder to see the Templates Model. The generators in MPS use templates, which are like parameterized code fragments, to transform models from one language to another target language. For example, we will write a template that converts HelloWorld models into Base Language models (which will in turn generate true Java code). The generator uses a 'template mapping configuration' to help it decide which templates should be applied to which concepts. Together, the templates and the template mapping configuration enable the generator to automatically transform one language into another.
The first thing we will do is to create a simple template mapping configuration. Select in under template model node.
Set the name of the new MappingConfiguration to HelloWorldGenerator. Add a mapping rule to the mapping rules list.
MPS currently uses what are called 'query methods' to select which nodes of the model should be transformed. Query methods are currently written in Java, until such a time when they will be able to be written directly in MPS using a query language. Select 'New query method' in the 'for each' field of the mapping rule. Use 'AllHelloWorlds' for the query method ID.
IntelliJ IDEA will be opened, and the new query method will be shown. Initially it is empty. We need to write some Java code to implement the query method. Use IntelliJ IDEA to write the method shown in the screenshot below, or copy and paste the code from here:
ArrayList<SNode> result = new ArrayList<SNode>();
for (SNode node : generator.getSourceModel()) {
if (node instanceof HelloWorld) {
result.add(node);
}
}
return result;
Back in MPS, we need to create a new template to use with the mapping rule. Right-click Templates Model and select Create Root Node > jetbrains.mps.transformation.TLBase > TemplateDeclaration.
You will get something like this:
Now we will use the MPS Base Language, which is a Java-like language, to write the concrete code for each HelloWorld instance in our test model. Each HelloWorld instance will be mapped to a class in the Base Language. In the 'Content node' field, select ClassConcept. Give the new class the name 'HelloWorld'. (Note: Since we only have one instance of the HelloWorld concept, it is safe to hard-code the class name. If we had multiple instances, we would have to use a macro to generate unique class names.)
Give the class a static method with void type and the name 'main'.
We want to turn the entire class into a template. Use Ctrl-Up Arrow to select the whole class, as shown in the screenshot below (Ctrl-Down Arrow shrinks the selection).
Use Ctrl-Shift-F to convert the class into a template fragment.
Inside the 'main' method, we need to add the code which writes our helloText to System.out. Click on the empty statement list. Press Ctrl-Space to see the list of possible statements. Select '.<static field>' from the list. For the class, select 'System'. For the field, select 'out'. With the cursor at the end of the word 'out', press '.' and then Ctrl-Space to select 'instance method invocation'. Select 'println(java.lang.String p0)' from the list of methods. Inside the method's parentheses, select '" string literal'. Inside the quotes of the string literal, type some sample text like 'hello' or 'HelloWorld' (do not use spaces in the sample text). The final result should look like this:
Select the sample text by simply placing the cursor on it, like this:
We will turn this sample text into a macro by pressing Ctrl-Shift-M. This creates a property macro.
Our property macro also needs another query method to render the text of the macro. First, select the property macro cell by clicking on the '$' symbol. In the Inspector panel, add a 'New query method' to the propertyMacro field. Use the name 'HelloText' for the query ID. This creates a method in IntelliJ IDEA.
Back in MPS, we want to wire up our new template to the mapping rule that we had created previously. First, we need to give the template a name. In the TemplateDeclaration, at the top, set the name to 'HelloWorld'. Go back to HelloWorldGenerator and set the template in the mapping rule to the freshly named HelloWorld template.
Give the rule itself a name, such as 'hello'.
Go to IntelliJ IDEA and add code to the HelloText query method to retrieve the helloText from the HelloWorld instance called 'sourceNode'. You can enter it yourself in IntelliJ IDEA, or cut and paste this code:
return ((HelloWorld) sourceNode).getHelloText();
We are almost done! At this point, we have created a generator -- combined with some supporting Java code -- which can take models written in the HelloWorld language and transform them into models written in the Base Language. The Base Language is Java-like, and in fact maps very closely into Java. Once a model is transformed into the Base Language, the generator can automatically convert it into true Java code. Our final step is to configure our project in MPS to actually perform the generation. You might consider this last step analogous to creating a Run/Debug configuration in IntelliJ IDEA, but instead of running code, it generates code written in Java.
Right-click on the Project in the project explorer and select Project Properties.
The Project Properties dialog appears.
Add a new generator configuration to the 'Generator configurations' list. Set the name to something like 'java', and set the output path to somewhere on your file system where you would like any generated files to be saved.
Add a new command to the 'Commands' list. For the source, choose the HelloWorld language, and for the target, choose jetbrains.mps.baseLanguage. Click OK to close the dialog.
Finally, we can generate our Java code. Right-click the test model and select Generate Text From Model > java.
The result should look something like this:
Note: This example doesn't actually generate Java files. To do that, use Generate From Model instead of Generate Text From Model in the last step. The file(s) will be generated in the output folder you chose.
Congratulations! You have just experienced Language Oriented Programming. We created a language definition, which included an editor for the concepts in the language. Then we created a program written in our HelloWorld language. And finally, we created a generator to transform the program into actual Java code. The language definition and editor could be reused to write other programs. The generator could be modified to handle more complex models (such as multiple HelloWorld instances), and you could even write new generators to transform the HelloWorld programs into different forms, such as a Java Swing application.
This is just the beginning of the journey. MPS is undergoing constant development, and could benefit greatly from any feedback you might have. You may want to join the discussion.
