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;
}
}