From 60ab9f8f525d319aa5b6d5052018c6781da036eb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Apr 2015 10:36:16 +0200 Subject: Pickling modularization reorg The pickling package got rather large and confusing with three separate tasks that each had their own conventions: read JVM classfiles, read Scala2 pickle info, read Tasty. The classes for each task are now in separate packages. --- .../tools/dotc/core/tasty/PositionPickler.scala | 75 ++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/dotty/tools/dotc/core/tasty/PositionPickler.scala (limited to 'src/dotty/tools/dotc/core/tasty/PositionPickler.scala') diff --git a/src/dotty/tools/dotc/core/tasty/PositionPickler.scala b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala new file mode 100644 index 000000000..b0550b70a --- /dev/null +++ b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala @@ -0,0 +1,75 @@ +package dotty.tools +package dotc +package core +package tasty + +import ast.tpd._ +import ast.Trees.WithLazyField +import TastyFormat._ +import core._ +import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annotations._ +import collection.mutable +import TastyBuffer._ +import util.Positions._ + +object PositionPickler { + + trait DeferredPosition { + var parentPos: Position = NoPosition + } + + def traverse(x: Any, parentPos: Position, op: (Tree, Position) => Unit)(implicit ctx: Context): Unit = + if (parentPos.exists) + x match { + case x: Tree @unchecked => + op(x, parentPos) + x match { + case x: MemberDef @unchecked => traverse(x.symbol.annotations, x.pos, op) + case _ => + } + traverse(x.productIterator, x.pos, op) + case x: DeferredPosition => + x.parentPos = parentPos + case xs: TraversableOnce[_] => + xs.foreach(traverse(_, parentPos, op)) + case _ => + } +} +import PositionPickler._ + +class PositionPickler(pickler: TastyPickler, addrOfTree: Tree => Option[Addr]) { + val buf = new TastyBuffer(5000) + pickler.newSection("Positions", buf) + import buf._ + + def picklePositions(roots: List[Tree], totalRange: Position)(implicit ctx: Context) = { + var lastIndex = 0 + def record(tree: Tree, parentPos: Position): Unit = + if (tree.pos.exists) { + def msg = s"failure to pickle $tree at ${tree.pos}, parent = $parentPos" + val endPos = tree.pos.end min parentPos.end + // end positions can be larger than their parents + // e.g. in the case of synthetic empty ranges, which are placed at the next token after + // the current construct. + val endDelta = endPos - parentPos.end + val startPos = + if (endDelta == 0) tree.pos.start max parentPos.start else tree.pos.start min endPos + // Since end positions are corrected above, start positions have to follow suit. + val startDelta = startPos - parentPos.start + if (startDelta != 0 || endDelta != 0) + for (addr <- addrOfTree(tree)) { + buf.writeInt(addr.index - lastIndex) + lastIndex = addr.index + if (startDelta != 0) buf.writeInt(startDelta) + if (endDelta != 0) { + assert(endDelta < 0, msg) + buf.writeInt(endDelta) + } else + assert(startDelta >= 0, msg) + } + } + + buf.writeNat(totalRange.end) + traverse(roots, totalRange, record) + } +} -- cgit v1.2.3