#scala #scala-macros #scala-macro-paradise
#scala #scala-макросы #scala-макрос-рай
Вопрос:
Я использую аннотацию макроса для кода инструмента. Как я могу получить позицию диапазона некоторых выражений?
@ScalaKata object SHA {
val foo = "foo"
val bar = "bar"
foo; bar
// ...
}
// result: Map((75, 78) -> "foo", (80, 83) -> "bar")
Инструментальный макрос:
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
}
У меня включена опция диапазона scalacOptions = "-Yrangepos"
В настоящее время я получаю только начальную позицию: result: Map((75, 75) -> "foo", (80, 80) -> "bar")
Комментарии:
1. Какую версию Scala вы используете?
2. Я использую 2.11.1 и, очевидно, macro paradise.
3. К сожалению, это будет проблемой, поскольку в 2.11.x есть ошибка с позициями диапазона аргументов макроса, которая исправлена только в 2.11.2-SNAPSHOT. Если поддержка 2.11.0 и 2.11.1 действительно важна для вас, дайте мне знать, и мы что-нибудь придумаем.
Ответ №1:
В paradise есть ошибка, которая искажает позиции диапазона аргументов макроса. Теперь это исправлено в недавно опубликованном 2.1.0-SNAPSHOT.
Однако в Scala 2.11.0 и 2.11.1 также присутствует регрессия, которая также искажает позиции диапазона. Поэтому вы сможете получить доступ к позициям диапазонов в аннотациях макросов только в версии 2.10.x или в предстоящей версии 2.11.2 (запланирована на конец июля).
Комментарии:
1. Просто попробовал со scalaVersion : = «2.11.2-20140629.011517-23 «и рай»2.1.0-СНИМОК». Диапазон теперь работает. Спасибо
2. возможно ли получить положение открывающей и закрывающей скобки заключающего объекта (SHA)?
3. Не уверен. Если они не находятся в начале, точке или конце любого из поддеревьев ModuleDef, то, вероятно, нет. Вы смотрели на позицию шаблона?
4. Они начинаются с начала имени. Также у расширяющегося объекта нет позиции (NoPosition). Я решил это, обернув его
@... object A{ object B { /* code */ } }