diff options
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala')
-rw-r--r-- | compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala new file mode 100644 index 000000000..546894a9e --- /dev/null +++ b/compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala @@ -0,0 +1,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) + } +} |