Skip to content

Instantly share code, notes, and snippets.

@keynmol
Created November 22, 2024 08:32
Show Gist options
  • Save keynmol/bf9d79a1d36a2b99c5b23b09ebc82c2d to your computer and use it in GitHub Desktop.
Save keynmol/bf9d79a1d36a2b99c5b23b09ebc82c2d to your computer and use it in GitHub Desktop.
//> using dep org.scala-lang::scala3-compiler::3.5.2
//> using dep ch.epfl.scala::tasty-mima::1.3.0
//> using scala 3.5.2
import dotty.tools.dotc.Driver
import dotty.tools.dotc.core.Contexts.{Context, FreshContext}
import dotty.tools.dotc.config.Settings.Setting._
import dotty.tools.dotc.interfaces
import dotty.tools.dotc.ast.Trees.Tree
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.interfaces.{SourceFile => ISourceFile}
import dotty.tools.dotc.interfaces.{Diagnostic => IDiagnostic}
import dotty.tools.dotc.reporting._
import dotty.tools.dotc.parsing.Parsers.Parser
import dotty.tools.dotc.Compiler
import dotty.tools.io.{AbstractFile, VirtualDirectory}
import dotty.tools.repl.AbstractFileClassLoader
import dotty.tools.dotc.util.SourceFile
import java.io.File
import java.nio.file.Files
import java.nio.file.Paths
import scala.jdk.CollectionConverters._
import java.util.stream.Collector
import java.util.stream.Collectors
import javax.script.CompiledScript
import tastymima.*, intf.*
import java.nio.file.Path
import java.nio.file.FileSystems
@main def hello =
val code = "class X"
val dirOld = java.nio.file.Files.createTempDirectory("scala3-out")
val dirNew = java.nio.file.Files.createTempDirectory("scala3-out")
val classpath =
System.getProperty("java.class.path").split(File.pathSeparator)
val classpathF = classpath.map(Paths.get(_))
val scala3 = Scala3Compiler().withClasspath(classpath)
scala3.compile("old.scala", code, dirOld.toString())
scala3.compile("new.scala", code, dirNew.toString())
val mima = new tastymima.TastyMiMa(new Config)
println(
mima.analyze(
oldClasspath = javaLib ::: dirOld :: classpathF.toList,
oldClasspathEntry = dirOld,
newClasspath = javaLib ::: dirNew :: classpathF.toList,
newClasspathEntry = dirNew
)
)
lazy val javaLib: List[Path] =
System.getProperty("sun.boot.class.path") match
case null =>
List(
FileSystems
.getFileSystem(java.net.URI.create("jrt:/"))
.getPath("modules", "java.base")
)
case bootClasspath =>
val rtJarFile = bootClasspath
.split(java.io.File.pathSeparatorChar)
.find { path =>
new java.io.File(path).getName() == "rt.jar"
}
.getOrElse {
throw new RuntimeException(
s"cannot find rt.jar in $bootClasspath"
)
}
List(Paths.get(rtJarFile))
end javaLib
case class Scala3CompilationError(line: Int, column: Int, msg: String)
class CompilerDriver(val settings: List[String]) extends Driver {
/* Otherwise it will print usage instructions */
override protected def sourcesRequired: Boolean = false
def currentCtx = myInitCtx
private val myInitCtx: Context = {
val rootCtx = initCtx.fresh
val ctx = setup(settings.toArray, rootCtx) match
case Some((_, ctx)) => ctx
case None => rootCtx
ctx.initialize()(using ctx)
ctx
}
}
class AccumulatingReporter extends Reporter {
private var errors = List.newBuilder[Scala3CompilationError]
override def doReport(dia: Diagnostic)(using Context) =
if dia.level == interfaces.Diagnostic.ERROR then
errors.addOne(
Scala3CompilationError(dia.pos.line, dia.pos.column, dia.message)
)
def clear() = errors.clear()
def getErrors() = errors.result().toArray
}
class Scala213CompilationResult(
errs: Array[Scala3CompilationError],
cpath: Array[String]
)
class Scala3Compiler() {
private val defaultFlags =
List(
"-color:never",
"-unchecked",
"-deprecation",
"-Ximport-suggestion-timeout",
"0"
)
// lazy val driver: = CompilerDriver(defaultFlags)
var driver: CompilerDriver = null
val savedClasspath = List.newBuilder[String]
def withClasspath(cp: Array[String]) = {
savedClasspath.addAll(cp)
driver = CompilerDriver(
defaultFlags ++ List("-classpath", cp.mkString(File.pathSeparator))
)
this
}
def compile(
fileName: String,
contents: String,
outDir: String
) = {
Files.walk(Paths.get(outDir)).collect(Collectors.toList()).asScala.foreach {
path =>
if (path.getFileName().endsWith(".class"))
Files.delete(path)
}
val compiler = new Compiler
val ctx = driver.currentCtx.fresh
val reporter = new AccumulatingReporter
val context = ctx
.setReporter(reporter)
.setSetting(
ctx.settings.outputDir,
AbstractFile.getDirectory(outDir)
)
val run = compiler.newRun(using context)
val res =
run.compileSources(List(SourceFile.virtual(fileName, contents)))
new Scala213CompilationResult(
reporter.getErrors(),
savedClasspath.result.toArray
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment