I would like to compile and execute Scala code given as a String at run-time using Scala3. Like for example in Scala 2 I would have used Reflection
import scala.reflect.runtime.universe as ru
import scala.tools.reflect.ToolBox
val scalaCode = q"""println("Hello world!")"""
val evalMirror = ru.runtimeMirror(this.getClass.getClassLoader)
val toolBox = evalMirror.mkToolBox()
toolBox.eval(scalaCode) //Hello world!
If I try to run this code in Scala3 I get
Scala 2 macro cannot be used in Dotty. See https://dotty.epfl.ch/docs/reference/dropped-features/macros.html
To turn this error into a warning, pass -Xignore-scala2-macros to the compiler
How can I translate this code in Scala3 ?
This program compiles Scala 3 code dynamically:
import dotty.tools.dotc.Driver
import java.net.{URL, URLClassLoader}
import java.nio.file.{Files, Path}
import java.io.File
object DynamicCompiler:
private val driver = Driver()
def compile(code: String, className: String, outputDir: Path): Boolean =
val sourceFile = Files.createTempFile(className, ".scala").toFile
sourceFile.deleteOnExit()
Files.writeString(sourceFile.toPath, code)
val args = Array(
sourceFile.getAbsolutePath,
"-d",
outputDir.toAbsolutePath.toString,
"-classpath",
System.getProperty("java.class.path")
)
val result = driver.process(args)
!result.hasErrors
def loadClass(className: String, classDir: Path): Option[Class[?]] =
val loader = URLClassLoader(Array(classDir.toUri.toURL), getClass.getClassLoader)
try Some(loader.loadClass(className))
catch case _: ClassNotFoundException => None
def main(args: Array[String]): Unit =
val outDir = Files.createTempDirectory("scala3-compiled")
val objectName = "DynamicRoot"
val className = "Root"
val code =
s"""
|case class Address(city: Option[String], country: Option[String], street: Option[String])
|case class Person(address: Option[Address], age: Option[Long], name: Option[String])
|case class $className(people: Option[Seq[Person]])
|object $objectName
|""".stripMargin
if compile(code, objectName, outDir) then
println(s"Compilation succeeded. Output in: $outDir")
loadClass(objectName, outDir) match
case Some(objCls) => println(s"Loaded object class: $objCls")
case None => println(s"Failed to load object class: $objectName")
loadClass(className, outDir) match
case Some(rootCls) => println(s"Loaded case class: $rootCls")
case None => println(s"Failed to load case class: $className")
else
println("Compilation failed.")