MPS 2019.2ヘルプ

図形 - MPS入門チュートリアル

MPSに不慣れですぐにそれを試してみたいなら、これはあなたのための正しいチュートリアルです。2時間以内に、新しい言語とその言語を使用する機能コードを入手できます。このチュートリアルでは、最初から始め、安全で便利な道を歩むことで、新しい言語のコア要素を設計します。すぐにフィニッシュラインに到達するために、高度な概念、複雑な構成要素、および暗いコーナーを避けます。最後に、MPSとは何か、MPSがどのような原則に基づいているのかを理解できます。

では、シートベルトを締めてください。早く乗りに行きましょう。

前提条件

MPSチュートリアルへのファーストトラックの最初の部分を見てきたため、MPS環境に精通していて、言語とソリューションの概念を理解していて、MPSプロジェクションエディターに命令できると仮定します。そうでない場合は、チェックアウトするためにあなたの時間の最初の30分程度を費やすことを検討してください。特にこれらのキーボードショートカットはあなたの生存の鍵です:

  • Control + Space - 不完全な単語を補完したり、無効な(赤い)識別子を正しい(黒い)識別子に変える

  • Alt + Enter - 現在のエディター位置に適用可能な便利なオプションを含むポップアップメニューを表示します

  • Control/Cmd + Up-Arrow/Down-Arrow - 選択したテキストの領域を拡大/縮小する

  • タブ - エディターで編集可能な要素をナビゲートする

  • Control/Cmd + Z - 元に戻す

また、MPSをインストールし、あなたの目の前で実行していると仮定します。始めることができます。

ゴール

グラフィック図形を指定するためのサンプル言語を実装します。この言語により、ユーザーは平らなキャンバスに視覚的な2次元形状をレイアウトすることができます。その後、定義はJava Swingアプリケーションに変換され、これによって画面上のレイアウトが視覚化されます。

Tut1

Tut2

この言語により、プログラマーでなくてもJava、Swing、または2D Graphics APIに関する知識がなくてもJavaアプリケーションを作成できます。その一方で、言語デザイナーのロールを果たすでしょう。そして、その人はJavaの彼または彼女の知識の上にそのような使いやすい言語構築を準備するでしょう。UIプログラマーが現在手動で解決しなければならないいくつかのケースをカバーする言語とジェネレータを提供することによって、UIプログラマーの作業を自動化します。
JavaまたはSwingに精通していないなら、あまりにも早くあまりに心配しないでください。この可能性を想定し、慎重にあなたを導くためのチュートリアルを作りました。簡単に通過することができるでしょう、見るでしょう。

新規プロジェクトの作成

新しいプロジェクトから始めましょう。ようこそ画面で新規プロジェクトの作成をクリックしてウィザードに従ってください。

welcome20173

Sh2

空の言語定義と空のソリューションを含む空のプロジェクトが表示されます。

Sh4

ソリューションはあなたのプログラムを持ちます。これらのプログラムを書くためには、同じプロジェクトで定義されているかインポートされた言語のいずれかを使用します。このチュートリアルでは、まず言語を定義し、それを使って実行可能なコードを書くことにします。

ボンネットの言語とプログラム

まず、ここで先に進む前に知っておくべき少しの背景知識があります。これは、Shapes言語を完全に実装すれば作成できるコードの一部です。

Tut1

構築している言語は、それぞれが別々の行にあり、それぞれが描画する単一の形状を定義している個々のコマンドで構成されているペイント定義を許可する必要があります。私達の言語はコンセプトでそのようなそれぞれの命令をカバーする必要があります。概念は、言語の抽象構文、すなわち許容言語論理構成体のセットを定義します。プログラムは抽象構文ツリーで構成され、抽象構文ツリーはこれらの概念のインスタンスを保持します。

Sh5

上の短いプログラムのASTは抽象的な構文を示しています - それはノードから成り、それぞれのノードは言語が定義するコンセプトのインスタンスです。概念はプロパティー、子、参照を定義し、ノードは具体的な値を与えます。

ここでちょっとした理論をまとめると:

  • 言語概念で構成されています

  • 概念は、そのプロパティーおよび参照を使用して論理(抽象)要素を定義します

  • プログラム (解決策)はASTで構成され、ASTはノードで構成されています

  • ノードは、プロパティー、およびそれらの概念参照に具体的な値を与える概念のインスタンスです。

グラフィック形状

私達の言語はかなり簡単になるでしょう。必要な概念はいくつかあります。

  • キャンバス - 絵画の定義全体を表し、すべての図形を保持する最上位ノードを定義する

  • 形状 - キャンバス上に図形を描画するコマンドを表します。これは、円や四角形などのすべての具体的な図形に対する共通のsuper-conceptとして機能します。

  • 円形 - 円を描くコマンドを表す

  • 四角 - 四角形を描くコマンドを表す

  • カラーリファレンス - java.awt.Colorで定義されたいくつかの定義済み色の1つを表す

私達は形状の概念から私達の実用的な練習を始めます。オブジェクト指向プログラミングと同様に、概念は互いに拡張することができ、super-conceptの機能を継承することができます。私たちの言語のすべての図形はcolorプロパティーを必要とするため、形状のコンセプトはそのような共通のsuper-conceptとして機能し、colorプロパティーを保持するため便利に継承できます。

Sh6

言語の構造アスペクトを右クリックして、新しいコンセプトを作成してください。エディターで新しいコンセプト定義が開きます。

Sh7

コンセプトにはわかりやすい名前を付けてください。この場合は形状でうまくいきます。
MPSという名前がないことを示す形状と入力してください - 赤い<名前なし>フィールド。

Sh8

形状という概念を私たちの言語のすべての形に共通のsuper-conceptとして作成しました。それ自体では形状はASTで直接使用されません。形状のインスタンス( ノード )を作成できないことを明示に示すために、形状abstractとマークします。

Alt + Enterキーボードショートカットを練習する時です。

概念宣言の最初の行に電球の記号がありますか。(電球が表示されるようにするには、カーソルを最初の行に移動する必要があるかもしれません。少し恥ずかしがり屋です。)電球は、コンテキストメニューを非表示にしています。カーソル位置Alt + Enterはキーボードから電球メニュー(私達= インテンションメニューと呼ぶ)にアクセスすることを可能にします。

Sh17
Sh18

