MPS 2024.1 ヘルプ

ジェネレーターユーザガイド Demo7

ジェネレーターユーザガイドデモ 7

この最後のデモでは、デモ 3 に戻り、目的とする機能を少し異なる方法で実装します。そのため、MPS ジェネレーターの別の領域 - ウィービング規則とルートマッピング規則 - を探ります。

ここで構築するデモ 2 では、次のような java ステートメントを生成していました。

container.add(new JButton());

Swing コンポーネントを作成してアプリケーションのコンテンツペインに追加します。

デモ 7 では、デモ 3 と同様に、コンポーネントプロパティのサポートを追加します。これには、コンストラクターの呼び出しだけでなく、より複雑な初期化コードの生成が必要になります。さらに、生成されるプロパティ初期化コードは、コンポーネントのタイプごとに異なります。そこで、このような要求を処理することができる生成戦略を選択する代わりに - SWITCH マクロを利用することで、製織ルールが使用され、その「噴射」コンポーネントの初期化コードは、の DemoApp クラスにします。

新しい言語

繰り返しますが、新しい言語を設定し、それに Demo 2 ジェネレーターのアーティファクトをいくつかコピーする必要があります。

  • 新しい言語を作成する: 'generator_demo.demoLang7'

  • 言語プロパティダイアログで、'jetbrains.mps.sampleXML' および 'jetbrains.mps.baseLanguage' への依存関係拡張しました。

  • この言語用の新しいジェネレーターが存在しない場合は作成します。詳細については、デモ 1 を参照してください。

  • (空の)マッピング構成 'main' を demoLang7 ジェネレーターから削除します (デモ 2 のように、demoLang7 発生器に demoLang2 発生器からすべての必要な部分をコピーします)

  • コピー & ペースト demoLang7 ジェネレーターに demoLang2 ジェネレーターから「メイン」マッピング設定を

  • demoLang7 発生器に demoLang2 生成機からの「の DemoApp」テンプレートをコピー & ペースト

言語を向上させる

今回は、すべての入力 XML 要素 を入力モデルのスタンドアロンルートとして表すのではなく、XMLDocument と呼ばれる単一のルート概念にラップします。demoLang7 言語は、この新しい概念とそのエディターを紹介します。

gdg14.png

概念は XML 要素のコレクションを保持する場合があり、垂直コレクションとして画面に表示します。

Screen-Shot-2017-07-26-at-1-26-17-AM.png

