diff options
author | Paul Phillips <paulp@improving.org> | 2010-02-21 05:01:55 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2010-02-21 05:01:55 +0000 |
commit | 18aa7f0c8075ed543c108d99eeb10a974c3d0296 (patch) | |
tree | 0604200b3470410cdeaf75c2bc2751d7c189e669 | |
parent | 3bc73c1e1a02dc225f8723591e6d4427172478be (diff) | |
download | scala-18aa7f0c8075ed543c108d99eeb10a974c3d0296.tar.gz scala-18aa7f0c8075ed543c108d99eeb10a974c3d0296.tar.bz2 scala-18aa7f0c8075ed543c108d99eeb10a974c3d0296.zip |
Some repl cleanups and debugging conveniences.
-rw-r--r-- | src/compiler/scala/tools/nsc/Interpreter.scala | 82 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Settings.scala | 1 | ||||
-rw-r--r-- | src/library/scala/runtime/ScalaRunTime.scala | 27 | ||||
-rw-r--r-- | test/files/jvm/interpreter.check | 6 | ||||
-rw-r--r-- | test/files/run/constrained-types.check | 2 |
5 files changed, 64 insertions, 54 deletions
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala index 6e06518a7a..71a210de3f 100644 --- a/src/compiler/scala/tools/nsc/Interpreter.scala +++ b/src/compiler/scala/tools/nsc/Interpreter.scala @@ -98,13 +98,12 @@ class Interpreter(val settings: Settings, out: PrintWriter) { private val _compiler: Global = newCompiler(settings, reporter) private def _initialize(): Boolean = { val source = """ - | // this is assembled to force the loading of approximately the - | // classes which will be loaded on the first expression anyway. - | class $repl_$init { - | val x = "abc".reverse.length + (5 max 5) - | val nl = if (x.toString contains '\n') "\n" else "" - | scala.runtime.ScalaRunTime.stringOf(nl) - | } + |// this is assembled to force the loading of approximately the + |// classes which will be loaded on the first expression anyway. + |class $repl_$init { + | val x = "abc".reverse.length + (5 max 5) + | scala.runtime.ScalaRunTime.stringOf(x) + |} |""".stripMargin val run = new _compiler.Run() @@ -458,7 +457,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { for (imv <- x.boundNames) { if (currentImps contains imv) addWrapper() - code append ("import " + (req fullPath imv)) + code append ("import %s\n" format (req fullPath imv)) currentImps += imv } } @@ -491,7 +490,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { /** For :power - create trees and type aliases from code snippets. */ def mkContext(code: String = "") = compiler.analyzer.rootContext(mkUnit(code)) - def mkAlias(name: String, what: String) = interpret("type " + name + " = " + what) + def mkAlias(name: String, what: String) = interpret("type %s = %s".format(name, what)) def mkSourceFile(code: String) = new BatchSourceFile("<console>", code) def mkUnit(code: String) = new CompilationUnit(mkSourceFile(code)) @@ -541,6 +540,12 @@ class Interpreter(val settings: Settings, out: PrintWriter) { compileSources(new BatchSourceFile("<script>", code)) def compileAndSaveRun(label: String, code: String) = { + if (settings.Yrepldebug.value) { + parse(code) match { + case Some(trees) => trees foreach (t => println(compiler.asCompactString(t))) + case _ => println("Parse error:\n\n" + code) + } + } val run = new compiler.Run() run.compileSources(List(new BatchSourceFile(label, code))) run @@ -640,10 +645,10 @@ class Interpreter(val settings: Settings, out: PrintWriter) { val binderName = newBinder() compileString(""" - | object %s { - | var value: %s = _ - | def set(x: Any) = value = x.asInstanceOf[%s] - | } + |object %s { + | var value: %s = _ + | def set(x: Any) = value = x.asInstanceOf[%s] + |} """.stripMargin.format(binderName, boundType, boundType)) val binderObject = loadByName(binderName) @@ -723,19 +728,12 @@ class Interpreter(val settings: Settings, out: PrintWriter) { val isInternal = isGeneratedVarName(vname) && req.typeOfEnc(vname) == "Unit" if (!mods.isPublic || isInternal) return - lazy val extractor = """ - | { - | val s = scala.runtime.ScalaRunTime.stringOf(%s) - | val nl = if (s.contains('\n')) "\n" else "" - | nl + s + "\n" - | } - """.stripMargin.format(req fullPath vname) + lazy val extractor = "scala.runtime.ScalaRunTime.stringOf(%s)".format(req fullPath vname) // if this is a lazy val we avoid evaluating it here val resultString = if (isLazy) codegenln(false, "<lazy>") else extractor val codeToPrint = - """ + "%s: %s = " + %s""" . - format(prettyName, string2code(req.typeOf(vname)), resultString) + """ + "%s: %s = " + %s""".format(prettyName, string2code(req typeOf vname), resultString) code print codeToPrint } @@ -845,7 +843,7 @@ class Interpreter(val settings: Settings, out: PrintWriter) { importsCode(Set.empty ++ usedNames) /** Code to access a variable with the specified name */ - def fullPath(vname: String): String = "%s.`%s`\n".format(objectName + accessPath, vname) + def fullPath(vname: String): String = "%s.`%s`".format(objectName + accessPath, vname) /** Code to access a variable with the specified name */ def fullPath(vname: Name): String = fullPath(vname.toString) @@ -855,10 +853,11 @@ class Interpreter(val settings: Settings, out: PrintWriter) { /** generate the source code for the object that computes this request */ def objectSourceCode: String = stringFrom { code => - val preamble = """object %s { - | %s%s + val preamble = """ + |object %s { + | %s%s """.stripMargin.format(objectName, importsPreamble, indentCode(toCompute)) - val postamble = importsTrailer + "; }" + val postamble = importsTrailer + "\n}" code println preamble handlers foreach { _.extraCodeToEvaluate(this, code) } @@ -874,25 +873,27 @@ class Interpreter(val settings: Settings, out: PrintWriter) { val valueExtractor = handlers.last.generatesValue match { case Some(vname) if typeOf contains vname => """ - | lazy val scala_repl_value = { - | scala_repl_result // make sure that's run - | %s - | }""".stripMargin.format(fullPath(vname)) + |lazy val scala_repl_value = { + | scala_repl_result + | %s + |}""".stripMargin.format(fullPath(vname)) case _ => "" } + // first line evaluates object to make sure constructor is run + // initial "" so later code can uniformly be: + etc val preamble = """ - | object %s { - | %s - | val scala_repl_result: String = { - | %s // evaluate object to make sure constructor is run - | ("" // an initial "" so later code can uniformly be: + etc + |object %s { + | %s + | val scala_repl_result: String = { + | %s + | ("" """.stripMargin.format(resultObjectName, valueExtractor, objectName + accessPath) val postamble = """ - | ) - | } - | } + | ) + | } + |} """.stripMargin code println preamble @@ -1262,12 +1263,15 @@ object Interpreter { def codegenln(leadingPlus: Boolean, xs: String*): String = codegen(leadingPlus, (xs ++ Array("\n")): _*) def codegenln(xs: String*): String = codegenln(true, xs: _*) + def codegen(xs: String*): String = codegen(true, xs: _*) def codegen(leadingPlus: Boolean, xs: String*): String = { val front = if (leadingPlus) "+ " else "" - xs.map("\"" + string2code(_) + "\"").mkString(front, " + ", "") + front + (xs map string2codeQuoted mkString " + ") } + def string2codeQuoted(str: String) = "\"" + string2code(str) + "\"" + /** Convert a string into code that can recreate the string. * This requires replacing all special characters by escape * codes. It does not add the surrounding " marks. */ diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala index 638a755f3e..42d7a50938 100644 --- a/src/compiler/scala/tools/nsc/Settings.scala +++ b/src/compiler/scala/tools/nsc/Settings.scala @@ -905,6 +905,7 @@ trait ScalacSettings { BooleanSetting ("-Ybuild-manager-debug", "Generate debug information for the Refined Build Manager compiler.") val Ytyperdebug = BooleanSetting ("-Ytyper-debug", "Trace all type assignements") val Ypmatdebug = BooleanSetting ("-Ypmat-debug", "Trace all pattern matcher activity.") + val Yrepldebug = BooleanSetting ("-Yrepl-debug", "Trace all repl activity.") val Ypmatnaive = BooleanSetting ("-Ypmat-naive", "Desugar matches as naively as possible..") val Ytailrec = BooleanSetting ("-Ytailrecommend", "Alert methods which would be tail-recursive if private or final.") val Yjenkins = BooleanSetting ("-Yjenkins-hashCodes", "Use jenkins hash algorithm for case class generated hashCodes.") diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index 07da120399..a26d6b09bd 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -187,16 +187,21 @@ object ScalaRunTime { * @return a string representation of <code>arg</code> * */ - def stringOf(arg: Any): String = arg match { - case null => "null" - // Node extends NodeSeq extends Seq[Node] strikes again - case x: Node => x toString - case x: AnyRef if isArray(x) => WrappedArray make x map stringOf mkString ("Array(", ", ", ")") - case x: Traversable[_] => - // Some subclasses of AbstractFile implement Iterable, then throw an - // exception if you call iterator. What a world. - if (x.getClass.getName startsWith "scala.tools.nsc.io") x.toString - else x map stringOf mkString (x.stringPrefix + "(", ", ", ")") - case x => x toString + def stringOf(arg: Any): String = { + def inner(arg: Any): String = arg match { + case null => "null" + // Node extends NodeSeq extends Seq[Node] strikes again + case x: Node => x toString + case x: AnyRef if isArray(x) => WrappedArray make x map inner mkString ("Array(", ", ", ")") + case x: Traversable[_] => + // Some subclasses of AbstractFile implement Iterable, then throw an + // exception if you call iterator. What a world. + if (x.getClass.getName startsWith "scala.tools.nsc.io") x.toString + else x map inner mkString (x.stringPrefix + "(", ", ", ")") + case x => x toString + } + val s = inner(arg) + val nl = if (s contains "\n") "\n" else "" + nl + s + "\n" } } diff --git a/test/files/jvm/interpreter.check b/test/files/jvm/interpreter.check index f9f0d07c04..1a6fcba5fe 100644 --- a/test/files/jvm/interpreter.check +++ b/test/files/jvm/interpreter.check @@ -19,7 +19,7 @@ scala> defined type alias anotherint scala> four: anotherint = 4 -scala> <console>:5: error: type mismatch; +scala> <console>:6: error: type mismatch; found : java.lang.String("hello") required: anotherint val bogus: anotherint = "hello" @@ -217,7 +217,7 @@ scala> defined class Exp defined class Fact defined class Term -scala> | | <console>:15: warning: match is not exhaustive! +scala> | | <console>:16: warning: match is not exhaustive! missing combination Term missing combination Exp @@ -230,6 +230,6 @@ scala> plusOne: (x: Int)Int res0: Int = 6 res1: java.lang.String = after reset -<console>:5: error: not found: value plusOne +<console>:6: error: not found: value plusOne plusOne(5) // should be undefined now ^ diff --git a/test/files/run/constrained-types.check b/test/files/run/constrained-types.check index f18ff6e3c9..cc00a7c46b 100644 --- a/test/files/run/constrained-types.check +++ b/test/files/run/constrained-types.check @@ -121,7 +121,7 @@ y: java.lang.String = hello ----- val x = 3 : Int @Annot(e+f+g+h) //should have a graceful error message -<console>:5: error: not found: value e +<console>:6: error: not found: value e val x = 3 : Int @Annot(e+f+g+h) //should have a graceful error message ^ |