diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/Interpreter.scala | 68 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/InterpreterLoop.scala | 35 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/InterpreterSettings.scala | 20 |
3 files changed, 96 insertions, 27 deletions
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala index c66590c359..331e63108c 100644 --- a/src/compiler/scala/tools/nsc/Interpreter.scala +++ b/src/compiler/scala/tools/nsc/Interpreter.scala @@ -93,6 +93,9 @@ class Interpreter(val settings: Settings, reporter: Reporter, out: PrintWriter) } } + /** interpreter settings */ + val isettings = new InterpreterSettings + /** directory to save .class files to */ val classfilePath = File.createTempFile("scalaint", "") classfilePath.delete // the file is created as a file; make it a directory @@ -148,10 +151,20 @@ class Interpreter(val settings: Settings, reporter: Reporter, out: PrintWriter) private def newLineName = { val num = nextLineNo nextLineNo = nextLineNo + 1 - (compiler.nme.INTERPRETER_LINE_PREFIX + - (if (num>=0) num.toString else "_neg" + (-num).toString)) + compiler.nme.INTERPRETER_LINE_PREFIX + num + } + + /** next result variable number to use */ + private var nextVarNameNo = 0 + + /** allocate a fresh variable name */ + private def newVarName() = { + val num = nextVarNameNo + nextVarNameNo = nextVarNameNo + 1 + "unnamed" + num } + /** import statements that should be used for submitted code */ private def importLines: List[String] = for { @@ -174,6 +187,23 @@ class Interpreter(val settings: Settings, reporter: Reporter, out: PrintWriter) stringWriter.toString } + /** Truncate a string if it is longer than settings.maxPrintString */ + private def truncPrintString(str: String): String = { + val maxpr = isettings.maxPrintString + + if(maxpr <= 0) + return str + + if(str.length <= maxpr) + return str + + val trailer = "..." + if(maxpr >= trailer.length+1) + return str.substring(0, maxpr-3) + trailer + + return str.substring(0, maxpr) + } + /** Parse a line into a sequence of trees. Returns None if the input * is incomplete. */ private def parse(line: String): Option[List[Tree]] = { @@ -286,7 +316,7 @@ class Interpreter(val settings: Settings, reporter: Reporter, out: PrintWriter) if (printResults || !succeeded) { // print the result - out.print(interpreterResultString) + out.print(truncPrintString(interpreterResultString)) // print out types of functions; they are not printed in the // request printout @@ -337,18 +367,6 @@ class Interpreter(val settings: Settings, reporter: Reporter, out: PrintWriter) } - /** Make a dry run in order to fill caches. This is useful - * for interactive interpreters so that the interpreter responds - * quickly to the first user-supplied query. - */ - def prime: Unit = - if(prevRequests.isEmpty) - beQuietDuring { - nextLineNo = -1 // cosmetic: make the first user-requested line - // be number 0 - interpret("0") - } - /** <p> * This instance is no longer needed, so release any resources * it is using. @@ -386,7 +404,19 @@ class Interpreter(val settings: Settings, reporter: Reporter, out: PrintWriter) /** whether the trees need a variable name, as opposed to standing alone */ - def needsVarName: Boolean = false + val needsVarName: Boolean = false + + /** A cache for the chosen variable name, if one has been calculated */ + var varNameCache: Option[String] = None + + /** A computed variable name, if one is needed */ + def varName = + varNameCache match { + case None => + varNameCache = Some(newVarName) + varNameCache.get + case Some(name) => name + } /** list of methods defined */ val defNames = @@ -404,7 +434,7 @@ class Interpreter(val settings: Settings, reporter: Reporter, out: PrintWriter) } yield name if (needsVarName) - compiler.encode(lineName) :: baseNames // add a var name + compiler.encode(varName) :: baseNames // add a var name else baseNames } @@ -467,7 +497,7 @@ class Interpreter(val settings: Settings, reporter: Reporter, out: PrintWriter) // the line of code to compute if (needsVarName) - code.println(" val " + lineName + " = " + line) + code.println(" val " + varName + " = " + line) else code.println(" " + line) @@ -652,7 +682,7 @@ class Interpreter(val settings: Settings, reporter: Reporter, out: PrintWriter) override val boundNames = Nil override val usedNames = Nil override def resultExtractionCode(code: PrintWriter): Unit = { - code.println("+ \"" + line + "\"") + code.println("+ \"" + trees.head.toString + "\"") } } } diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala index a353c2b3e8..a8c26c4a79 100644 --- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala +++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala @@ -36,6 +36,7 @@ class InterpreterLoop(in0: BufferedReader, out: PrintWriter) { var settings: Settings = _ // set by main() var interpreter: Interpreter = null // set by createInterpreter() + def isettings = interpreter.isettings /** A reverse list of commands to replay if the user * requests a :replay */ @@ -72,6 +73,17 @@ class InterpreterLoop(in0: BufferedReader, out: PrintWriter) { } } + /** Bind the settings so that evaluated code can modiy them */ + def bindSettings() { + interpreter.beQuietDuring { + interpreter.bind( + "settings", + "scala.tools.nsc.InterpreterSettings", + isettings) + } + } + + /** print a friendly help message */ def printHelp { out.println("This is an interpreter for Scala.") @@ -89,21 +101,28 @@ class InterpreterLoop(in0: BufferedReader, out: PrintWriter) { out.println("Type :help for more information.") } - /** The main read-eval-print loop for the interpereter. It calls + /** The main read-eval-print loop for the interpreter. It calls * <code>command()</code> for each line of input, and stops when * <code>command()</code> returns <code>false</code>. */ - def repl { - var firstTime = true + def repl() { + var first = true while (true) { if (interactive) { out.print("\nscala> ") out.flush - if (firstTime) { - interpreter.prime - firstTime = false - } } + if(first) { + /* For some reason, the first interpreted command always takes + * a second or two. So, wait until the welcome message + * has been printed before calling bindSettings. That way, + * the user can read the welcome message while this + * command executes. + */ + bindSettings() + first = false + } + var line = in.readLine() if (line eq null) return () // assumes null means EOF @@ -145,7 +164,7 @@ class InterpreterLoop(in0: BufferedReader, out: PrintWriter) { } /** create a new interpreter and replay all commands so far */ - def replay { + def replay() { closeInterpreter createInterpreter for (val cmd <- replayCommands) { diff --git a/src/compiler/scala/tools/nsc/InterpreterSettings.scala b/src/compiler/scala/tools/nsc/InterpreterSettings.scala new file mode 100644 index 0000000000..7e5d0a5cc4 --- /dev/null +++ b/src/compiler/scala/tools/nsc/InterpreterSettings.scala @@ -0,0 +1,20 @@ +package scala.tools.nsc + +/** Settings for the interpreter */ +class InterpreterSettings { + /** A list of paths where :load should look */ + var loadPath = List(".", "/home/lex/tmp") // XXX remove tmp, just for testing + + /** The maximum length of toString to use when printing the result + * of an evaluation. 0 means no maximum. If a printout requires + * more than this number of characters, then the printout is + * truncated. + */ + var maxPrintString = 390 + + override def toString = + "InterpreterSettings {\n" + +// " loadPath = " + loadPath + "\n" + + " maxPrintString = " + maxPrintString + "\n" + + "}" +} |