Alt + Enterキーボードショートカットは、コンセプトの名前の上に置かれると、コンテキストポップアップメニューを表示します。このポップアップメニューには、"抽象化" インテンションをコンセプトに適用するオプションがあります。そのオプションを選択すると、その概念は抽象的としてマークされます。これで、形状のすべてのサブコンセプトで共有する必要があるプロパティー、子、参照を追加できましたが、後で学習曲線をフラットにするためにそれを残します。

それが私たちの最初のコンセプトです! 万歳!別のものを追加する時間です。円形はどうですか?確かに、構造の面を右クリックして別のコンセプトを作成し、名前を付けます - 円形

円形

同じ手順に従って、言語の構造部分を右クリックして新しい概念を追加する必要があります。円形という名前を付けます。

Sh9

サークルは形状から機能を継承する必要があるため、extends句よりも示す必要があります。"BaseConcept"テキストを保持しているセルの先頭にカーソルを置き、MPSで最も便利なキーボードショートカット(Control + Space)を押してコード補完を呼び出します。MPSはあなたに "BaseConcept"テキストの代わりとして適用可能なオプションのリストを表示します。円形形状を拡張するようにするには、ここで形状を選択する必要があります。

Sh10

補完メニューに形状が表示されない場合は、カーソルが単語の最初の位置にないためです。

Sni mek obrazovky 2018 12 06 v 10 42 17

カーソルの左側の文字は、これらの文字と一致するオプションのみを表示するためのフィルタとして使用されます。カーソルが右に行くほど、補完メニューに表示されるオプションは少なくなります。

Sni mek obrazovky 2018 12 06 v 10 41 46

カーソルを左矢印で移動する必要があります。または、Control + Spaceをもう一度押すと、MPSによって現在の単語の一番左にカーソルが移動します。


Sh11

これが私たちの言語のユーザーによって使われる最初の具体的な概念です。概念をコード補完ダイアログでわかりやすいテキスト表現にし、ユーザーが「circle」と入力するたびにMPSが円形のインスタンスを作成するのを賢くできるようにするには、概念にエイリアス「circle」を付ける必要があります。

Sh12

各円は、画面上の座標とその半径を指定する必要があります。これらの整数値を保持するプロパティーを作成します。プロパティーセクションに移動し、空の値の集まりを表す "<< ... >>"記号にカーソルを合わせて、Enterキーを押します。これで空のプロパティーが作成されます。

Sh13
Sh14

プロパティーに「x」という名前を付けてからタブを押して、プロパティーのタイプとして「integer」を指定します。"integer" とタイプしている間、Control + Spaceキーボードショートカットを押してタイプの名前をMPSで完成させることができます。

Sh15
Sh16

次に、"Y" と "radius" のプロパティーを追加すると、最初の具体的な概念は完了です。

四角

正方形の概念を作成するために独自を試みるべきです。円形に対して行った手順を繰り返すだけで、異なるプロパティーを作成することができます - upperLeftXupperLeftYで左上隅の座標を保持し、その後にsizeを続けて正方形の辺の長を指定します。結局のところ、これに到達する必要があります:

Sh19

最初の行に形状の概念を拡張することを忘れないでください。完成メニュー(Control + Space)が表示されている間、まだ文字をタイプすることができ、完成メニューで利用可能なエントリーを除外するのに使われることに気づいたかもしれません。

キャンバス

2つの図形を作成したら、次にすべて絵画の中に保持するための概念を定義します。キャンバスと呼ばれる別の概念を作成します。それは形から構成されるシーンを表します。ユーザーは複数のシーン(キャンバス)を作成することができます。これは互いに独立しており、形状を共有しません。各キャンバスは名前とそれが含む図形のリストを保持します。

それではまたしても言語の構造の側面を右クリックして新しい概念を作成し、それにキャンバスという名前を付けます。

Sh20

タブを使用して) implementsセクションの "<none>"テキストに移動し、INamedConceptを指定します(入力するかControl + Spaceを使用します)。INamedConceptキャンバスが今実装するコンセプトインターフェースです。コンセプトインターフェースは、概念と同様に、実装する新しい機能を概念に追加します。私達の場合のINamedConceptキャンバスnameプロパティーで強化しているため、キャンバスインスタンス(ノードと呼ばれる)はnameプロパティーを持っているためユーザーは容易に区別することができます。

Sh21
Sh23

キャンバスはペインティングシーンを表し、それ自体は他の概念の一部にはなりません(モデル内に親はありません)ため、インスタンスはルートになることができることを示します。これにより、キャンバスインスタンスをASTのルートにすることができます。

キャンバス図形を保持できることを示すために、図形の子コレクションを作成します。繰り返しますが、セクションの "<< ... >>"セルにEnterキーを押し、子の名前とそれが保持できるノードのタイプを入力します。コード補完ダイアログを表示するための* * Control + Spaceキーショートカットを忘れないでください。

Sh24
Sh25

このような概念定義で終わるべきです:

Sh26

これで、ミニマル言語を使えるようにするのに十分な概念を作成しました。やるだけやってみよう。

初期の試乗

使用する前に言語を構築する必要があります。将来、言語定義を変更した後は、変更が反映されるように「再構築」のプロセスを繰り返すことを忘れないでください。プロジェクト・ビューの一番上のノード( 言語とソリューションを含むプロジェクト全体を表す最もルート)を右クリックし、プロジェクトの再ビルドを選択します。

Sh35

構築された言語は、サンドボックスソリューション内のモデルで使用できるようになります。モデルを右クリックしてインスタンス化するルートの概念を選択し、新しいキャンバスを作成するだけです。ルートの概念はこのメニューに表示され、モデル内の最上位レベルでインスタンス化できるものです。

Sh27

キャンバスインスタンスに名前を付けましょうそしてあなたの最初の絵を持っています。キャンバスに視覚的な図形を配置するために、言語で定義されている概念を使い始めることができます。

Sh28

Sh29

繰り返しになりますが、Control + Spaceはここで頻繁に使用するキーボードショートカットです。何を躊躇するたびにそれを使用してください。コード補完ダイアログには、言語で作成した2種類の図形が表示されます。

Sh30

Sh31

Sh32


図形のリストの最後の図形の末尾でEnterキーを押すと、追加の図形を挿入できます。ここでは、"circle"の最後の "}"記号です。Control + Spaceは図形の名前をタイプすることをあなたに惜しまないことに注意してください。

Sh33
Sh34

