2017-05-09 22 views
2

のは、私がそうhaXeのカスタムメタデータ

@:build(macros.SampleMacro.build("arg")) 
class Main {} 

それはカスタム、速記メタデータに変換することが可能ですように使用することができますビルドマクロを作成したとしましょうか?

@:samplemacro("arg") 
class Main {} 

これに関するドキュメントはありますか?

答えて

2

多くのつまずきの後、私はそれが可能であることを理解しました。 $パス内のクラスのすべての機能を構築:ソリューションの

一部は

--macro addGlobalMetadata('$path', '@:build(Build.build())') 

これは、あなたが@を割り当てることができます使用することです。これは、コンパイラオプションまたはhaxeflagとして使用できます。

しかし、それだけでは動的な引数を取るメタデータタグを採用するには十分ではありません。しかし、今度はのために実行するBuild.build()があります。 Build.build()関数は、カスタムメタデータタグを持つクラスのチェックと何かをビルドすることができます私たちが必要とするクラスのために。次のように私たちのカスタムメタデータタグをチェックするために

、私たちはチェックマクロを設定します。addGlobalMetadata上

class Build { 

    static var META_STR:String = ":samplemacro"; 

    macro static public function build():Array<Field> { 

     // We check only those Contexts for where a class type exists 
     var localClass:Null<Ref<ClassType>> = Context.getLocalClass(); 
     if(localClass == null) return null; // no class type 

     // We check if the metadata for the class contains our 
     // custom metadata string at all 
     if(!localClass.get().meta.has(META_STR)) return null; 

     // This class does have our custom metadata! 
     // Because there may be more than one of the same type 
     // of metadata, we extract a list of all the custom metadata tags 

     var customTags = localClass.get().meta.extract(META_STR); 

     // For each tag we can get at the arguments passed in 
     // by accessing the params field 
     for(customTag in customTags){ 
      var params = customTag.params; 

      // Here we can handle each of our @:samplemacro(params) tags, 
      // save the params for use later, or 
      // pass the arguments over to another class to deal with 
     } 

     var fields = Context.getBuildFields(); 

     // Modify the class fields the way you want 

     // Optionally destroy the metadata tags afterwards 
     // with localClass.get().meta.remove(META_STR); 

     return fields; 
    } 
} 

詳細はで見つけることができます: https://stackoverflow.com/a/38075492/1502818

+1

コンパイルのパフォーマンスにどのような影響があるかを確認したい場合があります。すべてのビルドマクロを実行することは、大規模なプロジェクトでは高価になる可能性があります(基本的に、私はこのアプローチを提案しませんでした)。 – Gama11

+1

私はまだパフォーマンスの問題に遭遇していますし、さらに、私はこれを回避する他の方法を見つけることができません。幸いにも、タグの存在を確認するテストは、実際にはメタデータタグのマップをチェックするだけです。 –

+2

正確なことを行うライブラリがあります。いくつかの追加機能があります。https://github.com/haxetink/tink_syntaxhub – KevinResoL

3

確かにわかりませんが、@:autoBuild()メタデータがインターフェイスで動作するという事実を利用できます。これは、しばしば、このような「マーカーインタフェース」のために使用されます。

class Main implements ISampleMacro {} 

@:autoBuild(macros.SampleMacro.build("arg")) 
interface ISampleMacro {} 

しかし、おそらくあなたは、むしろそれをハードコーディングするよりも、使用状況ごとに異なる"arg"を持っていると思います。あなたは@:const型パラメータを使用することによって、これを達成することができます:ビルドマクロの型パラメータの値を抽出

class Main implements ISampleMacro<"foo"> {} 

@:autoBuild(macros.SampleMacro.build()) 
interface ISampleMacro<@:const T> {} 

は、単にそれにパラメータを渡すよりも少し多くの努力が必要です。

switch (Context.getLocalClass().get().interfaces[0].params[0]) { 
    case TInst(_.get() => t, params): 
     switch (t.kind) { 
      case KExpr({expr: EConst(CString(arg)), pos: _}): 
       trace(arg); // "foo" 
      case _: 
     } 
    case _: 
} 
+0

ご提案いただきありがとうございます - これはあります物事をする別の方法だが、私が探していたものではない。 –

関連する問題