diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-11-12 19:39:06 -0800 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-11-12 19:39:06 -0800 |
commit | 7bdb3f1b2518db9510d709da1d6ae6542d235b65 (patch) | |
tree | 120b03261bd6f19b31efd1dcc74344b0c71782e8 /src/repl | |
parent | c2a132401f0ef9b6835f76d6b78b319eccd6fa1c (diff) | |
parent | 1d3156ca5dc07470212afa016b3ad17b02c27a99 (diff) | |
download | scala-7bdb3f1b2518db9510d709da1d6ae6542d235b65.tar.gz scala-7bdb3f1b2518db9510d709da1d6ae6542d235b65.tar.bz2 scala-7bdb3f1b2518db9510d709da1d6ae6542d235b65.zip |
Merge pull request #3123 from som-snytt/issue/7747-scrapcodes-fix
SI-7747 Support class based wrappers in REPL
Diffstat (limited to 'src/repl')
-rw-r--r-- | src/repl/scala/tools/nsc/interpreter/IMain.scala | 64 | ||||
-rw-r--r-- | src/repl/scala/tools/nsc/interpreter/Imports.scala | 12 |
2 files changed, 59 insertions, 17 deletions
diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index e4a3416152..0d55423247 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -272,6 +272,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set case s => s } mkString "." ) + def readRootPath(readPath: String) = getModuleIfDefined(readPath) abstract class PhaseDependentOps { def shift[T](op: => T): T @@ -700,7 +701,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set * * Read! Eval! Print! Some of that not yet centralized here. */ - class ReadEvalPrint(lineId: Int) { + class ReadEvalPrint(val lineId: Int) { def this() = this(freshLineId()) val packageName = sessionNames.line + lineId @@ -777,7 +778,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set * following accessPath into the outer one. */ def resolvePathToSymbol(accessPath: String): Symbol = { - val readRoot = getModuleIfDefined(readPath) // the outermost wrapper + val readRoot = readRootPath(readPath) // the outermost wrapper (accessPath split '.').foldLeft(readRoot: Symbol) { case (sym, "") => sym case (sym, name) => exitingTyper(termMember(sym, name)) @@ -848,30 +849,69 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set /** Code to import bound names from previous lines - accessPath is code to * append to objectName to access anything bound by request. */ - val ComputedImports(importsPreamble, importsTrailer, accessPath) = - exitingTyper(importsCode(referencedNames.toSet)) + lazy val ComputedImports(importsPreamble, importsTrailer, accessPath) = + exitingTyper(importsCode(referencedNames.toSet, ObjectSourceCode)) /** the line of code to compute */ def toCompute = line - def fullPath(vname: String) = s"${lineRep.readPath}$accessPath.`$vname`" + /** The path of the value that contains the user code. */ + def fullAccessPath = s"${lineRep.readPath}$accessPath" + + /** The path of the given member of the wrapping instance. */ + def fullPath(vname: String) = s"$fullAccessPath.`$vname`" /** generate the source code for the object that computes this request */ - private object ObjectSourceCode extends IMain.CodeAssembler[MemberHandler] { + abstract class Wrapper extends IMain.CodeAssembler[MemberHandler] { def path = originalPath("$intp") def envLines = { if (!isReplPower) Nil // power mode only for now else List("def %s = %s".format("$line", tquoted(originalLine)), "def %s = Nil".format("$trees")) } - - val preamble = """ - |object %s { + def preamble = s""" + |$preambleHeader |%s%s%s - """.stripMargin.format(lineRep.readName, envLines.map(" " + _ + ";\n").mkString, importsPreamble, indentCode(toCompute)) - val postamble = importsTrailer + "\n}" + """.stripMargin.format(lineRep.readName, envLines.map(" " + _ + ";\n").mkString, + importsPreamble, indentCode(toCompute)) + val generate = (m: MemberHandler) => m extraCodeToEvaluate Request.this + + /** A format string with %s for $read, specifying the wrapper definition. */ + def preambleHeader: String + + /** Like preambleHeader for an import wrapper. */ + def prewrap: String = preambleHeader + "\n" + + /** Like postamble for an import wrapper. */ + def postwrap: String + } + + private class ObjectBasedWrapper extends Wrapper { + def preambleHeader = "object %s {" + + def postamble = importsTrailer + "\n}" + + def postwrap = "}\n" } + private class ClassBasedWrapper extends Wrapper { + def preambleHeader = "class %s extends Serializable {" + + /** Adds an object that instantiates the outer wrapping class. */ + def postamble = s"""$importsTrailer + |} + |object ${lineRep.readName} extends ${lineRep.readName} + |""".stripMargin + + import nme.{ INTERPRETER_IMPORT_WRAPPER => iw } + + /** Adds a val that instantiates the wrapping class. */ + def postwrap = s"}\nval $iw = new $iw\n" + } + + private lazy val ObjectSourceCode: Wrapper = + if (settings.Yreplclassbased) new ClassBasedWrapper else new ObjectBasedWrapper + private object ResultObjectSourceCode extends IMain.CodeAssembler[MemberHandler] { /** We only want to generate this code when the result * is a value which can be referred to as-is. @@ -890,7 +930,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set | ("" """.stripMargin.format( lineRep.evalName, evalResult, lineRep.printName, - executionWrapper, lineRep.readName + accessPath + executionWrapper, fullAccessPath ) val postamble = """ diff --git a/src/repl/scala/tools/nsc/interpreter/Imports.scala b/src/repl/scala/tools/nsc/interpreter/Imports.scala index ff7bfd432c..5244858a62 100644 --- a/src/repl/scala/tools/nsc/interpreter/Imports.scala +++ b/src/repl/scala/tools/nsc/interpreter/Imports.scala @@ -92,7 +92,7 @@ trait Imports { * last one imported is actually usable. */ case class ComputedImports(prepend: String, append: String, access: String) - protected def importsCode(wanted: Set[Name]): ComputedImports = { + protected def importsCode(wanted: Set[Name], wrapper: Request#Wrapper): ComputedImports = { /** Narrow down the list of requests from which imports * should be taken. Removes requests which cannot contribute * useful imports for the specified set of wanted names. @@ -130,13 +130,15 @@ trait Imports { // add code for a new object to hold some imports def addWrapper() { - val impname = nme.INTERPRETER_IMPORT_WRAPPER - code append "object %s {\n".format(impname) - trailingBraces append "}\n" - accessPath append ("." + impname) + import nme.{ INTERPRETER_IMPORT_WRAPPER => iw } + code append (wrapper.prewrap format iw) + trailingBraces append wrapper.postwrap + accessPath append s".$iw" currentImps.clear() } + def maybeWrap(names: Name*) = if (names exists currentImps) addWrapper() + def wrapBeforeAndAfter[T](op: => T): T = { addWrapper() try op finally addWrapper() |