aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/Driver.scala2
-rw-r--r--src/dotty/tools/dotc/Resident.scala1
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala2
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala2
-rw-r--r--src/dotty/tools/dotc/repl/CompilingInterpreter.scala24
-rw-r--r--src/dotty/tools/dotc/repl/InterpreterLoop.scala52
-rw-r--r--src/dotty/tools/dotc/repl/REPL.scala34
-rw-r--r--test/dotc/tests.scala2
-rw-r--r--test/test/CompilerTest.scala17
-rw-r--r--test/test/TestREPL.scala47
-rw-r--r--tests/repl/import.check11
-rw-r--r--tests/repl/imports.check24
-rw-r--r--tests/repl/multilines.check33
-rw-r--r--tests/repl/onePlusOne.check3
14 files changed, 191 insertions, 63 deletions
diff --git a/src/dotty/tools/dotc/Driver.scala b/src/dotty/tools/dotc/Driver.scala
index 887274fa8..2e78854c1 100644
--- a/src/dotty/tools/dotc/Driver.scala
+++ b/src/dotty/tools/dotc/Driver.scala
@@ -15,8 +15,6 @@ import scala.util.control.NonFatal
*/
abstract class Driver extends DotClass {
- val prompt = "\ndotc> "
-
protected def newCompiler(implicit ctx: Context): Compiler
protected def emptyReporter: Reporter = new StoreReporter(null)
diff --git a/src/dotty/tools/dotc/Resident.scala b/src/dotty/tools/dotc/Resident.scala
index 18bb2ff4f..e1b62e4d0 100644
--- a/src/dotty/tools/dotc/Resident.scala
+++ b/src/dotty/tools/dotc/Resident.scala
@@ -31,6 +31,7 @@ class Resident extends Driver {
private val quit = ":q"
private val reset = ":reset"
+ private val prompt = "dotc> "
private def getLine() = {
Console.print(prompt)
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index 2fc958a49..fd0cff94e 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -544,7 +544,7 @@ object Contexts {
*/
def initialize()(implicit ctx: Context): Unit = {
_platform = newPlatform
- definitions.init
+ definitions.init()
}
def squashed(p: Phase): Phase = {
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 6f8a8f837..d8c882d5c 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -798,7 +798,7 @@ class Definitions {
private[this] var _isInitialized = false
private def isInitialized = _isInitialized
- def init(implicit ctx: Context) = {
+ def init()(implicit ctx: Context) = {
this.ctx = ctx
if (!_isInitialized) {
// force initialization of every symbol that is synthesized or hijacked by the compiler
diff --git a/src/dotty/tools/dotc/repl/CompilingInterpreter.scala b/src/dotty/tools/dotc/repl/CompilingInterpreter.scala
index 7d1da1419..bc898488d 100644
--- a/src/dotty/tools/dotc/repl/CompilingInterpreter.scala
+++ b/src/dotty/tools/dotc/repl/CompilingInterpreter.scala
@@ -60,6 +60,8 @@ class CompilingInterpreter(out: PrintWriter, ictx: Context) extends Compiler wit
import ast.untpd._
import CompilingInterpreter._
+ ictx.base.initialize()(ictx)
+
/** directory to save .class files to */
val virtualDirectory =
if (ictx.settings.d.isDefault(ictx)) new VirtualDirectory("(memory)", None)
@@ -175,7 +177,7 @@ class CompilingInterpreter(out: PrintWriter, ictx: Context) extends Compiler wit
// if (prevRequests.isEmpty)
// new Run(this) // initialize the compiler // (not sure this is needed)
// parse
- parse(indentCode(line)) match {
+ parse(line) match {
case None => Interpreter.Incomplete
case Some(Nil) => Interpreter.Error // parse error or empty input
case Some(tree :: Nil) if tree.isTerm && !tree.isInstanceOf[Assign] =>
@@ -271,7 +273,7 @@ class CompilingInterpreter(out: PrintWriter, ictx: Context) extends Compiler wit
// header for the wrapper object
code.println("object " + objectName + " {")
code.print(importsPreamble)
- code.println(indentCode(toCompute))
+ code.println(toCompute)
handlers.foreach(_.extraCodeToEvaluate(this,code))
code.println(importsTrailer)
//end the wrapper object
@@ -477,7 +479,7 @@ class CompilingInterpreter(out: PrintWriter, ictx: Context) extends Compiler wit
addWrapper()
if (handler.statement.isInstanceOf[Import])
- preamble.append(handler.statement.toString + ";\n")
+ preamble.append(handler.statement.show + ";\n")
// give wildcard imports a import wrapper all to their own
if (handler.importsWildcard)
@@ -645,7 +647,7 @@ class CompilingInterpreter(out: PrintWriter, ictx: Context) extends Compiler wit
private class ImportHandler(imp: Import) extends StatementHandler(imp) {
override def resultExtractionCode(req: Request, code: PrintWriter): Unit = {
- code.println("+ \"" + imp.toString + "\\n\"")
+ code.println("+ \"" + imp.show + "\\n\"")
}
def isWildcardSelector(tree: Tree) = tree match {
@@ -734,20 +736,6 @@ class CompilingInterpreter(out: PrintWriter, ictx: Context) extends Compiler wit
/** Clean up a string for output */
private def clean(str: String)(implicit ctx: Context) =
truncPrintString(stripWrapperGunk(str))
-
- /** Indent some code by the width of the scala> prompt.
- * This way, compiler error messages read better.
- */
- def indentCode(code: String) = {
- val spaces = " "
-
- stringFrom(str =>
- for (line <- code.lines) {
- str.print(spaces)
- str.print(line + "\n")
- str.flush()
- })
- }
}
/** Utility methods for the Interpreter. */
diff --git a/src/dotty/tools/dotc/repl/InterpreterLoop.scala b/src/dotty/tools/dotc/repl/InterpreterLoop.scala
index eedec3c82..4ac9602e7 100644
--- a/src/dotty/tools/dotc/repl/InterpreterLoop.scala
+++ b/src/dotty/tools/dotc/repl/InterpreterLoop.scala
@@ -21,10 +21,10 @@ import scala.concurrent.ExecutionContext.Implicits.global
* @author Lex Spoon
* @author Martin Odersky
*/
-class InterpreterLoop(
- compiler: Compiler,
- private var in: InteractiveReader,
- out: PrintWriter)(implicit ctx: Context) {
+class InterpreterLoop(compiler: Compiler, config: REPL.Config)(implicit ctx: Context) {
+ import config._
+
+ private var in = input
val interpreter = compiler.asInstanceOf[Interpreter]
@@ -52,24 +52,20 @@ class InterpreterLoop(
/** print a friendly help message */
def printHelp(): Unit = {
printWelcome()
- out.println("Type :load followed by a filename to load a Scala file.")
- out.println("Type :replay to reset execution and replay all previous commands.")
- out.println("Type :quit to exit the interpreter.")
+ output.println("Type :load followed by a filename to load a Scala file.")
+ output.println("Type :replay to reset execution and replay all previous commands.")
+ output.println("Type :quit to exit the interpreter.")
}
/** Print a welcome message */
def printWelcome(): Unit = {
- out.println(s"Welcome to Scala$version " + " (" +
+ output.println(s"Welcome to Scala$version " + " (" +
System.getProperty("java.vm.name") + ", Java " + System.getProperty("java.version") + ")." )
- out.println("Type in expressions to have them evaluated.")
- out.println("Type :help for more information.")
- out.flush()
+ output.println("Type in expressions to have them evaluated.")
+ output.println("Type :help for more information.")
+ output.flush()
}
- /** Prompt to print when awaiting input */
- val prompt = "scala> "
- val continuationPrompt = " | "
-
val version = ".next (pre-alpha)"
/** The first interpreted command always takes a couple of seconds
@@ -92,7 +88,7 @@ class InterpreterLoop(
val (keepGoing, finalLineOpt) = command(line)
if (keepGoing) {
finalLineOpt.foreach(addReplay)
- out.flush()
+ output.flush()
repl()
}
}
@@ -103,16 +99,16 @@ class InterpreterLoop(
new FileReader(filename)
} catch {
case _: IOException =>
- out.println("Error opening file: " + filename)
+ output.println("Error opening file: " + filename)
return
}
val oldIn = in
val oldReplay = replayCommandsRev
try {
val inFile = new BufferedReader(fileIn)
- in = new SimpleReader(inFile, out, false)
- out.println("Loading " + filename + "...")
- out.flush
+ in = new SimpleReader(inFile, output, false)
+ output.println("Loading " + filename + "...")
+ output.flush
repl()
} finally {
in = oldIn
@@ -124,10 +120,10 @@ class InterpreterLoop(
/** create a new interpreter and replay all commands so far */
def replay(): Unit = {
for (cmd <- replayCommands) {
- out.println("Replaying: " + cmd)
- out.flush() // because maybe cmd will have its own output
+ output.println("Replaying: " + cmd)
+ output.flush() // because maybe cmd will have its own output
command(cmd)
- out.println
+ output.println
}
}
@@ -138,12 +134,12 @@ class InterpreterLoop(
def withFile(command: String)(action: String => Unit): Unit = {
val spaceIdx = command.indexOf(' ')
if (spaceIdx <= 0) {
- out.println("That command requires a filename to be specified.")
+ output.println("That command requires a filename to be specified.")
return
}
val filename = command.substring(spaceIdx).trim
if (!new File(filename).exists) {
- out.println("That file does not exist")
+ output.println("That file does not exist")
return
}
action(filename)
@@ -169,7 +165,7 @@ class InterpreterLoop(
else if (line matches replayRegexp)
replay()
else if (line startsWith ":")
- out.println("Unknown command. Type :help for help.")
+ output.println("Unknown command. Type :help for help.")
else
shouldReplay = interpretStartingWith(line)
@@ -188,7 +184,7 @@ class InterpreterLoop(
case Interpreter.Error => None
case Interpreter.Incomplete =>
if (in.interactive && code.endsWith("\n\n")) {
- out.println("You typed two blank lines. Starting a new command.")
+ output.println("You typed two blank lines. Starting a new command.")
None
} else {
val nextLine = in.readLine(continuationPrompt)
@@ -207,7 +203,7 @@ class InterpreterLoop(
val cmd = ":load " + filename
command(cmd)
replayCommandsRev = cmd :: replayCommandsRev
- out.println()
+ output.println()
}
case _ =>
}
diff --git a/src/dotty/tools/dotc/repl/REPL.scala b/src/dotty/tools/dotc/repl/REPL.scala
index 2d6a3c742..e5ff2d3af 100644
--- a/src/dotty/tools/dotc/repl/REPL.scala
+++ b/src/dotty/tools/dotc/repl/REPL.scala
@@ -23,27 +23,37 @@ import java.io.{BufferedReader, File, FileReader, PrintWriter}
*/
class REPL extends Driver {
- /** The default input reader */
- def input(implicit ctx: Context): InteractiveReader = {
- val emacsShell = System.getProperty("env.emacs", "") != ""
- //println("emacsShell="+emacsShell) //debug
- if (ctx.settings.Xnojline.value || emacsShell) new SimpleReader()
- else InteractiveReader.createDefault()
- }
-
- /** The defult output writer */
- def output: PrintWriter = new NewLinePrintWriter(new ConsoleWriter, true)
+ lazy val config = new REPL.Config
override def newCompiler(implicit ctx: Context): Compiler =
- new repl.CompilingInterpreter(output, ctx)
+ new repl.CompilingInterpreter(config.output, ctx)
override def sourcesRequired = false
override def doCompile(compiler: Compiler, fileNames: List[String])(implicit ctx: Context): Reporter = {
if (fileNames.isEmpty)
- new InterpreterLoop(compiler, input, output).run()
+ new InterpreterLoop(compiler, config).run()
else
ctx.error(s"don't now what to do with $fileNames%, %")
ctx.reporter
}
}
+
+object REPL {
+ class Config {
+ val prompt = "scala> "
+ val continuationPrompt = " | "
+ val version = ".next (pre-alpha)"
+
+ /** The default input reader */
+ def input(implicit ctx: Context): InteractiveReader = {
+ val emacsShell = System.getProperty("env.emacs", "") != ""
+ //println("emacsShell="+emacsShell) //debug
+ if (ctx.settings.Xnojline.value || emacsShell) new SimpleReader()
+ else InteractiveReader.createDefault()
+ }
+
+ /** The default output writer */
+ def output: PrintWriter = new NewLinePrintWriter(new ConsoleWriter, true)
+ }
+}
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index d6bafe6be..48242f2d1 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -46,6 +46,7 @@ class tests extends CompilerTest {
val negDir = testsDir + "neg/"
val runDir = testsDir + "run/"
val newDir = testsDir + "new/"
+ val replDir = testsDir + "repl/"
val sourceDir = "./src/"
val dottyDir = sourceDir + "dotty/"
@@ -112,6 +113,7 @@ class tests extends CompilerTest {
@Test def pos_859 = compileFile(posSpecialDir, "i859", scala2mode)(allowDeepSubtypes)
@Test def new_all = compileFiles(newDir, twice)
+ @Test def repl_all = replFiles(replDir)
@Test def neg_all = compileFiles(negDir, verbose = true, compileSubDirs = false)
@Test def neg_typedIdents() = compileDir(negDir, "typedIdents")
diff --git a/test/test/CompilerTest.scala b/test/test/CompilerTest.scala
index ef2f719fc..1ca836133 100644
--- a/test/test/CompilerTest.scala
+++ b/test/test/CompilerTest.scala
@@ -5,12 +5,12 @@ import dotty.tools.dotc.{Main, Bench, Driver}
import dotty.tools.dotc.reporting.Reporter
import dotty.tools.dotc.util.SourcePosition
import dotty.tools.dotc.config.CompilerCommand
+import dotty.tools.io.PlainFile
import scala.collection.mutable.ListBuffer
import scala.reflect.io.{ Path, Directory, File => SFile, AbstractFile }
import scala.tools.partest.nest.{ FileManager, NestUI }
import scala.annotation.tailrec
import java.io.{ RandomAccessFile, File => JFile }
-import dotty.tools.io.PlainFile
import org.junit.Test
@@ -205,7 +205,22 @@ abstract class CompilerTest {
}
}
+ def replFile(prefix: String, fileName: String): Unit = {
+ val path = s"$prefix$fileName"
+ val f = new PlainFile(path)
+ val repl = new TestREPL(new String(f.toCharArray))
+ repl.process(Array[String]())
+ repl.check()
+ }
+ def replFiles(path: String): Unit = {
+ val dir = Directory(path)
+ val fileNames = dir.files.toArray.map(_.jfile.getName).filter(_ endsWith ".check")
+ for (name <- fileNames) {
+ log(s"testing $path$name")
+ replFile(path, name)
+ }
+ }
// ========== HELPERS =============
diff --git a/test/test/TestREPL.scala b/test/test/TestREPL.scala
new file mode 100644
index 000000000..d01038c43
--- /dev/null
+++ b/test/test/TestREPL.scala
@@ -0,0 +1,47 @@
+package test
+
+import dotty.tools.dotc.repl._
+import dotty.tools.dotc.core.Contexts.Context
+import collection.mutable
+import java.io.StringWriter
+
+/** A subclass of REPL used for testing.
+ * It takes a transcript of a REPL session in `script`. The transcript
+ * starts with the first input prompt `scala> ` and ends with `scala> :quit` and a newline.
+ * Invoking `process()` on the `TestREPL` runs all input lines and
+ * collects then interleaved with REPL output in a string writer `out`.
+ * Invoking `check()` checks that the collected output matches the original
+ * `script`.
+ */
+class TestREPL(script: String) extends REPL {
+
+ private val out = new StringWriter()
+
+ override lazy val config = new REPL.Config {
+ override val output = new NewLinePrintWriter(out)
+
+ override def input(implicit ctx: Context) = new InteractiveReader {
+ val lines = script.lines
+ def readLine(prompt: String): String = {
+ val line = lines.next
+ if (line.startsWith(prompt) || line.startsWith(continuationPrompt)) {
+ output.println(line)
+ line.drop(prompt.length)
+ }
+ else readLine(prompt)
+ }
+ val interactive = false
+ }
+ }
+
+ def check() = {
+ out.close()
+ val printed = out.toString
+ val transcript = printed.drop(printed.indexOf(config.prompt))
+ if (transcript.toString != script) {
+ println("input differs from transcript:")
+ println(transcript)
+ assert(false)
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/repl/import.check b/tests/repl/import.check
new file mode 100644
index 000000000..ccaa52190
--- /dev/null
+++ b/tests/repl/import.check
@@ -0,0 +1,11 @@
+scala> import collection.mutable._
+import collection.mutable._
+scala> val buf = new ListBuffer[Int]
+buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer()
+scala> buf += 22
+res0: scala.collection.mutable.ListBuffer[Int] = ListBuffer(22)
+scala> buf ++= List(1, 2, 3)
+res1: scala.collection.mutable.ListBuffer[Int] = ListBuffer(22, 1, 2, 3)
+scala> buf.toList
+res2: scala.collection.immutable.List[Int] = List(22, 1, 2, 3)
+scala> :quit
diff --git a/tests/repl/imports.check b/tests/repl/imports.check
new file mode 100644
index 000000000..3fa103283
--- /dev/null
+++ b/tests/repl/imports.check
@@ -0,0 +1,24 @@
+scala> import scala.collection.mutable
+import scala.collection.mutable
+scala> val buf = mutable.ListBuffer[Int]()
+buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer()
+scala> object o {
+ | val xs = List(1, 2, 3)
+ | }
+defined module o
+scala> import o._
+import o._
+scala> buf += xs
+<console>:11: error: type mismatch:
+ found : scala.collection.immutable.List[Int](o.xs)
+ required: String
+buf += xs
+ ^
+<console>:11: error: type mismatch:
+ found : String
+ required: scala.collection.mutable.ListBuffer[Int]
+buf += xs
+^
+scala> buf ++= xs
+res1: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3)
+scala> :quit
diff --git a/tests/repl/multilines.check b/tests/repl/multilines.check
new file mode 100644
index 000000000..3bc32707e
--- /dev/null
+++ b/tests/repl/multilines.check
@@ -0,0 +1,33 @@
+scala> val x = """alpha
+ |
+ | omega"""
+x: String =
+alpha
+
+omega
+scala> val y = """abc
+ | |def
+ | |ghi
+ | """.stripMargin
+y: String =
+abc
+def
+ghi
+
+scala> val z = {
+ | def square(x: Int) = x * x
+ | val xs = List(1, 2, 3)
+ | square(xs)
+ | }
+<console>:8: error: type mismatch:
+ found : scala.collection.immutable.List[Int](xs)
+ required: Int
+ square(xs)
+ ^
+scala> val z = {
+ | def square(x: Int) = x * x
+ | val xs = List(1, 2, 3)
+ | xs.map(square)
+ | }
+z: scala.collection.immutable.List[Int] = List(1, 4, 9)
+scala> :quit
diff --git a/tests/repl/onePlusOne.check b/tests/repl/onePlusOne.check
new file mode 100644
index 000000000..9db6e6817
--- /dev/null
+++ b/tests/repl/onePlusOne.check
@@ -0,0 +1,3 @@
+scala> 1+1
+res0: Int = 2
+scala> :quit