MPS 2025.3 ヘルプ

MPS Kotlin 言語

入門

MPS Kotlin を使用するには、型システムプラグインをインストールする必要があります。その方法については、プラグインページ(英語)を参照してください。このプラグインは、作成するコードに適切な型を取得するために必要です。

インストールしたら、型システムを有効にするために必要なことは、MPS ウィンドウの右下にある Coderules ウィジェットを切り替えることだけです。コードルール(英語)は、型システムのベースとなるフレームワークです。

mps_kotlin_1.png

余談ですが、コードがモデルに書き留められると、生成 / テキスト生成 / コンパイルにプラグイン (およびコードルール) が常に必要になるわけではありません (サブ言語がそのジェネレーターで型システム機能を使用する場合のみ)。

MPS での Kotlin コードの記述

MPS で Kotlin コードを記述するための最初のステップは、言語をモデルにインポートすることです。いくつかの便利な言語がバンドルされている次の開発キットを使用できます。

  • jetbrains.mps.devkit.kotlin - 純粋な kotlin 言語

  • jetbrains.mps.devkit.kotlin.jvm - kotlin 言語、baseLanguage、相互運用性を提供する追加言語が含まれています

さらに、コードで MPS ノードを操作する必要がある場合は、jetbrains.mps.kotlin.smodel をインポートできます。

モデルに新しい kotlin ファイルを追加することで、kotlin コードを記述できるようになります。この言語で記述できる内容については、kotlin の公式ドキュメント(英語)を参照してください (構文は類似しており、編集エクスペリエンスはテキストベースの IDE と同様のエクスペリエンスを提供することを目的としています)。

mps_kotlin_2.png

Kotlin コード補完

Kotlin の MPS 実装は、型の計算とスコープの制約に Coderules 型システムに依存しています。Coderules がインストールされていないか有効になっていない場合でも、Kotlin は型を完全に計算できないにもかかわらず、限定的なスコープサポートを提供できます。

Completion in Kotlin when Coderules is disabled

プラットフォームサポート

ソースセット

通常の Kotlin プロジェクトでは、ソースセットを使用して、異なるプラットフォームを対象とするコードを分離できます。MPS では、これをルートレベルで導入し、各 Kotlin ルートノードでサポートされるプラットフォームのセットを指定するオプションを用意しました。これらのソースセットは、インテンションアクションを使用してルートノードレベルで構成できます。

Platform definition for a Kotlin root node

実際には、これは次のことを意味します。

  • 特定のソースセットのコードは、互換性のあるプラットフォームの宣言にのみアクセスできます。例: JVM 固有のコードは、JVM 固有のコードと、JVM を対象とする共通コードにのみアクセスできます。

  • 生成されたソースは、ソースセット固有のディレクトリに構造化されます。ディレクトリが指定されていない場合は、モジュールのデフォルトに対応するデフォルトのソースセットが使用されます。期待される宣言と実際の宣言がサポートされるようになりました。

デフォルトでは、明示的なプラットフォームのない Kotlin コードは JVM を使用し、下位互換性を維持します。

スタブの読み込みとコンパイル

スタブは、新しいマルチプラットフォームのユースケースをサポートするために改善されます。これまで、MPS は、共通スタブと JVM スタブをそれぞれロードする Kotlin スタブと Kotlin/JVM スタブに別々のオプションを提供していました。これらのオプションは現在、Kotlin スタブのオプションに統合されており、提供されたアーティファクトが共通コード、JVM コード、または他のプラットフォームのコードのうちのどれを公開するかを自動的に判断します。共通ライブラリとプラットフォーム固有のライブラリ間の宣言は冗長であるため (両方のアーティファクトに必要な宣言がすべて含まれている)、重複をフィルタリングする新しいメカニズムが導入され、スタブが整理された状態を保ちます。プラットフォーム固有のライブラリが同じモジュールで宣言されている場合、共通宣言にアクセスできるため、再度宣言する必要はありません。

