In Scala 2.9.x, I wrote the func function which gives me back the name of the function where func() is executed like the FUNC C preprocessor macro. I understand that in Scala2.10 I should be able to write something more elegant than throwing an exception to do the job.
How can I do it? Thanks in advance for your help.
object TestMyLog extends App {
val MatchFunc = """(.+)\(.+""".r
def func(i_level: Int): String = {
val s_rien = "functionNotFound"
try {
throw new Exception()
} catch {
case unknwn => unknwn.getStackTrace.toList.apply(i_level).toString match {
case MatchFunc(funcs) => funcs.split('.').toList.last
case _ => s_rien
}
} finally {
s_rien
}
}
def tracedFunction1 = func(1)
def tracedFunction2 = func(1)
println(tracedFunction1)
assert(tracedFunction1=="tracedFunction1")
println(tracedFunction2)
assert(tracedFunction2=="tracedFunction2")
}
With a macro, we can treat programs as values, which allows us to analyze and generate them at compile time. A Scala expression with type T is represented by an instance of the type scala.quoted.Expr [T].
Follow the instructions at the “Macro Paradise” page to download and use our compiler plugin if using those older Scala versions. Note that the macro paradise plugin is needed both to compile and to expand macro annotations, which means that your users will have to also add macro paradise to their builds in order to use your macro annotations.
Both in Scala IDE and in Intellij IDEA macros are known to work fine, given they are moved to a separate project. Debugging macros (i.e. the logic that drives macro expansion) is fairly straightforward. Since macros are expanded within the compiler, all that you need is to run the compiler under a debugger.
In order to work with more complex expressions, Scala 3 offers different metaprogramming facilities ranging from each increasing in complexity and potentially losing safety guarantees. It is generally recommended to prefer simple APIs over more advanced ones.
import scala.reflect.macros.Context
import scala.language.experimental.macros
def impl(c: Context) = {
import c.universe._
c.enclosingMethod match {
case DefDef(_, name, _, _, _, _) =>
c.universe.reify(println(c.literal(name.toString).splice))
case _ => c.abort(c.enclosingPosition, "no enclosing method")
}
}
scala> def printEnclosingMethod = macro impl
defined term macro printEnclosingMethod: Unit
scala> def foo = printEnclosingMethod
foo: Unit
scala> foo
foo
scala> printEnclosingMethod
<console>:32: error: no enclosing method
printEnclosingMethod
^
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With