Scala macro get enclosing line

試著忘記壹切 提交于 2019-12-10 17:59:53

问题


I have the following macro

object Example {
  def doIt(s: String): String = macro doItImpl

  def doItImpl(c: Context)(s: c.Expr[String]): c.Expr[String] = {
    import c.{ universe => u }
    import u._
    ???
  }
}

Instead of the ??? I would like to inspect the line where the method doIt was called to check if the result of the method was used (in an assignment, method call or whatever). If the result is not used I respond with an error-message.

Call-example:

val s: String = doIt("Hallo") // alright
doIt("Hallo") // ERROR!

Is there a simple way to get the Tree of the whole line?


回答1:


For completeness, here's a lightly adapted version of the solution I mention above:

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

object Example {
  def doIt(s: String): String = macro doItImpl

  def doItImpl(c: Context)(s: c.Expr[String]): c.Expr[String] = {
    import c.universe._

    c.enclosingClass.collect {
      case ValDef(_, name, _, rhs) if rhs.pos == c.macroApplication.pos =>
        c.literal(s"Okay, defining a variable named ${name.decoded}.")
    }.headOption.getOrElse(
      c.abort(c.enclosingPosition, "Not a valid application.")
    )
  }
}

Now in a REPL:

scala> import Example._
import Example._

scala> object Test1 { val x = doIt("foo") }
defined module Test1

scala> Test1.x
res0: String = Okay, defining a variable named x.

And in the case that we don't have an definition:

scala> object Test2 { doIt("foo") }
<console>:13: error: Not a valid application.
       object Test2 { doIt("foo") }
                          ^

As expected. See the comments on the question linked above for some caveats, but unless your real use case is much more complicated, this approach should work fine.



来源:https://stackoverflow.com/questions/20452609/scala-macro-get-enclosing-line

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!