ジェネレータークックブック
この文書は、MPS ジェネレーターに関する最も一般的な質問に対する回答を提供することを目的としています。代わりにジェネレーターのドキュメントを調べてジェネレーターデモをチェックすることもできます。
ジェネレーターはどのようにルールを処理しますか?
生成は、入力モデルを徐々に出力モデルに変換します。出力モデルは、TextGen を使用してテキストに変換する場合としない場合があります。生成プロセス自体はステップで構成されています。各ステップには 3 つのフェーズがあります。
マッピング前スクリプトの実行
テンプレートベースのモデル変換
マッピング後スクリプトの実行
テンプレートベースのモデル変換フェーズは、1 つ以上のマイクロステップで構成されています。マイクロステップは、入力モデルを過渡(出力)モデルにシングルパスモデル変換することです。生成ステップ中のジェネレーターは、モデルを反復処理し、このステップに含まれるすべての言語のジェネレーターで入力モデル内のノードに適用可能な規則を検索します。該当する規則が見つからない場合は、生成ステップは停止します。次の世代ステップ(もしあれば)は、その入力として前の世代ステップの出力モデルを受け取ります。
ジェネレーターのドキュメントでジェネレーターのアルゴリズムの完全な説明をチェックすることができます。
一つの言語に対してさらに多くのジェネレーターを使うことができますか?
いいえ、MPS は現時点では言語ごとに 1 つのジェネレーターしか許可しません。1 つの言語に対して複数のジェネレーターが必要な場合は、自分の言語を拡張する空の言語を作成し、それぞれの拡張言語で目的の代替ジェネレーターを定義することをお勧めします。
ジェネレーターごとに複数のマッピング設定を持つことができますか?
はい、生成プロセス中はすべて同じものとして扱われます。さらに、各マッピング構成で 生成プロセスの優先順位を個別に指定できるため、生成をより柔軟に調整できます。
単一のソースから複数のターゲットを生成する方法
同じコードベースから複数のターゲットプラットフォーム用のコードを生成することができます。それを達成するには、少なくとも 2 つの方法があります。
異なるプラットフォームのすべての生成ルールを単一のジェネレーターに配置し、おそらく仮想パッケージと複数のマッピング構成に論理的に分離し、各ルールの条件を使用して、現在選択されているターゲットに基づいてルールをアクティブ化します。開発者は、コードにフラグを設定して、目的のターゲットプラットフォームを示します
言語に直接ジェネレーターを持たず、それぞれのターゲットプラットフォームのジェネレーターを別々の空の言語で提供することで、元の言語を拡張します。開発者は適切な拡張言語をインポートすることによって目的のターゲットプラットフォームを選択します。
テンプレートにはどのようなマクロがありますか?
プロパティマクロ - プロパティの値を計算します
参照マクロ - 参照のターゲット(ノード)を計算します
ノードマクロ - 生成時にテンプレートの塗りつぶしを制御するために使用されます。
$IF$ - 条件付き生成
$CALL$ - 現在位置に別のテンプレートを挿入し、それを現在のノードに渡して処理します
$LOOP$ - ノードのコレクションを反復処理し、反復ごとに現在のノードを設定します
$COPY_SRC$ - 指定されたノードをコピーしてラップされたノードを置き換えます。処理中に、コピーされたノードとその子に削減規則が適用されます。
$COPY_SRCL$ - 指定されたノードのコレクションをコピーし、折り返したコードを置き換えます。処理中に、コピーされたノードとその子に削減規則が適用されます。
$MAP_SRC$ - 折り返しコード内で現在のノードとして使用されるノードを設定します
$MAP_SRCL$ - 折り返しコード内の現在のノードとして順番に使用されるノードのコレクションを設定します
$SWITCH$ - 複数の選択肢から生成に使用するテンプレートを選択します
$LABEL$- ラップされたノードをマッピングラベルに格納して、他のマクロで簡単に検出できるようにします
$VAR$- 値を変数に設定します。変数は、ラップされたノードで genContext.varName を介してアクセスできます。
$TRACE$- ラップされたノードの元のノードをトレースバックするために必要な情報を格納し、ソースノードと結果の生成されたテキスト間のマッピングを trace.info ファイルに格納します。一時モデルの保存がオンの場合、これによりデバッグの起点ノードを表示オプションが有効になります。一時モデルのポップアップメニュー項目
$WEAVE$ - 特定の製織規則を呼び出す
$INSERT$ - 現在位置にノードを出力モデルに挿入します
ユーティリティクラスはどこに配置すればよいですか ?
ジェネレーター内に新しいモデルを作成します。ジェネレーターステレオタイプがアタッチされていないことを確認してください。モデルは通常、BaseLanguage に依存して、クラスを作成できるようにする必要があります。その後、元のジェネレーターモデルはユーティリティモデルをインポートする必要があります。
ランタイムクラスはどこに配置すればよいですか ?
依存関係を正しくする「プロジェクトへの外部 Java クラスと jar の追加 - ランタイムソリューション」セクションに従って、生成コードが依存するクラスとライブラリは、別々のランタイムソリューションに入れる必要があります。
一意の名前を生成する方法
genContext パラメーターを使用します。これにより、ジェネレーターコンテキストオブジェクトにアクセスして、以下を呼び出すことができます。
からの固有の名前 <base name> 文脈で <node>
ベース名 - 生成された名前の一部である必要がある任意の文字列です
コンテキストノード - 指定されている場合、MPS は、スコープ(通常はルートノード)に「含まれている」名前を生成するために最善を尽くします。次に、名前が再計算されるとき(入力モデルまたはジェネレーターモデルの変更のため)、これはスコープ外の他の名前には影響しません。コンテキストノードパラメーターはオプションですが、生成の安定性を保証するために指定することをお勧めします。
生成された名前の一意性は、生成セッション全体を通じて保護されます。
このサービスを使用して生成されなかった名前との衝突は引き続き発生する可能性があります。
列挙データ型を生成する方法
列挙型データ型を Java 列挙型に縮小する必要がある場合、通常は $SWITCH$ マクロを使用するのが最良のオプションです。

