2013-09-10 30 views
5

Próbuję uzyskać oryginalny ciąg wejściowy parametru do makra, ale zwrócona pozycja wydaje się nieco wyłączona. Rozważmy to makro, na przykład:Co się dzieje z pozycją w makrach Scali?

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

Kiedy próbuję go z tego pliku:

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

uzyskać ten wynik:

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

który nie ma sensu dla mnie. Spodziewam się, że wskaże on na x, lub będzie wyłączony przez jeden. Co z tym?

+0

Jeśli go zmienić na 'println (MF (x. + (Y)))) punkt przesuwa się o jeden do punktu na y, a za pomocą 'println (Mf (if (true) {x + y})) wskazuje na f, jeśli. Podejrzewam, że próbuje wskazać wierzchołek drzewa, inwokację + lub if, ale to, czy ma, czy nie, jest kolejnym pytaniem. Może również występować co najmniej jeden błąd typu "off-by-one". Wygląda to na stosowne dla zgłoszenia błędu. – wingedsubmariner

+0

Byłoby śmieszniej, gdyby pytanie brzmiało: Jakie jest Twoje stanowisko w sprawie makr? –

Odpowiedz

3

To błąd typu "jeden po drugim" w tym sensie, że Position.column i Position.line są oparte na 1.

To błąd w dokumentacji w tym sensie, że zadali sobie trud udokumentowania interfejsu API, ale nie zadali sobie trudu, aby o tym wspomnieć.

można skompilować z -Yrangepos oraz:

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

lub podobny do wskazania najwcześniejszą pozycję w drzewie.

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

Aktualizacja:

Letting makro zwróci wyrażenie to podane, i zestawiania ze -Xprint:typer -Yshow-trees, drzewo jest wewnętrzna Apply węzeł, który jest umieszczony na +:

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

Z pozycja "zakres", pozycja wierzchołka drzewa zawiera wszystko poniżej. Więc podczas gdy point jest gdzie znajduje się +, start pozycji zakresu jest najwcześniejszą pozycją wszystkiego zawartą przez pozycję zasięgu, tj. Wszystko poniżej w drzewie. W tym przypadku lewy liść to x.

Tak więc różnica point - start mówi, jak daleko należy się cofnąć.

(nie rozważaliśmy, co jeśli przesunięcia w pliku źródłowym różnią się od kolumn przesunięć z powodu różnic w kodowaniu znaków).

+0

Ale na co wskazuje "kolumna"? A jakie jest znaczenie "pos.point - pos.startOrPoint" (które były dla mnie bezsensowne)? –

+0

@ DanielC.Sobral Wiem tylko tyle o pozycjach zasięgu, aby wprowadzić błąd, który musieli naprawić ludzie IDE. Przynajmniej naprawiałem też błąd, więc było to pranie. Poza tym myślałem, że -Yrangepos stanie się domyślnym? Zaktualizowany moją ograniczoną wiedzą. –

+0

@ DanielC.Sobral Istnieją ulepszone komentarze (i kod) na https://github.com/scala/scala/pull/2936 –

Powiązane problemy