MPS 2020.1 ヘルプ

カスタム言語アスペクトクックブック

構造エディター型システムなどの通常の言語アスペクトと並んで、言語制作者はカスタム言語アスペクト(たとえば、インタープリター、代替型システムなど)を作成し、言語ランタイムに生成してから実行することができます。コードからこれらの生成されたアスペクトを使用してください。

カスタムアスペクトとは何ですか?

MPS の言語定義は、構造、エディター、型システム、ジェネレータといったアスペクトの集まりと考えることができます。各アスペクトは、対応するアスペクトサブシステムによって使用される宣言で構成されています。例:型システムアスペクトは型システム規則からなり、型システムエンジンによって使用されます。

言語の各側面は、個別のアスペクトモデルで定義されています。例:言語 L のエディターの側面は L.editor モデルで定義されています。

各側面は、アスペクトの主な言語のセットを使用して説明されています。例 : エディターの側面を記述するための j.m.lang.editor 言語があります。

アスペクトモデル内の宣言は、何らかの概念に結び付けられていてもいなくてもかまいません(概念のエディターが概念に結び付けられているように、ジェネレータアスペクトのマッピング構成は結び付けられていません)。

アスペクトは、実行時、つまり言語が使用されるときにこのアスペクトを表す言語のアスペクトランタイムに生成できます。

バージョン 3.3 以降、MPS では言語の作者はその言語の新しい側面を定義することができます。

カスタムアスペクトの開発サイクル

  1. アスペクトを記述するための言語を作成します。既存の言語を再利用するか、アスペクトのニーズに合わせて言語を作成できます。例:MPS の中核的な側面はそれぞれ独自の言語セットと、BaseLanguagesmodel などのいくつかの一般的な言語を使用しています。

  2. この言語(そしておそらく他の言語)が他の言語の何らかの側面を記述していることを宣言する - アスペクト記述子を作成する

  3. 作成した言語でジェネレータを開発してアスペクトの実行時クラスを生成する (必要な場合)

  4. アスペクトのランタイムを使用するアスペクトサブシステムを開発する

各ステップを詳細に説明します。

サンプルプロジェクトを見回す

customAspect サンプルプロジェクトを開くと、5 つのモジュールがあります。

Screen Shot 2015 09 10 at 04 27 51

ドキュメント言語とそのランタイムソリューションは他の言語のための新しいドキュメントアスペクトを定義するために使われます。sampleLanguage この新しいアスペクトを利用します - それはその概念を文書化するためにそれを使います。サンドボックスソリューションは、sampleLanguage のドキュメント機能を表示するための使い方を示しています。アスペクトサブシステムは pluginSolution によって表されます。これは、現在注目しているノードの概念に関するドキュメントを表示するアクションを定義します。

言語ランタイム

先に進む前に、実行時に言語の側面がどのように機能するのかを考えてみましょう。

  • MPS の各言語に対して、言語記述子が生成されます(クラスは Language.java と呼ばれます)。

  • アスペクトインターフェースを指定すると、言語記述子はこの言語でこのアスペクトの具体的な実装を返します(AspectDescriptor と呼びましょう)。

  • AspectDescriptor は任意のメソッドを持つ任意のクラスにすることができます。唯一の制限はそれがマーカーインターフェース ILanguageAspect を実装するべきであるということです。AspectDescriptor がこの側面によって記述された実体のために getter 以外のコードを全く含まないことを提案します。

これは典型的な言語ランタイムがどのように見えるかです:

Screen Shot 2015 09 10 at 00 33 07

createAspect() メソッドは、アスペクトで宣言されたインターフェースの 1 つを期待するパラメーターの型をチェックし、対応する新しくインスタンス化された実装を返します。

これは、アスペクトで定義されたインターフェースがどのように見えるかです(この例はインテンションアスペクトで定義されています)。

Screen Shot 2015 09 10 at 00 30 32

言語の側面を使う

それでは、アスペクトのいくつかを使いたいとしましょう。たとえば、エディターで作業中に、現在選択されているノードに適用できるインテンションのリストを取得したいのです。

  1. 最初に、インポートされた言語に対応するすべての言語ランタイムを見つけます。

  2. それから、それらそれぞれのインテンション記述子を取得します。

  3. そして最後にディスクリプタからすべてのインテンションを取得し、それらが現在のノードに適用可能かどうかをチェックします。

全体的なスキームは : 言語 - > LanguageRuntimes-> 必要なアスペクト - > このアスペクトから欲しいものを入手

そのため、呼び出し側がそれを把握できるようにするために、カスタムアスペクトをこの検出メカニズムにフックする必要があります。

