rework REPL support

allow bindings, which requires specifying the parent class loader
same code can be used for both 'console' and 'console-project' now
provide interface through main/Console
This commit is contained in:
Mark Harrah 2010-09-04 08:16:22 -04:00
parent 37594904f9
commit 9bcd68d28c
4 changed files with 91 additions and 17 deletions

View File

@ -31,12 +31,15 @@ class AnalyzingCompiler(val scalaInstance: ScalaInstance, val manager: Component
val arguments = (new CompilerArguments(scalaInstance, cp))(sources, classpath, outputDirectory, options)
call("xsbt.ScaladocInterface", log) (classOf[Array[String]], classOf[Int], classOf[xLogger]) (arguments.toArray[String] : Array[String], maximumErrors: java.lang.Integer, log)
}
def console(classpath: Seq[File], options: Seq[String], initialCommands: String, log: Logger): Unit =
def console(classpath: Seq[File], options: Seq[String], initialCommands: String, log: Logger)(loader: Option[ClassLoader] = None, bindings: Seq[(String, Any)] = Nil): Unit =
{
val arguments = new CompilerArguments(scalaInstance, cp)
val classpathString = CompilerArguments.absString(arguments.finishClasspath(classpath))
val bootClasspath = if(cp.autoBoot) arguments.createBootClasspath else ""
call("xsbt.ConsoleInterface", log) (classOf[Array[String]], classOf[String], classOf[String], classOf[String], classOf[xLogger]) (options.toArray[String]: Array[String], bootClasspath, classpathString, initialCommands, log)
val (names, values) = bindings.unzip
call("xsbt.ConsoleInterface", log)(
classOf[Array[String]], classOf[String], classOf[String], classOf[String], classOf[ClassLoader], classOf[Array[String]], classOf[Array[Any]], classOf[xLogger])(
options.toArray[String]: Array[String], bootClasspath, classpathString, initialCommands, loader.orNull, names.toArray[String], values.toArray[Any], log)
}
def force(log: Logger): Unit = getInterfaceJar(log)
private def call(interfaceClassName: String, log: Logger)(argTypes: Class[_]*)(args: AnyRef*)

View File

