diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index dfdcbde73a66..65443a2377e3 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -140,7 +140,8 @@ trait MessageRendering { /** The whole message rendered from `msg` */ def messageAndPos(msg: Message, pos: SourcePosition, diagnosticLevel: String)(implicit ctx: Context): String = { val sb = mutable.StringBuilder.newBuilder - sb.append(posStr(pos, diagnosticLevel, msg)).append('\n') + val posString = posStr(pos, diagnosticLevel, msg) + if (posString.nonEmpty) sb.append(posString).append('\n') if (pos.exists) { val (srcBefore, srcAfter, offset) = sourceLines(pos) val marker = columnMarker(pos, offset) diff --git a/compiler/src/dotty/tools/repl/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index 89e6a868eed0..7a16fa0a26ca 100644 --- a/compiler/src/dotty/tools/repl/ParseResult.scala +++ b/compiler/src/dotty/tools/repl/ParseResult.scala @@ -98,7 +98,9 @@ object ParseResult { @sharable private[this] val CommandExtract = """(:[\S]+)\s*(.*)""".r - private def parseStats(parser: Parser): List[untpd.Tree] = { + private def parseStats(sourceCode: String)(implicit ctx: Context): List[untpd.Tree] = { + val source = new SourceFile("", sourceCode.toCharArray) + val parser = new Parser(source) val stats = parser.blockStatSeq() parser.accept(Tokens.EOF) stats @@ -118,10 +120,7 @@ object ParseResult { case _ => UnknownCommand(cmd) } case _ => { - val source = new SourceFile("", sourceCode.toCharArray) - val parser = new Parser(source) - - val stats = parseStats(parser) + val stats = parseStats(sourceCode) if (ctx.reporter.hasErrors) { SyntaxErrors(sourceCode, @@ -145,9 +144,7 @@ object ParseResult { val reporter = storeReporter var needsMore = false reporter.withIncompleteHandler(_ => _ => needsMore = true) { - val source = new SourceFile("", sourceCode.toCharArray) - val parser = new Parser(source)(ctx.fresh.setReporter(reporter)) - parseStats(parser) + parseStats(sourceCode)(ctx.fresh.setReporter(reporter)) !reporter.hasErrors && needsMore } } diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index cf220fd58ae7..579ef637315b 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -33,7 +33,7 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler { /** A GenBCode phase that outputs to a virtual directory */ private class REPLGenBCode extends GenBCode { - override def phaseName = "replGenBCode" + override def phaseName = "genBCode" override def outputDir(implicit ctx: Context) = directory } @@ -51,6 +51,25 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler { ) } + def newRun(initCtx: Context, objectIndex: Int) = new Run(this, initCtx) { + override protected[this] def rootContext(implicit ctx: Context) = + addMagicImports(super.rootContext.fresh.setReporter(storeReporter)) + + private def addMagicImports(initCtx: Context): Context = { + def addImport(path: TermName)(implicit ctx: Context) = { + val importInfo = ImportInfo.rootImport { () => + ctx.requiredModuleRef(path) + } + ctx.fresh.setNewScope.setImportInfo(importInfo) + } + + (1 to objectIndex) + .foldLeft(addImport("dotty.Show".toTermName)(initCtx)) { (ictx, i) => + addImport(nme.EMPTY_PACKAGE ++ "." ++ objectNames(i))(ictx) + } + } + } + private[this] var objectNames = Map.empty[Int, TermName] private def objectName(state: State) = objectNames.get(state.objectIndex).getOrElse { @@ -59,9 +78,9 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler { newName } - sealed case class Definitions(stats: List[untpd.Tree], state: State) + private case class Definitions(stats: List[untpd.Tree], state: State) - def definitions(trees: List[untpd.Tree], state: State): Result[Definitions] = { + private def definitions(trees: List[untpd.Tree], state: State): Definitions = { import untpd._ implicit val ctx: Context = state.run.runContext @@ -80,7 +99,7 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler { def createPatDefShows(patDef: PatDef) = { def createDeepShows(tree: untpd.Tree) = { - object PatFolder extends UntypedDeepFolder[List[DefDef]] ( + class PatFolder extends UntypedDeepFolder[List[DefDef]] ( (acc, tree) => tree match { case Ident(name) if name.isVariableName && name != nme.WILDCARD => createShow(name.toTermName, tree.pos) :: acc @@ -90,7 +109,7 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler { acc } ) - PatFolder.apply(Nil, tree).reverse + (new PatFolder).apply(Nil, tree).reverse } // cannot fold over the whole tree because we need to generate show methods @@ -130,12 +149,12 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler { } Definitions( - state.imports.map(_._1) ++ defs, + state.imports ++ defs, state.copy( objectIndex = state.objectIndex + (if (defs.isEmpty) 0 else 1), valIndex = valIdx ) - ).result + ) } /** Wrap trees in an object and add imports from the previous compilations @@ -153,65 +172,40 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler { * } * ``` */ - def wrapped(defs: Definitions, sourceCode: String): untpd.PackageDef = { + private def wrapped(defs: Definitions): untpd.PackageDef = { import untpd._ - implicit val ctx: Context = defs.state.run.runContext + assert(defs.stats.nonEmpty) - val module = { - val tmpl = Template(emptyConstructor(ctx), Nil, EmptyValDef, defs.stats) - List( - ModuleDef(objectName(defs.state), tmpl) - .withMods(new Modifiers(Module | Final)) - .withPos(Position(0, sourceCode.length)) - ) - } + implicit val ctx: Context = defs.state.run.runContext - PackageDef(Ident(nme.EMPTY_PACKAGE), module) - } + val tmpl = Template(emptyConstructor, Nil, EmptyValDef, defs.stats) + val module = ModuleDef(objectName(defs.state), tmpl) + .withMods(new Modifiers(Module | Final)) + .withPos(Position(0, defs.stats.last.pos.end)) - def newRun(initCtx: Context, objectIndex: Int) = new Run(this, initCtx) { - override protected[this] def rootContext(implicit ctx: Context) = - addMagicImports(super.rootContext.fresh.setReporter(storeReporter), objectIndex) + PackageDef(Ident(nme.EMPTY_PACKAGE), List(module)) } - def createUnit(defs: Definitions, sourceCode: String): Result[CompilationUnit] = { + private def createUnit(defs: Definitions, sourceCode: String): CompilationUnit = { val unit = new CompilationUnit(new SourceFile(objectName(defs.state).toString, sourceCode)) - unit.untpdTree = wrapped(defs, sourceCode) - unit.result + unit.untpdTree = wrapped(defs) + unit } - def runCompilation(unit: CompilationUnit, state: State): Result[State] = { + private def runCompilationUnit(unit: CompilationUnit, state: State): Result[(CompilationUnit, State)] = { val run = state.run val reporter = state.run.runContext.reporter run.compileUnits(unit :: Nil) - if (!reporter.hasErrors) state.result + if (!reporter.hasErrors) (unit, state).result else run.runContext.flushBufferedMessages().errors } def compile(parsed: Parsed)(implicit state: State): Result[(CompilationUnit, State)] = { - for { - defs <- definitions(parsed.trees, state) - unit <- createUnit(defs, parsed.sourceCode) - state <- runCompilation(unit, defs.state) - } yield (unit, state) - } - - private[this] def addMagicImports(initCtx: Context, objectIndex: Int): Context = { - def addImport(path: TermName)(implicit ctx: Context) = { - val ref = tpd.ref(ctx.requiredModuleRef(path.toTermName)) - val symbol = ctx.newImportSymbol(ctx.owner, ref) - val importInfo = - new ImportInfo(implicit ctx => symbol, untpd.Ident(nme.WILDCARD) :: Nil, None) - ctx.fresh.setNewScope.setImportInfo(importInfo) - } - - List - .range(1, objectIndex + 1) - .foldLeft(addImport("dotty.Show".toTermName)(initCtx)) { (ictx, i) => - addImport(nme.EMPTY_PACKAGE ++ "." ++ objectNames(i))(ictx) - } + val defs = definitions(parsed.trees, state) + val unit = createUnit(defs, parsed.sourceCode) + runCompilationUnit(unit, defs.state) } def typeOf(expr: String)(implicit state: State): Result[String] = @@ -223,7 +217,7 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler { case _ => """Couldn't compute the type of your expression, so sorry :( | - |Please report this to my masters at Github.com/lampepfl/dotty + |Please report this to my masters at github.com/lampepfl/dotty """.stripMargin } } @@ -240,7 +234,7 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler { val tmpl = Template(emptyConstructor, List(Ident(tpnme.Any)), EmptyValDef, - state.imports.map(_._1) :+ valdef) + state.imports :+ valdef) PackageDef(Ident(nme.EMPTY_PACKAGE), TypeDef("EvaluateExpr".toTypeName, tmpl) @@ -286,7 +280,7 @@ class ReplCompiler(val directory: AbstractFile) extends Compiler { val src = new SourceFile(s"EvaluateExpr", expr) val runCtx = run.runContext.fresh - .setSetting(run.runContext.settings.YstopAfter, List("replFrontEnd")) + .setSetting(run.runContext.settings.YstopAfter, List("frontend")) wrapped(expr, src, state)(runCtx).flatMap { pkg => val unit = new CompilationUnit(src) diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 4f5c01505c5f..14f96438509d 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -25,7 +25,10 @@ import dotc.core.NameKinds.SimpleNameKind import dotc.config.CompilerCommand import dotc.{ Compiler, Driver } import dotc.printing.SyntaxHighlighting +import dotc.reporting.diagnostic.Message import dotc.util.Positions.Position +import dotc.util.SourcePosition + import io._ import AmmoniteReader._ @@ -56,7 +59,7 @@ import results._ case class State(objectIndex: Int, valIndex: Int, history: History, - imports: List[(untpd.Import, String)], + imports: List[untpd.Import], run: Run) { def withHistory(newEntry: String) = copy(history = newEntry :: history) @@ -184,8 +187,8 @@ class ReplDriver(settings: Array[String], private def readLine()(implicit state: State): ParseResult = AmmoniteReader(out, state.history, completions(_, _, state))(state.run.runContext).prompt - private def extractImports(trees: List[untpd.Tree])(implicit context: Context): List[(untpd.Import, String)] = - trees.collect { case imp: untpd.Import => (imp, imp.show) } + private def extractImports(trees: List[untpd.Tree]): List[untpd.Import] = + trees.collect { case imp: untpd.Import => imp } private def interpret(res: ParseResult)(implicit state: State): State = res match { @@ -223,7 +226,7 @@ class ReplDriver(settings: Array[String], { case (unit: CompilationUnit, newState: State) => { val newestWrapper = extractNewestWrapper(unit.untpdTree) - val newImports = newState.imports ++ extractImports(parsed.trees)(newState.run.runContext) + val newImports = newState.imports ++ extractImports(parsed.trees) val newStateWithImports = newState.copy(imports = newImports) displayDefinitions(unit.tpdTree, newestWrapper)(newStateWithImports) @@ -323,7 +326,7 @@ class ReplDriver(settings: Array[String], } case Imports => { - state.imports foreach { case (_, i) => println(SyntaxHighlighting(i)) } + state.imports.foreach(i => out.println(SyntaxHighlighting(i.show(state.run.runContext)))) state.withHistory(Imports.command) } @@ -361,18 +364,7 @@ class ReplDriver(settings: Array[String], /** A `MessageRenderer` without file positions */ private val messageRenderer = new MessageRendering { - import dotc.reporting.diagnostic._ - import dotc.util._ - override def messageAndPos(msg: Message, pos: SourcePosition, diagnosticLevel: String)(implicit ctx: Context): String = { - val sb = scala.collection.mutable.StringBuilder.newBuilder - if (pos.exists) { - val (srcBefore, srcAfter, offset) = sourceLines(pos) - val marker = columnMarker(pos, offset) - val err = errorMsg(pos, msg.msg, offset) - sb.append((srcBefore ::: marker :: err :: outer(pos, " " * (offset - 1)) ::: srcAfter).mkString("\n")) - } - sb.toString - } + override def posStr(pos: SourcePosition, diagnosticLevel: String, message: Message)(implicit ctx: Context): String = "" } /** Render messages using the `MessageRendering` trait */ diff --git a/compiler/src/dotty/tools/repl/ReplFrontEnd.scala b/compiler/src/dotty/tools/repl/ReplFrontEnd.scala index e02053dacd92..da950eafb44b 100644 --- a/compiler/src/dotty/tools/repl/ReplFrontEnd.scala +++ b/compiler/src/dotty/tools/repl/ReplFrontEnd.scala @@ -12,19 +12,17 @@ import dotc.core.Contexts.Context * compiler pipeline. */ private[repl] class REPLFrontEnd extends FrontEnd { - override def phaseName = "replFrontEnd" + override def phaseName = "frontend" override def isRunnable(implicit ctx: Context) = true override def runOn(units: List[CompilationUnit])(implicit ctx: Context) = { - val unitContexts = for (unit <- units) yield ctx.fresh.setCompilationUnit(unit) - var remaining = unitContexts - while (remaining.nonEmpty) { - enterSyms(remaining.head) - remaining = remaining.tail - } - unitContexts.foreach(enterAnnotations(_)) - unitContexts.foreach(typeCheck(_)) - unitContexts.map(_.compilationUnit).filterNot(discardAfterTyper) + assert(units.size == 1) // REPl runs one compilation unit at a time + + val unitContext = ctx.fresh.setCompilationUnit(units.head) + enterSyms(unitContext) + enterAnnotations(unitContext) + typeCheck(unitContext) + List(unitContext.compilationUnit) } } diff --git a/compiler/test-resources/repl/patdef b/compiler/test-resources/repl/patdef index a6ebf9688fde..c7ca5d287ce7 100644 --- a/compiler/test-resources/repl/patdef +++ b/compiler/test-resources/repl/patdef @@ -22,5 +22,5 @@ val x: Int = 1 scala> val List(_ @ List(x)) = List(List(2)) val x: Int = 2 scala> val B @ List(), C: List[Int] = List() -val B: List[Int] = Nil -val C: List[Int] = Nil +val B: List[Int] = List() +val C: List[Int] = List() diff --git a/dist/bin/dotr b/dist/bin/dotr index 568f201f38ad..7b14f243e1b3 100755 --- a/dist/bin/dotr +++ b/dist/bin/dotr @@ -60,7 +60,7 @@ if [ $run_repl == true ] || [ ${#residual_args[@]} -eq 0 ]; then if [ "$CLASS_PATH" ]; then cp_arg="-classpath $CLASS_PATH" fi - echo "Starting dotty REPL" + echo "Starting dotty REPL..." eval "$PROG_HOME/bin/dotc $cp_arg -repl ${residual_args[@]}" else cp_arg="-classpath $DOTTY_LIB$PSEP$SCALA_LIB" diff --git a/library/src/dotty/Show.scala b/library/src/dotty/Show.scala index 2feeb29efbcc..64794e7955c9 100644 --- a/library/src/dotty/Show.scala +++ b/library/src/dotty/Show.scala @@ -28,21 +28,22 @@ object Show { implicit val stringShow: Show[String] = new Show[String] { // From 2.12 spec, `charEscapeSeq`: // ‘\‘ (‘b‘ | ‘t‘ | ‘n‘ | ‘f‘ | ‘r‘ | ‘"‘ | ‘'‘ | ‘\‘) - def show(str: String) = - "\"" + { - val sb = new StringBuilder - str.foreach { - case '\b' => sb.append("\\b") - case '\t' => sb.append("\\t") - case '\n' => sb.append("\\n") - case '\f' => sb.append("\\f") - case '\r' => sb.append("\\r") - case '\'' => sb.append("\\'") - case '\"' => sb.append("\\\"") - case c => sb.append(c) - } - sb.toString - } + "\"" + def show(str: String) = { + val sb = new StringBuilder + sb.append("\"") + str.foreach { + case '\b' => sb.append("\\b") + case '\t' => sb.append("\\t") + case '\n' => sb.append("\\n") + case '\f' => sb.append("\\f") + case '\r' => sb.append("\\r") + case '\'' => sb.append("\\'") + case '\"' => sb.append("\\\"") + case c => sb.append(c) + } + sb.append("\"") + sb.toString + } } implicit val intShow: Show[Int] = new Show[Int] { @@ -72,12 +73,12 @@ object Show { implicit def showList[T](implicit st: Show[T]): Show[List[T]] = new Show[List[T]] { def show(xs: List[T]) = - if (xs.isEmpty) "Nil" + if (xs.isEmpty) "List()" else "List(" + xs.map(_.show).mkString(", ") + ")" } implicit val showNil: Show[Nil.type] = new Show[Nil.type] { - def show(xs: Nil.type) = "Nil" + def show(xs: Nil.type) = "List()" } implicit def showOption[T](implicit st: Show[T]): Show[Option[T]] = new Show[Option[T]] {