is() メソッドを使用して実際の列挙データ型が等しいかどうかをテストする方法に注意してください。

生成された Java クラスのパッケージを変更する方法
複雑な Java コードを生成する場合、Java クラス、インターフェース、列挙型をパッケージに編成する必要があることがよくあります。デフォルトでは、MPS ジェネレーターは、生成された Java コードのパッケージの構造に MPS モデルの構造を反映します。各 BaseLanguage モデルは、同じ名前の Java パッケージに変換されます。生成された Java パッケージの構造を操作する必要がある場合は、Classifier
コンセプトの packageName プロパティを使用してください。このプロパティは、ルート分類子で使用できます。

ルートマッピング規則と縮小規則の違いは何ですか?
生成中に、ツリーの形式を持つモデル (抽象構文ツリー、基本的な考え方を参照) は、同じくツリーである生成モデルに変換されます。通常、ルートノードはルートノード (例: Java クラスへのロボットスクリプト ) に生成され、非ルートノードは非ルートノード (例: Java BlockStatement へのロボット Step コマンド) に生成されます。ルートマッピングルールのテンプレートは、生成されたモデルの開始点を表し、コンテキストを保持し、テンプレートフラグメントマークで実際の生成内容を示すリダクションテンプレートとは異なり、テンプレートコンテキストを指定できません。
未変換の根はどうなりますか?
適用可能な変換規則がないルートは、そのまま次の生成ステップに持ち越されます。
単一のノードに対して複数のノードを生成する方法
テンプレート内のテンプレートフラグメントは、どのノードが現在の入力ノードを置き換えるかを示します。テンプレートフラグメントはテンプレート内の 1 つのノードにしかアタッチできませんが、ジェネレーターテンプレートには複数のテンプレートフラグメントを含めることができます。ただし、すべてのフラグメントが同じ親で同じロールのノードにアタッチされている場合です。このようにして、単一の入力ノードに対して複数のノードを生成することができます。

