Created
November 22, 2024 08:32
-
-
Save keynmol/bf9d79a1d36a2b99c5b23b09ebc82c2d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//> 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