summaryrefslogtreecommitdiff
path: root/src/repl/scala/tools/nsc/interpreter/Imports.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-03-10 17:17:58 -0700
committerPaul Phillips <paulp@improving.org>2013-03-11 20:07:24 -0700
commit48cc8b47fcadaa187026ca0422178c9094e4b412 (patch)
tree32f3cce4559030e3088741390024c19eb5110bbe /src/repl/scala/tools/nsc/interpreter/Imports.scala
parent1b6297f642877dcc7edcd704a5d3cf99a12e54b8 (diff)
downloadscala-48cc8b47fcadaa187026ca0422178c9094e4b412.tar.gz
scala-48cc8b47fcadaa187026ca0422178c9094e4b412.tar.bz2
scala-48cc8b47fcadaa187026ca0422178c9094e4b412.zip
Modularized the repl.
Following in the footsteps of scaladoc and interactive. The interpreter sources move into src/repl, and are given a separate build target. As with the others, at present they are still packaged into scala-compiler.jar. A summary of changes: - repl requires use of ReplGlobal (this was already implied) - macro code's repl-specific classloader hack pulled into overridable method and overridden in ReplGlobal - removed -Ygen-javap option to eliminate backend's dependency on javap - removed -Yrepl-debug option (can still be enabled with -Dscala.repl.debug) - pushed javap code into src/repl so javax.tools dependency can bee weakened to the repl only - removed some "show pickled" related code which hasn't worked right in a while and isn't the right way to do it anymore anyway. Will return to fix showPickled and provide it with some tests.
Diffstat (limited to 'src/repl/scala/tools/nsc/interpreter/Imports.scala')
-rw-r--r--src/repl/scala/tools/nsc/interpreter/Imports.scala181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/repl/scala/tools/nsc/interpreter/Imports.scala b/src/repl/scala/tools/nsc/interpreter/Imports.scala
new file mode 100644
index 0000000000..ff7bfd432c
--- /dev/null
+++ b/src/repl/scala/tools/nsc/interpreter/Imports.scala
@@ -0,0 +1,181 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package interpreter
+
+import scala.collection.{ mutable, immutable }
+
+trait Imports {
+ self: IMain =>
+
+ import global._
+ import definitions.{ ObjectClass, ScalaPackage, JavaLangPackage, PredefModule }
+ import memberHandlers._
+
+ /** Synthetic import handlers for the language defined imports. */
+ private def makeWildcardImportHandler(sym: Symbol): ImportHandler = {
+ val hd :: tl = sym.fullName.split('.').toList map newTermName
+ val tree = Import(
+ tl.foldLeft(Ident(hd): Tree)((x, y) => Select(x, y)),
+ ImportSelector.wildList
+ )
+ tree setSymbol sym
+ new ImportHandler(tree)
+ }
+
+ /** Symbols whose contents are language-defined to be imported. */
+ def languageWildcardSyms: List[Symbol] = List(JavaLangPackage, ScalaPackage, PredefModule)
+ def languageWildcardHandlers = languageWildcardSyms map makeWildcardImportHandler
+
+ def allImportedNames = 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 filter (_.importsWildcard) map (_.targetType) distinct
+ }
+
+ def languageSymbols = languageWildcardSyms flatMap membersAtPickler
+ def sessionImportedSymbols = importHandlers flatMap (_.importedSymbols)
+ def importedSymbols = languageSymbols ++ sessionImportedSymbols
+ def importedTermSymbols = importedSymbols collect { case x: TermSymbol => x }
+
+ /** 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 != NoType) map { mh =>
+ (mh.targetType.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 traversed 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] = {
+ // 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 wanted)
+ }
+
+ 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()
+ }
+ def maybeWrap(names: Name*) = if (names exists currentImps) addWrapper()
+ def wrapBeforeAndAfter[T](op: => T): T = {
+ addWrapper()
+ try op finally addWrapper()
+ }
+
+ // loop through previous requests, adding imports for each one
+ wrapBeforeAndAfter {
+ 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 =>
+ wrapBeforeAndAfter(code append (x.member + "\n"))
+ case x: ImportHandler =>
+ maybeWrap(x.importedNames: _*)
+ code append (x.member + "\n")
+ 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 (sym <- x.definedSymbols) {
+ maybeWrap(sym.name)
+ code append s"import ${x.path}\n"
+ currentImps += sym.name
+ }
+ }
+ }
+ }
+
+ ComputedImports(code.toString, trailingBraces.toString, accessPath.toString)
+ }
+
+ private def allReqAndHandlers =
+ prevRequestList flatMap (req => req.handlers map (req -> _))
+
+ private def membersAtPickler(sym: Symbol): List[Symbol] =
+ enteringPickler(sym.info.nonPrivateMembers.toList)
+}