Generator User Guide Demo 1
In this demo we will generate a java application for each document in input model.
The input model is going to be the 'generator_demo.test1' model in solution 'test_models' that we have created earlier.
This model uses 'jetbrains.mps.xml' language and contains two xml documents - 'Button' and 'Label'.
We will apply root mapping rule to each of those documents to generate output java class.
In the main method we will create Swing frame and add Swing component to its content pane. The component is going to be either button or label - it depends on name of root element in the input document.
New Language
Create new language 'generator_demo.L1'.

In the language properties dialog add language 'jetbrains.mps.xml' to the extended languages section.

New Generator
Create new generator and name it 'swing' (as we are going to generate Swing UI). Actually, the generator name doesn't really matter. You can give it any other name as well.


MPS will create the generator module belonging to language 'generator_demo.L1'.
MPS will also create generator model 'main@generator' and mapping configuration node 'main'.
Mapping configuration serves as a generator 'entry point' where all generator rules are declared and from where references on templates are made.
The model stereotype 'generator' (shown after symbol '@' in the model name) allows MPS to tell a generator model from a regular model.
Any node in a generator model is interpreted as a template unless that node is part of generator language itself.
For the instance, mapping configuration node is part of the generator language (i.e. the 'MappingConfiguration' concept is declared in language 'jetbrains.mps.lang.generator').
And the class node that we will create on next step is not a part of generator language and will be serving as a template in our generator.
Root Mapping Rule
Let's create our first rule.
Open mapping configuration 'main' in editor and add new rule in the mapping rules section.
Choose 'Document' as the rule's applicable concept.

As we want to generate Class for each input Document, the template for this root mapping rule is going to be a Class (i.e. instance of concept 'ClassConcept' in baseLanguage).
The easiest way to create that template is to apply intention (see yellow bulb?
).
Press Alt-Enter, choose New root template then choose class.
Open the newly created class in editor.

Property-macro
Property-macro is used to compute value of an output node's property at the time of generation.
In this demo it would be nice if we generate classes with same names as were names of input documents.
Thus we will create property-macro for the output class's name.
Put cursor somewhere inside the class name, then press Ctrl-Shift+M and choose property macro in menu. Select the macro node in editor (rendered as '$' symbol), open inspector (Alt-Shift+I) and enter the code as shown:

The place where we have entered code is value function of the property-macro.
The node parameter is an input node (i.e. Document) to which template is applied.
| Type of input node Type of node in this case is 'node<Document>' (to find out type of node select it in code and press Ctrl-Shift+T). MPS knows that because it is explicitly stated in the template's header. |
The main() method
In the main() method we are going to use classes from 'javax.swing' and 'java.awt' package.
Therefore our first step will be importing of correspondent java_stub models into generator model.
While cursor in the 'Document' class (template) in editor press Ctrl-M (import model), then choose 'javax.swing@java_stub' model.

Import 'java.awt@java_stub' model in the same manner.
Create the main() method as shown:

If you stumbled trying to enter 'String[]' - don't panic, you are not alone. Help is here
SWITCH-macro
The last thing to do in this template is to replace 'null' argument in 'container.add(null)' expression with 'new JButton()' expression or 'new JLabel()' expression.
We will generate 'new JButton()' if input document contains root element with name 'button', and 'new JLabel()' otherwise.
We will use SWITCH-macro to do the job.
SWITCH-macro replaces 'wrapped' template node with other node depending on which case-condition is satisfied in the associated template switch.
To begin with let's create new template switch named 'switch_JComponentByElementName'.

The '<T...T>' things on next screenshot are called in-line template. See also note below the screenshot.

That's it. We are testing element's name. If it is 'button' we generate 'new JButton()' and if it is 'label' we generate 'new JLabel()'. If it is neither 'button' nor 'label' we are raising an error.
| In-line template Creation of in-line template like <T new JButton() T> is not a trivial task. |
Now we are ready to attach SWITCH-macro to the 'null' node in our code in main() method.
Select the 'null' and press Ctrl-Shift-M to add abstract node-macro, then choose $SWITCH$ using completion menu (Ctrl-Space).
Go to inspector, enter code in the mapped node query and make reference to the 'switch_JComponentByElementName' created earlier.

What does the mapped node query and why do we need it?
Up to this point our input node was Document.
But template switch 'switch_JComponentByElementName' expects an Element as its input. Therefore we are replacing the input node here.
The expression 'node.rootElement' will return root element of current input document (the 'rootElement' is role of child as it is declared in structure of 'jetbrains.mps.xml' language).
Getting Ready to First Test
It is very important to remember that whatever changes you made in generator models, your last action should always be the same: re-generate generator models.
There is just one model in our generator so hit Shift-F9 (re-generate current model) when you finish editing template.
Generating Test Model
Let's return to model 'test1' in solution 'test_models'.
We have defined a semantic for nodes contained in that model but unfortunately MPS doesn't know about that.
MPS doesn't understand that model 'test1' is now written in two languages (XML+L1).
As we can not really use language L1 in model 'test1', we will explicitly tell MPS to use L1 generator for model 'test1' generation
| note Pure virtual languages like L1 are not common in language development. Normally, language defines set of concepts and semantic for those concepts. If these concepts (their instances) are used in a solution model then MPS engage the language's generator automatically. We will see example of this in Demo 6. |
Open properties of model 'test1' and language 'generator_demo.L1' to the Languages Engaged On Generation section.

Run Generate Files command in the model's popup menu. MPS will generate two java files:
c:\MPS_generator_demo\solutions\test_models\source_gen\generator_demo\test1\Button.java c:\MPS_generator_demo\solutions\test_models\source_gen\generator_demo\test1\Label.java
MPS will also compile these classes but it doesn't provide a way to run generated applications. For this reason, in addition to the MPS project we will create project in IntelliJ IDEA.
Setting Up IntelliJ IDEA Project
Launch IntelliJ IDEA and choose Create New Project on the 'Welcome page'.
In the 'New Project' wizard:
- choose 'Create project from existing sources';
- enter project name: 'generator_demo_idea';
- choose project file location: 'C:\MPS_generator_demo';
- include sources in 'c:\MPS_generator_demo\solutions\test_models\source_gen\' (as the wizard will offer);
- accept offer to create 'Test_models' module;
The new IDEA project will look like on screenshot:

To complete project set-up open setting of 'Test_models' module and set the compile output path = 'c:\MPS_generator_demo\solutions\test_models\classes_gen'

The 'classes_gen' folder is the default output location for compiled classes in MPS.
Now that we have set-up an IntelliJ IDEA project we can easily review generated code and run generated application.
Running generated app in IntelliJ IDEA Project

Add Comment