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

Generator User Guide Demo 4

In this demo we will evolve L3 generator (see Demo 3) and add support for panel component. Unlike button or label, panel can contain other components, including other panels, which involves recursion. We will see how reduction can help to solve problems of that kind.

New Language

  • create new language 'generator_demo.L4'
  • 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 L4 generator (we will copy needed parts from L3 generator to L4 generator)
  • copy-paste all nodes from L3 generator to L4 generator

    when pasting nodes - don't forget to exclude L3 generator model from imports

    Icon

    See Demo 2 for details.

    copy-paste all nodes in one step

    Icon

    Doing so you won't be even offered to import generator model from L3 generator.

Weaving Rule for Panel

Supporting of panel component will require another one weaving rule in L4 generator.
As this rule is going to be very similar to, say, 'weave_Label' rule, we will create this new rule by copying and modifying of existing rule:

  • select (in tree) 'weave_Label' rule in L4 generator and invoke Clone Root command in popup-menu
  • in editor - rename new rule: 'weave_Label' -> 'weave_Panel'
  • in template code - replace JLabel with JPanel
  • remove 'setText(...)' statement - panel doesn't support the 'text' property

  • in mapping configuration add weaving rule applicable to a 'panel' element:

  • re-generate generator

First Test

Let's create new test model:

  • go to the 'test_models' solution
  • clone model 'test3' to model 'test4'
  • in the model properties dialog replace 'engaged on generation' language L3 -> L4 (See Demo 2 for details)
  • in model 'test4' add new document 'Panel' with root element - 'panel'
  • to the 'panel' element add attribute: 'background="white"'
  • add a couple of 'label' elements to the 'panel' element:

  • generate files form model 'test4'
  • switch to IntelliJ IDEA and run the generated application:

The generated UI is looking fine except that 'Hello MPS!' labels are not shown on a white background (those labels are children of 'white panel' element in input model, thus we expect them to show up on a white background).

This is because our weaving rules do not make a difference between root and not-root elements. For each element in input model they insert method declaration 'createComponent()' into 'DemoApp' class (which is perfectly okay) and generate corresponding method call inside 'addContent()' method in the 'DemoApp' class.
The latter has turned out not a very good idea because this way we flatten our components hierarchy (all components are added directly to the application's content pane).

Replacing of Weaving with Reduction

Let's delete unhappy template fragment from all our weaving templates (there are: 'weave_Button', 'weave_Label' and 'weave_Panel').

Instead of injecting of 'container.add(..)' statements we are now going to enumerate input elements and generate 'container.add(..)' explicitly, right in the 'DemoApp' template.

  • open the 'DemoApp' template
  • find the 'addContent()' method and add 'container.add(..);' statement into its body
  • wrap the statement (whole statement(warning) ) into a LOOP-macro
  • enter code in mapped nodes function as shown:

The LOOP-macro will generate 'container.add(..);' statement for each document in input model.
Next, we will use COPY_SRC-macro to generate actual parameter in this method call.

COPY_SRC-macro

  • create COPY_SRC-macro wrapping the 'null' expression
  • enter code in its mapped node function as shown:


The mapped node function is returning an XML element - root element of input document.

COPY_SRC-macro

Icon

While processing COPY_SRC-macro, MPS creates a copy of input node (aka mapped node) in output model. The wrapped node in template code is ignored.

Well, now it sounds really weird - are we going to generate java code where XML element is passed as a parameter in method call?
Of course we are not, and the trick is that the 'copying' during a generation is not that simple.

copying trick

Icon

Whenever MPS generator performs copying of an input node to output model, it tries to reduce this node (i.e. find and apply a reduction rule).

Thus, our input xml element can easy become something else after being 'copied' by MPS generator.
And now we will define what that 'something else' is going to be.

Reduction Rule

  • go to mapping configuration in L4 generator and create Reduction Rule which is applicable to Element
  • apply intention to create template for this rule (Alt-Enter):

  • open the 'reduce_Element' template in editor (Ctrl-click on reference)
  • select ClassConcept as the rule content node
  • add a static method to this class (name doesn't matter)
  • create this method's call expression and make it a template fragment (Ctrl-Shift+F):

template fragment

Icon

Make sure that only the method call expression is marked as a template fragment, not whole statement. The rightmost ';' symbol should be outside the template fragment.

  • add reference-macro for method name in method call expression:

In Demo 3 we already used reference-macro to resolve reference to color constant.
In that case it was enough to return name of a color constant from macro's referent function.

Unfortunately, we can't use the same approach here because we don't know exact name of method that we are going to call (method names 'createComponentX()' are generated with making use of create unique name service).

Resolving Reference Using a Mapping Label

To find 'createComponentN()' method generated for given input XML element we will once again use mapping label.

  • in mapping configuration add new mapping label and give it name 'factory_method' (use inspector):

  • in each weaving template (weave_Button/Label/Panel) attach this label to template fragment:

Now we can easily find generated method using this mapping label and input node.

  • return to reference-macro in 'reduce_Element' template
  • enter code in its referent function as shown:

Second Test

Re-generate generator, generate files form model 'test4' and run the 'DemoApp' application.

This time labels "Hello" and "MPS!" are not added to content pane - good.
Our last task in this demo will be to add these labels as children components to our 'white panel'.

Complete Generator

  • open the 'weave_Panel' template in editor
  • add code similar to that we have added to 'DemoApp' template earlier (i.e. 'component.add();' statement wrapped into $LOOP$ and with $COPY-SRC$ in parameter):

The LOOP-macro will enumerate children elements in current input node (which is 'panel' element) and generate 'component.add(..);' statement for each such child element.
COPY_SRC-macro will reduce input node (which is child of 'panel' element in this case).

Third Test

Re-generate generator, generate files from model 'test4' and run the 'DemoApp':

End of Demo 4

  • No labels