Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 644 lines (565 sloc) 24.451 kb
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
1 /* NSC -- new Scala compiler
2d11a5b Updated copyright notices to 2011
Antonio Cunei authored
2 * Copyright 2005-2011 LAMP/EPFL
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
3 * @author Martin Odersky
4 */
5 // $Id$
6
e93c1a9 @paulp Introduces scala.tools.cmd providing command li...
paulp authored
7 package scala.tools
8 package nsc
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
9 package settings
10
2700617 @paulp Upgraded -d so you can output classes directly ...
paulp authored
11 import io.{ AbstractFile, Path, PlainFile, VirtualDirectory }
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
12 import scala.tools.util.StringOps
13 import scala.collection.mutable.ListBuffer
6dfcae3 @paulp Some modifications to repl classloading to make...
paulp authored
14 import scala.io.Source
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
15
16 /** A mutable Settings object.
17 */
fdfdd09 @paulp Warning! Warning! Yes, that's what's in this co...
paulp authored
18 class MutableSettings(val errorFn: String => Unit)
19 extends scala.reflect.internal.settings.MutableSettings
20 with AbsSettings
21 with ScalaSettings
22 with Mutable {
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
23 type ResultOfTryToSet = List[String]
24
4e987a3 Reflection toolboxes now respect settings that ...
Eugene Burmako authored
25 def withErrorFn(errorFn: String => Unit): MutableSettings = {
26 val settings = new MutableSettings(errorFn)
27 copyInto(settings)
28 settings
29 }
30
814cf34 @xeno-by Next generation of macros
xeno-by authored
31 def copyInto(settings: MutableSettings) {
4e987a3 Reflection toolboxes now respect settings that ...
Eugene Burmako authored
32 allSettings foreach { thisSetting =>
33 val otherSetting = settings.allSettings find { _.name == thisSetting.name }
34 otherSetting foreach { otherSetting =>
35 if (thisSetting.isSetByUser || otherSetting.isSetByUser) {
36 otherSetting.value = thisSetting.value.asInstanceOf[otherSetting.T]
37 }
38 }
39 }
40 }
41
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
42 /** Iterates over the arguments applying them to settings where applicable.
43 * Then verifies setting dependencies are met.
44 *
45 * This temporarily takes a boolean indicating whether to keep
46 * processing if an argument is seen which is not a command line option.
47 * This is an expedience for the moment so that you can say
48 *
49 * scalac -d /tmp foo.scala -optimise
50 *
51 * while also allowing
52 *
53 * scala Program opt opt
54 *
55 * to get their arguments.
56 *
57 * Returns (success, List of unprocessed arguments)
58 */
59 def processArguments(arguments: List[String], processAll: Boolean): (Boolean, List[String]) = {
eb0b73b @paulp Undoing some much too hacky code to implement a...
paulp authored
60 def loop(args: List[String], residualArgs: List[String]): (Boolean, List[String]) = args match {
61 case Nil =>
62 (checkDependencies, residualArgs)
63 case "--" :: xs =>
64 (checkDependencies, xs)
65 case x :: xs =>
66 val isOpt = x startsWith "-"
67 if (isOpt) {
68 val newArgs = parseParams(args)
69 if (args eq newArgs) {
70 errorFn("bad option: '" + x + "'")
71 (false, args)
72 }
1ad15b1 @paulp Discard empty strings in option position, but n...
paulp authored
73 // discard empties, sometimes they appear because of ant or etc.
74 // but discard carefully, because an empty string is valid as an argument
75 // to an option, e.g. -cp "" . So we discard them only when they appear
76 // in option position.
77 else if (x == "") {
78 loop(xs, residualArgs)
79 }
eb0b73b @paulp Undoing some much too hacky code to implement a...
paulp authored
80 else lookupSetting(x) match {
81 case Some(s) if s.shouldStopProcessing => (checkDependencies, newArgs)
82 case _ => loop(newArgs, residualArgs)
83 }
84 }
85 else {
86 if (processAll) loop(xs, residualArgs :+ x)
87 else (checkDependencies, args)
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
88 }
89 }
1ad15b1 @paulp Discard empty strings in option position, but n...
paulp authored
90 loop(arguments, Nil)
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
91 }
92 def processArgumentString(params: String) = processArguments(splitParams(params), true)
93
94 /** Create a new Settings object, copying all user-set values.
95 */
96 def copy(): Settings = {
97 val s = new Settings()
bd988df @paulp Fix for set/list/oops bug in MutableSettings#copy.
paulp authored
98 s.processArguments(recreateArgs, true)
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
99 s
100 }
101
102 /** A list pairing source directories with their output directory.
103 * This option is not available on the command line, but can be set by
104 * other tools (IDEs especially). The command line specifies a single
105 * output directory that is used for all source files, denoted by a
106 * '*' in this list.
107 */
108 lazy val outputDirs = new OutputDirs
109
f3b970b @paulp Accumulated work on fsc.
paulp authored
110 /** A list of settings which act based on prefix rather than an exact
111 * match. This is basically -D and -J.
112 */
113 lazy val prefixSettings = allSettings collect { case x: PrefixSetting => x }
114
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
115 /** Split the given line into parameters.
116 */
e93c1a9 @paulp Introduces scala.tools.cmd providing command li...
paulp authored
117 def splitParams(line: String) = cmd.Parser.tokenize(line, errorFn)
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
118
119 /** Returns any unprocessed arguments.
120 */
c5c02cf removed duplicated error message for bad compil...
michelou authored
121 protected def parseParams(args: List[String]): List[String] = {
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
122 // verify command exists and call setter
123 def tryToSetIfExists(
124 cmd: String,
125 args: List[String],
126 setter: (Setting) => (List[String] => Option[List[String]])
127 ): Option[List[String]] =
128 lookupSetting(cmd) match {
c5c02cf removed duplicated error message for bad compil...
michelou authored
129 //case None => errorFn("Parameter '" + cmd + "' is not recognised by Scalac.") ; None
130 case None => None //error reported in processArguments
4f12f2a @paulp Noticed that Settings post-set hooks were not b...
paulp authored
131 case Some(cmd) => setter(cmd)(args)
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
132 }
133
134 // if arg is of form -Xfoo:bar,baz,quux
135 def parseColonArg(s: String): Option[List[String]] = {
136 val (p, args) = StringOps.splitWhere(s, _ == ':', true) getOrElse (return None)
137
138 // any non-Nil return value means failure and we return s unmodified
1c89ab7 @odersky Enabling postfix ops feature warning, and working on libs to avoid them.
odersky authored
139 tryToSetIfExists(p, (args split ",").toList, (s: Setting) => s.tryToSetColon _)
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
140 }
141
142 // if arg is of form -Xfoo or -Xfoo bar (name = "-Xfoo")
143 def parseNormalArg(p: String, args: List[String]): Option[List[String]] =
144 tryToSetIfExists(p, args, (s: Setting) => s.tryToSet _)
145
eb0b73b @paulp Undoing some much too hacky code to implement a...
paulp authored
146 args match {
147 case Nil => Nil
148 case arg :: rest =>
149 if (!arg.startsWith("-")) {
150 errorFn("Argument '" + arg + "' does not start with '-'.")
151 args
a69c1af added -jar option to scala interpreter
michelou authored
152 }
eb0b73b @paulp Undoing some much too hacky code to implement a...
paulp authored
153 else if (arg == "-") {
154 errorFn("'-' is not a valid argument.")
155 args
a69c1af added -jar option to scala interpreter
michelou authored
156 }
eb0b73b @paulp Undoing some much too hacky code to implement a...
paulp authored
157 else {
158 // we dispatch differently based on the appearance of p:
f3b970b @paulp Accumulated work on fsc.
paulp authored
159 // 1) If it matches a prefix setting it is sent there directly.
160 // 2) If it has a : it is presumed to be -Xfoo:bar,baz
161 // 3) Otherwise, the whole string should be a command name
eb0b73b @paulp Undoing some much too hacky code to implement a...
paulp authored
162 //
163 // Internally we use Option[List[String]] to discover error,
164 // but the outside expects our arguments back unchanged on failure
f3b970b @paulp Accumulated work on fsc.
paulp authored
165 val prefix = prefixSettings find (_ respondsTo arg)
166 if (prefix.isDefined) {
167 prefix.get tryToSet args
168 rest
169 }
170 else if (arg contains ":") parseColonArg(arg) match {
eb0b73b @paulp Undoing some much too hacky code to implement a...
paulp authored
171 case Some(_) => rest
172 case None => args
173 }
174 else parseNormalArg(arg, rest) match {
175 case Some(xs) => xs
176 case None => args
177 }
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
178 }
179 }
180 }
181
6dfcae3 @paulp Some modifications to repl classloading to make...
paulp authored
182 /** Initializes these settings for embedded use by type `T`.
183 * The class loader defining `T` should provide resources `app.class.path`
184 * and `boot.class.path`. These resources should contain the application
185 * and boot classpaths in the same form as would be passed on the command line.*/
0f0144c @xeno-by migrates stdlib and compiler to tags
xeno-by authored
186 def embeddedDefaults[T: ClassTag]: Unit =
187 embeddedDefaults(classTag[T].erasure.getClassLoader)
6dfcae3 @paulp Some modifications to repl classloading to make...
paulp authored
188
189 /** Initializes these settings for embedded use by a class from the given class loader.
190 * The class loader for `T` should provide resources `app.class.path`
191 * and `boot.class.path`. These resources should contain the application
192 * and boot classpaths in the same form as would be passed on the command line.*/
193 def embeddedDefaults(loader: ClassLoader) {
194 explicitParentLoader = Option(loader) // for the Interpreter parentClassLoader
195 getClasspath("app", loader) foreach { classpath.value = _ }
196 getClasspath("boot", loader) foreach { bootclasspath append _ }
197 }
198
199 /** The parent loader to use for the interpreter.*/
200 private[nsc] var explicitParentLoader: Option[ClassLoader] = None
201
202 /** Retrieves the contents of resource "${id}.class.path" from `loader`
203 * (wrapped in Some) or None if the resource does not exist.*/
204 private def getClasspath(id: String, loader: ClassLoader): Option[String] =
205 Option(loader).flatMap(ld => Option(ld.getResource(id + ".class.path"))).map { cp =>
206 Source.fromURL(cp).mkString
207 }
208
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
209 // a wrapper for all Setting creators to keep our list up to date
210 private def add[T <: Setting](s: T): T = {
211 allSettings += s
212 s
213 }
214
215 def BooleanSetting(name: String, descr: String) = add(new BooleanSetting(name, descr))
ed54595 @paulp Cleaned up and brought up to date the help text...
paulp authored
216 def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String) =
217 add(new ChoiceSetting(name, helpArg, descr, choices, default))
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
218 def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]) = add(new IntSetting(name, descr, default, range, parser))
219 def MultiStringSetting(name: String, arg: String, descr: String) = add(new MultiStringSetting(name, arg, descr))
220 def OutputSetting(outputDirs: OutputDirs, default: String) = add(new OutputSetting(outputDirs, default))
8095275 @paulp Created infrastructure for testing icode + sett...
paulp authored
221 def PhasesSetting(name: String, descr: String, default: String = "") = add(new PhasesSetting(name, descr, default))
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
222 def StringSetting(name: String, arg: String, descr: String, default: String) = add(new StringSetting(name, arg, descr, default))
ed54595 @paulp Cleaned up and brought up to date the help text...
paulp authored
223 def PathSetting(name: String, descr: String, default: String): PathSetting = {
8e380b6 @paulp Created invisible setting to expose empty packa...
paulp authored
224 val prepend = StringSetting(name + "/p", "", "", "").internalOnly()
225 val append = StringSetting(name + "/a", "", "", "").internalOnly()
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
226
ed54595 @paulp Cleaned up and brought up to date the help text...
paulp authored
227 add(new PathSetting(name, descr, default, prepend, append))
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
228 }
f3b970b @paulp Accumulated work on fsc.
paulp authored
229 def PrefixSetting(name: String, prefix: String, descr: String): PrefixSetting = add(new PrefixSetting(name, prefix, descr))
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
230
231 /** A class for holding mappings from source directories to
232 * their output location. This functionality can be accessed
233 * only programmatically. The command line compiler uses a
234 * single output location, but tools may use this functionality
235 * to set output location per source directory.
236 */
237 class OutputDirs {
238 /** Pairs of source directory - destination directory. */
239 private var outputDirs: List[(AbstractFile, AbstractFile)] = Nil
240
241 /** If this is not None, the output location where all
242 * classes should go.
243 */
244 private var singleOutDir: Option[AbstractFile] = None
245
246 /** Add a destination directory for sources found under srcdir.
247 * Both directories should exits.
248 */
249 def add(srcDir: String, outDir: String): Unit =
250 add(checkDir(AbstractFile.getDirectory(srcDir), srcDir),
251 checkDir(AbstractFile.getDirectory(outDir), outDir))
252
253 /** Check that dir is exists and is a directory. */
2700617 @paulp Upgraded -d so you can output classes directly ...
paulp authored
254 private def checkDir(dir: AbstractFile, name: String, allowJar: Boolean = false): AbstractFile = (
255 if (dir != null && dir.isDirectory)
256 dir
257 else if (allowJar && dir == null && Path.isJarOrZip(name, false))
258 new PlainFile(Path(name))
259 else
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
260 throw new FatalError(name + " does not exist or is not a directory")
2700617 @paulp Upgraded -d so you can output classes directly ...
paulp authored
261 )
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
262
263 /** Set the single output directory. From now on, all files will
264 * be dumped in there, regardless of previous calls to 'add'.
265 */
266 def setSingleOutput(outDir: String) {
267 val dst = AbstractFile.getDirectory(outDir)
2700617 @paulp Upgraded -d so you can output classes directly ...
paulp authored
268 setSingleOutput(checkDir(dst, outDir, true))
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
269 }
270
2700617 @paulp Upgraded -d so you can output classes directly ...
paulp authored
271 def getSingleOutput: Option[AbstractFile] = singleOutDir
272
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
273 /** Set the single output directory. From now on, all files will
274 * be dumped in there, regardless of previous calls to 'add'.
275 */
276 def setSingleOutput(dir: AbstractFile) {
277 singleOutDir = Some(dir)
278 }
279
280 def add(src: AbstractFile, dst: AbstractFile) {
281 singleOutDir = None
9bdc1a0 @paulp Following up on things that -Xlint told me, som...
paulp authored
282 outputDirs ::= ((src, dst))
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
283 }
284
285 /** Return the list of source-destination directory pairs. */
286 def outputs: List[(AbstractFile, AbstractFile)] = outputDirs
287
288 /** Return the output directory for the given file.
289 */
290 def outputDirFor(src: AbstractFile): AbstractFile = {
291 def isBelow(srcDir: AbstractFile, outDir: AbstractFile) =
292 src.path.startsWith(srcDir.path)
293
294 singleOutDir match {
295 case Some(d) => d
296 case None =>
297 (outputs find (isBelow _).tupled) match {
298 case Some((_, d)) => d
299 case _ =>
300 throw new FatalError("Could not find an output directory for "
301 + src.path + " in " + outputs)
302 }
303 }
304 }
305
306 /** Return the source file path(s) which correspond to the given
307 * classfile path and SourceFile attribute value, subject to the
308 * condition that source files are arranged in the filesystem
309 * according to Java package layout conventions.
310 *
311 * The given classfile path must be contained in at least one of
312 * the specified output directories. If it does not then this
313 * method returns Nil.
314 *
315 * Note that the source file is not required to exist, so assuming
316 * a valid classfile path this method will always return a list
317 * containing at least one element.
318 *
319 * Also that if two or more source path elements target the same
320 * output directory there will be two or more candidate source file
321 * paths.
322 */
323 def srcFilesFor(classFile : AbstractFile, srcPath : String) : List[AbstractFile] = {
324 def isBelow(srcDir: AbstractFile, outDir: AbstractFile) =
325 classFile.path.startsWith(outDir.path)
326
327 singleOutDir match {
41c2801 @hubertp Better fix for #2757. Review by milessabin.
hubertp authored
328 case Some(d) =>
9933cbe @hubertp Missing bit from r21620.
hubertp authored
329 d match {
2700617 @paulp Upgraded -d so you can output classes directly ...
paulp authored
330 case _: VirtualDirectory | _: io.ZipArchive => Nil
9933cbe @hubertp Missing bit from r21620.
hubertp authored
331 case _ => List(d.lookupPathUnchecked(srcPath, false))
332 }
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
333 case None =>
334 (outputs filter (isBelow _).tupled) match {
335 case Nil => Nil
336 case matches => matches.map(_._1.lookupPathUnchecked(srcPath, false))
337 }
338 }
339 }
340 }
341
342 /** A base class for settings of all types.
60c8697 @kzys Fixes #4490 and #4467.
kzys authored
343 * Subclasses each define a `value` field of the appropriate type.
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
344 */
345 abstract class Setting(val name: String, val helpDescription: String) extends AbsSetting with SettingValue with Mutable {
346 /** Will be called after this Setting is set for any extra work. */
347 private var _postSetHook: this.type => Unit = (x: this.type) => ()
a10f699 @paulp Seeing about getting trunk building again, no r...
paulp authored
348 override def postSetHook(): Unit = _postSetHook(this)
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
349 def withPostSetHook(f: this.type => Unit): this.type = { _postSetHook = f ; this }
350
351 /** The syntax defining this setting in a help string */
352 private var _helpSyntax = name
353 override def helpSyntax: String = _helpSyntax
354 def withHelpSyntax(s: String): this.type = { _helpSyntax = s ; this }
355
356 /** Abbreviations for this setting */
357 private var _abbreviations: List[String] = Nil
358 override def abbreviations = _abbreviations
359 def withAbbreviation(s: String): this.type = { _abbreviations ++= List(s) ; this }
360
361 /** Optional dependency on another setting */
362 private var dependency: Option[(Setting, String)] = None
363 override def dependencies = dependency.toList
364 def dependsOn(s: Setting, value: String): this.type = { dependency = Some((s, value)); this }
5691a39 @paulp Wanting to deprecate -make, first I had to writ...
paulp authored
365
366 private var _deprecationMessage: Option[String] = None
367 override def deprecationMessage = _deprecationMessage
368 def withDeprecationMessage(msg: String): this.type = { _deprecationMessage = Some(msg) ; this }
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
369 }
370
371 /** A setting represented by an integer */
372 class IntSetting private[nsc](
373 name: String,
374 descr: String,
375 val default: Int,
376 val range: Option[(Int, Int)],
377 parser: String => Option[Int])
378 extends Setting(name, descr) {
379 type T = Int
82eb1aa @paulp Hand specialized SettingValue.
paulp authored
380 protected var v: Int = default
381 override def value: Int = v
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
382
383 // not stable values!
384 val IntMin = Int.MinValue
385 val IntMax = Int.MaxValue
386 def min = range map (_._1) getOrElse IntMin
387 def max = range map (_._2) getOrElse IntMax
388
389 override def value_=(s: Int) =
390 if (isInputValid(s)) super.value_=(s) else errorMsg
391
392 // Validate that min and max are consistent
393 assert(min <= max)
394
395 // Helper to validate an input
396 private def isInputValid(k: Int): Boolean = (min <= k) && (k <= max)
397
acc5311 @paulp After having to update the code for someone els...
paulp authored
398 // Helper to generate a textual explanation of valid inputs
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
399 private def getValidText: String = (min, max) match {
400 case (IntMin, IntMax) => "can be any integer"
401 case (IntMin, x) => "must be less than or equal to "+x
402 case (x, IntMax) => "must be greater than or equal to "+x
403 case _ => "must be between %d and %d".format(min, max)
404 }
405
406 // Ensure that the default value is actually valid
407 assert(isInputValid(default))
408
409 def parseArgument(x: String): Option[Int] = {
410 parser(x) orElse {
411 try { Some(x.toInt) }
412 catch { case _: NumberFormatException => None }
413 }
414 }
415
c5d9b7e @paulp I wrote a warning when nullary methods return U...
paulp authored
416 def errorMsg() = errorFn("invalid setting for -"+name+" "+getValidText)
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
417
418 def tryToSet(args: List[String]) =
419 if (args.isEmpty) errorAndValue("missing argument", None)
420 else parseArgument(args.head) match {
421 case Some(i) => value = i ; Some(args.tail)
422 case None => errorMsg ; None
423 }
424
425 def unparse: List[String] =
426 if (value == default) Nil
427 else List(name, value.toString)
4b04c9c @paulp Altered IntSetting help syntax to be more indic...
paulp authored
428
429 withHelpSyntax(name + " <n>")
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
430 }
431
432 /** A setting represented by a boolean flag (false, unless set) */
433 class BooleanSetting private[nsc](
434 name: String,
435 descr: String)
436 extends Setting(name, descr) {
437 type T = Boolean
82eb1aa @paulp Hand specialized SettingValue.
paulp authored
438 protected var v: Boolean = false
439 override def value: Boolean = v
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
440
441 def tryToSet(args: List[String]) = { value = true ; Some(args) }
442 def unparse: List[String] = if (value) List(name) else Nil
8290934 Partial revert of r24325; tryToSetFromPropertyV...
Eugene Vigdorchik authored
443 override def tryToSetFromPropertyValue(s : String) {
444 value = s.equalsIgnoreCase("true")
445 }
be9a178 @paulp Changes to startup.
paulp authored
446 }
447
448 /** A special setting for accumulating arguments like -Dfoo=bar. */
f3b970b @paulp Accumulated work on fsc.
paulp authored
449 class PrefixSetting private[nsc](
be9a178 @paulp Changes to startup.
paulp authored
450 name: String,
451 prefix: String,
452 descr: String)
453 extends Setting(name, descr) {
f3b970b @paulp Accumulated work on fsc.
paulp authored
454 type T = List[String]
82eb1aa @paulp Hand specialized SettingValue.
paulp authored
455 protected var v: T = Nil
be9a178 @paulp Changes to startup.
paulp authored
456
f3b970b @paulp Accumulated work on fsc.
paulp authored
457 def tryToSet(args: List[String]) = args match {
458 case x :: xs if x startsWith prefix =>
459 v = v :+ x
460 Some(xs)
461 case _ =>
462 None
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
463 }
f3b970b @paulp Accumulated work on fsc.
paulp authored
464 override def respondsTo(token: String) = token startsWith prefix
465 def unparse: List[String] = value
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
466 }
467
60c8697 @kzys Fixes #4490 and #4467.
kzys authored
468 /** A setting represented by a string, (`default` unless set) */
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
469 class StringSetting private[nsc](
470 name: String,
471 val arg: String,
472 descr: String,
473 val default: String)
474 extends Setting(name, descr) {
475 type T = String
82eb1aa @paulp Hand specialized SettingValue.
paulp authored
476 protected var v: T = default
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
477
478 def tryToSet(args: List[String]) = args match {
479 case Nil => errorAndValue("missing argument", None)
480 case x :: xs => value = x ; Some(xs)
481 }
482 def unparse: List[String] = if (value == default) Nil else List(name, value)
483
484 withHelpSyntax(name + " <" + arg + ">")
485 }
486
487 class PathSetting private[nsc](
488 name: String,
489 descr: String,
490 default: String,
491 prependPath: StringSetting,
492 appendPath: StringSetting)
ed54595 @paulp Cleaned up and brought up to date the help text...
paulp authored
493 extends StringSetting(name, "path", descr, default) {
e93c1a9 @paulp Introduces scala.tools.cmd providing command li...
paulp authored
494 import util.ClassPath.join
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
495 def prepend(s: String) = prependPath.value = join(s, prependPath.value)
496 def append(s: String) = appendPath.value = join(appendPath.value, s)
497
498 override def value = join(
499 prependPath.value,
500 super.value,
501 appendPath.value
502 )
503 }
504
505 /** Set the output directory. */
506 class OutputSetting private[nsc](
4d25cc3 @paulp Trying to get fsc doing the right thing with re...
paulp authored
507 private[nsc] val outputDirs: OutputDirs,
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
508 default: String)
2700617 @paulp Upgraded -d so you can output classes directly ...
paulp authored
509 extends StringSetting("-d", "directory|jar", "destination for generated classfiles.", default) {
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
510 value = default
511 override def value_=(str: String) {
512 super.value_=(str)
1fd0b31 @paulp Since somewhere before 2.8.0 shipped scalac has...
paulp authored
513 try outputDirs.setSingleOutput(str)
514 catch { case FatalError(msg) => errorFn(msg) }
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
515 }
516 }
517
518 /** A setting that accumulates all strings supplied to it,
519 * until it encounters one starting with a '-'. */
520 class MultiStringSetting private[nsc](
521 name: String,
522 val arg: String,
523 descr: String)
524 extends Setting(name, descr) {
525 type T = List[String]
82eb1aa @paulp Hand specialized SettingValue.
paulp authored
526 protected var v: T = Nil
217415a @paulp More progress toward immutable Settings, and va...
paulp authored
527 def appendToValue(str: String) { value ++= List(str) }
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
528
529 def tryToSet(args: List[String]) = {
530 val (strings, rest) = args span (x => !x.startsWith("-"))
531 strings foreach appendToValue
532
533 Some(rest)
534 }
535 override def tryToSetColon(args: List[String]) = tryToSet(args)
e7b362f @dotta -Xplugin value passed by the Eclipse IDE are incorrectly parsed when it
dotta authored
536 override def tryToSetFromPropertyValue(s: String) = tryToSet(s.trim.split(',').toList)
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
537 def unparse: List[String] = value map { name + ":" + _ }
538
539 withHelpSyntax(name + ":<" + arg + ">")
540 }
541
2621ee6 scaladoc fixes and improvements
michelou authored
542 /** A setting represented by a string in a given set of `choices`,
543 * (`default` unless set).
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
544 */
545 class ChoiceSetting private[nsc](
546 name: String,
ed54595 @paulp Cleaned up and brought up to date the help text...
paulp authored
547 helpArg: String,
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
548 descr: String,
b13d8fe @milessabin Unbreak the IDE build following [21086].
milessabin authored
549 override val choices: List[String],
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
550 val default: String)
ed54595 @paulp Cleaned up and brought up to date the help text...
paulp authored
551 extends Setting(name, descr + choices.mkString(" (", ",", ") default:" + default)) {
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
552 type T = String
82eb1aa @paulp Hand specialized SettingValue.
paulp authored
553 protected var v: T = default
69d8830 @paulp Removed unnecessary DebugSetting, folding the s...
paulp authored
554 def indexOfChoice: Int = choices indexOf value
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
555
455ee61 @paulp [I'm laptop only so there's some chance this wi...
paulp authored
556 private def usageErrorMessage = {
557 "Usage: %s:<%s>\n where <%s> choices are %s (default: %s)\n".format(
558 name, helpArg, helpArg, choices mkString ", ", default)
559 }
560 def tryToSet(args: List[String]) = errorAndValue(usageErrorMessage, None)
69d8830 @paulp Removed unnecessary DebugSetting, folding the s...
paulp authored
561
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
562 override def tryToSetColon(args: List[String]) = args match {
455ee61 @paulp [I'm laptop only so there's some chance this wi...
paulp authored
563 case Nil => errorAndValue(usageErrorMessage, None)
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
564 case List(x) if choices contains x => value = x ; Some(Nil)
565 case List(x) => errorAndValue("'" + x + "' is not a valid choice for '" + name + "'", None)
566 case xs => errorAndValue("'" + name + "' does not accept multiple arguments.", None)
567 }
568 def unparse: List[String] =
569 if (value == default) Nil else List(name + ":" + value)
8290934 Partial revert of r24325; tryToSetFromPropertyV...
Eugene Vigdorchik authored
570 override def tryToSetFromPropertyValue(s: String) = tryToSetColon(s::Nil)
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
571
ed54595 @paulp Cleaned up and brought up to date the help text...
paulp authored
572 withHelpSyntax(name + ":<" + helpArg + ">")
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
573 }
574
8095275 @paulp Created infrastructure for testing icode + sett...
paulp authored
575 private def mkPhasesHelp(descr: String, default: String) = {
576 descr + " <phases>" + (
577 if (default == "") "" else " (default: " + default + ")"
578 )
579 }
580
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
581 /** A setting represented by a list of strings which should be prefixes of
582 * phase names. This is not checked here, however. Alternatively the string
2621ee6 scaladoc fixes and improvements
michelou authored
583 * `"all"` can be used to represent all phases.
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
584 * (the empty list, unless set)
585 */
586 class PhasesSetting private[nsc](
587 name: String,
8095275 @paulp Created infrastructure for testing icode + sett...
paulp authored
588 descr: String,
589 default: String
590 ) extends Setting(name, mkPhasesHelp(descr, default)) {
591 private[nsc] def this(name: String, descr: String) = this(name, descr, "")
592
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
593 type T = List[String]
82eb1aa @paulp Hand specialized SettingValue.
paulp authored
594 protected var v: T = Nil
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
595 override def value = if (v contains "all") List("all") else super.value
ed54595 @paulp Cleaned up and brought up to date the help text...
paulp authored
596 private lazy val (numericValues, stringValues) =
9c776fd @paulp Fixed an edge case setting crasher, no review.
paulp authored
597 value filterNot (_ == "" ) partition (_ forall (ch => ch.isDigit || ch == '-'))
ed54595 @paulp Cleaned up and brought up to date the help text...
paulp authored
598
599 /** A little ad-hoc parsing. If a string is not the name of a phase, it can also be:
600 * a phase id: 5
601 * a phase id range: 5-10 (inclusive of both ends)
602 * a range with no start: -5 means up to and including 5
603 * a range with no end: 10- means 10 until completion.
604 */
605 private def stringToPhaseIdTest(s: String): Int => Boolean = (s indexOf '-') match {
606 case -1 => (_ == s.toInt)
607 case 0 => (_ <= s.tail.toInt)
608 case idx =>
609 if (s.last == '-') (_ >= s.init.toInt)
610 else (s splitAt idx) match {
611 case (s1, s2) => (id => id >= s1.toInt && id <= s2.tail.toInt)
612 }
613 }
614 private lazy val phaseIdTest: Int => Boolean =
615 (numericValues map stringToPhaseIdTest) match {
616 case Nil => _ => false
617 case fns => fns.reduceLeft((f1, f2) => id => f1(id) || f2(id))
618 }
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
619
8095275 @paulp Created infrastructure for testing icode + sett...
paulp authored
620 def tryToSet(args: List[String]) =
621 if (default == "") errorAndValue("missing phase", None)
622 else { tryToSetColon(List(default)) ; Some(args) }
623
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
624 override def tryToSetColon(args: List[String]) = args match {
8095275 @paulp Created infrastructure for testing icode + sett...
paulp authored
625 case Nil => if (default == "") errorAndValue("missing phase", None) else tryToSetColon(List(default))
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
626 case xs => value = (value ++ xs).distinct.sorted ; Some(Nil)
627 }
628 // we slightly abuse the usual meaning of "contains" here by returning
629 // true if our phase list contains "all", regardless of the incoming argument
ed54595 @paulp Cleaned up and brought up to date the help text...
paulp authored
630 def contains(phName: String) = doAllPhases || containsName(phName)
631 def containsName(phName: String) = stringValues exists (phName startsWith _)
632 def containsId(phaseId: Int) = phaseIdTest(phaseId)
633 def containsPhase(ph: Phase) = contains(ph.name) || containsId(ph.id)
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
634
ed54595 @paulp Cleaned up and brought up to date the help text...
paulp authored
635 def doAllPhases = stringValues contains "all"
636 def unparse: List[String] = value map (name + ":" + _)
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
637
8095275 @paulp Created infrastructure for testing icode + sett...
paulp authored
638 withHelpSyntax(
639 if (default == "") name + ":<phases>"
640 else name + "[:phases]"
641 )
5f9c20c @paulp One minute too many trying to figure out where ...
paulp authored
642 }
643 }
Something went wrong with that request. Please try again.