summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-04-27 18:39:45 +0000
committerPaul Phillips <paulp@improving.org>2010-04-27 18:39:45 +0000
commit4a785c87272e07f34782a3d05092884472a15b63 (patch)
tree156dfa7238751ecfbc10d6e19a131a26eff4831b
parent99cbff74b765678746d74e421d83480833229db5 (diff)
downloadscala-4a785c87272e07f34782a3d05092884472a15b63.tar.gz
scala-4a785c87272e07f34782a3d05092884472a15b63.tar.bz2
scala-4a785c87272e07f34782a3d05092884472a15b63.zip
Various refinements and polishing to do with me...
Various refinements and polishing to do with method signature completion. No review.
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala6
-rw-r--r--src/compiler/scala/tools/nsc/InterpreterLoop.scala1
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Completion.scala53
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala88
4 files changed, 107 insertions, 41 deletions
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index 547799bd4f..ba81e1885c 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -991,6 +991,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
* in power mode.
*/
class Power {
+ import compiler.{ phaseNames, atPhase, currentRun }
def mkContext(code: String = "") = compiler.analyzer.rootContext(mkUnit(code))
def mkAlias(name: String, what: String) = interpret("type %s = %s".format(name, what))
def mkSourceFile(code: String) = new BatchSourceFile("<console>", code)
@@ -1017,6 +1018,11 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
("Names used: " :: allUsedNames) ++
("\nIdentifiers: " :: unqualifiedIds)
) mkString " "
+
+ lazy val allPhases: List[Phase] = phaseNames map (currentRun phaseNamed _)
+ def atAllPhases[T](op: => T): List[(String, T)] = allPhases map (ph => (ph.name, atPhase(ph)(op)))
+ def showAtAllPhases(op: => Any): Unit =
+ atAllPhases(op.toString) foreach { case (ph, op) => Console.println("%15s -> %s".format(ph, op take 240)) }
}
lazy val power = new Power
diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
index d369ef4fa3..4e8a04de44 100644
--- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala
+++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
@@ -346,6 +346,7 @@ class InterpreterLoop(in0: Option[BufferedReader], protected val out: PrintWrite
powerUserOn = true
interpreter.unleash()
injectOne("history", in.historyList)
+ in.completion foreach (x => injectOne("completion", x))
out println powerUserBanner
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
index 24b5737960..fddb1ee928 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
@@ -8,11 +8,7 @@ package scala.tools.nsc
package interpreter
import jline._
-import java.net.URL
import java.util.{ List => JList }
-import java.lang.reflect
-import scala.tools.util.PathResolver
-import io.{ Path, Directory }
object Completion {
def looksLikeInvocation(code: String) = (
@@ -34,7 +30,7 @@ import Completion._
// REPL completor - queries supplied interpreter for valid
// completions based on current contents of buffer.
-class Completion(val repl: Interpreter) {
+class Completion(val repl: Interpreter) extends CompletionOutput {
// verbosity goes up with consecutive tabs
private var verbosity: Int = 0
def resetVerbosity() = verbosity = 0
@@ -45,7 +41,7 @@ class Completion(val repl: Interpreter) {
lazy val global: repl.compiler.type = repl.compiler
import global._
- import definitions.{ PredefModule, RootClass, AnyClass, AnyRefClass, ScalaPackage, JavaLangPackage, isRepeatedParamType }
+ import definitions.{ PredefModule, RootClass, AnyClass, AnyRefClass, ScalaPackage, JavaLangPackage }
// XXX not yet used.
lazy val dottedPaths = {
@@ -78,40 +74,6 @@ class Completion(val repl: Interpreter) {
private def anyMembers = AnyClass.tpe.nonPrivateMembers
def anyRefMethodsToShow = List("isInstanceOf", "asInstanceOf", "toString")
- /** Only prints the parameter names if they're not synthetic,
- * since "x$1: Int" does not offer any more information than "Int".
- */
- def typeString(tp: Type): String = {
- val str = tp.toString
- val prefixes = List("java.lang.", "scala.collection.")
-
- prefixes.foldLeft(str)(_ stripPrefix _)
- }
-
- def methodSignatureString(name: String, sym: Symbol) = atPhase(currentRun.typerPhase) {
- def assembleParams(params: List[Symbol]): String = {
- if (params.isEmpty)
- return "()"
- if (isRepeatedParamType(params.last.tpe)) // (
- return assembleParams(params.init).init + "*)"
-
- val xs =
- if (params exists (_.isSynthetic)) params map (x => typeString(x.tpe))
- else params map (_.defString)
-
- xs.mkString("(", ", ", ")")
- }
-
- def assemble(paramPart: String, resType: Type): String =
- "def " + name + paramPart + ": " + typeString(resType)
-
- sym.info match {
- case MethodType(params, resType) => assemble(assembleParams(params), resType)
- case PolyType(tparams, resType) => assemble("", resType)
- case x => x.toString
- }
- }
-
def tos(sym: Symbol) = sym.name.decode.toString
def memberNamed(s: String) = members find (x => tos(x) == s)
def hasMethod(s: String) = methods exists (x => tos(x) == s)
@@ -142,6 +104,15 @@ class Completion(val repl: Interpreter) {
def excludeStartsWith: List[String] = List("<") // <byname>, <repeated>, etc.
def excludeNames: List[String] = anyref.methodNames -- anyRefMethodsToShow ++ List("_root_")
+ def methodSignatureString(sym: Symbol) = {
+ def asString = new MethodSymbolOutput(sym).methodString()
+
+ if (isCompletionDebug)
+ repl.power.showAtAllPhases(asString)
+
+ atPhase(currentRun.typerPhase)(asString)
+ }
+
def exclude(name: String): Boolean = (
(name contains "$") ||
(excludeNames contains name) ||
@@ -158,7 +129,7 @@ class Completion(val repl: Interpreter) {
override def alternativesFor(id: String): List[String] =
debugging(id + " alternatives ==> ") {
- val alts = members filter (x => x.isMethod && tos(x) == id) map (sym => methodSignatureString(id, sym))
+ val alts = members filter (x => x.isMethod && tos(x) == id) map methodSignatureString
if (alts.nonEmpty) "" :: alts else Nil
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
new file mode 100644
index 0000000000..9b9d9a36f1
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
@@ -0,0 +1,88 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package interpreter
+
+/** This has a lot of duplication with other methods in Symbols and Types,
+ * but repl completion utility is very sensitive to precise output. Best
+ * thing would be to abstract an interface for how such things are printed,
+ * as is also in progress with error messages.
+ */
+trait CompletionOutput {
+ self: Completion =>
+
+ import global._
+ import definitions.{ NothingClass, AnyClass, isTupleType, isFunctionType, isRepeatedParamType }
+
+ /** Reducing fully qualified noise for some common packages.
+ */
+ val typeTransforms = List(
+ "java.lang." -> "",
+ "scala.collection.immutable." -> "immutable.",
+ "scala.collection.mutable." -> "mutable.",
+ "scala.collection.generic." -> "generic."
+ )
+
+ def quietString(tp: String): String =
+ typeTransforms.foldLeft(tp) {
+ case (str, (prefix, replacement)) =>
+ if (str startsWith prefix) replacement + (str stripPrefix prefix)
+ else str
+ }
+
+ class MethodSymbolOutput(method: Symbol) {
+ val pkg = method.ownerChain find (_.isPackageClass) map (_.fullName) getOrElse ""
+
+ def relativize(str: String): String = quietString(str stripPrefix (pkg + "."))
+ def relativize(tp: Type): String = relativize(tp.normalize.toString)
+ def relativize(sym: Symbol): String = relativize(sym.info)
+
+ def braceList(tparams: List[String]) = if (tparams.isEmpty) "" else (tparams map relativize).mkString("[", ", ", "]")
+ def parenList(params: List[Any]) = params.mkString("(", ", ", ")")
+
+ def methodTypeToString(mt: MethodType) =
+ (mt.paramss map paramsString mkString "") + ": " + relativize(mt.finalResultType)
+
+ def typeToString(tp: Type): String = relativize(
+ tp match {
+ case x if isFunctionType(x) => functionString(x)
+ case x if isTupleType(x) => tupleString(x)
+ case x if isRepeatedParamType(x) => typeToString(x.typeArgs.head) + "*"
+ case mt @ MethodType(_, _) => methodTypeToString(mt)
+ case x => x.toString
+ }
+ )
+
+ def tupleString(tp: Type) = parenList(tp.normalize.typeArgs map relativize)
+ def functionString(tp: Type) = tp.normalize.typeArgs match {
+ case List(t, r) => t + " => " + r
+ case xs => parenList(xs.init) + " => " + xs.last
+ }
+
+ def tparamsString(tparams: List[Symbol]) = braceList(tparams map (_.defString))
+ def paramsString(params: List[Symbol]) = {
+ def paramNameString(sym: Symbol) = if (sym.isSynthetic) "" else sym.nameString + ": "
+ def paramString(sym: Symbol) = paramNameString(sym) + typeToString(sym.info.normalize)
+
+ val isImplicit = params.nonEmpty && params.head.isImplicit
+ val strs = (params map paramString) match {
+ case x :: xs if isImplicit => ("implicit " + x) :: xs
+ case xs => xs
+ }
+ parenList(strs)
+ }
+
+ def methodString() =
+ method.keyString + " " + method.nameString + (method.info.normalize match {
+ case PolyType(Nil, resType) => ": " + typeToString(resType) // nullary method
+ case PolyType(tparams, resType) => tparamsString(tparams) + typeToString(resType)
+ case mt @ MethodType(_, _) => methodTypeToString(mt)
+ case x =>
+ DBG("methodString(): %s / %s".format(x.getClass, x))
+ x.toString
+ })
+ }
+}