我正在尝试将参数的原始输入字符串获取到宏,但返回的位置似乎有点偏.考虑这个宏,例如:
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
}
}
Run Code Online (Sandbox Code Playgroud)
当我尝试使用此文件时:
object N extends App {
val x = 1
val y = 2
println(M.f(x + y))
}
Run Code Online (Sandbox Code Playgroud)
我得到这个输出:
println(M.f(x + y))
^
^
Run Code Online (Sandbox Code Playgroud)
这对我没有意义.我希望它指向x,或者被一个人关闭.那是怎么回事?
Position.column从和Position.line是基于 1 的意义上来说,这是一个差一错误。
从某种意义上说,这是一个文档错误,因为他们费心记录 API,但没有费心提及这一点。
您可以使用-Yrangeposand 进行编译:
val n = pos.column - (pos.point - pos.startOrPoint) - 1
println(" " * n + "^")
Run Code Online (Sandbox Code Playgroud)
或类似的指示树中最早的位置。
println(M.f(x + y))
^
Run Code Online (Sandbox Code Playgroud)
更新:
让宏返回给定的表达式,并使用 进行编译-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
)
)
Run Code Online (Sandbox Code Playgroud)
对于“范围”位置,树顶部的位置包括其下方的所有内容。因此,当pointis 位于范围位置的+is 时,start范围位置的 是范围位置所包围的所有内容(即树中较低位置的所有内容)的最早位置。在这种情况下,左叶是x。
因此,差异point - start告诉您要备份多远。
(我没有考虑如果由于字符编码的差异导致源文件的偏移量与列偏移量不同怎么办。)