MPS 2020.1 ヘルプ

生成コードからのソースの削除

MPS はデフォルトでソースを生成モデルにバンドルします。モデルのユーザーは、自分のコードで使用している概念の定義にナビゲートすることができます。たとえば、呼び出しているメソッドやインスタンス化しているクラスの実装を確認するには、1 回の Control キーを押しながらクリックするだけです。彼らは単に実装側を覗くことによって言語 / ライブラリの作者のアイデアの多くを把握することができるため、これはユーザーにとって非常に便利です。
ただし、実装を隠すことが望ましい場合があるかもしれません。特にクローズドソースプロジェクトでは、実装に含まれる知的財産を慎重に保護する必要があります。ユーザーはまだコードを呼び出すことができるはずですが、Control + B を押すと、クラスとメソッドのシグネチャーを見ることしかできなくなります。

obfuscated1

難読化されたクラスファイルと、リバースエンジニアリングによる他の人へのチャンスとを組み合わせると、ハードワークの成果はかなり低くなります。これを行う方法を見つけるために参照してください。

BaseLanguage コードからソースを削除する

BuildLanguage は、特定のアーティファクトからソースを削除する必要があることを示すためのストリップ実装フラグを提供します。

obf2

いずれかのビルドレイアウトコマンド( modulesources ofplugin)でこのフラグを true に設定すると、生成されたアーティファクトから実装のソースを削除するようにビルドプロセスに指示します。このフラグは、BaseLanguage メソッドの本体が空の StatementList に置き換えられ、クラスの静的およびインスタンス初期化子が削除されるようにします。言語の実装を隠したい場合は、このフラグによって、振る舞いメソッドの本体も空の StatementList に置き換えられます。

まとめると、MPS はそのまま使用できます。

  • BaseLanguage で書かれたあなたの実装を隠す

  • 言語定義の側面を隠す

必要なソリューションまたは言語に合わせて、ビルドスクリプトで strip 実装フラグを設定するだけです。

いくつかの便利なメモ

  1. MPS でキャッシュの破棄を使用する機能は、ストリップされたバージョンとされていないバージョンの言語を含むプロジェクトを切り替えるときに便利です。

  2. ビルドスクリプトが生成された成果物の変更を反映するように、言語に手動で変更を加える必要がある場合があります。

独自の言語のための実装ストリッピングのカスタマイズ

BaseLanguage コードが実装の隠蔽を許可するのと同じように、あなたの言語も実装の隠蔽を許可することができます。

MPS は実装ストリッピングに関してあなたの言語の概念の意図されたふるまいを区別するためにあなたに 3 つのマーカーインターフェースを与えます:

  • InterfacePart - 生成されたモデルに完全に表示される概念ユーザーは自分のところに移動して自分のコード内でそれらの参照を保持することができます。

  • ImplementationPart - 生成されたモデルから削除される概念ユーザーは自分のコードに移動したり、自分の参照を自分のコードで保持したりできなくなります。

  • ImplementationWithStubPart - 空のスタブに置き換えられる概念。コード内のノードを表すためにスタブ置換が使用される点を除いて、ImplementationPart のように動作します。たとえば、空のメソッド本体を表す /* compiled code */ マークを考えてください。

ロボットカヤサンプル

たとえば、Robot Kaja のサンプル言語(MPS にバンドルされている)を使用してその実装を隠すことができるようにしたい場合は、いくつかの手順で実現できます。次のシナリオを想定しましょう。

  1. エンドユーザーがロボットカヤ言語で SampleRobotScripts プロジェクトの一部としてスクリプトを書いています。彼はロボットルーチン(MPS ソリューション)と呼ばれるロボットルーチンのライブラリをダウンロードして再利用したいと考えています。

  2. ロボットルーチンの作者は彼女のライブラリの実装を隠したいと思います。

  3. ロボットルーチンの実装を隠すことをサポートするために、ロボットカヤ言語を修正する必要があります。それは、その概念のうちどれがその言語で書かれたアプリケーション/ライブラリのパブリックインターフェース(契約)を形成し、どれがその実装を保持するかを宣言する必要があります。単純な言語を選んだため、3 つの概念だけを本当にインターフェースの一部にする必要があることを識別するのはかなり簡単です。他の人たちはパッケージングの間に彼らの源を取り除かれることができます。
    1. スクリプト
    2. ライブラリ
    3. ルーチン定義

