MPS 2023.3 ヘルプ

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

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

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

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

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

各側面は、アスペクトの主な言語のセットを使用して記述されます。たとえば、エディターの様相を記述するための jmlang.editor の 言語があります。

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

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

バージョン 3.3 以降、MPS では、言語作成者が言語の新しい側面を定義できるようになりました。

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

  1. アスペクトを説明する言語を作成します。既存の言語を再利用するか、アスペクトのニーズに固有の言語を作成できます。例: コア MPS アスペクトのそれぞれは、独自の言語セットと、BaseLanguagesmodel などのいくつかの一般的な言語セットを使用します。

  2. この言語を (おそらく他の言語を使用して) 他の言語の定義の一部の側面を定義するために使用できることを宣言します。適切な側面記述子を言語で作成する必要があります。

  3. 作成した言語でジェネレーターを開発し、アスペクトのランタイムクラスを生成します (必要な場合)。

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

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

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

CustomAspect サンプルプロジェクトを開くと、6 つのモジュールが表示されます。

CustomAspectx1.png

ドキュメント言語とそのランタイムソリューションは、他の言語の新しいドキュメントの側面を定義するために使用される重要な構成要素です。アスペクトサブシステムは pluginSolution によって表され、現在フォーカスされているノードの概念に関するドキュメントを表示するアクションを定義します。SampleLanguage ソリューションは、この新しい側面を利用する言語の一例であり、それを使用して独自の概念をドキュメント化します。サンドボックスソリューションは、sampleLanguage の使用箇所を示し、ユーザーがドキュメントアスペクトによって定義されたドキュメントを表示できるようにします。ビルドソリューションは、サンプルプロジェクトを MPS プラグインとしてパッケージ化するビルドスクリプトを定義します。

言語ランタイム

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

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

  • アスペクトインターフェース - 各アスペクトは、ランタイムの API を一連のインターフェースとして定義します。マーカーインターフェース ILanguageAspect を実装する必要があります。

  • Language.createAspect() - ここでは言語記述子の createAspect() メソッドに注目してみましょう。アスペクトインターフェースをパラメーターとして指定すると、このメソッドは、この言語のこのアスペクトの具体的な実装を返します (これを AspectDescriptor と呼びます)。

  • アスペクト記述子 - AspectDescriptor はAspect インターフェースを実装する任意のクラスです。AspectDescriptor には、このアスペクトで記述されるエンティティの getter 以外のコードを含めないことをお勧めします。

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

CustomAspectx3.png

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

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

CustomAspectx2.png

言語の側面を使う

ここで、コードのいくつかの側面を使用したいとします。例: エディターで作業しているときに、現在選択されているノードに適用できるインテンションのリストを取得したいと考えています。

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

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

  3. 最後に、記述子からすべてのインテンションを取得し、現在のノードへの適用性を確認します。

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

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

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

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

  1. MPS に特別なモデルをドキュメントアスペクト (つまり、新しいカスタムアスペクト) として扱わせるには、ドキュメント言語でアスペクト宣言を作成する必要があります。これを行うには、言語でプラグインアスペクトを作成し、jetbrains.mps.lang.aspect 言語をインポートします。

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

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

    CustomAspectx6.png
  4. ConceptDocumentation コンセプトのインスタンスは、ドキュメントの側面で作成できます。

    CustomAspectx7.png
  5. ここで、MPS 内で動作する新しいアスペクトの機能を指定するために、言語ランタイムに移動する必要があります。この例では、選択した概念のドキュメントを取得して返すことができるインターフェースを作成しましょう。これを行うには、ランタイムソリューションを作成し、それをドキュメント言語のランタイムモジュールとして追加し、その中にインターフェースを作成します。インターフェースは ILanguageAspect インターフェースを拡張する必要があることに注意してください。ここでのインターフェースに必要なのは、概念をパラメーターとして受け取り、対応するドキュメントテキストを含む文字列を返すメソッド 1 つだけです。

    CustomAspectx8.png
  6. 次に、ドキュメント言語のジェネレーターで、インターフェースの実装を提供する必要があります。条件付きルートルールと次のテンプレートがうまく機能し、ドキュメント記述子クラスを生成します。

    CustomAspectx9.png

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

  7. インターフェースと実装クラスがあります。ここで、結び付ける必要があります。言語ランタイムクラスの createAspect メソッドの一部を生成する必要があります。これにより、コンセプトがインスタンス化されます。つまり、ドキュメントアスペクトが必要なときは常に (DocumentationAspectDescriptor インターフェースを渡すことによって)、生成された DocumentationDescriptor クラス。


    以下の動作を理解するには、Language.java クラスがどのように生成されるかを見てください (モデル jmlang.descriptor.generator.template.main の Language クラスを参照)。記述子のインスタンス化は、jetbrains.mps.lang.descriptor クラスの AspectDescriptor_Instantiate というテンプレートスイッチによって行われます。これは、もう 1 つのアスペクトモデルで動作するように、新しいアスペクト言語で拡張する必要があります。

    CustomAspectx10.png

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


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

    clx202.png

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

    clx201.png
  9. clx200.png

    このようにして、IDE コードメニューが強化されます。

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

    Screen-Shot-2015-09-10-at-04-22-19.png

関連ページ:

プラグイン

プラグインは、コードを MPS IDE 機能と統合する方法です。jetbrains.mps.lang.plugin および jetbrains.mps.lang.plugin.standalone 言語は、プラグインで使用できるいくつかのルート概念を提供します。この章では、それらすべてについて説明します。プラグインのインスタンス化:プラグインを開発している間、プラグインを保持するソリューションがあり、その効果を確認するために各変更の後に MPS を再起動する必要がないようにプラグインクラスを自動的に...

インタープリタークックブックの作成

バージョン 3.1 以降 MPS にバンドルされている Shapes サンプルプロジェクトを確認してください。エディターでいくつかの凝ったトリックを行うことができます。デフォルトでは、エディターは、キャンバス上に指定されたサイズと色の視覚的形状を描画するためのコマンドで構成されるプレーンコードを表示します。コードを Java に生成して実行することができます。これにより、上記のコードから生成されたばかりのアプリケーションを実行する新しい Java プロセスが起動します。ただし、MPS は Java...

カスタム持続クックブック

このドキュメントでは、MPS にバンドルされている xmlPersistence サンプルを使用して、独自の永続化形式を定義、デプロイ、使用する方法を説明します。カスタム永続性とは何ですか? :MPS は通常、モデルを独自の XML ベースの形式で保存します。ただし、モデルファイルを独自の形式でロードまたは保存したい場合があります。スタブモデルこれらは読み取り専用モデルであり、通常はライブラリコードを表します。たとえば、MPS を利用して既存の言語の 1 つを記述したいとします。たとえば、BaseLa...