Skip to content

Commit 52a871f

Browse files
committed
add MainGenericCompiler
1 parent ee9cc8f commit 52a871f

File tree

2 files changed

+231
-38
lines changed

2 files changed

+231
-38
lines changed
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
package dotty.tools
2+
3+
import scala.language.unsafeNulls
4+
5+
import scala.annotation.tailrec
6+
import scala.io.Source
7+
import scala.util.Try
8+
import java.io.File
9+
import java.lang.Thread
10+
import scala.annotation.internal.sharable
11+
import dotty.tools.dotc.util.ClasspathFromClassloader
12+
import dotty.tools.runner.ObjectRunner
13+
import dotty.tools.dotc.config.Properties.envOrNone
14+
import dotty.tools.io.Jar
15+
import dotty.tools.runner.ScalaClassLoader
16+
import java.nio.file.Paths
17+
import dotty.tools.dotc.config.CommandLineParser
18+
import dotty.tools.scripting.StringDriver
19+
20+
enum CompileMode:
21+
case Guess
22+
case Compile
23+
case Decompile
24+
case PrintTasty
25+
case Script
26+
case Repl
27+
case Run
28+
29+
case class CompileSettings(
30+
verbose: Boolean = false,
31+
classPath: List[String] = List.empty,
32+
compileMode: CompileMode = CompileMode.Guess,
33+
exitCode: Int = 0,
34+
javaArgs: List[String] = List.empty,
35+
javaProps: List[(String, String)] = List.empty,
36+
scalaArgs: List[String] = List.empty,
37+
residualArgs: List[String] = List.empty,
38+
scriptArgs: List[String] = List.empty,
39+
targetScript: String = "",
40+
compiler: Boolean = false,
41+
quiet: Boolean = false,
42+
colors: Boolean = false,
43+
) {
44+
def withCompileMode(em: CompileMode): CompileSettings = this.compileMode match
45+
case CompileMode.Guess =>
46+
this.copy(compileMode = em)
47+
case _ =>
48+
println(s"compile_mode==[$compileMode], attempted overwrite by [$em]")
49+
this.copy(exitCode = 1)
50+
end withCompileMode
51+
52+
def withScalaArgs(args: String*): CompileSettings =
53+
this.copy(scalaArgs = scalaArgs.appendedAll(args.toList.filter(_.nonEmpty)))
54+
55+
def withJavaArgs(args: String*): CompileSettings =
56+
this.copy(javaArgs = javaArgs.appendedAll(args.toList.filter(_.nonEmpty)))
57+
58+
def withJavaProps(args: (String, String)*): CompileSettings =
59+
this.copy(javaProps = javaProps.appendedAll(args.toList))
60+
61+
def withResidualArgs(args: String*): CompileSettings =
62+
this.copy(residualArgs = residualArgs.appendedAll(args.toList.filter(_.nonEmpty)))
63+
64+
def withScriptArgs(args: String*): CompileSettings =
65+
this.copy(scriptArgs = scriptArgs.appendedAll(args.toList.filter(_.nonEmpty)))
66+
67+
def withTargetScript(file: String): CompileSettings =
68+
Try(Source.fromFile(file)).toOption match
69+
case Some(_) => this.copy(targetScript = file)
70+
case None =>
71+
println(s"not found $file")
72+
this.copy(exitCode = 2)
73+
end withTargetScript
74+
75+
def withCompiler: CompileSettings =
76+
this.copy(compiler = true)
77+
78+
def withQuiet: CompileSettings =
79+
this.copy(quiet = true)
80+
81+
def withColors: CompileSettings =
82+
this.copy(colors = true)
83+
84+
def withNoColors: CompileSettings =
85+
this.copy(colors = false)
86+
}
87+
88+
object MainGenericCompiler {
89+
90+
val classpathSeparator = File.pathSeparator
91+
92+
@sharable val javaOption = raw"""-J(.*)""".r
93+
@sharable val javaPropOption = raw"""-D(.+?)=(.?)""".r
94+
@tailrec
95+
def process(args: List[String], settings: CompileSettings): CompileSettings = args match
96+
case Nil =>
97+
settings
98+
case "--" :: tail =>
99+
process(Nil, settings.withResidualArgs(tail.toList*))
100+
case ("-v" | "-verbose" | "--verbose") :: tail =>
101+
process(tail, settings.withScalaArgs("-verbose"))
102+
case ("-q" | "-quiet") :: tail =>
103+
process(tail, settings.withQuiet)
104+
case "-Oshort" :: tail =>
105+
process(tail, settings.withJavaArgs("-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1"))
106+
case "-repl" :: tail =>
107+
process(tail, settings.withCompileMode(CompileMode.Repl))
108+
case "-script" :: targetScript :: tail =>
109+
process(Nil, settings
110+
.withCompileMode(CompileMode.Script)
111+
.withJavaProps("script.path" -> targetScript)
112+
.withTargetScript(targetScript)
113+
.withScriptArgs(tail.toList*))
114+
case "-compile" :: tail =>
115+
process(tail, settings.withCompileMode(CompileMode.Compile))
116+
case "-decompile" :: tail =>
117+
process(tail, settings.withCompileMode(CompileMode.Decompile))
118+
case "-print-tasty" :: tail =>
119+
process(tail, settings.withCompileMode(CompileMode.PrintTasty))
120+
case "-run" :: tail =>
121+
process(tail, settings.withCompileMode(CompileMode.Run))
122+
case "-colors" :: tail =>
123+
process(tail, settings.withColors)
124+
case "-no-colors" :: tail =>
125+
process(tail, settings.withNoColors)
126+
case "-with-compiler" :: tail =>
127+
process(tail, settings.withCompiler)
128+
case ("-cp" | "-classpath" | "--class-path") :: cp :: tail =>
129+
val cpEntries = cp.split(classpathSeparator).toList
130+
val singleEntryClasspath: Boolean = cpEntries.sizeIs == 1
131+
val globdir: String = if singleEntryClasspath then cp.replaceAll("[\\\\/][^\\\\/]*$", "") else "" // slash/backslash agnostic
132+
def validGlobbedJar(s: String): Boolean = s.startsWith(globdir) && ((s.toLowerCase.endsWith(".jar") || s.toLowerCase.endsWith(".zip")))
133+
val (tailargs, newEntries) = if singleEntryClasspath && validGlobbedJar(cpEntries.head) then
134+
// reassemble globbed wildcard classpath
135+
// globdir is wildcard directory for globbed jar files, reconstruct the intended classpath
136+
val cpJars = tail.takeWhile( f => validGlobbedJar(f) )
137+
val remainingArgs = tail.drop(cpJars.size)
138+
(remainingArgs, cpEntries ++ cpJars)
139+
else
140+
(tail, cpEntries)
141+
142+
process(tailargs, settings.copy(classPath = settings.classPath ++ newEntries.filter(_.nonEmpty)))
143+
case (o @ javaOption(stripped)) :: tail =>
144+
process(tail, settings.withJavaArgs(stripped))
145+
case (javaPropOption(opt, value)) :: tail =>
146+
process(tail, settings.withJavaProps(opt -> value))
147+
case arg :: tail =>
148+
process(tail, settings.withResidualArgs(arg))
149+
end process
150+
151+
def main(args: Array[String]): Unit =
152+
val settings = process(args.toList, CompileSettings())
153+
if settings.exitCode != 0 then System.exit(settings.exitCode)
154+
155+
def classpathSetting =
156+
if settings.classPath.isEmpty then List()
157+
else List("-classpath", settings.classPath.mkString(classpathSeparator))
158+
159+
def reconstructedArgs() =
160+
classpathSetting ++ settings.scalaArgs ++ settings.residualArgs
161+
162+
def addJavaProps(): Unit =
163+
settings.javaProps.foreach { (k, v) => sys.props(k) = v }
164+
165+
def run(settings: CompileSettings): Unit = settings.compileMode match
166+
case CompileMode.Compile =>
167+
addJavaProps()
168+
val properArgs = reconstructedArgs()
169+
dotty.tools.dotc.Main.main(properArgs.toArray)
170+
case CompileMode.Decompile =>
171+
addJavaProps()
172+
val properArgs = reconstructedArgs()
173+
dotty.tools.dotc.decompiler.Main.main(properArgs.toArray)
174+
case CompileMode.PrintTasty =>
175+
addJavaProps()
176+
val properArgs = reconstructedArgs()
177+
dotty.tools.dotc.core.tasty.TastyPrinter.main(properArgs.toArray)
178+
case CompileMode.Script => // Naive copy from scalac bash script
179+
addJavaProps()
180+
val properArgs =
181+
reconstructedArgs()
182+
++ List("-script", settings.targetScript)
183+
++ settings.scriptArgs
184+
scripting.Main.main(properArgs.toArray)
185+
case CompileMode.Repl | CompileMode.Run =>
186+
addJavaProps()
187+
val properArgs = reconstructedArgs()
188+
repl.Main.main(properArgs.toArray)
189+
case CompileMode.Guess =>
190+
run(settings.withCompileMode(CompileMode.Compile))
191+
end run
192+
193+
run(settings)
194+
end main
195+
}