クール!あなたの成功をきちんと祝っていることを願っています。では、これらのエディターを調整してコードが画面上で見栄えよくなるようにしましょう。

エディター

MPSは投影エディターを使用します。エディターの振る舞いが期待していたものとは少し違っていると感じているかもしれません。テキスト・ベースの言語とは異なり、MPSはコードをプレーン・テキストとして表現しません。代わりに、MPSのコードは常に AST 抽象構文ツリーを意味します。

これには、言語設計、言語の合成可能性、および解析不可能な表記法に関する大きな利点があります。これらの表記法については、MPSの資料で詳しく読むことができます。

ここでは投影言語の編集面に焦点を当てるべきです。プレーンテキストのエディターはASTを確実に表現することができず、ASTを直接編集することは非常に不便であるため、投影型言語はその言語の一部であるすべての概念用のエディターを提供する必要があります。1つのコンセプトに対して複数の代替エディターが使用されることさえありますが、ここでのゴールではありません。MPSは多くの場合概念用のデフォルトエディターを提供するために良い作業をすることができます。これは言語のプロトタイプ作成にはとても便利です。しかし、エンドユーザーが便利に使用するためには、明示的なエディターを準備するためにしばらく時間を費やす必要があります。

形状

形状の概念は抽象的概念であるため、エディターは必要ありません。それで私達はこれをそのままにしておきます。

円形

円形では、必要なすべてのプロパティーを1行に収めるエディターを作成できます。エディターで円形の概念を開き、左下隅にある緑色の「+」ボタンをクリックしてエディター->コンセプトエディターを選択します。

Sh9a

Sh36

円形概念のために空のエディター定義を得るでしょう。覚えておいて、Control + Spaceはここでものを編集するために重く必要とされるでしょう。

Sh37

MPSのコンセプトのエディターはビジュアルセルで構成されており、各セルは基礎となるコンセプトに属する情報の一部を表しています。ノードはAST内で階層的に構成されているため、それらのエディターは画面上で構成され、サブノードのエディターはそれらの先祖のものの中にネストされています。

円形では、すべてのプロパティー(xyradius )の値とその周囲の任意のテキストをすべて1行で表示します。
そのため、最初にこれらのセルのレイアウトを選択します - インデントレイアウトはここで問題なく動作します。赤いセルでControl + Spaceを押して、リストからそれを拾います。角括弧に続けてマイナス記号を入力すると、検索が速くなります。

Sh38

行の先頭に配置される定数のテキストを入力するには、「circle」と入力します。

Sh39

新しいセルを作成するには、Enterキーを押します。次のセルにxプロパティーの値が含まれていることを示すには、"x:"と入力します。

Sh40
Sh41

新しいセルを作成するには、もう一度Enterキーを押します。新しいセルを追加するときは必ず最初にEnterキーを押してから、完了メニューから挿入するセルの種類を選択してください(Control + Space)。

セルを正しいプロパティーにバインドするには、コード補完メニューからxプロパティーを選択する必要があります。{x}と入力しないでくださいControl + Spaceを使用して補完メニューを表示し、メニューからxプロパティーを選択します。

Sh42

yradiusプロパティーの値と同様に一定のテキストを保持するセルを挿入するために独自で続けることができます。Enterキーを押すと新しいセルが挿入され、Control + Spaceではコード補完メニューが表示されます。このようなエディターになってしまうはずです。

Sh43

四角

四角にもエディターが必要です。エディターで四角の概念を開き、左下隅の '+'記号を押して新しいコンセプトエディターを作成します。前のセクションの指示に従って、次のようにエディター定義を入力します。

Sh44

確かに独自でこれをすることができます。

キャンバス

キャンバスコンセプト用のエディターは少し異なります。なぜなら、全てスクリーン上のいくらかのスペースを与える必要がある形状のコレクションを保持するからです。キャンバスはこのように複数の線にまたがって広がり、各線はキャンバスの形状の集合から1つの形状を示します。ただし、以前と同じ方法で開始し、キャンバスの概念を開き、「+」記号を押して新しいコンセプトエディターを作成し、インデントレイアウトを挿入して次のテキストを入力します。

Sh45

赤のセルをnameプロパティーにバインドします。このプロパティーはINamedConceptのコンセプトインターフェースから継承されているため、完成メニューの方に表示されます(Control + Space)、ただし必ず表示されます)。

Sh46

波括弧がそれをラップしているのを見ることができるなら、正しくnameプロパティーを挿入したことを確認します。(注意してください。これらの波括弧を独自で挿入することになっていません。それらはすべてのプロパティーセルのためにMPSによって追加されます。)
次のセルは、キャンバスに追加された形状のコレクションを保持します。ここでエディターを構成する方法に注意してください - キャンバスは個々の図形が編集されるべき領域をマークするだけで、それらがその領域をどのように使用するかを図形に任せます。
図形は1行に1つずつ縦に並べられるため、補完メニューから縦のコレクションレイアウトを選択する必要があります。

Sh47

ここに注意してください。とは異なるレイアウトを選択した場合、図形は上下に並んでいるためはなく、おそらく同じ行に並んでいるため、最も直感的に言語を使用することはできません。

Sni mek obrazovky 2018 12 06 v 14 51 05

赤のセルをキャンバス図形の子コレクションにバインドする必要があります。

Sni mek obrazovky 2018 12 06 v 14 51 26


Sni mek obrazovky 2018 12 06 v 14 51 50

ここで、コレクションをキャンバスの名前に配置するには、Alt + Enterショートカット(またはlight-bulb記号)を使用してインテンションポップアップメニューを表示し、Add On New Lineを選択します。

Sni mek obrazovky 2018 12 06 v 14 52 08

誤って "新しい行を追加" を押した場合は、Control/Cmd + Zでその操作を元に戻します。.
最終的なエディターの定義が表示されます。

Sni mek obrazovky 2018 12 06 v 14 52 24

