:
import scala.language.experimental.macros
import reflect.macros.Context
implicit class WithSourceHelper[T](source: T) {
def withSource[R](f: (String, T) => R): R = macro withSourceImpl[T, R]
}
def withSourceImpl[T, R](c: Context)(f: c.Expr[(String, T) => R]): c.Expr[R] = {
import c.universe.{reify, Apply}
val source = c.prefix.tree match {
case Apply(_, List(s)) => s
case _ => c.abort(c.enclosingPosition, "can't find source")
}
reify{ f.splice.apply(c.literal(source.toString).splice, c.Expr[T](source).splice) }
}
使い方。 withSource
マクロは同じオブジェクト自体からは利用できません(そのため、わずかに変更されたバージョンのwithSourceをそのファイルに追加することはできません)。WithSourceHelper
のサブクラスからwithSource
を呼び出して継承を通じて再利用を制限できません。
誰かが興味がある場合は、ソースの値をログに記録して残りの計算が行われるように値を返すだけで、Seniaの答えを補うことができます。
def logValueImpl[T](c: Context): c.Expr[T] = {
import c.universe._
val source = c.prefix.tree match {
case Apply(_, List(s)) => s
case _ => c.abort(c.enclosingPosition, "can't find source")
}
val freshName = newTermName(c.fresh("logValue$"))
val valDef = ValDef(Modifiers(), freshName, TypeTree(source.tpe), source)
val ident = Ident(freshName)
val print = reify{
println(c.literal(show(source)).splice + ": " + c.Expr[T](ident).splice) }
c.Expr[T](Block(List(valDef, print.tree), ident))
}
次に暗黙の変換としてdef p = macro Debug.logValueImpl[T]
と定義します。
List(1, 2, 3).reverse.p.head
// prints: immutable.this.List.apply[Int](1, 2, 3).reverse: List(3, 2, 1)
面白い部分は、私はそれを2回適用することができるということです:
List(1, 2, 3).reverse.p.p
そして、それはlogValueImpl
マクロが何をしたか、私が表示されます:
{
val logValue$7: List[Int] = immutable.this.List.apply[Int](1, 2, 3).reverse;
Predef.println("immutable.this.List.apply[Int](1, 2, 3).reverse: ".+(logValue$7));
logValue$7
}
私は、このように使用することができます他のマクロでもうまくいくようです:
f"float ${1.3f}%3.2f; str ${"foo".reverse}%s%n".p`
//prints:
{
val arg$1: Float = 1.3;
val arg$2: Any = scala.this.Predef.augmentString("foo").reverse;
scala.this.Predef.augmentString("float %3.2f; str %s%%n").format(arg$1, arg$2)
}: float 1.30; str oof%n
show
の代わりにshowRaw
を使用した場合、他のマクロの書き方を理解するのに便利な拡張マクロのツリーも見ることができます。
私はちょうど次のライブラリに類似の機能(およびその他)があることを知りました:https://github.com/retronym/macrocosm; 'log'、' trace'、 'desugar'を参照してください... – huynhjl