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 建议的解决方案放在适当的位置,但一直得到相同的结果。