diff options
author | Paul Phillips <paulp@improving.org> | 2010-04-27 18:39:45 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2010-04-27 18:39:45 +0000 |
commit | 4a785c87272e07f34782a3d05092884472a15b63 (patch) | |
tree | 156dfa7238751ecfbc10d6e19a131a26eff4831b | |
parent | 99cbff74b765678746d74e421d83480833229db5 (diff) | |
download | scala-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.
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 + }) + } +} |