MPS 2024.1 ヘルプ

ジェネレーターアルゴリズム

ジェネレーターアルゴリズム

入力モデルからターゲットアセットを生成するプロセス(生成セッション)には、5 つのステージが含まれます。

  • 関与する必要があるすべてのジェネレーターの定義

  • 変換の優先順位を定義する

  • 段階的なモデル変換

  • テキストを生成してファイルに保存する (出力モデルの各ルートに対して)

  • 後処理アセット: コンパイルなど

このプロセスの最初の 3 段階について詳しく説明します。

関与するジェネレーターの定義

必要なジェネレーターを定義するために、MPS は入力モデルを調べて、その中で使用される言語を決定します。このジョブ MPS を実行しても、モデルプロパティダイアログで指定された「使用言語」は使用されません。代わりに、MPS はモデル内の各ノードを調べ、実際に使用されている言語を収集します。

各「使用言語」から MPS はジェネレーターモジュールを取得します。言語に複数のジェネレーターモジュールがある場合、MPS は最初のモジュールを選択します(同じ言語の複数のジェネレーターは、現在のバージョンの MPS では完全にサポートされていません)。このリスト内のジェネレーターが他のジェネレーターに依存している場合(「ジェネレーターに依存」プロパティで指定)、それらのジェネレーターもリストに追加されます。

MPS は、ジェネレーターの初期リストを取得した後、ジェネレーターのテンプレートのスキャンを開始して、中間(一時)モデルで使用される言語を決定します。この方法で検出された言語は、元の入力モデルで使用されている言語と同じ方法で処理されます。「使用言語」が検出されなくなるまで、この手順が繰り返されます。

明示的な関与

まれに、MPS は、ジェネレーターがモデル変換に関与している必要がある言語を検出できない場合があります。これは、その言語が入力モデルまたは他の(検出された)言語のテンプレートコードで使用されていない場合に発生する可能性があります。この場合、入力モデルのプロパティダイアログ(詳細設定タブ)の生成に関与する言語セクションを使用して、ジェネレーターの関与を明示的に指定できます。

依存関係のスコープ / 種類 -「生成ターゲット」と「デザイン」。

「Generation Target」は、2 つの言語間の「Extends」関係を置き換えます(L2 は L1 を拡張します)。現在、言語(L2)が別の言語(L1)に翻訳され、L1 にランタイム依存関係がある場合、L1 を L2 の「生成ターゲット」として使用します。このアプローチは「拡張」よりもはるかに優れていますが、言語ではなくジェネレーターの属性であるため、まだ完全ではありません。ジェネレーターが言語から完全に独立したら、このアプローチを修正する必要があります(異なるジェネレーターは異なる言語をターゲットとする場合があるため、ソース言語ではなくジェネレーターにターゲットを指定する必要があります)。

「設計」依存関係は、2 つのジェネレーター間の「拡張」を置き換えます。別のジェネレーターを参照して優先度ルールを指定する必要がある場合に使用します (これらの優先順位が本当に必要かどうかを検討してください。以下のジェネレータープランの変更を参照してください)

優先順位の定義

前に説明したように、ジェネレーターモジュールにはジェネレーターモデルが含まれ、ジェネレーターモデルにはマッピング構成が含まれます。マッピング構成(略してマッピング)は、ジェネレータールールのセットです。多くの場合、一部のマッピングは、他のマッピングの前(または後、または一緒)に適用する必要があります。言語開発者は、ジェネレーターのプロパティダイアログでマッピングの制約を使用して、マッピング間のこのような関係を指定します。

MPS は、関連するジェネレーターのリストを作成した後、指定されたマッピング優先順位に従って、すべてのマッピングをグループに分割します。優先順位が指定されていないすべてのマッピングは、最後の(最も優先順位の低い)グループに分類されます。

最適化された生成計画

