Skip to content

Commit d521895

Browse files
committed
Pulled some more repl code from trunk.
1 parent 2402240 commit d521895

File tree

10 files changed

+228
-130
lines changed

10 files changed

+228
-130
lines changed

src/compiler/scala/tools/nsc/interpreter/ILoop.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
4343
var settings: Settings = _
4444
var intp: IMain = _
4545

46+
override def echoCommandMessage(msg: String): Unit =
47+
intp.reporter.printMessage(msg)
48+
4649
def isAsync = !settings.Yreplsync.value
47-
lazy val power = {
48-
val g = intp.global
49-
Power[g.type](this, g)
50-
}
50+
lazy val power = Power(this)
5151

5252
// TODO
5353
// object opt extends AestheticSettings
@@ -622,6 +622,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
622622
def enablePowerMode(isDuringInit: Boolean) = {
623623
replProps.power setValue true
624624
power.unleash()
625+
intp.beSilentDuring(phaseCommand("typer"))
625626
if (isDuringInit) asyncMessage(power.banner)
626627
else echo(power.banner)
627628
}

src/compiler/scala/tools/nsc/interpreter/IMain.scala

Lines changed: 99 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,10 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
154154
@deprecated("Use `global` for access to the compiler instance.", "2.9.0")
155155
lazy val compiler: global.type = global
156156

157-
import global._
157+
import global.{ treeWrapper => _, _ }
158158
import definitions.{ ScalaPackage, JavaLangPackage, PredefModule, RootClass }
159159

