Child pages
  • Generator User Guide Demo1
Skip to end of metadata
Go to start of metadata

Generator User Guide Demo 1

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.

New Language

  • choose New Language in project's popup menu
  • enter language name: 'generator_demo.L1'
  • add language 'jetbrains.mps.sampleXML' to the extended languages section in the language properties dialog

New Generator

  • choose New Generator in the language 'generator_demo.L1' popup menu
  • enter generator name: 'swing'

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.

Root Mapping Rule

Let's create our first rule which will generate Java application class for each input XML Document.

  • open mapping configuration 'main' in editor
  • add new rule in the mapping rules section (press Insert while cursor is in this section)
  • choose the rule's applicable concept: '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 (lightbulb) on the left edge of the editor?):

  • press Alt-Enter while cursor is in the red field '<no template>'
  • choose New Root Template
  • choose class.
  • open the newly created class in editor (use Ctrl+left-click or Ctrl+B on the reference)

Property-macro

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:

  • put cursor somewhere inside the class name in editor
  • press Ctrl-Shift+M and choose property macro in menu
  • select macro node in editor (rendered as '$' symbol) and open its inspector (Alt-Shift+I)
  • enter code into the value function as shown:

This value function will return name of input node (Document).

Type of input node

Icon

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.

The main() method

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.

  • press Ctrl-M (import model)
  • choose 'javax.awt@java_stub' model
  • press Ctrl-M again
  • choose 'javax.swing@java_stub' model

Create the main() method as shown:

(info) 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 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'.

(tick) To start entering a condition code press Insert
(info) 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

Icon

Creation of in-line template like <T new JButton() T> is not a trivial task.
If you stumbled trying to do that consider the following diagram.

Now we are ready to attach SWITCH-macro to the 'null' argument node in the in the 'container.add(null)' expression.

  • return to 'main()' method in the 'Document' template
  • select the 'null' node in the 'container.add(null)' expression
  • press Ctrl-Shift-M to add abstract node-macro
  • press Ctrl+Space to invoke completion menu and choose $SWITCH$
  • go to inspector of the $SWITCH$ macro
  • enter code (see below) in the mapped node function (press Insert to start entering)
  • make reference to the 'switch_JComponentByElementName' template switch node created earlier.

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.

note

Icon

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'.

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 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'.

note

Icon

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.

  • open properties of model 'test1'
  • add 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:

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 File -> New Project....
In the 'New Project' wizard:

  • choose 'Create Java project from existing sources'
  • enter project name: 'generator_demo_idea'
  • choose project file location: 'C:\MPS_generator_demo'
  • on the 2nd page of the wizard - make sure that source root 'c:\MPS_generator_demo\solutions\test_models\source_gen\' is checked (it is recommended to un-check language root 'L1\source_gen' - we don't need it for the purpose of this demo)
  • skip the 3d page
  • on the 4th page - accept the suggested module structure of the project ('Test_models' module)

The new IDEA project will look like on screenshot:

  • open settings of the 'Test_models' module
  • set the Compiler output : Output path : 'c:\MPS_generator_demo\solutions\test_models\classes_gen'
  • clear the Compiler output : Test output path

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

Choose Run in popup menu of either of generated classes:

End of Demo 1

  • No labels