マクロの編集がなぜ奇妙なのでしょうか。
実際、ジェネレーターマクロとテンプレートフラグメントマークは、最初は少し編集するのが面倒です。しかし、それらがどのように機能するかの基本原則を理解すれば、効率的に使用することができます。
マクロはノード / プロパティ / 参照属性として実装されています(構造の章の属性セクションを参照)。そのため、それらは任意の言語で使用することができ、その言語で使用可能になるための事前サポートを必要としません。MPS では任意の言語を生成対象として使用できるため、これは重要です。マクロはそれらがラップするノードに付加された属性です。マクロで囲まれたノードを削除または置換すると、そのマクロも削除されるため、新しいノードにアタッチするにはマクロを再入力する必要があります。推奨される方法は、最初にテンプレートのコードを入力してからマクロを追加することです。マクロで囲まれたノードを変更する必要がある場合は、新しいノードのマクロにコピーペーストすることによって、少なくとも古いノードのマクロのインスペクターウィンドウの内容を保存できます。
非ルートノードに対してルートノードを生成するにはどうすればよいですか?
単に概念のためのルートマッピング規則を作成し、おそらくそれをさらに条件で制限します。この規則は、ルートノードを生成するため、ルートと呼ばれます。ルートとして入力されるとは限りません。
あるいは、ブール述語の評価に基づいてルートノードを挿入する条件付きルート規則、または入力モデルをインスペクションして必要に応じてルートノードを作成する前処理スクリプトを使用することもできます。
不要になった根をモデルから削除する方法
ルートノードは、ルートマッピングルールを使用して変換されると自動的に削除されます。直接変換されていないルートの場合は、次の生成ステップに伝播されないようにするために放棄ルート規則を使用します。
アクセサーリモデルのノードに対してノードを生成する方法
アクセサーリモデル内のノードは、ジェネレーターによってはまったく処理されません。アクセサーリモデル内のノードに基づいてノードを生成するために、条件付きルート規則または前処理スクリプトを利用できます。

次いで、削減規則を使用して、「挿入されたノード」を所望のゴール言語にさらに生成することができます。
マッピングラベルの使い方
マッピングラベルは、マッピング構成(例: main)で定義されます。次に、保存するノードを $LOOP$、$LABEL$、$COPY_SRC$ などのマクロでラップしてデータを入力する必要があります。
生成中に参照を処理する方法
生成された参照に適切なターゲットノードを設定するには、参照マクロを使用する必要があります。通常、参照マクロはマッピング ラベルと一緒に使用します。
ここでの基本的な作業は、ノード N を指す参照 R に対して、R から生成された参照 G(R) が、N から生成されたノード G(N) を指すようにする必要があることです。
R-> N の場合、N は G(N) に生成され、R は G(R) に生成され 、G(R)-> G(N)
マッピングラベルは辞書として機能し、ノードはキーとして、またそれらが値として生成されたものは何でも格納します。この例では N-> G(N) です。ノードとその生成されたノード間のマッピングをマッピングラベルに格納するようにジェネレーターに明示的に指示する必要があります。テンプレートフラグメントとノードマクロによって、ユーザーは生成されたノードを保存するマッピングラベルを指定できます。
G(R) に R を低減する場合、G(R) に参照マクロは、ラベルおよび入力によって genContext.get 出力に発生コンテキストを呼び出すキーとして N を使用してマッピングラベルから G(N) を取り出すことができます。
ジェネレーターチュートリアルの第 7 章では、ラベルのマッピングについて詳しく説明しています。
生成プロセスをデバッグできますか?
最初のオプションは、一時モデルの保存を有効にすることです。MPS が生成中に作成する中間モデルは保持され、画面の左側にあるプロジェクトビューパネルからアクセスできます。


