什么与Scala宏的位置有关?

时间:2013-09-10 21:45:15

标签: scala macros

我正在尝试将参数的原始输入字符串添加到宏中,但返回的位置似乎有点偏离。考虑这个宏,例如:

object M {
  import scala.reflect.macros.Context
  import language.experimental.macros
  def f[T](v: => T) = macro fImpl[T]
  def fImpl[T : c.WeakTypeTag](c: Context)(v: c.Expr[T]): c.Expr[Unit] = {
    import c.universe._
    val pos = v.tree.pos
    println(pos.lineContent)
    println(" " * pos.column + "^")
    println(" " * pos.point + "^")
    c.literalUnit 
  }
}

当我尝试使用此文件时:

object N extends App {
  val x = 1
  val y = 2
  println(M.f(x + y))
}

我得到了这个输出:

  println(M.f(x + y))
                 ^
                                                                  ^

对我来说没有意义。我希望它指向x,或者被一个人关闭。怎么了?

1 个答案:

答案 0 :(得分:3)

Position.columnPosition.line基于1的意义上讲,这是一个错误的错误。

这是一个文档错误,因为他们不愿意记录API,但没有理由提及。

您可以使用-Yrangepos

进行编译
val n = pos.column - (pos.point - pos.startOrPoint) - 1
println(" " * n + "^")

或类似表示树中最早的位置。

println(M.f(x + y))
            ^

更新

让宏返回给定的表达式,并使用-Xprint:typer -Yshow-trees进行编译,树是内部Apply节点,位于+

      Apply( // def println(x: Any): Unit in object Predef, tree.tpe=Unit
        scala.this."Predef"."println" // def println(x: Any): Unit in object Predef, tree.tpe=(x: Any)Unit
        Apply( // def +(x: Int): Int in class Int, tree.tpe=Int
          "x"."$plus" // def +(x: Int): Int in class Int, tree.tpe=(x: Int)Int
          "y" // val y: Int, tree.tpe=Int
        )
      )

对于“范围”位置,树顶部的位置包括它下面的所有内容。因此,虽然point+所在的位置,但是范围位置的start是范围位置所包围的所有内容的最早位置,即树中较低的一切。在这种情况下,左侧叶子是x

因此差异point - start会告诉您备份的距离。

(由于字符编码的差异,我没有考虑如果源文件中的偏移与列偏移不同会怎样。)