MPS 2020.1 ヘルプ

ジェネレータークックブック

この文書は、MPS ジェネレーターに関する最も一般的な質問に対する回答を提供することを目的としています。代わりにジェネレーターのドキュメントを調べてジェネレーターデモをチェックすることもできます。

ジェネレーターはどのようにルールを処理しますか?

生成は、入力モデルを徐々に出力モデルに変換します。出力モデルは、TextGen を使用してテキストに変換する場合としない場合があります。生成プロセス自体はステップで構成されています。各ステップには 3 つのフェーズがあります。

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

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

  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 はスコープ(通常はルートノード)に「含まれる」名前を生成するように最善を尽くします。(入力モデルやジェネレーターモデルの変更により)名前が再計算されても、範囲外の他の名前には影響しません。context node パラメーターはオプションですが、生成の安定性を保証するために指定することをお勧めします。

生成された名前の一意性は、生成セッション全体を通して保証されます。
このサービスを使用して生成されなかった名前と衝突することはまだ可能です。

列挙データ型を生成する方法

$SWITCH$ マクロを使用して列挙型データ型を Java 列挙型に縮小する必要があるのが通常最善の選択肢です。

Generator2

is() メソッドを使用して、実際の列挙データ型の等価性がテストされる方法に注目してください。

Generator3

生成された Java クラスのパッケージを変更する方法

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

cp iface

ルートマッピング規則と縮小規則の違いは何ですか?

生成モデルの間に、木の形をしています(抽象構文木、基本的な考え方を見てください)、生成されたモデルはまた木です。通常、ルートノードはルートノードに生成され(たとえば、ロボットスクリプトから Java クラスに)、非ルートノードは非ルートノードに生成されます(たとえば、ロボットステップコマンドから Java BlockStatement へ)。ルートマッピング規則のテンプレートは生成されたモデルの開始点を表し、コンテキストを保持して実際の生成内容をテンプレートフラグメントマークで示すことができる縮小テンプレートとは異なり、テンプレートコンテキストを指定することはできません。

未変換の根はどうなりますか?

適用可能な変換規則がないルートは、そのまま次の生成ステップに持ち越されます。

単一のノードに対して複数のノードを生成する方法

テンプレート内のテンプレートフラグメントは、どのノードが現在の入力ノードを置き換えるかを示します。テンプレートフラグメントはテンプレート内の 1 つのノードにしかアタッチできませんが、ジェネレーターテンプレートには複数のテンプレートフラグメントを含めることができます。ただし、すべてのフラグメントが同じ親で同じロールのノードにアタッチされている場合です。このようにして、単一の入力ノードに対して複数のノードを生成することができます。

templateFragments

マクロの編集がなぜ奇妙なのでしょうか。

実際、ジェネレーターマクロとテンプレートフラグメントマークは、最初は少し編集するのが面倒です。しかし、それらがどのように機能するかの基本原則を理解すれば、効率的に使用することができます。

マクロはノード / プロパティ / 参照属性として実装されています(構造の章の属性セクションを参照)。そのため、それらは任意の言語で使用することができ、その言語で使用可能になるための事前サポートを必要としません。MPS では任意の言語を生成対象として使用できるため、これは重要です。マクロはそれらがラップするノードに付加された属性です。マクロで囲まれたノードを削除または置換すると、そのマクロも削除されるため、新しいノードにアタッチするにはマクロを再入力する必要があります。推奨される方法は、最初にテンプレートのコードを入力してからマクロを追加することです。マクロで囲まれたノードを変更する必要がある場合は、新しいノードのマクロにコピーペーストすることによって、少なくとも古いノードのマクロのインスペクターウィンドウの内容を保存できます。

非ルートノードに対してルートノードを生成するにはどうすればよいですか?

単に概念のためのルートマッピング規則を作成し、おそらくそれをさらに条件で制限します。この規則は、ルートノードを生成するため、ルートと呼ばれます。ルートとして入力されるとは限りません。

