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 + -
显示快捷键?