初期の状況

Robot Kaja 言語では、ライブラリのルーチンを作成できます。ライブラリは根本的な概念であり、コレクションまたはルーチン定義を保持します。ロボットカヤ言語を使用するロボットルーチンライブラリは、いくつかのライブラリルートノードを作成し、それらにいくつかの便利なルーチンを実装することができます。

obf6

SampleRobotScripts コードで使用すると、開発者はいつでも定義に移動してロボットルーチンライブラリの完全な実装を見ることができます。

obf3

obf4b

ゴール

ロボットルーチンなどのライブラリの作者に実装を隠す機能を提供したいです。一度正しく実装されると、SampleRobotScripts の開発者はルーチンのシグネチャーとそれらの空の本体しか見ることができません。

obf4a

Robot Kaja 言語への変更

ロボットカヤ言語では、スクリプトライブラリ、およびルーチン定義の概念を InterfacePart インターフェースでマークする必要があります。これは、ユーザーコードで参照できるためです。

obf7

obf8

ルーチンの実装を隠すには、それらの本体を隠す必要があります。ルーチン本体は CommandList の概念です。それを隠すには、ImplementationPart インターフェースまたは ImplementationWithStubPart インターフェースのいずれかでそれをマークする必要があります。どちらも実装を隠すことになりますが、後者では削除された実装の代わりに挿入される置換「スタブ」の概念を提供できます。スタブは、削除された実装でコードの見栄えをよくする機会を提供します。エンドユーザーに時折見られるような隠れた実装については常に考慮する必要があります。

obf9

スタブ作成

ImplementationPart に対する ImplementationWithStubPart のオーバーヘッドは、スタブの概念を作成することにあります。私たちの CommandList のために StubCommandList 概念を必要とし、それを IDontSubstituteByDefaultIStubForAnotherConcept でマークします。StubCommandListCommandList から ImplementationWithStubPart インターフェースを継承するため、IStubForAnotherConcept が必要です。MPS は、StubCommandList がスタブ自体であり、さらに別のスタブによってスタブされる必要がないことを明示的に伝える必要があります。

stubx2

StubCommandListCommandList の代わりに AbstractCommand を拡張していた場合、AbstractCommandImplementationWithStubPart ではないため、IStubForAnotherConcept としてマークする必要はありません。

stubx3

スタブエディターは、実装が削除されており、ここでは表示されないことを読者に丁寧に明らかにする必要があります。

obf11

再構築してパッケージ化すると、言語はロボットルーチンの作者が彼女のライブラリの実装を隠すのを手助けする準備ができています。

ライブラリ作家のためのスクリプトを作成する

ロボットカヤ言語が実装の削除をサポートするようになると、ロボットルーチンライブラリの作者は自分のビルドスクリプトで strip の実装フラグを設定し、生成されたプラグインから自分のライブラリの実装のソースを削除することができます。

obf5

