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
|
package dotty.tools.dotc
import config.CompilerCommand
import core.Contexts.{Context, ContextBase}
import util.DotClass
import reporting._
import scala.util.control.NonFatal
abstract class Driver extends DotClass {
val prompt = "\ndotc> "
protected def newCompiler(): Compiler
protected def emptyReporter: Reporter = new StoreReporter(null)
protected def doCompile(compiler: Compiler, fileNames: List[String])(implicit ctx: Context): Reporter =
if (fileNames.nonEmpty)
try {
val run = compiler.newRun
run.compile(fileNames)
run.printSummary()
}
catch {
case ex: FatalError =>
ctx.error(ex.getMessage) // signals that we should fail compilation.
ctx.reporter
}
else emptyReporter
protected def initCtx = (new ContextBase).initialCtx
protected def sourcesRequired = true
def setup(args: Array[String], rootCtx: Context): (List[String], Context) = {
val ctx = rootCtx.fresh
val summary = CompilerCommand.distill(args)(ctx)
ctx.setSettings(summary.sstate)
val fileNames = CompilerCommand.checkUsage(summary, sourcesRequired)(ctx)
(fileNames, ctx)
}
/** Principal entry point to the compiler.
* Creates a new compiler instance and run it with arguments `args`.
*
* The optional arguments of this method all have `null` as their default
* value, this makes it easier to call this method by reflection or from Java.
*
* @param args Arguments to pass to the compiler.
* @param reporter Used to log errors, warnings, and info messages.
* The default reporter is used if this is `null`.
* @param callback Used to execute custom code during the compilation
* process. No callbacks will be executed if this is `null`.
* @return The `Reporter` used. Use `Reporter#hasErrors` to check
* if compilation succeeded.
*/
final def process(args: Array[String], reporter: Reporter = null,
callback: CompilerCallback = null): Reporter = {
val ctx = initCtx.fresh
if (reporter != null)
ctx.setReporter(reporter)
if (callback != null)
ctx.setCompilerCallback(callback)
process(args, ctx)
}
/** Entry point to the compiler with no optional arguments.
*
* This overload is provided for compatibility reasons: the
* `RawCompiler` of sbt expects this method to exist and calls
* it using reflection. Keeping it means that we can change
* the other overloads without worrying about breaking compatibility
* with sbt.
*/
final def process(args: Array[String]): Reporter =
process(args, null, null)
/** Entry point to the compiler using a custom `Context`.
*
* In most cases, you do not need a custom `Context` and should
* instead use one of the other overloads of `process`. However,
* the other overloads cannot be overriden, instead you
* should override this one which they call internally.
*
* @param args Arguments to pass to the compiler.
* @param rootCtx The root Context to use.
* @return The `Reporter` used. Use `Reporter#hasErrors` to check
* if compilation succeeded.
*/
def process(args: Array[String], rootCtx: Context): Reporter = {
val (fileNames, ctx) = setup(args, rootCtx)
doCompile(newCompiler(), fileNames)(ctx)
}
def main(args: Array[String]): Unit = {
// Preload scala.util.control.NonFatal. Otherwise, when trying to catch a StackOverflowError,
// we may try to load it but fail with another StackOverflowError and lose the original exception,
// see <https://groups.google.com/forum/#!topic/scala-user/kte6nak-zPM>.
val _ = NonFatal
sys.exit(if (process(args).hasErrors) 1 else 0)
}
}
class FatalError(msg: String) extends Exception
|