MPS 2020.1 ヘルプ

TextGen

TextGen 言語アスペクト

導入

TextGen 言語アスペクトは、テキスト変換へのモデルを定義します。モデルを直接テキスト形式に変換する必要があるたびに便利です。この言語には、テキストを出力し、ノードをテキスト値に変換し、出力に合理的なレイアウトを与えるための構成要素が含まれています。

操作

append コマンドは変換を実行し、結果のテキストを出力に追加します。モデルの問題を報告するために found error コマンドを使用できます。with indent コマンドは、インデントを大きくしてブロックを区別します。あるいは、深さ増加コマンドおよび深さ 減少コマンドは、ブロック構造に限定されることなく、現在のインデント深さを操作します。indent buffer コマンドは、現在の行に現在のインデントを( ident または深さの増減で指定されたとおりに)適用します。

演算命令

引数

append

任意の数

  • {string value} , 挿入するには "char を使うか、補完メニューから定数を選んでください。

  • \n
  • $ list {node.list} - 区切りなしのリスト

  • $ list {node.list with、} - セパレータ付き (セパレータを追加 / 削除するインテンションが利用可能です)

  • $ ref {node.reference}、たとえば $ ref {node.reference <target>} - 廃止予定のため削除されます

  • ${node.child}
  • ${ 属性付きノード } $ - 属性ノードで使用可能、属性付きノードへの委譲

found error

エラーテキスト

decrease depth

これからインデントレベルを下げます

increase depth

これからインデントレベルを上げる

indent buffer

現在の行に字下げを適用する

with indent { <code> }

のインデントレベルを上げる

インデント

根本的な原則を理解すれば、正しいインデントは簡単に得られます。TextGen は AST をテキストにフラッシュします。TextGen コマンドは単に出力バッファを順番に操作して、一度に 1 ノードずつそこにテキストを出力します。現在のインデントの深さ(インデントバッファ)を保持している変数は、それぞれの根の概念に対して保存されます。インデントバッファはゼロから始まり、深さの増減indent コマンドで変更されます。

ただし、「インデント」は append コマンドで明示的に出力ストリームに挿入する必要があります。ブロックを単に indent でマークしても、ラップされた TextGen コードによって生成されたテキストは自動的にはインデントされません。with indent ブロックはインデントバッファの値を増やすだけですが、個々の追加は現在のサイズのインデントバッファを前に付けることを望むかもしれません。

インデントバッファを出力ストリームに明示的に挿入する方法は 2 つあります。

  • インデントバッファコマンド

  • append コマンドのパラメーターに対するインスペクタの indent フラグ付き

例:定数のリストの中で定数を適切にインデントするために、発行された各行の先頭で indent buffer を呼び出します。これにより、インデントは各行の先頭にのみ挿入されます。

text gen component for concept Constants {  file name : Constants     extension : <no extension>                                                                                                                                                                                                                                                            encoding : utf-8                                                                                                                                                                                                                                                                        (context, buffer, node)->void {      append ${node.name} \n ;      with indent {        node.constants.forEach({~constant =>          indent buffer ;          append ${constant.name} {=} ${constant.initializer} \n ;        });      }    }  }                                                                                                                                                                                                                                                                                                                                 

あるいは、append コマンドの最初のパラメーターにインスペクタで with indent フラグを指定することもできます。これはまた各行の始めにだけ字下げを挿入します。

TextGen1

ルートの概念

TextGen には、2 種類のルート概念があります。

  • 概念テキストへの変換をエンコードする ConceptTextGenDeclaration 概念によって表現されるテキスト gen コンポーネントコンポーネント。ルート可能な概念の場合、ターゲットファイルも指定できます。

  • LanguageTextGenDeclaration の概念で表される基本テキストの gen コンポーネント。再利用可能な textgen 操作とユーティリティメソッドを定義できます。これらは、拡張言語と同じ言語の他のテキスト gen コンポーネントから呼び出すことができます。

拡張概念での TextGen

MPS はルート概念用のファイルを自動的には作成しません。TextGen が定義されている概念の下位概念でも、ファイルは自動的には作成されません。厳密な概念の一致のみが考慮されます。拡張概念が祖先の textgen コンポーネントをそのまま再利用することを望むなら、それ自身のの TextGen コンポーネントを宣言し、その本質をファイル名、符号化および拡張として述べ、コンポーネントの本体を空のままにします。

レイアウト

