Skip to content
95 changes: 21 additions & 74 deletions compiler/src/dotty/tools/MainGenericCompiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,8 @@ package dotty.tools

import scala.annotation.tailrec
import scala.io.Source
import scala.util.Try
import scala.util.{Try, Success, Failure}
import java.io.File
import java.lang.Thread
import scala.annotation.internal.sharable
import dotty.tools.dotc.util.ClasspathFromClassloader
import dotty.tools.dotc.config.Properties.envOrNone
import dotty.tools.io.Jar
import java.nio.file.Paths
import dotty.tools.dotc.config.CommandLineParser
import dotty.tools.scripting.StringDriver

enum CompileMode:
case Guess
Expand All @@ -21,19 +13,14 @@ enum CompileMode:
case Script

case class CompileSettings(
verbose: Boolean = false,
classPath: List[String] = List.empty,
compileMode: CompileMode = CompileMode.Guess,
exitCode: Int = 0,
javaArgs: List[String] = List.empty,
javaProps: List[(String, String)] = List.empty,
scalaArgs: List[String] = List.empty,
residualArgs: List[String] = List.empty,
scriptArgs: List[String] = List.empty,
targetScript: String = "",
compiler: Boolean = false,
quiet: Boolean = false,
colors: Boolean = false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not know if this is used anywhere (in a build tool), but I would be cautious. It used to be easier to know "how is the compiler launched".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is used, we'll get some feedback early enough, right? I asked around for who uses MainGenericCompiler and was told other tools mostly call the compiler directly as a library.

) {
def withCompileMode(em: CompileMode): CompileSettings = this.compileMode match
case CompileMode.Guess =>
Expand All @@ -46,9 +33,6 @@ case class CompileSettings(
def withScalaArgs(args: String*): CompileSettings =
this.copy(scalaArgs = scalaArgs.appendedAll(args.toList.filter(_.nonEmpty)))

def withJavaArgs(args: String*): CompileSettings =
this.copy(javaArgs = javaArgs.appendedAll(args.toList.filter(_.nonEmpty)))

def withJavaProps(args: (String, String)*): CompileSettings =
this.copy(javaProps = javaProps.appendedAll(args.toList))

Expand All @@ -59,56 +43,41 @@ case class CompileSettings(
this.copy(scriptArgs = scriptArgs.appendedAll(args.toList.filter(_.nonEmpty)))

def withTargetScript(file: String): CompileSettings =
Try(Source.fromFile(file)).toOption match
case Some(_) => this.copy(targetScript = file)
case None =>
Try(Source.fromFile(file)) match
case Success(_) => this.copy(targetScript = file)
case Failure(_) =>
println(s"not found $file")
this.copy(exitCode = 2)
end withTargetScript

def withCompiler: CompileSettings =
this.copy(compiler = true)

def withQuiet: CompileSettings =
this.copy(quiet = true)

def withColors: CompileSettings =
this.copy(colors = true)

def withNoColors: CompileSettings =
this.copy(colors = false)
}

object MainGenericCompiler {

val classpathSeparator: String = File.pathSeparator
private val classpathSeparator: String = File.pathSeparator
private val javaPropOption = raw"""-D(.+?)=(.?)""".r

def processClasspath(cp: String, tail: List[String]): (List[String], List[String]) =
private def processClasspath(cp: String, tail: List[String]): (List[String], List[String]) =
val cpEntries = cp.split(classpathSeparator).toList
val singleEntryClasspath: Boolean = cpEntries.take(2).size == 1
val globdir: String = if singleEntryClasspath then cp.replaceAll("[\\\\/][^\\\\/]*$", "") else "" // slash/backslash agnostic
def validGlobbedJar(s: String): Boolean = s.startsWith(globdir) && ((s.toLowerCase.endsWith(".jar") || s.toLowerCase.endsWith(".zip")))
val globDir: String = if singleEntryClasspath then cp.replaceAll("[\\\\/][^\\\\/]*$", "") else "" // slash/backslash agnostic
def validGlobbedJar(s: String): Boolean = s.startsWith(globDir) && (s.toLowerCase.endsWith(".jar") || s.toLowerCase.endsWith(".zip"))
if singleEntryClasspath && validGlobbedJar(cpEntries.head) then
// reassemble globbed wildcard classpath
// globdir is wildcard directory for globbed jar files, reconstruct the intended classpath
val cpJars = tail.takeWhile( f => validGlobbedJar(f) )
// globDir is wildcard directory for globbed jar files, reconstruct the intended classpath
val cpJars = tail.takeWhile(validGlobbedJar)
val remainingArgs = tail.drop(cpJars.size)
(remainingArgs, cpEntries ++ cpJars)
else
(tail, cpEntries)

@sharable val javaOption = raw"""-J(.*)""".r
@sharable val javaPropOption = raw"""-D(.+?)=(.?)""".r
@tailrec
def process(args: List[String], settings: CompileSettings): CompileSettings = args match
case Nil =>
settings
case "--" :: tail =>
process(Nil, settings.withResidualArgs(tail.toList*))
settings.withResidualArgs(tail*)
case ("-v" | "-verbose" | "--verbose") :: tail =>
process(tail, settings.withScalaArgs("-verbose"))
case ("-q" | "-quiet") :: tail =>
process(tail, settings.withQuiet)
case "-script" :: targetScript :: tail =>
process(Nil, settings
.withCompileMode(CompileMode.Script)
Expand All @@ -121,23 +90,15 @@ object MainGenericCompiler {
process(tail, settings.withCompileMode(CompileMode.Decompile))
case "-print-tasty" :: tail =>
process(tail, settings.withCompileMode(CompileMode.PrintTasty))
case "-colors" :: tail =>
process(tail, settings.withColors)
case "-no-colors" :: tail =>
process(tail, settings.withNoColors)
case "-with-compiler" :: tail =>
process(tail, settings.withCompiler)
case ("-cp" | "-classpath" | "--class-path") :: cp :: tail =>
val (tailargs, newEntries) = processClasspath(cp, tail)
process(tailargs, settings.copy(classPath = settings.classPath ++ newEntries.filter(_.nonEmpty)))
val (tailArgs, newEntries) = processClasspath(cp, tail)
process(tailArgs, settings.copy(classPath = settings.classPath ++ newEntries.filter(_.nonEmpty)))
case "-Oshort" :: tail =>
// Nothing is to be done here. Request that the user adds the relevant flags manually.
val addTC="-XX:+TieredCompilation"
val tStopAtLvl="-XX:TieredStopAtLevel=1"
println(s"ignoring deprecated -Oshort flag, please add `-J$addTC` and `-J$tStopAtLvl` flags manually")
process(tail, settings)
case javaOption(stripped: String) :: tail =>
process(tail, settings.withJavaArgs(stripped))
case javaPropOption(opt: String, value: String) :: tail =>
process(tail, settings.withJavaProps(opt -> value))
case arg :: tail =>
Expand All @@ -148,40 +109,26 @@ object MainGenericCompiler {
val settings = process(args.toList, CompileSettings())
if settings.exitCode != 0 then System.exit(settings.exitCode)

def classpathSetting =
val classpathSetting =
if settings.classPath.isEmpty then List()
else List("-classpath", settings.classPath.mkString(classpathSeparator))

def reconstructedArgs() =
classpathSetting ++ settings.scalaArgs ++ settings.residualArgs
val properArgs = classpathSetting ++ settings.scalaArgs ++ settings.residualArgs

def addJavaProps(): Unit =
settings.javaProps.foreach { (k, v) => sys.props(k) = v }
settings.javaProps.foreach { (k, v) => sys.props(k) = v }

def run(settings: CompileSettings): Unit = settings.compileMode match
case CompileMode.Compile =>
addJavaProps()
val properArgs = reconstructedArgs()
settings.compileMode match
case CompileMode.Guess | CompileMode.Compile =>
dotty.tools.dotc.Main.main(properArgs.toArray)
case CompileMode.Decompile =>
addJavaProps()
val properArgs = reconstructedArgs()
dotty.tools.dotc.decompiler.Main.main(properArgs.toArray)
case CompileMode.PrintTasty =>
addJavaProps()
val properArgs = reconstructedArgs()
dotty.tools.dotc.core.tasty.TastyPrinter.main(properArgs.toArray)
case CompileMode.Script => // Naive copy from scalac bash script
addJavaProps()
val properArgs =
reconstructedArgs()
val fullArgs =
properArgs
++ List("-script", settings.targetScript)
++ settings.scriptArgs
scripting.Main.main(properArgs.toArray)
case CompileMode.Guess =>
run(settings.withCompileMode(CompileMode.Compile))
end run

run(settings)
end main
}
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/debug/ExpressionCompiler.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dotty.tools.debug

import dotty.tools.dotc.Compiler
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.transform.ElimByName

Expand All @@ -14,7 +13,7 @@ import dotty.tools.dotc.transform.ElimByName
* To do so, it extends the Compiler with 3 phases:
* - InsertExpression: parses and inserts the expression in the original source tree
* - ExtractExpression: extract the typed expression and places it in the new expression class
* - ResolveReflectEval: resolves local variables or inacessible members using reflection calls
* - ResolveReflectEval: resolves local variables or inaccessible members using reflection calls
*/
class ExpressionCompiler(config: ExpressionCompilerConfig) extends Compiler:

Expand Down
4 changes: 0 additions & 4 deletions compiler/src/dotty/tools/debug/ExpressionCompilerBridge.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package dotty.tools.debug

import java.nio.file.Path
import java.util.function.Consumer
import java.{util => ju}
import scala.jdk.CollectionConverters.*
import scala.util.control.NonFatal
import dotty.tools.dotc.reporting.StoreReporter
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.Driver

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class ExpressionCompilerConfig private[debug] (
def withLocalVariables(localVariables: ju.Set[String]): ExpressionCompilerConfig = copy(localVariables = localVariables)
def withErrorReporter(errorReporter: Consumer[String]): ExpressionCompilerConfig = copy(errorReporter = errorReporter)

private[debug] val expressionTermName: TermName = termName(outputClassName.toLowerCase.toString)
private[debug] val expressionTermName: TermName = termName(outputClassName.toLowerCase)
private[debug] val expressionClassName: TypeName = typeName(outputClassName)

private[debug] def expressionClass(using Context): ClassSymbol =
Expand Down
8 changes: 2 additions & 6 deletions compiler/src/dotty/tools/debug/ExtractExpression.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package dotty.tools.debug

import dotty.tools.dotc.core.SymUtils
import dotty.tools.dotc.ast.tpd.*
import dotty.tools.dotc.core.Constants.Constant
import dotty.tools.dotc.core.Contexts.*
Expand All @@ -14,11 +13,8 @@ import dotty.tools.dotc.core.SymDenotations.SymDenotation
import dotty.tools.dotc.transform.MacroTransform
import dotty.tools.dotc.core.Phases.*
import dotty.tools.dotc.report
import dotty.tools.dotc.util.SrcPos
import scala.annotation.nowarn

/**
* This phase extracts the typed expression from the source tree, transfoms it and places it
* This phase extracts the typed expression from the source tree, transforms it and places it
* in the evaluate method of the Expression class.
*
* Before:
Expand Down Expand Up @@ -110,7 +106,7 @@ private class ExtractExpression(
case tree: (Ident | Select | This) if isStaticObject(tree.symbol) =>
getStaticObject(tree)(tree.symbol.moduleClass)

// non static this or outer this
// non-static this or outer this
case tree: This if !tree.symbol.is(Package) =>
thisOrOuterValue(tree)(tree.symbol.enclosingClass.asClass)

Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/debug/InsertExpression.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import dotty.tools.dotc.core.Names.*
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.parsing.Parsers
import dotty.tools.dotc.report
import dotty.tools.dotc.transform.MegaPhase.MiniPhase
import dotty.tools.dotc.util.NoSourcePosition
import dotty.tools.dotc.util.SourceFile
import dotty.tools.dotc.util.SourcePosition
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/debug/ResolveReflectEval.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package dotty.tools.debug

import dotty.tools.dotc.core.SymUtils
import dotty.tools.dotc.ast.tpd.*
import dotty.tools.dotc.core.Constants.Constant
import dotty.tools.dotc.core.Contexts.*
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/CompilationUnit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import ast.Trees.{Import, Ident}
import typer.Nullables
import core.Decorators.*
import config.{SourceVersion, Feature}
import StdNames.nme
import scala.annotation.internal.sharable
import scala.util.control.NoStackTrace
import transform.MacroAnnotations.isMacroAnnotation
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/Driver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import dotty.tools.dotc.ast.Positioned
import dotty.tools.io.{AbstractFile, FileExtension}
import reporting.*
import core.Decorators.*
import config.Feature
import util.chaining.*

import scala.util.control.NonFatal
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/Resident.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class Resident extends Driver {
line = getLine()
}
if line.startsWith(quit) then ctx.reporter
else loop((line.split("\\s+")).asInstanceOf[Array[String]], nextCtx)
else loop(line.split("\\s+"), nextCtx)
case None =>
prevCtx.reporter
}
Expand Down
Loading
Loading