首页 > 解决方案 > 将字符串插值器宏包装在另一个中

问题描述

我有插值xxx器由宏实现(我拥有代码)并返回 XXX。yyy当我有函数时,我想实现插值器f: XXX => YYY

编码

class XXXMacro(val c: blackbox.Context) {
  import c.universe._

  final def xxx(args: c.Expr[Any]*): c.Expr[XXX] = {
      val Apply(_, Apply(_, parts) :: Nil) = c.prefix.tree
      ???
  }
}

implicit class XXXInterpolator(sc: StringContext) {
  def xxx(args: Any*): XXX = macro XXXMacro.xxx
}

class YYYMacro(val c: blackbox.Context) {
  import c.universe._

  final def yyy(args: c.Expr[Any]*): c.Expr[YYY] = q"yyy($xxx\"args\")"
}

implicit class YYYInterpolator(sc: StringContext) {
  def yyy(args: Any*): YYY = macro XXXMacro.yyy
}

问题是我不能轻易参数化代码。编译器不会让我做macro XXXMacro(f).yyy or macro XXXMacro.yyy(f)

此外,当我将它像宏中的上下文一样包装时,它def yyy(args: Any*): YYY = f(new XXXInterpolator(sc).xxx(args))完全不同并使其复杂化,我无法重用它。有什么办法让它更容易吗?

标签: scalascala-macrosscala-reflect

解决方案


我不希望 XXXMacro 依赖于 YYY。所以解决方案是用户traitTree

trait XXXMacroTree {
  val c: blackbox.Context
  import c.universe._

  final def xxxTree(args: c.Expr[Any]*): Tree = ???

  final def xxx(args: c.Expr[Any]*): c.Expr[XXX] = c.Expr[XXX](xxxTree(args: _*))
}
class XXXMacro(val c: blackbox.Context) extends XXXMacroTree

implicit class XXXInterpolator(sc: StringContext) {
  def xxx(args: Any*): XXX = macro XXXMacro.xxx
}

class YYYMacro(val c: blackbox.Context) extends XXXMacroTree {
  import c.universe._

  final def yyy(args: c.Expr[Any]*): c.Expr[YYY] = c.Expr[YYY](q"f(${xxxTree(args: _*)}))
}

implicit class YYYInterpolator(sc: StringContext) {
  def yyy(args: Any*): YYY = macro YYYMacro.yyy
}

推荐阅读