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

时间:2013-05-07 09:54:02

标签: scala scala-macros

如何让scala宏替换方法调用?

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

除了Expecty之外,我所看到的所有这些示例都是有效地使用静态方法调用:不使用调用宏的对象。 Expecty有以下方法,它给我一个关于如何检测'隐含这个'的线索,但我找不到在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 ) }
  }
}

1 个答案:

答案 0 :(得分:4)

您可以TreeToStringAdder实例获得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))