バージョンが違って見える場合は、いくつかの理由が考えられます。

  • 完了メニューからnameプロパティーを挿入しました。「name」と入力しただけの場合、セルはnameプロパティーにバインドされていない可能性が最も高く、使用時にはテキスト「name」のみが表示されます。

  • "Add On New Line" インテンションを設定します。誤って "Add New Line"を選択した場合、図形セルは "Painting ..."の最初の行には描画されず、その隣に描画されます。

  • シェイプセルとは異なるセルに新しい行に追加プロパティーを設定した場合、レイアウトも予想されるものとは異なります。

  • シェイプコレクションに垂直以外の異なるレイアウトを選択しました。異なるレイアウトは異なるシンボルを使用します。垂直は「(>」を使用し、「(-」と「(/」はそれぞれインデントと水平レイアウトに属します。

これらすべての場合において、繰り返しの元に戻す (Control/Cmd + Z)が役立ちます。

2回目の実行

これでプロジェクトを再ビルドし(プロジェクト・ビューの一番上のノードを右クリック)、のサンドボックスコードを見ることができます。

Sh53

コードレイアウトがどのように変わったか参照してください。

Sh54

これは同じコード(AST)ですが、画面上では編成が異なります。以前は波括弧をたくさん含んだ醜い木のようなテキストでしたが、今やコードはMPSに提供したエディター定義を反映しています。

見方が異なる場合は、3人のエディターに戻ってください。サイズがかなり小さいため、必要に応じて削除してやり直してください。エディターアスペクトモデルのプロジェクト・ビューでそれを見つけて削除を押すか、右クリックしてコンテキストメニューで削除を選択すると、エディター定義全体を削除できます。あるいは、疑わしく見えるコードをすべて削除するまで、エディター定義内の削除ボタンとバックスペースボタンを押し続けることもできます。

色指定

今度は形状に戻って色のサポートを追加します。円形四角はどちらも形状を継承しているため、どちらも色を継承します。

言語のユーザーが定義済みの色のリストから形の色を選ぶことができるようにしたいため、色の値を保持するためにテキストプロパティーを使うことはできません。代わりに、形状への参照を追加し、この参照を事前定義済みの色定数の1つを指すようにします。定義済みの色を表すような定数を作成することから始めましょう。

色の概念

1つの方法は、色を定義するためにMPS列挙型を使うことです。ただし、これではユーザーは自分の色を定義できません。すべての色は、Shapes言語の一部となる列挙型で定義されています。代わりに、色については本格的な概念を使用し、その概念のノードによって個々の色を定義します。これらのカラーノードは、言語の一部として(いわゆるアクセサーリモデル内で)定義することも、キャンバスコンセプトのインスタンスの隣のユーザーモデルで直接定義することもできます。

まず、色定数を表す概念を作成します。とルート化できるため、モデル内に配置できます。

Shx1

エディターも必要です。

Shx2

定義済みの色

それでは、プロジェクトを再構築してください。追加したばかりのの概念は、色を作成するためにそれを使用できるようにコンパイルする必要があります。概念の具体的なノードを提供する必要があります。それは個々の色定数を表しそして私達の言語のユーザーが彼らのキャンバスから参照できるようになるでしょう。これにはアクセサーリーモデルを利用します。アクセサーリーモデルは任意のノードを保持する言語定義内のモデルです。これらのノードは言語の一部になり、言語ユーザーに表示されます。

それで最初に、言語でアクセサーリーモデルを作成する必要があります。

Shx7

モデルは名前を要求します。MPSでステレオタイプボックスが無効になっていない場合は、ステレオタイプボックスが空であることを確認してください。

Shx8

の概念を宣言する図形言語は、アクセサーリーモデルにインポートする必要がある唯一の言語です。

Shx10

使用言語タブに切り替えます。それは空か、リストに残すことができるdevkitを含みます。プラス記号をクリックして、リストから図形言語を選択します。その言語は使用言語のリストに追加されていなければなりません。

次に「 詳細設定」タブに切り替えて、「生成しない」チェックボックスを選択します。

GenShap

次にOKをクリックしてダイアログを閉じます。

色を作成する

これで、新しく作成したアクセサーリモデルに色定数を作成できるはずです。

Shx11

新規メニューにが表示されない場合は、おそらく言語を再構築するのを忘れています。それとも、trueに設定する必要がありコンセプトの可能ルートプロパティーを逃しました。

Shx12

依存関係への最初の接触

MPSの重要な知識は、依存関係とインポートされた言語を処理する方法です。モジュールまたはモデルの依存関係を表示するには、左側のプロジェクト・ビューパネル(パネルを開くにはAlt/Cmd + 1)でそれに移動する必要があります。図形言語でそれを試してください。ツリーでそれを選択してください。

Sh70

Alt + Enterを押す(またはそれを右クリックしてモジュール/モデルのプロパティーを選択する)と、モジュール/モデルのプロパティーを含むダイアログが表示されます。依存関係タブには、現在のモジュール/モデルが依存しているモジュール/モデルが表示されます(Javaのインポート、Rubyのインポートなど)。

Shx100

今は空っぽです。'+'ボタンを使って要素を追加します。小さな検索ダイアログで、目的の依存関係の名前を数文字入力して検索を絞り込み、正しいものを見つけたらEnterを押します。

Sh72

使用言語セクションで、モジュール/モデルでどの言語(構文)を使用できるようにするかを指定します。

Shx101

ここでは何も変更する必要はないため、OKボタンをクリックして続けましょう。

色参照のための概念

今私たちの言語は私たちのコードで図形の望ましい色を示す方法を必要としています。形状図形言語のアクセサーリモデルの色定数の1つを参照しているはずです。ユーザーが形状の色を指定しようとしているときはいつでも、MPSは自動的にすべての利用可能な色定数を補完メニューに表示します。

構造アスペクトモデルに新しい概念を作成し、カラーリファレンスという名前を付けます。

Shx3

カラーリファレンスは、単一の色定数(コンセプトのノード)を指す参照(AST階層を横切るポインタ)を保持します。

色を表示し編集するためにはカラーリファレンス用のエディターも必要です。

Shx4

参照は単にそれが参照する色定数の名前を表示する必要があるため、コード補完メニューからtargetを選び、色定数のnameプロパティーがユーザーに表示したいものであることを指定します。

Shx5

次のようにエディターの定義を取得する必要があります。

Shx6

形状を更新する

円形四角の両方がそれを継承するため、形状概念は我々の新しいカラーリファレンスを置くための良い場所です。エディターで開き、変更を加えます。

Sh96

形状は色のためのエディターを定義するためのエディターコンポーネントを定義することもでき、円形と同様に四角はそれらのエディターコンポーネントをそれらのエディターで再利用することができるため重複を避けることができます。

「+」記号を押して、新しいエディターコンポーネントを作成してください。

Sh97

Sh98

エディターコンポーネントはすでに慣れ親しんだ言語を定義しているため、インデントレイアウトを簡単に指定でき、定数テキストセルとそれに続くcolorプロパティーにバインドされたセルを定義できます。

エディターコンポーネントを埋め込む

形状用に定義されたエディターコンポーネントが、円形および四角用のエディターに追加されました。

Sh99

Sh100

Sh101

エディターコンポーネントは、エディターのレイアウト内の別のセルになります。

3回目の実行

今度は言語を再構築する最もよい時期です。プロジェクト・ビューの言語ノードを右クリックして「言語の再構築」を選択します。

プログラムを開くと、赤の色のための空のセルが表示されるはずです。それらの中でControl + Spaceを試すと、選ぶことができる色のリストを得るでしょう。

Shx13

Shx14


私たちの言語は完全に定義されています。キャンバスを作成し、それにサークル四角を追加して、それらの位置、サイズ、色を指定することができます。それはそのような短い期間のかなりの成果です。

まだ欠落しているのは、これらのプログラムをJavaに変換することです。そのため、実行して、画面上にうまく描かれた形を見ることができます。続けるなら、すぐにそこにいるということにすぐに気づくでしょう。

生成プログラム

言語は、コンパイルして実行できるコードを生成できるように、ジェネレータを必要としています。DSLのターゲットとしてBaseLanguageを選択します。BaseLanguageはMPSと一緒に配布されるJavaのコピーであるため、Javaコンパイラがバイナリにコンパイルするためのテキスト形式のJavaソースに簡単に変換できます。そのターゲット言語の定義をプロジェクトにプラグインするのであれば、他のターゲットプラットフォームと言語を選択することもできます。

ジェネレータは非常に簡単で、いくつかのルールと単一のマッピング設定のみを必要とします。

Tg1

言語はすでに空のジェネレータのスケルトンを含んでいます。マッピング設定を開くことができます。これは、どのルールをいつ適用するかを指定します。ここで設定エントリを徐々に追加していきます。

これがジェネレータの背後にある、実装するという考えです。

  • キャンバスはJavaクラスに変換されます。これは、JavaのJFrameクラスを拡張し、すべての図形が描画されるJPanelを保持します。

  • 形状グラフィックスオブジェクトのメソッド呼び出しに変換され、JPanel上に図形を描画します。

  • カラーリファレンスは、java.awt.Colorクラスの適切な色定数への参照に変換されます。

キャンバスのクラスから始めましょう。キャンバスはルートの概念なので、ルートマッピングロールに新しいエントリを追加する必要があります。Enterを押して新しい空のルールを挿入します。

Tg2

ポップアップメニューから "New Root Template"を選択できるようにインテンションAlt + Enter))を使用する必要があります。

この規則は、キャンバスノードをJavaクラスに置き換える必要があることを定義します: テンプレートはどのクラスで定義します:

Tg3

ルートテンプレートはJavaクラスを生成するはずなので、"class" を選ぶ必要があります。

Tg4

これが終了ルートマッピングルールです。map_Canvasは、ジェネレータで作成されたルートテンプレートの名前です。変更することができるように、それを開くべきです。

Tg5

まず、JDKモジュールに依存するようにジェネレータモジュールの依存関係を設定する必要があります。この依存関係がなければ、サンドボックスを最終的にコンパイルすることはできません。

注意Alt + Enterは左側のプロジェクト・ビューで選択されたノードのプロパティーを表示します。

Shxx4

次に、ジェネレータモデルは、java.swingjava.awtに依存しなければなりません。これらの依存関係がなければ、ジェネレータテンプレートの実装に必要なJava Swingコードを入力することはできません。

Shxx3

依存関係があれば、生成されたJavaクラスの一部となるJavaコードを入力し始めることができます。それからキャンバスからの値でコードをパラメータ化して、それがユーザーの意図を反映するようにします。

クラスはJFrameを拡張する必要があります。

Tg8

実行可能なJavaクラスを取得するためのmainメソッドを追加します。"psvm"ライブテンプレートを使用してメソッドに素早く入ることができます。

Tg9

Tg10

メソッド内で、map_Canvasをインスタンス化する必要があります。

Tg11

フレームを初期化するためのメソッドも必要です。「method」と入力し、Control + Spaceを使用してメソッド定義を完成させます。

Tg12

メソッドのInitialize()を呼び出し、メソッドメインから呼び出されていることを確認します。

Tg13

すべての形状はJPanel上に描かれるため、今度はそれをフィールドとして追加する必要があります。

Tg14

Tg15

JPanelを少しカスタマイズできるように、匿名の内部クラスを使用しています。

重要 : BaseLanguageで匿名の内部クラスを作成するには、new JPanel()の直後と末尾のセミコロンの前にカーソルを置きます。それから "{"(左波括弧)キーを押すとMPSが最後の "}"記号を追加します。パネルの匿名内部クラスにメソッドを追加するには、これらの "{"と "}"の間にカーソルを置いてください。

JPanelのpaintComponentメソッドをオーバーライドします。これは、JavaによってJPanel上に図形を簡単に描画できるためです。JPanelメソッドの上書きダイアログを呼び出してpaintComponentメソッドを選択するには、カーソルがJPanelの "{"と "}"記号の間の無名クラス本体内にあるときにControl/Cmd + Oを押します。

Tg16

スクリーンショットに表示されているように、paintComponent()メソッドがJPanelの匿名内部クラス内に正しくネストされていることを確認してください。また、それがpaintComponentsではなく、paintComponentと呼ばれていることも確認してください。

メソッドに次のコードを入力します。

Tg17

では、初期化メソッドを入力してください。テンプレートを用意してください。

Tg18

テンプレートのパラメータ化

templateのコードは現在、入力モデルの値を使用していません。それは単にコードをハードコードしているため、テンプレートによって生成されたコードは、ユーザーモデルでどんな形状が作成されても、常に同じになります。これは変わります。テンプレートは入力モデルに反応する必要があり、生成されたコードは形状、サイズ、色を反映する必要があります。キャンバスのプロパティーと子はマクロを通してテンプレートに挿入されるべきです。MPSには3種類のマクロがあります。

  • プロパティーマクロ - 入力モデルからプロパティーを挿入する

  • ノードマクロ - テンプレート内のノードを入力モデルのノードと置き換える

  • 参照マクロ - 入力モデル内のノードを指すようにテンプレート内の参照を調整する

徐々にこれらすべてを使います。

まず最初に、生成されたクラスの名前とフレームのタイトルキャンバスの名前でカスタマイズします。クラス名 - map_Canvasにカーソルを合わせてAlt + Enterを押します。

Tg19

Tg20

今すぐポップアップメニューからnode.nameプロパティーマクロを選択します。

Tg21

"map_Canvas"テキストは、nameプロパティーをキャンバス名前に変更するプロパティーマクロでラップ(注釈)されています。インスペクターパネル(Alt + 2)を使用して、プロパティーマクロを入力または変更することもできます。現在それは現在のキャンバスの名前であるnode.nameの値を返します。

これで、「タイトル」テキストを折り返してフレームのタイトルをカスタマイズできます。Control/Cmd + Up Arrowキーショートカットを使用して、周囲の "文字なしでテキスト"タイトル " を選択し、Alt + Enterで正しいプロパティーマクロを挿入します。

Tg22

コードは次のようになります。

Tg23

図形を描く

テンプレートは、JPanelフィールドのpaintComponentメソッド内に図形を描画するコードを配置する必要があると想定しています。ステートメント "System.out.println("ここに描画 ");"すべての図形を描画する実際のコードのプレースホルダーとして機能します。COPY_SRCマクロを使用して、プレースホルダーステートメントを単一の図形を描画するステートメントに置き換えます。次に、LOOPマクロを利用して、現在のキャンバスで定義されているすべての図形についてそれを繰り返します。

今すぐControl/Cmd + Up Arrowキーショートカットを使用している閉じるセミコロン含むプレースホルダステートメントを選択し、Alt + Enterを押して、現在のキャンバスのすべての子図形を介してループするLOOPマクロを挿入するために、適切なノードマクロオプションを選択します。

Shxx1

繰り返しになりますが、インスペクターAlt + 2)はバインディングコードを示しています。

