summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-01-29 19:27:13 +0000
committerPaul Phillips <paulp@improving.org>2011-01-29 19:27:13 +0000
commitf89016a8736f7b09ea1dd74baa6c45bb39e47444 (patch)
tree332c043a83574c6c2e1e9788439dacadceafb6f9 /src/compiler
parent80488e4218a0a72dec3ba727e6de276da87f1398 (diff)
downloadscala-f89016a8736f7b09ea1dd74baa6c45bb39e47444.tar.gz
scala-f89016a8736f7b09ea1dd74baa6c45bb39e47444.tar.bz2
scala-f89016a8736f7b09ea1dd74baa6c45bb39e47444.zip
Bringing lots more encapsulation to the repl.
interfaces from implementations and isolating jline better so it doesn't become an accidental dependency or have other unexpected effects. No review.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Completion.scala31
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/History.scala15
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoop.scala40
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala1
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala33
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala58
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/JLineHistory.scala56
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/JLineReader.scala77
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala20
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala57
10 files changed, 222 insertions, 166 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
index 3436c6631e..79f0317533 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
@@ -7,30 +7,37 @@ package scala.tools.nsc
package interpreter
import java.util.{ List => JList }
+import Completion._
/** An implementation-agnostic completion interface which makes no
* reference to the jline classes.
*/
trait Completion {
type ExecResult
- trait Instance {
- def complete(buffer: String, cursor: Int, candidates: JList[CharSequence]): Int
- }
def resetVerbosity(): Unit
def execute(line: String): Option[ExecResult]
- def completer(): Instance
+ def completer(): ScalaCompleter
+}
+object NoCompletion extends Completion {
+ type ExecResult = Nothing
+ def resetVerbosity() = ()
+ def execute(line: String) = None
+ def completer() = NullCompleter
}
object Completion {
- object Empty extends Completion {
- type ExecResult = Nothing
- object NullCompleter extends Instance {
- def complete(buffer: String, cursor: Int, candidates: JList[CharSequence]) = -1
- }
- def resetVerbosity() = ()
- def execute(line: String) = None
- def completer() = NullCompleter
+ def empty: Completion = NoCompletion
+
+ case class Candidates(cursor: Int, candidates: List[String]) { }
+ val NoCandidates = Candidates(-1, Nil)
+
+ object NullCompleter extends ScalaCompleter {
+ def complete(buffer: String, cursor: Int): Candidates = NoCandidates
+ }
+ trait ScalaCompleter {
+ def complete(buffer: String, cursor: Int): Candidates
}
+
def looksLikeInvocation(code: String) = (
(code != null)
&& (code startsWith ".")
diff --git a/src/compiler/scala/tools/nsc/interpreter/History.scala b/src/compiler/scala/tools/nsc/interpreter/History.scala
index e0364b5c6e..246cea12dd 100644
--- a/src/compiler/scala/tools/nsc/interpreter/History.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/History.scala
@@ -16,13 +16,14 @@ trait History {
def grep(s: String): List[String]
def flush(): Unit
}
+object NoHistory extends History {
+ def asStrings = Nil
+ def grep(s: String) = Nil
+ def index = 0
+ def size = 0
+ def flush() = ()
+}
object History {
- object Empty extends History {
- def asStrings = Nil
- def grep(s: String) = Nil
- def index = 0
- def size = 0
- def flush() = ()
- }
+ def empty: History = NoHistory
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
index 413f08dfb1..5c57e70927 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
@@ -154,7 +154,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter)
/** Show the history */
def printHistory(xs: List[String]): Result = {
- if (in.history eq History.Empty)
+ if (in.history eq NoHistory)
return "No history available."
val defaultLines = 20
@@ -273,7 +273,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter)
val oldReplay = replayCommandStack
try file applyReader { reader =>
- in = new SimpleReader(reader, out, false)
+ in = SimpleReader(reader, out, false)
plushln("Loading " + file + "...")
loop()
}
@@ -530,29 +530,39 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter)
case _ =>
}
+ /** Tries to create a JLineReader, falling back to SimpleReader:
+ * unless settings or properties are such that it should start
+ * with SimpleReader.
+ */
+ def chooseReader(settings: Settings): InteractiveReader = {
+ if (settings.Xnojline.value || Properties.isEmacsShell)
+ SimpleReader()
+ else try JLineReader(
+ if (settings.noCompletion.value) NoCompletion
+ else new JLineCompletion(intp)
+ )
+ catch {
+ case _: Exception | _: NoClassDefFoundError => SimpleReader()
+ }
+ }
+
def process(settings: Settings): Boolean = {
this.settings = settings
createInterpreter()
// sets in to some kind of reader depending on environmental cues
in = in0 match {
- case Some(in0) => new SimpleReader(in0, out, true)
- case None =>
- // the interpreter is passed as an argument to expose tab completion info
- if (settings.Xnojline.value || Properties.isEmacsShell) new SimpleReader
- else JLineReader(
- if (settings.noCompletion.value) Completion.Empty
- else new JLineCompletion(intp)
- )
+ case Some(reader) => SimpleReader(reader, out, true)
+ case None => chooseReader(settings)
}
loadFiles(settings)
- try {
- // it is broken on startup; go ahead and exit
- if (intp.reporter.hasErrors) return false
-
- printWelcome()
+ // it is broken on startup; go ahead and exit
+ if (intp.reporter.hasErrors)
+ return false
+ printWelcome()
+ try {
// this is about the illusion of snappiness. We call initialize()
// which spins off a separate thread, then print the prompt and try
// our best to look ready. Ideally the user will spend a
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index 84189cddad..794e6c158a 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -91,7 +91,6 @@ class IMain(val settings: Settings, out: PrintWriter) {
out.flush()
}
-
/** directory to save .class files to */
val virtualDirectory = new VirtualDirectory("(memory)", None)
diff --git a/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala b/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala
index e7ef50ddf7..1a67cc647d 100644
--- a/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala
@@ -10,38 +10,35 @@ import java.io.IOException
import java.nio.channels.ClosedByInterruptException
import scala.util.control.Exception._
import InteractiveReader._
+import Properties.isMac
/** Reads lines from an input stream */
trait InteractiveReader {
val interactive: Boolean
- protected def readOneLine(prompt: String): String
def history: History
def completion: Completion
+
def init(): Unit
def reset(): Unit
- def redrawLine(): Unit = ()
- def currentLine = "" // the current buffer contents, if available
-
- def readLine(prompt: String): String = {
- def handler: Catcher[String] = {
- case e: ClosedByInterruptException => sys.error("Reader closed by interrupt.")
- // Terminal has to be re-initialized after SIGSTP or up arrow etc. stop working.
- case e: IOException if restartSystemCall(e) => reset() ; readLine(prompt)
- }
- catching(handler) { readOneLine(prompt) }
- }
+ protected def readOneLine(prompt: String): String
+ def redrawLine(): Unit
+ def currentLine: String
- // hack necessary for OSX jvm suspension because read calls are not restarted after SIGTSTP
- private def restartSystemCall(e: Exception): Boolean =
- Properties.isMac && (e.getMessage == msgEINTR)
+ def readLine(prompt: String): String =
+ // hack necessary for OSX jvm suspension because read calls are not restarted after SIGTSTP
+ if (isMac) restartSysCalls(readOneLine(prompt), reset())
+ else readOneLine(prompt)
}
object InteractiveReader {
val msgEINTR = "Interrupted system call"
- def apply(): InteractiveReader = new SimpleReader
+ def restartSysCalls[R](body: => R, reset: => Unit): R =
+ try body catch {
+ case e: IOException if e.getMessage == msgEINTR => reset ; body
+ }
- // @deprecated("Use `apply` instead") def createDefault(intp: IMain): InteractiveReader = apply(intp)
- // @deprecated("Use `apply` instead") def createDefault(comp: Completion): InteractiveReader = apply(comp)
+ def apply(): InteractiveReader = SimpleReader()
}
+
diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala
index 3f2003a2f7..148b80df12 100644
--- a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala
@@ -264,7 +264,7 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
def completions(buf: String): List[String] =
topLevelFor(Parsed.dotted(buf + ".", buf.length + 1))
- def completer() = new JLineCompleterClass
+ def completer(): ScalaCompleter = new JLineTabCompletion
/** This gets a little bit hairy. It's no small feat delegating everything
* and also keeping track of exactly where the cursor is and where it's supposed
@@ -272,7 +272,7 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
* string in the list of completions, that means we are expanding a unique
* completion, so don't update the "last" buffer because it'll be wrong.
*/
- class JLineCompleterClass extends Instance with Completer {
+ class JLineTabCompletion extends ScalaCompleter {
// For recording the buffer on the last tab hit
private var lastBuf: String = ""
private var lastCursor: Int = -1
@@ -281,35 +281,43 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
def isConsecutiveTabs(buf: String, cursor: Int) =
cursor == lastCursor && buf == lastBuf
+ def sameHead(xs: List[String]) = {
+ if (xs.isEmpty || xs.head.length == 0) false
+ else {
+ val y :: ys = xs
+ val ch = y.head
+ ys forall (s => s.length > 0 && s.head == ch)
+ }
+ }
// Longest common prefix
- def commonPrefix(xs: List[String]) =
- if (xs.isEmpty) ""
- else xs.reduceLeft(_ zip _ takeWhile (x => x._1 == x._2) map (_._1) mkString)
+ def commonPrefix(xs: List[String]): String = {
+ if (sameHead(xs)) xs.head + commonPrefix(xs map (_.tail))
+ else ""
+ }
// This is jline's entry point for completion.
- override def complete(_buf: String, cursor: Int, candidates: JList[CharSequence]): Int = {
- val buf = if (_buf == null) "" else _buf
+ override def complete(buf: String, cursor: Int): Candidates = {
verbosity = if (isConsecutiveTabs(buf, cursor)) verbosity + 1 else 0
DBG("\ncomplete(%s, %d) last = (%s, %d), verbosity: %s".format(buf, cursor, lastBuf, lastCursor, verbosity))
// we don't try lower priority completions unless higher ones return no results.
- def tryCompletion(p: Parsed, completionFunction: Parsed => List[String]): Option[Int] = {
+ def tryCompletion(p: Parsed, completionFunction: Parsed => List[String]): Option[Candidates] = {
completionFunction(p) match {
case Nil => None
case xs =>
- // modify in place and return the position
- xs foreach (candidates add _)
-
- // update the last buffer unless this is an alternatives list
- if (xs contains "") Some(p.cursor)
- else {
- val advance = commonPrefix(xs)
- lastCursor = p.position + advance.length
- lastBuf = (buf take p.position) + advance
-
- DBG("tryCompletion(%s, _) lastBuf = %s, lastCursor = %s, p.position = %s".format(p, lastBuf, lastCursor, p.position))
- Some(p.position)
- }
+ Some(Candidates(
+ if (xs contains "") p.cursor
+ else {
+ // update the last buffer unless this is an alternatives list
+ val advance = commonPrefix(xs)
+ lastCursor = p.position + advance.length
+ lastBuf = (buf take p.position) + advance
+ DBG("tryCompletion(%s, _) lastBuf = %s, lastCursor = %s, p.position = %s".format(
+ p, lastBuf, lastCursor, p.position))
+ p.position
+ },
+ xs)
+ )
}
}
@@ -332,14 +340,12 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
* compiler still throws some Errors it may not be.
*/
try {
- (lastResultCompletion orElse regularCompletion orElse fileCompletion) getOrElse cursor
+ (lastResultCompletion orElse regularCompletion orElse fileCompletion) getOrElse Candidates(cursor, Nil)
}
catch {
case ex: Exception =>
- DBG("Error: complete(%s, %s, _) provoked %s".format(_buf, cursor, ex))
- candidates add " "
- candidates add "<completion error>"
- cursor
+ DBG("Error: complete(%s, %s) provoked %s".format(buf, cursor, ex))
+ Candidates(cursor, List(" ", "<completion error>"))
}
}
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineHistory.scala b/src/compiler/scala/tools/nsc/interpreter/JLineHistory.scala
new file mode 100644
index 0000000000..e9be7141f1
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interpreter/JLineHistory.scala
@@ -0,0 +1,56 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package interpreter
+
+import java.io.File
+import java.util.{ List => JList }
+import scala.tools.jline.console.ConsoleReader
+import scala.tools.jline.console.completer._
+import scala.tools.jline.console.history._
+import scala.tools.jline.console.history.{ FileHistory, PersistentHistory, History => JHistory }
+import scala.tools.jline.console.history.History.{ Entry => JEntry }
+import scala.tools.jline.console.ConsoleReader
+import scala.collection.JavaConverters._
+import Properties.userHome
+
+/** A wrapper for JLine's History.
+ */
+class JLineHistory(val jhistory: JHistory) extends History {
+ def asJavaList = jhistory.entries()
+ def asStrings = asList map (_.value.toString)
+ def asList: List[JEntry] = asJavaList.asScala.toList
+ def index = jhistory.index()
+ def size = jhistory.size()
+
+ def grep(s: String) = asStrings filter (_ contains s)
+ def flush() = jhistory match {
+ case x: PersistentHistory => x.flush()
+ case _ => ()
+ }
+}
+
+object JLineHistory {
+ val ScalaHistoryFile = ".scala_history"
+
+ def apply() = new JLineHistory(
+ try newFile()
+ catch { case x : Exception =>
+ Console.println("Error creating file history: memory history only. " + x)
+ newMemory()
+ }
+ )
+
+ def newMemory() = new MemoryHistory()
+ def newFile() = new FileHistory(new File(userHome, ScalaHistoryFile)) {
+ // flush after every add to avoid installing a shutdown hook.
+ // (The shutdown hook approach also loses history when they aren't run.)
+ override def add(item: CharSequence): Unit = {
+ super.add(item)
+ flush()
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala
index d09567eadf..7652e6646b 100644
--- a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala
@@ -16,65 +16,27 @@ import scala.tools.jline.console.history.History.{ Entry => JEntry }
import scala.tools.jline.console.ConsoleReader
import scala.collection.JavaConverters._
import Properties.userHome
-
-/** A wrapper for JLine's History.
- */
-class JLineHistory(val jhistory: JHistory) extends History {
- def asJavaList = jhistory.entries()
- def asStrings = asList map (_.value.toString)
- def asList: List[JEntry] = asJavaList.asScala.toList
- def index = jhistory.index()
- def size = jhistory.size()
-
- def grep(s: String) = asStrings filter (_ contains s)
- def flush() = jhistory match {
- case x: PersistentHistory => x.flush()
- case _ => ()
- }
-}
-
-object JLineHistory {
- val ScalaHistoryFile = ".scala_history"
-
- def apply() = new JLineHistory(
- try newFile()
- catch { case x : Exception =>
- Console.println("Error creating file history: memory history only. " + x)
- newMemory()
- }
- )
-
- def newMemory() = new MemoryHistory()
- def newFile() = new FileHistory(new File(userHome, ScalaHistoryFile)) {
- // flush after every add to avoid installing a shutdown hook.
- // (The shutdown hook approach also loses history when they aren't run.)
- override def add(item: CharSequence): Unit = {
- super.add(item)
- flush()
- }
- }
-}
+import Completion._
/** Reads from the console using JLine */
class JLineReader(val completion: Completion) extends InteractiveReader {
+ val interactive = true
lazy val history = JLineHistory()
def reset() = consoleReader.getTerminal().reset()
def init() = consoleReader.getTerminal().init()
- override def redrawLine() = {
- consoleReader.flush()
- consoleReader.drawLine()
- consoleReader.flush()
+ def scalaToJline(tc: ScalaCompleter): Completer = new Completer {
+ def complete(_buf: String, cursor: Int, candidates: JList[CharSequence]): Int = {
+ val buf = if (_buf == null) "" else _buf
+ val Candidates(newCursor, newCandidates) = tc.complete(buf, cursor)
+ newCandidates foreach (candidates add _)
+ newCursor
+ }
}
def argCompletor: ArgumentCompleter = {
- val wrapped = new Completer {
- val cc = completion.completer()
- def complete(buffer: String, cursor: Int, candidates: JList[CharSequence]): Int =
- cc.complete(buffer, cursor, candidates)
- }
- val c = new ArgumentCompleter(new JLineDelimiter, wrapped)
+ val c = new ArgumentCompleter(new JLineDelimiter, scalaToJline(completion.completer()))
c setStrict false
c
}
@@ -82,10 +44,10 @@ class JLineReader(val completion: Completion) extends InteractiveReader {
val consoleReader = {
val r = new ConsoleReader()
r setBellEnabled false
- if (history ne History.Empty)
+ if (history ne NoHistory)
r setHistory history.jhistory
- if (completion ne Completion.Empty) {
+ if (completion ne NoCompletion) {
r addCompleter argCompletor
r setAutoprintThreshold 400 // max completion candidates without warning
}
@@ -93,15 +55,16 @@ class JLineReader(val completion: Completion) extends InteractiveReader {
r
}
- override def currentLine: String = consoleReader.getCursorBuffer.buffer.toString
+ def currentLine: String = consoleReader.getCursorBuffer.buffer.toString
+ def redrawLine() = {
+ consoleReader.flush()
+ consoleReader.drawLine()
+ consoleReader.flush()
+ }
def readOneLine(prompt: String) = consoleReader readLine prompt
- val interactive = true
}
object JLineReader {
- def apply(intp: IMain): InteractiveReader = apply(new JLineCompletion(intp))
- def apply(comp: Completion): InteractiveReader = {
- try new JLineReader(comp)
- catch { case e @ (_: Exception | _: NoClassDefFoundError) => new SimpleReader }
- }
+ def apply(intp: IMain): JLineReader = apply(new JLineCompletion(intp))
+ def apply(comp: Completion): JLineReader = new JLineReader(comp)
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala b/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala
index e4c0bf8307..079fa4b9fb 100644
--- a/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala
@@ -13,15 +13,15 @@ class SimpleReader(
in: BufferedReader,
out: PrintWriter,
val interactive: Boolean)
-extends InteractiveReader {
- def this() = this(Console.in, new PrintWriter(Console.out), true)
- def this(in: io.File, out: PrintWriter, interactive: Boolean) = this(in.bufferedReader(), out, interactive)
-
- lazy val history = History.Empty
- lazy val completion = Completion.Empty
+extends InteractiveReader
+{
+ val history = NoHistory
+ val completion = NoCompletion
def init() = ()
def reset() = ()
+ def redrawLine() = ()
+ def currentLine = ""
def readOneLine(prompt: String): String = {
if (interactive) {
out.print(prompt)
@@ -30,3 +30,11 @@ extends InteractiveReader {
in.readLine()
}
}
+
+object SimpleReader {
+ def defaultIn = Console.in
+ def defaultOut = new PrintWriter(Console.out)
+
+ def apply(in: BufferedReader = defaultIn, out: PrintWriter = defaultOut, interactive: Boolean = true): SimpleReader =
+ new SimpleReader(in, out, interactive)
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala b/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala
index 91dee97277..f72409c8e7 100644
--- a/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala
@@ -19,46 +19,55 @@ import scala.reflect.NameTransformer
*/
trait TypeStrings {
private val ObjectClass = classOf[java.lang.Object]
- private val primitives = Set[String]("byte", "char", "short", "int", "long", "float", "double", "boolean")
- private def unbox(s: String): String = s.stripPrefix("java.lang.") match {
- case "Integer" => "scala.Int"
- case "Character" => "scala.Char"
- case "Void" => "scala.Unit"
- case x @ ("Byte" | "Short" | "Long" | "Float" | "Double" | "Boolean") => "scala." + x
- case _ => NameTransformer.decode(s)
- }
+ private val primitives = Set[String]("byte", "char", "short", "int", "long", "float", "double", "boolean", "void")
+ private val primitiveMap = primitives.toList map { x =>
+ val key = x match {
+ case "void" => "Void"
+ case "int" => "Integer"
+ case "char" => "Character"
+ case s => s.capitalize
+ }
+ val value = x match {
+ case "void" => "Unit"
+ case s => s.capitalize
+ }
+
+ ("java.lang." + key) -> ("scala." + value)
+ } toMap
def scalaName(s: String): String = {
- if (s endsWith "$") (s dropRight 1) + ".type"
- else if (primitives(s)) "scala." + s.capitalize
+ if (s endsWith "$") s.init + ".type"
else if (s == "void") "scala.Unit"
- else unbox(s)
+ else if (primitives(s)) "scala." + s.capitalize
+ else primitiveMap.getOrElse(s, NameTransformer decode s)
}
def scalaName(clazz: JClass): String = scalaName(clazz.getName)
def scalaName(m: ClassManifest[_]): String = scalaName(m.erasure)
def anyClass(x: Any): JClass = if (x == null) null else x.asInstanceOf[AnyRef].getClass
+ private def brackets(tps: String*): String =
+ if (tps.isEmpty) ""
+ else tps.mkString("[", ", ", "]")
+
private def tvarString(tvar: TypeVariable[_]): String = tvarString(tvar.getBounds.toList)
private def tvarString(bounds: List[AnyRef]): String = {
val xs = bounds filterNot (_ == ObjectClass) collect { case x: Class[_] => x }
if (xs.isEmpty) "_"
else scalaName(xs.head)
}
- private def tparamString(clazz: JClass): String = {
- val tps = clazz.getTypeParameters.toList
- if (tps.isEmpty)
- return ""
+ private def tparamString(clazz: JClass): String =
+ brackets(clazz.getTypeParameters map tvarString: _*)
- (tps map tvarString).mkString("[", ", ", "]")
- }
- private def tparamString[T: Manifest] : String = {
- val tps = manifest[T].typeArguments
- if (tps.isEmpty)
- return ""
+ private def tparamString[T: Manifest] : String =
+ brackets(manifest[T].typeArguments map (m => tvarString(List(m.erasure))): _*)
- tps.map(m => tvarString(List(m.erasure))).mkString("[", ", ", "]")
- }
- /** Going for an overabundance of caution right now.
+ /** Going for an overabundance of caution right now. Later these types
+ * can be a lot more precise, but right now the manifests have a habit of
+ * introducing material which is not syntactically valid as scala source.
+ * When this happens it breaks the repl. It would be nice if we mandated
+ * that manifest toString methods (or some other method, since it's bad
+ * practice to rely on toString for correctness) generated the VALID string
+ * representation of the type.
*/
def fromTypedValue[T: Manifest](x: T): String = fromManifest[T]
def fromValue(value: Any): String = if (value == null) "Null" else fromClazz(anyClass(value))