问题描述
我在Haxe 3中使用过这样的代码:
macro public static function get(key:String)
{
return Context.makeExpr(Context.definedValue(key),Context.currentPos());
}
但是,在迁移到Haxe 4之后,该编译失败并出现错误:
宏未捕获的异常
该如何将该功能迁移到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
{
此函数签名表示,如果我已经在宏上下文中,请不要将此函数视为宏函数。在那时,它只是一个静态助手。请记住,它返回的是Expr
,而不是像在主上下文中那样返回的字符串。
如果将宏函数和非宏函数混合在一个文件中,您可能还会发现自己也需要使用#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,而非宏函数将调用MacroUtils。请注意,帮助程序返回了一个String,然后由调用站点将其转换为表达式(如果他们想要的话)。
,我们最终删除了整个get
方法,并将出现的事件切换为改为使用Compiler.getDefine(),Haxe 3和4均支持。
我认为,我们面临的问题与以下事实有关:从我们的测试运行器脚本中调用了此静态宏get
,因此很可能是某个宏在其中调用另一个宏的地方。尽管如此,我还是尝试将杰夫·沃德(Jeff Ward)建议的解决方案放在适当的位置,但始终得到相同的结果。