【问题标题】:Haxe 4: Uncaught exception macro-in-macroHaxe 4:宏中未捕获的异常
【发布时间】:2020-08-11 18:33:47
【问题描述】:

我有这样的代码与 Haxe 3 一起使用:

macro public static function get(key:String)
{
    return Context.makeExpr(Context.definedValue(key), Context.currentPos());
}

但是,在迁移到 Haxe 4 后,编译失败并出现错误:

宏中未捕获的异常

我应该如何将此功能迁移到 Haxe 4?有没有更好的方法来访问构建标志以避免这个问题?

【问题讨论】:

  • 该函数本身似乎对我来说编译得很好...您是否尝试从 within 宏中使用它?在这种情况下,您可以直接使用Context.definedValue()

标签: haxe


【解决方案1】:

正如@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。请注意,助手返回一个字符串,然后由调用站点将其转换为表达式,如果这是他们想要的。

【讨论】:

  • 感谢您的精彩解释,阅读后我可以更好地理解这个问题!但是,即使我执行了此处提出的修复程序,我也无法使其正常工作,它仍然会产生与宏中宏相同的错误。我试图在我的代码中找到另一个宏调用此函数get(),但我找不到它。
  • 嗯...如果不查看代码就很难调试。一个随机的想法——get() 是一个相当通用的函数名称,难以跟踪,并且可能被无意调用?也许尝试重命名函数? VSCode 的 Haxe 插件可能有助于查找所有参考资料?
【解决方案2】:

我们最终删除了整个 get 方法,并改为使用 Compiler.getDefine(),这在 Haxe 3 和 4 中均受支持。

我相信我们面临的问题与这个静态宏 get 是从我们的测试运行程序脚本中调用的事实有关,因此这可能是一个宏调用另一个宏的地方。尽管如此,我还是尝试采用 Jeff Ward 建议的解决方案,但始终得到相同的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-28
    • 2012-05-31
    相关资源
    最近更新 更多