保存されたトランジェントモデルを使用すると、生成プロセスのさまざまな段階でモデルがどのように見えるかを調べることができます。
2 番目の選択肢はジェネレータートレーサツールを使うことです。このツールでは、Save transient models オプションも on に設定する必要があります。ジェネレータートレーサツールを使用すると、選択したノードの生成プロセスを詳細に調査することができます。元のモデルまたは一時的なノードのいずれかでノードを選択すると、コンテキストメニューに生成プロセスを前方または後方にトレースするためのオプションが表示されます。その結果、生成中に特定のノードが通過したすべてのステージとその生成に影響を与えるルールにアクセスできるツリー状のレポートが得られます。


さらに、$TRACE$ ジェネレーターマクロには、トレース用にテンプレートの一部をマークするオプションがあり、コンテキストメニューの起点ノードを表示オプションを使用して、一時モデルで生成されたノードから元のノードに戻ることができます。> 言語デバッグメニュー:


実際の生成手順はどのようにしてわかりますか?
ジェネレーターのコンテキストメニューからジェネレーションプランの表示アクションを使用します。これにより、計画されているすべての生成フェーズを示し、各フェーズで実行されるマッピング構成を一覧表示する詳細なレポートが提供されます。


ジェネレーターを実行する順序を指定できますか?
ジェネレーターのモジュールプロパティダイアログのジェネレーターの優先順位タブでは、2 つの異なるマッピング構成間の順序付けルールを指定できます。

より複雑なシナリオでは、生成計画の新機能によりジェネレータープロセスを完全に制御できます。
ジェネレーターを起動する前にモデルにエラーがないことを確認する方法
モデル / 言語 / ソリューションでモデル(言語 / ソリューション)のコンテキストメニューアクションを実行して、チェックします。

環境設定 -> ビルド、実行、デプロイ -> ジェネレーター -> 生成前にモデルのエラーをチェック構成フラグは、ジェネレーターがトリガーされるたびにモデルチェッカーを自動的に実行するかどうかを指定します。
既存のジェネレーターを拡張する方法
従うべき 1 つの規則があります - あなたの拡張ジェネレーターが拡張されたものの前に実行されることを確認する - ジェネレーター順序優先順位ダイアログでより高い優先順位を与えてください。
拡張可能なジェネレーターを構築する方法
ジェネレーターを拡張することで、拡張機能は元の言語の意味を変更することができます。MPS ジェネレーターは設計によって拡張可能です - それはすべての関係言語からすべてのジェネレータールールとマッピング設定を解決して、グローバルな世代計画を構築します。プロジェクトにアタッチされている言語には、その規則が含まれます。プランは、マッピング構成で表現された相互の相対的優先順位に基づいてジェネレータールールの実行順序を指定します。これにより、言語拡張機能は、最適な生成フェーズに独自の目的の生成規則を挿入することができます。優先順位はマッピング構成間の相対的な順序付けの集まりとして表現されるため、言語拡張は機能するために生成に関与する他のすべての生成子について知る必要はありません。潜在的な(そしてまれな)衝突が検出され、解決するために開発者に任されます。いったん作成されると、生成計画は、相互に独立した規則のために潜在的に基礎となるハードウェアの並列処理を利用する可能性があるジェネレーターを繰り返し呼び出すために使用されます。
追加の削減規則を提供することは、言語を拡張するための 1 つの方法です。ジェネレータースイッチの使用は別の選択肢です。親言語がジェネレータースイッチを使用して正しいリダクションルールを選択する場合、言語拡張はリダクションルールを選択するための追加ロジックでそのジェネレータースイッチを拡張します - 通常は拡張言語によって提供された新しいルールを含みます。
TextGen を何に使用すればよいですか ?
ジェネレーターがモデル間の変換を実行している間、TextGen はテキストへのマッピングを行います。これは通常、生成の最後のステップであり、ジェネレーターによって完全に管理されています。根はジェネレーターによって選択され、ファイルに変換されます。TextGen は言語設計者に意図的にほとんど柔軟性を提供していません。それはジェネレーターで、生成プロセスは主に構成され処理されるべきです。TextGen の制限を回避する必要があると感じる場合は、おそらく間違ったやり方で試してください。ジェネレーターは最も柔軟性がある場所です。
生成された出力を別の場所にコピーするにはどうすればよいですか?
jetbrains.mps.lang.makeup 言語の CopyOutcome 属性を使用して、ノード用に最終的に生成されたテキストが指定された場所にコピーされるようにすることができます。
ルートノードごとに複数のファイルを生成する方法
TextGen はルートノードごとに 1 つのファイルしか許可しません。また、コンセプトごとに 1 つの TextGen コンポーネントしか持てません。代わりに、柔軟性をジェネレーターにエンコードする必要があります。ジェネレーターがノードの複数のコピーを作成することを手に入れます。多分異なる概念の新しいノードに包みます。これらの新しいノードは、希望するモデルからファイルへの変換を実行するように TextDef を定義しています。
関連ページ:

