检索将分配给 Scala 宏调用的值的名称 [英] Retrieve the name of the value a Scala macro invocation will be assigned to

查看:44
本文介绍了检索将分配给 Scala 宏调用的值的名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个宏,该宏将包装一个函数并从其调用将分配给的值中减去一个参数.

I'm attempting to write a macro that would wrap a function and deducting a parameter from the value its invocation will be assigned to.

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
}

我不知道这是否足够清楚.我研究了c.prefix和c.macroApplication都没有成功.我正在使用没有宏天堂编译器插件的Scala 2.10.2.

I don't know if this is clear enough. I've investigated both c.prefix and c.macroApplication without success. I'm using Scala 2.10.2 without the macro-paradise compiler plugin.

推荐答案

这很有可能.我知道,因为我已经完成之前类似的事情.技巧是在外围树中搜索一个值,该值的右侧与宏应用程序的位置相同:

This is very possible. I know, because I've done something like it before. The trick is to search the enclosing tree for a value whose right-hand side has the same position as the macro application:

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.")
    )
  }
}

然后:

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

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

Note that you can apply foo at compile-time, since you know the name of the val at compile-time. If you wanted it to be applied at runtime that would also be possible, of course.

这篇关于检索将分配给 Scala 宏调用的值的名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