如何让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 ) }
}
}
答案 0 :(得分: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))