summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-12-16 19:25:26 +0000
committerPaul Phillips <paulp@improving.org>2009-12-16 19:25:26 +0000
commit1a7200a1d20afb60bf5e1eb912e7e31c3156a851 (patch)
treeab31356647f8a357cfa998ccecbc6fe88f7a4dc9 /src/compiler
parenteb46c9ab39c5b95724f17908225b2a3728e7b72d (diff)
downloadscala-1a7200a1d20afb60bf5e1eb912e7e31c3156a851.tar.gz
scala-1a7200a1d20afb60bf5e1eb912e7e31c3156a851.tar.bz2
scala-1a7200a1d20afb60bf5e1eb912e7e31c3156a851.zip
REPL completion now understands type aliases de...
REPL completion now understands type aliases defined in package objects. For instance try scala.List.<tab>. review by community.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala11
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala8
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ByteCode.scala36
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Completion.scala44
-rw-r--r--src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala2
5 files changed, 81 insertions, 20 deletions
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index b1065113ad..55e3b354e5 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -145,8 +145,8 @@ class Interpreter(val settings: Settings, out: PrintWriter)
shadow the old ones, and old code objects refer to the old
definitions.
*/
- private var classLoader: ScalaClassLoader = makeClassLoader()
- private def makeClassLoader(): ScalaClassLoader = {
+ private var classLoader: AbstractFileClassLoader = makeClassLoader()
+ private def makeClassLoader(): AbstractFileClassLoader = {
val parent =
if (parentClassLoader == null) ScalaClassLoader fromURLs compilerClasspath
else new URLClassLoader(compilerClasspath, parentClassLoader)
@@ -907,13 +907,14 @@ class Interpreter(val settings: Settings, out: PrintWriter)
/** Another entry point for tab-completion, ids in scope */
def unqualifiedIds(): List[String] =
- allBoundNames .
- map(_.toString) .
- filter(!isSynthVarName(_))
+ allBoundNames map (_.toString) filterNot isSynthVarName
/** For static/object method completion */
def getClassObject(path: String): Option[Class[_]] = classLoader tryToLoadClass path
+ /** Parse the ScalaSig to find type aliases */
+ def aliasForType(path: String) = ByteCode.aliasForType(path)
+
// debugging
private var debuggingOutput = false
def DBG(s: String) = if (debuggingOutput) out println s else ()
diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
index 1c5fa3a5b9..c821b9ed80 100644
--- a/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/AbstractFileClassLoader.scala
@@ -18,7 +18,7 @@ class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader)
extends ClassLoader(parent)
with ScalaClassLoader
{
- override def findClass(name: String): Class[_] = {
+ def getBytesForClass(name: String): Array[Byte] = {
def onull[T](x: T): T = if (x == null) throw new ClassNotFoundException(name) else x
var file: AbstractFile = root
val pathParts = name.split("[./]").toList
@@ -27,7 +27,11 @@ class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader)
file = onull(file.lookupName(dirPart, true))
file = onull(file.lookupName(pathParts.last+".class", false))
- val bytes = file.toByteArray
+ file.toByteArray
+ }
+
+ override def findClass(name: String): Class[_] = {
+ val bytes = getBytesForClass(name)
defineClass(name, bytes, 0, bytes.length)
}
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala b/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala
new file mode 100644
index 0000000000..d66cbb7818
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interpreter/ByteCode.scala
@@ -0,0 +1,36 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package interpreter
+
+import java.io.File
+import java.util.jar.{ JarEntry, JarFile }
+import java.util.concurrent.ConcurrentHashMap
+import util.ScalaClassLoader.getSystemLoader
+
+object ByteCode {
+ /** Until I figure out why I can't get scalap onto the classpath such
+ * that the compiler will bootstrap, we have to use reflection.
+ */
+ private lazy val DECODE: Option[String => Option[Map[String, String]]] =
+ for (clazz <- getSystemLoader.tryToLoadClass[AnyRef]("scala.tools.scalap.Decode$")) yield {
+ val module = clazz.getField("MODULE$").get()
+ val method = clazz.getMethod("typeAliases", classOf[String])
+ val map = method.invoke(module, _: String).asInstanceOf[Option[Map[String, String]]]
+ map
+ }
+
+ def aliasesForPackage(pkg: String) = DECODE flatMap (_(pkg))
+
+ /** Use scalap to look through type aliases */
+ def aliasForType(path: String): Option[String] = {
+ val (pkg, name) = (path lastIndexOf '.') match {
+ case -1 => return None
+ case idx => (path take idx, path drop (idx + 1))
+ }
+ aliasesForPackage(pkg) flatMap (_ get name)
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
index 3303ba3550..2ecafa974a 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
@@ -38,10 +38,7 @@ class Completion(val interpreter: Interpreter) extends Completor {
// it takes a little while to look through the jars so we use a future and a concurrent map
class CompletionAgent {
- val dottedPaths = new ConcurrentHashMap[String, List[String]]
- // TODO - type aliases defined in package objects, like scala.List.<tab>
- // val typeAliases = new ConcurrentHashMap[String, String]
- // val packageObjects = new ConcurrentHashMap[String, List[String]]
+ val dottedPaths = new ConcurrentHashMap[String, List[CompletionInfo]]
val topLevelPackages = new DelayedLazyVal(
() => enumToList(dottedPaths.keys) filterNot (_ contains '.'),
getDottedPaths(dottedPaths, interpreter)
@@ -121,14 +118,12 @@ class Completion(val interpreter: Interpreter) extends Completor {
}
}
- def getOrElse[K, V](map: ConcurrentHashMap[K, V], key: K, value: => V) =
- if (map containsKey key) map get key
- else value
-
def isValidId(s: String) = interpreter.unqualifiedIds contains s
def membersOfId(s: String) = interpreter membersOfIdentifier s
def membersOfPath(s: String) = {
- val xs = getOrElse(dottedPaths, s, Nil)
+ val xs =
+ if (dottedPaths containsKey s) dottedPaths get s map (_.visibleName)
+ else Nil
s match {
case "scala" => xs filterNot scalaToHide
@@ -191,7 +186,11 @@ class Completion(val interpreter: Interpreter) extends Completor {
// java style, static methods
val js = getClassObject(path) map (getMembers(_, true)) getOrElse Nil
// scala style, methods on companion object
- val ss = getClassObject(path + "$") map (getMembers(_, false)) getOrElse Nil
+ // if getClassObject fails, see if there is a type alias
+ val clazz = getClassObject(path + "$") orElse {
+ (ByteCode aliasForType path) flatMap (x => getClassObject(x + "$"))
+ }
+ val ss = clazz map (getMembers(_, false)) getOrElse Nil
js ::: ss
}
@@ -201,6 +200,7 @@ object Completion
{
import java.io.File
import java.util.jar.{ JarEntry, JarFile }
+ import scala.tools.nsc.io.Streamable
val EXPAND_SEPARATOR_STRING = "$$"
val ANON_CLASS_NAME = "$anon"
@@ -208,6 +208,24 @@ object Completion
val IMPL_CLASS_SUFFIX ="$class"
val INTERPRETER_VAR_PREFIX = "res"
+ case class CompletionInfo(visibleName: String, className: String, jar: String) {
+ lazy val jarfile = new JarFile(jar)
+ lazy val entry = jarfile getEntry className
+
+ override def hashCode = visibleName.hashCode
+ override def equals(other: Any) = other match {
+ case x: CompletionInfo => visibleName == x.visibleName
+ case _ => false
+ }
+
+ def getBytes(): Array[Byte] = {
+ if (entry == null) Array() else {
+ val x = new Streamable.Bytes { def inputStream() = jarfile getInputStream entry }
+ x.toByteArray()
+ }
+ }
+ }
+
def enumToList[T](e: java.util.Enumeration[T]): List[T] = enumToList(e, Nil)
def enumToList[T](e: java.util.Enumeration[T], xs: List[T]): List[T] =
if (e == null || !e.hasMoreElements) xs else enumToList(e, e.nextElement :: xs)
@@ -233,7 +251,7 @@ object Completion
// all the dotted path to classfiles we can find by poking through the jars
def getDottedPaths(
- map: ConcurrentHashMap[String, List[String]],
+ map: ConcurrentHashMap[String, List[CompletionInfo]],
interpreter: Interpreter): Unit =
{
val cp =
@@ -264,7 +282,9 @@ object Completion
def oneJar(jar: String): Unit = {
val classfiles = Completion getClassFiles jar
- for (cl <- classfiles.removeDuplicates ; (k, v) <- subpaths(cl)) {
+ for (cl <- classfiles.removeDuplicates ; (k, _v) <- subpaths(cl)) {
+ val v = CompletionInfo(_v, cl, jar)
+
if (map containsKey k) {
val vs = map.get(k)
if (vs contains v) ()
diff --git a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
index 62f11c544c..95396dd95b 100644
--- a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
+++ b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala
@@ -67,7 +67,7 @@ object ScalaClassLoader {
def setContextLoader(cl: JavaClassLoader) = Thread.currentThread.setContextClassLoader(cl)
def getContextLoader() = Thread.currentThread.getContextClassLoader()
- def getSystemLoader() = JavaClassLoader.getSystemClassLoader()
+ def getSystemLoader(): ScalaClassLoader = new JavaClassLoader(JavaClassLoader.getSystemClassLoader()) with ScalaClassLoader
def defaultParentClassLoader() = findExtClassLoader()
def fromURLs(urls: Seq[URL]): URLClassLoader =