Haxe 4:未捕获的异常宏中宏
Haxe 4: Uncaught exception macro-in-macro
我有这样的代码与 Haxe 3 一起使用:
macro public static function get(key:String)
{
return Context.makeExpr(Context.definedValue(key), Context.currentPos());
}
但是,在迁移到 Haxe 4 之后,编译失败并出现错误:
Uncaught exception macro-in-macro
我应该如何将此功能迁移到 Haxe 4?是否有更好的方法来访问构建标志以避免此问题?
正如@Gama11 所暗示的,您的宏函数实际上没有问题,您从哪里调用它有问题。 (Haxe 4 可能对这些检查变得更加严格。)
如果你有:
Main.hx
class Main
{
public static function main()
{
// Can call get from here:
var cvar = MacroUtil.get('cvar');
MacroUtil.some_macro_function();
trace('Hello world! cvar=${ cvar }');
}
}
MacroUtil.hx
import haxe.macro.Context;
import haxe.macro.Expr;
class MacroUtil
{
macro public static function get(key:String):Expr
{
return Context.makeExpr(Context.definedValue(key), Context.currentPos());
}
macro public static function some_macro_function()
{
// Cannot call get from here:
var cvar:Expr = get('cvar');
trace('will trace at compile time, and cvar is ${ cvar }');
return macro trace('will trace at runtime');
}
}
并执行:haxe -x Main -D cvar=abc
这将产生您遇到的错误。这是因为在some_macro_function
中,你已经在宏上下文中,所以你不能从那里调用宏函数get
。
有几种方法可以解决这个问题。
一种方法
您可以使用 #if macro
/ if !macro
检测宏上下文并相应地进行调整。尽管这看起来很愚蠢,但它确实解决了您的特定问题:
class MacroUtil
{
#if !macro macro #end public static function get(key:String):Expr
{
这个函数签名说,如果我已经在宏上下文中,请不要将此函数视为宏函数。那时它只是一个静态助手。请记住,它 returns 是一个 Expr
,而不是像在主要上下文中那样的字符串。
如果您将宏和 non-macro 函数混合在一个文件中,您可能还会发现自己也需要使用 #if macro
来避免这种情况。
另一种方法
您可以将宏函数重构为宏函数和宏助手。它有点冗长,但对于正在发生的事情可能更清楚一点:
MacroUtil.hx
import haxe.macro.Context;
import haxe.macro.Expr;
class MacroUtil
{
macro public static function get(key:String):Expr
{
return Context.makeExpr(MacroHelpers.get_define(key), Context.currentPos());
}
macro public static function some_macro_function()
{
// Cannot call get from here:
var cvar:String = MacroHelpers.get_define('cvar');
trace('will trace at compile time, and cvar is ${ cvar }');
return macro trace('will trace at runtime');
}
}
class MacroHelpers
{
public static function get_define(key:String):String
{
return Context.definedValue(key);
}
}
如果你这样做,那么你的宏函数都调用了MacroHelpers,而non-macro函数调用了MacroUtils。请注意帮助器 returns 一个字符串,然后由 call-site 将其转换为表达式,如果这是他们想要的。
我们最终删除了整个 get
方法,并将事件切换为使用 Compiler.getDefine(),Haxe 3 和 4 都支持这种方法。
我相信我们面临的问题与以下事实有关:这个静态宏 get
是从我们的测试运行程序脚本中调用的,所以这可能是一个宏调用另一个宏的地方。尽管如此,我还是尝试将 Jeff Ward 建议的解决方案放在适当的位置,但一直得到相同的结果。
我有这样的代码与 Haxe 3 一起使用:
macro public static function get(key:String)
{
return Context.makeExpr(Context.definedValue(key), Context.currentPos());
}
但是,在迁移到 Haxe 4 之后,编译失败并出现错误:
Uncaught exception macro-in-macro
我应该如何将此功能迁移到 Haxe 4?是否有更好的方法来访问构建标志以避免此问题?
正如@Gama11 所暗示的,您的宏函数实际上没有问题,您从哪里调用它有问题。 (Haxe 4 可能对这些检查变得更加严格。)
如果你有:
Main.hx
class Main
{
public static function main()
{
// Can call get from here:
var cvar = MacroUtil.get('cvar');
MacroUtil.some_macro_function();
trace('Hello world! cvar=${ cvar }');
}
}
MacroUtil.hx
import haxe.macro.Context;
import haxe.macro.Expr;
class MacroUtil
{
macro public static function get(key:String):Expr
{
return Context.makeExpr(Context.definedValue(key), Context.currentPos());
}
macro public static function some_macro_function()
{
// Cannot call get from here:
var cvar:Expr = get('cvar');
trace('will trace at compile time, and cvar is ${ cvar }');
return macro trace('will trace at runtime');
}
}
并执行:haxe -x Main -D cvar=abc
这将产生您遇到的错误。这是因为在some_macro_function
中,你已经在宏上下文中,所以你不能从那里调用宏函数get
。
有几种方法可以解决这个问题。
一种方法
您可以使用 #if macro
/ if !macro
检测宏上下文并相应地进行调整。尽管这看起来很愚蠢,但它确实解决了您的特定问题:
class MacroUtil
{
#if !macro macro #end public static function get(key:String):Expr
{
这个函数签名说,如果我已经在宏上下文中,请不要将此函数视为宏函数。那时它只是一个静态助手。请记住,它 returns 是一个 Expr
,而不是像在主要上下文中那样的字符串。
如果您将宏和 non-macro 函数混合在一个文件中,您可能还会发现自己也需要使用 #if macro
来避免这种情况。
另一种方法
您可以将宏函数重构为宏函数和宏助手。它有点冗长,但对于正在发生的事情可能更清楚一点:
MacroUtil.hx
import haxe.macro.Context;
import haxe.macro.Expr;
class MacroUtil
{
macro public static function get(key:String):Expr
{
return Context.makeExpr(MacroHelpers.get_define(key), Context.currentPos());
}
macro public static function some_macro_function()
{
// Cannot call get from here:
var cvar:String = MacroHelpers.get_define('cvar');
trace('will trace at compile time, and cvar is ${ cvar }');
return macro trace('will trace at runtime');
}
}
class MacroHelpers
{
public static function get_define(key:String):String
{
return Context.definedValue(key);
}
}
如果你这样做,那么你的宏函数都调用了MacroHelpers,而non-macro函数调用了MacroUtils。请注意帮助器 returns 一个字符串,然后由 call-site 将其转换为表达式,如果这是他们想要的。
我们最终删除了整个 get
方法,并将事件切换为使用 Compiler.getDefine(),Haxe 3 和 4 都支持这种方法。
我相信我们面临的问题与以下事实有关:这个静态宏 get
是从我们的测试运行程序脚本中调用的,所以这可能是一个宏调用另一个宏的地方。尽管如此,我还是尝试将 Jeff Ward 建议的解决方案放在适当的位置,但一直得到相同的结果。