summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
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 /src/compiler/scala/tools
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.
Diffstat (limited to 'src/compiler/scala/tools')
-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 + "\"" }