生成フェーズを計画するとき、MPS はすべてのジェネレーターを可能な限り孤独に保つことを好みます。最終的に、比較的小さくて高速なプロセス生成ステップが多数表示されます。もちろん、優先ルールと一緒に実行することを強制されたジェネレーターは、同じステップで実行されます。同じ生成ステップ(3.2 より前の MPS)で複数の無関係なジェネレーターを処理すると、同じステップの他のジェネレーターに対するルールの適用可能性を不必要に多くチェックするため、効率が悪いことが判明しました。3.2 以降のインプレース変換では、追加の生成ステップごとのパフォーマンスの低下は無視できます。

無視された優先ルール

優先順位の競合に加えて、生成計画中に無視されるルールがあります。これは、入力モデルに優先順位ルールに参加する言語の概念がない場合に発生する可能性があります。言語の実際の使用はないため、ルールは無視され、「生成プランの表示」アクションは競合するルールとともに報告します。以前の MPS バージョンは、それ以外の場合は未使用の言語のジェネレーターを生成プロセスに含めるために使用されていましたが、現在これらのジェネレーターは移動する機会を得ません

暗黙の優先順位

ターゲット言語(テンプレートによって生成された言語)は、暗黙の「より遅くない」ルールと見なされます。これらの優先順位を手動で指定する必要はありません。MPS は、ソース言語およびターゲット言語のすべてのジェネレーターモデルに「より遅くない」ルールを自動的に挿入します。優先度ルールはモデルの粒度レベルで機能することを理解することが重要です。

モデル変換

マッピングの各グループは、個別の生成ステップで適用されます。生成セッション全体は、マッピングパーティショニング中に形成されたマッピンググループと同数の生成ステップで構成されます。生成ステップには 3 つのフェーズが含まれます。

  • マッピング前スクリプトの実行

  • テンプレートベースのモデル変換

  • マッピング後スクリプトの実行

テンプレートベースのモデル変換フェーズは、1 つ以上のマイクロステップで構成されます。マイクロステップとは、入力モデルから過渡(出力)モデルへのシングルパスモデル変換です。

マイクロステップ MPS の実行中、次の手順に従います。

  1. 条件付きルートルールを適用する (一度だけ -1 番目のマイクロステップ)

  2. ルートマッピングルールを適用する

  3. 明示的なルートマッピングが指定されていない入力ルートをコピーする (これは、ルートマッピングルールの「キープ入力ルート」オプションおよび「ルートを破棄」ルールによってオーバーライドできます。)

  4. 製織ルールを適用する

  5. 遅延マッピングを適用する (MAP_SRC マクロから)

  6. 出力モデルの参照を再検証する (すべての参照マクロはここで実行されます)

リダクションおよびパターンルールを適用するための別個の段階はありません。代わりに、MPS は入力ノードを出力モデルにコピーするたびに、適用可能な削減(またはパターン)ルールを見つけようとします。MPS は、ルートノードのコピー中または COPY_SRC マクロの実行中にノードのコピーを実行します。モデル変換のいずれかの段階で削減が発生する可能性があります。

MPS は、生成ステップ内のすべてのマイクロステップに同じルールセット(マッピンググループ)を使用します。マイクロステップが完了し、実行中にいくつかの変換が行われた後、MPS は次のマイクロステップを開始し、前のマイクロステップの出力モデルを次のマイクロステップへの入力として渡します。最後のマイクロステップの実行中に変換が発生しなかった場合、つまり現在のルールセットに現在の入力モデルのノードに適用できるルールがなくなった場合、生成ステップ全体が完了したと見なされます。

次の世代のステップ(存在する場合)は、前の世代のステップの出力モデルを入力として受け取ります。

生成中のノード属性の処理

ノード属性は汎用の拡張メカニズムを構成するため、ジェネレーターは、テンプレートでの明示的なサポートなしで (属性設計者が属性を保持しないことを選択しない限り) 変換プロセスに沿って属性を保持する必要があります。入力ノードが別のノードに変換されると、Generator は入力ノードのアトリビュートを出力にコピーします。コピーは、新しく導入されたドロップ属性ルールによってのみ制御され、@attribute 情報仕様 (つまり、その属性概念または複数の制限) に関係なく発生します。変換ルールが属性ノード自体を生成した可能性があるという事実は考慮されません (つまり、リダクションルールがノード属性を新しく作成された出力ノードに明示的にコピーする場合、属性の自動コピーにより属性が重複します。ただし、これはまれです。ノード属性をコピーする削減ルール。問題が発生した場合でも、ドロップルールで簡単に軽減できます)。

