ジェネレーターユーザガイド Demo6
Generator ユーザーガイドデモ 6
このデモは、おそらくすべてのデモの中で最もエキサイティングなものです。ここでは、この言語が実際にいくつかの高レベルの概念を定義するという意味で、「実際の」言語を作成するためです。
また、この DSL を既存の言語(「jetbrains.mps.sampleXML」および「generator_demo.demoLang5」(デモ 5 で以前に作成))と簡単に統合できることも確認します。
核となるアイデア
テストモデルに XML 要素を入力するためのより便利な構文を許可します。開発者は、ボタンとラベルに新しい構文を使用します。これにより、よりコンパクトで直感的になります。同時に、デモ 5 で構築した demoLang5 言語で定義されたジェネレーターを再利用できるようになります。新しい demoLang6 言語は、新しい概念を XML 要素 に変換し、demoLang5 ジェネレーターで受け入れることができます。
新しい言語
新しい言語「generator_demo.demoLang6」を作成します
言語プロパティダイアログで拡張言語を追加します:「jetbrains.mps.sampleXML」と「jetbrains.mps.baseLanguage」
この言語用の新しいジェネレーターが存在しない場合は作成します。詳細については、デモ 1 を参照してください。
demoLang6 構造モデルでは、「ElementPart」という概念を拡張する「Button」という名前の新しい概念を作成します (「jetbrains.mps.sampleXML」から)
「ボタン」の概念では、「text」という名前のプロパティを宣言し、エイリアスを設定します(自動補完メニューを美しく表示するにはエイリアスが必要です)。
「ボタン」コンセプトのエディターを作成します。
エディターは 3 つのセルで構成されます。2 つの定数セル(太字で表示)と 1 つのプロパティセル({text
} で表示)で、'text' プロパティの実際の値を表示します。
「ラベル」という名前の同様のコンセプトを作成する
言語を再生成する (Ctrl + F9)
新しいテストモデル
それでは、新しい DSL を試してみましょう。
'test_models' ソリューションに移動します
'test5' モデルを 'test6' に複製します(今回は、engage ongeneration 言語を置き換えないでください
generator_demo.demoLang5 - > generator_demo.demoLang6、まだ TEST6 で実行するように demoLang5 ジェネレーターを必要とするため)
'generator_demo.demoLang6' 言語を使用言語セクションに追加して(new!)、demoLang6 言語を使用してモデルを編集できるようにします。
'test6' モデルで、'Panel' ドキュメントを開き、2 つの 'label' 要素を新しいボタンとラベルの概念に置き換えます。
新しい DSL により、「コード」がより明確になり、短くなり、エラーが発生しにくくなりました。たとえば、ユーザーはラベルやボタン内に要素を追加できなくなりました。
生成プログラム
以前に XML 要素に対して行われたことを模倣したボタンとラベルからメソッドとメソッド呼び出しを生成できます。この方法は、demoLang6 ジェネレーターと demoLang5 ジェネレーター (demoLang6 ジェネレーターが demoLang5 ジェネレーターの実装の詳細について知る必要があります)との間に間接的な依存関係を導入するため、しかし、これは、良いアイデアではありません。
幸いなことに、はるかに優れたオプションがあります。現在(XML と比較して)抽象化のレベルが高いため、意味的に豊富な概念を低レベルの概念(XML 要素)に単純に減らすことができます。これらの低レベル(XML)の概念をさらに低レベルの概念にさらに誰をどのように変換するかについては、もう気にしません。
削減ルール
削減ルールを使用して、新しい概念を XML 要素に変換します。sampleXML 言語から。
demoLang6 ジェネレーターで(空の)マッピング構成 'main' を開きます
ボタンの概念に適用可能な新しい削減ルールを追加します
ルールの結果としてインラインテンプレートを選択します(コントロール + スペース):
テンプレートは非常に単純で、周囲の「コンテキスト」を必要としません。そのため、他のデモで行ったように本格的な外部テンプレートを作成する必要はありません。
生成テンプレートの「jetbrains.mps.sampleXML」の言語から XML 要素を使用したいため、第一主 @ ジェネレーターモデルで使用される言語の中で、その言語を宣言する必要があります。
メインのマッピング構成に戻り、テンプレートのコンテンツノードとして要素を選択します。
「text」属性を持つ「button」XML 要素を作成します
属性値にプロパティマクロを添付します
マクロの value 関数にコードを入力して、text プロパティの値が XML ボタンに伝播されるようにします。
以上です。高レベルのボタンは、「text」属性を持つ「button」XML 要素に縮小されています。XML 要素は、おそらく他の誰かによってさらに Java に変換されるでしょう。
ラベルの概念に適用可能な同様の削減ルールを追加します
最初のテスト (失敗)
ジェネレーターを再構築し、「test6」モデルを生成します。
MPS メッセージビューには、多数のエラーメッセージと警告メッセージが表示されます。
「入力ノードでした」というエラーメッセージをクリックします。MPS は、ジェネレーターが失敗したルールを適用しようとしたノードを表示します。
これは demoLang5 ジェネレーターの縮小ルールであり(demoLang5 と demoLang6 の 2 つのジェネレーターで「test6」モデルを生成しています。覚えていますか? )、マッピングラベルメソッドを介して静的メソッド宣言を見つけることができませんでした。
方法ラベルは insert_Button と insert_Label テンプレート内部で生成された静的メソッドを割り当てられているため、何が悪かったのか不思議に思うかもしれません。DempApp クラス内で作成され、マッピングラベルに格納されているメソッドが見つからなかったのはなぜですか?
その質問に答えるために、生成プロセス全体を詳しく見てみましょう。
最初のステップとして、ジェネレーターは過渡モデルを作成します。これは、現在の生成フェーズの出力モデルとして機能します。このモデル名は「test6 @ 0」です。
次に、ジェネレーターは条件付きルートルールを適用し、出力モデルに「DemoApp」クラスを作成します。
次に、ある時点で、insert_Panel テンプレートが呼び出され、その LOOP -macro が実行されます(insert_Panel テンプレートから、使い慣れたパネル初期化コードを含むパネルファクトリメソッドを確認できます)。LOOP マクロは、「panel」要素の子ごとにステートメント「component.add()」を作成し、子を減らして「component.add()」メソッド呼び出しへの実際の引数を生成します。
'panel' 要素には、ボタン、ラベル、テキストの 3 つの子が含まれています。これらの子は、前処理生成スクリプトによってラベルに変換されています。ボタンと最初のラベルはどちらも demoLang6 によって導入された高レベルの抽象化であり、それらの削減により、対応する XML 要素が生成されます。(最初のスクリーンショットではっきりとわかります。ボタンを表す XML 要素は、'component.add()' メソッドの呼び出しへの実際の引数として渡されます。これは、以前のジェネレーターによって警告として報告されています。黄色のトレース出力)。
これで「test6 @ 1_1」の生成が終了し、ジェネレーターは「test6 @ 1_2」という名前の新しい過渡モデルを作成します。このモデルは新しい出力モデルになり、以前の出力モデルは新しい入力モデルになります。
ジェネレーターは、以前は何もなかったふりをして、新しいモデル「test6 @ 2_2」の生成を開始します。ジェネレーターには以前のアクティビティに関するメモリがありませんが、例外は 1 つだけです。条件付きルートルールが 2 回適用されることはありません。今回は、出力「DemoApp」クラスは、条件付きルートルールを適用するのではなく、入力モデルから「DemoApp」クラスをコピーすることによって作成されます。
この段階で、ジェネレーターはボタンとラベルを表す XML 要素をさらに削減しようとします。使用可能な唯一のルールは、demoLang5 の reduce_Element 削減ルールです。XML 要素を静的ファクトリメソッド宣言への参照に置き換えようとしますが、作成されていないため、メソッドマッピングラベルに何も見つかりません。XML 要素はまだ DempApp 内部 LOOP マクロが実行された時にボタンとラベル demoLang6 概念として表現されたため、メソッドの定義は、単純に作成されていません。
これは demoLang5 と demoLang6 ジェネレーター間のタイミングの問題です。後者を最初に実行する必要があります。
何が起こっているのか理解できたため、次の質問はそれを修正する方法です。
demoLang5 ジェネレーターに依存しており、入力モデルが「有効な XML」である場合、demoLang5 ジェネレーターが適切に機能することがわかっています(デモ 5 でテスト済み)。
デモ 6 では、入力モデルは厳密には「有効な XML」ではありません。さらに、一時モデル「test6@1_1」はまったく有効なモデルではないことがわかりました。メソッド呼び出しは XML 要素を引数として受け入れることができません (MPS メッセージビューで、「子 'Expression' はロール 'actualArgument' に必要ですが、'Element' でした」という警告メッセージも見つかります)。
demoLang5 ジェネレーターに戻り、「無効な」入力モデルを扱えるように「改善」することも可能でしょう。幸い、さらに良い方法があります。生成プロセスを 2 段階に分けて、オリジナルの入力モデルをまず「有効な XML」モデルに変換し、この「有効な XML」モデルを 2 段階目で demoLang5 ジェネレーターによって Java に変換するようにすればいいのです。
生成プロセスをステップに分割する
ボタンとラベル(「パネル」ドキュメント内)を XML 要素に縮小すると、「test6」入力モデルから「有効な XML」モデルを確実に取得できます。この変換は、demoLang5 が XML 要素の Java への変換を開始する前に行う必要があります。換言すれば、demoLang6 ジェネレーターで指定された還元ルールは demoLang5 発生器の任意のルールの前に適用されなければなりません。
この制約を指定しましょう:
generator_demo.demoLang6 にジェネレーターに移動して、ジェネレーターのプロパティを開きダイアログ
demoLang5 ジェネレーターに拡張機能の依存関係を追加します
ジェネレーターの優先順位タブで、目的の優先度ルールを追加します
これは demoLang5 ジェネレーター前 demoLang6 ジェネレーターの実行を保証します。
セカンドテスト
言語を再構築し、「test6」モデル用に生成されたテキストをプレビューします。生成中に問題が発生することはなく、生成されたコードには新しいボタンとラベルが正しく含まれます。
過渡モデルの保存
二つの異なる段階に生成プロセスを分割しているため、私たちの demoLang5 と demoLang6 発生器は、よく一緒に働いています。
最初のステップで、demoLang6 ジェネレーターは高レベルの概念(ボタンとラベル)を対応する XML 要素に縮小し、出力として「有効な XML」モデルを生成します。
2 番目のステップでは、demoLang5 ジェネレーターがその「有効な XML」モデルから Java を生成します。
ステップ 1 とステップ 2 の間に少なくとも 1 つの過渡モデルが存在する必要があります。
>
生成の過程で実際に作成されたモデルを見てみましょう。
プロジェクト設定で、生成時に一時モデルを保存するオプションを有効にします。
「test6」モデルを生成する
プロジェクトツリーで、「一時モデル」という名前のノードを見つけて展開します (このノードは下部にあります)
(驚くべきことに)5 つの一時的なモデルがあります。一時的なモデルを閲覧すると、モデル間に微妙な違いや劇的な違いが見られることがあります。これにより、各ステップでどのような変換が行われたかについての手がかりが得られます。
たとえば、モデル「test @ 1_0」の「パネル」ノードを開きます(このモデルは最初のステップで生成されています)。
高レベルのボタンとラベルの概念が対応する XML に置き換えられていることがわかりますが、テキスト「Helloeverybody!」まだそこにあります。
次のモデルでは、「test6 @ 2_0」というテキスト「Helloeverybody!」 'label' 要素に置き換えられました(demoLang5 ジェネレーターで前処理スクリプト 'fix_text' を実行した結果)。
モデル 'test6 @ 2_1' には、生成された DemoApp クラスが含まれています。
モデル「test6@2_3」には同じクラスが含まれていますが、文字列「MPS!」は「JetBrains MPS!」に置き換えられています (demoLang5 ジェネレーターの後処理スクリプト「refine_text」の結果)。
ルートノードのコピーおよび削減ルール
ご覧のとおり、モデル 'test6 @ 1_0' は、XML 要素に縮小された高レベルのボタンとラベルの概念を除いて、元の入力モデル 'test6' と同じです。
これは望んでいたことですが、「test6 @ 1_0」のルートがどのように作成されたか(ドキュメントを作成する「ルートルール」はありません)、なぜ削減ルールが適用されたのかはまだ明らかではありません。
削減ルールに関する以前の経験から、削減を実行するには COPY_SRC_macro を作成する必要があったことを覚えています。しかし、_demoLang6 ジェネレーターには _COPY_SRC _macros がありませんか?
このようにして、「test6」からの入力ドキュメント(ボタン、ラベル、パネル)がモデル「test6 @ 1_0」にコピーされ、「パネル」ドキュメント 内にあったボタンとラベルの概念に削減が適用されました。
_COPY_SRC _macro に戻る - 削減を「起動」することはありません(それが思われるかもしれません)。代わりに、マップされたノードに同じコピー手順を適用するだけで、縮小ルールが適用されると、変換が発生します。
生成トレーサーツールの使用
一時的なモデルを保存および参照する方法はすでに知っています。実際、生成時に一時モデルを保存するオプションを有効にすると、MPS は一時モデルを保存するだけでなく、変換プロセスに関する大量のデータも収集します。このデータは、生成トレーサーツールを使用して表示できます。
たとえば、トランジェントモデルの「パネル」ドキュメント「test6 @ 1_0」を開き、「ラベル」を選択して、ポップアップメニューで「生成トレースバックの表示」を選択します。
Generation Tracer ビューが開きます。
このツリーのルートには、「ラベル」ノードがあり、トレースバック情報を要求しました(青い矢印は出力ノードを示します)。ツリーの残りの部分は、イベントのシーケンスを逆順で示しています。この出力。
このツリーを見て、そのノードをクリックして(エディターで開くために)、変換プロセスを非常に詳細に再現できます。
たとえば、出力 'label' が reduceLabel ルールのテンプレートによって作成されていることがわかります。
... そして、「パネル」ドキュメント(ルート入力ノード)がコピーされている間に、ラベルの削減ルールが入力ノード「ラベル」に適用されました。
関連ページ:
ジェネレーターユーザガイド Demo5
Generator ユーザーガイドデモ 5:このデモでは、生成スクリプトとユーティリティクラスの使用方法を学習します。生成スクリプトには、pre-processing スクリプトと post-processing スクリプトの 2 種類があります。前処理スクリプトは、ジェネレータールールを適用する前に呼び出され、通常、ルールによるさらなる処理を容易にする方法で入力モデルを変更します。後処理スクリプトは、すべてのジェネレータールールが終了した後に呼び出され、出力モデルに適用されます。さらに、ジェネレーター...
ジェネレーターユーザガイド Demo1
Generator ユーザーガイドのデモ 1:このデモでは、入力 XML ドキュメントごとに java アプリケーションを生成するジェネレーターを作成します。以前に作成したソリューション「test_models」で「generator_demo.test1」モデルを再利用します。このモデルは「jetbrains.mps.sampleXML」言語を使用し、「ボタン」と「ラベル」の 2 つの XML ドキュメントを含みます。出力 java アプリケーションを生成するために、これらの各ドキュメントにル...
ジェネレーターユーザガイド Demo7
ジェネレーターユーザガイドデモ 7:この最後のデモでは、デモ 3 に戻り、目的とする機能を少し異なる方法で実装します。そのため、MPS ジェネレーターの別の領域 - ウィービング規則とルートマッピング規則 - を探ります。ここで構築するデモ 2 では、次のような java ステートメントを生成していました。container.add(new JButton());Swing コンポーネントを作成してアプリケーションのコンテンツペインに追加します。デモ 7 では、デモ 3 と同様に、コンポーネント...