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




                            
 

                               


                                                  

                                            
                                                    













                                                                               
                                                



                                                           
                           
  


                                                                                                          
     
  

                                         
 



                                                 
                         
                             
                                                     
                                              


                                                                   

                               
                     






                                                                   
                                                         
     
 
                                                           

                                                
                                 




                                                                             




                                
                                                                                  



                                                          
                                                    
                                        
                          
                                                          
 

                                                            
                                                                                     
 
                                                                      
                                                           

                                           
                                  

       
                                                                             

                                                                             

                                                           




                                                      





                                                              

                                                            
       
 

                                                                    
                                                                    









                                                                                                        
         
       
                                                                  




                                                                                                        





                                                              
       




                                                                           
                                              


                                                                                


                                                
       
                                                                                                  


                                                       
 
  


                                                                           
  
 
                                                                                                                                         

                                                                             
                                                                
     






                                                                
                                                    
                                                      
   
  
                                                                        


                                                                                     
  

                                                                                             
                                                     
                                                       

   
                                                 
                                                                                
                                          
                                    
   
 
/* NSC -- new scala compiler
 * Copyright 2005 LAMP/EPFL
 * @author  Martin Odersky
 */
// $Id$

package scala.tools.nsc.symtab;

import java.io.{File, IOException};
import scala.tools.nsc.util.{Position, ClassPath};
import scala.tools.nsc.io.AbstractFile;
import scala.tools.nsc.util.NameTransformer;
import scala.collection.mutable.HashMap;
import classfile.{ClassfileParser, SymblfileParser};
import Flags._;


abstract class SymbolLoaders {
  val global: Global;
  import global._;

  /** A lazy type that completes itself by calling parameter doComplete.
   *  Any linked modules/classes or module classes are also initialized.
   *  @param doComplete    The type completion procedure to be run.
   *                       It takes symbol to compkete as parameter and returns
   *                       name of file loaded for completion as a result.
   *                       Can throw an IOException on error.
   */
  abstract class SymbolLoader extends LazyType {
    /** Load source or class file for `root', return */
    protected def doComplete(root: Symbol): unit;
    /** The kind of file that's processed by this loader */
    protected def kindString: String;
    private var ok = false;
/*
    private def setSource(sym: Symbol, sourceFile0: AbstractFile): unit = sym match {
      case clazz: ClassSymbol => if (sourceFile0 != null) clazz.sourceFile = sourceFile0;
      case _ => if (sourceFile0 != null) if (false) System.err.println("YYY: " + sym + " " + sourceFile0);
    }
*/
    def sourceFile : AbstractFile = null;
    protected def sourceString : String;

    override def complete(root: Symbol): unit = {
      try {
        val start = System.currentTimeMillis();
        val currentphase = phase;
        doComplete(root);
        phase = currentphase;
	def source = kindString + " " + sourceString;
        informTime("loaded " + source, start);
        if (root.rawInfo == this && root.linkedSym.rawInfo == this)
          throw new TypeError(source + " does not define " + root)
	ok = true;
      } catch {
        case ex: IOException =>
          ok = false;
	  if (settings.debug.value) ex.printStackTrace();
          val msg = ex.getMessage();
          error(
            if (msg == null) "i/o error while loading " + root.name
            else "error while loading " + root.name + ", " + msg);
      }
      initRoot(root);
      if (!root.isPackageClass) initRoot(root.linkedSym);
    }

    override def load(root: Symbol): unit = complete(root);

    private def initRoot(root: Symbol): unit = {
      if (root.rawInfo == this) {
        def markAbsent(sym: Symbol) =
          if (sym != NoSymbol) sym.setInfo(if (ok) NoType else ErrorType);
        markAbsent(root);
        markAbsent(root.moduleClass)
      } else if (root.isClass && !root.isModuleClass) root.rawInfo.load(root)
    }
  }

  /** Load contents of a package
   */
  class PackageLoader(directory: global.classPath0.Context) extends SymbolLoader {
    // System.err.println("PACKAGE LOADER: " + directory);

    protected def sourceString = directory.toString();

