summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-03-12 18:15:25 +0000
committerPaul Phillips <paulp@improving.org>2009-03-12 18:15:25 +0000
commit8bafc41b19deca3b95877633dd07ffa38c42feec (patch)
tree6783e1f00230b672c11f64318ab03b85da954a8a
parent8e28858bd1f1c4e8a4df03b87f51c362bc8e449e (diff)
downloadscala-8bafc41b19deca3b95877633dd07ffa38c42feec.tar.gz
scala-8bafc41b19deca3b95877633dd07ffa38c42feec.tar.bz2
scala-8bafc41b19deca3b95877633dd07ffa38c42feec.zip
A big cleanup of Settings code.
manage existing settings and add new ones. It's paving the way for low-fuss scalac preferences so we can exert fine grained config file based control over compiler behavior.
-rw-r--r--src/compiler/scala/tools/ant/Scalac.scala2
-rw-r--r--src/compiler/scala/tools/ant/Scaladoc.scala13
-rw-r--r--src/compiler/scala/tools/nsc/CompileClient.scala4
-rw-r--r--src/compiler/scala/tools/nsc/CompilerCommand.scala148
-rw-r--r--src/compiler/scala/tools/nsc/GenericRunnerCommand.scala5
-rw-r--r--src/compiler/scala/tools/nsc/GenericRunnerSettings.scala50
-rw-r--r--src/compiler/scala/tools/nsc/InterpreterCommand.scala2
-rw-r--r--src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala16
-rw-r--r--src/compiler/scala/tools/nsc/ScriptRunner.scala2
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala913
-rw-r--r--src/compiler/scala/tools/nsc/doc/Settings.scala8
-rw-r--r--src/partest/scala/tools/partest/nest/TestFile.scala2
12 files changed, 614 insertions, 551 deletions
diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala
index 7518ab8664..f4cbcf1bf8 100644
--- a/src/compiler/scala/tools/ant/Scalac.scala
+++ b/src/compiler/scala/tools/ant/Scalac.scala
@@ -555,7 +555,7 @@ class Scalac extends MatchingTask {
if (!assemrefs.isEmpty) settings.assemrefs.value = assemrefs.get
log("Scalac params = '" + addParams + "'", Project.MSG_DEBUG)
- settings.parseParams(addParams, error)
+ settings.parseParams(addParams)
(settings, sourceFiles, javaOnly)
}
diff --git a/src/compiler/scala/tools/ant/Scaladoc.scala b/src/compiler/scala/tools/ant/Scaladoc.scala
index e3178e8d9e..ebb7414734 100644
--- a/src/compiler/scala/tools/ant/Scaladoc.scala
+++ b/src/compiler/scala/tools/ant/Scaladoc.scala
@@ -567,15 +567,16 @@ class Scaladoc extends MatchingTask {
var args =
if (addParams.trim() == "") Nil
else List.fromArray(addParams.trim().split(" ")).map(_.trim())
+
while (!args.isEmpty) {
- val argsBuf = args
if (args.head startsWith "-") {
- for (docSetting <- docSettings.allSettings)
- args = docSetting.tryToSet(args);
- } else error("Parameter '" + args.head + "' does not start with '-'.")
- if (argsBuf eq args)
- error("Parameter '" + args.head + "' is not recognised by Scaladoc.")
+ val args0 = args
+ args = docSettings.parseParams(args)
+ if (args0 eq args) error("Parameter '" + args.head + "' is not recognised by Scaladoc.")
+ }
+ else error("Parameter '" + args.head + "' does not start with '-'.")
}
+
Pair(docSettings, sourceFiles)
}
diff --git a/src/compiler/scala/tools/nsc/CompileClient.scala b/src/compiler/scala/tools/nsc/CompileClient.scala
index 013ce2a823..941c722efb 100644
--- a/src/compiler/scala/tools/nsc/CompileClient.scala
+++ b/src/compiler/scala/tools/nsc/CompileClient.scala
@@ -34,7 +34,7 @@ class StandardCompileClient {
pathsList.map(absFileName).mkString("", sep, "")
}
- val fileEnding = Properties.fileEndingString
+ val fileEndings = Properties.fileEndingString.split("""\|""").toList
protected def normalize(args: Array[String]): (String, String) = {
var i = 0
@@ -42,7 +42,7 @@ class StandardCompileClient {
var serverAdr = ""
while (i < args.length) {
val arg = args(i)
- if (fileEnding split ("\\|") exists (arg endsWith _)) {
+ if (fileEndings exists(arg endsWith _)) {
args(i) = absFileName(arg)
} else if (arg startsWith "-J") {
//see http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/javac.html#J
diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala
index 7896f4e270..ea0aa5f969 100644
--- a/src/compiler/scala/tools/nsc/CompilerCommand.scala
+++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala
@@ -6,6 +6,8 @@
package scala.tools.nsc
+import Settings.Setting
+import java.io.IOException
/** A class representing command line info for scalac */
class CompilerCommand(
@@ -18,16 +20,17 @@ class CompilerCommand(
def this(arguments: List[String], settings: Settings, error: String => Unit, interactive: Boolean) =
this(arguments, settings, error, interactive, true)
+ /** Private buffer for accumulating files to compile */
private var fs: List[String] = List()
- /** All files to compile */
+ /** Public list of files to compile */
def files: List[String] = fs.reverse
/** The name of the command */
val cmdName = "scalac"
- /** The file extension of files that the compiler can process */
- lazy val fileEnding = Properties.fileEndingString
+ /** The file extensions of files that the compiler can process */
+ lazy val fileEndings = Properties.fileEndingString.split("""\|""").toList
private val helpSyntaxColumnWidth: Int =
Iterable.max(settings.allSettings map (_.helpSyntax.length))
@@ -39,64 +42,30 @@ class CompilerCommand(
buf.toString()
}
- /** A message explaining usage and options */
- def usageMsg: String = {
- settings.allSettings
- .filter(_.isStandard)
- .map(setting =>
- format(setting.helpSyntax) + " " + setting.helpDescription)
- .mkString("Usage: " + cmdName + " <options> <source files>\n" +
- "where possible standard options include:\n ",
- "\n ",
- "\n")
- }
-
- /** A message explaining usage and options */
- def xusageMsg: String = {
- settings.allSettings
- .filter(_.isAdvanced)
- .map(setting =>
- format(setting.helpSyntax) + " " + setting.helpDescription)
- .mkString("Possible advanced options include:\n ",
- "\n ",
- "\n")
- }
-
- /** A message explaining usage and options */
- def yusageMsg: String = {
- settings.allSettings
- .filter(_.isPrivate)
- .map(setting =>
- format(setting.helpSyntax) + " " + setting.helpDescription)
- .mkString("Possible private options include:\n ",
- "\n ",
- "\n")
- }
-
- // If any of these settings is set, the compiler shouldn't
- // start; an informative message of some sort
- // should be printed instead.
+ /** Creates a help message for a subset of options based on cond */
+ def createUsageMsg(label: String, cond: (Setting) => Boolean): String =
+ settings.allSettings .
+ filter(cond) .
+ map(s => format(s.helpSyntax) + " " + s.helpDescription) .
+ mkString("Usage: %s <options> <source files>\n%s options include:\n " .
+ format(cmdName, label), "\n ", "\n")
+
+ /** Messages explaining usage and options */
+ def usageMsg = createUsageMsg("where possible standard", _.isStandard)
+ def xusageMsg = createUsageMsg("Possible advanced", _.isAdvanced)
+ def yusageMsg = createUsageMsg("Possible private", _.isPrivate)
+
+ // If any of these settings is set, the compiler shouldn't start;
+ // an informative message of some sort should be printed instead.
// (note: do not add "files.isEmpty" do this list)
val stopSettings = List[(() => Boolean, (Global) => String)](
- (() => settings.help.value,
- compiler => usageMsg + compiler.pluginOptionsHelp
- ),
- (() => settings.Xhelp.value,
- compiler => xusageMsg
- ),
- (() => settings.Yhelp.value,
- compiler => yusageMsg
- ),
- (() => settings.showPlugins.value,
- compiler => compiler.pluginDescriptions
- ),
- (() => settings.showPhases.value,
- compiler => compiler.phaseDescriptions
- )
+ (settings.help.value _, usageMsg + _.pluginOptionsHelp),
+ (settings.Xhelp.value _, _ => xusageMsg),
+ (settings.Yhelp.value _, _ => yusageMsg),
+ (settings.showPlugins.value _, _.pluginDescriptions),
+ (settings.showPlugins.value _, _.phaseDescriptions)
)
-
- def shouldStopWithInfo: Boolean =
- stopSettings.exists(pair => (pair._1)())
+ def shouldStopWithInfo: Boolean = stopSettings exists { _._1() }
def getInfoMessage(compiler: Global): String =
stopSettings.find(pair => (pair._1)()) match {
@@ -112,42 +81,37 @@ class CompilerCommand(
protected def processArguments() {
// initialization
var args = arguments
+ def errorAndNotOk(msg: String) = { error(msg) ; ok = false }
+
+ // given a @ argument expands it out
+ def doExpand(x: String) =
+ try { args = util.ArgumentsExpander.expandArg(x) ::: args.tail }
+ catch { case ex: IOException => errorAndNotOk(ex.getMessage) }
+
+ // true if it's a legit looking source file
+ def isSourceFile(x: String) =
+ (settings.script.value != "") ||
+ (fileEndings exists (ext => x endsWith ext))
+
+ // given an option for scalac finds out what it is
+ def doOption(x: String): Unit = {
+ if (interactive)
+ return errorAndNotOk("no options can be given in interactive mode")
+
+ val argsLeft = settings.parseParams(args)
+ if (args != argsLeft) args = argsLeft
+ else errorAndNotOk("bad option: '" + x + "'")
+ }
- while (!args.isEmpty && ok) {
- if (args.head startsWith "@") {
- try {
- args = util.ArgumentsExpander.expandArg(args.head) ::: args.tail
- } catch {
- case ex: java.io.IOException =>
- error(ex.getMessage())
- ok = false
- }
- } else if (args.head startsWith "-") {
- if (interactive) {
- error("no options can be given in interactive mode")
- ok = false
- } else {
- val args0 = args
- for (setting <- settings.allSettings)
- if (args eq args0)
- args = setting.tryToSet(args)
-
- if (args eq args0) {
- error("bad option: '" + args.head + "'")
- ok = false
- }
- }
- } else if ((settings.script.value != "") ||
- (fileEnding.split("\\|") exists (args.head.endsWith(_)))) {
- fs = args.head :: fs
- args = args.tail
- } else if (args.head.length == 0) {//quick fix [martin: for what?]
- args = args.tail
- } else {
- error("don't know what to do with " + args.head)
- ok = false
- }
+ // cycle through args until empty or error
+ while (!args.isEmpty && ok) args.head match {
+ case x if x startsWith "@" => doExpand(x)
+ case x if x startsWith "-" => doOption(x)
+ case x if isSourceFile(x) => fs = x :: fs ; args = args.tail
+ case "" => args = args.tail // quick fix [martin: for what?]
+ case x => errorAndNotOk("don't know what to do with " + x)
}
+
ok &&= settings.checkDependencies
}
diff --git a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala
index a131a6e737..5c0f9c6d62 100644
--- a/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala
+++ b/src/compiler/scala/tools/nsc/GenericRunnerCommand.scala
@@ -20,7 +20,6 @@ extends CompilerCommand(allargs, settings, error, false, false)
def this(allargs: List[String]) =
this(allargs, str => Console.println("Error: " + str))
-
/** name of the associated compiler command */
val compCmdName = "scalac"
@@ -35,9 +34,7 @@ extends CompilerCommand(allargs, settings, error, false, false)
while (!args.isEmpty && ok && args.head.startsWith("-")) {
val args0 = args
- for (setting <- settings.allSettings)
- if (args eq args0)
- args = setting.tryToSet(args)
+ args = settings parseParams args
if (args eq args0) {
error("bad option: '" + args.head + "'")
ok = false
diff --git a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala
index fc69df6203..0e23681ed6 100644
--- a/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala
+++ b/src/compiler/scala/tools/nsc/GenericRunnerSettings.scala
@@ -7,9 +7,6 @@
package scala.tools.nsc
-import java.lang.System.getProperties
-import scala.collection.mutable.Queue
-
class GenericRunnerSettings(error: String => Unit)
extends Settings(error) {
val howtorun =
@@ -42,50 +39,5 @@ extends Settings(error) {
"-nocompdaemon",
"do not use the fsc compilation daemon")
-
- /** For some reason, "object defines extends Setting(...)"
- * does not work here. The object is present but the setting
- * is not added to allsettings. Thus,
- */
- class DefinesSetting extends Setting("set a Java property") {
-
- def name = "-D<prop>"
-
- private val props = new Queue[(String, String)]
-
- def value = props.toList
-
- def tryToSet(args: List[String]): List[String] = {
- args match {
- case arg0::rest
- if arg0.startsWith("-D") =>
- val stripD = arg0.substring(2)
- val eqidx = stripD.indexOf('=')
- val addition =
- if (eqidx < 0)
- (stripD, "")
- else
- (stripD.substring(0, eqidx), stripD.substring(eqidx+1))
- props += addition
- rest
-
- case _ => args
- }
- }
-
- /** Apply the specified properties to the current JVM */
- def applyToCurrentJVM = {
- val systemProps = getProperties
- for ((key, value) <- props.toList)
- systemProps.setProperty(key, value)
- }
-
- def unparse: List[String] =
- (props.toList.foldLeft[List[String]]
- (Nil)
- ((args, prop) =>
- ("-D" + prop._1 + "=" + prop._2) :: args))
- }
-
- val defines = new DefinesSetting
+ val defines = DefinesSetting
}
diff --git a/src/compiler/scala/tools/nsc/InterpreterCommand.scala b/src/compiler/scala/tools/nsc/InterpreterCommand.scala
index f46f995ba8..3ed91c156c 100644
--- a/src/compiler/scala/tools/nsc/InterpreterCommand.scala
+++ b/src/compiler/scala/tools/nsc/InterpreterCommand.scala
@@ -14,5 +14,5 @@ package scala.tools.nsc
class InterpreterCommand(arguments: List[String], error: String => Unit)
extends CompilerCommand(arguments, new Settings(error), error, false) {
override val cmdName = "scala"
- override lazy val fileEnding = ".scalaint"
+ override lazy val fileEndings = List(".scalaint")
}
diff --git a/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala b/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala
index 2290ce517d..0bd436018c 100644
--- a/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala
+++ b/src/compiler/scala/tools/nsc/OfflineCompilerCommand.scala
@@ -18,11 +18,13 @@ class OfflineCompilerCommand(
extends CompilerCommand(arguments, new Settings(error), error, false)
{
override val cmdName = "fsc"
- settings.disable(settings.prompt)
- settings.disable(settings.resident)
- new settings.BooleanSetting("-reset", "Reset compile server caches")
- new settings.BooleanSetting("-shutdown", "Shutdown compile server")
- new settings.StringSetting("-server", "hostname:portnumber",
- "Specify compile server socket", "")
- new settings.BooleanSetting("-J<flag>", "Pass <flag> directly to runtime system")
+ import settings._
+
+ disable(prompt)
+ disable(resident)
+
+ BooleanSetting("-reset", "Reset compile server caches")
+ BooleanSetting("-shutdown", "Shutdown compile server")
+ StringSetting ("-server", "hostname:portnumber", "Specify compile server socket", "")
+ BooleanSetting("-J<flag>", "Pass <flag> directly to runtime system")
}
diff --git a/src/compiler/scala/tools/nsc/ScriptRunner.scala b/src/compiler/scala/tools/nsc/ScriptRunner.scala
index 261c4e4a05..aa440adbf3 100644
--- a/src/compiler/scala/tools/nsc/ScriptRunner.scala
+++ b/src/compiler/scala/tools/nsc/ScriptRunner.scala
@@ -211,7 +211,7 @@ object ScriptRunner {
scriptFileIn: String): Boolean =
{
val scriptFile = CompileClient.absFileName(scriptFileIn)
- for (setting:settings.StringSetting <- List(
+ for (setting <- List(
settings.classpath,
settings.sourcepath,
settings.bootclasspath,
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index b60f54bb79..b1d7cddee9 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -7,32 +7,29 @@
package scala.tools.nsc
import java.io.File
-import java.lang.System
-
-class Settings(error: String => Unit) {
+import Settings._
+class Settings(errorFn: String => Unit) extends ScalacSettings {
def this() = this(Console.println)
- private var allsettings: List[Setting] = List()
-
// optionizes a system property
private def sysprop(name: String): Option[String] = onull(System.getProperty(name))
// given any number of possible path segments, flattens down to a
// :-separated style path
- protected def concatPath(segments: Option[String]*): String =
+ private def concatPath(segments: Option[String]*): String =
segments.toList.flatMap(x => x) mkString File.pathSeparator
- protected val classpathDefault =
+ protected def classpathDefault =
sysprop("env.classpath") orElse sysprop("java.class.path") getOrElse ""
- protected val bootclasspathDefault =
+ protected def bootclasspathDefault =
concatPath(sysprop("sun.boot.class.path"), guessedScalaBootClassPath)
- protected val extdirsDefault =
+ protected def extdirsDefault =
concatPath(sysprop("java.ext.dirs"), guessedScalaExtDirs)
- protected val pluginsDirDefault =
+ protected def pluginsDirDefault =
guess(List("misc", "scala-devel", "plugins"), _.isDirectory) getOrElse ""
def onull[T <: AnyRef](x: T): Option[T] = if (x eq null) None else Some(x)
@@ -53,99 +50,7 @@ class Settings(error: String => Unit) {
private def guessedScalaExtDirs: Option[String] =
guess(List("lib"), _.isDirectory)
- val debuginfo = new DebugSetting ("-g", "Specify level of generated debugging info", List("none", "source", "line", "vars", "notailcalls"), "vars", "vars")
- val nowarnings = BooleanSetting ("-nowarn", "Generate no warnings").hideToIDE
- val verbose = BooleanSetting ("-verbose", "Output messages about what the compiler is doing").hideToIDE
- val deprecation = BooleanSetting ("-deprecation", "Output source locations where deprecated APIs are used").hideToIDE
- val unchecked = BooleanSetting ("-unchecked", "Enable detailed unchecked warnings").hideToIDE
- val classpath = (new StringSetting ("-classpath", "path", "Specify where to find user class files", classpathDefault) { override val abbreviation = "-cp" }).hideToIDE
- val sourcepath = StringSetting ("-sourcepath", "path", "Specify where to find input source files", "").hideToIDE
- val bootclasspath = StringSetting ("-bootclasspath", "path", "Override location of bootstrap class files", bootclasspathDefault).hideToIDE
- val extdirs = StringSetting ("-extdirs", "dirs", "Override location of installed extensions", extdirsDefault).hideToIDE
- val outdir = StringSetting ("-d", "directory", "Specify where to place generated class files", ".").hideToIDE
- val encoding = StringSetting ("-encoding", "encoding", "Specify character encoding used by source files", Properties.encodingString).hideToIDE
- val target = ChoiceSetting ("-target", "Specify for which target object files should be built", List("jvm-1.5", "jvm-1.4", "msil"), "jvm-1.5")
- val printLate = BooleanSetting ("-print", "Print program with all Scala-specific features removed").hideToIDE
- val XO = BooleanSetting ("-optimise", "Generates faster bytecode by applying optimisations to the program")
- val explaintypes = BooleanSetting ("-explaintypes", "Explain type errors in more detail").hideToIDE
- val uniqid = BooleanSetting ("-uniqid", "Print identifiers with unique names for debugging").hideToIDE
- val version = BooleanSetting ("-version", "Print product version and exit").hideToIDE
- val dependenciesFile = StringSetting ("-dependencyfile", "file", "Specify the file in which dependencies are tracked", ".scala_dependencies")
- val make = ChoiceSetting ("-make", "Specify the behaviour for selecting which files need to be recompiled", List("all", "changed", "immediate", "transitive"), "all")
- val help = BooleanSetting ("-help", "Print a synopsis of standard options").hideToIDE
- val Xhelp = BooleanSetting ("-X", "Print a synopsis of advanced options").hideToIDE
- val argfiles = BooleanSetting ("@<file>", "A text file containing compiler arguments (options and source files)") // only for the help message
-
- val assemname = StringSetting ("-Xassem", "file", "Name of the output assembly (only relevant with -target:msil)", "").dependsOn(target, "msil").hideToIDE
- val assemrefs = StringSetting ("-Xassem-path", "path", "List of assemblies referenced by the program (only relevant with -target:msil)", ".").dependsOn(target, "msil").hideToIDE
- val Xchecknull = BooleanSetting ("-Xcheck-null", "Emit warning on selection of nullable reference")
- val Xwarninit = BooleanSetting ("-Xwarninit", "Warn about possible changes in initialization semantics")
- val checkInit = BooleanSetting ("-Xcheckinit", "Add runtime checks on field accessors. Uninitialized accesses result in an exception being thrown.")
- val noassertions = BooleanSetting ("-Xdisable-assertions", "Generate no assertions and assumptions")
- val Xexperimental = BooleanSetting ("-Xexperimental", "Enable experimental extensions")
- val XlogImplicits = BooleanSetting ("-Xlog-implicits", "Show more info on why some implicits are not applicable")
- val Xnojline = new BooleanSetting("-Xnojline", "Do not use JLine for editing").hideToIDE
- val nouescape = BooleanSetting ("-Xno-uescape", "Disables handling of \\u unicode escapes")
- val plugin = MultiStringSetting("-Xplugin", "file", "Load a plugin from a file")
- val disable = MultiStringSetting("-Xplugin-disable", "plugin", "Disable a plugin")
- val showPlugins = BooleanSetting ("-Xplugin-list", "Print a synopsis of loaded plugins").hideToIDE
- val pluginOptions = new MultiStringSetting("-P", "plugin:opt", "Pass an option to a plugin") { override def helpSyntax = "-P:<plugin>:<opt>" }
- val require = MultiStringSetting("-Xplugin-require", "plugin", "Abort unless a plugin is available")
- val pluginsDir = StringSetting ("-Xpluginsdir", "path", "Location to find compiler plugins", pluginsDirDefault)
- val print = PhasesSetting ("-Xprint", "Print out program after")
- val writeICode = BooleanSetting ("-Xprint-icode", "Log internal icode to *.icode files").hideToIDE
- val Xprintpos = BooleanSetting ("-Xprint-pos", "Print tree positions (as offsets)").hideToIDE
- val printtypes = BooleanSetting ("-Xprint-types", "Print tree types (debugging option)").hideToIDE
- val prompt = BooleanSetting ("-Xprompt", "Display a prompt after each error (debugging option)").hideToIDE
- val resident = BooleanSetting ("-Xresident", "Compiler stays resident, files to compile are read from standard input").hideToIDE
- val Xshowcls = StringSetting ("-Xshow-class", "class", "Show class info", "").hideToIDE
- val Xshowobj = StringSetting ("-Xshow-object", "object", "Show object info", "").hideToIDE
- val showPhases = BooleanSetting ("-Xshow-phases", "Print a synopsis of compiler phases").hideToIDE
- val genPhaseGraph = StringSetting ("-Xgenerate-phase-graph", "filename", "Generate the phase graphs (outputs .dot files) to filenameX.dot", "").hideToIDE
- val sourceReader = StringSetting ("-Xsource-reader", "classname", "Specify a custom method for reading source files", "scala.tools.nsc.io.SourceReader").hideToIDE
- val future = BooleanSetting ("-Xfuture", "Turn on future language features")
-
- val Yhelp = BooleanSetting ("-Y", "Print a synopsis of private options").hideToIDE
- val browse = PhasesSetting ("-Ybrowse", "Browse the abstract syntax tree after")
- val check = PhasesSetting ("-Ycheck", "Check the tree at the end of")
- val Xcloselim = BooleanSetting ("-Yclosure-elim", "Perform closure elimination")
- val Xcodebase = StringSetting ("-Ycodebase", "codebase", "Specify the URL containing the Scala libraries", "").hideToIDE
- val debug = BooleanSetting ("-Ydebug", "Output debugging messages").hideToIDE
- val debugger = BooleanSetting ("-Ydebugger", "Enable interactive debugger").hideToIDE
- val Xdce = BooleanSetting ("-Ydead-code", "Perform dead code elimination")
- val Xdetach = BooleanSetting ("-Ydetach", "Perform detaching of remote closures")
-// val doc = BooleanSetting ("-Ydoc", "Generate documentation").hideToIDE
- val inline = BooleanSetting ("-Yinline", "Perform inlining when possible")
- val Xlinearizer = ChoiceSetting ("-Ylinearizer", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo")
- val log = PhasesSetting ("-Ylog", "Log operations in")
- val noimports = BooleanSetting ("-Yno-imports", "Compile without any implicit imports")
- val nopredefs = BooleanSetting ("-Yno-predefs", "Compile without any implicit predefined values")
- val Yrecursion = IntSetting ("-Yrecursion", "Recursion depth used when locking symbols", 0, Some(0), None).hideToIDE
- val script = StringSetting ("-Xscript", "object", "Compile as a script, wrapping the code into object.main()", "").hideToIDE
-
- val Xshowtrees = BooleanSetting ("-Yshow-trees", "Show detailed trees when used in connection with -print:phase").hideToIDE
- val skip = PhasesSetting ("-Yskip", "Skip")
- val completion = BooleanSetting ("-Ycompletion", "Enable tab-completion in the REPL").hideToIDE
- val Xsqueeze = ChoiceSetting ("-Ysqueeze", "if on, creates compact code in matching", List("on","on","off"), "on").hideToIDE
- val statistics = BooleanSetting ("-Ystatistics", "Print compiler statistics").hideToIDE
- val stop = PhasesSetting ("-Ystop", "Stop after phase")
- val refinementMethodDispatch
- = ChoiceSetting ("-Ystruct-dispatch", "Selects what dispatch method to use for structural refinement method calls", List("no-cache", "mono-cache", "poly-cache"), "poly-cache").hideToIDE
- val Xwarndeadcode = BooleanSetting ("-Ywarn-dead-code", "Emit warnings for dead code")
- val Ynogenericsig = BooleanSetting ("-Yno-generic-signatures", "Suppress generation of generic signatures for Java")
-
- val XnoVarargsConversion = BooleanSetting("-Xno-varargs-conversion", "disable varags conversion")
- val selfInAnnots = BooleanSetting ("-Yself-in-annots", "Include a \"self\" identifier inside of annotations")
-
- val suppressVTWarn = BooleanSetting ("-Ysuppress-vt-typer-warnings", "Suppress warnings from the typer when testing the virtual class encoding, NOT FOR FINAL!")
-
- /** A list of all settings */
- def allSettings: List[Setting] = allsettings.reverse
- /** Disable a setting */
- def disable(s: Setting) = {
- allsettings = allsettings filter (s !=)
- }
-
+ override def hashCode() = allSettings.hashCode
override def equals(that: Any) = that match {
case s: Settings => this.allSettings == s.allSettings
case _ => false
@@ -158,97 +63,273 @@ class Settings(error: String => Unit) {
case cs: ChoiceSetting => cs.value == value
case _ => "" == value
}
- var ok = true
- for (setting <- allsettings if !setting.dependency.isEmpty) {
- val (dep, value) = setting.dependency.get
- if (! (setting.isDefault || hasValue(dep, value))) {
- error("incomplete option " + setting.name + " (requires " + dep.name + ")")
- ok = false
+
+ for (setting <- allSettings ; (dep, value) <- setting.dependency)
+ if (!setting.isDefault && !hasValue(dep, value)) {
+ errorFn("incomplete option " + setting.name + " (requires " + dep.name + ")")
+ return false
}
- }
- ok
+
+ true
}
- /** Try to add additional command line parameters. */
- def parseParams(line: String, error: String => Nothing) {
- var args =
- if (line.trim() == "") Nil
- else List.fromArray(line.trim().split(" ")).map(_.trim())
- while (!args.isEmpty) {
- val argsBuf = args
- if (args.head startsWith "-") {
- for (setting <- allSettings)
- args = setting.tryToSet(args);
+ /** Try to add additional command line parameters.
+ * Returns unconsumed arguments.
+ */
+ def parseParams(line: String): List[String] =
+ parseParams(line.trim.split("""\s+""").toList)
+
+ def parseParams(args: List[String]): List[String] = {
+ // verify command exists and call setter
+ def tryToSetIfExists(
+ cmd: String,
+ args: List[String],
+ setter: (Setting) => (List[String] => Option[List[String]])
+ ): Option[List[String]] =
+ lookupSetting(cmd) match {
+ case None => errorFn("Parameter '" + cmd + "' is not recognised by Scalac.") ; None
+ case Some(cmd) => setter(cmd)(args)
}
- else error("Parameter '" + args.head + "' does not start with '-'.")
- if (argsBuf eq args)
- error("Parameter '" + args.head + "' is not recognised by Scalac.")
+
+ // if arg is of form -Xfoo:bar,baz,quux
+ def parseColonArg(s: String): Option[List[String]] = {
+ val idx = s.findIndexOf(_ == ':')
+ val (p, args) = (s.substring(0, idx), s.substring(idx+1).split(",").toList)
+
+ // any non-Nil return value means failure and we return s unmodified
+ tryToSetIfExists(p, args, (s: Setting) => s.tryToSetColon _)
+ }
+ // if arg is of form -Dfoo=bar or -Dfoo (name = "-D")
+ def isPropertyArg(s: String) = lookupSetting(s.substring(0, 2)) match {
+ case Some(x: DefinesSetting) => true
+ case _ => false
+ }
+ def parsePropertyArg(s: String): Option[List[String]] = {
+ val (p, args) = (s.substring(0, 2), s.substring(2))
+
+ tryToSetIfExists(p, List(args), (s: Setting) => s.tryToSetProperty _)
}
+
+ // if arg is of form -Xfoo or -Xfoo bar (name = "-Xfoo")
+ def parseNormalArg(p: String, args: List[String]): Option[List[String]] =
+ tryToSetIfExists(p, args, (s: Setting) => s.tryToSet _)
+
+ def doArgs(args: List[String]): List[String] = {
+ if (args.isEmpty) return Nil
+ val p = args.head
+ if (!p.startsWith("-")) {
+ errorFn("Parameter '" + p + "' does not start with '-'.")
+ return args
+ }
+ else if (p == "-") {
+ errorFn("'-' is not a valid argument.")
+ return args
+ }
+
+ // we dispatch differently based on the appearance of p:
+ // 1) If it has a : it is presumed to be -Xfoo:bar,baz
+ // 2) If the first two chars are the name of a command, -Dfoo=bar
+ // 3) Otherwise, the whole string should be a command name
+ //
+ // Internally we use Option[List[String]] to discover error,
+ // but the outside expects our arguments back unchanged on failure
+ if (p contains ":") parseColonArg(p) match {
+ case Some(_) => args.tail
+ case None => args
+ }
+ else if (isPropertyArg(p)) parsePropertyArg(p) match {
+ case Some(_) => args.tail
+ case None => args
+ }
+ else parseNormalArg(p, args.tail) match {
+ case Some(xs) => xs
+ case None => args
+ }
+ }
+
+ doArgs(args)
+ }
+
+ // checks both name and any available abbreviations
+ def lookupSetting(cmd: String): Option[Setting] =
+ settingSet.find(x => x.name == cmd || (x.abbreviations contains cmd))
+
+ // The *Setting classes used to be case classes defined inside of Settings.
+ // The choice of location was poor because it tied the type of each setting
+ // to its enclosing instance, which broke equality, so I moved the class
+ // definitions into the companion object. The one benefit it was getting
+ // out of this was using its knowledge of the enclosing instance to add
+ // itself to the list of settings in the Setting constructor. However,
+ // this was dicey and not working predictably, as illustrated in the comment
+ // in GenericRunnerSettings:
+ //
+ // For some reason, "object defines extends Setting(...)"
+ // does not work here. The object is present but the setting
+ // is not added to allsettings.
+ //
+ // To capture similar semantics, I created instance methods on setting
+ // which call a factory method for the right kind of object and then add
+ // the newly constructed instance to allsettings. The constructors are
+ // private to force all creation to go through these methods.
+ //
+ // The usage of case classes was becoming problematic (due to custom
+ // equality, case class inheritance, and the need to control object
+ // creation without a synthetic apply method getting in the way) and
+ // it was providing little benefit, so they are no longer cases.
+
+ // a wrapper for all Setting creators to keep our list up to date
+ // and tell them how to announce errors
+ private def add[T <: Setting](s: T): T = {
+ s setErrorHandler errorFn
+ allsettings += s
+ s
+ }
+
+ /**
+ * The canonical creators for Setting objects.
+ */
+ import Function.{ tupled, untupled }
+ import Setting._
+
+ // A bit too clever, but I haven't found any other way to compose
+ // functions with arity 2+ without having to annotate parameter types
+ lazy val IntSetting = untupled(tupled(sint _) andThen add[IntSetting])
+ lazy val BooleanSetting = untupled(tupled(bool _) andThen add[BooleanSetting])
+ lazy val StringSetting = untupled(tupled(str _) andThen add[StringSetting])
+ lazy val MultiStringSetting = untupled(tupled(multi _) andThen add[MultiStringSetting])
+ lazy val ChoiceSetting = untupled(tupled(choice _) andThen add[ChoiceSetting])
+ lazy val DebugSetting = untupled(tupled(sdebug _) andThen add[DebugSetting])
+ lazy val PhasesSetting = untupled(tupled(phase _) andThen add[PhasesSetting])
+ lazy val DefinesSetting = add(defines())
+}
+
+object Settings
+{
+ // basically this is a value which remembers if it's been modified
+ trait SettingValue {
+ type T <: Any
+ protected var v: T
+ private var setByUser: Boolean = false
+ def isDefault: Boolean = !setByUser
+ def value: T = v
+ def value_=(arg: T) = { setByUser = true ; v = arg }
+ }
+
+ // The Setting companion object holds all the factory methods
+ object Setting {
+ def bool(name: String, descr: String) =
+ new BooleanSetting(name, descr)
+
+ def str(name: String, arg: String, descr: String, default: String) =
+ new StringSetting(name, arg, descr, default)
+
+ def sint(name: String, descr: String, default: Int, min: Option[Int], max: Option[Int]) =
+ new IntSetting(name, descr, default, min, max)
+
+ def multi(name: String, arg: String, descr: String) =
+ new MultiStringSetting(name, arg, descr)
+
+ def choice(name: String, descr: String, choices: List[String], default: String): ChoiceSetting =
+ new ChoiceSetting(name, descr, choices, default)
+
+ def sdebug(name: String, descr: String, choices: List[String], default: String, defaultEmpty: String) =
+ new DebugSetting(name, descr, choices, default, defaultEmpty)
+
+ def phase(name: String, descr: String) =
+ new PhasesSetting(name, descr)
+
+ def defines() = new DefinesSetting()
}
/** A base class for settings of all types.
* Subclasses each define a `value' field of the appropriate type.
*/
- abstract class Setting(descr: String) {
-
+ abstract class Setting(descr: String) extends Ordered[Setting] with SettingValue {
/** The name of the option as written on the command line, '-' included. */
def name: String
- /** If first arg defines this setting, consume it as well as all following
- * args needed to define the setting. If this can be done without
- * error, set value field and return suffix of args else
- * issue error message and return the arguments unchanged.
- * If first arg does not define this setting return args unchanged.
+ /** Error handling function, set after creation by enclosing Settings instance */
+ private var _errorFn: String => Unit = _
+ private[Settings] def setErrorHandler(e: String => Unit) = _errorFn = e
+ def errorFn(msg: String) = _errorFn(msg)
+ def errorAndValue[T](msg: String, x: T): T = { errorFn(msg) ; x }
+
+ /** After correct Setting has been selected, tryToSet is called with the
+ * remainder of the command line. It consumes any applicable arguments and
+ * returns the unconsumed ones.
+ */
+ private[Settings] def tryToSet(args: List[String]): Option[List[String]]
+
+ /** Commands which can take lists of arguments in form -Xfoo:bar,baz override
+ * this method and accept them as a list. It returns List[String] for
+ * consistency with tryToSet, and should return its incoming arguments
+ * unmodified on failure, and Nil on success.
+ */
+ private[Settings] def tryToSetColon(args: List[String]): Option[List[String]] =
+ errorAndValue("'" + name + "' does not accept multiple arguments", None)
+
+ /** Commands which take properties in form -Dfoo=bar or -Dfoo
*/
- def tryToSet(args: List[String]): List[String]
+ private[Settings] def tryToSetProperty(args: List[String]): Option[List[String]] =
+ errorAndValue("'" + name + "' does not accept property style arguments", None)
/** The syntax defining this setting in a help string */
- def helpSyntax: String = name
+ private var _helpSyntax = name
+ def helpSyntax: String = _helpSyntax
+ def withHelpSyntax(s: String): this.type = { _helpSyntax = s ; this }
+
+ /** Abbreviations for this setting */
+ private var _abbreviations: List[String] = Nil
+ def abbreviations = _abbreviations
+ def withAbbreviation(s: String): this.type = { _abbreviations ++= List(s) ; this }
/** A description of the purpose of this setting in a help string */
def helpDescription = descr
- /** Return a list of strings that can be used to recreate
- * the receiver's current setting.
- */
+ /** A list of Strings which can recreate this setting. */
def unparse: List[String]
- /** override if option should be hidden from IDE.
- */
- var hiddenToIDE: Boolean = false
- def hideToIDE: this.type = {
- hiddenToIDE = true
- this
- }
- def showToIDE: this.type = {
- hiddenToIDE = false
- this
- }
-
- protected var setByUser: Boolean = false
- def isDefault: Boolean = !setByUser
+ /** Set to false if option should be shown to IDE. */
+ var hiddenToIDE: Boolean = true
+ def showToIDE() = hiddenToIDE = false
+ /** Optional dependency on another setting */
protected[Settings] var dependency: Option[(Setting, String)] = None
def dependsOn(s: Setting, value: String): this.type = { dependency = Some((s, value)); this }
def dependsOn(s: Setting): this.type = dependsOn(s, "")
- def isStandard: Boolean = !isAdvanced && !isPrivate && !(name eq "-Y")
- def isAdvanced: Boolean =
- (name startsWith "-X") && !(name eq "-X")
- def isPrivate: Boolean =
- (name == "-P") || ((name startsWith "-Y") && !(name eq "-Y"))
- def equalLists[T <% Ordered[T]](xs: List[T], ys: List[T]) = xs.sort(_ < _) == ys.sort(_ < _)
-
-/*
- def isDocOption: Boolean =
- !dependency.isEmpty && dependency.get._1 == doc
-*/
- // initialization
- allsettings = this :: allsettings
+ def isStandard: Boolean = !isAdvanced && !isPrivate && name != "-Y"
+ def isAdvanced: Boolean = (name startsWith "-X") && name != "-X"
+ def isPrivate: Boolean = (name == "-P") || ((name startsWith "-Y") && name != "-Y")
+
+ // Ordered (so we can use TreeSet)
+ def compare(that: Setting): Int = name compare that.name
+ def compareLists[T <% Ordered[T]](xs: List[T], ys: List[T]) = xs.sort(_ < _) == ys.sort(_ < _)
+
+ // Equality
+ def eqValues: List[Any] = List(name, value)
+ def isEq(other: this.type) = eqValues == other.eqValues
+ override def hashCode() = name.hashCode
+ override def equals(that: Any) = that match {
+ case x: this.type => this isEq x
+ case _ => false
+ }
}
/** A setting represented by a positive integer */
- case class IntSetting(name: String, descr: String, default: Int, min: Option[Int], max: Option[Int]) extends Setting(descr) {
+ class IntSetting private[Settings](
+ val name: String,
+ val descr: String,
+ val default: Int,
+ val min: Option[Int],
+ val max: Option[Int])
+ extends Setting(descr)
+ {
+ type T = Int
+ protected var v = default
+ override def value_=(s: Int) =
+ if (isInputValid(s)) super.value_=(s) else errorMsg
+
// Validate that min and max are consistent
(min, max) match {
case (Some(i), Some(j)) => assert(i <= j)
@@ -256,248 +337,149 @@ class Settings(error: String => Unit) {
}
// Helper to validate an input
- private def isInputValid(k: Int): Boolean =
- (min, max) match {
- case (Some(i), Some(j)) => (i <= k) && (k <= j)
- case (Some(i), None) => (i <= k)
- case (None, Some(j)) => (k <= j)
- case _ => true
- }
+ private def isInputValid(k: Int): Boolean = (min, max) match {
+ case (Some(i), Some(j)) => (i <= k) && (k <= j)
+ case (Some(i), None) => (i <= k)
+ case (None, Some(j)) => (k <= j)
+ case _ => true
+ }
// Helper to generate a textual explaination of valid inputs
- private def getValidText: String =
- (min, max) match {
- case (Some(i), Some(j)) => "must be between "+i+" and "+j
- case (Some(i), None) => "must be greater than or equal to "+i
- case (None, Some(j)) => "must be less than or equal to "+j
- case _ => throw new Error("this should never be used")
- }
+ private def getValidText: String = (min, max) match {
+ case (Some(i), Some(j)) => "must be between "+i+" and "+j
+ case (Some(i), None) => "must be greater than or equal to "+i
+ case (None, Some(j)) => "must be less than or equal to "+j
+ case _ => throw new Error("this should never be used")
+ }
// Ensure that the default value is actually valid
assert(isInputValid(default))
- protected var v: Int = default
-
- def errorMsg = error("invalid setting for -"+name+" "+getValidText)
+ def parseInt(x: String): Option[Int] =
+ try { Some(x.toInt) }
+ catch { case _: NumberFormatException => None }
- def value: Int = this.v
- def value_=(s: Int) {
- if (!isInputValid(s)) errorMsg
- setByUser = true;
- this.v = s
- }
+ def errorMsg = errorFn("invalid setting for -"+name+" "+getValidText)
- def tryToSet(args: List[String]): List[String] = args match {
- case n :: rest if (name == n) =>
- if (rest.isEmpty) {
- error("missing argument")
- args
- } else {
- try {
- value = rest.head.toInt
- } catch {
- case e: java.lang.NumberFormatException => errorMsg
- }
- rest.tail
- }
- case _ => args
- }
+ def tryToSet(args: List[String]) =
+ if (args.isEmpty) errorAndValue("missing argument", None)
+ else parseInt(args.head) match {
+ case Some(i) => value = i ; Some(args.tail)
+ case None => errorMsg ; None
+ }
def unparse: List[String] =
- if (value == default) Nil else List(name, value.toString)
-
- override def equals(that: Any) = that match {
- case is: Settings#IntSetting => this.name == is.name && this.value == is.value
- case _ => false
- }
-
+ if (value == default) Nil
+ else List(name, value.toString)
}
/** A setting represented by a boolean flag (false, unless set) */
- case class BooleanSetting(name: String, descr: String) extends Setting(descr) {
- protected var v: Boolean = false
-
- def value: Boolean = this.v
- def value_=(s: Boolean) { setByUser = true; this.v = s }
-
- def tryToSet(args: List[String]): List[String] = args match {
- case n :: rest if (n == name) => value = true; rest
- case _ => args
- }
-
+ class BooleanSetting private[Settings](
+ val name: String,
+ val descr: String)
+ extends Setting(descr)
+ {
+ type T = Boolean
+ protected var v = false
+
+ def tryToSet(args: List[String]) = { value = true ; Some(args) }
def unparse: List[String] = if (value) List(name) else Nil
-
- override def equals(that: Any) = that match {
- case bs: Settings#BooleanSetting => this.name == bs.name && this.value == bs.value
- case _ => false
- }
-
}
/** A setting represented by a string, (`default' unless set) */
- case class StringSetting(name: String, arg: String, descr: String, default: String)
- extends Setting(descr) {
- def abbreviation: String = null
-
- protected var v: String = default
-
- def value: String = this.v
- def value_=(s: String) { setByUser = true; this.v = s }
-
- def tryToSet(args: List[String]): List[String] = args match {
- case n :: rest if (name == n || abbreviation == n) =>
- if (rest.isEmpty) {
- error("missing argument")
- args
- } else {
- value = rest.head
- rest.tail
- }
- case _ => args
- }
-
- override def helpSyntax = name + " <" + arg + ">"
-
- def unparse: List[String] =
- if (value == default) Nil else List(name, value)
-
- override def equals(that: Any) = that match {
- case ss: Settings# StringSetting => this.name == ss.name && this.value == ss.value
- case _ => false
+ class StringSetting private[Settings](
+ val name: String,
+ val arg: String,
+ val descr: String,
+ val default: String)
+ extends Setting(descr)
+ {
+ type T = String
+ protected var v = default
+
+ def tryToSet(args: List[String]) = args match {
+ case Nil => errorAndValue("missing argument", None)
+ case x :: xs => value = x ; Some(xs)
}
+ def unparse: List[String] = if (value == default) Nil else List(name, value)
+ withHelpSyntax(name + " <" + arg + ">")
}
/** A setting that accumulates all strings supplied to it */
- case class MultiStringSetting(name: String, arg: String, descr: String)
- extends Setting(descr) {
- hideToIDE
+ class MultiStringSetting private[Settings](
+ val name: String,
+ val arg: String,
+ val descr: String)
+ extends Setting(descr)
+ {
+ type T = List[String]
protected var v: List[String] = Nil
- def value = v
- def appendToValue(str: String) { v = v ::: List(str) }
-
- protected val nameColon = name + ":"
- def tryToSet(args: List[String]): List[String] = args match {
- case arg :: rest if (arg startsWith nameColon) =>
- val toadd = arg.substring(nameColon.length())
- if (toadd.length == 0) {
- error("empty argument to " + nameColon)
- args
- } else {
- appendToValue(toadd)
- rest
- }
-
- case opt :: arg :: rest if (opt == name) =>
- appendToValue(arg)
- rest
-
- case _ => args
- }
-
- override def helpSyntax = name + ":<" + arg + ">"
+ def appendToValue(str: String) { value ++= List(str) }
- def unparse: List[String] =
- for (opt <- value) yield nameColon+opt
-
- override def equals(that: Any) = that match {
- case mss: Settings# MultiStringSetting =>
- this.name == mss.name && equalLists(this.value, mss.value)
- case _ => false
+ def tryToSet(args: List[String]) = {
+ args foreach appendToValue
+ Some(Nil)
}
+ override def tryToSetColon(args: List[String]) = tryToSet(args)
+ def unparse: List[String] = value map { name + ":" + _ }
+ withHelpSyntax(name + ":<" + arg + ">")
}
/** A setting represented by a string in a given set of <code>choices</code>,
* (<code>default</code> unless set).
*/
- case class ChoiceSetting(name: String, descr: String, choices: List[String], default: String)
- extends Setting(descr + choices.mkString(" (", ",", ")")) {
+ class ChoiceSetting private[Settings](
+ val name: String,
+ val descr: String,
+ val choices: List[String],
+ val default: String)
+ extends Setting(descr + choices.mkString(" (", ",", ")"))
+ {
+ type T = String
protected var v: String = default
-
- def value: String = this.v
- def value_=(s: String) { setByUser = true; this.v = s }
-
protected def argument: String = name.substring(1)
- def tryToSet(args: List[String]): List[String] = args match {
- case n :: rest if (n startsWith (name + ":")) =>
- val choice = n.substring(name.length() + 1)
- if (!(choices contains choice)) {
- error(
- if (choice == "") "missing " + argument
- else "unknown " + argument + " '" + choice + "'")
- args
- } else {
- value = choice
- rest
- }
- case n :: choice :: rest if n == name => // alternative to be consistent with IDE
- if (!(choices contains choice)) {
- error(
- if (choice == "") "missing " + argument
- else "unknown " + argument + " '" + choice + "'")
- args
- } else {
- value = choice
- rest
- }
- case _ => args
+ def tryToSet(args: List[String]) = { value = default ; Some(args) }
+ override def tryToSetColon(args: List[String]) = args match {
+ case Nil => errorAndValue("missing " + argument, None)
+ case List(x) if choices contains x => value = x ; Some(Nil)
+ case List(x) => errorAndValue("'" + x + "' is not a valid choice for '" + name + "'", None)
+ case xs => errorAndValue("'" + name + "' does not accept multiple arguments.", None)
}
-
- override def helpSyntax = name + ":<" + argument + ">"
-
def unparse: List[String] =
if (value == default) Nil else List(name + ":" + value)
- override def equals(that: Any) = that match {
- case cs: Settings# ChoiceSetting => this.name == cs.name && this.value == cs.value
- case _ => false
- }
-
+ withHelpSyntax(name + ":<" + argument + ">")
}
/** Same as ChoiceSetting but have a <code>level</code> int which tells the
* index of the selected choice. The <code>defaultEmpty</code> is used when
* this setting is used without specifying any of the available choices.
*/
- class DebugSetting(name: String, descr: String, choices: List[String], default: String, defaultEmpty: String)
- extends ChoiceSetting(name, descr, choices, default) {
-
- def indexOf[a](xs: List[a], e: a): Option[Int] = xs match {
- case y :: ys => if (e == y) Some(0) else indexOf(ys, e) match {
- case Some(idx) => Some(1 + idx)
- case None => None
- }
- case _ => None
+ class DebugSetting private[Settings](
+ name: String,
+ descr: String,
+ choices: List[String],
+ default: String,
+ val defaultEmpty: String)
+ extends ChoiceSetting(name, descr, choices, default)
+ {
+ def indexOf[T](xs: List[T], e: T): Option[Int] = xs.indexOf(e) match {
+ case -1 => None
+ case x => Some(x)
}
var level: Int = indexOf(choices, default).get
- override def value_=(choice: String) {
- setByUser = true
- this.v = choice
- this.level = indexOf(choices, choice).get
+ override def value_=(choice: String) = {
+ super.value_=(choice)
+ level = indexOf(choices, choice).get
}
- override def tryToSet(args: List[String]): List[String] = args match {
- case n :: rest if (n startsWith (name + ":")) =>
- val choice = n.substring(name.length() + 1)
- if (!(choices contains choice)) {
- error(
- if (choice == "") "missing " + argument
- else "unknown " + argument + " '" + choice + "'")
- args
- } else {
- value = choice
- rest
- }
-
- case n :: rest if (n startsWith name) =>
- value = defaultEmpty
- rest
-
- case _ => args
- }
+ override def tryToSet(args: List[String]) =
+ if (args.isEmpty) { value = defaultEmpty ; Some(Nil) }
+ else super.tryToSet(args)
}
/** A setting represented by a list of strings which should be prefixes of
@@ -505,43 +487,204 @@ class Settings(error: String => Unit) {
* "all" can be used to represent all phases.
* (the empty list, unless set)
*/
- case class PhasesSetting(name: String, descr: String)
- extends Setting(descr + " <phase> or \"all\"") {
- hideToIDE
- protected var v: List[String] = List()
-
- def value: List[String] = this.v
- def value_=(s: List[String]) { setByUser = true; this.v = s }
- def doAllPhases() = value contains "all"
+ class PhasesSetting private[Settings](
+ val name: String,
+ val descr: String)
+ extends Setting(descr + " <phase> or \"all\"")
+ {
+ type T = List[String]
+ protected var v: List[String] = Nil
- def tryToSet(args: List[String]): List[String] = args match {
- case n :: rest if (n startsWith (name + ":")) =>
- val phase = n.substring(name.length() + 1)
- if (phase == "") {
- error("missing phase")
- args
- } else {
- value = value ::: List(phase)
- rest
- }
- case _ => args
+ def tryToSet(args: List[String]) = errorAndValue("missing phase", None)
+ override def tryToSetColon(args: List[String]) = args match {
+ case Nil => errorAndValue("missing phase", None)
+ case xs => value ++= xs ; Some(Nil)
}
-
- override def helpSyntax = name + ":<phase>"
-
// 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(phasename: String): Boolean =
- doAllPhases || (value exists (str => phasename startsWith str))
+ doAllPhases || (value exists { phasename startsWith _ } )
- def unparse: List[String] = value.map(phase => name + ":" + phase)
+ def doAllPhases() = value contains "all"
+ def unparse: List[String] = value map { name + ":" + _ }
override def equals(that: Any) = that match {
- case ps: Settings#PhasesSetting =>
- (this.name == ps.name) &&
- (this.doAllPhases && ps.doAllPhases || equalLists(this.value, ps.value))
- case _ => false
+ case ps: PhasesSetting if name == ps.name =>
+ (doAllPhases && ps.doAllPhases) || compareLists(value, ps.value)
+ case _ => false
+ }
+
+ withHelpSyntax(name + ":<phase>")
+ }
+
+ /** A setting for a -D style property definition */
+ class DefinesSetting private[Settings] extends Setting("set a Java property")
+ {
+ type T = List[(String, String)]
+ protected var v: T = Nil
+ def name = "-D"
+ withHelpSyntax(name + "<prop>")
+
+ // given foo=bar returns Some(foo, bar), or None if parse fails
+ def parseArg(s: String): Option[(String, String)] = {
+ if (s == "") return None
+ val regexp = """^(.*)?=(.*)$""".r
+
+ regexp.findAllIn(s).matchData.toList match {
+ case Nil => Some(s, "")
+ case List(md) => md.subgroups match { case List(a,b) => Some(a,b) }
+ }
}
+ def tryToSet(args: List[String]) =
+ if (args.isEmpty) None
+ else parseArg(args.head) match {
+ case None => None
+ case Some((a, b)) => value ++= List((a, b)) ; Some(args.tail)
+ }
+
+ /** Apply the specified properties to the current JVM */
+ def applyToCurrentJVM =
+ value foreach { case (k, v) => System.getProperties.setProperty(k, v) }
+
+ def unparse: List[String] =
+ value map { case (k,v) => "-D" + k + (if (v == "") "" else "=" + v) }
+ }
+
+}
+
+trait ScalacSettings
+{
+ self: Settings =>
+
+ import collection.immutable.TreeSet
+
+ /** A list of all settings */
+ protected var allsettings: Set[Setting] = TreeSet[Setting]()
+ def settingSet: Set[Setting] = allsettings
+ def allSettings: List[Setting] = settingSet.toList
+
+ /** Disable a setting */
+ def disable(s: Setting) = allsettings -= s
+
+ /**
+ * Temporary Settings
+ */
+ val suppressVTWarn = BooleanSetting ("-Ysuppress-vt-typer-warnings", "Suppress warnings from the typer when testing the virtual class encoding, NOT FOR FINAL!")
+
+ /**
+ * Standard settings
+ */
+ // argfiles is only for the help message
+ val argfiles = BooleanSetting ("@<file>", "A text file containing compiler arguments (options and source files)")
+ val bootclasspath = StringSetting ("-bootclasspath", "path", "Override location of bootstrap class files", bootclasspathDefault)
+ val classpath = StringSetting ("-classpath", "path", "Specify where to find user class files", classpathDefault).withAbbreviation("-cp")
+ val outdir = StringSetting ("-d", "directory", "Specify where to place generated class files", ".")
+ val dependenciesFile = StringSetting ("-dependencyfile", "file", "Specify the file in which dependencies are tracked", ".scala_dependencies")
+ val deprecation = BooleanSetting ("-deprecation", "Output source locations where deprecated APIs are used")
+ val encoding = StringSetting ("-encoding", "encoding", "Specify character encoding used by source files", Properties.encodingString)
+ val explaintypes = BooleanSetting ("-explaintypes", "Explain type errors in more detail")
+ val extdirs = StringSetting ("-extdirs", "dirs", "Override location of installed extensions", extdirsDefault)
+ val debuginfo = DebugSetting ("-g", "Specify level of generated debugging info", List("none", "source", "line", "vars", "notailcalls"), "vars", "vars")
+ val help = BooleanSetting ("-help", "Print a synopsis of standard options")
+ val make = ChoiceSetting ("-make", "Specify recompilation detection strategy", List("all", "changed", "immediate", "transitive"), "all") .
+ withHelpSyntax("-make:<strategy>")
+ val nowarnings = BooleanSetting ("-nowarn", "Generate no warnings")
+ val XO = BooleanSetting ("-optimise", "Generates faster bytecode by applying optimisations to the program")
+ val printLate = BooleanSetting ("-print", "Print program with all Scala-specific features removed")
+ val sourcepath = StringSetting ("-sourcepath", "path", "Specify where to find input source files", "")
+ val target = ChoiceSetting ("-target", "Specify for which target object files should be built", List("jvm-1.5", "jvm-1.4", "msil"), "jvm-1.5")
+ val unchecked = BooleanSetting ("-unchecked", "Enable detailed unchecked warnings")
+ val uniqid = BooleanSetting ("-uniqid", "Print identifiers with unique names for debugging")
+ val verbose = BooleanSetting ("-verbose", "Output messages about what the compiler is doing")
+ val version = BooleanSetting ("-version", "Print product version and exit")
+
+ /**
+ * -X "Advanced" settings
+ */
+ val Xhelp = BooleanSetting ("-X", "Print a synopsis of advanced options")
+ val assemname = StringSetting ("-Xassem", "file", "Name of the output assembly (only relevant with -target:msil)", "").dependsOn(target, "msil")
+ val assemrefs = StringSetting ("-Xassem-path", "path", "List of assemblies referenced by the program (only relevant with -target:msil)", ".").dependsOn(target, "msil")
+ val Xchecknull = BooleanSetting ("-Xcheck-null", "Emit warning on selection of nullable reference")
+ val checkInit = BooleanSetting ("-Xcheckinit", "Add runtime checks on field accessors. Uninitialized accesses result in an exception being thrown.")
+ val noassertions = BooleanSetting ("-Xdisable-assertions", "Generate no assertions and assumptions")
+ val Xexperimental = BooleanSetting ("-Xexperimental", "Enable experimental extensions")
+ val future = BooleanSetting ("-Xfuture", "Turn on future language features")
+ val genPhaseGraph = StringSetting ("-Xgenerate-phase-graph", "file", "Generate the phase graphs (outputs .dot files) to fileX.dot", "")
+ val XlogImplicits = BooleanSetting ("-Xlog-implicits", "Show more info on why some implicits are not applicable")
+ val nouescape = BooleanSetting ("-Xno-uescape", "Disables handling of \\u unicode escapes")
+ val XnoVarargsConversion = BooleanSetting("-Xno-varargs-conversion", "disable varags conversion")
+ val Xnojline = BooleanSetting ("-Xnojline", "Do not use JLine for editing")
+ val plugin = MultiStringSetting("-Xplugin", "file", "Load a plugin from a file")
+ val disable = MultiStringSetting("-Xplugin-disable", "plugin", "Disable a plugin")
+ val showPlugins = BooleanSetting ("-Xplugin-list", "Print a synopsis of loaded plugins")
+ val require = MultiStringSetting("-Xplugin-require", "plugin", "Abort unless a plugin is available")
+ val pluginsDir = StringSetting ("-Xpluginsdir", "path", "Location to find compiler plugins", pluginsDirDefault)
+ val print = PhasesSetting ("-Xprint", "Print out program after")
+ val writeICode = BooleanSetting ("-Xprint-icode", "Log internal icode to *.icode files")
+ val Xprintpos = BooleanSetting ("-Xprint-pos", "Print tree positions (as offsets)")
+ val printtypes = BooleanSetting ("-Xprint-types", "Print tree types (debugging option)")
+ val prompt = BooleanSetting ("-Xprompt", "Display a prompt after each error (debugging option)")
+ val resident = BooleanSetting ("-Xresident", "Compiler stays resident, files to compile are read from standard input")
+ val script = StringSetting ("-Xscript", "object", "Compile as a script, wrapping the code into object.main()", "")
+ val Xshowcls = StringSetting ("-Xshow-class", "class", "Show class info", "")
+ val Xshowobj = StringSetting ("-Xshow-object", "object", "Show object info", "")
+ val showPhases = BooleanSetting ("-Xshow-phases", "Print a synopsis of compiler phases")
+ val sourceReader = StringSetting ("-Xsource-reader", "classname", "Specify a custom method for reading source files", "scala.tools.nsc.io.SourceReader")
+ val Xwarninit = BooleanSetting ("-Xwarninit", "Warn about possible changes in initialization semantics")
+
+ /**
+ * -Y "Private" settings
+ */
+ val Yhelp = BooleanSetting ("-Y", "Print a synopsis of private options")
+ val browse = PhasesSetting ("-Ybrowse", "Browse the abstract syntax tree after")
+ val check = PhasesSetting ("-Ycheck", "Check the tree at the end of")
+ val Xcloselim = BooleanSetting ("-Yclosure-elim", "Perform closure elimination")
+ val Xcodebase = StringSetting ("-Ycodebase", "codebase", "Specify the URL containing the Scala libraries", "")
+ val completion = BooleanSetting ("-Ycompletion", "Enable tab-completion in the REPL")
+ val Xdce = BooleanSetting ("-Ydead-code", "Perform dead code elimination")
+ val debug = BooleanSetting ("-Ydebug", "Output debugging messages")
+ val debugger = BooleanSetting ("-Ydebugger", "Enable interactive debugger")
+ val Xdetach = BooleanSetting ("-Ydetach", "Perform detaching of remote closures")
+ // val doc = BooleanSetting ("-Ydoc", "Generate documentation")
+ val inline = BooleanSetting ("-Yinline", "Perform inlining when possible")
+ val Xlinearizer = ChoiceSetting ("-Ylinearizer", "Linearizer to use", List("normal", "dfs", "rpo", "dump"), "rpo") .
+ withHelpSyntax("-Ylinearizer:<which>")
+ val log = PhasesSetting ("-Ylog", "Log operations in")
+ val Ynogenericsig = BooleanSetting ("-Yno-generic-signatures", "Suppress generation of generic signatures for Java")
+ val noimports = BooleanSetting ("-Yno-imports", "Compile without any implicit imports")
+ val nopredefs = BooleanSetting ("-Yno-predefs", "Compile without any implicit predefined values")
+ val Yrecursion = IntSetting ("-Yrecursion", "Recursion depth used when locking symbols", 0, Some(0), None)
+ val selfInAnnots = BooleanSetting ("-Yself-in-annots", "Include a \"self\" identifier inside of annotations")
+ val Xshowtrees = BooleanSetting ("-Yshow-trees", "Show detailed trees when used in connection with -print:phase")
+ val skip = PhasesSetting ("-Yskip", "Skip")
+ val Xsqueeze = ChoiceSetting ("-Ysqueeze", "if on, creates compact code in matching", List("on","off"), "on") .
+ withHelpSyntax("-Ysqueeze:<enabled>")
+ val statistics = BooleanSetting ("-Ystatistics", "Print compiler statistics")
+ val stop = PhasesSetting ("-Ystop", "Stop after phase")
+ val refinementMethodDispatch =
+ ChoiceSetting ("-Ystruct-dispatch", "Selects dispatch method for structural refinement method calls",
+ List("no-cache", "mono-cache", "poly-cache"), "poly-cache") .
+ withHelpSyntax("-Ystruct-dispatch:<method>")
+ val Xwarndeadcode = BooleanSetting ("-Ywarn-dead-code", "Emit warnings for dead code")
+
+ /**
+ * -P "Plugin" settings
+ */
+ val pluginOptions = MultiStringSetting("-P", "plugin:opt", "Pass an option to a plugin") .
+ withHelpSyntax("-P:<plugin>:<opt>")
+
+ /**
+ * IDE Visible Settings - "showToIDE" called on each.
+ */
+
+ val settingsForIDE = {
+ val xs = List(
+ argfiles, dependenciesFile, debuginfo, make, XO, target,
+ Xchecknull, checkInit, noassertions, Xexperimental, future, XlogImplicits, nouescape, XnoVarargsConversion, pluginsDir, Xwarninit,
+ Xcloselim, Xdce, Xdetach, inline, Xlinearizer, Ynogenericsig, noimports, nopredefs, selfInAnnots, Xwarndeadcode
+ )
+ xs foreach { _.showToIDE }
+ xs
}
}
diff --git a/src/compiler/scala/tools/nsc/doc/Settings.scala b/src/compiler/scala/tools/nsc/doc/Settings.scala
index a43f61b048..a6357a31cf 100644
--- a/src/compiler/scala/tools/nsc/doc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/doc/Settings.scala
@@ -19,10 +19,14 @@ class Settings(error: String => Unit) extends scala.tools.nsc.Settings(error) {
val doctitle = StringSetting ("-doctitle", "doctitle", "Include title for the overview page", "Scala 2<br/>API Specification")
val pagefooter = StringSetting ("-footer", "pagefooter", "Include footer text for each page", "")
val pageheader = StringSetting ("-header", "pageheader", "Include header text for each page", "")
- val linksource = BooleanSetting ("-linksource", "Generate source in HTML").hideToIDE
- val nocomment = BooleanSetting ("-nocomment", "Suppress description and tags, generate only declarations.").hideToIDE
+ val linksource = BooleanSetting ("-linksource", "Generate source in HTML")
+ val nocomment = BooleanSetting ("-nocomment", "Suppress description and tags, generate only declarations.")
val stylesheetfile = StringSetting ("-stylesheetfile", "stylesheetfile", "File to change style of the generated documentation", "style.css")
val pagetop = StringSetting ("-top", "pagetop", "Include top text for each page", "")
val windowtitle = StringSetting ("-windowtitle", "windowtitle", "Specify window title of generated HTML documentation", "Scala 2")
+ List(
+ memberaccess, pagebottom, doccharset, doctitle, pagefooter,
+ pageheader, stylesheetfile, pagetop, windowtitle
+ ) foreach { _.showToIDE }
}
diff --git a/src/partest/scala/tools/partest/nest/TestFile.scala b/src/partest/scala/tools/partest/nest/TestFile.scala
index e7afcfee36..07a96956dd 100644
--- a/src/partest/scala/tools/partest/nest/TestFile.scala
+++ b/src/partest/scala/tools/partest/nest/TestFile.scala
@@ -33,7 +33,7 @@ class TestFile(kind: String, val file: File, val fileManager: FileManager, creat
val reader = new BufferedReader(new java.io.FileReader(flagsFile))
val flags = reader.readLine
if (flags ne null)
- settings.parseParams(flags, error)
+ settings.parseParams(flags)
}
}