Tg25

LOOPマクロに赤の下線が引かれている場合は、インテンションを適用する前に行全体を選択していない可能性があります。元に戻して、セミコロンを含む行全体を選択して、LOOPマクロを追加 インテンションをもう一度適用します。
LOOPマクロは "System.out.println(" Draw here ");"を繰り返します。node.shapesにリストされている各形状のステートメント。

しかし、"System.out.println("ここに描画 ");"が必要です。ステートメントは、これらの各図形を描画するコードに置き換えられました。COPY_SRCマクロはまさにそれをするでしょう。もう一度、セミコロンを含めて LOOPマクロ内の文全体を選択し、Alt + Enterを押してノードマクロを選択してください。

Shxx2

COPY_SRC (Control + Space) と入力すると、マクロが起動し、LOOPマクロが提供しているすべてのシェイプの現在のシェイプで "System.out.println("Draw here");" を置き換えることができます。

Tg27

Tg28

COPY_SRCマクロが、セミコロンを含めて文全体を、イメージに表示されているように囲むようにしてください。そうでない場合は、元に戻してステートメント全体を選択してから、COPY_SRCマクロをもう一度挿入してください。

円を生成する

これでキャンバスをJavaクラスに翻訳することができ、また図形が描画するコードを追加する場所を作りました。図形自体の実際の変換規則を定義する時間が来たため、円形形状の代わりに生成されたコードに "graphics.drawCircle()"メソッドを挿入します。メインのマッピング設定を開き、「リダクションルール」セクションに新しいエントリを追加する必要があります。