addContent(container)

  • DemoApp テンプレートを開きます

  • 静的 void メソッド 'addContent(Container)' を追加します。

  • 'main()' メソッドで、次の文を見つけます。

    $LOOP$[container.add($SWITCH$[null]);
  • 上の文を下の文に置き換えます。

    addContent(container);
gdc1.png

新しいテストモデル

ジェネレーターを使う前に、新しい入力テストモデルを作成しましょう。

  • 'test_models' ソリューションに移動します

  • 新しいモデル 'test7' を作成します。

  • 使用言語タブに 'jetbrains.mps.sampleXML' と 'jetbrains.mps.samples.generator_demo.demoLang7' を追加

  • 新しい XMLDocument ルートノードを追加し、コードを入力します。

gdg15.png

それでは、これらの文書のセマンティクスを定義しましょう。

ルートマッピング規則

以前のデモでは、DemoApp クラステンプレートをインスタンス化するために条件付きルートルールを利用していました。デモ 7 では、別のメカニズムであるルートマッピングルールを使用します。'main' マッピング構成で、条件付きルートルールセクションのエントリと放棄ルートセクションのエントリを削除し、代わりにルートマッピングルールを追加します。

gdg16.png

このルールは、XMLDocument を目的の DemoApp クラステンプレートに置き換えます。

製織ルール

ウィービングルールは、出力モデルにノードを追加する手段です。私たちの場合は、利用して、それらのコンテナーに swing コンポーネントを追加するためのコードを挿入します。

  • demoLang7 ジェネレーターに戻り、エディターでマッピング構成「main」を開きます

  • 新しい製織規則を作成する (キャレットがウィービングルールセクションにあるときに、Insert または _Enter _ を押します。)

  • 適用可能なルールを選ぶ - '要素'

  • 以下に示すようにルール条件を入力します。

gdg9.png

織り方

ウィービングルールは、追加の生成されたコードを他の生成されたコードに挿入します。ウィービングコンテキストは、ウィービングルールがコードを挿入する正確な場所です。(インジェクションされたノードはコンテキストノードの子になります)。

この場合、コンポーネントのセットアップコードを DemoApp クラスに挿入します。出力モデルで生成された DemoApp クラスを見つけ、このクラスをウィービングコンテキストとしてウィービングルールに渡す必要があります。

マッピングラベル

マッピングラベルを使用して、出力モデルで生成された 'DemoApp' ノードを見つけます。デモ 3 ですでに説明したように、これらは生成されたノードのレジストリとして機能するため、後でジェネレーターの他の部分で取得することができます。これは独立したジェネレーター部品間の結合を緩めます。

マッピングラベルの宣言

マッピングラベルを使用する前に、マッピング設定で宣言する必要があります。

  • メインのマッピング設定のマッピングラベルセクションに移動します

  • 新しいマッピングラベルを追加する (Insert または Enter を押します)

  • 名前をつける: 'main_class'

  • ClassConcepts をマッピングラベルに格納するため、ラベルの出力コンセプトとして「ClassConcept」を選択します。

gdg18.png

ラベルをルールに付ける

ルールのインスペクターを使用して、マッピングラベル「main_class」をルートマッピングルールに添付します。

gdg17.png

目的の出力ノードを見つけるためのマッピングラベルの使用

それでは、Weaving Rule に戻り、コンテキスト関数に次のコードを入力します。

gdg19.png

これにより、処理された XMLDocument に 対応する DemoApp クラスが正しく解決され、ウィービングルールに渡されるため、新しいメソッドを追加できます。jetbrains.mps.smodel クエリ node.ancestor の使用に注意してください。これは、AST で指定された概念の最も近いノードの祖先を取得します。

外部テンプレート

次に、このウィービングルールのテンプレートを作成します。これは、DempApp クラスに追加するコードを生成するために使用されます。

  • 赤い「結果を選択」セルに「weave_Button」と入力します

  • Alt-Enter を押して、新しいテンプレートを選択します (インテンションを適用)

  • エディターでテンプレートを開く (参照セルで Ctrl- <左クリック> または Ctrl + B を使用します )

テンプレートには、テンプレートのコンテンツノードとしてクラスが設定されている必要があります。これは、main_class マッピングラベルに格納されている要素のタイプであるためです。そうでない場合は、テンプレートのコンテンツノードとして「ClassConcept」を選択します。

  • クラスに名前を付ける

  • 静的メソッド 'createComponent()' を追加

  • テンプレートフラグメントを作成する: メソッド宣言全体を選択し、Ctrl + Shift + F を押します:

gdg6.png

IF マクロ

次の手順は、デモ 3 で行った手順と非常によく似ています。異なる手法を使用して同じコードを効果的に生成するためです。つまり、縮小規則ではなく規則を作成します。

'createComponent()' メソッド内で、JButton コンポーネントを作成して初期化します。

オプションで、入力要素に属性 'text' がある場合、ステートメントを生成します。

component.setText( _text_ )

ここで、text は、inputElement の「text」属性で指定された文字列です。

  • 'createComponent()' メソッドの本体に次のコードを入力してください

  • 'component.setText("text" );' の周囲に IF マクロを作成します。ステートメント (ステートメント全体を選択し、Ctrl-Shift + M を押します )

  • IF マクロの条件関数のコードを入力します。これは 'text' 属性の存在をチェックします

gdg7.png
  • 文字列リテラル "text" の中にプロパティマクロを作成する

  • プロパティマクロの value 関数で、入力要素の「text」属性の値を返すコードを入力します

gdg8.png

ジェネレーターを完成させる

このステップを完了するには、'label' 要素に適用可能な別のウィービングルールを作成する必要があります。

  • 「メイン」マッピング設定エディターを開く

  • 'ボタン' 用に作成したウィービングルールを選択します (ノード全体を選択します。ルール内にカーソルを置き、Ctrl + W を使用して選択を展開します)

  • Ctrl + D (複製)を押して、元のルールのすぐ隣に同じルールを作成します

  • 条件関数内、ステートメント内

    node.name.equals("button");

    「ボタン」を「ラベル」に置き換えます

  • プロジェクトツリーでテンプレートノード 'weave_Button' を選択します。

  • ポップアップメニューのルートの複製コマンドを使用して、このテンプレートノードを複製します

  • エディターで、この新しいテンプレートの名前を「weave_Label」に変更します。

  • テンプレートコード内のステートメントを置き換えます

    JButton component = new JButton();
  • with

    JLabel component = new JLabel();
    gdg12.png
  • メソッド呼び出しが自動的に解決されない場合は、ステートメント内の 'setText' を再自動補完します。

    $IF$[component.setText("$[text]");]
  • 'weave_Label' テンプレートを 'main' マッピング構成の 2 番目のウィービングルールにアタッチします

    gdg11.png
  • ジェネレーターモデルを再生成

最初のテスト (エラー)

言語を再構築し、モデル「test7」からファイルを生成してみてください。生成は問題なく実行されるはずですが、コンパイルはエラーで失敗します:

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

生成されたコード内のエラーを表示するには、エラーメッセージをクリックします。

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; }

問題は、私たちの製織規則は常に同じ名前のメソッド宣言をインジェクションしているということです。'createComponent()'

一意の名前を生成する

生成された各 'createComponent()' メソッドの名前を一意にするために、別のプロパティマクロを作成します。

  • エディターで 'weave_Button' テンプレートを開く

  • 'createComponent()' メソッドの名前にプロパティマクロを追加

  • 示されているようにその関数にコードを入力してください

gdg22.png

