aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/pickling/PositionPickler.scala
blob: 6215a452d9ee6ab3e8dcf3509b9042872c2e2f95 (plain) (blame)
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
package dotty.tools
package dotc
package core
package pickling

import ast.tpd._
import ast.Trees.WithLazyField
import PickleFormat._
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(100000)
  pickler.newSection("Positions", buf)
  import buf._
  
  private def record(tree: Tree, parentPos: Position): Unit = {
    assert(tree.pos.exists)
    val startDelta = tree.pos.start - parentPos.start
    val endDelta = tree.pos.end - parentPos.end
    if (startDelta != 0 || endDelta != 0)
      for (addr <- addrOfTree(tree)) {
        buf.writeInt(addr.index)
        if (startDelta != 0) buf.writeInt(startDelta)
        if (endDelta != 0) {
          assert(endDelta < 0)
          buf.writeInt(endDelta)
        } else assert(startDelta >= 0)
      }
    
  }
    
  def picklePositions(roots: List[Tree], totalRange: Position)(implicit ctx: Context) = {
    buf.writeNat(totalRange.end)
    traverse(roots, totalRange, record)
  }
}