-
Notifications
You must be signed in to change notification settings - Fork 1k
/
CompilerCommand.scala
133 lines (112 loc) · 4.77 KB
/
CompilerCommand.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package dotty.tools.dotc
package config
import java.nio.file.{Files, Paths}
import Settings._
import core.Contexts._
import util.DotClass
import Properties._
import scala.collection.JavaConverters._
object CompilerCommand extends DotClass {
/** The name of the command */
def cmdName = "dotc"
private def explainAdvanced = """
|-- Notes on option parsing --
|Boolean settings are always false unless set.
|Where multiple values are accepted, they should be comma-separated.
| example: -Xplugin:plugin1,plugin2
|<phases> means one or a comma-separated list of:
| - (partial) phase names with an optional "+" suffix to include the next phase
| - the string "all"
| example: -Xprint:all prints all phases.
| example: -Xprint:front,mixin prints the frontend and mixin phases.
| example: -Ylog:erasure+ logs the erasure phase and the phase after the erasure phase.
| This is useful because during the tree transform of phase X, we often
| already are in phase X + 1.
"""
def shortUsage = s"Usage: $cmdName <options> <source files>"
def versionMsg = s"Dotty compiler $versionString -- $copyrightString"
/** Distill arguments into summary detailing settings, errors and files to compiler */
def distill(args: Array[String])(implicit ctx: Context): ArgsSummary = {
/**
* Expands all arguments starting with @ to the contents of the
* file named like each argument.
*/
def expandArg(arg: String): List[String] = {
def stripComment(s: String) = s takeWhile (_ != '#')
val path = Paths.get(arg stripPrefix "@")
if (!Files.exists(path))
throw new java.io.FileNotFoundException("argument file %s could not be found" format path.getFileName)
val lines = Files.readAllLines(path) // default to UTF-8 encoding
val params = lines.asScala map stripComment mkString " "
CommandLineParser.tokenize(params)
}
// expand out @filename to the contents of that filename
def expandedArguments = args.toList flatMap {
case x if x startsWith "@" => expandArg(x)
case x => List(x)
}
ctx.settings.processArguments(expandedArguments, processAll = true)
}
/** Provide usage feedback on argument summary, assuming that all settings
* are already applied in context.
* @return The list of files to compile.
*/
def checkUsage(summary: ArgsSummary, sourcesRequired: Boolean)(implicit ctx: Context): List[String] = {
val settings = ctx.settings
/** Creates a help message for a subset of options based on cond */
def availableOptionsMsg(cond: Setting[_] => Boolean): String = {
val ss = (ctx.settings.allSettings filter cond).toList sortBy (_.name)
val width = (ss map (_.name.length)).max
def format(s: String) = ("%-" + width + "s") format s
def helpStr(s: Setting[_]) = s"${format(s.name)} ${s.description}"
ss map helpStr mkString "\n"
}
def createUsageMsg(label: String, shouldExplain: Boolean, cond: Setting[_] => Boolean): String = {
val prefix = List(
Some(shortUsage),
Some(explainAdvanced) filter (_ => shouldExplain),
Some(label + " options include:")
).flatten mkString "\n"
prefix + "\n" + availableOptionsMsg(cond)
}
def isStandard(s: Setting[_]): Boolean = !isAdvanced(s) && !isPrivate(s)
def isAdvanced(s: Setting[_]): Boolean = s.name startsWith "-X"
def isPrivate(s: Setting[_]) : Boolean = s.name startsWith "-Y"
/** Messages explaining usage and options */
def usageMessage = createUsageMsg("where possible standard", shouldExplain = false, isStandard)
def xusageMessage = createUsageMsg("Possible advanced", shouldExplain = true, isAdvanced)
def yusageMessage = createUsageMsg("Possible private", shouldExplain = true, isPrivate)
def shouldStopWithInfo = {
import settings._
Set(help, Xhelp, Yhelp) exists (_.value)
}
def infoMessage: String = {
import settings._
if (help.value) usageMessage
else if (Xhelp.value) xusageMessage
else if (Yhelp.value) yusageMessage
else ""
}
// Print all warnings encountered during arguments parsing
summary.warnings.foreach(ctx.warning(_))
if (summary.errors.nonEmpty) {
summary.errors foreach (ctx.error(_))
ctx.echo(" dotc -help gives more information")
Nil
}
else if (settings.version.value) {
ctx.echo(versionMsg)
Nil
} else if (!Properties.isJavaAtLeast("1.8")) {
ctx.error("Dotty requires Java 8 to run")
Nil
}
else if (shouldStopWithInfo) {
ctx.echo(infoMessage)
Nil
} else {
if (sourcesRequired && summary.arguments.isEmpty) ctx.echo(usageMessage)
summary.arguments
}
}
}