aboutsummaryrefslogblamecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala
blob: 546894a9efca7d87b860c6d1488bb788ac2996f9 (plain) (tree)
1
2
3
4
5
6
7
8
9


                   
             
 

                  
                              
                    



                                                                                        

                       
                                                                                    
                                 

                                      

                  

                                                                                  
                                                                                                 
                                           
                                                                                                
   
 
                                                                   
                     




                                                   
                                                                                       

                                                   
                                                        


                       


                                                                                      

                                                                                               
                                                                                                 


                     
                                          
                                

                                                                                   
                               
                              

                                                          
                     
                                             
           
         
                                                        
                 
                                         
                                                                

                   
                                   
                                    
                            

                           

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