カスタムアスペクトの実装

customAspect サンプルプロジェクトを使用してカスタムアスペクトを実装するために必要な手順を詳しく見てみましょう。

  1. MPS が何らかの特別なモデルをドキュメントアスペクト(つまり、私たちの新しいカスタムアスペクト)として扱うようにするには、アスペクト宣言をドキュメント言語で作成する必要があります。そのためには、言語でプラグインアスペクトを作成して customAspect 言語をインポートします。

    Screen Shot 2015 09 09 at 23 55 58

  2. 言語のプラグインモデルにアスペクト宣言を作成し、そのフィールドに入力します。これは MPS にこの言語が他の言語のための新しいカスタムアスペクトを実装するために使われることができることを伝えます。

    Screen Shot 2015 09 10 at 00 01 41

  3. ドキュメント言語を作成 / 再構築した後、サンプル言語でドキュメントアスペクトを作成し、その中にドキュメントコンセプトを作成することはすでに可能です。

    Screen Shot 2015 09 10 at 00 05 02

  4. Screen Shot 2015 09 10 at 00 09 41
  5. それでは、MPS 内で機能するように、新しいアスペクトの機能を指定するために言語ランタイムに移行する必要があります。この例では、選択した概念のドキュメントを取得して返すことができるインターフェースを作成しましょう。そのためには、ランタイムソリューションを作成し、それをドキュメント言語のランタイムモジュールとして追加し、その中にインターフェースを作成します。ランタイムクラスは ILanguageAspect インターフェースを実装する必要があることに注意してください。私たちのニーズを満たすために、このメソッドは概念をパラメーターとして取り、対応する文書テキストと共に文字列を返さなければなりません。

    Screen Shot 2015 09 10 at 00 17 23

  6. ドキュメント言語用のジェネレータでは、上記から生成されたインターフェースの実装を持つ必要があります。条件付きルートルールと次のテンプレートがうまくいき、ドキュメント記述子クラスを生成します。

    Screen Shot 2015 10 27 at 17 57 32

    この条件により、ルールはカスタムアスペクトのモデル、つまりドキュメント定義(jetbrains.mps.samples.customAspect.sampleLanguage.documentation)を保持するモデルに対してのみトリガーされることが保証されます。
    ここで役立つ機能は、コンセプトスイッチの構築です。これにより、コンセプトの実装の詳細を無視できます。文書化されたすべての概念(LOOP マクロ)を単にループし、そのような概念ごとに、対応する ConceptDocumentation から取得した文字列値を返す一致するケース(正確に -> $[ConceptDocumentation])を作成します。

  7. それで、インターフェースと実装クラスがあります。それらを結び付ける必要があります - LanguageRuntime クラスの一部を生成する必要があります。それは私たちの概念を具体化します。すなわちドキュメントの側面が要求されるときはいつでも、DocumentationDescriptor クラスを返します。以下がどのように機能するかを理解するために、クラス Language.java がどのように生成されるかを見てください(モデル j.m.lang.descriptor.generator.template.main の言語クラスを参照)。ディスクリプタのインスタンス化は InstantiateAspectDescriptor と呼ばれるテンプレートスイッチによって行われます。それはもう 1 つのアスペクトモデルで動作するように新しいアスペクト言語で拡張する必要があります。

    Screen Shot 2015 10 27 at 18 00 22

    基本的に、リクエストされた aspectClass が私たちのカスタムアスペクトインターフェースであれば、生成された言語クラスに DocumentationAspectDescriptor インターフェースのチェックを追加し、DocumentationDescriptor の新しいインスタンスを返します。

  8. 残っているのは私たちの新しい側面を使うことだけです。そのためには、カーソルがオンデマンドでオンになっているノードの概念に関するドキュメントを表示するアクションを作成する必要があります。

    clx202


    コンテキストパラメーターを指定できるようにするには、 モデルをインポートする必要があります。アクションは StandalonePluginDescriptor を使用して(新しく作成された)プラグインソリューション(プラグインのプラグインソリューションの一部)の一部として作成し、ActionGroupDeclaration を介してメニューにフックする必要があります。
    clx201

  9. clx200

    これにより IDE コードメニューが拡張されます。

  10. それを試してみましょう ! プロジェクトを再構築し、サンドボックスソリューションで DocumentedConcept コンセプトのノードを作成するか開き、コードメニューからドキュメントの表示アクションを呼び出します。

    Screen Shot 2015 09 10 at 04 22 19

最終更新日 : 2020 年 6 月 18 日