diff options
author | Martin Odersky <odersky@gmail.com> | 2012-12-06 14:06:00 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2012-12-06 14:06:00 +0100 |
commit | 90962407e72d88f8f3249ade0f6bd60ff15af5ce (patch) | |
tree | 6b2fc0ba13bad7c4532ebf1df39b0b2f5d7e70b6 /src/dotty/tools/dotc/core/Scopes.scala | |
parent | 2308509d2651ee78e1122b5d61b798c984c96c4d (diff) | |
download | dotty-90962407e72d88f8f3249ade0f6bd60ff15af5ce.tar.gz dotty-90962407e72d88f8f3249ade0f6bd60ff15af5ce.tar.bz2 dotty-90962407e72d88f8f3249ade0f6bd60ff15af5ce.zip |
Initial commit
Diffstat (limited to 'src/dotty/tools/dotc/core/Scopes.scala')
-rw-r--r-- | src/dotty/tools/dotc/core/Scopes.scala | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/core/Scopes.scala b/src/dotty/tools/dotc/core/Scopes.scala new file mode 100644 index 000000000..cc50e9072 --- /dev/null +++ b/src/dotty/tools/dotc/core/Scopes.scala @@ -0,0 +1,299 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2012 LAMP/EPFL + * @author Martin Odersky + */ + +package dotty.tools.dotc +package core + +import Symbols._ +import Names._ +import Periods._ +import Decorators._ +import Contexts._ + +object Scopes { + + /** Maximal fill factor of hash table */ + private final val FillFactor = 2.0/3.0 + + /** A hashtable is created once current size exceeds MinHash * FillFactor + * The initial hash table has twice that size (i.e 24). + */ + private final val MinHash = 12 + + /** The maximal permissible number of recursions when creating + * a hashtable + */ + private final val MaxRecursions = 1000 + + class ScopeEntry private[Scopes] (val sym: Symbol, val owner: Scope) { + + /** the next entry in the hash bucket + */ + var tail: ScopeEntry = null + + /** the preceding entry in this scope + */ + var prev: ScopeEntry = null + + override def toString: String = sym.toString + } + + /** Note: constructor is protected to force everyone to use the factory methods newScope or newNestedScope instead. + * This is necessary because when run from reflection every scope needs to have a + * SynchronizedScope as mixin. + */ + class Scope protected[Scopes](initElems: ScopeEntry, initSize: Int, val nestingLevel: Int = 0) + extends Iterable[Symbol] { + + protected[Scopes] def this(base: Scope)(implicit ctx: Context) = { + this(base.lastEntry, base.size, base.nestingLevel + 1) + ensureCapacity(MinHash)(ctx) // WTH??? it seems the implicit is not in scope for a secondary constructor call. + } + + def this() = this(null, 0, 0) + + private[dotc] var lastEntry: ScopeEntry = initElems + + /** The size of the scope */ + private[this] var _size = initSize + + override def size = _size + private def size_= (x: Int) = _size = x + + /** the hash table + */ + private var hashTable: Array[ScopeEntry] = null + + /** a cache for all elements, to be used by symbol iterator. + */ + private var elemsCache: List[Symbol] = null + + /** Returns a new scope with the same content as this one. */ + def cloneScope(implicit ctx: Context): Scope = newScopeWith(this.toList: _*) + + /** is the scope empty? */ + override def isEmpty: Boolean = lastEntry eq null + + /** create and enter a scope entry */ + protected def newScopeEntry(sym: Symbol)(implicit ctx: Context): ScopeEntry = { + val e = new ScopeEntry(sym, this) + e.prev = lastEntry + lastEntry = e + size += 1 + elemsCache = null + if (hashTable ne null) { + ensureCapacity(hashTable.length) + enterInHash(e) + } else { + ensureCapacity(MinHash) + } + e + } + + private def enterInHash(e: ScopeEntry)(implicit ctx: Context): Unit = { + val i = e.sym.name.start & (hashTable.length - 1) + e.tail = hashTable(i) + hashTable(i) = e + } + + /** enter a symbol + * + * @param sym ... + */ + def enter[T <: Symbol](sym: T)(implicit ctx: Context): T = { + newScopeEntry(sym) + sym + } + + /** enter a symbol, asserting that no symbol with same name exists in scope + * + * @param sym ... + */ + def enterUnique(sym: Symbol)(implicit ctx: Context) { + assert(lookup(sym.name) == NoSymbol, (sym.locatedFullString, lookup(sym.name).locatedFullString)) + enter(sym) + } + + private def ensureCapacity(tableSize: Int)(implicit ctx: Context): Unit = + if (size > tableSize * FillFactor) createHash(tableSize * 2) + + private def createHash(tableSize: Int)(implicit ctx: Context): Unit = + if (size > tableSize * FillFactor) createHash(tableSize * 2) + else { + hashTable = new Array[ScopeEntry](tableSize) + enterAllInHash(lastEntry) + } + + private def enterAllInHash(e: ScopeEntry, n: Int = 0)(implicit ctx: Context) { + if (e ne null) { + if (n < MaxRecursions) { + enterAllInHash(e.prev, n + 1) + enterInHash(e) + } else { + var entries: List[ScopeEntry] = List() + var ee = e + while (ee ne null) { + entries = ee :: entries + ee = ee.prev + } + entries foreach enterInHash + } + } + } + + /** remove entry from this scope. */ + def unlink(e: ScopeEntry)(implicit ctx: Context) { + if (lastEntry == e) { + lastEntry = e.prev + } else { + var e1 = lastEntry + while (e1.prev != e) e1 = e1.prev + e1.prev = e.prev + } + if (hashTable ne null) { + val index = e.sym.name.start & (hashTable.length - 1) + var e1 = hashTable(index) + if (e1 == e) + hashTable(index) = e.tail + else { + while (e1.tail != e) e1 = e1.tail; + e1.tail = e.tail + } + } + elemsCache = null + size -= 1 + } + + /** remove symbol from this scope */ + def unlink(sym: Symbol)(implicit ctx: Context) { + var e = lookupEntry(sym.name) + while (e ne null) { + if (e.sym == sym) unlink(e); + e = lookupNextEntry(e) + } + } + + /** lookup a symbol + * + * @param name ... + * @return ... + */ + def lookup(name: Name)(implicit ctx: Context): Symbol = { + val e = lookupEntry(name) + if (e eq null) NoSymbol else e.sym + } + + /** Returns an iterator yielding every symbol with given name in this scope. + */ + def lookupAll(name: Name)(implicit ctx: Context): Iterator[Symbol] = new Iterator[Symbol] { + var e = lookupEntry(name) + def hasNext: Boolean = e ne null + def next(): Symbol = { val r = e.sym; e = lookupNextEntry(e); r } + } + + /** lookup a symbol entry matching given name. + * @note from Martin: I believe this is a hotspot or will be one + * in future versions of the type system. I have reverted the previous + * change to use iterators as too costly. + */ + def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { + var e: ScopeEntry = null + if (hashTable ne null) { + e = hashTable(name.start & (hashTable.length - 1)) + while ((e ne null) && e.sym.name != name) { + e = e.tail + } + } else { + e = lastEntry + while ((e ne null) && e.sym.name != name) { + e = e.prev + } + } + e + } + + /** lookup next entry with same name as this one */ + def lookupNextEntry(entry: ScopeEntry)(implicit ctx: Context): ScopeEntry = { + var e = entry + if (hashTable ne null) + do { e = e.tail } while ((e ne null) && e.sym.name != entry.sym.name) + else + do { e = e.prev } while ((e ne null) && e.sym.name != entry.sym.name); + e + } + + /** Return all symbols as a list in the order they were entered in this scope. + */ + override def toList: List[Symbol] = { + if (elemsCache eq null) { + elemsCache = Nil + var e = lastEntry + while ((e ne null) && e.owner == this) { + elemsCache = e.sym :: elemsCache + e = e.prev + } + } + elemsCache + } + + /** Vanilla scope - symbols are stored in declaration order. + */ + def sorted: List[Symbol] = toList + + /** Return all symbols as an iterator in the order they were entered in this scope. + */ + def iterator: Iterator[Symbol] = toList.iterator + + override def foreach[U](p: Symbol => U): Unit = toList foreach p + + def filteredScope(p: Symbol => Boolean)(implicit ctx: Context): Scope = { + val unfiltered = toList + val filtered = unfiltered filterConserve p + if (filtered eq unfiltered) this + else newScopeWith(filtered: _*) + } + + @deprecated("Use `toList.reverse` instead", "2.10.0") + def reverse: List[Symbol] = toList.reverse + + override def mkString(start: String, sep: String, end: String) = + toList.map(_.defString).mkString(start, sep, end) + + override def toString(): String = mkString("Scope{\n ", ";\n ", "\n}") + } + + /** Create a new scope */ + def newScope: Scope = new Scope() + + /** Create a new scope nested in another one with which it shares its elements */ + def newNestedScope(outer: Scope)(implicit ctx: Context): Scope = new Scope(outer) + + /** Create a new scope with given initial elements */ + def newScopeWith(elems: Symbol*)(implicit ctx: Context): Scope = { + val scope = newScope + elems foreach scope.enter + scope + } + + /** Create new scope for the members of package `pkg` */ + def newPackageScope(pkgClass: Symbol): Scope = newScope + + /** Transform scope of members of `owner` using operation `op` + * This is overridden by the reflective compiler to avoid creating new scopes for packages + */ + def scopeTransform(owner: Symbol)(op: => Scope): Scope = op + + /** The empty scope (immutable). + */ + object EmptyScope extends Scope { + override def newScopeEntry(sym: Symbol)(implicit ctx: Context): ScopeEntry = { + throw new AssertionError("EmptyScope.newScopeEntry") + } + } + + /** The error scope (mutable) + */ + class ErrorScope(owner: Symbol) extends Scope +} |