diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala new file mode 100644 index 0000000000..11f0c21c4f --- /dev/null +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -0,0 +1,192 @@ +/* NSC -- new scala compiler + * Copyright 2005 LAMP/EPFL + * @author Martin Odersky + */ +// $Id$ +package scala.tools.nsc.symtab; + +import java.io.IOException; +import scala.tools.nsc.util.Position; +import scala.tools.util.{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(file: AbstractFile) 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): unit = sym match { + case clazz: ClassSymbol => clazz.sourceFile = file; + case _ => + } + override def complete(root: Symbol): unit = { + try { + val start = System.currentTimeMillis(); + val currentphase = phase; + doComplete(root); + phase = currentphase; + def source = kindString + " " + file; + informTime("loaded " + source, start); + if (root.rawInfo != this) { + ok = true; + setSource(root.linkedModule); + setSource(root.linkedClass); + } else error(source + " does not define " + root) + } catch { + case ex: IOException => + 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) { + root.setInfo(if (ok) NoType else ErrorType); + if (root.isModule) + root.moduleClass.setInfo(if (ok) NoType else ErrorType) + } + if (root.isClass && !root.isModuleClass) root.rawInfo.load(root) + } + } + + /** Load contents of a package + */ + class PackageLoader(directory: AbstractFile) extends SymbolLoader(directory) { + protected def doComplete(root: Symbol): unit = { + assert(root.isPackageClass, root); + root.setInfo(new PackageClassInfoType(new 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(Position.NOPOS, newTermName(str)); + pkg.moduleClass.setInfo(completer); + pkg.setInfo(pkg.moduleClass.tpe); + root.info.decls.enter(pkg) + } + + def enterClassAndModule(str: String, completer: SymbolLoader, sfile : AbstractFile): unit = { + val owner = if (root.isRoot) definitions.EmptyPackageClass else root; + val name = newTermName(str); + val clazz = owner.newClass(Position.NOPOS, name.toTypeName); + val module = owner.newModule(Position.NOPOS, name); + clazz.sourceFile = sfile; + clazz.setInfo(completer); + module.setInfo(completer); + module.moduleClass.setInfo(moduleClassLoader); + owner.info.decls.enter(clazz); + owner.info.decls.enter(module); + assert(clazz.linkedModule == module, module); + assert(module.linkedClass == clazz, clazz); + } + + val sources = new HashMap[String, AbstractFile]; + val classes = new HashMap[String, AbstractFile]; + val packages = new HashMap[String, AbstractFile]; + val it = directory.list(); + while (it.hasNext()) { + val file = it.next().asInstanceOf[AbstractFile]; + val filename = file.getName(); + if (file.isDirectory()) { + if (filename != "META_INF" && !packages.isDefinedAt(filename)) packages(filename) = file; +/* + } else if (filename.endsWith(".symbl")) { + val name = filename.substring(0, filename.length() - 6); + if (isValid(name) && + (!classes.isDefinedAt(name) || classes(name).getName().endsWith(".class"))) + classes(name) = file; +*/ + } else if (filename.endsWith(".class")) { + val name = filename.substring(0, filename.length() - 6); + if (isValid(name) && !classes.isDefinedAt(name)) + classes(name) = file; + } else if (filename.endsWith(".scala")) { + val name = filename.substring(0, filename.length() - 6); + if (isValid(name) && !sources.isDefinedAt(name)) + sources(name) = file; + } + } + for (val Pair(name, sfile) <- sources.elements) { + classes.get(name) match { + case Some(cfile) if (cfile.lastModified() >= sfile.lastModified()) => {} + case _ => enterClassAndModule(name, new SourcefileLoader(sfile), sfile); + } + } + for (val Pair(name, cfile) <- classes.elements) { + val sfile = sources.get(name) match { + case Some(sfile0) => sfile0; + case _ => null; + } + sources.get(name) match { + case Some(sfile) if (sfile.lastModified() > cfile.lastModified()) => {} + case _ => + val loader = +/* if (cfile.getName().endsWith(".symbl")) new SymblfileLoader(cfile) + else */ + new ClassfileLoader(cfile); + enterClassAndModule(name, loader, sfile) + } + } + for (val Pair(name, file) <- packages.elements) { + if (!sources.contains(name) && !classes.contains(name)) + enterPackage(name, new PackageLoader(file)); + } + } + protected def kindString: String = "directory path" + } + + private object classfileParser extends ClassfileParser { + val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global; + } + +/* + private object symblfileParser extends SymblfileParser { + val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global; + } +*/ + + class ClassfileLoader(file: AbstractFile) extends SymbolLoader(file) { + protected def doComplete(root: Symbol): unit = classfileParser.parse(file, root); + protected def kindString: String = "class file"; + } +/* + 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(file: AbstractFile) extends SymbolLoader(file) { + protected def doComplete(root: Symbol): unit = global.currentRun.compileLate(file); + protected def kindString: String = "source file"; + } + + object moduleClassLoader extends SymbolLoader(null) { + protected def doComplete(root: Symbol): unit = + root.sourceModule.initialize; + protected def kindString: String = ""; + } +} |