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 of generator rules and usually alter input model in a way that makes it easier for further processing by rules.
Post-processing scripts are invoked after all generator rules are done and are applied to output model.
- create new language 'generator_demo.L5'
- in language properties dialog add extended language : 'jetbrains.mps.sampleXML'
- create new generator for this language (see Demo 1 for details)
- delete (empty) mapping configuration 'main' from L5 generator
- copy-paste all nodes from L4 generator to L5 generator
New Test Model
- in solution 'test_models' clone model 'test4' to model 'test5'
- in model properties dialog replace 'engaged on generation' language L4 -> L5 (see Demo 2 for details)
- in model 'test5' open document 'Panel'
- add a Text node to the 'panel' element:
Our L5 generator doesn't support text nodes, but text node in this context has the same meaning as 'label' element with 'text' attribute.
Therefore, instead of adding more rules to our generator, we will add pre-processing script which will convert text nodes to 'label' elements and let existing rules do rest of the job.
- in model 'main@generator' (in L5 generator) create root node mapping script
- give it name 'fix_text'
- set script kind = pre-process input model
- set modifies model = true.
- enter code which will perform search and replace of all text nodes in model:
- add the 'fix_text' script to mapping configuration 'main' to the pre-processing scripts section:
Re-generate generator, generate files from model 'test5', run the generated 'generator_demo.test5.DemoApp' class.
Utility Classes in Generator
Now suppose we got an idea to fix possible syntax and stylistic errors in generated texts. We can create a post-processing script to do that but those NLP algorithms tend to be quite complex, so we decide to develop them in a separate utility class.
The problem is that an utility class can not be created in generator model 'main@generator' because any root node in any model with stereotype 'generator' is treated as a root template.
The solution is to create another model in generator module:
- select generator node (L5 generator) in tree and choose New->Model in popup menu:
- give the new model name: 'util':
- in model 'util' create class 'TextUtil'
- add static method 'fixText()' to class 'TextUtil':
We are going to call the 'fixText()' method in post-processing script and pass output model as a parameter. The output model contains classes, methods, expressions and so on. Thus we are manipulating with a java-like syntax tree here.
The 'fixText()' method will replace all strings "MPS" with strings "JetBrains MPS".
Now we can use this utility method 'fixText()' in post-processing script:
- in model 'main@generator' (in L5 generator) create new mapping script
- give it name 'refine_text'
- import model 'generator_demo.L5.generator.template.util' to model 'main@generator' (see Demo 1 for details on model importing)
- in mapping script 'refine_text' enter code as shown:
- add the 'refine_text' script to post-processing scripts section in mapping configuration 'main':
You can use Ctrl-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.
Generate model 'test5', run 'DemoApp'.
End of Demo 5