dist/bin/scalac

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -30,43 +30,42 @@ source "$PROG_HOME/bin/common"
3030

3131
[ -z "$PROG_NAME" ] && PROG_NAME=$CompilerMain
3232

33-
withCompiler=true
34-
3533
while [[ $# -gt 0 ]]; do
36-
case "$1" in
37-
--) shift; for arg; do addResidual "$arg"; done; set -- ;;
38-
-v|-verbose) verbose=true && addScala "-verbose" && shift ;;
39-
-q|-quiet) quiet=true && shift ;;
40-
41-
# Optimize for short-running applications, see https://github.com/lampepfl/dotty/issues/222
42-
-Oshort) addJava "-XX:+TieredCompilation -XX:TieredStopAtLevel=1" && shift ;;
43-
-repl) PROG_NAME="$ReplMain" && shift ;;
44-
-script) PROG_NAME="$ScriptingMain" && target_script="$2" && shift && shift
45-
while [[ $# -gt 0 ]]; do addScript "$1" && shift ; done ;;
46-
-compile) PROG_NAME="$CompilerMain" && shift ;;
47-
-decompile) PROG_NAME="$DecompilerMain" && shift ;;
48-
-print-tasty) PROG_NAME="$TastyPrinterMain" && shift ;;
49-
-run) PROG_NAME="$ReplMain" && shift ;;
50-
-colors) colors=true && shift ;;
51-
-no-colors) unset colors && shift ;;
52-
-with-compiler) jvm_cp_args="$PSEP$DOTTY_COMP$PSEP$TASTY_CORE" && shift ;;
53-
54-
# break out -D and -J options and add them to java_args so
55-
# they reach the JVM in time to do some good. The -D options
56-
# will be available as system properties.
57-
-D*) addJava "$1" && shift ;;
58-
-J*) addJava "${1:2}" && shift ;;
59-
*) addResidual "$1" && shift ;;
34+
case "$1" in
35+
-D*)
36+
# pass to scala as well: otherwise we lose it sometimes when we
37+
# need it, e.g. communicating with a server compiler.
38+
addJava "$1"
39+
addScala "$1"
40+
# respect user-supplied -Dscala.usejavacp
41+
shift
42+
;;
43+
-J*)
44+
# as with -D, pass to scala even though it will almost
45+
# never be used.
46+
addJava "${1:2}"
47+
addScala "$1"
48+
shift
49+
;;
50+
-classpath*)
51+
if [ "$1" != "${1##* }" ]; then
52+
# hashbang-combined args "-classpath 'lib/*'"
53+
A=$1 ; shift # consume $1 before adding its substrings back
54+
set -- $A "$@" # split $1 on whitespace and put it back
55+
else
56+
addScala "$1"
57+
shift
58+
fi
59+
;;
60+
*)
61+
addScala "$1"
62+
shift
63+
;;
6064
esac
6165
done
6266

