Search code examples
scalamacrosannotationsvarscala-macros

Can I access the value(s) of the argument(s) of an annotation in the body of the variable (val/var) that is being annotated?


In my project, programmers can annotate certain fields of a class as a prediction in the following way :

class Foo() {
  @prediction('p1) var quality = // access 'p1 here
}

A Symbol is given in the definition of a prediction annotation that represents its id (in this case the id of quality is 'p1).

My problem: I want to access the value of that Symbol in the implementation of the quality variable. I think this is achievable by using a macro but I wasn't able to implement it.

My question: How can I achieve this (macros are allowed)?


Solution

  • Yes, you can. Try to make prediction a macro annotation

    class Foo() {
      @prediction('p1) var quality = {
        println(access) //'p1
      }
    }
    
    import scala.annotation.{StaticAnnotation, compileTimeOnly}
    import scala.language.experimental.macros
    import scala.reflect.macros.whitebox
    
    @compileTimeOnly("enable macro paradise to expand macro annotations")
    class prediction(s: Symbol) extends StaticAnnotation {
      def macroTransform(annottees: Any*): Any = macro predictionMacro.impl
    }
    
    object predictionMacro {
      def impl(c: whitebox.Context)(annottees: c.Tree*): c.Tree = {
        import c.universe._
        val symb = c.prefix.tree match {
          case q"new prediction($s)" => s
        }
        annottees match {
          case q"$mods var $tname: $tpt = $expr" :: _ =>
            q"""$mods var $tname: $tpt = {
                val access = $symb
                $expr
              }"""
        }
      }
    }