1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
package dotty.tools
package dotc
package core
package tasty
import ast._
import ast.Trees._
import ast.Trees.WithLazyField
import TastyFormat._
import core._
import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annotations._
import collection.mutable
import TastyBuffer._
import util.Positions._
class PositionPickler(pickler: TastyPickler, addrOfTree: tpd.Tree => Option[Addr]) {
val buf = new TastyBuffer(5000)
pickler.newSection("Positions", buf)
import buf._
import ast.tpd._
private val remainingAddrs = new java.util.IdentityHashMap[Tree, Iterator[Addr]]
def header(addrDelta: Int, hasStartDelta: Boolean, hasEndDelta: Boolean, hasPoint: Boolean) = {
def toInt(b: Boolean) = if (b) 1 else 0
(addrDelta << 3) | (toInt(hasStartDelta) << 2) | (toInt(hasEndDelta) << 1) | toInt(hasPoint)
}
def picklePositions(roots: List[Tree])(implicit ctx: Context) = {
var lastIndex = 0
var lastPos = Position(0, 0)
def pickleDeltas(index: Int, pos: Position) = {
val addrDelta = index - lastIndex
val startDelta = pos.start - lastPos.start
val endDelta = pos.end - lastPos.end
buf.writeInt(header(addrDelta, startDelta != 0, endDelta != 0, !pos.isSynthetic))
if (startDelta != 0) buf.writeInt(startDelta)
if (endDelta != 0) buf.writeInt(endDelta)
if (!pos.isSynthetic) buf.writeInt(pos.pointDelta)
lastIndex = index
lastPos = pos
}
/** True if x's position cannot be reconstructed automatically from its initialPos
*/
def alwaysNeedsPos(x: Positioned) = x match {
case _: WithLazyField[_] // initialPos is inaccurate for trees with lazy field
| _: Trees.PackageDef[_] => true // package defs might be split into several Tasty files
case _ => false
}
def traverse(x: Any): Unit = x match {
case x: Tree @unchecked =>
val pos = if (x.isInstanceOf[MemberDef]) x.pos else x.pos.toSynthetic
if (pos.exists && (pos != x.initialPos.toSynthetic || alwaysNeedsPos(x))) {
addrOfTree(x) match {
case Some(addr) =>
//println(i"pickling $x with $pos at $addr")
pickleDeltas(addr.index, pos)
case _ =>
//println(i"no address for $x")
}
}
//else if (x.pos.exists) println(i"skipping $x")
x match {
case x: MemberDef @unchecked =>
for (ann <- x.symbol.annotations) traverse(ann.tree)
case _ =>
}
traverse(x.productIterator)
case xs: TraversableOnce[_] =>
xs.foreach(traverse)
case x: Annotation =>
traverse(x.tree)
case _ =>
}
traverse(roots)
}
}
|