Tg29

新しいテンプレートを作成するAlt + Enter

Tg30

新しいreduct_Circleテンプレートが左側のプロジェクト・ビューに表示されます。

Tg31

四角の削減規則を作成することもできます。

Tg32

reduce_Circleテンプレートを開きます。サークルに代わるJavaコードを指定する必要があります。Javaコードは、paintComponentメソッドmap_Canvasに配置されることを、覚えておいてください。

Tg33

まず、ブロックステートメントを入力します。これでテンプレートがラップされます。

Tg34

同じ名前のpaintComponentパラメータのプレースホルダとしてグラフィックス型のローカル変数が必要です。それでもブロックステートメント

Tg35

Tg36

Tg37

Javaで円を描くには、グラフィックスオブジェクトを使用して最初に色を設定し、そのdrawOvalメソッドを呼び出します。以下のコードを入力してください。

Tg41

Tg38

次にControl/Cmd / Up Arrawを使用して内側のブロックステートメントを選択し、Alt + Enterlight-bulb)を押してインテンションメニューから「Create Template Fragment」を選択します。これは選択されたコードの断片を実際のテンプレートとしてマークし、最終的にmap_Canvasに配置されます。

Tg39

パラメータ化

コードは円形ノードからの実際の値でパラメータ化される必要があります。

Tg42

最初の値 "10"は、円形ノードのx座標に置き換えます。プロパティーマクロがそれを行います。同様に、2番目の値 "10"はy座標に置き換えます。

Tg43

3番目4番目の値 "10"は、両方ともノードの半径値に置き換えます。

Tg44

最後に、"Color.red"カラープレースホルダの参照は、円形ノードのカラー参照の実際のターゲットに置き換える必要があります。参照を置き換えるために参照マクロを使用します。カーソルを「赤い」単語の上に置き、Alt + Enterを押してください。

Tg45

参照マクロは、インスペクターウィンドウで指定したノードへの参照でへの参照を置き換えます。

Shx102

参照関数は文字列値(参照する宣言の名前)またはノード<StaticFieldDeclaration>StaticFieldDeclarationを表すノード)のいずれかを返します。これは、自体はノード<StaticFieldDeclaration>への参照であるためです。実際、java.awt.Colorクラスのすべての色定数はStaticFieldDeclarationsとして宣言されています。

そのため、参照マクロ内での作業は、円形がその色子として設定した色に対応するクラス内からStaticFieldDeclarationを取得することです。これはプログラム的に行うため、正しいモジュールとモデルに依存関係を設定する必要があります。これにより、必要なコードを書くことができます。

まず、ジェネレータモジュールは、その言語で宣言されているStaticFieldDeclarationの概念を参照できるようにするためにBaseLanguageに依存する必要があります。

Shx104

次に、ジェネレータモデルは、図形言語の構造で定義されている概念を参照できる必要があります。

Shx105

これらの言語をインポートすると、クラス内で正しい静的フィールド宣言を発見するコードを入力できるはずです。

Sni mek obrazovky 2018 12 07 v 20 29 44