依存関係の構成は以前と同じです。

  • 共通ライブラリとプラットフォーム固有のライブラリの両方をスタブとして使用できます。共通コードを JVM にコンパイルするには JVM ライブラリが必要であり、Java ファセットで宣言する必要があります。

  • たとえば、共通コードを記述するには、共通ソースセットを使用してスタブ用の共通ライブラリを使用する必要がありますが、Java ファセットで Java アーティファクトを宣言する必要もあります。

ライブラリのインポート

Kotlin ライブラリのサポートは現在、kotlin 共通ライブラリ(英語)に限定されています。現在、java クラスから kotlin スタブをインポートすることはできません。コンパイル / ランタイムでは、現時点では kotlin コンパイラープラグインを追加することもできません。

使用したいライブラリ (Ktor など) がある場合は、ライブラリの「共通」ディストリビューション (通常は .class ファイルの代わりに .kotlin_metadata ファイルを含む .jar) からスタブをインポートできます。コードを JVM で実行する場合は、ライブラリの JVM ディストリビューションをクラスパスにアタッチすることもできます。例として、プロジェクトに Kotlinx シリアライゼーションコアをセットアップしてみることができます。このライブラリには 2 つの分散 jar があります。

  • kotlinx-serialization-core - 共通ディストリビューション

  • kotlinx-serialization-core-jvm - jvm ディストリビューション

このライブラリをホストするための新しいソリューションを作成できます。このソリューションプロパティで、「Kotlin Common」スタブモデルルートを追加できます。

mps_kotlin_3.png

共通ディストリビューション jar (kotlinx-serialization-core.jar) を選択して追加します。kotlin_metadata がほとんど検出されていない新しいエントリが表示されるはずです。次に、jar 自体を「ソース」としてマークし、次の結果を取得します。

mps_kotlin_4.png

これだけで、このライブラリを使用してコードを書くことができます。jvm にコンパイルする必要がある場合は、java タブに移動して、jvm ディストリビューション (kotlinx-serialization-core-jvm.jar) を追加します。

mps_kotlin_5.png

モジュールでまだ kotlin を使用していない場合は、「依存関係」で kotlin stdlib に依存関係を追加する必要がある場合もあります (kotlin コアタイプが解決されるように)。同様に、ライブラリが他の Kotlin 共通ライブラリにも依存している場合は、それらにも依存する (または必要に応じて同じプロセスを使用してインポートする) 必要があります。

これで、このライブラリを使用してコードを記述できるようになります。この例 (kotlin シリアライゼーション) では、実行時に動作するようにコンパイラープラグインを設定する必要もありますが、これは現時点で MPS ではサポートされていません。

作業 / ビルドスクリプトのエクスポート

Kotlin コードはコンパイルされ、エディターで java コードと連携する必要がありますが、そのコンパイルをビルドスクリプトに反映させるには、少し追加の手順が必要です。

ビルドスクリプトで kotlin コンパイルを必要とする各モジュールは、手動でそのようにマークする必要があります。インスペクタから行うことができます。

mps_kotlin_6.png

このオプションは、java コンパイラーの fork オプションと互換性がない(英語)ことに注意してください。

言語の拡張

MPS 用の Kotlin は、言語のいくつかの側面を拡張可能にし、既存の概念と互換性を持たせるためのいくつかの機能を提供します。これらの機能の一部の概要を次に示します。

型と型システム

ノードの入力 (コードルールを使用せずに)

純粋な kotlin 言語では、ほぼすべての概念が、リテラル呼び出しと関数呼び出しの 2 つのカテゴリに分類されます。そのため、型システムはデフォルトで、型を計算するための 2 つの対応する機能を提供します。このセクションでは、処理されたユースケースが要件に適合する場合に指定された API を使用する方法について説明します。それ以外の場合は、MPS Kotlin の coderules 実装に飛び込んで、そこに独自のルールを統合してください。

単純なケースでは、IStaticType インターフェースを拡張して、動作メソッドから直接型を提供できます。これは、型システム操作 (例: otherNode.type、coerce、サブタイプチェックなど) に依存しないため、型が単純な場合にのみ使用する必要があります。

