Skip to content
This repository
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 185 lines (152 sloc) 7.371 kb
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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
/* NSC -- new Scala compiler
* Copyright 2009-2013 Typesafe/Scala Solutions and LAMP/EPFL
* @author Martin Odersky
*/
package scala.tools.nsc
package interactive

import util.InterruptReq
import scala.reflect.internal.util.{ SourceFile, BatchSourceFile }
import io.{ AbstractFile, PlainFile, Pickler, CondPickler }
import util.EmptyAction
import scala.reflect.internal.util.{ RangePosition, OffsetPosition, TransparentPosition }
import io.Pickler._
import scala.collection.mutable
import mutable.ListBuffer

trait Picklers { self: Global =>

  lazy val freshRunReq =
    unitPickler
      .wrapped { _ => new FreshRunReq } { x => () }
      .labelled ("FreshRunReq")
      .cond (_.isInstanceOf[FreshRunReq])

      lazy val shutdownReq = singletonPickler(ShutdownReq)

  def defaultThrowable[T <: Throwable]: CondPickler[T] = javaInstancePickler[T] cond { _ => true }

  implicit lazy val throwable: Pickler[Throwable] =
    freshRunReq | shutdownReq | defaultThrowable

  implicit def abstractFile: Pickler[AbstractFile] =
    pkl[String]
      .wrapped[AbstractFile] { new PlainFile(_) } { _.path }
      .asClass (classOf[PlainFile])

  private val sourceFilesSeen = new mutable.HashMap[AbstractFile, Array[Char]] {
    override def default(key: AbstractFile) = Array()
  }

  type Diff = (Int /*start*/, Int /*end*/, String /*replacement*/)

  def delta(f: AbstractFile, cs: Array[Char]): Diff = {
    val bs = sourceFilesSeen(f)
    var start = 0
    while (start < bs.length && start < cs.length && bs(start) == cs(start)) start += 1
    var end = bs.length
    var end2 = cs.length
    while (end > start && end2 > start && bs(end - 1) == cs(end2 - 1)) { end -= 1; end2 -= 1 }
    sourceFilesSeen(f) = cs
    (start, end, cs.slice(start, end2).mkString(""))
  }

  def patch(f: AbstractFile, d: Diff): Array[Char] = {
    val (start, end, replacement) = d
    val patched = sourceFilesSeen(f).patch(start, replacement, end - start)
    sourceFilesSeen(f) = patched
    patched
  }

  implicit lazy val sourceFile: Pickler[SourceFile] =
    (pkl[AbstractFile] ~ pkl[Diff]).wrapped[SourceFile] {
      case f ~ d => new BatchSourceFile(f, patch(f, d))
    } {
      f => f.file ~ delta(f.file, f.content)
    }.asClass (classOf[BatchSourceFile])

  lazy val offsetPosition: CondPickler[OffsetPosition] =
    (pkl[SourceFile] ~ pkl[Int])
      .wrapped { case x ~ y => new OffsetPosition(x, y) } { p => p.source ~ p.point }
      .asClass (classOf[OffsetPosition])

  lazy val rangePosition: CondPickler[RangePosition] =
    (pkl[SourceFile] ~ pkl[Int] ~ pkl[Int] ~ pkl[Int])
      .wrapped { case source ~ start ~ point ~ end => new RangePosition(source, start, point, end) } { p => p.source ~ p.start ~ p.point ~ p.end }
      .asClass (classOf[RangePosition])

  lazy val transparentPosition: CondPickler[TransparentPosition] =
    (pkl[SourceFile] ~ pkl[Int] ~ pkl[Int] ~ pkl[Int])
      .wrapped { case source ~ start ~ point ~ end => new TransparentPosition(source, start, point, end) } { p => p.source ~ p.start ~ p.point ~ p.end }
      .asClass (classOf[TransparentPosition])

  lazy val noPosition = singletonPickler(NoPosition)

  implicit lazy val position: Pickler[Position] = transparentPosition | rangePosition | offsetPosition | noPosition

  implicit lazy val namePickler: Pickler[Name] =
    pkl[String] .wrapped[Name] {
      str => if ((str.length > 1) && (str endsWith "!")) newTypeName(str.init) else newTermName(str)
    } {
      name => if (name.isTypeName) name.toString+"!" else name.toString
    }