6367
compilerJavaClasspathArgs
6468

65-
if [ "$PROG_NAME" == "$ScriptingMain" ]; then
66-
setScriptName="-Dscript.path=$target_script"
67-
scripting_string="-script $target_script ${script_args[@]}"
68-
fi
69-
7069
[ -n "$script_trace" ] && set -x
7170
[ -z "${ConEmuPID-}" -o -n "${cygwin-}" ] && export MSYSTEM= PWD= # workaround for #12405
7271

@@ -75,11 +74,10 @@ eval "\"$JAVACMD\"" \
7574
${JAVA_OPTS:-$default_java_opts} \
7675
"${java_args[@]}" \
7776
"-classpath \"$jvm_cp_args\"" \
78-
-Dscala.usejavacp=true \
79-
"$setScriptName" \
80-
"$PROG_NAME" \
81-
"${scala_args[@]}" \
82-
"${residual_args[@]}" \
83-
"${scripting_string-}"
84-
scala_exit_status=$?
77+
"-Dscala.usejavacp=true" \
78+
"-Dscala.home=$PROG_HOME" \
79+
"dotty.tools.MainGenericCompiler" \
80+
"${scala_args[@]}"
8581

82+
scala_exit_status=$?
83+
onExit

0 commit comments

Comments
 (0)