idesupport.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 617 行 · 第 1/2 页

SCALA
617
字号
package scala.tools.nsc.symtabimport scala.tools.nsc.util._   import scala.collection.jcl._import scala.collection.jclimport scala.tools.nsc.io._trait IdeSupport extends SymbolTable { // added to global, not analyzers.  trait ScopeClient {    def changed : Unit = {}     def addTo(set : => LinkedHashSet[ScopeClient]) = set += this    def notify(name : Name, scope : HookedScope) : Boolean = false    def notify(name : Name, sym : Symbol) : Unit = {}    def verifyAndPrioritize[T](verify : Symbol => Symbol)(pt : Type)(f : => T) : T = f    def makeNoChanges : Boolean = false  }  override def inIDE = true  import CompatibleResult._  trait TrackedPosition extends Position with ReallyHasClients {    // symbols without scopes!    def asOffset : Option[(Int,AbstractFile)]    private var recycled : List[Symbol] = Nil    def recycle(sym : Symbol) : Symbol = {      recycled.foreach{existing => compatible(existing,sym) match {      case NotCompatible => false      case GoResult(existing) => return existing      }}      recycled = sym :: recycled; sym    }    private var scopes : List[((ScopeKind,AnyRef),PersistentScope)] = Nil    def scopeFor(key : (ScopeKind,AnyRef)) : PersistentScope =       scopes.find{      case (key0,scope) if key == key0 => true      case _ => false      } match {      case Some((_,scope)) => reuse(scope)      case None =>         val scope = new PersistentScope(key,this)        scopes = (key,scope) :: scopes        scope      }  }  // dynamic context  private object NullClient extends ScopeClient {    override def addTo(clients : => LinkedHashSet[ScopeClient]) = {}  }    def currentClient : ScopeClient = NullClient  abstract class HookedScope(entry : ScopeEntry) extends Scope(entry) {    def record(client : ScopeClient, name : Name) = {}    override def lookupEntry(name : Name) = {      val client = currentClient      if (client.notify(name, this)) null // not found      else {        record(client, name)        super.lookupEntry(name)      }    }  }  private val topDefs = new LinkedHashMap[AbstractFile,LinkedHashSet[ClassSymbol]] {    override def default(what : AbstractFile) = {      val set = new LinkedHashSet[ClassSymbol]      this(what) = set; set    }  }  private val emptySet = new jcl.LinkedList[Symbol]  val reuseMap = new LinkedHashMap[PersistentScope,jcl.LinkedList[Symbol]] {    override def default(key : PersistentScope) = emptySet  }  def reuse(scope : PersistentScope, sym : Symbol) = {    var e = scope.lookupEntry(sym.name)    var delete = List[Symbol]()    while (e != null && e.sym != sym) {      if (false && !e.sym.rawInfo.isComplete) {        assert(true)        delete = e.sym :: delete      }      e = scope.lookupNextEntry(e)    }    delete.foreach(scope.unlink)    if (e != null && e.sym == sym) {      assert(true)      val list = reuseMap.get(scope) match {      case Some(list) => list      case None =>        val list = new jcl.LinkedList[Symbol]        reuseMap(scope) = list; list      }      assert(!sym.isPackage)      import symtab.Flags._      if (sym.isClass && sym.hasFlag(CASE)) {        // grab the case factory        val name = sym.name.toTermName        e = scope.lookupEntry(name)        while (e != null && !e.sym.hasFlag(MODULE)) e = scope.lookupNextEntry(e)        assert(e != null)        list += e.sym        scope unlink e.sym        //Console.println("RS-UNLINK: " + factory)      }      // if def is abstract, will only unlink its name      if (sym.isGetter) {        val setter = scope lookup nme.getterToSetter(sym.name)        if (setter != NoSymbol && setter.isSetter) {          list += setter          scope unlink setter          //Console.println("RS-UNLINK: " + setter)        }      } else if (sym.hasGetter) {         e = scope lookupEntry nme.getterName(sym.name)        while (e != null && !e.sym.isGetter) e = scope lookupNextEntry e        if (e != null) {          val getter = e.sym          assert(getter.accessed == sym && !getter.isSetter)          list += getter          scope unlink getter          //Console.println("RS-UNLINK: " + getter)          e = scope lookupEntry nme.getterToSetter(getter.name)          while (e != null && !e.sym.isSetter) e = scope lookupNextEntry e          if (e != null) {            assert(getter.accessed == sym)            val setter = e.sym            list += setter            scope unlink setter            //Console.println("RS-UNLINK: " + setter)          }        }      }      //Console.println("RS-UNLINK: " + sym)      list += sym      scope unlink sym // clear from scope.    }  }  private def reuse(scope : PersistentScope) : PersistentScope = {    if (currentClient.makeNoChanges) return scope    val buf = new jcl.LinkedList[Symbol]    buf addAll scope.toList    buf.foreach(sym => assert(!sym.isPackage))    scope.clear    if (!buf.isEmpty) {      assert(true)            reuseMap(scope) = buf     }    scope  }    // TODO: implement a good compile late for the IDE.   def reloadSource(file : AbstractFile) = {    assert(true)    if (!currentClient.makeNoChanges) topDefs.removeKey(file) match {  case None =>   case Some(symbols) => symbols.foreach{sym =>      def f(sym : Symbol) = sym.owner.info.decls match {      case scope : PersistentScope => reuse(scope, (sym))      }      if (sym.isModuleClass) {         assert(sym.name.isTypeName)        if (sym.hasRawInfo)          if (sym.linkedModuleOfClass != NoSymbol) f(sym.linkedModuleOfClass)      } else {        assert(sym.name.isTypeName)        f(sym)      }    }  }  }  override def attachSource(clazz : ClassSymbol, file : io.AbstractFile) = {    topDefs(file) += clazz    super.attachSource(clazz, file)  }  def finishTyping = {    val clear = reuseMap.toList    reuseMap.clear    clear.foreach{    case (scope,old) => old.foreach{    case NoSymbol =>     case sym =>       // note that we didn't unlink them      val scope0 = scope      Console.println("RECYCLE: " + sym + ":" + sym.id + " in " + sym.owner + " " + scope0 + " " + scope0.key);       scope0.invalidate(sym.name)    }}    reuseMap.clear    tracedTypes.foreach{case (sym,oldType) =>      if (sym.rawInfo != NoType && !sym.rawInfo.isComplete) {        Console.println("XXX uncompleted: " + sym)      }      val resetType = sym.info == NoType || hasError(sym.info)      if (!resetType && !compareTypes(sym.info, oldType,Nil)(sym => tracedTypes.get(sym) match {      case None => sym.info       case Some(oldType) => oldType      })) (trackedTypes.removeKey(sym) match {      case Some(set) => set.foreach(_.changed)      case None =>        })       if (resetType) {        assert(true)        sym.setInfo(oldType) // restore old good type.      }    }    tracedTypes.clear  }  def oldTypeFor(sym : Symbol) = tracedTypes.get(sym) match {  case Some(tpe) => tpe  case None => NoType  }    private def compare0(newP : Any, oldP : Any, syms : List[Symbol])(implicit oldType : Symbol => Type) : Boolean = ((newP,oldP) match {  case (newP:AnyRef,oldP:AnyRef) if newP eq oldP => true  case (newP:Type,oldP:Type) => compareTypes(newP,oldP, syms)  case (newS:Symbol,oldS:Symbol) if compareSyms(newS,oldS,syms) => true    case (newL:List[a],oldL:List[b]) =>    var va = newL; var vb = oldL    while (!va.isEmpty && !vb.isEmpty) {      if (!compare0(va.head,vb.head,syms)) return false      va = va.tail; vb = vb.tail    }    va.isEmpty && vb.isEmpty  case (newS:Scope,oldS:Scope) =>    val set = new LinkedHashSet[Symbol]    set addAll newS.toList    oldS.toList.forall{oldS => if (!set.remove(oldS)) {      var other = newS.lookupEntry(oldS.name)      while (other != null && !compareTypes(other.sym.info,oldType(oldS), syms))        other = newS.lookupNextEntry(other)      other != null    } else true}  case (newP,oldP) => newP == oldP  })  private def compareSyms(newS : Symbol, oldS : Symbol, syms : List[Symbol])(implicit oldType : Symbol => Type) =     if (oldS eq newS) {      if (syms.contains(oldS)) true      else {        compareTypes(newS.info, oldType(oldS), newS :: syms)      }    } else {      if (syms.contains(oldS) && syms.contains(newS)) true      else newS.name == oldS.name && newS.owner == oldS.owner && newS.flags == oldS.flags &&        compareTypes(newS.info,oldType(oldS), newS :: oldS :: syms)    }  def hasError(infoA : Type) : Boolean = {    if (infoA == ErrorType) return true    infoA match {    case MethodType(args,ret) => hasError(ret) || args.exists(hasError)    case PolyType(params,ret) => hasError(ret)    case TypeBounds(lo,hi) => hasError(lo) || hasError(hi)    case TypeRef(pre,_,args) => hasError(pre) || args.exists(hasError)    case _ => false    }  }  def compareTypes(newInfo : Type, oldInfo : Type, syms : List[Symbol])(implicit oldType : Symbol => Type) : Boolean = (newInfo eq oldInfo) || (newInfo.getClass == oldInfo.getClass && ((newInfo,oldInfo) match {  case (newInfo:ThisType,oldInfo:ThisType) if compare0(newInfo.typeSymbol,oldInfo.typeSymbol,syms) => true   case (newInfo:Product, oldInfo:Product) =>    (0 until newInfo.productArity).forall(i =>       compare0(newInfo.productElement(i), oldInfo.productElement(i),syms))  }))    trait HasClients {    def record(client : ScopeClient, name : Name) : Unit     def invalidate(name : Name) : Unit  }    trait ReallyHasClients extends HasClients {    private var clients : Map = null    private class Map extends LinkedHashMap[Int,LinkedHashSet[ScopeClient]] {      override def default(hash : Int) = {        val set = new LinkedHashSet[ScopeClient]        this(hash) = set; set      }    }    def record(client : ScopeClient, name : Name) : Unit =       client.addTo({        if (clients eq null) clients = new Map        clients(name.start)      })    override def invalidate(name : Name) : Unit = if (clients ne null) clients.removeKey(name.start) match {    case Some(clients) => clients.foreach(_.changed)    case None =>    }  }        class PersistentScope(val key : AnyRef, val owner : HasClients) extends HookedScope(null) {    override def record(client : ScopeClient, name : Name) =       owner.record(client, name)    override def invalidate(name : Name) : Unit = owner.invalidate(name)    override def enter(symbol : Symbol) : Symbol = {      if (currentClient.makeNoChanges) { // might have unpickles.        return if (lookupEntry(symbol.name) == null)           super.enter(symbol)        else symbol      }      def finish(symbol : Symbol) = {        if (symbol.isTypeSkolem) {          assert(true)          assert(true)        }        if (symbol.owner.isPackageClass && !symbol.isPackageClass && symbol.sourceFile != null) {          assert(true)          assert(true)          topDefs(symbol.sourceFile) += (symbol match {            case symbol : ClassSymbol => symbol            case symbol : ModuleSymbol => symbol.moduleClass.asInstanceOf[ClassSymbol]          })        }        super.enter(symbol)      }      def nuke(existing: Symbol, other : Symbol) : Unit = {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?