TextGen
TextGen 言語アスペクト
導入
TextGen 言語の側面は、モデルからテキストへの変換を定義します。モデルを直接テキスト形式に変換する必要があるたびに便利です。この言語には、テキストを印刷し、ノードをテキスト値に変換し、出力に適切なレイアウトを与えるための構造が含まれています。
操作
append コマンドは変換を実行し、結果のテキストを出力に追加します。found error コマンドを使用して、モデルの問題を報告できます。with indent コマンドは、インデントが増加したブロックの境界を定めます。あるいは、深さの増加および深さの 減少コマンドは、ブロック構造に限定されることなく、現在の押し込み深さを操作します。indent buffer コマンドは、現在の行に現在のインデントを適用します(ident で指定するか、深さを増減します)。
操作 | 引数 |
---|---|
append | 任意の数
|
found error | エラーテキスト |
decrease depth | これからインデントレベルを下げます |
increase depth | これからインデントレベルを上げる |
indent buffer | 現在の行に字下げを適用する |
with indent { <code> } | <code> のインデントレベルを上げる |
インデント
基本的な原則を理解すれば、適切なインデントを簡単に正しく行うことができます。TextGen は AST をテキストにフラッシュします。TextGen コマンドは、出力バッファーを順番に操作し、一度に 1 ノードずつテキストを出力するだけです。現在のインデントの深さを保持する変数(インデントバッファー)は、ルートコンセプトごとに保持されます。インデントバッファはゼロから始まり、深さの増減とインデントコマンドによって変更されます。
ただし、「インデント」は append コマンドで明示的に出力ストリームに挿入する必要があります。ブロックを単に indent でマークしても、ラップされた TextGen コードによって生成されたテキストは自動的にはインデントされません。with indent ブロックはインデントバッファの値を増やすだけですが、個々の追加は現在のサイズのインデントバッファを前に付けることを望むかもしれません。
インデントバッファを出力ストリームに明示的に挿入する方法は 2 つあります。
インデントバッファコマンド
append コマンドのパラメーターに対するインスペクタの indent フラグ付き
例: 定数のリストの中で定数を適切にインデントするために、発行された各行の先頭で indent buffer を呼び出します。これにより、インデントは各行の先頭にのみ挿入されます。
あるいは、append コマンドの最初のパラメーターにインスペクタで with indent フラグを指定することもできます。これはまた各行の始めにだけ字下げを挿入します。
ルートの概念
TextGen には、2 種類のルート概念があります。
ConceptTextGenDeclaration コンセプトで表される textgen コンポーネント。これは、コンセプトのテキストへの変換をエンコードします。ルート化可能な概念の場合、ターゲットファイルも指定できます。
LanguageTextGenDeclaration コンセプトで表されるベーステキスト生成コンポーネント。これにより、再利用可能な textgen 操作とユーティリティメソッドの定義が可能になります。これらは、同じ言語の他のテキスト生成コンポーネントや拡張言語から呼び出すことができます
拡張概念での TextGen
MPS は、ルート概念のファイルを自動的に作成しません。TextGen が定義されている概念のサブ概念であっても、ファイルは自動的に作成されません。コンセプトが完全に一致する場合のみが考慮されます。拡張コンセプトが祖先の textgen コンポーネントをそのまま再利用したい場合は、独自の空の TextGen コンポーネントを宣言し、ファイル名、エンコーディング、拡張子などの重要事項を記述し、コンポーネントの本体を空のままにしておく必要があります。
レイアウト
出力ファイルのレイアウトを制御するための暫定的なメカニズムがあります。ConceptTextGenDeclaration のテキストレイアウトセクション(ルート化可能な概念でのみ使用可能)を使用すると、作成者は複数の論理セクション(デフォルトのセクション)を定義し、オプションで各追加にテキストを追加するセクションを指定できます。
テキスト生成は、物理ファイル内の行に対応するシーケンスで常に可能であるとは限りません。例: Java ソースでは、imports とクラス本体の 2 つの異なる領域を区別できます。この場合、imports は 本体と一緒に設定されます。熱心な言語設計者であれば、ファイルをさらに分割して、たとえばファイルコメント、パッケージステートメント、imports、フィールドとメソッドで構成されるクラス本体まで分割し、ClassConcept をトラバースしながらそれぞれを個別に設定したいと考えるかもしれません。これが出力ファイルのレイアウトと呼ばれるもので、現在制御できるのはこれです。MPS のベテランは、TextGen で長年使用できた 2 つのバッファー (TOP と BOTTOM) に気付いているかもしれません。これらは定義済みのハードコードされた値でした。現在、出力ファイルの領域とその順序を指定するのは言語設計者の責任です。
実行順序が変わるため、属性からテキストを生成する場合は特に、個別の領域が便利になります。使って、テキスト gen の流れが物理的なテキスト行に対応することを確認するのはさらにトリッキーであり、指定された領域は生成をずっと快適にします。
ファイルのレイアウトは、ファイルを生成するトップテキストの gen に指定できます。
このメカニズムのサポートは準備ものであり、現在は非常に初歩的なものです。BaseLanguage の実装で使用しているため、この通知は、これを本番環境に移行することを推奨するのではなく、何が起こっているのかを説明するためのものです。
コンテキストオブジェクト
特定のモデルからテキストへの変換シナリオでは、TextGen の間にいくつかのコンテキスト情報を保存することが重要です。たとえば BaseLanguage では、TextGen はモデルのインポートと修飾されたクラス名を追跡する必要があります。直接テキストバッファ操作に基づく以前のバージョンの面倒で低レベルのアプローチは、概念の textgen 仕様の一部としてカスタマイズされたオブジェクトを定義して使用する可能性に置き換えられました。
現時点では、通常の java クラス(概念インスタンスをとる引数なしまたは単一引数のコンストラクターを持つ)がコンテキストオブジェクトとしてサポートされています。通常の変数としてコードからコンテキストオブジェクトを参照します。
TextGen で属性を処理する
ノードに属性のアノテーションが付けられている場合、これらの属性の TexGen が最初に処理されます。次に、属性の TextGen 内の ${attributed node} 構成要素は、属性ノード自体の TextGen を挿入します。
1 つのノードに複数の属性がある場合、それらは最後に割り当てられた(最上位の)属性から順番に処理されます。TextGen が関連付けられていない属性は無視され、スキップされます。
サンプル
ForeachStatement (jetbrains.mps.baseLanguage)のテキスト生成コンポーネントの例を次に示します。
これは、テキスト gen の人工的な例です。
インデント付きの行数を含む次のコードブロックを生成します。
属性付きノードの出力に追加テキストを追加する attribute の TextGen の例:
関連ページ:
ジェネレーターユーザガイド Demo7
ジェネレーターユーザガイドデモ 7:この最後のデモでは、デモ 3 に戻り、目的とする機能を少し異なる方法で実装します。そのため、MPS ジェネレーターの別の領域 - ウィービング規則とルートマッピング規則 - を探ります。ここで構築するデモ 2 では、次のような java ステートメントを生成していました。container.add(new JButton());Swing コンポーネントを作成してアプリケーションのコンテンツペインに追加します。デモ 7 では、デモ 3 と同様に、コンポーネント...
マイグレーション
言語が公開され、ユーザーがそれを使い始めた後、言語の作者は言語定義へのさらなる変更に注意しなければなりません。特に、概念を削除したり、プロパティ、子、概念への参照を追加および削除すると、前の言語バージョンと次の言語バージョンの間に互換性がなくなります。次の言語バージョンに更新すると、言語のユーザーに影響があります。自分のモデルが言語定義と一致しなくなり、適切なエラーがモデルから報告されるためです。MPS はプロジェクトで使用されている言語のバージョンを追跡し、言語の使用箇所を最新のバージョンにア...