MPS 2019.1ヘルプ

スコープ

カスタム言語要素のスコープを定義する2つの方法、継承 (階層)参照アプローチを見ていきます。実験用のテストベッドとして計算機のチュートリアル言語を選択しました。MPSディストリビューションに付属のサンプルプロジェクトのセットにcalculator-tutorialプロジェクトが含まれています。

2 つの方法

すべての参照は許可されたターゲットのセットを知る必要があります。これにより、ユーザーが参照の値を入力しようとしているときはいつでもMPSが完了メニューに値を入力することができます。既存の参照がそのセットに対して検証され、範囲外の要素を参照している場合は無効としてマークされます。デフォルトでは、参照に対して有効範囲が定義されていない場合、現在のモデル内およびインポートされたモデル内のすべてのターゲットが有効範囲内にあるため、参照に使用できます。

MPSはスコープを定義する2つの方法を提供します。

  • 継承スコープ

  • 参照スコープ

継承スコープではモデル内のノードの階層に従ってスコープを徐々に構築することができますが、参照スコープでは低いセレモニーが提供されます。

継承スコープ

最初に、スコープ解決の新しい階層( 継承 )メカニズムについて説明します。このメカニズムはScopeProviderを実装する先祖にスコープ解決を委譲します。

  1. MPSは、ScopeProviderを実装し、現在の種類のスコープを提供できる参照ノードに最も近い先祖を探し始めます。

  2. ScopeProvidernullを返した場合、MPSはより遠い先祖の検索を続けます

  3. ScopeProviderはできます
    • スコープ実装を構築して返す (これらの詳細)

    • 親スコープに委譲する

    • 独自の要素を親スコープに追加する

    • 親スコープから要素を隠す (スコープを操作する方法の詳細については後で説明する)

親スコープを取得するための呼び出しは、ScopeProvider内から明示的に行わなければなりません。

InputFieldReferenceInputFieldノードを検索し、それらのリストを構築するためにその先祖に頼ります。

Sc1
Sc2

InputFieldを検索するときのInputFieldReferenceのスコープが継承されるように指定したら、電卓ScopeProviderであることを示す必要があります。これは、電卓がその子孫として配置されているすべてのInputFieldReferencesのスコープを構築することを宣言していることを保証します。

Sc3

場合の電卓は、InputFieldのスコープについて問い合わせをされたときはいつでも、その入力フィールドすべてのリストを返すべきです。そのため、電卓振る舞いアスペクトでは、getScope()メソッドをオーバーライド(Control + O)します。

Co1111

スコープが未解決のままである場合は、それを含むモデル(Control + R)をインポートする必要があります。(jetbrains.mps.scope)。

Sc5

getScope()メソッドは2つのパラメータを取ります。

  • kind - 参照の可能なターゲットの概念

  • child - 要求の送信元である現在の(this)ScopeProviderの子ノード。実際の参照はノードの子孫の中にあります。

機能をエンコードする必要があるため、BaseLanguageも必要です。ノードを照会するには、jetbrains.mps.lang。 smodel言語をインポートする必要があります。これらの言語は自動的にインポートされているはずです。そうでない場合は、Control + Lショートカットを使用してインポートできます。

Sc6

これで、スコープ定義コードを完成させることができます。スコープ定義コードは、本質的に、電卓内からすべての入力フィールドを返します。

Sc8

簡単なヒント:SimpleRoleScopeクラスの使い方に注目してください。それは独自のカスタムスコープを構築するのを手助けすることができるいくつかのヘルパークラスの1つです。SimpleRoleScope(Control + N)にナビゲートし、それを含んでいるパッケージ構造(Alt + F1)を開くことによってチェックしてください。

スコープヘルパーの実装

MPSには、考えられる多くのシナリオをカバーするヘルパースコープ実装がいくつか付属しており、使用してスコープを定義する作業を容易にすることができます。

  • ListScope - コンストラクターに渡されたノードを表する

  • DelegatingScope - コンストラクターに渡されたScopeインスタンスへのデリゲート。通常は既存のスコープの周囲に機能を追加する必要があるスコープによって拡張されます。LazyScope

  • CompositeScope - (ラップされた)Scopeインスタンスのグループに委譲する

  • FilteringScope - 述語を使ってノードをフィルタリングしながら、単一のScopeインスタンスに委譲する (isExcludedメソッド)

  • FilteringByNameScope - 単一のScopeインスタンスに委譲し、そのノードを名前ブラックリストでフィルタリングします。これはコンストラクターパラメータとして取得されます。

  • EmptyScope - ノードを持たないスコープ

  • SimpleRoleScope - 特定のロールに一致する、ノードのすべての子ノードを提供するスコープ

  • モデルスコープ - 提供されたモデルのセットに含まれる特定の概念のすべてのノードを含むスコープ

  • ModelPlusImportedScope - ModelsScopeと似ていますが、指定されたモデルによってインポートされたすべてのモデルを含みます。

例:getScope()メソッドは、ListScopeを使用して次のように書き直すことができます。

Scopex1001

VariableReference

もう少し高度な例がBaseLanguage VariableReferenceで見つけることができます。variableDeclaration参照に継承されたスコープを使用します。

scp1

強制テイトメントLocalVariableDeclarationBaseMethodDeclaration分類子などの概念やその他の概念では、スコープに変数宣言を追加してScopeProviderを実装しています。

scp2

例:強制テイトメントは、Scopes.forVariablesヘルパー関数を使用して、for スコープで宣言されたすべての変数で親スコープを強化するスコープを構築します。親スコープ内で同じ名前の変数を隠す可能性があります。from from式は、現在スコープを解決している参照がサブツリーの特定の部分にあるかどうかを検出します。

参照スコープを使用する

スコープは、参照スコープを使用して、高速ではあるがスケーラビリティの低い方法で実装することもできます。

rsc1

解決を行うためにScopeProvider型の祖先に委譲する代わりに、スコープ解決コードを制約定義に挿入することができます。


rsc2

元々電卓のgetScope()メソッドの内部にあったコードの代わりに、スコープを定義するのはInputFieldReference自体です。参照スコープの関数は、ScopeProvider.getScope()メソッドと同じように、スコープインスタンスを返すことになっています。スコープは本質的に潜在的な参照ターゲットのリストと一緒にこれらのターゲットをテキスト値で解決するためのロジックです。

あなたを思い出させるために、使用する準備ができているいくつかの定義済みスコープ実装と関連するヘルパーファクトリメソッドがあります:

  • SimpleRoleScope - 指定されたロールに属している、指定されたノードに接続されているすべてのノードを単純に追加する

  • ModelPlusImportedScope - インポートされたモデルから参照ターゲットを提供します。ユーザーがCtrl + R / cmd + R(モデルを含むインポート)によってスコープにターゲットを追加することを許可します。

  • FilteringScope - 他のスコープからいくつかの要素を除外することを許可します。FilteringScopeのサブクラスはisExcluded()メソッドをオーバーライドします。

  • DelegatingScope - 別のスコープに委譲します。元のスコープの動作をカスタマイズするためにオーバーライドされることを意味します。

スコープモデルで自分を見回すこともできます。

scp3

最終更新日: 2019年7月5日