summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-11-27 22:53:42 +0000
committerPaul Phillips <paulp@improving.org>2010-11-27 22:53:42 +0000
commita5553b8384a6e4cb6071846368bb0d17be2e246f (patch)
tree76299ca2948389e4a05d28b8a6e4ede6c3157d50 /src/compiler
parent3e3e3564ca2771b0946c9c8b35a6a393f4330354 (diff)
downloadscala-a5553b8384a6e4cb6071846368bb0d17be2e246f.tar.gz
scala-a5553b8384a6e4cb6071846368bb0d17be2e246f.tar.bz2
scala-a5553b8384a6e4cb6071846368bb0d17be2e246f.zip
Some hardening of the repl's internals extracte...
Some hardening of the repl's internals extracted from a more interesting patch in progress. No review.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/cmd/program/Tokens.scala6
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala141
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Completion.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Parsed.scala3
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/package.scala3
-rw-r--r--src/compiler/scala/tools/util/StringOps.scala1
6 files changed, 98 insertions, 58 deletions
diff --git a/src/compiler/scala/tools/cmd/program/Tokens.scala b/src/compiler/scala/tools/cmd/program/Tokens.scala
index 36786aa2b7..9be1eb4325 100644
--- a/src/compiler/scala/tools/cmd/program/Tokens.scala
+++ b/src/compiler/scala/tools/cmd/program/Tokens.scala
@@ -70,6 +70,12 @@ object Tokens {
Path onlyFiles traverse filter (_ hasExtension "scala") toList
}
+ def fromScalaString(code: String): List[Any] = {
+ val f = File.makeTemp("tokens")
+ f writeAll code
+ fromScalaSource(f)
+ }
+
/** Tokenizes a single scala file.
*/
def fromScalaSource(file: Path): List[Any] = fromScalaSource(file.path)
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index 8a22c76ab5..e9474e973c 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -8,29 +8,28 @@ package scala.tools.nsc
import Predef.{ println => _, _ }
import java.io.{ File, PrintWriter, StringWriter, Writer }
import File.pathSeparator
-import java.lang.{ Class, ClassLoader }
+import java.lang.{ reflect, Class, ClassLoader => JavaClassLoader }
import java.net.{ MalformedURLException, URL }
-import java.lang.reflect
-import java.util.concurrent.Future
import reflect.InvocationTargetException
+import java.util.concurrent.Future
-import scala.collection.{ mutable, immutable }
-import scala.PartialFunction.{ cond, condOpt }
+import util.{ Set => _, _ }
+import interpreter._
+import io.{ PlainFile, VirtualDirectory, spawn, callable, newDaemonThreadExecutor }
+import reporters.{ ConsoleReporter, Reporter }
+import symtab.{ Flags, Names }
+import scala.tools.nsc.{ InterpreterResults => IR }
import scala.tools.util.{ PathResolver, SignalManager }
-import scala.reflect.Manifest
-import scala.collection.mutable.{ ListBuffer, HashSet, HashMap, ArrayBuffer }
import scala.tools.nsc.util.{ ScalaClassLoader, Exceptional }
import ScalaClassLoader.URLClassLoader
import Exceptional.unwrap
-import scala.util.control.Exception.{ Catcher, catching, catchingPromiscuously, ultimately }
-import io.{ PlainFile, VirtualDirectory, spawn, callable, newDaemonThreadExecutor }
-import reporters.{ ConsoleReporter, Reporter }
-import symtab.{ Flags, Names }
-import util.{ ScalaPrefs, JavaStackFrame, SourceFile, BatchSourceFile, ScriptSourceFile, ClassPath, Chars, stringFromWriter }
+import scala.collection.{ mutable, immutable }
+import scala.collection.mutable.{ ListBuffer, ArrayBuffer }
+import scala.PartialFunction.{ cond, condOpt }
+import scala.util.control.Exception.{ Catcher, catching, catchingPromiscuously, ultimately, unwrapping }
import scala.reflect.NameTransformer
-import scala.tools.nsc.{ InterpreterResults => IR }
-import interpreter._
+
import Interpreter._
/** <p>
@@ -76,6 +75,8 @@ import Interpreter._
class Interpreter(val settings: Settings, out: PrintWriter) {
repl =>
+ private val RESULT_OBJECT_PREFIX = "RequestResult$"
+
def println(x: Any) = {
out.println(x)
out.flush()
@@ -252,10 +253,10 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
def setContextClassLoader() = classLoader.setAsContext()
/** the previous requests this interpreter has processed */
- private val prevRequests = new ArrayBuffer[Request]()
- private val usedNameMap = new HashMap[Name, Request]()
- private val boundNameMap = new HashMap[Name, Request]()
- private def allHandlers = prevRequests.toList flatMap (_.handlers)
+ private val prevRequests = new ArrayBuffer[Request]()
+ private val usedNameMap = new mutable.HashMap[Name, Request]()
+ private val boundNameMap = new mutable.HashMap[Name, Request]()
+ private def allHandlers = prevRequests.toList flatMap (_.handlers)
private def allReqAndHandlers = prevRequests.toList flatMap (req => req.handlers map (req -> _))
def printAllTypeOf = {
@@ -276,6 +277,15 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
None
}
+ /** Stubs for work in progress. */
+ def handleTypeRedefinition(name: Name, old: Request, req: Request) = {
+ DBG("Redefining type '%s'\n %s -> %s".format(name, old simpleNameOfType name, req simpleNameOfType name))
+ }
+
+ def handleTermRedefinition(name: Name, old: Request, req: Request) = {
+ DBG("Redefining term '%s'\n %s -> %s".format(name, old compilerTypeOf name, req compilerTypeOf name))
+ }
+
def recordRequest(req: Request) {
def tripart[T](set1: Set[T], set2: Set[T]) = {
val intersect = set1 intersect set2
@@ -284,7 +294,14 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
prevRequests += req
req.usedNames foreach (x => usedNameMap(x) = req)
- req.boundNames foreach (x => boundNameMap(x) = req)
+
+ req.boundNames foreach { name =>
+ if (boundNameMap contains name) {
+ if (name.isTypeName) handleTypeRedefinition(name, boundNameMap(name), req)
+ else handleTermRedefinition(name, boundNameMap(name), req)
+ }
+ boundNameMap(name) = req
+ }
// XXX temporarily putting this here because of tricky initialization order issues
// so right now it's not bound until after you issue a command.
@@ -297,18 +314,19 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
}
private def keyList[T](x: collection.Map[T, _]): List[T] = x.keys.toList sortBy (_.toString)
- def allUsedNames = keyList(usedNameMap)
- def allBoundNames = keyList(boundNameMap)
- def allSeenTypes = prevRequests.toList flatMap (_.typeOf.values.toList) distinct
+ def allUsedNames = keyList(usedNameMap)
+ def allBoundNames = keyList(boundNameMap)
+ def allSeenTypes = prevRequests.toList flatMap (_.typeOf.values.toList) distinct
+ def allDefinedTypes = prevRequests.toList flatMap (_.definedTypes.values.toList) distinct
def allValueGeneratingNames = allHandlers flatMap (_.generatesValue)
- def allImplicits = partialFlatMap(allHandlers) {
+ def allImplicits = partialFlatMap(allHandlers) {
case x: MemberHandler if x.definesImplicit => x.boundNames
}
/** Generates names pre0, pre1, etc. via calls to apply method */
class NameCreator(pre: String) {
private var x = -1
- var mostRecent: String = null
+ var mostRecent: String = ""
def apply(): String = {
x += 1
@@ -437,7 +455,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
}
val code, trailingBraces, accessPath = new StringBuffer
- val currentImps = HashSet[Name]()
+ val currentImps = mutable.HashSet[Name]()
// add code for a new object to hold some imports
def addWrapper() {
@@ -522,7 +540,11 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
compileSources(new BatchSourceFile("<script>", code))
def compileAndSaveRun(label: String, code: String) = {
- if (isReplDebug) {
+ /** Secret bookcase entrance for repl debuggers: end the line
+ * with "// show" and see what's going on.
+ */
+ if (code.lines exists (_.trim endsWith "// show")) {
+ Console println code
parse(code) match {
case Some(trees) => trees foreach (t => DBG(compiler.asCompactString(t)))
case _ => DBG("Parse error:\n\n" + code)
@@ -670,7 +692,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
* that need to be imported. It might return extra names.
*/
private class ImportVarsTraverser extends Traverser {
- val importVars = new HashSet[Name]()
+ val importVars = new mutable.HashSet[Name]()
override def traverse(ast: Tree) = ast match {
// XXX this is obviously inadequate but it's going to require some effort
@@ -712,7 +734,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
override def generatesValue = Some(vname)
override def resultExtractionCode(req: Request, code: PrintWriter) {
- val isInternal = isGeneratedVarName(vname) && req.typeOfEnc(vname) == "Unit"
+ val isInternal = isGeneratedVarName(vname) && req.lookupTypeOf(vname) == "Unit"
if (!mods.isPublic || isInternal) return
lazy val extractor = "scala.runtime.ScalaRunTime.stringOf(%s, %s)".format(req fullPath vname, maxStringElements)
@@ -748,7 +770,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
/** Print out lhs instead of the generated varName */
override def resultExtractionCode(req: Request, code: PrintWriter) {
- val lhsType = string2code(req typeOfEnc helperName)
+ val lhsType = string2code(req lookupTypeOf helperName)
val res = string2code(req fullPath helperName)
val codeToPrint = """ + "%s: %s = " + %s + "\n" """.format(lhs, lhsType, res)
@@ -819,7 +841,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
def objectName = lineName + INTERPRETER_WRAPPER_SUFFIX
/** name of the object that retrieves the result from the above object */
- def resultObjectName = "RequestResult$" + objectName
+ def resultObjectName = RESULT_OBJECT_PREFIX + objectName
/** handlers for each tree in this request */
val handlers: List[MemberHandler] = trees map chooseHandler
@@ -837,6 +859,11 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
case x: ValHandler => boundNames
case x: ModuleHandler => List(x.name)
}
+ /** Type names */
+ def typeNames = handlers collect {
+ case x: ClassHandler => x.name
+ case x: TypeAliasHandler => x.name
+ }
/** Code to import bound names from previous lines - accessPath is code to
* append to objectName to access anything bound by request.
@@ -935,6 +962,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
// extract and remember types
typeOf
+ definedTypes
// compile the result-extraction object
extractionObjectRun
@@ -943,7 +971,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
!reporter.hasErrors
}
- def atNextPhase[T](op: => T): T = compiler.atPhase(objRun.typerPhase.next)(op)
+ def afterTyper[T](op: => T): T = compiler.atPhase(objRun.typerPhase.next)(op)
/** The outermost wrapper object */
lazy val outerResObjSym: Symbol = getMember(EmptyPackage, newTermName(objectName))
@@ -953,34 +981,38 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
lazy val resObjSym =
accessPath.split("\\.").foldLeft(outerResObjSym) { (sym, name) =>
if (name == "") sym else
- atNextPhase(sym.info member newTermName(name))
+ afterTyper(sym.info member newTermName(name))
}
/* typeOf lookup with encoding */
- def typeOfEnc(vname: Name) = typeOf(compiler encode vname)
-
- /** Types of variables defined by this request. */
- lazy val typeOf: Map[Name, String] = {
- def getTypes(names: List[Name], nameMap: Name => Name): Map[Name, String] = {
- names.foldLeft(Map.empty[Name, String]) { (map, name) =>
- val tp1 = atNextPhase(resObjSym.info.nonPrivateDecl(name).tpe)
- // the types are all =>T; remove the =>
- val tp2 = tp1 match {
- case PolyType(Nil, tp) => tp
- case tp => tp
- }
- // normalize non-public types so we don't see protected aliases like Self
- val tp3 = compiler.atPhase(objRun.typerPhase)(tp2 match {
- case TypeRef(_, sym, _) if !sym.isPublic => tp2.normalize.toString
- case tp => tp.toString
- })
-
- map + (name -> tp3)
- }
+ def lookupTypeOf(name: Name) = typeOf.getOrElse(name, typeOf(compiler encode name))
+
+ def simpleNameOfType(name: Name) = compilerTypeOf(name).typeSymbol.simpleName
+
+ private def typeMap[T](f: Type => T): Map[Name, T] = {
+ def toType(name: Name): T = {
+ // the types are all =>T; remove the =>
+ val tp1 = afterTyper(resObjSym.info.nonPrivateDecl(name).tpe match {
+ case PolyType(Nil, tp) => tp
+ case tp => tp
+ })
+ // normalize non-public types so we don't see protected aliases like Self
+ afterTyper(tp1 match {
+ case TypeRef(_, sym, _) if !sym.isPublic => f(tp1.normalize)
+ case tp => f(tp)
+ })
}
+ valueNames ++ defNames ++ typeNames map (x => x -> toType(x)) toMap
+ }
+ /** Types of variables defined by this request. */
+ lazy val compilerTypeOf = typeMap[Type](x => x)
+ /** String representations of same. */
+ lazy val typeOf = typeMap[String](_.toString)
- getTypes(valueNames, nme.getterToLocal(_)) ++ getTypes(defNames, identity)
+ lazy val definedTypes: Map[Name, Type] = {
+ typeNames map (x => x -> afterTyper(resObjSym.info.nonPrivateDecl(x).tpe)) toMap
}
+
private def bindExceptionally(t: Throwable) = {
val ex: Exceptional =
if (isettings.showInternalStackTraces) Exceptional(t)
@@ -1095,7 +1127,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
case x: ValOrDefDef => x.name
case Assign(Ident(name), _) => name
case ModuleDef(_, name, _) => name
- case _ => onull(varNameCreator.mostRecent)
+ case _ => varNameCreator.mostRecent
}
private def requestForName(name: Name): Option[Request] =
@@ -1103,6 +1135,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) {
private def requestForIdent(line: String): Option[Request] = requestForName(newTermName(line))
+ // XXX literals.
def stringToCompilerType(id: String): compiler.Type = {
// if it's a recognized identifier, the type of that; otherwise treat the
// String like a value (e.g. scala.collection.Map) .
diff --git a/src/compiler/scala/tools/nsc/interpreter/Completion.scala b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
index 22a95a4bf8..426f2debf4 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Completion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Completion.scala
@@ -310,7 +310,7 @@ class Completion(val repl: Interpreter) extends CompletionOutput {
// This is jline's entry point for completion.
override def complete(_buf: String, cursor: Int, candidates: JList[String]): Int = {
- val buf = onull(_buf)
+ val buf = if (_buf == null) "" else _buf
verbosity = if (isConsecutiveTabs(buf, cursor)) verbosity + 1 else 0
DBG("\ncomplete(%s, %d) last = (%s, %d), verbosity: %s".format(buf, cursor, lastBuf, lastCursor, verbosity))
diff --git a/src/compiler/scala/tools/nsc/interpreter/Parsed.scala b/src/compiler/scala/tools/nsc/interpreter/Parsed.scala
index 84f5477c21..d5953d3a23 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Parsed.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Parsed.scala
@@ -22,6 +22,7 @@ class Parsed private (
def isAtStart = cursor <= 0
private var _verbosity = 0
+
def verbosity = _verbosity
def withVerbosity(v: Int): this.type = returning[this.type](this)(_ => _verbosity = v)
@@ -56,6 +57,8 @@ class Parsed private (
}
object Parsed {
+ private def onull(s: String) = if (s == null) "" else s
+
def apply(s: String): Parsed = apply(onull(s), onull(s).length)
def apply(s: String, cursor: Int): Parsed = apply(onull(s), cursor, "{},`; \t" contains _)
def apply(s: String, cursor: Int, delimited: Char => Boolean): Parsed =
diff --git a/src/compiler/scala/tools/nsc/interpreter/package.scala b/src/compiler/scala/tools/nsc/interpreter/package.scala
index eaf736c5b7..c57874e59a 100644
--- a/src/compiler/scala/tools/nsc/interpreter/package.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/package.scala
@@ -12,9 +12,6 @@ package object interpreter {
/** Frequency counter */
def freq[T](seq: Seq[T]) = seq groupBy identity mapValues (_.length)
- /** null becomes "", otherwise identity */
- def onull(s: String) = if (s == null) "" else s
-
/** Heuristically strip interpreter wrapper prefixes
* from an interpreter output string.
*/
diff --git a/src/compiler/scala/tools/util/StringOps.scala b/src/compiler/scala/tools/util/StringOps.scala
index a3e7c512eb..216e9f1f6c 100644
--- a/src/compiler/scala/tools/util/StringOps.scala
+++ b/src/compiler/scala/tools/util/StringOps.scala
@@ -17,6 +17,7 @@ package util
* @version 1.0
*/
object StringOps {
+ def onull(s: String) = if (s == null) "" else s
def oempty(xs: String*) = xs filterNot (x => x == null || x == "")
def ojoin(xs: Seq[String], sep: String) = oempty(xs: _*) mkString sep
def ojoinOr(xs: Seq[String], sep: String, orElse: String) = {