templateValue は「createComponent」(つまり、テンプレートに記述されているメソッドの名前)になります。

  • 'weave_Label' テンプレートにも同様の変更を加えます

  • ジェネレーターモデルを再生成

セカンドテスト

'test7' モデルからファイルを生成します - 今度はエラーにはなりません。

'test7' の生成テキストをプレビューします。

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; } }

このコードにはコンパイルの問題はありませんが、'addContent()' メソッドの本体が空のため、まだ機能していません。今作成した作成メソッドは呼び出していません。次のコードを作成して修正しましょう。

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

'addContent()' メソッドの本体に入ります。

2 番目のテンプレートフラグメント

'createComponent()' メソッドのメソッド呼び出しを生成するために、もう 1 つのウィービングルールとテンプレートを追加します。生成されたすべての 'createComponent()' メソッドへの呼び出しは、生成されたメインクラスの 'addContent()' メソッドに織り込む必要があります。製織規則からそれを参照するには、まず 'addContent()' メソッドをマッピングラベルに格納する必要があります。

g7f1.png

LABEL ノードマクロを使用して、生成されたメソッドをマッピングラベルに格納できます。

g7f3.png

次に、メイン マッピング構成のウィービングルールセクションに新しいウィービングルールを追加する必要があります。これにより、個々の「createComponent()」メソッドの呼び出しが「addContent()」メソッドに挿入されます。

g7f4.png

コンテキストマッピングラベルから「addContent()」メソッドを取得し、メソッドの本体を、テンプレートフラグメントが織り込まれているノードとして返すことに注意してください。

weave_ElementInitialization テンプレートは、個々の 'createComponent()' メソッドへの呼び出しをそのコンテキストノード(メソッド本体、つまり StatementList)に挿入します。

g7f5.png

メソッド宣言にパラメーター「コンテナーコンテナ」を追加します(このパラメーターは、「DemoApp」テンプレートの実際の「addContent()」メソッドのパラメーターと同じ名前でなければなりません)。

: マッピングラベルはうまく動作するため、最初にこれらのメソッドを保持し、マッピングラベルにメソッドを挿入するための新しいマッピングラベルを作成する必要がある - 実際の「createComponent()」メソッドはどこから入手する必要があります

g7f6.png

LABEL ノードマクロは、それぞれの織りルール / テンプレートのボタンラベルの両方の createComponentMethods マッピングラベルに「createComponent()」メソッドを格納できます。

g7f2.png

これは weave_Buttonweave_Label の両方に対して行われるべきです。

これで、weave_ElementInitialization テンプレートに戻り、「createComponent()」の呼び出しで参照マクロを指定して、createComponentMethods マッピングラベルから適切な「createComponent()」メソッドを取得できます。

g7f7.png

第 3 テスト

これで、ジェネレーターモデルを 'test_models' ソリューションの 'test7' モデルからファイルを生成させることができます。

gdg21.png

私たちの単純なアプリケーションのための正確で完全なコードを手に入れます。

関連ページ:

ジェネレーターユーザガイド Demo1

Generator ユーザーガイドのデモ 1:このデモでは、入力 XML ドキュメントごとに java アプリケーションを生成するジェネレーターを作成します。以前に作成したソリューション「test_models」で「generator_demo.test1」モデルを再利用します。このモデルは「jetbrains.mps.sampleXML」言語を使用し、「ボタン」と「ラベル」の 2 つの XML ドキュメントを含みます。出力 java アプリケーションを生成するために、これらの各ドキュメントにル...

ジェネレーターユーザガイド Demo2

Generator ユーザーガイドデモ 2:このデモでは、Java Swing アプリケーションを再度生成しますが、前のデモ 1 とは異なり、今回は入力モデルごとに 1 つの Java アプリケーションになります(デモ 1 では、入力 XML ドキュメントごとに個別の Java アプリケーションを生成しました)。デモ 2 が作成する単一の Java アプリケーションには、入力モデルのすべての XML ドキュメントに記載されているすべてのコンポーネントが含まれます。新しい言語:最初に少し技術的な...

ジェネレーターユーザガイド Demo6

Generator ユーザーガイドデモ 6:このデモは、おそらくすべてのデモの中で最もエキサイティングなものです。ここでは、この言語が実際にいくつかの高レベルの概念を定義するという意味で、「実際の」言語を作成するためです。また、この DSL を既存の言語(「jetbrains.mps.sampleXML」および「generator_demo.demoLang5」(デモ 5 で以前に作成))と簡単に統合できることも確認します。核となるアイデア:テストモデルに XML 要素を入力するためのより便利な...

TextGen

TextGen 言語アスペクト:導入 TextGen 言語の側面は、モデルからテキストへの変換を定義します。モデルを直接テキスト形式に変換する必要があるたびに便利です。この言語には、テキストを印刷し、ノードをテキスト値に変換し、出力に適切なレイアウトを与えるための構造が含まれています。操作 append コマンドは変換を実行し、結果のテキストを出力に追加します。found error コマンドを使用して、モデルの問題を報告できます。with indent コマンドは、インデントが増加したブロックの境界を定...