1

I'm using macro annotation to instrument code. How can I get the range position of some expressions ?

@ScalaKata object SHA {
    val foo = "foo" 
    val bar = "bar"
    foo; bar
    // ...
}
// result: Map((75, 78) -> "foo", (80, 83) -> "bar")

The instrumenting macro:

package com.scalakata.eval

import scala.reflect.macros.blackbox.Context

import scala.language.experimental.macros
import scala.annotation.StaticAnnotation

object ScalaKataMacro {

  def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._


    val result: Tree = {
      val eval = newTermName("eval$")
      annottees.map(_.tree).toList match {
        case q"object $name { ..$body }" :: Nil => {

          val instr = newTermName("instr$")
          implicit def lift = Liftable[c.universe.Position] { p =>
            q"(${p.start}, ${p.end})"
          }
          def instrument(rhs: Tree): Tree = {
            q"""
            {
              val t = $rhs
              ${instr}(${rhs.pos}) = t
              t
            }
            """
          }

          val bodyI = body.map {
            case ident: Ident => instrument(ident)
            case otherwise => otherwise
          }
          q"""
          object $name { 
            val $instr = scala.collection.mutable.Map.empty[(Int, Int), Any]

            def $eval() = {
              ..$bodyI
              $instr
            }
          }
          """
        }
      }
    }
    c.Expr[Any](result)
  }
}

class ScalaKata extends StaticAnnotation {
  def macroTransform(annottees: Any*) = macro ScalaKataMacro.impl
}

I have range option enabled scalacOptions += "-Yrangepos"

I'm currently getting only the starting position: result: Map((75, 75) -> "foo", (80, 80) -> "bar")

Guillaume Massé
  • 8,004
  • 8
  • 44
  • 57

1 Answers1

1

There is a bug in paradise that corrupts range positions of macro arguments. It's now fixed in freshly published 2.1.0-SNAPSHOT.

However, there's also a regression in Scala 2.11.0 and 2.11.1 that also corrupts range positions. Therefore you will only be able to access range positions in macro annotations in 2.10.x or in the upcoming 2.11.2 (scheduled for the end of July).

Eugene Burmako
  • 13,028
  • 1
  • 46
  • 59
  • Just tryed with scalaVersion := "2.11.2-20140629.011517-23" and paradise "2.1.0-SNAPSHOT". The range is now working. Thanks – Guillaume Massé Jun 29 '14 at 15:27
  • is it all possible to get the position of the opening and the closing bracket of the enclosing object (SHA)? – Guillaume Massé Jun 29 '14 at 18:56
  • Not sure. If they aren't in start, point or end of any of the subtrees of ModuleDef, then probably not. Have you looked into the position of the Template? – Eugene Burmako Jul 02 '14 at 10:39
  • They start at the beginning of the name. Also the expanding object dont have a position (NoPosition). I solved this by wraping it ```@... object A{ object B { /* code */ } }``` – Guillaume Massé Jul 02 '14 at 19:50