summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-03-07 05:24:00 +0000
committerPaul Phillips <paulp@improving.org>2010-03-07 05:24:00 +0000
commit5f9c20c232ee33d60f012aa999cb70da56e690ab (patch)
treeb35d9aa49dda5de45e23381ef24bc417d3d587b7
parent121164ef717226fafaa6a72dcfef0aec1bd89ee4 (diff)
downloadscala-5f9c20c232ee33d60f012aa999cb70da56e690ab.tar.gz
scala-5f9c20c232ee33d60f012aa999cb70da56e690ab.tar.bz2
scala-5f9c20c232ee33d60f012aa999cb70da56e690ab.zip
One minute too many trying to figure out where ...
One minute too many trying to figure out where some partest classpath mutation was disappearing on me, and I snapped and started the process of creating an immutable Settings. This commit is for the most part infrastructure to enable its smooth and uneventful entrance. Review by community.
-rw-r--r--src/compiler/scala/tools/nsc/CompilerCommand.scala5
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala2
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala960
-rw-r--r--src/compiler/scala/tools/nsc/settings/AbsScalacSettings.scala35
-rw-r--r--src/compiler/scala/tools/nsc/settings/AbsSettings.scala118
-rw-r--r--src/compiler/scala/tools/nsc/settings/ImmutableSettings.scala11
-rw-r--r--src/compiler/scala/tools/nsc/settings/MutableSettings.scala601
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalacSettings.scala185
-rw-r--r--src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala60
-rw-r--r--src/compiler/scala/tools/util/BashCompletion.scala2
10 files changed, 1019 insertions, 960 deletions
diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala
index dd581e0878..f24bef9b60 100644
--- a/src/compiler/scala/tools/nsc/CompilerCommand.scala
+++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala
@@ -6,7 +6,6 @@
package scala.tools.nsc
-import Settings.Setting
import java.io.IOException
import scala.collection.mutable.ListBuffer
import scala.tools.nsc.util.ArgumentsExpander
@@ -22,6 +21,8 @@ class CompilerCommand(
def this(arguments: List[String], settings: Settings, error: String => Unit, interactive: Boolean) =
this(arguments, settings, error, interactive, true)
+ type Setting = Settings#Setting
+
/** file extensions of files that the compiler can process */
lazy val fileEndings = Properties.fileEndings
@@ -46,7 +47,7 @@ class CompilerCommand(
/** Messages explaining usage and options */
def usageMsg = createUsageMsg("where possible standard", _.isStandard)
- def fscUsageMsg = createUsageMsg("where possible standard", ( st => st.isStandard || st.isFscSpecific ))
+ def fscUsageMsg = createUsageMsg("where possible standard", ( st => st.isStandard || st.name == "-shutdown"))
def xusageMsg = createUsageMsg("Possible advanced", _.isAdvanced)
def yusageMsg = createUsageMsg("Possible private", _.isPrivate)
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index bf75c8d121..bb9fbed0e9 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -725,7 +725,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
val startTime = currentTime
phase = globalPhase
globalPhase.run
- if (settings.print contains globalPhase.name)
+ if (settings.Xprint contains globalPhase.name)
if (settings.writeICode.value && globalPhase.id >= icodePhase.id) writeICode()
else if (settings.Xshowtrees.value) nodePrinters.printAll()
else printAllUnits()
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index 1740844110..cd4626c0c6 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -6,962 +6,10 @@
package scala.tools.nsc
-import java.io.File
-import File.pathSeparator
-import io.AbstractFile
-import util.{ ClassPath, SourceFile, CommandLineParser }
-import Settings._
-import annotation.elidable
-import scala.tools.util.{ PathResolver, StringOps }
-import scala.collection.mutable.ListBuffer
-import scala.collection.immutable.TreeSet
-import interpreter.{ returning }
+import settings.MutableSettings
-class Settings(errorFn: String => Unit) extends ScalacSettings {
+/** A compatibility stub.
+ */
+class Settings(errorFn: String => Unit) extends MutableSettings(errorFn) {
def this() = this(Console.println)
-
- /** Iterates over the arguments applying them to settings where applicable.
- * Then verifies setting dependencies are met.
- *
- * This temporarily takes a boolean indicating whether to keep
- * processing if an argument is seen which is not a command line option.
- * This is an expedience for the moment so that you can say
- *
- * scalac -d /tmp foo.scala -optimise
- *
- * while also allowing
- *
- * scala Program opt opt
- *
- * to get their arguments.
- *
- * Returns (success, List of unprocessed arguments)
- */
- def processArguments(arguments: List[String], processAll: Boolean): (Boolean, List[String]) = {
- var args = arguments
- val residualArgs = new ListBuffer[String]
-
- while (args.nonEmpty) {
- if (args.head startsWith "-") {
- val args0 = args
- args = this parseParams args
- if (args eq args0) {
- errorFn("bad option: '" + args.head + "'")
- return ((false, args))
- }
- }
- else if (args.head == "") { // discard empties, sometimes they appear because of ant or etc.
- args = args.tail
- }
- else {
- if (!processAll)
- return ((checkDependencies, args))
-
- residualArgs += args.head
- args = args.tail
- }
- }
-
- ((checkDependencies, residualArgs.toList))
- }
- def processArgumentString(params: String) = processArguments(splitParams(params), true)
-
- override def hashCode() = visibleSettings.hashCode
- override def equals(that: Any) = that match {
- case s: Settings => this.visibleSettings == s.visibleSettings
- case _ => false
- }
-
- /** Create a new Settings object, copying all user-set values.
- */
- def copy(): Settings = {
- val s = new Settings()
- val xs = userSetSettings flatMap (_.unparse)
- s.processArguments(xs.toList, true)
- s
- }
-
- def checkDependencies: Boolean = {
- def hasValue(s: Setting, value: String): Boolean = s match {
- case bs: BooleanSetting => bs.value
- case ss: StringSetting => ss.value == value
- case cs: ChoiceSetting => cs.value == value
- case _ => "" == value
- }
-
- for (setting <- visibleSettings ; (dep, value) <- setting.dependency)
- if (!setting.isDefault && !hasValue(dep, value)) {
- errorFn("incomplete option " + setting.name + " (requires " + dep.name + ")")
- return false
- }
-
- true
- }
-
- /** A list pairing source directories with their output directory.
- * This option is not available on the command line, but can be set by
- * other tools (IDEs especially). The command line specifies a single
- * output directory that is used for all source files, denoted by a
- * '*' in this list.
- */
- lazy val outputDirs = new OutputDirs
-
- /** Split the given line into parameters.
- */
- def splitParams(line: String) = CommandLineParser.tokenize(line, errorFn)
-
- /** Returns any unprocessed arguments.
- */
- 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) =>
- val res = setter(cmd)(args)
- cmd.postSetHook()
- res
- }
-
- // if arg is of form -Xfoo:bar,baz,quux
- def parseColonArg(s: String): Option[List[String]] = {
- val (p, args) = StringOps.splitWhere(s, _ == ':', true) getOrElse (return None)
-
- // any non-Nil return value means failure and we return s unmodified
- tryToSetIfExists(p, args split "," toList, (s: Setting) => s.tryToSetColon _)
- }
- // if arg is of form -Dfoo=bar or -Dfoo (name = "-D")
- def isPropertyArg(s: String) = lookupSetting(s take 2) match {
- case Some(x: DefinesSetting) => true
- case _ => false
- }
- def parsePropertyArg(s: String): Option[List[String]] = {
- val (p, args) = (s take 2, s drop 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 arg :: rest = args
- if (arg == "") {
- // it looks like Ant passes "" sometimes
- rest
- }
- else if (!arg.startsWith("-")) {
- errorFn("Argument '" + arg + "' does not start with '-'.")
- args
- }
- else if (arg == "-") {
- errorFn("'-' is not a valid argument.")
- args
- }
- else
- // 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 (arg contains ":") parseColonArg(arg) match {
- case Some(_) => rest
- case None => args
- }
- else if (isPropertyArg(arg)) parsePropertyArg(arg) match {
- case Some(_) => rest
- case None => args
- }
- else parseNormalArg(arg, rest) match {
- case Some(xs) => xs
- case None => args
- }
- }
-
- doArgs(args)
- }
-
- // checks both name and any available abbreviations
- def lookupSetting(cmd: String): Option[Setting] =
- allSettings.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.{ 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((sint _).tupled andThen add[IntSetting])
- lazy val BooleanSetting = untupled((bool _).tupled andThen add[BooleanSetting])
- lazy val StringSetting = untupled((str _).tupled andThen add[StringSetting])
- lazy val MultiStringSetting = untupled((multi _).tupled andThen add[MultiStringSetting])
- lazy val ChoiceSetting = untupled((choice _).tupled andThen add[ChoiceSetting])
- lazy val DebugSetting = untupled((sdebug _).tupled andThen add[DebugSetting])
- lazy val PhasesSetting = untupled((phase _).tupled andThen add[PhasesSetting])
- lazy val OutputSetting = untupled((output _).tupled andThen add[OutputSetting])
- lazy val DefinesSetting = () => add(new DefinesSetting())
-
- def PathSetting(name: String, arg: String, descr: String, default: String): PathSetting = {
- val prepend = new Settings.StringSetting(name + "/p", "", "", "") { override val isInternalOnly = true }
- val append = new Settings.StringSetting(name + "/a", "", "", "") { override val isInternalOnly = true }
-
- /** Not flipping this part on just yet.
- add[StringSetting](prepend)
- add[StringSetting](append)
- */
- returning(new PathSetting(name, arg, descr, default, prepend, append))(x => add[PathSetting](x))
- }
-
- override def toString() = "Settings {\n%s}\n" format (userSetSettings map (" " + _ + "\n") mkString)
- def toConciseString = userSetSettings.mkString("(", " ", ")")
-}
-
-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 }
- val choices : List[T] = Nil
- }
-
- /** A class for holding mappings from source directories to
- * their output location. This functionality can be accessed
- * only programmatically. The command line compiler uses a
- * single output location, but tools may use this functionality
- * to set output location per source directory.
- */
- class OutputDirs {
- /** Pairs of source directory - destination directory. */
- private var outputDirs: List[(AbstractFile, AbstractFile)] = Nil
-
- /** If this is not None, the output location where all
- * classes should go.
- */
- private var singleOutDir: Option[AbstractFile] = None
-
- /** Add a destination directory for sources found under srcdir.
- * Both directories should exits.
- */
- def add(srcDir: String, outDir: String): Unit =
- add(checkDir(AbstractFile.getDirectory(srcDir), srcDir),
- checkDir(AbstractFile.getDirectory(outDir), outDir))
-
- /** Check that dir is exists and is a directory. */
- private def checkDir(dir: AbstractFile, name: String): AbstractFile = {
- if ((dir eq null) || !dir.isDirectory)
- throw new FatalError(name + " does not exist or is not a directory")
- dir
- }
-
- /** Set the single output directory. From now on, all files will
- * be dumped in there, regardless of previous calls to 'add'.
- */
- def setSingleOutput(outDir: String) {
- val dst = AbstractFile.getDirectory(outDir)
- setSingleOutput(checkDir(dst, outDir))
- }
-
- /** Set the single output directory. From now on, all files will
- * be dumped in there, regardless of previous calls to 'add'.
- */
- def setSingleOutput(dir: AbstractFile) {
- singleOutDir = Some(dir)
- }
-
- def add(src: AbstractFile, dst: AbstractFile) {
- singleOutDir = None
- outputDirs ::= (src, dst)
- }
-
- /** Return the list of source-destination directory pairs. */
- def outputs: List[(AbstractFile, AbstractFile)] = outputDirs
-
- /** Return the output directory for the given file.
- */
- def outputDirFor(src: AbstractFile): AbstractFile = {
- def isBelow(srcDir: AbstractFile, outDir: AbstractFile) =
- src.path.startsWith(srcDir.path)
-
- singleOutDir match {
- case Some(d) => d
- case None =>
- (outputs find (isBelow _).tupled) match {
- case Some((_, d)) => d
- case _ =>
- throw new FatalError("Could not find an output directory for "
- + src.path + " in " + outputs)
- }
- }
- }
-
- /** Return the source file path(s) which correspond to the given
- * classfile path and SourceFile attribute value, subject to the
- * condition that source files are arranged in the filesystem
- * according to Java package layout conventions.
- *
- * The given classfile path must be contained in at least one of
- * the specified output directories. If it does not then this
- * method returns Nil.
- *
- * Note that the source file is not required to exist, so assuming
- * a valid classfile path this method will always return a list
- * containing at least one element.
- *
- * Also that if two or more source path elements target the same
- * output directory there will be two or more candidate source file
- * paths.
- */
- def srcFilesFor(classFile : AbstractFile, srcPath : String) : List[AbstractFile] = {
- def isBelow(srcDir: AbstractFile, outDir: AbstractFile) =
- classFile.path.startsWith(outDir.path)
-
- singleOutDir match {
- case Some(d) => Nil
- case None =>
- (outputs filter (isBelow _).tupled) match {
- case Nil => Nil
- case matches => matches.map(_._1.lookupPathUnchecked(srcPath, false))
- }
- }
- }
- }
-
- // 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,
- range: Option[(Int, Int)] = None,
- parser: String => Option[Int] = _ => None
- ) =
- new IntSetting(name, descr, default, range, parser)
-
- 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 output(outputDirs: OutputDirs, default: String) =
- new OutputSetting(outputDirs, default)
- }
-
- implicit val SettingOrdering : Ordering[Setting] = Ordering.ordered;
- /** A base class for settings of all types.
- * Subclasses each define a `value' field of the appropriate type.
- */
- 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 the setting should not appear in help output, etc. */
- def isInternalOnly = false
-
- /** 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 }
-
- /** Will be called after this Setting is set, for any cases where the
- * Setting wants to perform extra work. */
- private var _postSetHook: this.type => Unit = (x: this.type) => ()
- def postSetHook(): Unit = _postSetHook(this)
- def withPostSetHook(f: this.type => Unit): this.type = { _postSetHook = f ; this }
-
- /** 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
- */
- private[Settings] def tryToSetProperty(args: List[String]): Option[List[String]] =
- errorAndValue("'" + name + "' does not accept property style arguments", None)
-
- /**
- * Attempt to set from a properties file style property value.
- */
- def tryToSetFromPropertyValue(s : String) {
- tryToSet(s :: Nil)
- }
-
- /** The syntax defining this setting in a help string */
- 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
-
- /** A list of Strings which can recreate this setting. */
- def unparse: List[String]
-
- /** 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 = !isFscSpecific && !isAdvanced && !isPrivate && name != "-Y"
- def isFscSpecific: Boolean = (name == "-shutdown")
- 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: Ordering](xs: List[T], ys: List[T]) = xs.sorted == ys.sorted
-
- // Equality
- def eqValues: List[Any] = List(name, value)
- def isEq(other: Setting) = eqValues == other.eqValues
- override def hashCode() = name.hashCode
- override def toString() = "%s = %s".format(name, value)
- }
-
- /** A setting represented by an integer */
- class IntSetting private[Settings](
- val name: String,
- val descr: String,
- val default: Int,
- val range: Option[(Int, Int)],
- parser: String => Option[Int])
- extends Setting(descr) {
- type T = Int
- protected var v = default
-
- // not stable values!
- val IntMin = Int.MinValue
- val IntMax = Int.MaxValue
- def min = range map (_._1) getOrElse IntMin
- def max = range map (_._2) getOrElse IntMax
-
- override def value_=(s: Int) =
- if (isInputValid(s)) super.value_=(s) else errorMsg
-
- // Validate that min and max are consistent
- assert(min <= max)
-
- // Helper to validate an input
- private def isInputValid(k: Int): Boolean = (min <= k) && (k <= max)
-
- // Helper to generate a textual explaination of valid inputs
- private def getValidText: String = (min, max) match {
- case (IntMin, IntMax) => "can be any integer"
- case (IntMin, x) => "must be less than or equal to "+x
- case (x, IntMax) => "must be greater than or equal to "+x
- case _ => "must be between %d and %d".format(min, max)
- }
-
- // Ensure that the default value is actually valid
- assert(isInputValid(default))
-
- def parseArgument(x: String): Option[Int] = {
- parser(x) orElse {
- try { Some(x.toInt) }
- catch { case _: NumberFormatException => None }
- }
- }
-
- def errorMsg = errorFn("invalid setting for -"+name+" "+getValidText)
-
- def tryToSet(args: List[String]) =
- if (args.isEmpty) errorAndValue("missing argument", None)
- else parseArgument(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 x: IntSetting => this isEq x
- case _ => false
- }
- }
-
- /** A setting represented by a boolean flag (false, unless set) */
- 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 tryToSetFromPropertyValue(s : String) {
- value = s.equalsIgnoreCase("true")
- }
- override def equals(that: Any) = that match {
- case x: BooleanSetting => this isEq x
- case _ => false
- }
- }
-
- /** A setting represented by a string, (`default' unless set) */
- 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 + ">")
-
- override def equals(that: Any) = that match {
- case x: StringSetting => this isEq x
- case _ => false
- }
- }
-
- class PathSetting private[Settings](
- name: String,
- arg: String,
- descr: String,
- default: String,
- prependPath: StringSetting,
- appendPath: StringSetting)
- extends StringSetting(name, arg, descr, default) {
- import ClassPath.join
- def prepend(s: String) = prependPath.value = join(s, prependPath.value)
- def append(s: String) = appendPath.value = join(appendPath.value, s)
-
- override def value = join(
- prependPath.value,
- super.value,
- appendPath.value
- )
- }
-
- /** Set the output directory. */
- class OutputSetting private[Settings](
- outputDirs: OutputDirs,
- default: String)
- extends StringSetting("-d", "directory", "Specify where to place generated class files", default) {
- value = default
- override def value_=(str: String) {
- super.value_=(str)
- outputDirs.setSingleOutput(str)
- }
- }
-
- /** A setting that accumulates all strings supplied to it,
- * until it encounters one starting with a '-'. */
- 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 appendToValue(str: String) { value ++= List(str) }
-
- def tryToSet(args: List[String]) = {
- val (strings, rest) = args span (x => !x.startsWith("-"))
- strings foreach appendToValue
-
- Some(rest)
- }
- override def tryToSetColon(args: List[String]) = tryToSet(args)
- def unparse: List[String] = value map { name + ":" + _ }
-
- withHelpSyntax(name + ":<" + arg + ">")
- override def equals(that: Any) = that match {
- case x: MultiStringSetting => this isEq x
- case _ => false
- }
- }
-
- /** A setting represented by a string in a given set of <code>choices</code>,
- * (<code>default</code> unless set).
- */
- class ChoiceSetting private[Settings](
- val name: String,
- val descr: String,
- override val choices: List[String],
- val default: String)
- extends Setting(descr + choices.mkString(" (", ",", ")")) {
- type T = String
- protected var v: String = default
- protected def argument: String = name drop 1
-
- 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)
- }
- def unparse: List[String] =
- if (value == default) Nil else List(name + ":" + value)
-
- withHelpSyntax(name + ":<" + argument + ">")
- override def equals(that: Any) = that match {
- case x: ChoiceSetting => this isEq x
- case _ => false
- }
- }
-
- /** 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 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) = {
- super.value_=(choice)
- level = indexOf(choices, choice).get
- }
-
- override def tryToSet(args: List[String]) =
- if (args.isEmpty) { value = defaultEmpty ; Some(Nil) }
- else super.tryToSet(args)
- override def equals(that: Any) = that match {
- case x: DebugSetting => this isEq x
- case _ => false
- }
- }
-
- /** A setting represented by a list of strings which should be prefixes of
- * phase names. This is not checked here, however. Alternatively the string
- * "all" can be used to represent all phases.
- * (the empty list, unless set)
- */
- 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]) = errorAndValue("missing phase", None)
- override def tryToSetColon(args: List[String]) = args match {
- case Nil => errorAndValue("missing phase", None)
- case xs => value ++= xs ; 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(phasename: String): Boolean =
- doAllPhases || (value exists { phasename startsWith _ } )
-
- def doAllPhases() = value contains "all"
- def unparse: List[String] = value map { name + ":" + _ }
-
- override def equals(that: Any) = that match {
- 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 idx = s indexOf '='
-
- if (idx < 0) Some(s, "")
- else Some(s take idx, s drop (idx + 1))
- }
-
- private[Settings] override def tryToSetProperty(args: List[String]): Option[List[String]] =
- tryToSet(args)
-
- 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)
- }
-
- def unparse: List[String] =
- value map { case (k,v) => "-D" + k + (if (v == "") "" else "=" + v) }
-
- override def equals(that: Any) = that match {
- case x: DefinesSetting => this isEq x
- case _ => false
- }
-
- /** Apply the specified properties to the current JVM and returns them. */
- def applyToJVM() = {
- value foreach { case (k, v) => System.getProperties.setProperty(k, v) }
- value
- }
- }
-}
-
-trait ScalacSettings {
- self: Settings =>
-
- import PathResolver.{ Defaults, Environment }
-
- /** Sorted set of settings */
- protected var allSettings: Set[Setting] = TreeSet[Setting]()
-
- /** All settings */
- def visibleSettings: Set[Setting] = allSettings filterNot (_.isInternalOnly)
-
- /** Set settings */
- def userSetSettings: Set[Setting] = visibleSettings filterNot (_.isDefault)
-
- /** 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!")
- def appendToClasspath(entry: String) = {
- val oldClasspath = classpath.value
- classpath.value = ClassPath.join(classpath.value, entry)
-
- if (Ylogcp.value)
- Console.println("Updated classpath from '%s' to '%s'".format(oldClasspath, classpath.value))
- }
-
- /**
- * Classpath related settings
- */
-
- val classpath = PathSetting ("-classpath", "path", "Specify where to find user class files", ".") withAbbreviation ("-cp")
- val bootclasspath = PathSetting ("-bootclasspath", "path", "Override location of bootstrap class files", Defaults.scalaBootClassPath)
- val extdirs = PathSetting ("-extdirs", "dirs", "Override location of installed extensions", Defaults.scalaExtDirs)
- val javabootclasspath = PathSetting ("-javabootclasspath", "path", "Override java boot classpath.", Defaults.javaBootClassPath)
- val javaextdirs = PathSetting ("-javaextdirs", "path", "Override java extdirs classpath.", Defaults.javaExtDirs)
- /** This one is most likely temporary, but so helpful while I try to get an iron grip on the classpath. */
- val javaignorecp = BooleanSetting ("-javaignorecp", "scala will not use java's -classpath no matter what.")
-
- val outdir = OutputSetting (outputDirs, ".")
- val sourcepath = StringSetting ("-sourcepath", "path", "Specify where to find input source files", "")
- val Ylogcp = BooleanSetting ("-Ylog-classpath", "Output information about what classpath is being applied.")
-
- /**
- * Standard settings
- */
- // argfiles is only for the help message
- val argfiles = BooleanSetting ("@<file>", "A text file containing compiler arguments (options and source files)")
- val defines = DefinesSetting()
- 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.sourceEncoding)
- val explaintypes = BooleanSetting ("-explaintypes", "Explain type errors in more detail")
- 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", "transitivenocp"), "all") .
- withHelpSyntax("-make:<strategy>")
- val nowarnings = BooleanSetting ("-nowarn", "Generate no warnings")
- val XO = BooleanSetting ("-optimise", "Generates faster bytecode by applying optimisations to the program").withAbbreviation("-optimize") .
- withPostSetHook(_ => List(inline, Xcloselim, Xdce) foreach (_.value = true))
- val printLate = BooleanSetting ("-print", "Print program with all Scala-specific features removed")
- val target = ChoiceSetting ("-target", "Specify for which target object files should be built", List("jvm-1.5", "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-name", "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 assemextdirs = StringSetting ("-Xassem-extdirs", "dirs", "List of directories containing assemblies, defaults to `lib'", Defaults.scalaLibDir.path).dependsOn(target, "msil")
- val sourcedir = StringSetting ("-Xsourcedir", "directory", "When -target:msil, the source folder structure is mirrored in output directory.", ".").dependsOn(target, "msil")
- 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 elideLevel = IntSetting ("-Xelide-level", "Generate calls to @elidable-marked methods only method priority is greater than argument.",
- elidable.ASSERTION, None, elidable.byName.get(_))
- val Xexperimental = BooleanSetting ("-Xexperimental", "Enable experimental extensions")
- val noForwarders = BooleanSetting ("-Xno-forwarders", "Do not generate static forwarders in mirror classes")
- 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 Xmigration28 = BooleanSetting ("-Xmigration", "Warn about constructs whose behavior may have changed between 2.7 and 2.8")
- val nouescape = BooleanSetting ("-Xno-uescape", "Disables handling of \\u unicode escapes")
- 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", "Path to search compiler plugins", Defaults.scalaPluginPath)
- 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")
-
- /**
- * -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 Ycompacttrees = BooleanSetting ("-Ycompact-trees", "Use compact tree printer when displaying trees")
- val noCompletion = BooleanSetting ("-Yno-completion", "Disable tab-completion in the REPL")
- val Xdce = BooleanSetting ("-Ydead-code", "Perform dead code elimination")
- val debug = BooleanSetting ("-Ydebug", "Output debugging messages")
- 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, Int.MaxValue), _ => 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 Ystatistics = 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", "invoke-dynamic"), "poly-cache") .
- withHelpSyntax("-Ystruct-dispatch:<method>")
- val specialize = BooleanSetting ("-Yspecialize", "Specialize generic code on types.")
- val Yrangepos = BooleanSetting ("-Yrangepos", "Use range positions for syntax trees.")
- val Yidedebug = BooleanSetting ("-Yide-debug", "Generate, validate and output trees using the interactive compiler.")
- val Ybuilderdebug = ChoiceSetting ("-Ybuilder-debug", "Compile using the specified build manager", List("none", "refined", "simple"), "none") .
- withHelpSyntax("-Ybuilder-debug:<method>")
- val Ybuildmanagerdebug =
- BooleanSetting ("-Ybuild-manager-debug", "Generate debug information for the Refined Build Manager compiler.")
- val Ytyperdebug = BooleanSetting ("-Ytyper-debug", "Trace all type assignements")
- val Ypmatdebug = BooleanSetting ("-Ypmat-debug", "Trace all pattern matcher activity.")
- val Yrepldebug = BooleanSetting ("-Yrepl-debug", "Trace all repl activity.")
- val Ypmatnaive = BooleanSetting ("-Ypmat-naive", "Desugar matches as naively as possible..")
- val Ytailrec = BooleanSetting ("-Ytailrecommend", "Alert methods which would be tail-recursive if private or final.")
- val Yjenkins = BooleanSetting ("-Yjenkins-hashCodes", "Use jenkins hash algorithm for case class generated hashCodes.")
-
- // Warnings
- val Ywarnfatal = BooleanSetting ("-Yfatal-warnings", "Fail the compilation if there are any warnings.")
- val Xwarninit = BooleanSetting ("-Xwarninit", "Warn about possible changes in initialization semantics")
- val Xchecknull = BooleanSetting ("-Xcheck-null", "Emit warning on selection of nullable reference")
- val Xwarndeadcode = BooleanSetting ("-Ywarn-dead-code", "Emit warnings for dead code")
- val YwarnShadow = BooleanSetting ("-Ywarn-shadowing", "Emit warnings about possible variable shadowing.")
- val YwarnCatches = BooleanSetting ("-Ywarn-catches", "Emit warnings about catch blocks which catch everything.")
- val Xwarnings = BooleanSetting ("-Xstrict-warnings", "Emit warnings about lots of things.") .
- withPostSetHook(_ =>
- List(YwarnShadow, YwarnCatches, Xwarndeadcode, Xwarninit) foreach (_.value = true)
- )
- /**
- * "fsc-specific" settings.
- */
- val fscShutdown = BooleanSetting ("-shutdown", "Shutdown the fsc daemon")
-
- /**
- * -P "Plugin" settings
- */
- val pluginOptions = MultiStringSetting("-P", "plugin:opt", "Pass an option to a plugin") .
- withHelpSyntax("-P:<plugin>:<opt>")
}
diff --git a/src/compiler/scala/tools/nsc/settings/AbsScalacSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsScalacSettings.scala
new file mode 100644
index 0000000000..34f10d3769
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/settings/AbsScalacSettings.scala
@@ -0,0 +1,35 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package settings
+
+trait AbsScalacSettings {
+ self: AbsSettings =>
+
+ type BooleanSetting <: AbsSetting
+ type ChoiceSetting <: AbsSetting
+ type DebugSetting <: AbsSetting
+ type DefinesSetting <: AbsSetting
+ type IntSetting <: AbsSetting
+ type MultiStringSetting <: AbsSetting
+ type PathSetting <: AbsSetting
+ type PhasesSetting <: AbsSetting
+ type StringSetting <: AbsSetting
+
+ type OutputDirs
+ type OutputSetting <: AbsSetting
+
+ def BooleanSetting(name: String, descr: String): BooleanSetting
+ def ChoiceSetting(name: String, descr: String, choices: List[String], default: String): ChoiceSetting
+ def DebugSetting(name: String, descr: String, choices: List[String], default: String, defaultEmpty: String): DebugSetting
+ def DefinesSetting(): DefinesSetting
+ def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]): IntSetting
+ def MultiStringSetting(name: String, arg: String, descr: String): MultiStringSetting
+ def OutputSetting(outputDirs: OutputDirs, default: String): OutputSetting
+ def PathSetting(name: String, arg: String, descr: String, default: String): PathSetting
+ def PhasesSetting(name: String, descr: String): PhasesSetting
+ def StringSetting(name: String, arg: String, descr: String, default: String): StringSetting
+}
diff --git a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala
new file mode 100644
index 0000000000..8b51c00a48
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala
@@ -0,0 +1,118 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package settings
+
+import io.AbstractFile
+
+/** A Settings abstraction boiled out of the original highly mutable Settings
+ * class with the intention of creating an ImmutableSettings which can be used
+ * interchangeably. Except of course without the mutants.
+ */
+
+trait AbsSettings {
+ type Setting <: AbsSetting // Fix to the concrete Setting type
+ type ResultOfTryToSet // List[String] in mutable, (Settings, List[String]) in immutable
+ def errorFn: String => Unit
+ protected def allSettings: Set[Setting]
+
+ // settings minus internal usage settings
+ def visibleSettings = allSettings filterNot (_.isInternalOnly)
+
+ // only settings which differ from default
+ def userSetSettings = visibleSettings filterNot (_.isDefault)
+
+ // checks both name and any available abbreviations
+ def lookupSetting(cmd: String): Option[Setting] = allSettings find (_ respondsTo cmd)
+
+ // two AbsSettings objects are equal if their visible settings are equal.
+ override def hashCode() = visibleSettings.hashCode
+ override def equals(that: Any) = that match {
+ case s: AbsSettings => this.visibleSettings == s.visibleSettings
+ case _ => false
+ }
+ override def toString() = "Settings {\n%s}\n" format (userSetSettings map (" " + _ + "\n") mkString)
+ def toConciseString = userSetSettings.mkString("(", " ", ")")
+
+ def checkDependencies =
+ visibleSettings filterNot (_.isDefault) forall (setting => setting.dependencies forall {
+ case (dep, value) =>
+ (Option(dep.value) exists (_.toString == value)) || {
+ errorFn("incomplete option %s (requires %s)".format(setting.name, dep.name))
+ false
+ }
+ })
+
+ implicit lazy val SettingOrdering: Ordering[Setting] = Ordering.ordered
+
+ trait AbsSettingValue {
+ type T <: Any
+ def value: T
+ def isDefault: Boolean
+ }
+
+ trait AbsSetting extends Ordered[Setting] with AbsSettingValue {
+ def name: String
+ def helpDescription: String
+ def unparse: List[String] // A list of Strings which can recreate this setting.
+
+ def helpSyntax: String = name
+ def abbreviations: List[String] = Nil
+ def dependencies: List[(Setting, String)] = Nil
+ def respondsTo(label: String) = (name == label) || (abbreviations contains label)
+
+ /** If the setting should not appear in help output, etc. */
+ def isInternalOnly = false
+
+ /** Issue error and return */
+ 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.
+ */
+ protected[nsc] def tryToSet(args: List[String]): Option[ResultOfTryToSet]
+
+ /** 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.
+ */
+ protected[nsc] def tryToSetColon(args: List[String]): Option[ResultOfTryToSet] =
+ errorAndValue("'%s' does not accept multiple arguments" format name, None)
+
+ /** Commands which take properties in form -Dfoo=bar or -Dfoo
+ */
+ protected[nsc] def tryToSetProperty(args: List[String]): Option[ResultOfTryToSet] =
+ errorAndValue("'%s' does not accept property style arguments" format name, None)
+
+ /** Attempt to set from a properties file style property value.
+ */
+ def tryToSetFromPropertyValue(s: String): Unit = tryToSet(s :: Nil)
+
+ def isCategory: Boolean = List("-X", "-Y", "-P") contains name
+ def isAdvanced: Boolean = (name startsWith "-X") && name != "-X"
+ def isPrivate: Boolean = (name startsWith "-Y") && name != "-Y"
+ def isStandard: Boolean = !isAdvanced && !isPrivate && !isCategory
+
+ def compare(that: Setting): Int = name compare that.name
+
+ /** Equality tries to sidestep all the drama and define it simply and
+ * in one place: two AbsSetting objects are equal if their names and
+ * values compare equal.
+ */
+ override def equals(that: Any) = that match {
+ case x: AbsSettings#AbsSetting => (name == x.name) && (value == x.value)
+ case _ => false
+ }
+ override def hashCode() = (name, value).hashCode
+ override def toString() = "%s = %s".format(name, value)
+ }
+
+ trait InternalSetting extends AbsSetting {
+ override def isInternalOnly = true
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/settings/ImmutableSettings.scala b/src/compiler/scala/tools/nsc/settings/ImmutableSettings.scala
new file mode 100644
index 0000000000..a673860417
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/settings/ImmutableSettings.scala
@@ -0,0 +1,11 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package settings
+
+/** TODO.
+ */
+class ImmutableSettings
diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
new file mode 100644
index 0000000000..3b1cb89f41
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
@@ -0,0 +1,601 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+
+package scala.tools.nsc
+package settings
+
+import io.AbstractFile
+import util.{ ClassPath, CommandLineParser }
+import annotation.elidable
+import scala.tools.util.StringOps
+import scala.collection.mutable.ListBuffer
+import interpreter.{ returning }
+
+/** A mutable Settings object.
+ */
+class MutableSettings(val errorFn: String => Unit) extends AbsSettings with ScalacSettings with Mutable {
+ type ResultOfTryToSet = List[String]
+
+ /** Iterates over the arguments applying them to settings where applicable.
+ * Then verifies setting dependencies are met.
+ *
+ * This temporarily takes a boolean indicating whether to keep
+ * processing if an argument is seen which is not a command line option.
+ * This is an expedience for the moment so that you can say
+ *
+ * scalac -d /tmp foo.scala -optimise
+ *
+ * while also allowing
+ *
+ * scala Program opt opt
+ *
+ * to get their arguments.
+ *
+ * Returns (success, List of unprocessed arguments)
+ */
+ def processArguments(arguments: List[String], processAll: Boolean): (Boolean, List[String]) = {
+ var args = arguments
+ val residualArgs = new ListBuffer[String]
+
+ while (args.nonEmpty) {
+ if (args.head startsWith "-") {
+ val args0 = args
+ args = this parseParams args
+ if (args eq args0) {
+ errorFn("bad option: '" + args.head + "'")
+ return ((false, args))
+ }
+ }
+ else if (args.head == "") { // discard empties, sometimes they appear because of ant or etc.
+ args = args.tail
+ }
+ else {
+ if (!processAll)
+ return ((checkDependencies, args))
+
+ residualArgs += args.head
+ args = args.tail
+ }
+ }
+
+ ((checkDependencies, residualArgs.toList))
+ }
+ def processArgumentString(params: String) = processArguments(splitParams(params), true)
+
+ /** Create a new Settings object, copying all user-set values.
+ */
+ def copy(): Settings = {
+ val s = new Settings()
+ val xs = userSetSettings flatMap (_.unparse)
+ s.processArguments(xs.toList, true)
+ s
+ }
+
+ /** A list pairing source directories with their output directory.
+ * This option is not available on the command line, but can be set by
+ * other tools (IDEs especially). The command line specifies a single
+ * output directory that is used for all source files, denoted by a
+ * '*' in this list.
+ */
+ lazy val outputDirs = new OutputDirs
+
+ /** Split the given line into parameters.
+ */
+ def splitParams(line: String) = CommandLineParser.tokenize(line, errorFn)
+
+ /** Returns any unprocessed arguments.
+ */
+ 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) =>
+ val res = setter(cmd)(args)
+ cmd.postSetHook()
+ res
+ }
+
+ // if arg is of form -Xfoo:bar,baz,quux
+ def parseColonArg(s: String): Option[List[String]] = {
+ val (p, args) = StringOps.splitWhere(s, _ == ':', true) getOrElse (return None)
+
+ // any non-Nil return value means failure and we return s unmodified
+ tryToSetIfExists(p, args split "," toList, (s: Setting) => s.tryToSetColon _)
+ }
+ // if arg is of form -Dfoo=bar or -Dfoo (name = "-D")
+ def isPropertyArg(s: String) = lookupSetting(s take 2) match {
+ case Some(x: DefinesSetting) => true
+ case _ => false
+ }
+ def parsePropertyArg(s: String): Option[List[String]] = {
+ val (p, args) = (s take 2, s drop 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 arg :: rest = args
+ if (arg == "") {
+ // it looks like Ant passes "" sometimes
+ rest
+ }
+ else if (!arg.startsWith("-")) {
+ errorFn("Argument '" + arg + "' does not start with '-'.")
+ args
+ }
+ else if (arg == "-") {
+ errorFn("'-' is not a valid argument.")
+ args
+ }
+ else
+ // 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 (arg contains ":") parseColonArg(arg) match {
+ case Some(_) => rest
+ case None => args
+ }
+ else if (isPropertyArg(arg)) parsePropertyArg(arg) match {
+ case Some(_) => rest
+ case None => args
+ }
+ else parseNormalArg(arg, rest) match {
+ case Some(xs) => xs
+ case None => args
+ }
+ }
+
+ doArgs(args)
+ }
+
+ // 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
+ }
+
+ def BooleanSetting(name: String, descr: String) = add(new BooleanSetting(name, descr))
+ def ChoiceSetting(name: String, descr: String, choices: List[String], default: String) = add(new ChoiceSetting(name, descr, choices, default))
+ def DebugSetting(name: String, descr: String, choices: List[String], default: String, defaultEmpty: String) = add(new DebugSetting(name, descr, choices, default, defaultEmpty))
+ def DefinesSetting() = add(new DefinesSetting())
+ def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]) = add(new IntSetting(name, descr, default, range, parser))
+ def MultiStringSetting(name: String, arg: String, descr: String) = add(new MultiStringSetting(name, arg, descr))
+ def OutputSetting(outputDirs: OutputDirs, default: String) = add(new OutputSetting(outputDirs, default))
+ def PhasesSetting(name: String, descr: String) = add(new PhasesSetting(name, descr))
+ def StringSetting(name: String, arg: String, descr: String, default: String) = add(new StringSetting(name, arg, descr, default))
+ def PathSetting(name: String, arg: String, descr: String, default: String): PathSetting = {
+ val prepend = new StringSetting(name + "/p", "", "", "") with InternalSetting
+ val append = new StringSetting(name + "/a", "", "", "") with InternalSetting
+
+ /** Not flipping this part on just yet.
+ add[StringSetting](prepend)
+ add[StringSetting](append)
+ */
+ add(new PathSetting(name, arg, descr, default, prepend, append))
+ }
+
+ // basically this is a value which remembers if it's been modified
+ trait SettingValue extends AbsSettingValue {
+ protected var v: T
+ protected var setByUser: Boolean = false
+
+ def isDefault: Boolean = !setByUser
+ def value: T = v
+ def value_=(arg: T) = { setByUser = true ; v = arg }
+ }
+
+ /** A class for holding mappings from source directories to
+ * their output location. This functionality can be accessed
+ * only programmatically. The command line compiler uses a
+ * single output location, but tools may use this functionality
+ * to set output location per source directory.
+ */
+ class OutputDirs {
+ /** Pairs of source directory - destination directory. */
+ private var outputDirs: List[(AbstractFile, AbstractFile)] = Nil
+
+ /** If this is not None, the output location where all
+ * classes should go.
+ */
+ private var singleOutDir: Option[AbstractFile] = None
+
+ /** Add a destination directory for sources found under srcdir.
+ * Both directories should exits.
+ */
+ def add(srcDir: String, outDir: String): Unit =
+ add(checkDir(AbstractFile.getDirectory(srcDir), srcDir),
+ checkDir(AbstractFile.getDirectory(outDir), outDir))
+
+ /** Check that dir is exists and is a directory. */
+ private def checkDir(dir: AbstractFile, name: String): AbstractFile = {
+ if ((dir eq null) || !dir.isDirectory)
+ throw new FatalError(name + " does not exist or is not a directory")
+ dir
+ }
+
+ /** Set the single output directory. From now on, all files will
+ * be dumped in there, regardless of previous calls to 'add'.
+ */
+ def setSingleOutput(outDir: String) {
+ val dst = AbstractFile.getDirectory(outDir)
+ setSingleOutput(checkDir(dst, outDir))
+ }
+
+ /** Set the single output directory. From now on, all files will
+ * be dumped in there, regardless of previous calls to 'add'.
+ */
+ def setSingleOutput(dir: AbstractFile) {
+ singleOutDir = Some(dir)
+ }
+
+ def add(src: AbstractFile, dst: AbstractFile) {
+ singleOutDir = None
+ outputDirs ::= (src, dst)
+ }
+
+ /** Return the list of source-destination directory pairs. */
+ def outputs: List[(AbstractFile, AbstractFile)] = outputDirs
+
+ /** Return the output directory for the given file.
+ */
+ def outputDirFor(src: AbstractFile): AbstractFile = {
+ def isBelow(srcDir: AbstractFile, outDir: AbstractFile) =
+ src.path.startsWith(srcDir.path)
+
+ singleOutDir match {
+ case Some(d) => d
+ case None =>
+ (outputs find (isBelow _).tupled) match {
+ case Some((_, d)) => d
+ case _ =>
+ throw new FatalError("Could not find an output directory for "
+ + src.path + " in " + outputs)
+ }
+ }
+ }
+
+ /** Return the source file path(s) which correspond to the given
+ * classfile path and SourceFile attribute value, subject to the
+ * condition that source files are arranged in the filesystem
+ * according to Java package layout conventions.
+ *
+ * The given classfile path must be contained in at least one of
+ * the specified output directories. If it does not then this
+ * method returns Nil.
+ *
+ * Note that the source file is not required to exist, so assuming
+ * a valid classfile path this method will always return a list
+ * containing at least one element.
+ *
+ * Also that if two or more source path elements target the same
+ * output directory there will be two or more candidate source file
+ * paths.
+ */
+ def srcFilesFor(classFile : AbstractFile, srcPath : String) : List[AbstractFile] = {
+ def isBelow(srcDir: AbstractFile, outDir: AbstractFile) =
+ classFile.path.startsWith(outDir.path)
+
+ singleOutDir match {
+ case Some(d) => Nil
+ case None =>
+ (outputs filter (isBelow _).tupled) match {
+ case Nil => Nil
+ case matches => matches.map(_._1.lookupPathUnchecked(srcPath, false))
+ }
+ }
+ }
+ }
+
+ /** A base class for settings of all types.
+ * Subclasses each define a `value' field of the appropriate type.
+ */
+ abstract class Setting(val name: String, val helpDescription: String) extends AbsSetting with SettingValue with Mutable {
+ /** Error handling function, set after creation by enclosing Settings instance */
+ private var _errorFn: String => Unit = _
+ private[nsc] def setErrorHandler(e: String => Unit) = _errorFn = e
+ def errorFn(msg: String) = _errorFn(msg)
+
+ /** Will be called after this Setting is set for any extra work. */
+ private var _postSetHook: this.type => Unit = (x: this.type) => ()
+ def postSetHook() = { _postSetHook(this) ; this }
+ def withPostSetHook(f: this.type => Unit): this.type = { _postSetHook = f ; this }
+
+ /** The syntax defining this setting in a help string */
+ private var _helpSyntax = name
+ override def helpSyntax: String = _helpSyntax
+ def withHelpSyntax(s: String): this.type = { _helpSyntax = s ; this }
+
+ /** Abbreviations for this setting */
+ private var _abbreviations: List[String] = Nil
+ override def abbreviations = _abbreviations
+ def withAbbreviation(s: String): this.type = { _abbreviations ++= List(s) ; this }
+
+ /** Optional dependency on another setting */
+ private var dependency: Option[(Setting, String)] = None
+ override def dependencies = dependency.toList
+ def dependsOn(s: Setting, value: String): this.type = { dependency = Some((s, value)); this }
+ }
+
+ /** A setting represented by an integer */
+ class IntSetting private[nsc](
+ name: String,
+ descr: String,
+ val default: Int,
+ val range: Option[(Int, Int)],
+ parser: String => Option[Int])
+ extends Setting(name, descr) {
+ type T = Int
+ protected var v = default
+
+ // not stable values!
+ val IntMin = Int.MinValue
+ val IntMax = Int.MaxValue
+ def min = range map (_._1) getOrElse IntMin
+ def max = range map (_._2) getOrElse IntMax
+
+ override def value_=(s: Int) =
+ if (isInputValid(s)) super.value_=(s) else errorMsg
+
+ // Validate that min and max are consistent
+ assert(min <= max)
+
+ // Helper to validate an input
+ private def isInputValid(k: Int): Boolean = (min <= k) && (k <= max)
+
+ // Helper to generate a textual explaination of valid inputs
+ private def getValidText: String = (min, max) match {
+ case (IntMin, IntMax) => "can be any integer"
+ case (IntMin, x) => "must be less than or equal to "+x
+ case (x, IntMax) => "must be greater than or equal to "+x
+ case _ => "must be between %d and %d".format(min, max)
+ }
+
+ // Ensure that the default value is actually valid
+ assert(isInputValid(default))
+
+ def parseArgument(x: String): Option[Int] = {
+ parser(x) orElse {
+ try { Some(x.toInt) }
+ catch { case _: NumberFormatException => None }
+ }
+ }
+
+ def errorMsg = errorFn("invalid setting for -"+name+" "+getValidText)
+
+ def tryToSet(args: List[String]) =
+ if (args.isEmpty) errorAndValue("missing argument", None)
+ else parseArgument(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)
+ }
+
+ /** A setting represented by a boolean flag (false, unless set) */
+ class BooleanSetting private[nsc](
+ name: String,
+ descr: String)
+ extends Setting(name, 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 tryToSetFromPropertyValue(s : String) {
+ value = s.equalsIgnoreCase("true")
+ }
+ }
+
+ /** A setting represented by a string, (`default' unless set) */
+ class StringSetting private[nsc](
+ name: String,
+ val arg: String,
+ descr: String,
+ val default: String)
+ extends Setting(name, 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 + ">")
+ }
+
+ class PathSetting private[nsc](
+ name: String,
+ arg: String,
+ descr: String,
+ default: String,
+ prependPath: StringSetting,
+ appendPath: StringSetting)
+ extends StringSetting(name, arg, descr, default) {
+ import ClassPath.join
+ def prepend(s: String) = prependPath.value = join(s, prependPath.value)
+ def append(s: String) = appendPath.value = join(appendPath.value, s)
+
+ override def value = join(
+ prependPath.value,
+ super.value,
+ appendPath.value
+ )
+ }
+
+ /** Set the output directory. */
+ class OutputSetting private[nsc](
+ outputDirs: OutputDirs,
+ default: String)
+ extends StringSetting("-d", "directory", "Specify where to place generated class files", default) {
+ value = default
+ override def value_=(str: String) {
+ super.value_=(str)
+ outputDirs.setSingleOutput(str)
+ }
+ }
+
+ /** A setting that accumulates all strings supplied to it,
+ * until it encounters one starting with a '-'. */
+ class MultiStringSetting private[nsc](
+ name: String,
+ val arg: String,
+ descr: String)
+ extends Setting(name, descr) {
+ type T = List[String]
+ protected var v: List[String] = Nil
+ // def appendToValue(str: String) { value ++= List(str) }
+ def appendToValue(str: String) { value = value ++ List(str) } // ++= List(str) }
+
+ def tryToSet(args: List[String]) = {
+ val (strings, rest) = args span (x => !x.startsWith("-"))
+ strings foreach appendToValue
+
+ Some(rest)
+ }
+ 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).
+ */
+ class ChoiceSetting private[nsc](
+ name: String,
+ descr: String,
+ val choices: List[String],
+ val default: String)
+ extends Setting(name, descr + choices.mkString(" (", ",", ")")) {
+ type T = String
+ protected var v: String = default
+ protected def argument: String = name drop 1
+
+ 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)
+ }
+ def unparse: List[String] =
+ if (value == default) Nil else List(name + ":" + value)
+
+ 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 private[nsc](
+ 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) = {
+ super.value_=(choice)
+ level = indexOf(choices, choice).get
+ }
+
+ 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
+ * phase names. This is not checked here, however. Alternatively the string
+ * "all" can be used to represent all phases.
+ * (the empty list, unless set)
+ */
+ class PhasesSetting private[nsc](
+ name: String,
+ descr: String)
+ extends Setting(name, descr + " <phase> or \"all\"") {
+ type T = List[String]
+ protected var v: List[String] = Nil
+ override def value = if (v contains "all") List("all") else super.value
+
+ 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 = (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(phasename: String): Boolean =
+ doAllPhases || (value exists { phasename startsWith _ } )
+
+ def doAllPhases() = value contains "all"
+ def unparse: List[String] = value map { name + ":" + _ }
+
+ withHelpSyntax(name + ":<phase>")
+ }
+
+ /** A setting for a -D style property definition */
+ class DefinesSetting private[nsc] extends Setting("-D", "set a Java property") {
+ type T = List[(String, String)]
+ protected var v: T = Nil
+ 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 idx = s indexOf '='
+
+ if (idx < 0) Some(s, "")
+ else Some(s take idx, s drop (idx + 1))
+ }
+
+ protected[nsc] override def tryToSetProperty(args: List[String]): Option[List[String]] =
+ tryToSet(args)
+
+ def tryToSet(args: List[String]) =
+ if (args.isEmpty) None
+ else parseArg(args.head) match {
+ case None => None
+ case Some((a, b)) => value = value ++ List((a, b)) ; Some(args.tail)
+ }
+
+ def unparse: List[String] =
+ value map { case (k,v) => "-D" + k + (if (v == "") "" else "=" + v) }
+
+ /** Apply the specified properties to the current JVM and returns them. */
+ def applyToJVM() = {
+ value foreach { case (k, v) => System.getProperties.setProperty(k, v) }
+ value
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/settings/ScalacSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalacSettings.scala
new file mode 100644
index 0000000000..2f9a362457
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/settings/ScalacSettings.scala
@@ -0,0 +1,185 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+
+package scala.tools.nsc
+package settings
+
+import io.AbstractFile
+import util.{ ClassPath, SourceFile, CommandLineParser }
+import annotation.elidable
+import scala.tools.util.{ PathResolver, StringOps }
+import scala.collection.mutable.ListBuffer
+import scala.collection.immutable.TreeSet
+import interpreter.{ returning }
+
+trait ScalacSettings extends AbsScalacSettings with StandardScalaSettings {
+ self: MutableSettings =>
+
+ import PathResolver.{ Defaults, Environment }
+
+ /** Set of settings */
+ protected var allSettings = Set[Setting]()
+
+ /** 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!")
+ def appendToClasspath(entry: String) = {
+ val oldClasspath = classpath.value
+ classpath.value = ClassPath.join(classpath.value, entry)
+
+ if (Ylogcp.value)
+ Console.println("Updated classpath from '%s' to '%s'".format(oldClasspath, classpath.value))
+ }
+
+ /**
+ * Classpath related settings
+ */
+
+ val classpath = PathSetting ("-classpath", "path", "Specify where to find user class files", ".") withAbbreviation ("-cp")
+ val bootclasspath = PathSetting ("-bootclasspath", "path", "Override location of bootstrap class files", Defaults.scalaBootClassPath)
+ val extdirs = PathSetting ("-extdirs", "dirs", "Override location of installed extensions", Defaults.scalaExtDirs)
+ val javabootclasspath = PathSetting ("-javabootclasspath", "path", "Override java boot classpath.", Defaults.javaBootClassPath)
+ val javaextdirs = PathSetting ("-javaextdirs", "path", "Override java extdirs classpath.", Defaults.javaExtDirs)
+ /** This one is most likely temporary, but so helpful while I try to get an iron grip on the classpath. */
+ val javaignorecp = BooleanSetting ("-javaignorecp", "scala will not use java's -classpath no matter what.")
+
+ val d = OutputSetting (outputDirs, ".")
+ val sourcepath = StringSetting ("-sourcepath", "path", "Specify where to find input source files", "")
+ val Ylogcp = BooleanSetting ("-Ylog-classpath", "Output information about what classpath is being applied.")
+
+ /**
+ * Standard settings
+ */
+ // argfiles is only for the help message
+ val argfiles = BooleanSetting ("@<file>", "A text file containing compiler arguments (options and source files)")
+ val defines = DefinesSetting()
+ val dependencyfile = 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.sourceEncoding)
+ val explaintypes = BooleanSetting ("-explaintypes", "Explain type errors in more detail")
+ val g = 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", "transitivenocp"), "all") .
+ withHelpSyntax("-make:<strategy>")
+ val nowarn = BooleanSetting ("-nowarn", "Generate no warnings")
+ val optimise = BooleanSetting ("-optimise", "Generates faster bytecode by applying optimisations to the program").withAbbreviation("-optimize") .
+ withPostSetHook(_ => List(inline, Xcloselim, Xdce) foreach (_.value = true))
+ val print = BooleanSetting ("-print", "Print program with all Scala-specific features removed")
+ val target = ChoiceSetting ("-target", "Specify for which target object files should be built", List("jvm-1.5", "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-name", "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 assemextdirs = StringSetting ("-Xassem-extdirs", "dirs", "List of directories containing assemblies, defaults to `lib'", Defaults.scalaLibDir.path).dependsOn(target, "msil")
+ val sourcedir = StringSetting ("-Xsourcedir", "directory", "When -target:msil, the source folder structure is mirrored in output directory.", ".").dependsOn(target, "msil")
+ 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 elideLevel = IntSetting ("-Xelide-level", "Generate calls to @elidable-marked methods only method priority is greater than argument.",
+ elidable.ASSERTION, None, elidable.byName.get(_))
+ val Xexperimental = BooleanSetting ("-Xexperimental", "Enable experimental extensions")
+ val noForwarders = BooleanSetting ("-Xno-forwarders", "Do not generate static forwarders in mirror classes")
+ 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 Xmigration28 = BooleanSetting ("-Xmigration", "Warn about constructs whose behavior may have changed between 2.7 and 2.8")
+ val nouescape = BooleanSetting ("-Xno-uescape", "Disables handling of \\u unicode escapes")
+ 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", "Path to search compiler plugins", Defaults.scalaPluginPath)
+ val Xprint = 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")
+
+ /**
+ * -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 Ycompacttrees = BooleanSetting ("-Ycompact-trees", "Use compact tree printer when displaying trees")
+ val noCompletion = BooleanSetting ("-Yno-completion", "Disable tab-completion in the REPL")
+ val Xdce = BooleanSetting ("-Ydead-code", "Perform dead code elimination")
+ val debug = BooleanSetting ("-Ydebug", "Output debugging messages")
+ 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, Int.MaxValue), (_: String) => 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 Ystatistics = 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", "invoke-dynamic"), "poly-cache") .
+ withHelpSyntax("-Ystruct-dispatch:<method>")
+ val specialize = BooleanSetting ("-Yspecialize", "Specialize generic code on types.")
+ val Yrangepos = BooleanSetting ("-Yrangepos", "Use range positions for syntax trees.")
+ val Yidedebug = BooleanSetting ("-Yide-debug", "Generate, validate and output trees using the interactive compiler.")
+ val Ybuilderdebug = ChoiceSetting ("-Ybuilder-debug", "Compile using the specified build manager", List("none", "refined", "simple"), "none") .
+ withHelpSyntax("-Ybuilder-debug:<method>")
+ val Ybuildmanagerdebug =
+ BooleanSetting ("-Ybuild-manager-debug", "Generate debug information for the Refined Build Manager compiler.")
+ val Ytyperdebug = BooleanSetting ("-Ytyper-debug", "Trace all type assignements")
+ val Ypmatdebug = BooleanSetting ("-Ypmat-debug", "Trace all pattern matcher activity.")
+ val Yrepldebug = BooleanSetting ("-Yrepl-debug", "Trace all repl activity.")
+ val Ypmatnaive = BooleanSetting ("-Ypmat-naive", "Desugar matches as naively as possible..")
+ val Ytailrec = BooleanSetting ("-Ytailrecommend", "Alert methods which would be tail-recursive if private or final.")
+ val Yjenkins = BooleanSetting ("-Yjenkins-hashCodes", "Use jenkins hash algorithm for case class generated hashCodes.")
+
+ // Warnings
+ val Ywarnfatal = BooleanSetting ("-Yfatal-warnings", "Fail the compilation if there are any warnings.")
+ val Xwarninit = BooleanSetting ("-Xwarninit", "Warn about possible changes in initialization semantics")
+ val Xchecknull = BooleanSetting ("-Xcheck-null", "Emit warning on selection of nullable reference")
+ val Xwarndeadcode = BooleanSetting ("-Ywarn-dead-code", "Emit warnings for dead code")
+ val YwarnShadow = BooleanSetting ("-Ywarn-shadowing", "Emit warnings about possible variable shadowing.")
+ val YwarnCatches = BooleanSetting ("-Ywarn-catches", "Emit warnings about catch blocks which catch everything.")
+ val Xwarnings = BooleanSetting ("-Xstrict-warnings", "Emit warnings about lots of things.") .
+ withPostSetHook(_ =>
+ List(YwarnShadow, YwarnCatches, Xwarndeadcode, Xwarninit) foreach (_.value = true)
+ )
+ /**
+ * "fsc-specific" settings.
+ */
+ val fscShutdown = BooleanSetting ("-shutdown", "Shutdown the fsc daemon")
+
+ /**
+ * -P "Plugin" settings
+ */
+ val pluginOptions = MultiStringSetting("-P", "plugin:opt", "Pass an option to a plugin") .
+ withHelpSyntax("-P:<plugin>:<opt>")
+}
diff --git a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
new file mode 100644
index 0000000000..69d411235c
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
@@ -0,0 +1,60 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package settings
+
+/** Settings which aren't behind a -X, -Y, or -P option.
+ * Wherever possible, the val and the option have identical.
+ * names.
+ */
+trait StandardScalaSettings {
+ self: AbsScalacSettings =>
+
+ /** Path related settings.
+ */
+ val bootclasspath: PathSetting
+ val classpath: PathSetting
+ val d: OutputSetting
+ val extdirs: PathSetting
+ val g: DebugSetting
+ val javabootclasspath: PathSetting
+ val javaextdirs: PathSetting
+ val javaignorecp: BooleanSetting
+ val sourcepath: StringSetting
+
+ /** Other settings.
+ */
+ val dependencyfile: StringSetting
+ val deprecation: BooleanSetting
+ val encoding: StringSetting
+ val explaintypes: BooleanSetting
+ val help: BooleanSetting
+ val make: ChoiceSetting
+ val nowarn: BooleanSetting
+ val optimise: BooleanSetting
+ val print: BooleanSetting
+ val target: ChoiceSetting
+ val unchecked: BooleanSetting
+ val uniqid: BooleanSetting
+ val verbose: BooleanSetting
+ val version: BooleanSetting
+
+ /** These are @<file> and -Dkey=val style settings, which don't
+ * nicely map to identifiers.
+ */
+ val argfiles: BooleanSetting
+ val defines: DefinesSetting
+
+ /** Compatibility stubs for options whose value name did
+ * not previously match the option name.
+ */
+ def XO = optimise
+ def debuginfo = g
+ def dependenciesFile = dependencyfile
+ def nowarnings = nowarn
+ def outdir = d
+ def printLate = print
+}
diff --git a/src/compiler/scala/tools/util/BashCompletion.scala b/src/compiler/scala/tools/util/BashCompletion.scala
index bb36326b7e..ad7c1136ca 100644
--- a/src/compiler/scala/tools/util/BashCompletion.scala
+++ b/src/compiler/scala/tools/util/BashCompletion.scala
@@ -7,7 +7,6 @@ package scala.tools
package util
import nsc.{ Global, Settings }
-import Settings._
/** Examines Settings and generates a bash completion file
* containing both bells and whistles.
@@ -83,6 +82,7 @@ _scala_commands
""".trim
private lazy val settings = new Settings()
+ import settings._
val phaseNames = "all" :: (new Global(settings) phaseNames)
val phaseSettings = settings.visibleSettings partialMap { case x: PhasesSetting => "\"" + x.name + "\"" }