MPS 2020.3 ヘルプ

軽量 DSL

MPS コア言語を何年にもわたって進化させてきたため、IDE 統合のための言語記述 DSL の繰り返しパターンを認識するようになりました。概念的には、それらは、いくつかの高レベルのインターフェースを実装するプレーンクラスによって表現される高レベルの構造のように見え、動作しました。言語指向プログラミングの良い伝統では、これらのパターンを言語に反映し、プレーンな BaseLanguage クラスの上に薄い抽象化として再実装することにしました。このような抽象化を可能にするために、新しい軽量 DSL 言語が作成されました。

jetbrains.mps.baselanguage.lightweightdsl 言語を使用すると、内部 DSL を BaseLanguage クラスに埋め込むことができます。一般に、内部 DSL は、本格的な外部 DSL よりも開発が簡単で高速であり、通常、ホスト言語の構文を再利用し、周囲の非 DSL コードと緊密に統合されます。同様に、MPS 軽量 DSL は、単一のノードを定義した後 BaseLanguage ClassConcept またはそのサブコンセプトにノードを織ることによって作成することができます。

MPS 自体がいくつかの場所でこのメカニズムを利用しています。

  • 単なる BaseLanguage クラスである MigrationScript の概念は、いくつかの追加のプロパティ、メンバー、カスタムメンバーを追加する MigrationDSLDescriptor によって拡張されます。

  • 使用箇所の検索

  • インテンション

  • カスタム言語の側面

軽量 DSL をプレーンな BaseLanguage クラスに織り込むことも、ClassConcept を拡張する独自の概念に織り込むこともできます。

普通のクラスを拡張する

軽量 DSL 言語の背後にある中心的な考え方は、DSL 設計者が、オプションのメソッドとプロパティ、制約に依存する型、オプションのメソッドパラメーター、カスタムクラスメンバーなどの制約を持つインターフェースを定義できるようにすることです。 DSLDescriptor の 概念は、クラスの実装時に適用する必要がある制約付きインターフェースを体系化するノードを表します。例: 以下の DSLDescriptor インスタンスcalculateFoo() 方法とカスタム BuilderMember ノードだけでなく、クラスに numberOfFrames プロパティを織ります。

コンセプト ClassConcept の dslclassSwingBuilder {
プロパティ numberOfFrames: 整数 ; プレースホルダー <1 フレーム>
メソッド calculateFoo(int value): int; 必須
カスタムメンバー BuilderMember; <修飾子>

初期化子:
{node <ClassConcept> ノード、モデルモデル =>}
}

特定の DSLDescriptor をクラスで有効にするには、インテンションを介して行われる DSLAnnotation でアノテーションを付ける必要があります。

Ldsl1

Ldsl2

アノテーションが追加されるとすぐに、DSLDescriptor で定義されている必要な要素、またはプレースホルダーが指定されている要素がクラスに追加されます。必要な要素を削除すると、クラスにエラーが表示されます。

Ldsl3

インテンションを使用して、必要な要素とプレースホルダーを 1 つのステップで追加し直すことができます。

Ldsl4

標準のメソッドの実装アクション Ctrl+I は、必要なメソッドでも機能します。

DSLDescriptor を定義する

DSLDescriptor がクラスに追加できる要素には次の 4 つのタイプがあります。

  • プロパティ

  • メソッド

  • カスタムメンバー

  • イニシャライザ

これらはそれぞれ必須であり、欠落しているメンバーを表すようにプレースホルダーを定義でき、カスタムメンバー複数としてマークして、この種類の複数のノードがクラスのメンバーになることができることを示すことができます。

Properties

プロパティには名前があり、stringint、または boolean 型にすることができます。プロパティは、weaved クラスの本格的なメンバーになり、このまたは他の DSLDescriptor を介して織り込まれたメンバーを含む他のメンバーからアクセスできます。

メソッド

メソッドは、軽量 DSL のユーザーがコードを挿入できるようにするための非常に便利な方法を提供します。DSLDescriptor は、拡張クラスが実装できる、または実装する必要のあるメソッドのメソッドシグネチャーを指定します。通常のメソッドとは異なり、戻り値の型とこれらのウィーブされたメソッドのパラメーターの型は、ホスト(拡張)クラスでの実際の使用箇所に基づいて決定できます。

依存型

依存型は、メソッドの戻り値の型またはパラメーター型に指定されている場合、特定のクラスのメソッドの実際の型を計算する方法を指定します。

Ldsl5

条件付きメソッドパラメーター

メソッドには、条件付きとしてマークされたいくつかのパラメーターを含めることができるため、指定された条件が満たされた場合にのみユーザーコードに表示されます。パラメーターを条件付きとしてマークするには、対応するインテンションを使用できます。

Ldsl19

実際の条件はインスペクターで指定されています。

Ldsl20

カスタムメンバー

プロパティもメソッドも必要な抽象化レベルを提供しない場合は、カスタムメンバーを使用して、わずかな追加作業で任意の概念を織り込むことができます。

Ldsl6

CustomMemberDescriptor は、新しいメンバーとしてクラスに組み込まれる概念(この場合は BuilderMember)を指します。これを可能にするには、コンセプトは MemberInstance および ClassifierMember コンセプトインターフェースを実装し、オーバーライドする getDeclaration() メソッドから CustomMemberDescriptor を指す必要があります。

Ldsl7

Ldsl8

指定された概念のノード(または CustomMemberDescriptor複数として定義されている場合は複数のノード)をホストクラスのメンバーとしてインスタンス化し、その中で編集できるようになりました。

Ldsl9

イニシャライザー

イニシャライザ関数は、ホストクラスが作成されるか、DSLAnnotation でアノテーションが付けられるとすぐに、プログラムでホストクラスを拡張する機会を得ます。初期化子が呼び出されたときにノード(ホストクラス)自体がモデルに追加されていない可能性があるため、ノードと同様にモデルパラメーターが提供されます。smodel 言語をインポートすると、クラスとモデルを操作できます。通常、初期化子は、必要に応じて、インポートと使用言語を設定するか、織り込まれたメンバーのデフォルト値と実装を提供します。

Ldsl10

カスタム ClassConcept サブコンセプトの強化

ClassConcept クラスの特定のサブ概念がありますが、直接ではない BaseLanguage クラスを強化している場合、一部の仕様がありますが、。これにより、外部 DSL と内部 DSL の利点を組み合わせることができます。目的の DSL でカスタマイズされた編集エクスペリエンス、専用のジェネレーター、または特定の型システムルールが必要になった場合は、通常、プレーンな BaseLanguage クラスを使用する代わりに、ClassConcept サブコンセプトを作成します。ClassConcept のサブコンセプトを作成して作るため、AutoInitDSLClass を実装します。

Ldsl11

概念のノードが作成されるたび、DSL の中に織り込ま適切に DSLDescriptorで定義された初期化子を呼び出すことによって初期化されますことを実装 AutoInitDSLClass を保証します。

Ldsl12

AutoInitDSLClass インターフェースはまた、織りに特定 DSLDescriptor インスタンスを返す必要があり getDescriptor() メソッドをオーバーライドする実装概念を義務付け。

サンプル

Lightweight DSL の基本的な使用箇所を示すサンプルは、MPS ディストリビューションにバンドルされている lightweightDSL サンプルプロジェクトにあります。