From 6eae720732d493a3a3370a067a3b3b05aef73820 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 8 Apr 2011 16:42:18 +0000 Subject: Factoring the imports related code out of the m... Factoring the imports related code out of the main Interpreter class, no review. --- .../scala/tools/nsc/interpreter/IMain.scala | 184 ++------------------- .../scala/tools/nsc/interpreter/Imports.scala | 178 ++++++++++++++++++++ 2 files changed, 190 insertions(+), 172 deletions(-) create mode 100644 src/compiler/scala/tools/nsc/interpreter/Imports.scala diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 4e405de3b2..f407b42689 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -57,7 +57,7 @@ import IMain._ * @author Moez A. Abdel-Gawad * @author Lex Spoon */ -class IMain(val settings: Settings, protected val out: PrintWriter) { +class IMain(val settings: Settings, protected val out: PrintWriter) extends Imports { imain => /** construct an interpreter that reports to Console */ @@ -163,11 +163,9 @@ class IMain(val settings: Settings, protected val out: PrintWriter) { else null } @deprecated("Use `global` for access to the compiler instance.") - lazy val compiler = global + lazy val compiler: global.type = global import global._ - import definitions.{ ScalaPackage, JavaLangPackage, PredefModule, RootClass } - import nme.{ INTERPRETER_IMPORT_WRAPPER } object naming extends { val global: imain.global.type = imain.global @@ -379,114 +377,6 @@ class IMain(val settings: Settings, protected val out: PrintWriter) { } } - /** Compute imports that allow definitions from previous - * requests to be visible in a new request. Returns - * three pieces of related code: - * - * 1. An initial code fragment that should go before - * the code of the new request. - * - * 2. A code fragment that should go after the code - * of the new request. - * - * 3. An access path which can be traverested to access - * any bindings inside code wrapped by #1 and #2 . - * - * The argument is a set of Names that need to be imported. - * - * Limitations: This method is not as precise as it could be. - * (1) It does not process wildcard imports to see what exactly - * they import. - * (2) If it imports any names from a request, it imports all - * of them, which is not really necessary. - * (3) It imports multiple same-named implicits, but only the - * last one imported is actually usable. - */ - private case class ComputedImports(prepend: String, append: String, access: String) - private def importsCode(wanted: Set[Name]): ComputedImports = { - /** Narrow down the list of requests from which imports - * should be taken. Removes requests which cannot contribute - * useful imports for the specified set of wanted names. - */ - case class ReqAndHandler(req: Request, handler: MemberHandler) { } - - def reqsToUse: List[ReqAndHandler] = { - /** Loop through a list of MemberHandlers and select which ones to keep. - * 'wanted' is the set of names that need to be imported. - */ - def select(reqs: List[ReqAndHandler], wanted: Set[Name]): List[ReqAndHandler] = { - val isWanted = wanted contains _ - // Single symbol imports might be implicits! See bug #1752. Rather than - // try to finesse this, we will mimic all imports for now. - def keepHandler(handler: MemberHandler) = handler match { - case _: ImportHandler => true - case x => x.definesImplicit || (x.definedNames exists isWanted) - } - - reqs match { - case Nil => Nil - case rh :: rest if !keepHandler(rh.handler) => select(rest, wanted) - case rh :: rest => - import rh.handler._ - val newWanted = wanted ++ referencedNames -- definedNames -- importedNames - rh :: select(rest, newWanted) - } - } - - /** Flatten the handlers out and pair each with the original request */ - select(allReqAndHandlers reverseMap { case (r, h) => ReqAndHandler(r, h) }, wanted).reverse - } - - val code, trailingBraces, accessPath = new StringBuilder - val currentImps = mutable.HashSet[Name]() - - // add code for a new object to hold some imports - def addWrapper() { - val impname = INTERPRETER_IMPORT_WRAPPER - code append "object %s {\n".format(impname) - trailingBraces append "}\n" - accessPath append ("." + impname) - - currentImps.clear - } - - addWrapper() - - // loop through previous requests, adding imports for each one - for (ReqAndHandler(req, handler) <- reqsToUse) { - handler match { - // If the user entered an import, then just use it; add an import wrapping - // level if the import might conflict with some other import - case x: ImportHandler => - if (x.importsWildcard || (currentImps exists (x.importedNames contains _))) - addWrapper() - - code append (x.member + "\n") - - // give wildcard imports a import wrapper all to their own - if (x.importsWildcard) addWrapper() - else currentImps ++= x.importedNames - - // For other requests, import each defined name. - // import them explicitly instead of with _, so that - // ambiguity errors will not be generated. Also, quote - // the name of the variable, so that we don't need to - // handle quoting keywords separately. - case x => - for (imv <- x.definedNames) { - if (currentImps contains imv) addWrapper() - - code append ("import %s\n" format (req fullPath imv)) - currentImps += imv - } - } - } - // add one extra wrapper, to prevent warnings in the common case of - // redefining the value bound in the last interpreter request. - addWrapper() - ComputedImports(code.toString, trailingBraces.toString, accessPath.toString) - } - /** Parse a line into a sequence of trees. Returns None if the input is incomplete. */ def parse(line: String): Option[List[Tree]] = { var justNeedsMore = false @@ -660,14 +550,14 @@ class IMain(val settings: Settings, protected val out: PrintWriter) { virtualDirectory.clear() resetClassLoader() resetAllCreators() - prevRequests.clear + prevRequests.clear() } /** This instance is no longer needed, so release any resources * it is using. The reporter's output gets flushed. */ def close() { - reporter.flush + reporter.flush() } /** Here is where we: @@ -989,7 +879,6 @@ class IMain(val settings: Settings, protected val out: PrintWriter) { requestForName(name) flatMap { req => req.handlers find (_.definedNames contains name) } - // def valueOfTerm(id: String): Option[AnyRef] = requestForIdent(id) flatMap (_.getEval) @@ -998,7 +887,7 @@ class IMain(val settings: Settings, protected val out: PrintWriter) { valueOfTerm(id) map (_.getClass) def typeOfTerm(id: String): Option[Type] = newTermName(id) match { - case nme.ROOTPKG => Some(RootClass.tpe) + case nme.ROOTPKG => Some(definitions.RootClass.tpe) case name => requestForName(name) flatMap (_.compilerTypeOf get name) } def symbolOfTerm(id: String): Symbol = @@ -1057,71 +946,22 @@ class IMain(val settings: Settings, protected val out: PrintWriter) { // } // } - private def onlyTerms(xs: List[Name]) = xs collect { case x: TermName => x } - private def onlyTypes(xs: List[Name]) = xs collect { case x: TypeName => x } + protected def onlyTerms(xs: List[Name]) = xs collect { case x: TermName => x } + protected def onlyTypes(xs: List[Name]) = xs collect { case x: TypeName => x } - def importHandlers = allHandlers collect { case x: ImportHandler => x } def definedTerms = onlyTerms(allDefinedNames) filterNot isInternalVarName def definedTypes = onlyTypes(allDefinedNames) def definedSymbols = prevRequests.toSet flatMap ((x: Request) => x.definedSymbols.values) - def importedTerms = onlyTerms(importHandlers flatMap (_.importedNames)) - def importedTypes = onlyTypes(importHandlers flatMap (_.importedNames)) /** the previous requests this interpreter has processed */ - private lazy val prevRequests = mutable.ArrayBuffer[Request]() + private lazy val prevRequests = mutable.ListBuffer[Request]() private lazy val referencedNameMap = mutable.Map[Name, Request]() private lazy val definedNameMap = mutable.Map[Name, Request]() - private def allHandlers = prevRequests.toList flatMap (_.handlers) - private def allReqAndHandlers = prevRequests.toList flatMap (req => req.handlers map (req -> _)) - def allSeenTypes = prevRequests.toList flatMap (_.typeOf.values.toList) distinct + protected def prevRequestList = prevRequests.toList + private def allHandlers = prevRequestList flatMap (_.handlers) + def allSeenTypes = prevRequestList flatMap (_.typeOf.values.toList) distinct def allImplicits = allHandlers filter (_.definesImplicit) flatMap (_.definedNames) - - private def membersAtPickler(sym: Symbol): List[Symbol] = - atPickler(sym.info.nonPrivateMembers) - - /** Symbols whose contents are language-defined to be imported. */ - def languageWildcardSyms: List[Symbol] = List(JavaLangPackage, ScalaPackage, PredefModule) - def languageWildcards: List[Type] = languageWildcardSyms map (_.tpe) - - /** Types which have been wildcard imported, such as: - * val x = "abc" ; import x._ // type java.lang.String - * import java.lang.String._ // object java.lang.String - * - * Used by tab completion. - * - * XXX right now this gets import x._ and import java.lang.String._, - * but doesn't figure out import String._. There's a lot of ad hoc - * scope twiddling which should be swept away in favor of digging - * into the compiler scopes. - */ - def sessionWildcards: List[Type] = { - importHandlers flatMap { - case x if x.importsWildcard => x.targetType - case _ => None - } distinct - } - def wildcardTypes = languageWildcards ++ sessionWildcards - - def languageSymbols = languageWildcardSyms flatMap membersAtPickler - def sessionImportedSymbols = importHandlers flatMap (_.importedSymbols) - def importedSymbols = languageSymbols ++ sessionImportedSymbols - def implicitSymbols = importedSymbols filter (_.isImplicit) - - /** Tuples of (source, imported symbols) in the order they were imported. - */ - def importedSymbolsBySource: List[(Symbol, List[Symbol])] = { - val lang = languageWildcardSyms map (sym => (sym, membersAtPickler(sym))) - val session = importHandlers filter (_.targetType.isDefined) map { mh => - (mh.targetType.get.typeSymbol, mh.importedSymbols) - } - - lang ++ session - } - def implicitSymbolsBySource: List[(Symbol, List[Symbol])] = { - importedSymbolsBySource map { - case (k, vs) => (k, vs filter (_.isImplicit)) - } filterNot (_._2.isEmpty) - } + def importHandlers = allHandlers collect { case x: ImportHandler => x } def visibleTermNames: List[Name] = definedTerms ++ importedTerms distinct diff --git a/src/compiler/scala/tools/nsc/interpreter/Imports.scala b/src/compiler/scala/tools/nsc/interpreter/Imports.scala new file mode 100644 index 0000000000..990f504692 --- /dev/null +++ b/src/compiler/scala/tools/nsc/interpreter/Imports.scala @@ -0,0 +1,178 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.nsc +package interpreter + +import scala.collection.{ mutable, immutable } + +trait Imports { + self: IMain => + + import global._ + import definitions.{ ScalaPackage, JavaLangPackage, PredefModule } + import memberHandlers._ + + /** Symbols whose contents are language-defined to be imported. */ + def languageWildcardSyms: List[Symbol] = List(JavaLangPackage, ScalaPackage, PredefModule) + def languageWildcards: List[Type] = languageWildcardSyms map (_.tpe) + + def importedTerms = onlyTerms(importHandlers flatMap (_.importedNames)) + def importedTypes = onlyTypes(importHandlers flatMap (_.importedNames)) + + /** Types which have been wildcard imported, such as: + * val x = "abc" ; import x._ // type java.lang.String + * import java.lang.String._ // object java.lang.String + * + * Used by tab completion. + * + * XXX right now this gets import x._ and import java.lang.String._, + * but doesn't figure out import String._. There's a lot of ad hoc + * scope twiddling which should be swept away in favor of digging + * into the compiler scopes. + */ + def sessionWildcards: List[Type] = { + importHandlers flatMap { + case x if x.importsWildcard => x.targetType + case _ => None + } distinct + } + def wildcardTypes = languageWildcards ++ sessionWildcards + + def languageSymbols = languageWildcardSyms flatMap membersAtPickler + def sessionImportedSymbols = importHandlers flatMap (_.importedSymbols) + def importedSymbols = languageSymbols ++ sessionImportedSymbols + def implicitSymbols = importedSymbols filter (_.isImplicit) + + /** Tuples of (source, imported symbols) in the order they were imported. + */ + def importedSymbolsBySource: List[(Symbol, List[Symbol])] = { + val lang = languageWildcardSyms map (sym => (sym, membersAtPickler(sym))) + val session = importHandlers filter (_.targetType.isDefined) map { mh => + (mh.targetType.get.typeSymbol, mh.importedSymbols) + } + + lang ++ session + } + def implicitSymbolsBySource: List[(Symbol, List[Symbol])] = { + importedSymbolsBySource map { + case (k, vs) => (k, vs filter (_.isImplicit)) + } filterNot (_._2.isEmpty) + } + + /** Compute imports that allow definitions from previous + * requests to be visible in a new request. Returns + * three pieces of related code: + * + * 1. An initial code fragment that should go before + * the code of the new request. + * + * 2. A code fragment that should go after the code + * of the new request. + * + * 3. An access path which can be traverested to access + * any bindings inside code wrapped by #1 and #2 . + * + * The argument is a set of Names that need to be imported. + * + * Limitations: This method is not as precise as it could be. + * (1) It does not process wildcard imports to see what exactly + * they import. + * (2) If it imports any names from a request, it imports all + * of them, which is not really necessary. + * (3) It imports multiple same-named implicits, but only the + * last one imported is actually usable. + */ + case class ComputedImports(prepend: String, append: String, access: String) + protected def importsCode(wanted: Set[Name]): ComputedImports = { + /** Narrow down the list of requests from which imports + * should be taken. Removes requests which cannot contribute + * useful imports for the specified set of wanted names. + */ + case class ReqAndHandler(req: Request, handler: MemberHandler) { } + + def reqsToUse: List[ReqAndHandler] = { + /** Loop through a list of MemberHandlers and select which ones to keep. + * 'wanted' is the set of names that need to be imported. + */ + def select(reqs: List[ReqAndHandler], wanted: Set[Name]): List[ReqAndHandler] = { + val isWanted = wanted contains _ + // Single symbol imports might be implicits! See bug #1752. Rather than + // try to finesse this, we will mimic all imports for now. + def keepHandler(handler: MemberHandler) = handler match { + case _: ImportHandler => true + case x => x.definesImplicit || (x.definedNames exists isWanted) + } + + reqs match { + case Nil => Nil + case rh :: rest if !keepHandler(rh.handler) => select(rest, wanted) + case rh :: rest => + import rh.handler._ + val newWanted = wanted ++ referencedNames -- definedNames -- importedNames + rh :: select(rest, newWanted) + } + } + + /** Flatten the handlers out and pair each with the original request */ + select(allReqAndHandlers reverseMap { case (r, h) => ReqAndHandler(r, h) }, wanted).reverse + } + + val code, trailingBraces, accessPath = new StringBuilder + val currentImps = mutable.HashSet[Name]() + + // add code for a new object to hold some imports + def addWrapper() { + val impname = nme.INTERPRETER_IMPORT_WRAPPER + code append "object %s {\n".format(impname) + trailingBraces append "}\n" + accessPath append ("." + impname) + + currentImps.clear + } + + addWrapper() + + // loop through previous requests, adding imports for each one + for (ReqAndHandler(req, handler) <- reqsToUse) { + handler match { + // If the user entered an import, then just use it; add an import wrapping + // level if the import might conflict with some other import + case x: ImportHandler => + if (x.importsWildcard || (currentImps exists (x.importedNames contains _))) + addWrapper() + + code append (x.member + "\n") + + // give wildcard imports a import wrapper all to their own + if (x.importsWildcard) addWrapper() + else currentImps ++= x.importedNames + + // For other requests, import each defined name. + // import them explicitly instead of with _, so that + // ambiguity errors will not be generated. Also, quote + // the name of the variable, so that we don't need to + // handle quoting keywords separately. + case x => + for (imv <- x.definedNames) { + if (currentImps contains imv) addWrapper() + + code append ("import %s\n" format (req fullPath imv)) + currentImps += imv + } + } + } + // add one extra wrapper, to prevent warnings in the common case of + // redefining the value bound in the last interpreter request. + addWrapper() + ComputedImports(code.toString, trailingBraces.toString, accessPath.toString) + } + + private def allReqAndHandlers = + prevRequestList flatMap (req => req.handlers map (req -> _)) + + private def membersAtPickler(sym: Symbol): List[Symbol] = + atPickler(sym.info.nonPrivateMembers) +} \ No newline at end of file -- cgit v1.2.3