Macros Haxe自定义元数据到宏调用

Macros Haxe自定义元数据到宏调用,macros,haxe,Macros,Haxe,假设我已经创建了一个可以像这样使用的构建宏 @:build(macros.SampleMacro.build("arg")) class Main {} 是否可以将其转换为自定义的速记元数据 @:samplemacro("arg") class Main {} 有关于这方面的文档吗?我不确定这是否可行,但您可以利用这样一个事实,即@:autoBuild()元数据在接口上工作。这通常用于如下“标记接口”: class Main implements ISampleMacro {} @:aut

假设我已经创建了一个可以像这样使用的构建宏

@:build(macros.SampleMacro.build("arg"))
class Main {}
是否可以将其转换为自定义的速记元数据

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

有关于这方面的文档吗?

我不确定这是否可行,但您可以利用这样一个事实,即
@: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> {}

在经历了许多挫折之后,我发现这是可能的

部分解决方案是使用

--macro addGlobalMetadata('$path', '@:build(Build.build())')
这允许您为$path中的所有类分配@:build函数。这可以用作编译器选项或haxeflag

但这本身还不足以采用带有动态参数的元数据标记。但是因为我们现在有了一个Build.Build()来执行所有类,这个Build.Build()函数既可以检查哪些类有我们的自定义元数据标记,也可以为那些我们可能需要的类生成任何东西

为了检查我们的自定义元数据标记,我们设置了检查宏,如下所示:

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;
    }
}
类构建{
静态变量META_STR:String=“:samplemacro”;
宏静态公共函数build():数组{
//我们只检查那些上下文中存在类类型的位置
var localClass:Null=Context.getLocalClass();
if(localClass==null)返回null;//无类类型
//我们检查类的元数据是否包含
//自定义元数据字符串
if(!localClass.get().meta.has(meta_STR))返回null;
//这个类有我们的自定义元数据!
//因为同一类型可能有多个
//对于元数据,我们提取所有自定义元数据标记的列表
var customTags=localClass.get().meta.extract(meta_STR);
//对于每个标记,我们可以从传入的参数中获取
//通过访问params字段
for(customTags中的customTag){
var params=customTag.params;
//在这里我们可以处理我们的@:samplemacro(params)标记,
//保存参数以供以后使用,或
//将参数传递给另一个类来处理
}
var fields=Context.getBuildFields();
//按所需方式修改类字段
//以后可以选择销毁元数据标记
//使用localClass.get().meta.remove(meta_STR);
返回字段;
}
}
有关addGlobalMetadata的更多详细信息,请访问:

谢谢您的建议-这是另一种方法,但不是我想要的。您可能想检查一下这对编译性能的影响。在大型项目中对所有内容运行构建宏可能会很昂贵(这基本上是我不建议使用这种方法的原因)。我还没有遇到性能问题,而且,我似乎找不到任何其他解决方法。幸运的是,检查标记是否存在的测试实际上只涉及检查元数据标记的映射。有一个库可以做同样的事情,并具有一些附加功能:我想,一旦在我的代码库中注册了多个自定义宏,我就会转而使用tink_syntaxhub。
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;
    }
}