summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-07-12 19:43:14 +0000
committerPaul Phillips <paulp@improving.org>2011-07-12 19:43:14 +0000
commit70da5a627fe2ce15df64741b5784ed97c361a95e (patch)
treeb689950c0eba88d27e06c2baf4a56d4a2e8c5461 /src/compiler
parent6163cdcc236698b333016becc57f545098760e32 (diff)
downloadscala-70da5a627fe2ce15df64741b5784ed97c361a95e.tar.gz
scala-70da5a627fe2ce15df64741b5784ed97c361a95e.tar.bz2
scala-70da5a627fe2ce15df64741b5784ed97c361a95e.zip
A bunch of repl stuff.
type mismatches, for real this time. :power mode goes to phase typer automatically. You can get the symbols for repl-defined names more directly: scala> case class Bippy(x: Int) defined class Bippy scala> intp.terms("Bippy") res1: intp.global.Symbol = object Bippy scala> intp.types("Bippy") res2: intp.global.Symbol = class Bippy scala> intp("Bippy") // tries type first res3: intp.global.Symbol = class Bippy scala> intp("scala.collection.Map") // falls back to fully qualified res4: intp.global.Symbol = trait Map I changed the implicit which used to install "tpe" and "symbol" to install "tpe_" and "symbol_" because it was too easy to do something you didn't mean to, like calling x.tpe where x is a Manifest. Said implicit now handles manifest type arguments, so you can get the full translation from a manifest representation to a compiler type, at least for simple types and only as much as manifests work, which is not that much. Fortunately that situation is all changing soon. scala> List(List(1, 2, 3)).tpe_ res5: power.Type = List[List[Int]] scala> res5.typeArgs res6: List[power.global.Type] = List(List[Int]) Review by moors.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoop.scala9
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala93
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala5
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Power.scala127
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ReplVals.scala32
5 files changed, 184 insertions, 82 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
index b249d37006..8e7f73296f 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala
@@ -43,11 +43,11 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
var settings: Settings = _
var intp: IMain = _
+ override def echoCommandMessage(msg: String): Unit =
+ intp.reporter.printMessage(msg)
+
def isAsync = !settings.Yreplsync.value
- lazy val power = {
- val g = intp.global
- Power[g.type](this, g)
- }
+ lazy val power = Power(this)
// TODO
// object opt extends AestheticSettings
@@ -622,6 +622,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
def enablePowerMode(isDuringInit: Boolean) = {
replProps.power setValue true
power.unleash()
+ intp.beSilentDuring(phaseCommand("typer"))
if (isDuringInit) asyncMessage(power.banner)
else echo(power.banner)
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index dd147d7fff..6076f5add5 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -267,7 +267,10 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
definitions.
*/
private var _classLoader: AbstractFileClassLoader = null
- def resetClassLoader() = _classLoader = makeClassLoader()
+ def resetClassLoader() = {
+ repldbg("Setting new classloader: was " + _classLoader)
+ _classLoader = makeClassLoader()
+ }
def classLoader: AbstractFileClassLoader = {
if (_classLoader == null)
resetClassLoader()
@@ -287,8 +290,10 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
override protected def findAbstractFile(name: String): AbstractFile = {
super.findAbstractFile(name) match {
// deadlocks on startup if we try to translate names too early
- case null if isInitializeComplete => generatedName(name) map (x => super.findAbstractFile(x)) orNull
- case file => file
+ case null if isInitializeComplete =>
+ generatedName(name) map (x => super.findAbstractFile(x)) orNull
+ case file =>
+ file
}
}
}
@@ -533,18 +538,14 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
def interpret(line: String, synthetic: Boolean): IR.Result = {
def loadAndRunReq(req: Request) = {
val (result, succeeded) = req.loadAndRun
+
/** To our displeasure, ConsoleReporter offers only printMessage,
* which tacks a newline on the end. Since that breaks all the
* output checking, we have to take one off to balance.
*/
- def show() = {
- if (result == "") ()
- else printMessage(result stripSuffix "\n")
- }
-
if (succeeded) {
- if (printResults)
- show()
+ if (printResults && result != "")
+ printMessage(result stripSuffix "\n")
else if (isReplDebug) // show quiet-mode activity
printMessage(result.trim.lines map ("[quiet] " + _) mkString "\n")
@@ -555,7 +556,7 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
}
else {
// don't truncate stack traces
- withoutTruncating(show())
+ withoutTruncating(printMessage(result))
IR.Error
}
}
@@ -588,11 +589,19 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
|}
""".stripMargin.format(bindRep.evalName, boundType, boundType)
)
- bindRep.callOpt("set", value) match {
- case Some(_) => interpret("val %s = %s.value".format(name, bindRep.evalPath))
- case _ => repldbg("Set failed in bind(%s, %s, %s)".format(name, boundType, value)) ; IR.Error
+ bindRep.callEither("set", value) match {
+ case Left(ex) =>
+ repldbg("Set failed in bind(%s, %s, %s)".format(name, boundType, value))
+ repldbg(util.stackTraceString(ex))
+ IR.Error
+
+ case Right(_) =>
+ val line = "val %s = %s.value".format(name, bindRep.evalPath)
+ repldbg("Interpreting: " + line)
+ interpret(line)
}
}
+
def rebind(p: NamedParam): IR.Result = {
val name = p.name
val oldType = typeOfTerm(name) getOrElse { return IR.Error }
@@ -688,15 +697,30 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
def call(name: String, args: Any*): AnyRef =
evalMethod(name).invoke(evalClass, args.map(_.asInstanceOf[AnyRef]): _*)
+ def callEither(name: String, args: Any*): Either[Throwable, AnyRef] =
+ try Right(call(name, args: _*))
+ catch { case ex: Throwable => Left(ex) }
+
def callOpt(name: String, args: Any*): Option[AnyRef] =
try Some(call(name, args: _*))
- catch { case ex: Exception => bindError(ex) ; None }
+ catch { case ex: Throwable => bindError(ex) ; None }
+
+ class EvalException(msg: String, cause: Throwable) extends RuntimeException(msg, cause) { }
- private def load(s: String): Class[_] =
- (classLoader tryToInitializeClass s) getOrElse sys.error("Failed to load expected class: '" + s + "'")
+ private def evalError(path: String, ex: Throwable) =
+ throw new EvalException("Failed to load '" + path + "': " + ex.getMessage, ex)
+ private def load(path: String): Class[_] = {
+ try Class.forName(path, true, classLoader)
+ catch { case ex => evalError(path, unwrap(ex)) }
+ }
+
+ var evalCaught: Option[Throwable] = None
lazy val evalClass = load(evalPath)
- lazy val evalValue = callOpt(evalName)
+ lazy val evalValue = callEither(evalName) match {
+ case Left(ex) => evalCaught = Some(ex) ; None
+ case Right(result) => Some(result)
+ }
def compile(source: String): Boolean = compileAndSaveRun("<console>", source)
def lineAfterTyper[T](op: => T): T = {
@@ -986,6 +1010,39 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
def definedTypes = onlyTypes(allDefinedNames)
def definedSymbols = prevRequests.toSet flatMap ((x: Request) => x.definedSymbols.values)
+ private def findName(name: Name) = definedSymbols find (_.name == name)
+
+ private def missingOpt(op: => Symbol): Option[Symbol] =
+ try Some(op)
+ catch { case _: MissingRequirementError => None }
+ private def missingWrap(op: => Symbol): Symbol =
+ try op
+ catch { case _: MissingRequirementError => NoSymbol }
+
+ def optCompilerClass(name: String) = missingOpt(definitions.getClass(name))
+ def optCompilerModule(name: String) = missingOpt(definitions.getModule(name))
+ def getCompilerClass(name: String) = missingWrap(definitions.getClass(name))
+ def getCompilerModule(name: String) = missingWrap(definitions.getModule(name))
+
+ /** Translate a repl-defined identifier into a Symbol.
+ */
+ def apply(name: String): Symbol = {
+ val tpname = newTypeName(name)
+ (
+ findName(tpname)
+ orElse findName(tpname.companionName)
+ orElse optCompilerClass(name)
+ orElse optCompilerModule(name)
+ getOrElse NoSymbol
+ )
+ }
+ def types(name: String): Symbol = {
+ findName(newTypeName(name)) getOrElse getCompilerClass(name)
+ }
+ def terms(name: String): Symbol = {
+ findName(newTermName(name)) getOrElse getCompilerModule(name)
+ }
+
/** the previous requests this interpreter has processed */
private lazy val prevRequests = mutable.ListBuffer[Request]()
private lazy val referencedNameMap = mutable.Map[Name, Request]()
diff --git a/src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala b/src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala
index 188f891054..9469baa4e2 100644
--- a/src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala
@@ -29,6 +29,9 @@ object ProcessResult {
trait LoopCommands {
protected def out: JPrintWriter
+ // So outputs can be suppressed.
+ def echoCommandMessage(msg: String): Unit = out println msg
+
// a single interpreter command
abstract class LoopCommand(val name: String, val help: String) extends (String => Result) {
private var _longHelp: String = null
@@ -95,7 +98,7 @@ trait LoopCommands {
// to print something to the console, so we accomodate Unit and String returns.
implicit def resultFromUnit(x: Unit): Result = default
implicit def resultFromString(msg: String): Result = {
- out println msg
+ echoCommandMessage(msg)
default
}
}
diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala
index d907d5024f..95e2e99dd1 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Power.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala
@@ -6,7 +6,7 @@
package scala.tools.nsc
package interpreter
-import scala.reflect.NameTransformer
+import scala.reflect.{ NameTransformer, AnyValManifest }
import scala.collection.{ mutable, immutable }
import scala.util.matching.Regex
import scala.tools.nsc.util.{ BatchSourceFile }
@@ -15,8 +15,9 @@ import scala.io.Codec
import java.net.{ URL, MalformedURLException }
import io.{ Path }
-trait SharesGlobal[G <: Global] {
- val global: G
+trait SharesGlobal {
+ type GlobalType <: Global
+ val global: GlobalType
// This business gets really old:
//
@@ -42,26 +43,26 @@ trait SharesGlobal[G <: Global] {
}
object Power {
- def apply[G <: Global](repl: ILoop, g: G) =
- new { final val global: G = g } with Power[G](repl, repl.intp)
-
- def apply(intp: IMain) =
- new { final val global = intp.global } with Power[Global](null, intp)
+ def apply(intp: IMain): Power = apply(null, intp)
+ def apply(repl: ILoop): Power = apply(repl, repl.intp)
+ def apply(repl: ILoop, intp: IMain): Power =
+ new Power(repl, intp) {
+ type GlobalType = intp.global.type
+ final val global: intp.global.type = intp.global
+ }
}
/** A class for methods to be injected into the intp in power mode.
*/
-abstract class Power[G <: Global](
+abstract class Power(
val repl: ILoop,
val intp: IMain
-) extends SharesGlobal[G] {
- import intp.{ beQuietDuring, interpret, parse }
- import global.{
- opt, definitions, analyzer,
- stringToTermName, typeRef,
- CompilationUnit,
- NoSymbol, NoPrefix, NoType
+) extends SharesGlobal {
+ import intp.{
+ beQuietDuring, typeOfExpression, getCompilerClass, getCompilerModule,
+ interpret, parse
}
+ import global._
abstract class SymSlurper {
def isKeep(sym: Symbol): Boolean
@@ -129,47 +130,36 @@ abstract class Power[G <: Global](
private def customInit = replProps.powerInitCode.option flatMap (f => io.File(f).safeSlurp())
def banner = customBanner getOrElse """
- |** Power User mode enabled - BEEP BOOP WHIR **
+ |** Power User mode enabled - BEEP BOOP SPIZ **
+ |** :phase has been set to 'typer'. **
|** scala.tools.nsc._ has been imported **
|** global._ and definitions._ also imported **
- |** New vals! Try repl, intp, global, power **
- |** New cmds! :help to discover them **
- |** New defs! Type power.<tab> to reveal **
+ |** Try :help, vals.<tab>, power.<tab> **
""".stripMargin.trim
private def initImports = List(
"scala.tools.nsc._",
"scala.collection.JavaConverters._",
"global.{ error => _, _ }",
+ "definitions.{ getClass => _, _ }",
"power.Implicits._",
"power.rutil._"
)
- def init = customInit getOrElse "import " + initImports.mkString(", ")
+
+ def init = customInit match {
+ case Some(x) => List(x)
+ case _ => initImports map ("import " + _)
+ }
/** Starts up power mode and runs whatever is in init.
*/
def unleash(): Unit = beQuietDuring {
val r = new ReplVals(repl)
- intp.bind[ILoop]("repl", repl)
- intp.bind[ReplVals]("$r", r)
-
- intp.bind("intp", r.intp)
- intp.bind("global", r.global)
- intp.bind("power", r.power)
- intp.bind("phased", r.phased)
- intp.bind("isettings", r.isettings)
- intp.bind("completion", r.completion)
- intp.bind("history", r.history)
-
- init split '\n' foreach interpret
- }
-
- private def missingWrap(op: => Symbol): Symbol =
- try op
- catch { case _: MissingRequirementError => NoSymbol }
+ intp.bind("$r", r)
+ r bindWithPrefix intp.pathToTerm("$r") // binds all the vals
- private def getCompilerClass(name: String) = missingWrap(definitions.getClass(name))
- private def getCompilerModule(name: String) = missingWrap(definitions.getModule(name))
+ init foreach interpret
+ }
trait LowPriorityInternalInfo {
implicit def apply[T: Manifest] : InternalInfo[T] = new InternalInfo[T](None)
@@ -181,14 +171,41 @@ abstract class Power[G <: Global](
* customizable symbol filter (had to hardcode no-spec to reduce noise)
*/
class InternalInfo[T: Manifest](value: Option[T] = None) {
- def companion = symbol.companionSymbol
- def info = symbol.info
- def module = symbol.moduleClass
- def owner = symbol.owner
- def owners = symbol.ownerChain drop 1
- def symDef = symbol.defString
- def symName = symbol.name
- def tpe = symbol.tpe
+ // Decided it was unwise to have implicit conversions via commonly
+ // used type/symbol methods, because it's too easy to e.g. call
+ // "x.tpe" where x is a Type, and rather than failing you get the
+ // Type representing Types#Type (or Manifest, or whatever.)
+ private def tpe = tpe_
+ private def symbol = symbol_
+ private def name = name_
+
+ // Would love to have stuff like existential types working,
+ // but very unfortunately those manifests just stuff the relevant
+ // information into the toString method. Boo.
+ private def manifestToType(m: Manifest[_]): Type = m match {
+ case x: AnyValManifest[_] =>
+ getCompilerClass("scala." + x).tpe
+ case _ =>
+ val name = m.erasure.getName
+ if (name endsWith "$") getCompilerModule(name dropRight 1).tpe
+ else {
+ val sym = getCompilerClass(name)
+ val args = m.typeArguments
+
+ if (args.isEmpty) sym.tpe
+ else typeRef(NoPrefix, sym, args map manifestToType)
+ }
+ }
+
+ def symbol_ : Symbol = getCompilerClass(erasure.getName)
+ def tpe_ : Type = manifestToType(man)
+ def name_ : Name = symbol.name
+ def companion = symbol.companionSymbol
+ def info = symbol.info
+ def module = symbol.moduleClass
+ def owner = symbol.owner
+ def owners = symbol.ownerChain drop 1
+ def defn = symbol.defString
def declares = members filter (_.owner == symbol)
def inherits = members filterNot (_.owner == symbol)
@@ -197,8 +214,8 @@ abstract class Power[G <: Global](
def overrides = declares filter (_.isOverride)
def inPackage = owners find (x => x.isPackageClass || x.isPackage) getOrElse definitions.RootPackage
- def erasure = manifest[T].erasure
- def symbol = getCompilerClass(erasure.getName)
+ def man = manifest[T]
+ def erasure = man.erasure
def members = tpe.members filterNot (_.name.toString contains "$mc")
def allMembers = tpe.members
def bts = info.baseTypeSeq.toList
@@ -331,10 +348,10 @@ abstract class Power[G <: Global](
implicit lazy val powerSymbolOrdering: Ordering[Symbol] = Ordering[Name] on (_.name)
implicit lazy val powerTypeOrdering: Ordering[Type] = Ordering[Symbol] on (_.typeSymbol)
+ implicit def replInternalInfo[T: Manifest](x: T): InternalInfo[T] = new InternalInfo[T](Some(x))
implicit def replEnhancedStrings(s: String): RichReplString = new RichReplString(s)
implicit def replMultiPrinting[T: Prettifier](xs: TraversableOnce[T]): MultiPrettifierClass[T] =
new MultiPrettifierClass[T](xs.toSeq)
- implicit def replInternalInfo[T: Manifest](x: T): InternalInfo[T] = new InternalInfo[T](Some(x))
implicit def replPrettifier[T] : Prettifier[T] = Prettifier.default[T]
implicit def replTypeApplication(sym: Symbol): RichSymbol = new RichSymbol(sym)
implicit def replInputStream(in: InputStream)(implicit codec: Codec) = new RichInputStream(in)
@@ -343,6 +360,8 @@ abstract class Power[G <: Global](
object Implicits extends Implicits2 { }
trait ReplUtilities {
+ def module[T: Manifest] = getCompilerModule(manifest[T].erasure.getName stripSuffix "$")
+ def clazz[T: Manifest] = getCompilerClass(manifest[T].erasure.getName)
def info[T: Manifest] = InternalInfo[T]
def ?[T: Manifest] = InternalInfo[T]
def url(s: String) = {
@@ -367,8 +386,10 @@ abstract class Power[G <: Global](
}
lazy val rutil: ReplUtilities = new ReplUtilities { }
- lazy val phased: Phased = new Phased with SharesGlobal[G] {
- val global: G = Power.this.global
+
+ lazy val phased: Phased = new Phased with SharesGlobal {
+ type GlobalType = Power.this.global.type
+ final val global: Power.this.global.type = Power.this.global
}
def context(code: String) = analyzer.rootContext(unit(code))
diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala b/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala
index 2c5f5474af..80ccd06c70 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala
@@ -6,15 +6,35 @@
package scala.tools.nsc
package interpreter
-import java.lang.reflect.{ Method => JMethod }
+import java.lang.reflect.{ Method => JMethod, Modifier => JModifier }
-class ReplVals(final val r: ILoop) {
+final class ReplVals(final val r: ILoop) {
+ final val vals = this
final val intp = r.intp
- final val global = r.power.global
+ final val global = intp.global
final val power = r.power
- final val phased = r.power.phased
- final val isettings = r.intp.isettings
+ final val phased = power.phased
+ final val isettings = intp.isettings
final val completion = r.in.completion
final val history = r.in.history
- final val rutil = r.power.rutil
+ final val rutil = power.rutil
+
+ /** Reflectively finds the vals defined in this class. */
+ private def valMethods = this.getClass.getDeclaredMethods.toList filter { m =>
+ (
+ JModifier.isPublic(m.getModifiers())
+ && m.getParameterTypes.isEmpty
+ && !m.getName.contains('$')
+ )
+ }
+
+ /** Binds each val declared here into the repl with explicit singleton types
+ * based on the given prefix.
+ */
+ def bindWithPrefix(prefix: String) {
+ valMethods foreach { m =>
+ repldbg("intp.bind " + (m.getName, prefix + "." + m.getName + ".type", m.invoke(this)))
+ intp.bind(m.getName, prefix + "." + m.getName + ".type", m.invoke(this))
+ }
+ }
}