summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-01-31 05:46:44 +0000
committerPaul Phillips <paulp@improving.org>2011-01-31 05:46:44 +0000
commit2f1759cebcba51509f9d66ddbe1b8248f206e4a4 (patch)
tree29ea17c1a111af4ee3e88f4750c92923d6094985
parent174a25e1b3bc054920a9418761bf9f4a8c3d9e79 (diff)
downloadscala-2f1759cebcba51509f9d66ddbe1b8248f206e4a4.tar.gz
scala-2f1759cebcba51509f9d66ddbe1b8248f206e4a4.tar.bz2
scala-2f1759cebcba51509f9d66ddbe1b8248f206e4a4.zip
More work on the repl.
the target, so it will no longer offer you methods that scala won't let you call. class B { def f = 5 ; def g = "a" } class C extends B { def BIPPY = List(1, 2, 3) } scala> val x: B = new C ; x.<tab> f g scala> val x: C = new C ; x.<tab> BIPPY f g No review.
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoop.scala1
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala73
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala34
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala9
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Power.scala5
5 files changed, 59 insertions, 63 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
index 0e2eb5d579..3be18bbb08 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
@@ -128,7 +128,6 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter)
}
intp.setContextClassLoader()
installSigIntHandler()
- // intp.quietBind("settings", "scala.tools.nsc.InterpreterSettings", intp.isettings)
}
/** print a friendly help message */
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index cb6971e808..be80797c9b 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -272,10 +272,10 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
/** the previous requests this interpreter has processed */
private lazy val prevRequests = mutable.ArrayBuffer[Request]()
private lazy val referencedNameMap = mutable.Map[Name, Request]()
- private lazy val definedNameMap: mutable.Map[Name, Request] = mutable.Map[Name, Request]()
- private def allHandlers = prevRequests.toList flatMap (_.handlers)
- private def allReqAndHandlers = prevRequests.toList flatMap (req => req.handlers map (req -> _))
- private def importHandlers = allHandlers collect { case x: ImportHandler => x }
+ private lazy val definedNameMap = mutable.Map[Name, Request]()
+ private def allHandlers = prevRequests.toList flatMap (_.handlers)
+ private def allReqAndHandlers = prevRequests.toList flatMap (req => req.handlers map (req -> _))
+ private def importHandlers = allHandlers collect { case x: ImportHandler => x }
def allDefinedNames = definedNameMap.keys.toList sortBy (_.toString)
def pathToType(id: String): String = pathToName(newTypeName(id))
@@ -314,14 +314,8 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
}
}
def recordRequest(req: Request) {
- if (req == null || referencedNameMap == null) {
- DBG("Received null value at recordRequest.")
+ if (req == null || referencedNameMap == null)
return
- }
- def tripart[T](set1: Set[T], set2: Set[T]) = {
- val intersect = set1 intersect set2
- List(set1 -- intersect, intersect, set2 -- intersect)
- }
prevRequests += req
req.referencedNames foreach (x => referencedNameMap(x) = req)
@@ -333,11 +327,6 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
}
definedNameMap(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.
- if (prevRequests.size == 1)
- quietBind("settings", isettings)
}
def allSeenTypes = prevRequests.toList flatMap (_.typeOf.values.toList) distinct
@@ -675,7 +664,7 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
* append to objectName to access anything bound by request.
*/
val ComputedImports(importsPreamble, importsTrailer, accessPath) =
- importsCode(Set.empty ++ referencedNames)
+ importsCode(referencedNames.toSet)
/** Code to access a variable with the specified name */
def fullPath(vname: String): String = "%s.`%s`".format(objectName + accessPath, vname)
@@ -880,24 +869,49 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
})
private def requestForName(name: Name): Option[Request] =
- prevRequests.reverse find (_.definedNames contains name)
+ definedNameMap get name
- private def requestForIdent(line: String): Option[Request] = requestForName(newTermName(line))
+ private def requestForIdent(line: String): Option[Request] =
+ requestForName(newTermName(line)) orElse requestForName(newTypeName(line))
+
+ def definitionForName(name: Name): Option[MemberHandler] =
+ requestForName(name) flatMap { req =>
+ req.handlers find (_.definedNames contains name)
+ }
+
+ def typeOfDefinedName(name: Name): Option[Type] =
+ if (name == nme.ROOTPKG) Some(definitions.RootClass.tpe)
+ else requestForName(name) flatMap (_.compilerTypeOf get name)
// XXX literals.
- def stringToCompilerType(id: String): Type = {
- // if it's a recognized identifier, the type of that; otherwise treat the
- // String like a value (e.g. scala.collection.Map) .
- def findType = typeForIdent(id) match {
- case Some(x) => definitions.getClass(newTermName(x)).tpe
- case _ => definitions.getModule(newTermName(id)).tpe
+ // 1) Identifiers defined in the repl.
+ // 2) A path loadable via getModule.
+ // 3) Try interpreting it as an expression.
+ def typeOfExpression(expr: String): Option[Type] = {
+ val name = newTermName(expr)
+
+ def asModule = {
+ try Some(definitions.getModule(name).tpe)
+ catch { case _: MissingRequirementError => None }
+ }
+ def asExpr = beSilentDuring {
+ val lhs = freshInternalVarName()
+ interpret("val " + lhs + " = { " + expr + " } ") match {
+ case IR.Success => typeOfExpression(lhs)
+ case _ => None
+ }
}
- try findType catch { case _: MissingRequirementError => NoType }
+ typeOfDefinedName(name) orElse asModule orElse asExpr
}
+ // def compileAndTypeExpr(expr: String): Option[Typer] = {
+ // class TyperRun extends Run {
+ // override def stopPhase(name: String) = name == "superaccessors"
+ // }
+ // }
- def typeForIdent(id: String): Option[String] =
- requestForIdent(id) flatMap (x => x.typeOf get newTermName(id))
+ def clazzForIdent(id: String): Option[Class[_]] =
+ extractionValueForIdent(id) flatMap (x => Option(x) map (_.getClass))
def methodsOf(name: String) =
evalExpr[List[String]](methodsCode(name)) map (x => NameTransformer.decode(getOriginalName(x)))
@@ -925,9 +939,6 @@ class IMain(val settings: Settings, protected val out: PrintWriter) {
// evalExpr[T]("""implicitly[%s]""".format(manifest[T]))
}
- def clazzForIdent(id: String): Option[Class[_]] =
- extractionValueForIdent(id) flatMap (x => Option(x) map (_.getClass))
-
private def methodsCode(name: String) =
"%s.%s(%s)".format(classOf[ReflectionCompletion].getName, "methodsOf", name)
diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala
index 1df850458c..8093ae1d3c 100644
--- a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala
@@ -58,7 +58,7 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
// for some reason any's members don't show up in subclasses, which
// we need so 5.<tab> offers asInstanceOf etc.
private def anyMembers = AnyClass.tpe.nonPrivateMembers
- def anyRefMethodsToShow = List("isInstanceOf", "asInstanceOf", "toString")
+ def anyRefMethodsToShow = Set("isInstanceOf", "asInstanceOf", "toString")
def tos(sym: Symbol) = sym.name.decode.toString
def memberNamed(s: String) = members find (x => tos(x) == s)
@@ -89,8 +89,7 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
with CompilerCompletion {
def excludeEndsWith: List[String] = Nil
def excludeStartsWith: List[String] = List("<") // <byname>, <repeated>, etc.
- def excludeNames: List[String] =
- anyref.methodNames.filterNot(anyRefMethodsToShow contains) ++ List("_root_")
+ def excludeNames: List[String] = (anyref.methodNames filterNot anyRefMethodsToShow) :+ "_root_"
def methodSignatureString(sym: Symbol) = {
def asString = new MethodSymbolOutput(sym).methodString()
@@ -144,28 +143,13 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
// the unqualified vals/defs/etc visible in the repl
object ids extends CompletionAware {
- override def completions(verbosity: Int) = intp.unqualifiedIds :+ "classOf"
- // we try to use the compiler and fall back on reflection if necessary
- // (which at present is for anything defined in the repl session.)
+ override def completions(verbosity: Int) = intp.unqualifiedIds ++ List("classOf") //, "_root_")
+ // now we use the compiler for everything.
override def follow(id: String) = {
- if (completions(0) contains id) {
- for (clazz <- intp clazzForIdent id) yield {
- // XXX The isMemberClass check is a workaround for the crasher described
- // in the comments of #3431. The issue as described by iulian is:
- //
- // Inner classes exist as symbols
- // inside their enclosing class, but also inside their package, with a mangled
- // name (A$B). The mangled names should never be loaded, and exist only for the
- // optimizer, which sometimes cannot get the right symbol, but it doesn't care
- // and loads the bytecode anyway.
- //
- // So this solution is incorrect, but in the short term the simple fix is
- // to skip the compiler any time completion is requested on a nested class.
- if (clazz.isMemberClass) new InstanceCompletion(clazz)
- else (typeOf(clazz.getName) map TypeMemberCompletion.apply) getOrElse new InstanceCompletion(clazz)
- }
- }
- else None
+ if (completions(0) contains id)
+ intp typeOfExpression id map (tpe => TypeMemberCompletion(tpe))
+ else
+ None
}
override def toString = "<repl ids> (%s)".format(completions(0).size)
}
@@ -353,7 +337,7 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput
catch {
case ex: Exception =>
DBG("Error: complete(%s, %s) provoked %s".format(buf, cursor, ex))
- Candidates(cursor, List(" ", "<completion error>"))
+ Candidates(cursor, List(" ", "<completion error: " + ex.getMessage + ">"))
}
}
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala
index 29dd33112b..2de3c4ea5b 100644
--- a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala
@@ -95,6 +95,7 @@ trait MemberHandlers {
* in a single interpreter request.
*/
sealed abstract class MemberHandler(val member: Tree) {
+ def tpe = member.tpe
def definesImplicit = false
def definesValue = false
@@ -102,9 +103,9 @@ trait MemberHandlers {
def definesType = Option.empty[TypeName]
lazy val referencedNames = ImportVarsTraverser(member)
- def importedNames = List[Name]()
- def definedNames = definesTerm.toList ++ definesType.toList
- def definedOrImported = definedNames ++ importedNames
+ def importedNames = List[Name]()
+ def definedNames = definesTerm.toList ++ definesType.toList
+ def definedOrImported = definedNames ++ importedNames
def extraCodeToEvaluate(req: Request): String = ""
def resultExtractionCode(req: Request): String = ""
@@ -185,7 +186,7 @@ trait MemberHandlers {
class ImportHandler(imp: Import) extends MemberHandler(imp) {
val Import(expr, selectors) = imp
- def targetType = Some(intp.stringToCompilerType(expr.toString)) filterNot (_ == NoType)
+ def targetType = intp.typeOfExpression("" + expr)
private def selectorWild = selectors filter (_.name == nme.USCOREkw) // wildcard imports, e.g. import foo._
private def selectorRenames = selectors map (_.rename) filterNot (_ == null)
diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala
index e0b22ae511..dd0b05747b 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Power.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala
@@ -64,11 +64,12 @@ class Power(repl: ILoop, intp: IMain) {
if (repl != null) {
intp.bind[ILoop]("repl", repl)
intp.bind[History]("history", repl.in.history)
- intp.bind[Completion]("completion", repl.in.completion)
+ intp.bind("completion", repl.in.completion)
}
intp.bind[IMain]("intp", intp)
intp.bind[Power]("power", this)
+ intp.bind[ISettings]("isettings", intp.isettings)
init split '\n' foreach interpret
}
@@ -127,7 +128,7 @@ class Power(repl: ILoop, intp: IMain) {
run.units.toList map (_.body)
}
def mkTypedTree(code: String) = mkTypedTrees(code).head
- def mkType(id: String): Type = intp.stringToCompilerType(id)
+ def mkType(id: String): Type = intp.typeOfExpression(id) getOrElse NoType
override def toString = """
|** Power mode status **