@ -269,6 +269,9 @@ trait ShowTypeParameters
}
}
// this class is a hack to resolve some diverging implicit errors.
// I'm pretty sure the cause is the Show[Seq[T]] dominating Show[X] issue.
// It could probably be reduced a bit if that is the case (below was trial and error)
object DefaultShowAPI extends ShowBase with ShowBasicTypes with ShowValueParameters
{
def apply(d: Definition) = ShowAPI.show(d)

View File

@ -4,26 +4,51 @@
package xsbt
import xsbti.Logger
import scala.tools.nsc.{GenericRunnerCommand,InterpreterLoop}
import scala.tools.nsc.{GenericRunnerCommand, Interpreter, InterpreterLoop, ObjectRunner, Settings}
import scala.tools.nsc.interpreter.InteractiveReader
import scala.tools.nsc.reporters.Reporter
import scala.tools.nsc.util.ClassPath
class ConsoleInterface
{
def run(args: Array[String], bootClasspathString: String, classpathString: String, initialCommands: String, log: Logger)
def run(args: Array[String], bootClasspathString: String, classpathString: String, initialCommands: String, loader: ClassLoader, bindNames: Array[String], bindValues: Array[Any], log: Logger)
{
val settings = MakeSettings(args.toList, log)
val options = args.toList
lazy val interpreterSettings = xsbt.MakeSettings(options, log)
val compilerSettings = xsbt.MakeSettings(options, log)
if(!bootClasspathString.isEmpty)
settings.bootclasspath.value = bootClasspathString
settings.classpath.value = classpathString
compilerSettings.bootclasspath.value = bootClasspathString
compilerSettings.classpath.value = classpathString
log.info(Message("Starting scala interpreter..."))
log.debug(Message(" Classpath: " + settings.classpath.value))
log.debug(Message(" Boot classpath: " + compilerSettings.bootclasspath.value))
log.debug(Message(" Classpath: " + compilerSettings.classpath.value))
log.info(Message(""))
val loop = new InterpreterLoop {
override def createInterpreter() = {
super.createInterpreter()
if(!initialCommands.isEmpty) interpreter.interpret(initialCommands)
if(loader ne null)
{
in = InteractiveReader.createDefault()
interpreter = new Interpreter(settings)
{
override protected def parentClassLoader = if(loader eq null) super.parentClassLoader else loader
override protected def newCompiler(settings: Settings, reporter: Reporter) = super.newCompiler(compilerSettings, reporter)
}
interpreter.setContextClassLoader()
}
else
super.createInterpreter()
for( (id, value) <- bindNames zip bindValues)
interpreter.bind(id, value.asInstanceOf[AnyRef].getClass.getName, value)
if(!initialCommands.isEmpty)
interpreter.interpret(initialCommands)
}
}
loop.main(settings)
loop.main(if(loader eq null) compilerSettings else interpreterSettings)
}
}
object MakeSettings

View File

@ -1,7 +1,7 @@
/* sbt -- Simple Build Tool
* Copyright 2008, 2009 Mark Harrah
* Copyright 2008, 2009, 2010 Mark Harrah
*/
/*package sbt
package sbt
import java.io.File
import compile.AnalyzingCompiler
@ -9,12 +9,55 @@ import compile.AnalyzingCompiler
final class Console(compiler: AnalyzingCompiler) extends NotNull
{
/** Starts an interactive scala interpreter session with the given classpath.*/
def apply(classpath: Iterable[File], log: Logger): Option[String] =
def apply(classpath: Seq[File], log: Logger): Option[String] =
apply(classpath, Nil, "", log)
def apply(classpath: Iterable[File], options: Seq[String], initialCommands: String, log: Logger): Option[String] =
def apply(classpath: Seq[File], options: Seq[String], initialCommands: String, log: Logger): Option[String] =
apply(classpath, options, initialCommands)(None, Nil)(log)
def apply(classpath: Seq[File], options: Seq[String], loader: ClassLoader, initialCommands: String)(bindings: (String, Any)*)(implicit log: Logger): Option[String] =
apply(classpath, options, initialCommands)(Some(loader), bindings)
def apply(classpath: Seq[File], options: Seq[String], initialCommands: String)(loader: Option[ClassLoader], bindings: Seq[(String, Any)])(implicit log: Logger): Option[String] =
{
def console0 = compiler.console(Path.getFiles(classpath), options, initialCommands, log)
def console0 = compiler.console(classpath, options, initialCommands, log)(loader, bindings)
JLine.withJLine( Run.executeTrapExit(console0, log) )
}
}*/
}
object Console
{
val SbtInitial = "import sbt._; import Process._; import current._"
def apply(conf: build.Compile)(implicit log: Logger): Console = new Console( compiler(conf) )
def compiler(conf: build.Compile)(implicit log: Logger): AnalyzingCompiler =
{
val componentManager = new ComponentManager(conf.launcher.globalLock, conf.configuration.provider.components, log)
new AnalyzingCompiler(conf.instance, componentManager, log)
}
def sbtDefault(conf: build.Compile, value: Any)(implicit log: Logger)
{
val c = new Console(compiler(conf))
val loader = value.asInstanceOf[AnyRef].getClass.getClassLoader
c.apply(conf.compileClasspath, Nil, loader, SbtInitial)("current" -> value)
}
}
final class Scaladoc(maximumErrors: Int, compiler: AnalyzingCompiler)
{
final def apply(label: String, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String])(implicit log: Logger)
{
log.info(actionStartMessage(label))
if(sources.isEmpty)
log.info(actionNothingToDoMessage)
else
{
IO.createDirectory(outputDirectory)
compiler.doc(sources, classpath, outputDirectory, options, maximumErrors, log)
log.info(actionSuccessfulMessage)
}
}
def actionStartMessage(label: String) = "Generating API documentation for " + label + " sources..."
val actionNothingToDoMessage = "No sources specified."
val actionSuccessfulMessage = "API documentation generation successful."
}