9

如何获取 scala 宏来替换方法调用?

我的目标是创建一个名为ToStringAdder. 假设我有一个x具有此特征的对象,那么当我调用时,x.add(any)我希望宏实际调用x.add(any, string)字符串是 AST 的字符串表示形式的位置。(这样tostring当'any'是一个函数时我可以很好)。

除了 Expecty,我看到的所有这些例子都有效地使用了静态方法调用:调用宏的对象没有被使用。Expecty 具有以下方法,它为我提供了有关如何检测“隐式 this”的线索,但我找不到在 reify 调用中引用它的方法。

 private[this] def recordAllValues(expr: Tree): Tree = expr match {
    case New(_) => expr // only record after ctor call
    case Literal(_) => expr // don't record
    // don't record value of implicit "this" added by compiler; couldn't find a better way to detect implicit "this" than via point
    case Select(x@This(_), y) if getPosition(expr).point == getPosition(x).point => expr
    case _ => recordValue(recordSubValues(expr), expr)
  }

那么我该如何替换对已调用宏的对象的调用。我现在的代码如下,需要排序的是reify调用中的代码

trait ToStringAdder {
  def add(param: Any): Any = macro ToStringAdder.toStringAndValueImpl
  def add(param: Any, toStringBasedOnAST: String): Any ; //This is the actual method I want the above method call to be replaced by
}

object ToStringAdder {
  def toStringAndValueImpl(c: Context)(param: c.Expr[Any]): c.Expr[Unit] = {
    import c.universe._
    val paramRep = show(param.tree)
    val paramRepTree = Literal(Constant(paramRep))
    val paramRepExpr = c.Expr[String](paramRepTree)
    //need to put something here 
     reify { c.someMethodCall("something to represent the method any", param.splice, paramRepExpr.splice ) }
  }
}
4

1 回答 1

4

您可以Tree为您的ToStringAdder实例获取c.prefix.

试试这个:

reify { c.Expr[ToStringAdder](c.prefix.tree).splice.add(param.splice, c.literal(paramRep).splice) }

证明它有效:

scala> :paste
// Entering paste mode (ctrl-D to finish)

import scala.language.experimental.macros
import reflect.macros.Context

trait ToStringAdder {
  def add(param: Any): Any = macro ToStringAdder.toStringAndValueImpl
  def add(param: Any, toStringBasedOnAST: String): Any ; //This is the actual method I want the above method call to be replaced by
}

object ToStringAdder {
  def toStringAndValueImpl(c: Context)(param: c.Expr[Any]): c.Expr[Any] = {
    import c.universe._
    val paramRep = show(param.tree)
    reify { (c.Expr[ToStringAdder](c.prefix.tree)).splice.add(param.splice, c.literal(paramRep).splice) }
  }
}


// Exiting paste mode, now interpreting.

import scala.language.experimental.macros
import reflect.macros.Context
defined trait ToStringAdder
defined module ToStringAdder

scala> class ToStringAdder1 extends ToStringAdder {
     |   def add(param: Any, toStringBasedOnAST: String): Any = s"param: $param \ntoStringBasedOnAST: $toStringBasedOnAST"
     | }
defined class ToStringAdder1

scala> new ToStringAdder1().add( (i: Int) => i*2 )
res0: Any =
param: <function1>
toStringBasedOnAST: ((i: Int) => i.*(2))
于 2013-05-07T10:13:30.940 回答