我正在尝试将参数的原始输入字符串添加到宏中,但返回的位置似乎有点偏离。考虑这个宏,例如:
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
,或者被一个人关闭。怎么了?
答案 0 :(得分: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
)
)
对于“范围”位置,树顶部的位置包括它下面的所有内容。因此,虽然point
是+
所在的位置,但是范围位置的start
是范围位置所包围的所有内容的最早位置,即树中较低的一切。在这种情况下,左侧叶子是x
。
因此差异point - start
会告诉您备份的距离。
(由于字符编码的差异,我没有考虑如果源文件中的偏移与列偏移不同会怎样。)