-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathSimpleDriver.scala
90 lines (79 loc) · 3.75 KB
/
SimpleDriver.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
package replpp.util
import dotty.tools.dotc.Driver
import dotty.tools.dotc.core.Contexts
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.reporting.{ConsoleReporter, Diagnostic, Reporter}
import dotty.tools.dotc.util.SourcePosition
import dotty.tools.io.{Directory, PlainDirectory}
import replpp.scripting.CompilerError
import java.nio.file.{Files, Path}
import scala.language.unsafeNulls
import scala.util.Try
import scala.util.control.NoStackTrace
/** Compiles input files to a temporary directory
*
* TODO: use a VirtualDirectory for the output - I didn't manage to find a good way to pass those to the
* Context of the DottyReplDriver yet...
* val virtualDirectory = new VirtualDirectory("(virtual)")
* val cp = ClassPathFactory.newClassPath(virtualDirectory)
*
* TODO: cache results
* i.e. store hash of all inputs?
* that functionality must exist somewhere already, e.g. zinc incremental compiler, or even in dotty itself?
*/
class SimpleDriver(linesBeforeRunBeforeCode: Int = 0, linesBeforeScript: Int = 0) extends Driver {
def compileAndGetOutputDir[A](compilerArgs: Array[String], inputFiles: Seq[Path], verbose: Boolean): Try[Path] =
compile(compilerArgs, inputFiles, verbose) { (ctx, outDir) => outDir }
/** compiles given inputFiles and returns root directory that contains the class and tasty files */
def compile[A](compilerArgs: Array[String], inputFiles: Seq[Path], verbose: Boolean)(fun: (Context, Path) => A): Try[A] = {
if (verbose) {
println(s"compiler arguments: ${compilerArgs.mkString(",")}")
println(s"inputFiles: ${inputFiles.mkString(";")}")
}
val inputFiles0 = inputFiles.map(pathAsString).toArray
val allArgs = compilerArgs ++ inputFiles0
Try {
val (toCompile, rootCtx) = setup(allArgs, initCtx.fresh)
.getOrElse(throw CompilerError(s"error during setup with args=`${allArgs.mkString(" ")}`, details should have been reported already on stderr/stdout"))
val outDir = Files.createTempDirectory("scala-repl-pp")
given ctx0: Context = {
val ctx = rootCtx.fresh.setSetting(rootCtx.settings.outputDir, new PlainDirectory(Directory(outDir)))
if (linesBeforeRunBeforeCode != 0 || linesBeforeScript != 0) {
ctx.setReporter(createReporter(linesBeforeRunBeforeCode, linesBeforeScript, rootCtx.reporter))
}
if (verbose) {
ctx.setSetting(rootCtx.settings.help, true)
.setSetting(rootCtx.settings.XshowPhases, true)
.setSetting(rootCtx.settings.Vhelp, true)
.setSetting(rootCtx.settings.Vprofile, true)
.setSetting(rootCtx.settings.explain, true)
} else ctx
}
if (doCompile(newCompiler, toCompile).hasErrors) {
val msgAddonMaybe = if (verbose) "" else " - try `--verbose` for more output"
throw new CompilerError(s"Errors encountered during compilation$msgAddonMaybe") with NoStackTrace
} else {
fun(ctx0, outDir)
}
}
}
private def createReporter(linesBeforeRunBeforeCode: Int, linesBeforeScript: Int, originalReporter: Reporter): Reporter = {
new Reporter {
override def doReport(dia: Diagnostic)(using Context): Unit = {
val adjustedPos = new SourcePosition(source = dia.pos.source, span = dia.pos.span, outer = dia.pos.outer) {
override def line: Int = {
val original = super.line
val adjusted = original - linesBeforeScript
if (adjusted >= 0) {
adjusted
} else {
// adjusted line number is negative, i.e. the error must be in the `runBefore` code
original - linesBeforeRunBeforeCode
}
}
}
originalReporter.doReport(new Diagnostic(dia.msg, adjustedPos, dia.level))
}
}
}
}