node-ptr /.../コンストラクトを使用すると、指定された概念でインポートされたモデル内の、指定された名前で表されるノードを取得できます。JDKにはクラスが1つしか存在しないため、node-ptr /色/として識別される参照は一意になり、モデル内でクラスを指すようになります。

:補完メニューから正しい要素を選択してください。それは図形言語からの概念ではなく、java.awt.Colorでなければなりません。

Sni mek obrazovky 2018 12 07 v 20 30 23

ノードポインタは、ノードへの永続的な参照を表します。メモリ内の実ノードへの参照を取得するには、モデルポインタ内でノードポインタを解決する必要があります。次のコードを使用してリポジトリを取得し、そこからノードを解決します。

Sni mek obrazovky 2018 12 07 v 20 31 33

ダウンキャスト演算子を使用すると、基礎となるJava APIにアクセスできます。現在、この場所にリポジトリを取得する唯一の方法です。

Sni mek obrazovky 2018 12 07 v 20 44 23

コレクション言語を使用すると、簡潔なクエリを完成させることができます。

Sni mek obrazovky 2018 12 07 v 20 33 23

node円形の概念のインスタンスなので、node.colorは色に対する円の参照(カラーリファレンスのインスタンス)であり、node.color.targetアクセサーリモデル(Shapes.Colorの概念のインスタンス)です。

簡単に言うと、このクエリは、円形に指定された色の名前と同じ名前で、java.awt.Colorクラスの静的フィールド宣言内の最初の静的フィールド宣言を検索します。

正方形を減らす

サークルに対してジェネレータがどのように行われるかを模倣し始めます。同様に、reduce_Squareテンプレートに次のコードを提供します。

ヒント : ブロックステートメントを挿入することから始めます


Tg47

"drawRect"に渡された値は、四角のupperLeftXupperLeftY、およびsizeプロパティーを持つプロパティーマクロで置き換える必要があります。

Tg40

コードの生成

これでジェネレータの定義は終わりです。言語を再構築する場合は、を開き、それを右クリックしてPreview Generated Textを選択します。

Tg48

JFrameを正しく初期化し、すべての形状を描画する、うまく構造化されたJavaコードが得られます。

ppview2

コードが異なる場合は、ジェネレータテンプレートの1つを調べましょう。これらはおそらくチュートリアルで提示されているものとは異なります。あなたのマクロが正しいコードにアタッチされていないか、マクロのインスペクターウィンドウで指定された値がスクリーンショットのものと異なっているかもしれません。

コードがコンパイルされない場合は、以前に定義したように、ジェネレータモジュールがJDKモジュールに依存していることを確認してください。

Squaresのためのよりロバストな世代

テンプレート内でグラフィックスローカル変数を処理する方法が正しくありませんでした。おそらくは楽観的すぎて、map_Canvasreduce_Circle、およびreduce_Squareで変数名が同じであること頼り ました。これら3つのテンプレートの変数の名前が同じでないとどうなりますか?より堅牢なソリューションが必要です

円形ジェネレータのセクションで前述したように、グラフィックスローカル変数とmap_Canvasテンプレートが生成するグラフィックスパラメータを正しく関連付けるために、reduce_Squareテンプレートを使用します。名前の一致に頼ることはそれほど堅牢ではありません。

基本的に3つのステップを踏む必要があります。

  1. 作成されたグラフィックスパラメータ用のストレージを定義する

  2. map_Canvasテンプレートにグラフィックスパラメータを保存します

  3. reduce_Squareテンプレートの適切なグラフィックパラメータを取得する

マッピング設定でマッピングラベルを作成することから始めます。これはパラメータ宣言のストレージになり、それぞれキャンバスによって識別されます。このマッピングラベルは、キャンバスパラメータ宣言にマッピングする辞書として考えることもできます。

shapes3001

graphicsParamマッピングラベルには、キャンバスによってマッピングされたパラメータ宣言が属しています。

map_Canvasテンプレートは、グラフィックラベルをマッピングラベルに格納する必要があります。MAP_SRCマクロはそれを大いに成功させて利用することができます。

shapes3002

パラメータ宣言(型を含む)をMAP_SRCマクロ(Alt + Enter、選択ノードマクロ、型MAP_SRC_)。_Inspectorにウィンドウでラップしてから、生成されたパラメータ宣言を格納するために使用するマッピングラベルを選択します。キャンバスの概念のインスタンスである現在のソースノードは、マッピングラベルで生成されたグラフィックパラメータ宣言を識別するためのキーとして使用されます。

最後に、reduce_Squareテンプレートのマッピングラベルからパラメータ宣言を取得する必要があります。名前の一致に依存しなくなったことを明確に示すために、グラフィックとは異なる名前を変数に使用できます。サンプルではgを使います。

shapes3003

g参照でAlt + Enterを選択して参照マクロを選択すると、マッピングラベルから適切なグラフィックパラメータを取得できます。

shapes3004

次に、2番目のg参照に対して参照マクロの作成を繰り返します。作成したばかりのg変数参照に付加されている両方参照マクロは、インスペクターで目的の参照先の取得方法に関する詳細を指定する必要があります。genContextオブジェクトは、現在の生成セッションの有用なメソッドとプロパティーへのアクセスを提供します。genContextで " ラベルと入力の出力を取得 "操作を使用して、graphicsParamマッピングラベルと現在生成されている四角を保持するキャンバスを指定します。

shapes3005

これで、reduce_Circleテンプレートのgraphicsパラメータの取得も複製できました。

コードを実行する

生成されたコードを見るのはうれしいことですが、実際に実行してみるのを好むかもしれません。MPSは生成されたJavaコードを簡単にコンパイルして実行することができます。キャンバスは実行可能なJavaクラスに生成されるため、キャンバス自体は実行可能な、または「メイン」クラスとして扱われるべきであることを示すだけで済みます。キャンバスIMainClassインターフェースを実装させるだけで、あとはMPSが行います。IMainClassインターフェースはjet brains.mps.execution.util言語から来ているため、それを私たちの言語の依存関係のリストに追加し、スコープを拡張に設定する必要があります。

Tg50

プロパティーダイアログを表示するにはAlt + Enterを使用してください。言語は拡張としてマークされる必要があることに注意してください。

Convasのコンセプトで、implementsセクションにIMainClassインターフェースを追加できるようになりました。

Tg52

