Metadataとは
構文には直接関与しない付加的なデータです。
Hexeにおいて、大きく分けて Compiler Metadata と Runtime Metadata 2種類のMetadataがあります。
Compiler Metadata
- 付与された対象に作用させてコンパイル結果を変更したり、コンパイル時に制約を与えたりする際に用いられます。
- 表記は @:xxx (xxxに識別子として使用可能な文字)です。
- 標準でいくつか用意されており、 haxe --help-metas とタイプすることで確認することができます。
Runtime Metadata
- コンパイルで生成されたファイルに保存され、Metadata APIを通して取り出し、実行時に特別な振る舞いを与えたい場合に用いられます。
- Metadata APIは、haxe.rtti.Metaです。
- 表記は @xxx です。Compiler Metadataとは異なり、@の後ろにコロンがないことに注意。
Metadataの使い方
Metadataは、classやenumの宣言部、クラスフィールドやメソッド宣言部、およびたいていの式要素に付与することができます。
class, enumの場合
@hoge
class MyHogeClass {
...
}
クラスフィールド, メソッド宣言部の場合
class MyHogeClass {
@foo
private var _x;
@var
public function yyy() {
...
}
}
式要素の場合
以下の要素については使用できることを確認できてます
- コントロールフロー
- if / for / while(do-while) / switch / try / break / continue / return / throw / new
@:aaa if (x % 2 == 0) { ... }
- ローカルスコープ(ブロック)
var x = @:aaa {
var y = 10;
y * y;
}
- 変数宣言
@:aaa var x = 1024;
function foo(@:aaa x) { ... }
- ローカル関数
public function foo() {
var fn = @:aaa function() { ... };
}
使えなかったところ
- 演算子の前
var x = 10 @:aaa + 20; // NG
Metadata APIについて
APIリファレンスには、3つの関数が載っており、
- getType(...)
- class / enumに付与したメタデータ情報を抽出する
- getFields(...) / getStatics(...)
- クラスフィールド、メソッドから抽出。後者はstatic宣言用
と分類できます。
はて、式に付与したMetadataが取得できません。どうゆうことでしょう?
これは、Runtime Metadataがclass / enumおよびフィールド、メソッドに付与されたもののみが保存され、式に付与したMetadataは捨てられます。
式へのMetadataの付与は使い道がないのでしょうか?
否、その鍵を握るのがMacroです。
Macro
Macroの前に、Haxeのコンパイルプロセスのおさらい。
Haxeはソースコードが与えられると、
- 構文要素に分解(Tokenize)
- 抽象構文木(AST)を生成
- 型付け(型推論)
- コード生成
の流れで処理されます。
Macroは2と3の間および、3と4の間に入り込んで、構文木に任意の変換(AST変換)を施すことができます。
2と3の間は、 クラスに @:build Metadataを付与することによって入り込むことができ、
ここでは型無しMacro ( haxe.macro.Expr )を使用して変換処理を行います。
3と4の間は、コマンドライン引数で、 --macro xxx を与えることで、提供されたMacro: xxxから入り込むことができ、
ここでは型付きMacro ( haxe.macro.Type )を使用して変換処理を行います。
いずれの場合に置いても、Macroを通して構文木としての式要素にアクセスすることができるため、Metadataを任意の変換の目印として使用することができます。
また、コンパイルプロセスないでの使用からも分かるように、使用できるのは、Compiler Metadataに限られます。
まとめ
以上、HaxeのMetadataについて、簡単にまとめてみました。