summaryrefslogblamecommitdiff
path: root/src/compiler/scala/tools/nsc/symtab/Scopes.scala
blob: fd002c1f8664f22ed702c32d7ac0c2f25cef6dcd (plain) (tree)
1
2
3
4
5
6
7
8
9




                            

                               
                                   
 
                                                       












                                                     




                                                              







                                                         



                                                          























                                                                              
  



                                                                         
  
                                          

     
                                     
             
                         

























                                                                 

                              


                                            
                                    
                   




                      
                                                                   
 
                                                                               





                                           






                                                    



                                            






                                       
                       
              


                                          

                              






                                                          




                        


                                     
                                    
                              

       











                                                 
                                      

                                                           
              

                                                           



       


                                                          
                                    
                                                                         
          
                                                                            
       

     





                                                                                  
                                              






                                           



                                                                                        


                                                                  



                                                                        



                                                                                   























                                                                   
/* NSC -- new scala compiler
 * Copyright 2005 LAMP/EPFL
 * @author  Martin Odersky
 */
// $Id$
package scala.tools.nsc.symtab;

trait Scopes requires SymbolTable {

  class ScopeEntry(val sym: Symbol, val owner: Scope) {

    /** the next entry in the hash bucket
     */
    var tail: ScopeEntry = _;

    /** the next entry in this scope
     */
    var next: ScopeEntry = null;

    override def hashCode(): int = sym.name.start;
    override def toString(): String = sym.toString();
  }

  def newScopeEntry(sym: Symbol, owner: Scope): ScopeEntry = {
    val e = new ScopeEntry(sym, owner);
    e.next = owner.elems;
    owner.elems = e;
    e
  }

  object NoScopeEntry extends ScopeEntry(NoSymbol, null);

  class Scope(initElems: ScopeEntry)  {

    var elems: ScopeEntry = initElems;

    /** The number of times this scope is neted in another
     */
    private var nestinglevel = 0;

    /** 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;

    /** size and mask of hash tables
     *  todo: make hashtables grow?
     */
    private val HASHSIZE = 0x80;
    private val HASHMASK = 0x7f;

    /** the threshold number of entries from which a hashtable is constructed.
     */
    private val MIN_HASH = 8;

    if (size >= MIN_HASH) createHash;

    def this() = this(null: ScopeEntry);

    def this(base: Scope) = {
      this(base.elems);
/*
      if (base.hashtable != null) {
	this.hashtable = new Array[ScopeEntry](HASHSIZE);
        System.arraycopy(base.hashtable, 0, this.hashtable, 0, HASHSIZE);
      }
*/
      nestinglevel = base.nestinglevel + 1
    }

    def this(decls: List[Symbol]) = {
      this();
      decls foreach enter
    }

    /** Returns a new scope with the same content as this one. */
    def cloneScope: Scope = {
      val clone = new Scope();
      this.toList foreach clone.enter;
      clone
    }

    /** is the scope empty? */
    def isEmpty: boolean = elems == null;

    /** the number of entries in this scope */
    def size: int = {
      var s = 0;
      var e = elems;
      while (e != null) {
        s = s + 1;
        e = e.next
      }
      s
    }

    /** enter a scope entry
     */
    def enter(e: ScopeEntry): unit = {
      elemsCache = null;
      if (hashtable != null) {
        val i = e.sym.name.start & HASHMASK;
        elems.tail = hashtable(i);
        hashtable(i) = elems;
      } else if (size >= MIN_HASH) {
        createHash;
      }
    }

    /** enter a symbol
     */
    def enter(sym: Symbol): unit = enter(newScopeEntry(sym, this));

    /** enter a symbol, asserting that no symbol with same name exists in scope
     */
    def enterUnique(sym: Symbol): unit = {
      assert(lookup(sym.name) == NoSymbol);
      enter(sym);
    }

    private def createHash: unit = {
      hashtable = new Array[ScopeEntry](HASHSIZE);
      enterInHash(elems);
    }

    private def enterInHash(e: ScopeEntry): unit = {
      if (e != null) {
        enterInHash(e.next);
        val i = e.sym.name.start & HASHMASK;
        e.tail = hashtable(i);
        hashtable(i) = e;
      }
    }

    /** remove entry
     */
    def unlink(e: ScopeEntry): unit = {
      if (elems == e) {
        elems = e.next;
      } else {
        var e1 = elems;
        while (e1.next != e) e1 = e1.next;
        e1.next = e.next;
      }
      if (hashtable != null) {
        var e1 = hashtable(e.sym.name.start & HASHMASK);
        if (e1 == e) {
          hashtable(e.sym.name.start & HASHMASK) = e.tail;
        } else {
          while (e1.tail != e) e1 = e1.tail;
          e1.tail = e.tail;
        }
      }
      elemsCache = null
    }

    /** remove symbol */
    def unlink(sym: Symbol): unit = {
      var e = lookupEntry(sym.name);
      while (e != null) {
        if (e.sym == sym) unlink(e);
        e = lookupNextEntry(e)
      }
    }

    /** lookup a symbol
     */
    def lookup(name: Name): Symbol = {
      val e = lookupEntry(name);
      if (e == null) NoSymbol else e.sym;
    }

    /** lookup a symbol entry matching given name
     */
    def lookupEntry(name: Name): ScopeEntry = {
      var e: ScopeEntry = null;
      if (false & hashtable != null) {
        e = hashtable(name.start & HASHMASK);
        while (e != null && e.sym.name != name) e = e.tail;
      } else {
        e = elems;
        while (e != null && e.sym.name != name) e = e.next;
      }
      e
    }

    /** lookup next entry with same name as this one */
    def lookupNextEntry(entry: ScopeEntry): ScopeEntry = {
      var e = entry;
      if (hashtable != null) //debug
      do { e = e.tail } while (e != null && e.sym.name != entry.sym.name)
      else
        do { e = e.next } while (e != null && e.sym.name != entry.sym.name);
      e
    }

    /** Return all symbols as a list in the order they were entered in this scope.
     */
    def toList: List[Symbol] = {
      if (elemsCache == null) {
        elemsCache = Nil;
        var e = elems;
        while (e != null && e.owner == this) {
          elemsCache = e.sym :: elemsCache;
          e = e.next
        }
      }
      elemsCache
    }

    /** Return all symbols as an interator in the order they were entered in this scope.
     */
    def elements: Iterator[Symbol] = toList.elements;

    def filter(p: Symbol => boolean): Scope =
      if (!(toList forall p)) new Scope(toList filter p) else this

    def mkString(start: String, sep: String, end: String) =
      toList.map(.defString).mkString(start, sep, end);

    override def toString(): String = mkString("{\n  ", ";\n  ", "\n}");

    /** Return the nesting level of this scope, i.e. the number of times this scope
     *  was nested in another */
    def nestingLevel = nestinglevel;
  }

  /** The empty scope (immutable).
   */
  object EmptyScope extends Scope {
    override def enter(e: ScopeEntry): unit =
      throw new Error("EmptyScope.enter");
  }

  /** The error scope.
   */
  class ErrorScope(owner: Symbol) extends Scope(null: ScopeEntry) {
    override def lookupEntry(name: Name): ScopeEntry = {
      val e = super.lookupEntry(name);
      if (e != NoSymbol) e
      else {
        enter(if (name.isTermName) owner.newErrorValue(name)
              else owner.newErrorClass(name));
        super.lookupEntry(name);
      }
    }
  }
}