生成プログラム
導入:ジェネレーターは、言語の概念の表示的意味論を定義する言語仕様の一部です。MPS はモデル間変換アプローチに従います。MPS ジェネレーターは、入力言語でエンコードされた構成から出力言語でエンコードされた構成への変換を指定します。モデル間変換のプロセスには多くの中間モデルが含まれ、最終的には sn 出力モデルが生成されます。このモデルでは、すべての構成はすでに意味が別の場所で定義されている言語になります。たとえば、baseLanguage のほとんどの概念 (クラス、メソッドなど) は「機械が...

ジェネレーターデモ
ジェネレーターチュートリアル:MPS で言語ジェネレーターを定義および拡張するプロセスをガイドする、更新されたジェネレーターチュートリアルへようこそ。チュートリアルは 7 つのパートで構成されており、徐々に複雑さが増しています。すべてのデモは、同じ基本的なストーリー、つまり Java Swing コンポーネントへの XML コードの変換を共有しています。各デモは前のデモに基づいており、より高度な(または場合によっては単に異なる)機能、プラクティス、アプローチを示しています。すべてのデモは論理的に...

依存関係を正しくする
目的:モジュールとモデルは通常、さまざまな型の依存関係のネットワークによって相互接続されています。MPS プロジェクト構造のページに従って、モジュールとモデルの基本的な原則と分類を理解していると仮定すると、私達は今やすべての詳細を学ぶようにさらに深く掘り下げることができます。MPS で依存関係を正しく取得することは、経験の浅いユーザーやベテランのベテランの間でもフラストレーションの頻繁な原因です。このページは、問題を一度に解決することを目的としています。さまざまなモジュールと依存関係の種類によ...

基本的な考え方
この章では、基本的な MPS の概念であるノード、概念、言語について説明します。これらは、MPS の仕組みを正しく理解するための鍵となります。これらはすべて、他の要素と組み合わせることで初めて意味を成すため、すべて一緒に説明する必要があります。このセクションの目的は、各要素の本質を説明することです。詳細については、ノード、概念 (構造言語)、言語 (プロジェクト構造) に関するセクションを確認することを検討してください。抽象構文木 (AST):MPS は、テキスト形式を避けることによって他の多く...

構造
MPS を使用すると、目的の言語の文法を定義する必要がなくなるため、言語の構造を指定するためのさまざまな方法が明らかに必要になります。ここで構造言語が役に立ちます。それはあなたに言語構造を定義するためのすべての手段を与えます。前に説明したように、MPS でコーディングする場合、AST を直接効果的に構築しているため、言語の構造では、AST の構築に使用する要素であるブリックを指定する必要があります。プロパティ、参照、および子供: レンガをコンセプトと構造言語が公開の概念と概念インターフェースだけ...

ジェネレーターユーザガイド Demo7
ジェネレーターユーザガイドデモ 7:この最後のデモでは、デモ 3 に戻り、目的とする機能を少し異なる方法で実装します。そのため、MPS ジェネレーターの別の領域 - ウィービング規則とルートマッピング規則 - を探ります。ここで構築するデモ 2 では、次のような java ステートメントを生成していました。container.add(new JButton());Swing コンポーネントを作成してアプリケーションのコンテンツペインに追加します。デモ 7 では、デモ 3 と同様に、コンポーネント...