使用宏重写val和var构造函数参数

时间:2013-10-29 15:46:18

标签: scala macros

我正在评估创建宏注释的可能性和努力来解决这个问题:

@txn class Foo(var bar: Int)

进入这个:

import concurrent.stm.{Ref, InTxn}

class Foo(bar0: Int) {
  private val _bar = Ref(bar0)

  def bar(implicit tx: InTxn): Int = _bar()
  def bar_=(value: Int)(implicit tx: InTxn): Unit = _bar() = value
}

(或者可能使用Foo方法创建apply个随播广告对象,目前还不确定)

现在我从ClassDef身体看到的是这样的

List(<paramaccessor> var bar: Int = _, 
  def <init>(bar: Int) = {
    super.<init>();
    ()
  })

因此bar显示为没有init(_)的param-accessor,也是<init>方法的参数。

我如何重写那个身体?

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

class txn extends StaticAnnotation {
  def macroTransform(annottees: Any*) = macro txnMacro.impl
}
object txnMacro {
  def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    val inputs = annottees.map(_.tree).toList

    def reportInvalidAnnotationTarget(): Unit =
      c.error(c.enclosingPosition,
        "This annotation can only be used on a class definition")

    val expandees: List[Tree] = inputs match {
      case cd @ ClassDef(mods, nme, tp, tmp @ Template(parents, self, body)) :: Nil =>
        println(s"Body: $body")
        ???

      case _ =>
        reportInvalidAnnotationTarget()
        inputs
    }

    val outputs = expandees
    c.Expr[Any](Block(outputs, Literal(Constant(()))))
  }
}

1 个答案:

答案 0 :(得分:2)

正如尤金所说,使用quasiquotes可以使这更容易。我还没有提供完整的解决方案,但我尝试了一些部分,所以我认为这些方面的内容可行:

case q"class $name extends $parent with ..$traits { ..$body }"=>
  val newBody = body.flatMap {
    case q"var $varName = $varBody" =>
       List(
         //put the three defs you need here.  some variant of this ...
         q"""private val ${stringToTermName("_" + varName.toString)} = Ref(${stringToTermName(varName.name + "0")})""",
         //etc ...
       )
    case other => other
  }
  q"class $name extends $parent with ..$ttraits { ..${(newBody).toList} }"

您可能会发现我的博文相关:http://imranrashid.com/posts/learning-scala-macros/

最相关的代码段在这里: https://github.com/squito/learn_macros/blob/master/macros/src/main/scala/com/imranrashid/oleander/macros/FillTraitDefs.scala#L78

您可能还会发现这对定义吸气剂和放大器非常有用。 setter方法: https://groups.google.com/forum/#!searchin/scala-user/macro|sort:date/scala-user/Ug75FW73mJI/F1ijU0uxZAUJ