diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/settings/MutableSettings.scala | 71 | ||||
-rw-r--r-- | src/partest/scala/tools/partest/ReplTest.scala | 13 | ||||
-rw-r--r-- | src/repl/scala/tools/nsc/interpreter/ILoop.scala | 64 |
3 files changed, 106 insertions, 42 deletions
diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala index b5cc89c0c8..0536be92cf 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -9,8 +9,9 @@ package nsc package settings import io.{ AbstractFile, Jar, Path, PlainFile, VirtualDirectory } -import scala.reflect.internal.util.StringOps +import scala.collection.generic.Clearable import scala.io.Source +import scala.reflect.internal.util.StringOps import scala.reflect.{ ClassTag, classTag } /** A mutable Settings object. @@ -542,7 +543,7 @@ class MutableSettings(val errorFn: String => Unit) name: String, val arg: String, descr: String) - extends Setting(name, descr) { + extends Setting(name, descr) with Clearable { type T = List[String] protected var v: T = Nil def appendToValue(str: String) { value ++= List(str) } @@ -555,6 +556,7 @@ class MutableSettings(val errorFn: String => Unit) } override def tryToSetColon(args: List[String]) = tryToSet(args) override def tryToSetFromPropertyValue(s: String) = tryToSet(s.trim.split(',').toList) // used from ide + def clear(): Unit = (v = Nil) def unparse: List[String] = value map (name + ":" + _) withHelpSyntax(name + ":<" + arg + ">") @@ -608,44 +610,49 @@ class MutableSettings(val errorFn: String => Unit) name: String, descr: String, default: String - ) extends Setting(name, mkPhasesHelp(descr, default)) { + ) extends Setting(name, mkPhasesHelp(descr, default)) with Clearable { private[nsc] def this(name: String, descr: String) = this(name, descr, "") type T = List[String] - protected var v: T = Nil - override def value = if (v contains "all") List("all") else super.value - private lazy val (numericValues, stringValues) = - value filterNot (_ == "" ) partition (_ forall (ch => ch.isDigit || ch == '-')) - - /** A little ad-hoc parsing. If a string is not the name of a phase, it can also be: - * a phase id: 5 - * a phase id range: 5-10 (inclusive of both ends) - * a range with no start: -5 means up to and including 5 - * a range with no end: 10- means 10 until completion. - */ - private def stringToPhaseIdTest(s: String): Int => Boolean = (s indexOf '-') match { - case -1 => (_ == s.toInt) - case 0 => (_ <= s.tail.toInt) - case idx => - if (s.last == '-') (_ >= s.init.toInt) - else (s splitAt idx) match { - case (s1, s2) => (id => id >= s1.toInt && id <= s2.tail.toInt) - } - } - private lazy val phaseIdTest: Int => Boolean = - (numericValues map stringToPhaseIdTest) match { - case Nil => _ => false - case fns => fns.reduceLeft((f1, f2) => id => f1(id) || f2(id)) + private[this] var _v: T = Nil + private[this] var _numbs: List[(Int,Int)] = Nil + private[this] var _names: T = Nil + //protected var v: T = Nil + protected def v: T = _v + protected def v_=(t: T): Unit = { + // throws NumberFormat on bad range (like -5-6) + def asRange(s: String): (Int,Int) = (s indexOf '-') match { + case -1 => (s.toInt, s.toInt) + case 0 => (-1, s.tail.toInt) + case i if s.last == '-' => (s.init.toInt, Int.MaxValue) + case i => (s.take(i).toInt, s.drop(i+1).toInt) } + val numsAndStrs = t filter (_.nonEmpty) partition (_ forall (ch => ch.isDigit || ch == '-')) + _numbs = numsAndStrs._1 map asRange + _names = numsAndStrs._2 + _v = t + } + override def value = if (v contains "all") List("all") else super.value // i.e., v + private def numericValues = _numbs + private def stringValues = _names + private def phaseIdTest(i: Int): Boolean = numericValues exists (_ match { + case (min, max) => min <= i && i <= max + }) def tryToSet(args: List[String]) = if (default == "") errorAndValue("missing phase", None) - else { tryToSetColon(List(default)) ; Some(args) } + else tryToSetColon(List(default)) map (_ => args) + + override def tryToSetColon(args: List[String]) = try { + args match { + case Nil => if (default == "") errorAndValue("missing phase", None) + else tryToSetColon(List(default)) + case xs => value = (value ++ xs).distinct.sorted ; Some(Nil) + } + } catch { case _: NumberFormatException => None } + + def clear(): Unit = (v = Nil) - override def tryToSetColon(args: List[String]) = args match { - case Nil => if (default == "") errorAndValue("missing phase", None) else tryToSetColon(List(default)) - case xs => value = (value ++ xs).distinct.sorted ; Some(Nil) - } // we slightly abuse the usual meaning of "contains" here by returning // true if our phase list contains "all", regardless of the incoming argument def contains(phName: String) = doAllPhases || containsName(phName) diff --git a/src/partest/scala/tools/partest/ReplTest.scala b/src/partest/scala/tools/partest/ReplTest.scala index edd1f705a4..7381b8af54 100644 --- a/src/partest/scala/tools/partest/ReplTest.scala +++ b/src/partest/scala/tools/partest/ReplTest.scala @@ -7,6 +7,7 @@ package scala.tools.partest import scala.tools.nsc.Settings import scala.tools.nsc.interpreter.ILoop +import scala.tools.partest.nest.FileUtil import java.lang.reflect.{ Method => JMethod, Field => JField } /** A trait for testing repl code. It drops the first line @@ -29,3 +30,15 @@ abstract class ReplTest extends DirectTest { } def show() = eval() foreach println } + +abstract class SessionTest extends ReplTest with FileUtil { + def session: String + override final def code = expected filter (_.startsWith(prompt)) map (_.drop(prompt.length)) mkString "\n" + def expected = session.stripMargin.lines.toList + final def prompt = "scala> " + override def show() = { + val out = eval().toList + if (out.size != expected.size) Console println s"Expected ${expected.size} lines, got ${out.size}" + if (out != expected) Console print compareContents(expected, out, "expected", "actual") + } +} diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index 81d14c48dc..dc5183fdf6 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -7,22 +7,22 @@ package scala package tools.nsc package interpreter -import Predef.{ println => _, _ } -import java.io.{ BufferedReader, FileReader } -import session._ +import scala.language.{ implicitConversions, existentials } import scala.annotation.tailrec +import Predef.{ println => _, _ } +import interpreter.session._ +import StdReplTags._ import scala.util.Properties.{ jdkHome, javaVersion, versionString, javaVmName } -import util.{ ClassPath, Exceptional, stringFromWriter, stringFromStream } -import io.{ File, Directory } -import util.ScalaClassLoader +import scala.tools.nsc.util.{ ClassPath, Exceptional, stringFromWriter, stringFromStream } +import scala.reflect.classTag +import scala.reflect.internal.util.{ BatchSourceFile, ScalaClassLoader } import ScalaClassLoader._ +import scala.reflect.io.{ File, Directory } import scala.tools.util._ -import scala.language.{implicitConversions, existentials} -import scala.reflect.classTag -import StdReplTags._ +import scala.collection.generic.Clearable import scala.concurrent.{ ExecutionContext, Await, Future, future } import ExecutionContext.Implicits._ -import scala.reflect.internal.util.BatchSourceFile +import java.io.{ BufferedReader, FileReader } /** The Scala interactive shell. It provides a read-eval-print loop * around the Interpreter class. @@ -223,6 +223,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) nullary("replay", "reset execution and replay all previous commands", replay), nullary("reset", "reset the repl to its initial state, forgetting all session entries", resetCommand), shCommand, + cmd("settings", "[+|-]<options>", "+enable/-disable flags, set compiler options", changeSettings), nullary("silent", "disable/enable automatic printing of results", verbosity), cmd("type", "[-v] <expr>", "display the type of an expression without evaluating it", typeCommand), cmd("kind", "[-v] <expr>", "display the kind of expression's type", kindCommand), @@ -302,6 +303,49 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) intp.lastWarnings foreach { case (pos, msg) => intp.reporter.warning(pos, msg) } } + private def changeSettings(args: String): Result = { + def showSettings() = { + for (s <- settings.userSetSettings.toSeq.sorted) echo(s.toString) + } + def updateSettings() = { + // put aside +flag options + val (pluses, rest) = (args split "\\s+").toList partition (_.startsWith("+")) + val tmps = new Settings + val (ok, leftover) = tmps.processArguments(rest, processAll = true) + if (!ok) echo("Bad settings request.") + else if (leftover.nonEmpty) echo("Unprocessed settings.") + else { + // boolean flags set-by-user on tmp copy should be off, not on + val offs = tmps.userSetSettings filter (_.isInstanceOf[Settings#BooleanSetting]) + val (minuses, nonbools) = rest partition (arg => offs exists (_ respondsTo arg)) + // update non-flags + settings.processArguments(nonbools, processAll = true) + // also snag multi-value options for clearing, e.g. -Ylog: and -language: + for { + s <- settings.userSetSettings + if s.isInstanceOf[Settings#MultiStringSetting] || s.isInstanceOf[Settings#PhasesSetting] + if nonbools exists (arg => arg.head == '-' && arg.last == ':' && (s respondsTo arg.init)) + } s match { + case c: Clearable => c.clear() + case _ => + } + def update(bs: Seq[String], name: String=>String, setter: Settings#Setting=>Unit) = { + for (b <- bs) + settings.lookupSetting(name(b)) match { + case Some(s) => + if (s.isInstanceOf[Settings#BooleanSetting]) setter(s) + else echo(s"Not a boolean flag: $b") + case _ => + echo(s"Not an option: $b") + } + } + update(minuses, identity, _.tryToSetFromPropertyValue("false")) // turn off + update(pluses, "-" + _.drop(1), _.tryToSet(Nil)) // turn on + } + } + if (args.isEmpty) showSettings() else updateSettings() + } + private def javapCommand(line: String): Result = { if (javap == null) ":javap unavailable, no tools.jar at %s. Set JDK_HOME.".format(jdkHome) |