In this demo we will generate java application for each input XML Document.
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.sampleXML' language and contains two XML Documents - 'Button' and 'Label'.
We will apply root mapping rule to each of those documents to generate output java application.
In the application's main method we will create a swing frame and add swing component to its content pane. The component is going to be either JButton or JLabel - it depends on the name of root element in input document.
MPS will create new generator module inside the 'generator_demo.L1' language.
MPS will also create the generator model 'main@generator' and mapping configuration node 'main'.
Mapping configurations are serving as a generator's 'entry points' 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 generator model is interpreted as a template unless that node is a part of generator language itself.
For the instance, a mapping configuration node is a part of the generator language (the 'MappingConfiguration' concept is declared in language 'jetbrains.mps.lang.generator').
And the class node, which we will create on next step, is not a part of generator language and will be serving as a template in our generator.
Let's create our first rule which will generate Java application class for each input XML Document.
As we want to generate Class for each input Document, the template for this rule is going to be Class - instance of concept 'ClassConcept' in baseLanguage.
The easiest way to create that template is to apply intention (see the on the left edge of the editor?):
Property-macro is used to compute value of property of an output node at the time of generation.
In this demo we want to generate output class with the same name as was name of the input document.
Thus we will create a property-macro for the output class's name:
This value function will return name of input node (Document).
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 type of input node because this template's header explicitly specifies Document as the template input.
In the main() method we are going to use classes from 'java.awt' and 'javax.swing' packages.
Therefore our first step will be importing of correspondent java_stub models into the generator model.
Create the main() method as shown:
If you stumbled trying to enter 'String' - don't panic, you are not alone. Help is here
The last thing to do in this template is to replace 'null' argument in the 'container.add(null)' expression with expression creating a swing component.
We will generate 'new JButton()' expression if root element in the input document has name 'button', and 'new JLabel()' if the root element has name 'label'.
To perform this replacement we will 'wrap' the 'null' argument into a SWITCH-macro.
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'.
To start entering a condition code press Insert
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.
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' argument node in the in the 'container.add(null)' expression.
What does the mapped node function do and why do we need it?
Up to this point our input node has been a Document.
But the template switch 'switch_JComponentByElementName' expects an Element as its input.
Thus we have to replace the input node - Document, with new input node - Element.
The expression 'node.rootElement' returns root element of current input document which becomes the new input node.
The 'rootElement' is role of child. You can navigate to the child link declaration by pressing Ctrl+left-click or Ctrl+B on the 'rootElement'.
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.
Let's return to model 'test1' in solution 'test_models'.
We have defined semantics for XML nodes in that model. Unfortunately, MPS knows nothing about that.
MPS doesn't understand that model 'test1' is now written in two languages - XML + L1 because we cannot really use language L1 in model 'test1' (language L1 defines no concepts of its own).
Therefore we will explicitly tell MPS to use L1 generator for generation of the model 'test1'.
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 an example of this in Demo 6.
Run Generate Files command in the model's popup menu. MPS will generate two java files:
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.
Launch IntelliJ IDEA and choose File -> New Project....
In the 'New Project' wizard:
The new IDEA project will look like on screenshot:
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.
Choose Run in popup menu of either of generated classes:
End of Demo 1