5

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

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,或者相差一个。那是怎么回事?

4

1 回答 1

3

从某种意义上说,它是一个单独的错误,Position.column并且Position.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
        )
      )

对于“范围”位置,树顶的位置包括其下方的所有内容。所以 while pointis where the +is,start范围位置的 the 是范围位置所包围的所有内容的最早位置,即树中较低的所有内容。在这种情况下,左叶是x

因此,差异point - start告诉您要备份多远。

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

于 2013-09-11T03:13:47.417 回答