MPS 2019.2ヘルプ

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

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

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

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と呼ばれます)。

  • Given an aspect interface, the language descriptor returns a concrete implementation of this aspect in this language (let's call it 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(英語)

    The condition ensures that the rule only triggers for the models of your custom aspect, i.e. in our case models that hold the documentation definitions ( jetbrains.mps.samples.customAspect.sampleLanguage.documentation ).
    The useful feature here is the concept switch construction, which allows you to ignore the concept implementation details. It simply loops through all documented concepts (the LOOP macro) and for each such concept creates a matching case (exactly ->$[ConceptDocumentation]) that returns a string value obtained from the associated 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(英語)

最終更新日: 2019年8月30日