出力ファイルのレイアウトを制御するための暫定的なメカニズムがあります。(のみ rootable 概念で入手可能)ConceptTextGenDeclarationテキストレイアウト部は、作成者が(デフォルトのもので)複数の論理セクションを定義し、必要に応じてテキストを追加するためにどの区間に、それぞれが追加のために指定することができます。

テキストの生成は、物理ファイルの行に対応する順序で常に可能とは限りません。たとえば、Java ソースの場合、インポート本体の 2 つの異なる領域を区別することができます。ここで、インポート本体と一緒に入力されます。情熱的な言語設計者は、ファイルコメントパッケージステートメントインポート、およびフィールドメソッドからなるクラス本体まで、さらにファイルを分割し、ClassConcept をトラバースしながらそれぞれを個別に作成することができます。それが出力ファイルのレイアウトと呼ぶものです。それは今制御を与えるものです。MPS のベテランは、長年 TextGen で利用可能だった 2 つのバッファ(TOPBOTTOM)を知っているかもしれません。これらは事前定義された、ハードコードされた値です。出力ファイルの領域とその順序を指定するのは言語デザイナー次第です。

実行順序が変わるため、属性からテキストを生成する場合は特に、個別の領域が便利になります。使って、テキスト gen の流れが物理的なテキスト行に対応することを確認するのはさらにトリッキーであり、指定された領域は生成をずっと快適にします。

ファイルのレイアウトは、ファイルを生成するトップテキストの gen に指定できます。

このメカニズムのサポートは暫定的なものであり、現在はかなり初歩的なものです。BaseLanguage 実装でそれを利用します。それでこの通知はこれを本番に入れることを奨励するよりむしろ何が起こっているのかをあなたに説明することです。


tgp1

コンテキストオブジェクト

特定のモデルからテキストへの変換シナリオでは、TextGen の間にいくつかのコンテキスト情報を保存することが重要です。たとえば BaseLanguage では、TextGen はモデルのインポートと修飾されたクラス名を追跡する必要があります。直接テキストバッファ操作に基づく以前のバージョンの面倒で低レベルのアプローチは、概念の textgen 仕様の一部としてカスタマイズされたオブジェクトを定義して使用する可能性に置き換えられました。

ContextObject1

LanguageTextDeclaration は、コンテキストオブジェクトのタイプとインスタンス化メカニズムを定義する 1 つ以上の UnitContextDeclarations を宣言できます。その後、コンテキストオブジェクトは LanguageTextDeclaration のコードから使用できます。ルート可能な概念の ConceptTextGenDeclaration は、コンテキストオブジェクトセクションの UnitContextDeclarations を参照して、生成セッションのコンテキストオブジェクトをアクティブ化できます。

現時点では、通常の java クラス(概念インスタンスをとる引数なしまたは単一引数のコンストラクターを持つ)がコンテキストオブジェクトとしてサポートされています。通常の変数としてコードからコンテキストオブジェクトを参照します。

TextGen で属性を処理する

ノードに属性の注釈が付けられている場合、これらの属性の TexGen が最初に処理されます。その後、属性の TextGen 内の ${ 属性付きノード } 構造は、属性ノード自体の TextGen を挿入します。
単一ノードに複数の属性がある場合は、最後に割り当てられた(最上位の)属性から順に処理されます。TextGen が関連付けられていない属性は無視され、スキップされます。

サンプル

これは ForeachStatement(jetbrains.mps.baseLanguage)のテキスト gen コンポーネントの例です。

text gen component for concept ForeachStatement { (node, context, buffer)->void { if (node.loopLabel != null) { append \n ${node.loopLabel.name} {:} ; } else if (node.label != null) { append \n ${node.label} {:} ; } append \n ; indent buffer ; append {for (} ${node.variable} { : } ${node.iterable} {) {} ; with indent { append ${node.body} ; } append \n {}} ; } }

これは、テキスト gen の人工的な例です。

text gen component for concept CodeBlockConcept { (node, context, buffer)->void { indent buffer ; append {codeBlock {} \n ; with indent { indent buffer ; append {// Begin of codeBlock} \n ; indent buffer ; append {int i = 0} \n ; indent buffer ; append {// End of codeBlock} \n ; } append {}} ; } }

インデント付きの行数を含む次のコードブロックを生成します。

text gen component for concept CodeBlockConcept { codeBlock { // Begin of codeBlock int i = 0 // End of codeBlock }

属性付きノードの出力に追加テキストを追加する attribute の TextGen の例:

MethodDocCommentAttribute

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