言語を再構築してからプロジェクト・ビューを右クリックして「実行」をクリックします。

Tg53

あなたの努力の報酬としてあなたの絵が描かれた実行中のJavaアプリケーションを手に入れるでしょう。

Tg54

代替ジェネレータ - XMLを生成する

xmlなどの宣言型言語でコードを生成するためにジェネレータをどのように利用できるかを考えてみるために、ここではxmlを生成するShapes言語用の簡単なジェネレータを紹介します。空のジェネレータから始めます。Javaテンプレートとルールはすべて削除されました。

Sni mek obrazovky 2018 12 18 v 12 55 47

まず、jetbrains.mps.core.xml言語をインポートする必要があります。(Control + L)。BaseLanguageがJavaと同じ投影法であるのと同様に、これはxmlと同じ投影法です。

ルートマッピングルールは、XMLファイルキャンバス ESを変換するために作成する必要があります。

Sni mek obrazovky 2018 12 18 v 12 56 04

Sni mek obrazovky 2018 12 18 v 12 56 16

map_Canvasという名前のテンプレートが作成されます。

Sni mek obrazovky 2018 12 18 v 12 56 34

必要なコードを作成するためには、XMLコードをテンプレートに入力する必要があります。

Sni mek obrazovky 2018 12 18 v 12 56 44

Sni mek obrazovky 2018 12 18 v 12 57 01

name属性を挿入するには、"space"に続けて "name ="と入力します。

Sni mek obrazovky 2018 12 18 v 12 57 15

プロパティーマクロは、name属性値の内容に設定する必要があります。

Sni mek obrazovky 2018 12 18 v 12 57 28

Sni mek obrazovky 2018 12 18 v 12 57 48

もう少しxmlを挿入する必要があります。

Sni mek obrazovky 2018 12 18 v 12 58 08

すべての図形のプレースホルダーを作成します。

Sni mek obrazovky 2018 12 18 v 12 58 25

Control/Cmd + Upでプレースホルダのxml要素を選択します。

Sni mek obrazovky 2018 12 18 v 12 58 42

次に、COPY_SRCLマクロを挿入してキャンバスのすべての形状をループ処理し、それらの縮小規則をトリガーします。

Sni mek obrazovky 2018 12 18 v 12 59 28

Sni mek obrazovky 2018 12 18 v 12 59 40

生成されたxmlファイルの名前は、プロパティーマクロを使用してカスタマイズすることもできます。

Sni mek obrazovky 2018 12 18 v 14 40 49

Sni mek obrazovky 2018 12 18 v 14 40 57

四角円形のための削減規則は今作成される必要があります:

Sni mek obrazovky 2018 12 18 v 12 59 57

Sni mek obrazovky 2018 12 18 v 13 00 20

円形四角用のテンプレートは、それらのルートとしてXmlElementを保持する必要があります。

Sni mek obrazovky 2018 12 18 v 13 01 32

その後、xmlテンプレートを完全に構築する必要があります。

Sni mek obrazovky 2018 12 18 v 13 02 04

テンプレートフラグメントは、xmlコード全体の周囲に作成する必要があります。

Sni mek obrazovky 2018 12 18 v 13 02 48

Sni mek obrazovky 2018 12 18 v 13 03 07

TF記号はテンプレートフラグメントを示します。

Sni mek obrazovky 2018 12 18 v 13 03 16

プロパティーマクロはテンプレートをパラメータ化するために使用されるべきです:

Sni mek obrazovky 2018 12 18 v 13 03 27

正しい値が使用され、整数から文字列に変換されるように、プロパティーマクロをインスペクターでさらに指定する必要があります。

Sni mek obrazovky 2018 12 18 v 13 04 02

y xml属性についても同じことを繰り返す必要があります。

radiusでは、専用のxml要素を使います。

Sni mek obrazovky 2018 12 18 v 13 05 08

Sni mek obrazovky 2018 12 18 v 13 05 25

カラーリファレンスについても同様です。

Sni mek obrazovky 2018 12 18 v 13 07 31

四角のテンプレートはよく似ています。

Sni mek obrazovky 2018 12 18 v 13 09 27

ジェネレータは4つのルートノードを保持しているはずです。

Sni mek obrazovky 2018 12 18 v 13 09 53

言語を再構築してサンドボックス用に生成されたコードをプレビューすると、次のようなxmlファイルが表示されるはずです。

Sni mek obrazovky 2018 12 18 v 13 10 22

次に何をすべきか

おめでとうございます。MPSの入門チュートリアルはこれで完了です。

これで、言語に図形を追加して自分で続けることができます。ポイント、ライン、トライアングル、レクタングル、カラフルな塗りつぶしのある図形は、私たちの小さな言葉に加えて素晴らしいかもしれません。

MPSをさらに徹底的に理解したいのなら、詳細な計算機のチュートリアルを試すのがよいでしょう。これは多くの高度な概念を探り、コード生成、型システムとスコープについてさらに多くを教えるでしょう。

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

関連ページ:

MPSへのファストトラック - 習得するための10のステップ

ようこそ! このチュートリアルは、MPSにまったく慣れておらず、MPSの風景を見ながらのガイドツアーを好む開発者のために特別に設計されます。次に進むべき場所を示す明確なマークに従って、殴打された道を一度に1歩歩きます。情報は、より単純な概念からより複雑な概念へと進み、旅の終わりにMPSを理解し、あな...

エディターの指示

MPSでコーディングするとき、通常テキストエディターでコードをタイプする方法とMPSでコードがどのように編集されるかの間にいくつかの違いがあるのに気付くでしょう。MPSでは、射影エディターを使ってコードを入力するときにASTを直接操作します。エディターはあなたにテキストを編集するような錯覚を与えます...

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

バージョン3.1からMPSにバンドルされている図形サンプルプロジェクトをチェックしてください。それはエディターでいくつかの素晴らしいトリックをすることができます。サンプルプロジェクトは、最初の実行時にMPSによって自動的にインストールされ、$USER_HOME/MPSSamplesに配置されます。デ...

MPS電卓言語チュートリアル

このチュートリアル導入、テンプレートの実装、導入このチュートリアルでは、MPSでの言語デザインのさまざまな分野について説明します。単純なスタンドアロン言語の抽象的な構造を定義し、そのためのエディターを設計し、タイプを制限し、スコープを作成し、最後にJavaコードを生成するジェネレータを準備します。以...