检索将分配Scala宏调用的值的名称

Ale*_*ron 2 macros scala scala-2.10 scala-macros

我正在尝试编写一个宏,它将包装一个函数并从其调用将赋值的值中扣除一个参数.

object TestMacros {
  def foo(name: String): String = name.toUpper
  def bar = macro barImpl
  def barImpl(c: Context): c.Expr[String] = {
    import c.universe._
    //TODO extract value name (should be baz)
    c.Expr[String](Apply(
      Select(newTermName("TestMacros"), newTermName("foo")), // Probably wrong, just typed it quickly for demonstration purposes
      List(Literal(Constant("test"))))) // Should replace test by value name
  }
}

object TestUsage {
  val baz = bar // should be BAZ
}
Run Code Online (Sandbox Code Playgroud)

我不知道这是否足够清楚.我已经调查了c.prefix和c.macroApplication而没有成功.我在没有宏天堂编译器插件的情况下使用Scala 2.10.2.

Tra*_*own 5

这很有可能.我知道,因为我之前做过类似的事情.诀窍是在封闭树中搜索右侧与宏应用程序具有相同位置的值:

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

object TestMacros {
  def foo(name: String): String = name.toUpperCase

  def bar = macro barImpl
  def barImpl(c: Context): c.Expr[String] = {
    import c.universe._

    c.enclosingClass.collect {
      case ValDef(_, name, _, rhs)
        if rhs.pos == c.macroApplication.pos => c.literal(foo(name.decoded))
    }.headOption.getOrElse(
      c.abort(c.enclosingPosition, "Not a valid application.")
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

然后:

scala> object TestUsage { val baz = TestMacros.bar }
defined module TestUsage

scala> TestUsage.baz
res0: String = BAZ

scala> class TestClassUsage { val zab = TestMacros.bar }
defined class TestClassUsage

scala> (new TestClassUsage).zab
res1: String = ZAB
Run Code Online (Sandbox Code Playgroud)

请注意,您可以foo在编译时应用,因为您知道编译时的名称val.如果你想在运行时应用它,当然也是可能的.