160-
private def privateTreeOps(t: Tree): List[Tree] = {
160+
private implicit def privateTreeOps(t: Tree): List[Tree] = {
161161
(new Traversable[Tree] {
162162
def foreach[U](f: Tree => U): Unit = t foreach { x => f(x) ; () }
163163
}).toList
@@ -267,7 +267,10 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
267267
definitions.
268268
*/
269269
private var _classLoader: AbstractFileClassLoader = null
270-
def resetClassLoader() = _classLoader = makeClassLoader()
270+
def resetClassLoader() = {
271+
repldbg("Setting new classloader: was " + _classLoader)
272+
_classLoader = makeClassLoader()
273+
}
271274
def classLoader: AbstractFileClassLoader = {
272275
if (_classLoader == null)
273276
resetClassLoader()
@@ -287,8 +290,10 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
287290
override protected def findAbstractFile(name: String): AbstractFile = {
288291
super.findAbstractFile(name) match {
289292
// deadlocks on startup if we try to translate names too early
290-
case null if isInitializeComplete => generatedName(name) map (x => super.findAbstractFile(x)) orNull
291-
case file => file
293+
case null if isInitializeComplete =>
294+
generatedName(name) map (x => super.findAbstractFile(x)) orNull
295+
case file =>
296+
file
292297
}
293298
}
294299
}
@@ -301,8 +306,9 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
301306

302307
/** Given a simple repl-defined name, returns the real name of
303308
* the class representing it, e.g. for "Bippy" it may return
304-
*
309+
* {{{
305310
* $line19.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$Bippy
311+
* }}}
306312
*/
307313
def generatedName(simpleName: String): Option[String] = {
308314
if (simpleName endsWith "$") optFlatName(simpleName.init) map (_ + "$")
@@ -324,7 +330,7 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
324330
private def mostRecentlyHandledTree: Option[Tree] = {
325331
prevRequests.reverse foreach { req =>
326332
req.handlers.reverse foreach {
327-
case x: MemberDefHandler if x.definesValue && !isInternalVarName(x.name) => return Some(x.member)
333+
case x: MemberDefHandler if x.definesValue && !isInternalVarName(x.name) => return Some(x.member)
328334
case _ => ()
329335
}
330336
}
@@ -347,6 +353,7 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
347353
repldbg("Redefining term '%s'\n %s -> %s".format(name, t1, t2))
348354
}
349355
}
356+
350357
def recordRequest(req: Request) {
351358
if (req == null || referencedNameMap == null)
352359
return
@@ -378,9 +385,10 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
378385
}
379386
}
380387

381-
private[nsc] def replwarn(msg: => String): Unit =
388+
private[nsc] def replwarn(msg: => String) {
382389
if (!settings.nowarnings.value)
383390
printMessage(msg)
391+
}
384392

385393
def isParseable(line: String): Boolean = {
386394
beSilentDuring {
@@ -425,6 +433,7 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
425433
case idx => s take idx
426434
}) mkString "\n"
427435
}
436+
428437
private def safePos(t: Tree, alt: Int): Int =
429438
try t.pos.startOrPoint
430439
catch { case _: UnsupportedOperationException => alt }
@@ -448,7 +457,7 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
448457
}
449458
repltrace(
450459
trees map { t =>
451-
privateTreeOps(t) map { t0 => t0.getClass + " at " + safePos(t0, -1) + "\n" }
460+
t map { t0 => t0.getClass + " at " + safePos(t0, -1) + "\n" }
452461
} mkString
453462
)
454463
// If the last tree is a bare expression, pinpoint where it begins using the
@@ -467,15 +476,20 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
467476
else {
468477
// The position of the last tree
469478
val lastpos0 = earliestPosition(trees.last)
470-
// Oh boy, the parser throws away parens so "(2+2)" is mispositioned.
471-
// So until we can fix the parser we'll have to go trawling.
472-
val adjustment = ((content take lastpos0).reverse takeWhile { ch =>
473-
ch.isWhitespace || ch == '(' || ch == ')'
474-
}).length
479+
// Oh boy, the parser throws away parens so "(2+2)" is mispositioned,
480+
// with increasingly hard to decipher positions as we move on to "() => 5",
481+
// (x: Int) => x + 1, and more. So I abandon attempts to finesse and just
482+
// look for semicolons and newlines, which I'm sure is also buggy.
483+
val (raw1, raw2) = content splitAt lastpos0
484+
repldbg("[raw] " + raw1 + " <---> " + raw2)
485+
486+
val adjustment = (raw1.reverse takeWhile (ch => (ch != ';') && (ch != '\n'))).size
475487
val lastpos = lastpos0 - adjustment
476488

477489
// the source code split at the laboriously determined position.
478490
val (l1, l2) = content splitAt lastpos
491+
repldbg("[adj] " + l1 + " <---> " + l2)
492+
479493
val prefix = if (l1.trim == "") "" else l1 + ";\n"
480494
// Note to self: val source needs to have this precise structure so that
481495
// error messages print the user-submitted part without the "val res0 = " part.
@@ -528,18 +542,14 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
528542
def interpret(line: String, synthetic: Boolean): IR.Result = {
529543
def loadAndRunReq(req: Request) = {
530544
val (result, succeeded) = req.loadAndRun
545+
531546
/** To our displeasure, ConsoleReporter offers only printMessage,
532547
* which tacks a newline on the end. Since that breaks all the
533548
* output checking, we have to take one off to balance.
534549
*/
535-
def show() = {
536-
if (result == "") ()
537-
else printMessage(result stripSuffix "\n")
538-
}
539-
540550
if (succeeded) {
541-
if (printResults)
542-
show()
551+
if (printResults && result != "")
552+
printMessage(result stripSuffix "\n")
543553
else if (isReplDebug) // show quiet-mode activity
544554
printMessage(result.trim.lines map ("[quiet] " + _) mkString "\n")
545555

@@ -550,7 +560,7 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
550560
}
551561
else {
552562
// don't truncate stack traces
553-
withoutTruncating(show())
563+
withoutTruncating(printMessage(result))
554564
IR.Error
555565
}
556566
}
@@ -583,11 +593,19 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
583593
|}
584594
""".stripMargin.format(bindRep.evalName, boundType, boundType)
585595
)
586-
bindRep.callOpt("set", value) match {
587-
case Some(_) => interpret("val %s = %s.value".format(name, bindRep.evalPath))
588-
case _ => repldbg("Set failed in bind(%s, %s, %s)".format(name, boundType, value)) ; IR.Error
596+
bindRep.callEither("set", value) match {
597+
case Left(ex) =>
598+
repldbg("Set failed in bind(%s, %s, %s)".format(name, boundType, value))
599+
repldbg(util.stackTraceString(ex))
600+
IR.Error
601+
602+
case Right(_) =>
603+
val line = "val %s = %s.value".format(name, bindRep.evalPath)
604+
repldbg("Interpreting: " + line)
605+
interpret(line)
589606
}
590607
}
608+
591609
def rebind(p: NamedParam): IR.Result = {
592610
val name = p.name
593611
val oldType = typeOfTerm(name) getOrElse { return IR.Error }
@@ -683,15 +701,30 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
683701
def call(name: String, args: Any*): AnyRef =
684702
evalMethod(name).invoke(evalClass, args.map(_.asInstanceOf[AnyRef]): _*)
685703

704+
def callEither(name: String, args: Any*): Either[Throwable, AnyRef] =
705+
try Right(call(name, args: _*))
706+
catch { case ex: Throwable => Left(ex) }
707+
686708
def callOpt(name: String, args: Any*): Option[AnyRef] =
687709
try Some(call(name, args: _*))
688-
catch { case ex: Exception => bindError(ex) ; None }
710+
catch { case ex: Throwable => bindError(ex) ; None }
711+
712+
class EvalException(msg: String, cause: Throwable) extends RuntimeException(msg, cause) { }
689713

690-
private def load(s: String): Class[_] =
691-
(classLoader tryToInitializeClass s) getOrElse sys.error("Failed to load expected class: '" + s + "'")
714+
private def evalError(path: String, ex: Throwable) =
715+
throw new EvalException("Failed to load '" + path + "': " + ex.getMessage, ex)
716+
717+
private def load(path: String): Class[_] = {
718+
try Class.forName(path, true, classLoader)
719+
catch { case ex => evalError(path, unwrap(ex)) }
720+
}
692721

722+
var evalCaught: Option[Throwable] = None
693723
lazy val evalClass = load(evalPath)
694-
lazy val evalValue = callOpt(evalName)
724+
lazy val evalValue = callEither(evalName) match {
725+
case Left(ex) => evalCaught = Some(ex) ; None
726+
case Right(result) => Some(result)
727+
}
695728

696729
def compile(source: String): Boolean = compileAndSaveRun("<console>", source)
697730
def lineAfterTyper[T](op: => T): T = {
@@ -726,7 +759,7 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
726759
/** One line of code submitted by the user for interpretation */
727760
// private
728761
class Request(val line: String, val trees: List[Tree]) {
729-
val lineRep = new ReadEvalPrint()
762+
val lineRep = new ReadEvalPrint()
730763
import lineRep.lineAfterTyper
731764

732765
private var _originalLine: String = null
@@ -922,6 +955,7 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
922955
try Some(definitions.getClass(newTypeName(name)))
923956
catch { case _: MissingRequirementError => None }
924957
}
958+
925959
def safeModule(name: String): Option[Symbol] = {
926960
try Some(definitions.getModule(newTermName(name)))
927961
catch { case _: MissingRequirementError => None }
@@ -942,6 +976,7 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
942976
case nme.ROOTPKG => Some(definitions.RootClass.tpe)
943977
case name => requestForName(name) flatMap (_.compilerTypeOf get name)
944978
}
979+
945980
def symbolOfTerm(id: String): Symbol =
946981
requestForIdent(id) flatMap (_.definedSymbols get newTermName(id)) getOrElse NoSymbol
947982

@@ -981,6 +1016,39 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
9811016
def definedTypes = onlyTypes(allDefinedNames)
9821017
def definedSymbols = prevRequests.toSet flatMap ((x: Request) => x.definedSymbols.values)
9831018

1019+
private def findName(name: Name) = definedSymbols find (_.name == name)
1020+
1021+
private def missingOpt(op: => Symbol): Option[Symbol] =
1022+
try Some(op)
1023+
catch { case _: MissingRequirementError => None }
1024+
private def missingWrap(op: => Symbol): Symbol =
1025+
try op
1026+
catch { case _: MissingRequirementError => NoSymbol }
1027+
1028+
def optCompilerClass(name: String) = missingOpt(definitions.getClass(name))
1029+
def optCompilerModule(name: String) = missingOpt(definitions.getModule(name))
1030+
def getCompilerClass(name: String) = missingWrap(definitions.getClass(name))
1031+
def getCompilerModule(name: String) = missingWrap(definitions.getModule(name))
1032+
1033+
/** Translate a repl-defined identifier into a Symbol.
1034+
*/
1035+
def apply(name: String): Symbol = {
1036+
val tpname = newTypeName(name)
1037+
(
1038+
findName(tpname)
1039+
orElse findName(tpname.companionName)
1040+
orElse optCompilerClass(name)
1041+
orElse optCompilerModule(name)
1042+
getOrElse NoSymbol
1043+
)
1044+
}
1045+
def types(name: String): Symbol = {
1046+
findName(newTypeName(name)) getOrElse getCompilerClass(name)
1047+
}
1048+
def terms(name: String): Symbol = {
1049+
findName(newTermName(name)) getOrElse getCompilerModule(name)
1050+
}
1051+
9841052
/** the previous requests this interpreter has processed */
9851053
private lazy val prevRequests = mutable.ListBuffer[Request]()
9861054
private lazy val referencedNameMap = mutable.Map[Name, Request]()
@@ -1023,6 +1091,7 @@ class IMain(val settings: Settings, protected val out: JPrintWriter) extends Imp
10231091
parse(code) foreach (ts => ts foreach (t => withoutUnwrapping(repldbg(asCompactString(t)))))
10241092
}
10251093
}
1094+
10261095
// debugging
10271096
def debugging[T](msg: String)(res: T) = {
10281097
repldbg(msg + " " + res)

src/compiler/scala/tools/nsc/interpreter/LoopCommands.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ object ProcessResult {
2929
trait LoopCommands {
3030
protected def out: JPrintWriter
3131

32+
// So outputs can be suppressed.
33+
def echoCommandMessage(msg: String): Unit = out println msg
34+
3235
// a single interpreter command
3336
abstract class LoopCommand(val name: String, val help: String) extends (String => Result) {
3437
private var _longHelp: String = null
@@ -95,7 +98,7 @@ trait LoopCommands {
9598
// to print something to the console, so we accomodate Unit and String returns.
9699
implicit def resultFromUnit(x: Unit): Result = default
97100
implicit def resultFromString(msg: String): Result = {
98-
out println msg
101+
echoCommandMessage(msg)
99102
default
100103
}
101104
}

0 commit comments

Comments
 (0)