MPS 2019.3 Help

Generator User Guide Demo5

Generator User Guide Demo 5

In this demo we will learn how to use generation scripts and utility classes.

There are two kinds of generation scripts: pre-processing and post-processing scripts.
Pre-processing scripts are invoked before applying the generator rules and they usually alter the input model in a way that makes it easier for further processing by the rules.
Post-processing scripts are invoked after all generator rules have finished and they are applied to the output model.

Additionally, in case of having multiple scripts in a generator you can influence the order, in which the scripts will run.

New Language

We'll start with an exact copy of the demoLang4 language.

  • create new language 'generator_demo.demoLang5'

  • in the language properties dialog add extended languages: 'jetbrains.mps.sampleXML' and 'jetbrains.mps.baseLanguage'

  • create a new generator for this language if it has not been created (see Demo 1 for details)

  • delete the (empty) mapping configuration 'main' from demoLang5 generator

  • copy-paste all nodes from the demoLang4 generator to the demoLang5 generator

New Test Model

  • in the 'test_models' solution clone the model 'test4' into 'test5'

  • in the model properties dialog replace 'engaged on generation' language demoLang4 -> demoLang5 (see Demo 2 for details)

  • in the model 'test5' open the 'Panel' document

  • add a Text node to the 'panel' element:

gde1

Pre-processing Script

Our demoLang5 generator doesn't support text nodes, but text node in this context has the same meaning as a 'label' element with a 'text' attribute set. Therefore, instead of adding more rules to our generator, we will add a pre-processing script, which will convert all text nodes in the input model into 'label' elements and let existing rules do the rest of the job.

  • in the 'main@generator' model if the demoLang5 generator create a root node of type mapping script

  • give it a name 'fix_text'

  • set script kind = pre-process input model

  • set modifies model = true, since we're going to alter the input model inside the script

  • enter the code, which will perform a search and a replace of all text nodes in the input model:

gde2

  • add the 'fix_text' script to mapping configuration 'main' to the pre-processing scripts section:

gde3

First Test

Re-build the language and check out the generated text from the 'test5' model:

gde5

You can see that a label was correctly created for the 'Hello everybody' text and that the label is being added into the panel.

Utility Classes in Generator

Now, let's suppose we got an idea to fix possible syntax and stylistic errors in the generated texts. We'll create a post-processing script to do that. These NLP algorithms tend to be quite complex, so let's develop them in a separate utility class, instead of embedding them into the script directly.

The issue here is that a utility class cannot be created in the generator model 'main@generator' directly, because then it would be treated as a root template, just like any other root node in any 'generator'-stereotyped model would.
We'll have to create another model in the generator module:

  • select the generator node (the demoLang5 generator) in the tree and choose New->Model in the popup menu:

gde6

  • give the new model name: 'util':

newModelUpdated101

  • Make sure you clear our the Stereotype text field

  • in model 'util' create class 'TextUtil'

  • add static method 'fixText()' to class 'TextUtil':

gde8

We are going to call the 'fixText()' method in a post-processing script and pass the output model as a parameter. The output model contains classes, methods, expressions and so on. Thus we are manipulating a java-like syntax tree here.
The 'fixText()' method will replace all strings starting with "MPS" with strings that start with "JetBrains MPS".

Post-processing Script

Now we can use this utility method 'fixText()' in a post-processing script:

  • in model 'main@generator' (in the demoLang5 generator) create a new mapping script

  • give it a name 'refine_text'

  • import the  'generator_demo.demoLang5.generator.util' model to model 'main@generator' (see Demo 1 for details on model importing)

    gde10

  • in the 'refine_text' mapping script enter the code as shown:

gde11

  • add the 'refine_text' script to the post-processing scripts section in the mapping configuration 'main':

gde12

Re-build the generator.
You can use Ctrl/Cmd-F9 (generate all changed models in module). Note that Shift-F9 (generate current model) is not enough any more because now we have two models requiring generation.

Second Test

Generate model 'test5' and preview the generated text:

gde13

Notice the label now holds a "JetBrains MPS" text.

Last modified: 28 February 2020