ノードの属性をコピーしている間、Generator はドロップ属性ルール(MPS 3.3 で新しく導入され、ルート放棄ルールの隣にあります)を調べて、言語設計者が変換プロセスを生き残るためにこれらの属性を必要としないかどうかを確認します。このルールは、ルート放棄ルールと非常によく似ています。ルールがトリガーされると、属性は出力モデルにコピーされません。

属性の採用が増え、複雑さが増すにつれて、ジェネレーターは通常のテンプレート処理ルールを使用して属性コンテンツを変換できるようになりました。

  • 同じモデルのノードへの参照は、出力モデルのそれぞれのノードを指すように更新されます

  • 属性ノードの子を変換するために削減規則が適用されます。

インプレース変換

モデルで使用される言語のジェネレーターは、順次適用されます(別名 Generation Plan)。事実上、各生成ステップは元のモデルのほんの一部を変更し、モデルの残りの部分はそのままコピーされます。巨大なモデルと多数の生成ステップがあるため、このアプローチは非常に効果がないことがわかります。インプレース変換は、よく知られている「デルタ」アプローチでこれに対処しようとします。このアプローチでは、変更のみが収集され、元のモデルに適用されてインプレースで変更されます。

バージョン 3.1 では、インプレース変換はオプションとして残されており、デフォルトで有効になっており、プロジェクト設定 -> ジェネレーターで構成できます。インプレース生成は将来的に唯一の生成モードになる可能性が高いため、クライアントはインプレースモードで失敗するテンプレートを修正することをお勧めします。

インプレース変換を使用すると、以前の MPS バージョンで使用されていた特定の制限が生じたり、パターンを壊すことさえあります。

  • 最も注目に値する重要な点は、ルールのクエリ / 条件が実行された時点では出力モデルがないことです。変換プロセス中に出力モデルを参照するのは悪い習慣であり、インプレース変換では出力モデルが強制的に削除されます。変換ルールから出力モデルにアクセスすると、特定の実行順序が暗示されるため、MPS ジェネレーターが適用できる最適化のセットが実質的に制限されます。完全な入力と、この特定のルールが担当する出力の一部を含む変換ルールの契約は、「完全な入力モデル」と「不確実な状態の出力モデル」よりも厳密です。

  • 出力モデルは実際には、出力ノードを処理することを目的としているため、ウィービングルールのためにあります。

  • デルタ構築のプロセスでは、ジェネレーターがモデルに追加されているノードについて知る必要があります。以前は機能していた出力モデルの暗黙的な変更は、インプレース生成を有効にすると失敗します。例として、ノードを新しいノード postprocess: if (node.someCondition()) node.replace with new(AnotherNode); に置き換える後処理関数を備えた MAP-SRC について考えてみます。Generator は、MAP-SRC によって生成された新しいノードを記録し、追加のスケジュールを設定して、後処理を遅らせます。後処理が終了すると、「出力モデルへの追加」は無効になり、代わりに使用する必要がある別のノードがあるため、ジェネレーターが追跡するノードを特定する方法はありません。もちろん、後処理は MAP-SRC によって生成されたノードにあるものを安全に変更できますが、ノードのサンドボックスから出ようとするとエラーが発生します。

  • アクティブなウィービングルールが存在する場合、入力および出力モデルの両方が必要になるため、インプレース変換が防止されます。

生成トレース

インプレース変換と同様に、更新された生成トレースは、実際の変更のみを追跡するというアイデアに触発されています。変換されたノードのみが追跡されているため、要求がはるかに少なくなりました。また、変換プロセスにさまざまな視点を与えるために、さまざまなプレゼンテーションオプションを利用できます。