  implicit lazy val symPickler: Pickler[Symbol] = {
    def ownerNames(sym: Symbol, buf: ListBuffer[Name]): ListBuffer[Name] = {
      if (!sym.isRoot) {
        ownerNames(sym.owner, buf)
        buf += (if (sym.isModuleClass) sym.sourceModule else sym).name
        if (!sym.isType && !sym.isStable) {
          val sym1 = sym.owner.info.decl(sym.name)
          if (sym1.isOverloaded) {
            val index = sym1.alternatives.indexOf(sym)
            assert(index >= 0, sym1+" not found in alternatives "+sym1.alternatives)
            buf += newTermName(index.toString)
          }
        }
      }
      buf
    }
    def makeSymbol(root: Symbol, names: List[Name]): Symbol = names match {
      case List() =>
        root
      case name :: rest =>
        val sym = root.info.decl(name)
        if (sym.isOverloaded) makeSymbol(sym.alternatives(rest.head.toString.toInt), rest.tail)
        else makeSymbol(sym, rest)
    }
    pkl[List[Name]] .wrapped { makeSymbol(rootMirror.RootClass, _) } { ownerNames(_, new ListBuffer).toList }
  }

  implicit def workEvent: Pickler[WorkEvent] = {
    (pkl[Int] ~ pkl[Long])
      .wrapped { case id ~ ms => WorkEvent(id, ms) } { w => w.atNode ~ w.atMillis }
  }

  implicit def interruptReq: Pickler[InterruptReq] = {
    val emptyIR: InterruptReq = new InterruptReq { type R = Unit; val todo = () => () }
    pkl[Unit] .wrapped { _ => emptyIR } { _ => () }
  }

  implicit def reloadItem: CondPickler[ReloadItem] =
    pkl[List[SourceFile]]
      .wrapped { ReloadItem(_, new Response) } { _.sources }
      .asClass (classOf[ReloadItem])

  implicit def askTypeAtItem: CondPickler[AskTypeAtItem] =
    pkl[Position]
      .wrapped { new AskTypeAtItem(_, new Response) } { _.pos }
      .asClass (classOf[AskTypeAtItem])

  implicit def askTypeItem: CondPickler[AskTypeItem] =
    (pkl[SourceFile] ~ pkl[Boolean])
      .wrapped { case source ~ forceReload => new AskTypeItem(source, forceReload, new Response) } { w => w.source ~ w.forceReload }
      .asClass (classOf[AskTypeItem])

  implicit def askTypeCompletionItem: CondPickler[AskTypeCompletionItem] =
    pkl[Position]
      .wrapped { new AskTypeCompletionItem(_, new Response) } { _.pos }
      .asClass (classOf[AskTypeCompletionItem])

  implicit def askScopeCompletionItem: CondPickler[AskScopeCompletionItem] =
    pkl[Position]
      .wrapped { new AskScopeCompletionItem(_, new Response) } { _.pos }
      .asClass (classOf[AskScopeCompletionItem])

  implicit def askToDoFirstItem: CondPickler[AskToDoFirstItem] =
    pkl[SourceFile]
      .wrapped { new AskToDoFirstItem(_) } { _.source }
      .asClass (classOf[AskToDoFirstItem])

  implicit def askLinkPosItem: CondPickler[AskLinkPosItem] =
    (pkl[Symbol] ~ pkl[SourceFile])
      .wrapped { case sym ~ source => new AskLinkPosItem(sym, source, new Response) } { item => item.sym ~ item.source }
      .asClass (classOf[AskLinkPosItem])

  implicit def askLoadedTypedItem: CondPickler[AskLoadedTypedItem] =
    pkl[SourceFile]
      .wrapped { source => new AskLoadedTypedItem(source, new Response) } { _.source }
      .asClass (classOf[AskLoadedTypedItem])

  implicit def askParsedEnteredItem: CondPickler[AskParsedEnteredItem] =
    (pkl[SourceFile] ~ pkl[Boolean])
      .wrapped { case source ~ keepLoaded => new AskParsedEnteredItem(source, keepLoaded, new Response) } { w => w.source ~ w.keepLoaded }
      .asClass (classOf[AskParsedEnteredItem])

  implicit def emptyAction: CondPickler[EmptyAction] =
    pkl[Unit]
      .wrapped { _ => new EmptyAction } { _ => () }
      .asClass (classOf[EmptyAction])

  implicit def action: Pickler[() => Unit] =
    reloadItem | askTypeAtItem | askTypeItem | askTypeCompletionItem | askScopeCompletionItem |
    askToDoFirstItem | askLinkPosItem | askLoadedTypedItem | askParsedEnteredItem | emptyAction
}
Something went wrong with that request. Please try again.