summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/interpreter/IMain.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-05-31 05:08:25 +0000
committerPaul Phillips <paulp@improving.org>2011-05-31 05:08:25 +0000
commitedad717cc1934d80dc0b6a9af528eed8ef4b30b6 (patch)
treeabd8506f32326d513177569192c0ae5d546cae8a /src/compiler/scala/tools/nsc/interpreter/IMain.scala
parent35f7c2bde563b501e9661aace1e1610990b51544 (diff)
downloadscala-edad717cc1934d80dc0b6a9af528eed8ef4b30b6.tar.gz
scala-edad717cc1934d80dc0b6a9af528eed8ef4b30b6.tar.bz2
scala-edad717cc1934d80dc0b6a9af528eed8ef4b30b6.zip
Working on the finer points of the Total Repl E...
Working on the finer points of the Total Repl Experience. Some of what is in this patch: -- Instantaneous repl startup. Closes #4561. -- SIGINT handler installed last. If you've been annoyed at the repl being difficult to interrupt during its initialization, this one is especially for you. -- Started abstracting out some bits which would go into an API and reconfiguring the repl in those terms. For a good time, call S-C-A-L-A -Dscala.repl.power. No review.
Diffstat (limited to 'src/compiler/scala/tools/nsc/interpreter/IMain.scala')
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala170
1 files changed, 23 insertions, 147 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index 2594df90d1..803ef0225a 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -12,10 +12,9 @@ import java.lang.reflect
import java.net.URL
import util._
import io.VirtualDirectory
-import reporters.{ ConsoleReporter, Reporter }
+import reporters._
import symtab.Flags
import scala.reflect.internal.Names
-import scala.tools.nsc.interpreter.{ Results => IR }
import scala.tools.util.PathResolver
import scala.tools.nsc.util.{ ScalaClassLoader, Exceptional }
import ScalaClassLoader.URLClassLoader
@@ -91,7 +90,7 @@ class IMain(val settings: Settings, protected val out: PrintWriter) extends Impo
}
/** reporter */
- lazy val reporter: ConsoleReporter = new IMain.ReplReporter(this)
+ lazy val reporter: ReplReporter = new ReplReporter(this)
import reporter.{ printMessage, withoutTruncating }
// not sure if we have some motivation to print directly to console
@@ -110,55 +109,35 @@ class IMain(val settings: Settings, protected val out: PrintWriter) extends Impo
private var _initializeComplete = false
def isInitializeComplete = _initializeComplete
- private def _initialize(): Boolean = {
- val source = """
- |class $repl_$init {
- | scala.collection.immutable.List(1) map (_ + 1)
- |}
- |""".stripMargin
-
- val result = try {
- new _compiler.Run() compileSources List(new BatchSourceFile("<init>", source))
- if (isReplDebug || settings.debug.value) {
- // Can't use printMessage here, it deadlocks
- Console.println("Repl compiler initialized.")
- }
- // addImports(defaultImports: _*)
+ private def _initSources = List(new BatchSourceFile("<init>", "class $repl_$init { }"))
+ private def _initialize() = {
+ try {
+ new _compiler.Run() compileSources _initSources
+ _initializeComplete = true
true
}
- catch {
- case x: AbstractMethodError =>
- printMessage("""
- |Failed to initialize compiler: abstract method error.
- |This is most often remedied by a full clean and recompile.
- |""".stripMargin
- )
- x.printStackTrace()
- false
- case x: MissingRequirementError => printMessage("""
- |Failed to initialize compiler: %s not found.
- |** Note that as of 2.8 scala does not assume use of the java classpath.
- |** For the old behavior pass -usejavacp to scala, or if using a Settings
- |** object programatically, settings.usejavacp.value = true.""".stripMargin.format(x.req)
- )
- false
- }
-
- try result
- finally _initializeComplete = result
+ catch AbstractOrMissingHandler()
}
// set up initialization future
private var _isInitialized: () => Boolean = null
- def initialize() = synchronized {
+ // argument is a thunk to execute after init is done
+ def initialize(postInitSignal: => Unit): Unit = synchronized {
if (_isInitialized == null)
- _isInitialized = scala.concurrent.ops future _initialize()
+ _isInitialized = scala.concurrent.ops future {
+ val result = _initialize()
+ postInitSignal
+ result
+ }
}
/** the public, go through the future compiler */
lazy val global: Global = {
- initialize()
-
+ // If init hasn't been called yet you're on your own.
+ if (_isInitialized == null) {
+ repldbg("Warning: compiler accessed before init set up. Assuming no postInit code.")
+ initialize(())
+ }
// blocks until it is ; false means catastrophic failure
if (_isInitialized()) _compiler
else null
@@ -382,26 +361,6 @@ class IMain(val settings: Settings, protected val out: PrintWriter) extends Impo
}
}
- /** Parse a line into a sequence of trees. Returns None if the input is incomplete. */
- def parse(line: String): Option[List[Tree]] = {
- var justNeedsMore = false
- reporter.withIncompleteHandler((pos,msg) => {justNeedsMore = true}) {
- // simple parse: just parse it, nothing else
- def simpleParse(code: String): List[Tree] = {
- reporter.reset()
- val unit = new CompilationUnit(new BatchSourceFile("<console>", code))
- val scanner = new syntaxAnalyzer.UnitParser(unit)
-
- scanner.templateStatSeq(false)._2
- }
- val trees = simpleParse(line)
-
- if (reporter.hasErrors) Some(Nil) // the result did not parse, so stop
- else if (justNeedsMore) None
- else Some(trees)
- }
- }
-
private[nsc] def replwarn(msg: => String): Unit =
if (!settings.nowarnings.value)
printMessage(msg)
@@ -683,12 +642,6 @@ class IMain(val settings: Settings, protected val out: PrintWriter) extends Impo
lineAfterTyper(sym.info member newTermName(name))
}
}
-
- // def compileAndTypeExpr(expr: String): Option[Typer] = {
- // class TyperRun extends Run {
- // override def stopPhase(name: String) = name == "superaccessors"
- // }
- // }
private var lastRun: Run = _
private def evalMethod(name: String) = {
val methods = evalClass.getMethods filter (_.getName == name)
@@ -974,76 +927,11 @@ class IMain(val settings: Settings, protected val out: PrintWriter) extends Impo
}
}
- // Since people will be giving us ":t def foo = 5" even though that is not an
- // expression, we have a means of typing declarations too.
- private def typeOfDeclaration(code: String): Option[Type] = {
- repldbg("typeOfDeclaration(" + code + ")")
- val obname = freshInternalVarName()
-
- interpret("object " + obname + " {\n" + code + "\n}\n", true) match {
- case IR.Success =>
- val sym = symbolOfTerm(obname)
- if (sym == NoSymbol) None else {
- // TODO: bitmap$n is not marked synthetic.
- val decls = sym.tpe.decls.toList filterNot (x => x.isConstructor || x.isPrivate || (x.name.toString contains "$"))
- repldbg("decls: " + decls)
- decls.lastOption map (decl => typeCleanser(sym, decl.name))
- }
- case _ =>
- None
- }
- }
-
- // XXX literals.
- // 1) Identifiers defined in the repl.
- // 2) A path loadable via getModule.
- // 3) Try interpreting it as an expression.
- private var typeOfExpressionDepth = 0
+ private object exprTyper extends { val repl: IMain.this.type = imain } with ExprTyper { }
+ def parse(line: String): Option[List[Tree]] = exprTyper.parse(line)
def typeOfExpression(expr: String, silent: Boolean = true): Option[Type] = {
- repldbg("typeOfExpression(" + expr + ")")
- if (typeOfExpressionDepth > 2) {
- repldbg("Terminating typeOfExpression recursion for expression: " + expr)
- return None
- }
-
- def asQualifiedImport = {
- val name = expr.takeWhile(_ != '.')
- importedTermNamed(name) flatMap { sym =>
- typeOfExpression(sym.fullName + expr.drop(name.length), true)
- }
- }
- def asModule = safeModule(expr) map (_.tpe)
- def asExpr = {
- val lhs = freshInternalVarName()
- val line = "lazy val " + lhs + " =\n" + expr
-
- interpret(line, true) match {
- case IR.Success => typeOfExpression(lhs, true)
- case _ => None
- }
- }
- def evaluate() = {
- typeOfExpressionDepth += 1
- try typeOfTerm(expr) orElse asModule orElse asExpr orElse asQualifiedImport
- finally typeOfExpressionDepth -= 1
- }
-
- // Don't presently have a good way to suppress undesirable success output
- // while letting errors through, so it is first trying it silently: if there
- // is an error, and errors are desired, then it re-evaluates non-silently
- // to induce the error message.
- beSilentDuring(evaluate()) orElse beSilentDuring(typeOfDeclaration(expr)) orElse {
- if (!silent)
- evaluate()
-
- None
- }
+ exprTyper.typeOfExpression(expr, silent)
}
- // def compileAndTypeExpr(expr: String): Option[Typer] = {
- // class TyperRun extends Run {
- // override def stopPhase(name: String) = name == "superaccessors"
- // }
- // }
protected def onlyTerms(xs: List[Name]) = xs collect { case x: TermName => x }
protected def onlyTypes(xs: List[Name]) = xs collect { case x: TypeName => x }
@@ -1165,16 +1053,4 @@ object IMain {
}
}
}
-
- class ReplReporter(intp: IMain) extends ConsoleReporter(intp.settings, null, new ReplStrippingWriter(intp)) {
- override def printMessage(msg: String) {
- // Avoiding deadlock when the compiler starts logging before
- // the lazy val is done.
- if (intp.isInitializeComplete) {
- if (intp.totalSilence) ()
- else super.printMessage(msg)
- }
- else Console.println(msg)
- }
- }
}