それがすべての要件に合わない場合は、ノードを関数呼び出しとして使用してみてください。タイプが他のノード (子、レシーバーなど) に依存する可能性があり、推論の恩恵を受けるノードに使用する必要があります。例: この機能は、kotlin のすべての種類の関数呼び出し (x.f()、f()、x f y …) だけでなく、すべての演算子 (+、-、[] …) および一部の構造要素 (for ステートメント) にも使用されます。

すべては IFunctionCall の概念から始まり、いくつかの動作関数を実装する必要があります。

まず、呼び出し自体に関連する関数:

  • Receiver - この呼び出しを受け取るタイプに関する情報 (存在する場合) (たとえば、xf() では、これは x のタイプを参照する必要があります)

  • 引数

  • 型引数

  • Null セーフ - true に設定されている場合、null 許容レシーバー型を受け入れます

次に、関数宣言を記述するオブジェクトを返す単一の関数 getFunctionDescriptor

最後に、ユースケースに適用できる場合は、いくつかのメソッドが関数解決の機能を提供します (そうでない場合、それらはすべて null を返す可能性があります)。

  • 関数名 - スコープ内で検索する名前

  • ターゲットリンク (削除される可能性があります) - 上記の場合、解決された関数をノードに割り当てるために使用するリンク。

  • 修飾子フィルター - 検索時に、同じ修飾子を持たないメソッドを除外します

  • Function scope parts - 関数の解決のために検索するスコープのリスト。Kotlin は独自の Scope インターフェースを使用するため、このメソッドは制約 (通常の Scope にラップ) とメソッド解決メカニズムの両方から呼び出されます。(例: 自動解像度ヘルパー )

多くの関数は、ノードではなく、記述しようとしているものの抽象化を返すことに注意してください (例: FunctionDeclaration インターフェース)。これにより、関数メカニズムで概念を強制しないこと (たとえば、kotlin で使用される baseLanguage メソッドなど、最初は意図されていなくても、任意の概念を関数宣言にすることができます) と、どこでも実際のノードの使用を強制しないこと (引数はそうではありません) の両方が可能になります。式である必要があり、型を直接参照できます)。

もう 1 つの興味深い側面は、TypeReference インターフェースです。多くの抽象化では、IType の概念 (宣言とは異なり、IType の使用が強制されます) を使用するのではなく、型を返すために使用します。これにより、参照が型システムの外部で使用される場合 (たとえば、ノードの型は型システムへの新しい呼び出しを行う必要があります)、または型システムの内部で使用される場合 (同じノードの型は内部の型システム機能から取得できます) に異なる計算が可能になります。直接)。

新しいタイプの作成

Kotlin クラス型だけでも非常に強力で、使用と宣言の場所の差分をサポートし、言語は DSL を定義する独自の方法(英語)を提供します。ただし、新しいタイプと新しい機能を追加する必要がある場合があります。

タイプを Kotlin に追加するには、2 つのアクションがあります: 構造への追加と coderules タイプシステムへの追加です。

kotlin 構造と互換性のある型を追加する場合は、IType インターフェースを拡張できます。これには、型にサブタイピング、ジェネリクス、スコープのサポートを追加するための一連のメソッドが含まれています。kotlin.baseLanguageRef および kotlin.smodel 言語でいくつかの例を見つけることができます。

コードルール側では、物事はそれほど厳密ではありません。使用したいすべてのメカニズム (推論、サブタイピングなど) のサポートを追加すれば、任意の型を使用できます。ただし、型システムへの飛び込みは非常に複雑であるため、十分にサポートされている classType 構造を使用することをお勧めします。分類子を参照し (概念は適用されません)、(オプションで) いくつかの型パラメーターを持つ任意の型に使用できます。

その例として、kotlin.smodelNodeType を確認できます。同じ言語には、classType に依存せず、必要なすべての操作を実装する型の例がバンドルされています (conceptType を参照)。

2024 年 7 月 22 日