symbolloaders.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 329 行

SCALA
329
字号
/* NSC -- new Scala compiler * Copyright 2005-2008 LAMP/EPFL * @author  Martin Odersky */// $Id: SymbolLoaders.scala 13813 2008-01-27 13:11:26Z mcdirmid $package scala.tools.nsc.symtabimport java.io.{File, IOException}  import ch.epfl.lamp.compiler.msil.{Type => MSILType, Attribute => MSILAttribute}import scala.collection.mutable.{HashMap, HashSet}import scala.compat.Platform.currentTimeimport scala.tools.nsc.io.AbstractFileimport scala.tools.nsc.util.{Position, NoPosition}import classfile.ClassfileParserimport Flags._/** This class ... * *  @author  Martin Odersky *  @version 1.0 */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    def sourceFile: AbstractFile = null    protected def sourceString: String    override def complete(root: Symbol) : Unit = {      if (inIDE && root.owner != NoSymbol) {        assert(root.rawInfo == this)        if (root.isModuleClass) {          val clazz = root.sourceModule.linkedClassOfModule          assert(root.rawInfo == this)          if (clazz != NoSymbol && !clazz.rawInfo.isInstanceOf[SymbolLoader]) {            // bail            assert(true)            root.setInfo(ErrorType)            Console.println("ditch " + root)            return          }        } else if (root.isClass) {          val module = root.linkedModuleOfClass          assert(root.rawInfo == this)          if (module != NoSymbol && !module.rawInfo.isInstanceOf[SymbolLoader]) {            assert(true)            root.setInfo(ErrorType)            Console.println("ditch " + root)            return          }        } else {          assert(root.isModule)          assert(true)        }      }      try {        val start = currentTime        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 eq 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) { complete(root) }    private def initRoot(root: Symbol) {      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 {    protected def sourceString = directory.toString()    protected def kindString: String = "directory path"    protected def newPackageLoader(dir: global.classPath0.Context): PackageLoader =      new PackageLoader(dir)    protected def checkSource(name: String, source: AbstractFile): Boolean = true    protected var root: Symbol = _    def enterPackage(name: String, completer: SymbolLoader) {      if (inIDE && root.info.decls.lookup(newTermName(name)) != NoSymbol) {        return // refresh      }      val pkg = root.newPackage(NoPosition, newTermName(name))      pkg.moduleClass.setInfo(completer)      pkg.setInfo(pkg.moduleClass.tpe)      root.info.decls.enter(pkg)    }    // @return - the symbol of the class    def enterClassAndModule(name: String, completer: SymbolLoader): Symbol = {      val owner = if (root.isRoot) definitions.EmptyPackageClass else root      val className = newTermName(name)      assert(owner.info.decls.lookup(name) == NoSymbol, owner.fullNameString + "." + name)      var clazz = owner.newClass(NoPosition, name.toTypeName)      var module = owner.newModule(NoPosition, name)      clazz setInfo completer      module setInfo completer      module.moduleClass setInfo moduleClassLoader      clazz = (owner.info.decls enter clazz).asInstanceOf[ClassSymbol]      module = (owner.info.decls enter module).asInstanceOf[ModuleSymbol]      assert(clazz.linkedModuleOfClass == module, module)      assert(module.linkedClassOfModule == clazz, clazz)      clazz    }    def checkAdd(name0 : String) = {      var name = name0      while ((name indexOf '$') != -1) {        name = name.substring(0, name indexOf '$')      }    }    protected def doComplete(root: Symbol) {      assert(root.isPackageClass, root)      this.root = root      val scope = newScope      root.setInfo(new PackageClassInfoType(scope, root, this))      refresh    }    def refresh = {      /** Is the given name a valid input file base name? */      def isValid(name: String): Boolean =        name.length() > 0 && !name.endsWith("$class") && (/*settings.XO.value*/true ||          (name.indexOf("$anon") == -1));      val classes  = new HashMap[String, global.classPath0.Context]      val packages = new HashMap[String, global.classPath0.Context]      for (dir <- directory.entries) if (dir.location ne null) {        for (file <- dir.location) {          if (file.isDirectory && directory.validPackage(file.name) && !packages.isDefinedAt(file.name))            packages(file.name) = directory.find(file.name, true);          else if (!global.forMSIL && !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 ne null) classes(name) = clazz            }          }        }      }      for (dir <- directory.entries) if (dir.source ne null) {        for (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 ne null) && (source.sourceFile ne null))                if (checkSource(name, source.sourceFile))                  classes(name) = source                else if (settings.debug.value)                  Console.println("Skipping source file " + source.sourceFile)            }          }        }      }      // do classes first      for ((name, file) <- classes.elements) {        val loader = if (!file.isSourceFile) {          new ClassfileLoader(file.classFile, file.sourceFile, file.sourcePath)        } else {          assert(file.sourceFile ne null)          new SourcefileLoader(file.sourceFile)        }        enterClassAndModule(name, loader)      }      for ((name, file) <- packages.elements)        enterPackage(name, newPackageLoader(file))    }  }  class NamespaceLoader(directory: global.classPath0.Context) extends PackageLoader(directory) {    override protected def kindString: String = "namespace " + namespace    override protected def sourceString = ""    override def newPackageLoader(dir: global.classPath0.Context): PackageLoader =      new NamespaceLoader(dir)    val types = new HashMap[String, MSILType]()    val namespaces = new HashSet[String]()    def namespace: String = if (root.isRoot) "" else root.fullNameString    // TODO: Add check whether the source is newer than the assembly    override protected def checkSource(name: String, source: AbstractFile): Boolean =      !types.contains(name)    override protected def doComplete(root: Symbol) {      clrTypes.collectMembers(root, types, namespaces)      super.doComplete(root)      for (namespace <- namespaces.elements) {        val oldPkg = root.info.decls lookup newTermName(namespace)        if (oldPkg == NoSymbol)          enterPackage(namespace, new NamespaceLoader(new classPath0.Context(List())))        //else System.out.println("PackageLoader: package already in scope: " + oldPkg.fullNameString)      }      // import the CLR types contained in the package (namespace)      for ((name, typ) <- types.elements) {        assert(namespace == typ.Namespace, typ.FullName)        if (typ.IsDefined(clrTypes.SCALA_SYMTAB_ATTR, false)) {          val attrs = typ.GetCustomAttributes(clrTypes.SCALA_SYMTAB_ATTR, false)          assert (attrs.length == 1, attrs.length)          val a = attrs(0).asInstanceOf[MSILAttribute]          if (a.getConstructor() == clrTypes.SYMTAB_CONSTR)            enterClassAndModule(name, new MSILTypeLoader(typ))        }         else          enterClassAndModule(name, new MSILTypeLoader(typ))      }    }  }  // NamespaceLoader  class MSILTypeLoader(typ: MSILType) extends SymbolLoader {    private object typeParser extends clr.TypeParser {      val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global    }     protected def doComplete(root: Symbol) {      typeParser.parse(typ, root.asInstanceOf[typeParser.global.loaders.clrTypes.global.Symbol]) // don't check this      }     protected def kindString: String = typ.FullName    protected def sourceString = typ.Assembly.FullName  }  // IDE hook.  protected def completeClassfile(root : Symbol, loader : ClassfileLoader)(f : => Unit) : Unit = f  class ClassfileLoader(val classFile: AbstractFile, override val sourceFile: AbstractFile, sourcePath0: AbstractFile) extends SymbolLoader {    if (sourcePath0 == null) {      assert(true)      assert(true)    }        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) {      completeClassfile(root, this) {        classfileParser.parse(classFile, root)      }      root match {        case clazz: ClassSymbol =>           if ((sourceFile ne null) && (clazz.sourceFile eq null))             clazz.sourceFile = sourceFile        case module: ModuleSymbol if module.moduleClass.isInstanceOf[ClassSymbol] =>          val clazz = module.moduleClass.asInstanceOf[ClassSymbol]          if ((sourceFile ne null) && (clazz.sourceFile eq null))             clazz.sourceFile = sourceFile        case _ =>         }      if (root.sourceFile ne null)         prepareReset(root, this)    }    protected def kindString: String = "class file"    protected def sourceString = classFile.toString()  }  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) { root.sourceModule.initialize }    protected def kindString: String = ""    protected def sourceString = ""  }  object clrTypes extends clr.CLRTypes {    val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global    if (global.forMSIL) init()  }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?