Child pages
  • Generator User Guide Demo7

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • create a new language: 'generator_demo.demoLang7'
  • in the language properties dialog add extended dependencies on 'jetbrains.mps.sampleXML' as well as on 'jetbrains.mps.baseLanguage'
  • create a new generator for this language, if it does not exist (see Demo 1 for details)
  • delete the (empty) mapping configuration 'main' from the demoLang7 generator (as in Demo 2, we will copy all needed parts from the demoLang2 generator to the demoLang7 generator)
  • copy-paste the mapping configuration 'main' from the demoLang2 generator to the demoLang7 generator

    Note
    titlewhen pasting nodes - don't forget to exclude the demoLang2 generator model from imports

    See Demo 2 for details.

  • copy-paste the 'DemoApp' template from the demoLang2 generator to the demoLang7 generator

...

This time, instead of having all input XML Elements represented as standalone roots in the input model, we're going to wrap them into a single root concept, called XMLDocument. The demoLang7 language will introduce this new concept as well as its editor:


The concept may hold a collection of XML Elements and it will present them on the screen as a vertical collection.

...

  • open the DemoApp template
  • add a static void method 'addContent(Container)'
  • in the 'main()' method find the statement:

    Code Block
    $LOOP$[container.add($SWITCH$[null]);
  • replace the statement above with statement below:

    Code Block
    addContent(container);

...

We used to utilize conditional root rules for instantiating the DemoApp class template in the previous demos. In Demo 7 we'll use a different mechanism - root mapping rules. In the 'main' mapping configuration delete the entry in the conditional root rules section as well as the one in the abandon roots section and instead add a root mapping rule:

This rule will replace an XMLDocument with our desired DemoApp class template.

...

The template should already have a Class set as the template's content node, because that is the type of elements stored in the main_class mapping label. If not - choose 'ClassConcept' as the template's content node.

  • give the class a name

    Info
    titlenote

    You don't really have to give class a name. This class is not going to be generated.
    This class will serve as a context or a place, into which we can put the newly generated code
    We will mark this 'real code' with the template fragment tags.

...

  • open the 'main' mapping configuration in editor
  • select the weaving rule, which we have just created for 'button' (select the whole node: put cursor inside the rule, use Ctrl+W to expand selection)
  • press Ctrl+D (duplicate) to create an identical rule right next to the original one
  • in the condition function, in the statement

    Code Block
    node.name.equals("button");

    replace "button" with "label"

  • in the project tree select the template node 'weave_Button'
  • duplicate this template node using the Clone Root command in the popup menu
  • in the editor rename this new template to 'weave_Label'
  • in the template code replace the statement

    Code Block
    JButton component = new JButton();

    with

    Code Block
    JLabel component = new JLabel();
  • re-auto-complete 'setText' in the statement if the method call is not resolved automatically

    Code Block
    $IF$[component.setText("$[text]");]
  • attach the 'weave_Label' template to the second weaving rule in the 'main' mapping configuration
  • re-generate generator model

...

Try to rebuild the language and generate files from model 'test7'.
Generation should run with no problems but compilation will fail with an error:

Code Block

generator_demo\test7\DemoApp.java : Duplicate method createComponent() in type DemoApp (line: 37)

Click on the error message to view the error in generated code:

Code Block

public static Component createComponent() {  // <-- error
    JButton component = new JButton();
    component.setText("Hello");
    return component;
  }

public static Component createComponent() {  // <-- error
    JLabel component = new JLabel();
    component.setText("world!");
    return component;
  }

...

Preview the generated text for 'test7':

Code Block

public class DemoApp {

public static void main(String[] args) {
  JFrame frame = new JFrame("Demo");
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  Container container = frame.getContentPane();
  container.setLayout(new FlowLayout());
  addContent(container);
  frame.pack();
  frame.setLocationRelativeTo(null);
  frame.setVisible(true);
}

public static void addContent(Container container) {
}

public static Component createComponent0() {
  JButton component = new JButton();
  component.setText("Hello");
  return component;
}

public static Component createComponent1() {
  JLabel component = new JLabel();
  component.setText("world!");
  return component;
}
}

The code has no compilation problems, but it is still not working, because the body of the 'addContent()' method is empty. We're not calling the creational methods that we've just weaved in. Let's fix that by weaving the following code:

Code Block

container.add( createComponent0() );
container.add( createComponent1() );

...

  • open the 'weave_Button' template and add a second static method
  • name the method: 'addContent'

    Info
    titlenote

    The name of this method is not important but we will name it 'addContent' for clarity.
    This method is not going to be generated - it will be serving as context for a template fragment inside of it.

  • add a parameter 'Container container' to the method declaration ((warning) This parameter must have the same name as parameter in the 'addContent()' method in the 'DemoApp' template)
  • in the method body enter the code:

    Code Block
    container.add(createComponent());
  • tag this statement as a template fragment (select whole statement(warning) , press Ctrl-Shift+F):

...