あるいは、ブール述語の評価に基づいてルートノードを挿入する条件付きルート規則、または入力モデルをインスペクションして必要に応じてルートノードを作成する前処理スクリプトを使用することもできます。

不要になった根をモデルから削除する方法

ルートノードは、ルートマッピングルールを使用して変換されると自動的に削除されます。直接変換されていないルートの場合は、次の生成ステップに伝播されないようにするために放棄ルート規則を使用します。

アクセサーリモデルのノードに対してノードを生成する方法

アクセサーリモデル内のノードは、ジェネレーターによってはまったく処理されません。アクセサーリモデル内のノードに基づいてノードを生成するために、条件付きルート規則または前処理スクリプトを利用できます。

accessoryGeneration

次いで、削減規則を使用して、「挿入されたノード」を所望のゴール言語にさらに生成することができます。

マッピングラベルの使い方

マッピングラベルは、マッピング設定(例: 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)です。ノードとその生成されたノード間のマッピングをマッピングラベルに格納するようにジェネレーターに明示的に指示する必要があります。テンプレートフラグメントとノードマクロによって、ユーザーは生成されたノードを保存するマッピングラベルを指定できます。

RG(R) に縮小するとき、G(R) の参照マクロは、ラベルおよび入力による genContext.get の出力でジェネレーターコンテキストを呼び出すときに N をキーとして使用して、マッピングラベルから G(N) を取得できます。

ジェネレーターチュートリアル第 7 章では、ラベルのマッピングについて詳しく説明しています。

生成プロセスをデバッグできますか?

最初のオプションは、過渡モデルの保存を有効にすることです。MPS が生成中に作成する中間モデルは保存され、あなたのスクリーンの左側のプロジェクトビューパネルでそれらにアクセスすることができます:

transient1
transient2

保存されたトランジェントモデルを使用すると、生成プロセスのさまざまな段階でモデルがどのように見えるかを調べることができます。

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

tracer1

transient2

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

Trace2

Trace1

実際の生成手順はどのようにしてわかりますか?

ジェネレーターのコンテキストメニューから世代計画を表示するアクションを使用します。これにより、計画されているすべての生成フェーズと、各フェーズで実行されたマッピング構成のリストが詳細に表示されます。

genplan1

genplan2

ジェネレーターを実行する順序を指定できますか?

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

Priorities2

より複雑なシナリオでは、生成計画の新機能によりジェネレータープロセスを完全に制御できます。

ジェネレーターを起動する前にモデルにエラーがないことを確認する方法

モデル / 言語 / ソリューションでモデルをチェック (言語 / ソリューション) コンテキストメニューアクションを実行して確認します。

Generator101

設定 -> ビルド、実行、デプロイ -> ジェネレーター -> 生成前にモデルのエラーをチェック構成フラグは、ジェネレーターが起動されるたびにモデルチェッカーを自動的に実行するかどうかを指定します。

既存のジェネレーターを拡張する方法

従うべき 1 つの規則があります - あなたの拡張ジェネレーターが拡張されたものの前に実行されることを確認する - ジェネレーター順序優先順位ダイアログでより高い優先順位を与えてください。

拡張可能なジェネレーターを構築する方法

ジェネレーターを拡張することで、拡張機能は元の言語の意味を変更することができます。MPS ジェネレーターは設計によって拡張可能です - それはすべての関係言語からすべてのジェネレータールールとマッピング設定を解決して、グローバルな世代計画を構築します。プロジェクトにアタッチされている言語には、その規則が含まれます。プランは、マッピング構成で表現された相互の相対的優先順位に基づいてジェネレータールールの実行順序を指定します。これにより、言語拡張機能は、最適な生成フェーズに独自の目的の生成規則を挿入することができます。優先順位はマッピング構成間の相対的な順序付けの集まりとして表現されるため、言語拡張は機能するために生成に関与する他のすべての生成子について知る必要はありません。潜在的な(そしてまれな)衝突が検出され、解決するために開発者に任されます。いったん作成されると、生成計画は、相互に独立した規則のために潜在的に基礎となるハードウェアの並列処理を利用する可能性があるジェネレーターを繰り返し呼び出すために使用されます。

