在构建宏中访问 Class<T> of Context.getLocalClass()
Access Class<T> of Context.getLocalClass() in build macro
我想制作一个宏,为我的 classes 添加一个字段,字段值应该是他们所在的 class 的 Class<T>
。这是我的最小值例如,它不会编译并出现此错误:
src/Base.hx:3: characters 2-11 : Unknown identifier : foo.Foo
但是如果我将 Foo
从包 foo
移动到根包,那么它会编译并运行。
Main.hx
import foo.Foo;
class Main
{
static function main()
{
trace(Foo.data);
}
}
Build.hx
import haxe.macro.Context;
import haxe.macro.Type;
import haxe.macro.Expr;
class Build
{
macro static public function build(DataClass):Array<Field>
{
var cls = Context.getLocalClass().get();
var pack = cls.pack.concat([cls.name]);
var name = pack.join(".");
trace(name);
var expr = {
expr: ExprDef.EConst(Constant.CIdent(name)),
pos: Context.currentPos()
}
var newFieldCls = macro class {
public static var data:Class<Dynamic> = $expr;
}
var fields = Context.getBuildFields();
return fields.concat(newFieldCls.fields);
}
}
Base.hx
package;
@:autoBuild(Build.build(Main.Data))
class Base
{
public function new()
{
}
}
foo/Foo.hx
package foo;
class Foo extends Base
{
}
EConst(CIdent("foo.Bar"))
将不起作用,因为这非常类似于您可以在其中指定一个带有 .
句点的名称。相反,您需要执行 EField({ expr: EConst(CIdent("foo")) }, "Bar")
,因为这是 foo.Bar
被编译器本身解析的内容(尝试从宏中 trace
ing 表达式)。
所以正确的代码是
import haxe.macro.Context;
import haxe.macro.Expr;
class Build {
public static macro function build():Array<Field> {
var self = Context.getLocalClass().get();
var cpos = Context.currentPos();
var out:Expr = null;
inline function add(name:String) {
if (out == null) {
out = { expr: EConst(CIdent(name)), pos: cpos };
} else out = { expr: EField(out, name), pos: cpos };
}
for (name in self.pack) add(name);
add(self.name);
return Context.getBuildFields().concat((macro class {
public static var data:Class<Dynamic> = $out;
}).fields);
}
}
处理 EConst(CIdent)
表达式的创建并随后将其包装在 EField
层中用于尾随包,最后是 class 名称。
我想制作一个宏,为我的 classes 添加一个字段,字段值应该是他们所在的 class 的 Class<T>
。这是我的最小值例如,它不会编译并出现此错误:
src/Base.hx:3: characters 2-11 : Unknown identifier : foo.Foo
但是如果我将 Foo
从包 foo
移动到根包,那么它会编译并运行。
Main.hx
import foo.Foo;
class Main
{
static function main()
{
trace(Foo.data);
}
}
Build.hx
import haxe.macro.Context;
import haxe.macro.Type;
import haxe.macro.Expr;
class Build
{
macro static public function build(DataClass):Array<Field>
{
var cls = Context.getLocalClass().get();
var pack = cls.pack.concat([cls.name]);
var name = pack.join(".");
trace(name);
var expr = {
expr: ExprDef.EConst(Constant.CIdent(name)),
pos: Context.currentPos()
}
var newFieldCls = macro class {
public static var data:Class<Dynamic> = $expr;
}
var fields = Context.getBuildFields();
return fields.concat(newFieldCls.fields);
}
}
Base.hx
package;
@:autoBuild(Build.build(Main.Data))
class Base
{
public function new()
{
}
}
foo/Foo.hx
package foo;
class Foo extends Base
{
}
EConst(CIdent("foo.Bar"))
将不起作用,因为这非常类似于您可以在其中指定一个带有 .
句点的名称。相反,您需要执行 EField({ expr: EConst(CIdent("foo")) }, "Bar")
,因为这是 foo.Bar
被编译器本身解析的内容(尝试从宏中 trace
ing 表达式)。
所以正确的代码是
import haxe.macro.Context;
import haxe.macro.Expr;
class Build {
public static macro function build():Array<Field> {
var self = Context.getLocalClass().get();
var cpos = Context.currentPos();
var out:Expr = null;
inline function add(name:String) {
if (out == null) {
out = { expr: EConst(CIdent(name)), pos: cpos };
} else out = { expr: EField(out, name), pos: cpos };
}
for (name in self.pack) add(name);
add(self.name);
return Context.getBuildFields().concat((macro class {
public static var data:Class<Dynamic> = $out;
}).fields);
}
}
处理 EConst(CIdent)
表达式的创建并随后将其包装在 EField
层中用于尾随包,最后是 class 名称。