diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/repl/CompilingInterpreter.scala | 62 | ||||
-rw-r--r-- | src/dotty/tools/dotc/repl/Interpreter.scala | 11 | ||||
-rw-r--r-- | src/dotty/tools/dotc/repl/InterpreterLoop.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/repl/REPL.scala | 3 |
4 files changed, 78 insertions, 4 deletions
diff --git a/src/dotty/tools/dotc/repl/CompilingInterpreter.scala b/src/dotty/tools/dotc/repl/CompilingInterpreter.scala index 7b8ba698a..b6a3e388e 100644 --- a/src/dotty/tools/dotc/repl/CompilingInterpreter.scala +++ b/src/dotty/tools/dotc/repl/CompilingInterpreter.scala @@ -228,6 +228,65 @@ class CompilingInterpreter(out: PrintWriter, ictx: Context) extends Compiler wit } } + private def loadAndSetValue(objectName: String, value: AnyRef) = { + /** This terrible string is the wrapped class's full name inside the + * classloader: + * lineX$object$$iw$$iw$list$object + */ + val objName: String = List( + currentLineName + INTERPRETER_WRAPPER_SUFFIX, + INTERPRETER_IMPORT_WRAPPER, + INTERPRETER_IMPORT_WRAPPER, + objectName + ).mkString("$") + + try { + val resObj: Class[_] = Class.forName(objName, true, classLoader) + val setMethod = resObj.getDeclaredMethods.find(_.getName == "set") + + setMethod.fold(false) { method => + method.invoke(resObj, value) == null + } + } catch { + case NonFatal(_) => + // Unable to set value on object due to exception during reflection + false + } + } + + /** This bind is implemented by creating an object with a set method and a + * field `value`. The value is then set via Java reflection. + * + * Example: We want to bind a value `List(1,2,3)` to identifier `list` from + * sbt. The bind method accomplishes this by creating the following: + * {{{ + * object ContainerObjectWithUniqueID { + * var value: List[Int] = _ + * def set(x: Any) = value = x.asInstanceOf[List[Int]] + * } + * val list = ContainerObjectWithUniqueID.value + * }}} + * + * Between the object being created and the value being assigned, the value + * inside the object is set via reflection. + */ + override def bind(id: String, boundType: String, value: AnyRef)(implicit ctx: Context): Interpreter.Result = + interpret( + """ + |object %s { + | var value: %s = _ + | def set(x: Any) = value = x.asInstanceOf[%s] + |} + """.stripMargin.format(id + INTERPRETER_WRAPPER_SUFFIX, boundType, boundType) + ) match { + case Interpreter.Success if loadAndSetValue(id + INTERPRETER_WRAPPER_SUFFIX, value) => + val line = "val %s = %s.value".format(id, id + INTERPRETER_WRAPPER_SUFFIX) + interpret(line) + case Interpreter.Error | Interpreter.Incomplete => + out.println("Set failed in bind(%s, %s, %s)".format(id, boundType, value)) + Interpreter.Error + } + /** Trait collecting info about one of the statements of an interpreter request */ private trait StatementInfo { /** The statement */ @@ -738,6 +797,9 @@ class CompilingInterpreter(out: PrintWriter, ictx: Context) extends Compiler wit INTERPRETER_LINE_PREFIX + num } + private def currentLineName = + INTERPRETER_LINE_PREFIX + (nextLineNo - 1) + /** next result variable number to use */ private var nextVarNameNo = 0 diff --git a/src/dotty/tools/dotc/repl/Interpreter.scala b/src/dotty/tools/dotc/repl/Interpreter.scala index 6a292dfe2..e11fbf5cc 100644 --- a/src/dotty/tools/dotc/repl/Interpreter.scala +++ b/src/dotty/tools/dotc/repl/Interpreter.scala @@ -25,12 +25,15 @@ object Interpreter { trait Interpreter { import Interpreter._ - /** Interpret one line of input. All feedback, including parse errors - * and evaluation results, are printed via the context's reporter. - * reporter. Values defined are available for future interpreted strings. - */ + /** Interpret one line of input. All feedback, including parse errors and + * evaluation results, are printed via the context's reporter. Values + * defined are available for future interpreted strings. + */ def interpret(line: String)(implicit ctx: Context): Result + /** Tries to bind an id to a value, returns the outcome of trying to bind */ + def bind(id: String, boundType: String, value: AnyRef)(implicit ctx: Context): Result + /** Suppress output during evaluation of `operation`. */ def beQuietDuring[T](operation: => T): T diff --git a/src/dotty/tools/dotc/repl/InterpreterLoop.scala b/src/dotty/tools/dotc/repl/InterpreterLoop.scala index 95197f27f..7e5dcc7f1 100644 --- a/src/dotty/tools/dotc/repl/InterpreterLoop.scala +++ b/src/dotty/tools/dotc/repl/InterpreterLoop.scala @@ -170,6 +170,11 @@ class InterpreterLoop(compiler: Compiler, config: REPL.Config)(implicit ctx: Con interpreter.beQuietDuring(interpreter.interpret(cmd)) } + def silentlyBind(values: Array[(String, Any)]): Unit = values.foreach { case (id, value) => + interpreter.beQuietDuring( + interpreter.bind(id, value.asInstanceOf[AnyRef].getClass.getName, value.asInstanceOf[AnyRef])) + } + /** Interpret expressions starting with the first line. * Read lines until a complete compilation unit is available * or until a syntax error has been seen. If a full unit is @@ -201,6 +206,7 @@ class InterpreterLoop(compiler: Compiler, config: REPL.Config)(implicit ctx: Con if (!ctx.reporter.hasErrors) { // if there are already errors, no sense to continue printWelcome() silentlyRun(config.initialCommands) + silentlyBind(config.boundValues) repl(in.readLine(prompt)) silentlyRun(config.cleanupCommands) } diff --git a/src/dotty/tools/dotc/repl/REPL.scala b/src/dotty/tools/dotc/repl/REPL.scala index ae8f0b621..6fda355b5 100644 --- a/src/dotty/tools/dotc/repl/REPL.scala +++ b/src/dotty/tools/dotc/repl/REPL.scala @@ -65,6 +65,9 @@ object REPL { */ val cleanupCommands: List[String] = Nil + /** We also allow binding initial values */ + val boundValues: Array[(String, Any)] = Array.empty[(String, Any)] + /** The default input reader */ def input(in: Interpreter)(implicit ctx: Context): InteractiveReader = { val emacsShell = System.getProperty("env.emacs", "") != "" |