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か、1つずれていると思います。どうしたの?

4

1 に答える 1

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
        )
      )

「範囲」位置では、ツリーの最上部の位置にはその下のすべてが含まれます。while pointis where+start、範囲位置の は、範囲位置で囲まれたすべてのもの、つまり、ツリー内の下位のすべてのものの最初の位置です。この場合、左の葉はx.

したがって、その違いによって、point - startどこまでバックアップする必要があるかがわかります。

(文字エンコーディングの違いにより、ソース ファイルへのオフセットが列オフセットと異なる場合は考慮していません。)

于 2013-09-11T03:13:47.417 に答える