追加の削減規則を提供することは、言語を拡張するための 1 つの方法です。ジェネレータースイッチの使用は別の選択肢です。親言語がジェネレータースイッチを使用して正しいリダクションルールを選択する場合、言語拡張はリダクションルールを選択するための追加ロジックでそのジェネレータースイッチを拡張します - 通常は拡張言語によって提供された新しいルールを含みます。

TextGen は何に使用しますか?

ジェネレーターがモデル間の変換を実行している間、TextGen はテキストへのマッピングを行います。これは通常、生成の最後のステップであり、ジェネレーターによって完全に管理されています。根はジェネレーターによって選択され、ファイルに変換されます。TextGen は言語設計者に意図的にほとんど柔軟性を提供していません。それはジェネレーターで、生成プロセスは主に構成され処理されるべきです。TextGen の制限を回避する必要があると感じる場合は、おそらく間違ったやり方で試してください。ジェネレーターは最も柔軟性がある場所です。

生成された出力を別の場所にコピーするにはどうすればよいですか?

jetbrains.mps.lang.makeup 言語の CopyOutcome 属性を使用して、ノードに対して最終的に生成されたテキストが指定された場所に確実にコピーされるようにすることができます。

ルートノードごとに複数のファイルを生成する方法

TextGen はルートノードごとに 1 つのファイルしか許可しません。また、コンセプトごとに 1 つの TextGen コンポーネントしか持てません。代わりに、柔軟性をジェネレーターにエンコードする必要があります。ジェネレーターがノードの複数のコピーを作成することを手に入れます。多分異なる概念の新しいノードに包みます。これらの新しいノードは、希望するモデルからファイルへの変換を実行するように TextDef を定義しています。

関連ページ:

生成プログラム

MPS ジェネレーターに関する素早い使い方ドキュメントはジェネレータークックブックをチェックしてください。導入、概要、ジェネレーターモジュール、新しいジェネレーターを作成する、ジェネレーターのプロパティ、ジェネレーター、変換、マッピング設定、ジェネレータールール、マクロ、外部テンプレート、テンプレー...

ジェネレーターデモ

ジェネレーターチュートリアル :更新された Generator Tutorial へようこそ。MPS で言語生成プログラムを定義および拡張する手順を案内します。チュートリアルは 7 つの部分から成り、徐々に複雑さが増しています。すべてのデモは同じ基本的な物語 -Java Swing コンポーネントへ...

依存関係を正しくする

目的、便利なキーボードショートカット、ソリューション、ソリューションモデル、プロジェクトへの外部 Java クラスと jar の追加 - ランタイムソリューション、言語、言語モデル / 側面、生成プログラム、目的 :モジュールとモデルは通常、さまざまな型の依存関係のネットワークによって相互接続されて...

基本的な考え方

この章では、MPS の基本的な概念(ノード、概念、および言語)について説明します。これらは MPS がどのように機能するかを正しく理解するための鍵です。それらはすべて他のものと組み合わされたときに意味をなさないため、それらについてすべて一緒に話さなければなりません。このセクションでは、各要素の本質に...

構造

MPS はあなたの意図した言語のための文法を定義することからあなたを解放するため、明らかにあなたの言語の構造を指定するための異なる方法を必要とします。これは構造言語が便利になるところです。それはあなたに言語構造を定義するためのすべての手段を与えます。前に説明したように、MPS でコーディングするとき...

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

ジェネレーターユーザガイドデモ 7:この最後のデモでは、デモ 3 に戻り、目的とする機能を少し異なる方法で実装します。そのため、MPS ジェネレーターの別の領域 - ウィービング規則とルートマッピング規則 - を探ります。ここで構築するデモ 2 では、次のような java ステートメントを生成してい...