宏和字符串内插变量

4

提供代码

class Test {
  static function main() {
    var i = 1;
    trace(m('some before $i some after')); // some before 1 some after
  }

  static macro function m(e: haxe.macro.Expr)
  {
    trace(e); // { expr => EConst(CString(some before $i some after)), pos => #pos(Test.hx:4: characters 12-39) }

    // trace the name of referenced var
    /* 
    trace();
    */

    return macro $e;
  }
}

如果我想在注释掉的代码中使用trace()函数来追踪插值表达式中使用的变量名称,而不需要手动解析字符串常量,应该放置什么内容?

2个回答

4
您需要的是formatString点击查看文档)函数:
class Test {
  #if !macro
  static function main() {
    var i = 1;
    trace(m('some before $i some after')); // some before 1 some after
  }
  #end
  static macro function m(e: haxe.macro.Expr)
  {
    switch e.expr {
      case EConst(CString(s)):
        trace(haxe.macro.MacroStringTools.formatString(s, e.pos));
      default:
    }
    return e; 
  }
}

我猜这也是不同目标使用来输出它们的插值字符串的方式... 这实际上回答了我的原始问题。我认为我应该开始真正阅读API文档。还有你在Github上的库的源代码。 ;) - szczepanpp
2
整洁,谢谢Juraj,每天都学到新东西。我会留下我的答案,以防有人在搜索关键字时找到幼稚的解决方案。:D 至少我得到了case EConst(CString(str)):,这要感谢Mark最近的模式匹配教程。 - Jeff Ward

2
输入表达式是一个常量、字面量字符串。因此,您需要自己解析出$i。下面是一个使用正则表达式的示例,并且可以在调用上下文中获取其类型,获得额外积分。 http://try-haxe.mrcdk.com/#B0B9E(点击Build+run,查看输出编译器输出选项卡)。
import haxe.macro.Expr;
import haxe.macro.Context;

class Test {
  static function main() {
    var i = 1;
    trace(m('some before $i some after')); // some before 1 some after
  }

  static macro function m(e: Expr)
  {
    trace(e); // { expr => EConst(CString(some before $i some after)), pos => #pos(Test.hx:4: characters 12-39) }

    var interpolated:String = null;
    switch e.expr {
        case EConst(CString(str)):
        trace(str); // 'some before $i some after'
        var r = ~/\$\w+/;
        if (r.match(str)) { // matched(0) -> $i
          interpolated = r.matched(0).substr(1);
          trace(interpolated); // 'i'
        }
        default: throw 'Macro m expects a string literal...';
    }

    if (interpolated!=null) {
      var t = Context.typeof({expr: EConst(CIdent(interpolated)), pos:Context.currentPos()});
      trace('Got interpolated var $interpolated of type $t'); // Got interpolated var i of type TAbstract(Int,[])
    }

    return macro $e;
  }
}

Jeff,感谢你的完整回答(顺便说一句,我没有想到使用 Context.typeof(...))。但实际上,我的问题只是为了确认我的假设,这是唯一的方法。那么 trace(m('some before ${Std.string(i)} some after')); 呢?(http://try-haxe.mrcdk.com/#fEF62) :) - szczepanpp
是的,宏的输入只是一个字符串。您可以按照自己的喜好进行解析,正则表达式是一种懒惰快速的示例。可能有库可以解析$插值,我从未查看过。但是您可以四处探索:https://github.com/Simn/hxparse https://github.com/Simn/hxparse/wiki/Writing-a-Parser,这是基于https://github.com/Simn/haxeparser的。具体来说,这与插值解析相关:https://github.com/Simn/haxeparser/blob/master/src/haxeparser/HaxeLexer.hx#L198-L203 - Jeff Ward
据我所知,当在宏环境中使用时,haxeparser将无法工作。但实际上它可能有一些代码处理功能,所以我只需要检查haxparse是否在宏中工作(应该可以)。 - szczepanpp
是的,我将它们指向作为更好的解析而不是正则表达式的实现的例子,并且可能是$插值解析的例子。并非具体作为即插即用的解决方案。您的解决方案的复杂程度取决于您期望的输入内容--从简单的变量到潜在的任意Haxe代码。假设你希望支持表达式,一旦你解析出${...}中的内容(字符串),你可以调用Context.parse(innerContents, Context.currentPos())来获取内部Expr的AST。 - Jeff Ward

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接