    protected def doComplete(root: Symbol): unit = {
      assert(root.isPackageClass, root);
      val scope = newScope
      root.setInfo(new PackageClassInfoType(scope, root));

      /** Is the given name a valid input file base name? */
      def isValid(name: String): boolean =
        name.length() > 0 && !name.endsWith("$class") && name.indexOf("$anon") == -1;

      def enterPackage(str: String, completer: SymbolLoader): unit = {
        val pkg = root.newPackage(NoPos, newTermName(str));
        pkg.moduleClass.setInfo(completer);
        pkg.setInfo(pkg.moduleClass.tpe);
        root.info.decls.enter(pkg)
      }

      def enterClassAndModule(str: String, completer: SymbolLoader): unit = {
	val owner = if (root.isRoot) definitions.EmptyPackageClass else root;
	val name = newTermName(str);
        val clazz = owner.newClass(NoPos, name.toTypeName);
        val module = owner.newModule(NoPos, name);
        clazz.setInfo(completer);
        module.setInfo(completer);
        module.moduleClass.setInfo(moduleClassLoader);
        owner.info.decls.enter(clazz);
        owner.info.decls.enter(module);
/*
	if (completer.sourceFile != null) {
          clazz.sourceFile = completer.sourceFile;
          module.moduleClass.sourceFile = completer.sourceFile
        }
*/
        assert(clazz.linkedModuleOfClass == module, module);
        assert(module.linkedClassOfModule == clazz, clazz);
      }

      val classes  = new HashMap[String, global.classPath0.Context];
      val packages = new HashMap[String, global.classPath0.Context];
      for (val dir <- directory.entries) if (dir.location != null) {
        for (val file <- dir.location) {
      	  if (file.isDirectory && directory.validPackage(file.name) && !packages.isDefinedAt(file.name))
      	    packages(file.name) = directory.find(file.name, true);
      	  else if (!file.isDirectory && file.name.endsWith(".class")) {
      	    val name = file.name.substring(0, file.name.length() - (".class").length());
      	    if (isValid(name) && !classes.isDefinedAt(name)) {
              val clazz = directory.find(name, false);
              if (clazz != null) classes(name) = clazz;
            }
      	  }
      	}
      }
      for (val dir <- directory.entries) if (dir.source != null) {
        for (val file <- dir.source.location) {
      	  if (file.isDirectory && directory.validPackage(file.name) && !packages.isDefinedAt(file.name))
      	    packages(file.name) = directory.find(file.name, true);
      	  else if (dir.source.compile && !file.isDirectory && file.name.endsWith(".scala")) {
      	    val name = file.name.substring(0, file.name.length() - (".scala").length());
      	    if (isValid(name) && !classes.isDefinedAt(name)) {
              val source = directory.find(name, false);
              if (source != null) classes(name) = source;
            }
      	  }
      	}
      }
      //if (!packages.isEmpty) System.err.println("COMPLETE: " + packages);
      //if (! classes.isEmpty) System.err.println("COMPLETE: " + classes);
      // do classes first

      for (val Pair(name, file) <- classes.elements) {
      	val loader = if (!file.isSourceFile) {
      	  new ClassfileLoader(file.classFile, file.sourceFile, file.sourcePath);
      	} else {
      	  assert(file.sourceFile != null);
      	  new SourcefileLoader(file.sourceFile);
      	}
      	enterClassAndModule(name, loader);
      }
      for (val Pair(name, file) <- packages.elements) enterPackage(name, new PackageLoader(file));
    }
    protected def kindString: String = "directory path"
  }

/*
  private object symblfileParser extends SymblfileParser {
    val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global;
  }
*/

  class ClassfileLoader(classFile: AbstractFile, override val sourceFile: AbstractFile, sourcePath0: AbstractFile) extends SymbolLoader {
    private object classfileParser extends ClassfileParser {
      val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global;
      override def sourcePath = sourcePath0; /* could be null */
    }
    protected def doComplete(root: Symbol): unit = {
      classfileParser.parse(classFile, root);
      if (sourceFile != null) root match {
      case clazz : ClassSymbol => clazz.sourceFile = sourceFile;
      case _ =>
      }
    }
    protected def kindString: String = "class file";
    protected def sourceString = classFile.toString();
  }
/*
  class SymblfileLoader(file: AbstractFile) extends SymbolLoader(file) {
    protected def doComplete(root: Symbol): unit = symblfileParser.parse(file, root);
    protected def kindString: String = "symbl file";
  }
*/
  class SourcefileLoader(override val sourceFile: AbstractFile) extends SymbolLoader {
    protected def doComplete(root: Symbol): unit = global.currentRun.compileLate(sourceFile);
    protected def kindString: String = "source file";
    protected def sourceString = sourceFile.toString();
  }

  object moduleClassLoader extends SymbolLoader {
    protected def doComplete(root: Symbol): unit = root.sourceModule.initialize;
    protected def kindString: String = "";
    protected def sourceString = "";
  }
}