一般的なガイドラインと追加の注意事項

  1. マーカーインターフェースは、スーパーコンセプトとスーパーコンセプトインターフェースから伝統的な方法で継承されます。複数のマーカーインターフェースが概念に適用可能な場合(直接または継承を通じて)、InterfacePart が他のものに勝ち、ImplementationWithStubPartImplementationPart に勝ちます。

  2. どのマーカーインターフェースも指定されていない場合、概念は InterfacePart が設定されているかのように動作します。InterfacePart で概念をマークすることは 2 つの目的に役立ちます:
    • 概念があなたの言語の必要な公的要素であるという事実を文書化する

    • たとえば、概念が他のフラグのいずれかを継承している場合に、その概念が誤って実装の一部としてマークされるのを防ぎます。

  3. ImplementationPart インターフェースを使用して、クライアントコードから参照する必要がない、または必須(基数 1 および 1..n)リンクを介して InterfacePart の概念から直接アクセスする必要がない言語の概念をマークします。これらの概念のソースはビルド中にソリューションから削除されるため、ユーザーはコンセプト宣言へを使用するなどして定義を確認することはできません。

  4. ImplementationPart と同様に削除すべき概念をマークするために ImplementationWithStubPart インターフェースを使用しますが、ユーザーはそれらを概念の定義の一部として見ることができるため、単純にソースから削除する代わりにプレースホルダーに置き換える必要があります。InterfacePart のコンセプト

  5. ImplementationWithStubPart は、InterfacePart の概念から指し示す基数 1 および 1..n の子または参照の参照先を表す概念には通常必要です。なぜなら、含むリンクは空のままにできず、検証エラーを報告するからです。

  6. 0..1 および 0..n の基数を持つ参照の子およびターゲットは、安全に ImplementationPart としてマークできます。含まれているリンクは空のままになります。

  7. スタブは命名規則置き換えられる概念のスタブ + 名前に従い、置き換えられた概念を持つ同じパッケージ内に配置されなければなりません。

  8. スタブの概念は、それらの子ノードから型システムエラーが報告されるのを避けるために ISuppressErrors を実装することができます。

  9. スタブは、それらがコード補完メニューで提供されないように IDontSubstituteByDefault も実装するべきです。

  10. 概念が InterfacePart実装(WithStub)パートの両方である場合、MPS は警告を報告します。

  11. 概念が ImplementationWithStubPart インターフェースを宣言または継承し、同じ仮想パッケージ内に適切なスタブ概念が見つからない場合、MPS はエラーを報告します。

  12. ImplementationWithStubPart インターフェースを継承するスタブは、おそらくスタブ化された概念を拡張することによって、それらがスタブであることを示すために IStubForAnotherConcept を実装する必要があるため、自分でスタブする必要はありません。すべてのスタブに IStubForAnotherConcept インターフェースを実装させるのは良い戦略です。

  13. スタブは抽象的なスーパーコンセプトを置き換えるように定義することはできません。彼らは常に ImplementationWithStubPart を実装する 1 つの具体的な概念のために 1 つのスタブとして、すべての具体的な概念を個別に置き換える必要があります。

  14. 明確なメッセージを表示するようにスタブの概念のエディターを再定義します。別名「コンパイル済みコード」は、実装が削除されたことを読者に明確に示すためのものです。

  15. 削除された言語のユーザーがスタブ化された概念で見られるモデル検証エラーを回避するために、すべての子の「特殊化」およびそれらのスーパー概念からスタブ概念に継承された「少なくとも 1」カーディナリティの参照を検討してください。

これは、次のような概念に必要です。modelAccessor の子はカーディナリティ 1 を持つため、スタブ化された概念では必須です。

Hid1

スタブの概念は、スタブをスタブの概念の名前の前に付けるという命名規則に従う必要があります。スタブ化された概念を拡張する必要があるかもしれませんし、そうでないかもしれません - これは元の概念が他の言語からどのように参照されているかに依存します。スタブの概念がスタブの概念を拡張する必要がある場合は、子参照が空のままにならないように、何らかの理由で必須の子を処理する必要もあります。

推奨される方法は、子または参照関係を特殊化し、ターゲットの概念を BaseConcept に変更することです。

Stubx1

コンストラクターの動作の側面では、IntegerConstant などのダミーノードを指すように参照を設定します。これにより、リンクが空のままにならないようになりますが、スタブ化された概念で元の modelAccessor リンクを完全に満たすノードを作成する必要がなくなります。

Hid3

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