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

A LanguageTextDeclaration may declare one or more UnitContextDeclarations that defines the type and the instantiation mechanism for the context objects. The context object can then be used from code of the LanguageTextDeclaration . ConceptTextGenDeclaration of rootable concepts may then refer to the UnitContextDeclarations in the context objects section to activate the context object for their generation session.

現時点では、通常の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日