Ausgabe
Während der Ausführung eines Scala-Skripts möchte ich, dass es Code generiert und diesen ausführt.
Ich dachte, ich hätte online zwei Beispiele gefunden, die funktionieren könnten, aber sie sind nicht erfolgreich
import scala.reflect.runtime.universe._
import scala.reflect.runtime.currentMirror
import scala.tools.reflect.ToolBox
import java.io.{File, FileWriter}
def runstuff() = {
val fileWriter = new FileWriter(new File("temporaryScalaFile.scala"))
fileWriter.write("println(\"hello\")")
fileWriter.close()
temporaryScalaFile.scala
val cm = scala.reflect.runtime.universe.runtimeMirror(getClass.getClassLoader)
val tb = cm.mkToolBox()
val str = tb.eval(tb.parse("new String(\"Yo\")"))
println(str)
}
Dies sind vielleicht veraltete Beispiele.
Hat jemand eine funktionierende oder eine Lösung?
Lösung
Ich übernehme meine Antwort in Scala 2 unter Wie kompiliere und führe ich Scala-Code zur Laufzeit in Scala3 aus?
- Zum Beispiel können Sie den Ammonit von Li Haoyi verwenden
ammonite.Main(verboseOutput = false).runCode("""println("Hello, World!")""")
// Hello, World!
build.sbt
scalaVersion := "2.13.8"
libraryDependencies += "com.lihaoyi" % "ammonite" % "2.5.4" cross CrossVersion.full
- Sie können auch den standardmäßigen Scala 2 REPL- Interpreter verwenden
scala.tools.nsc.interpreter.shell.Scripted()
.eval("""System.out.println("Hello, World!")""")
// Hello, World!
build.sbt
scalaVersion := "2.13.8"
libraryDependencies ++= scalaOrganization.value % "scala-compiler" % scalaVersion.value
- Sie können die Scala 2 Reflective Toolbox verwenden
import scala.tools.reflect.ToolBox // implicit
val tb = scala.reflect.runtime.currentMirror.mkToolBox()
tb.eval(tb.parse("""println("Hello, world!")"""))
// Hello, world!
build.sbt
scalaVersion := "2.13.8"
libraryDependencies ++= scalaOrganization.value % "scala-compiler" % scalaVersion.value
- Wenn Sie eher eine
scala.reflect.runtime.universe.Tree
q"..."
Zeichenfolge als eine einfache Zeichenfolge haben, müssen Sie sie nicht analysieren
import scala.reflect.runtime.universe.Quasiquote // implicit for q"..." interpolator
import scala.tools.reflect.ToolBox // implicit for .eval
scala.reflect.runtime.currentMirror.mkToolBox()
.eval(q"""println("Hello, World!")""") // Hello, World!
build.sbt
scalaVersion := "2.13.8"
libraryDependencies ++= scalaOrganization.value % "scala-compiler" % scalaVersion.value
- Wenn Sie einen
scala.reflect.runtime.universe.Expr
reify {...}
(einen statisch typisierten Wrapper über einem Baum) anstelle einer einfachen Zeichenfolge haben, müssen Sie auch nicht analysieren
import scala.reflect.runtime.universe.reify
import scala.tools.reflect.ToolBox
scala.reflect.runtime.currentMirror.mkToolBox()
.eval(reify{ println("Hello, World!") }.tree)
// Hello, World!
build.sbt
scalaVersion := "2.13.8"
libraryDependencies ++= scalaOrganization.value % "scala-compiler" % scalaVersion.value
- All dies dient dazu, Scala 2-Code in Scala 2 auszuführen. Wenn wir Scala 3-Code in Scala 2 ausführen möchten, können wir den standardmäßigen Scala 3 REPL- Interpreter verwenden
(new dotty.tools.repl.ScriptEngine).eval("""println("Hello, World!")""")
// Hello, World!
build.sbt
scalaVersion := "2.13.8"
libraryDependencies += scalaOrganization.value %% "scala3-compiler" % "3.1.3" cross CrossVersion.for2_13Use3
scalacOptions += "-Ytasty-reader"
- Sie können auch JSR223- Scripting verwenden. Abhängig davon, ob Sie Scala 2 oder Scala 3 (eine der beiden oben genannten Skript-Engines: Scala 2 oder Scala 3 ) in Ihrem
scala-compiler
Klassenpfad haben . Wenn Sie beides haben, gewinnt die zuerst hinzugefügte Abhängigkeit.scala3-compiler
scala.tools.nsc.interpreter.shell.Scripted
dotty.tools.repl.ScriptEngine
new javax.script.ScriptEngineManager(getClass.getClassLoader)
.getEngineByName("scala")
.eval("""println("Hello, World!")""")
// Hello, World!
Wenn Sie besser steuern möchten, welche Abhängigkeit verwendet wird (ohne das Projekt erneut zu importieren), können Sie Coursier verwenden und den Klassenlader angeben
import coursier._ // libraryDependencies += "io.get-coursier" %% "coursier" % "2.1.0-M6-53-gb4f448130"
val files = Fetch()
.addDependencies(
Dependency(Module(Organization("org.scala-lang"), ModuleName("scala-compiler")), "2.13.9"),
// Dependency(Module(Organization("org.scala-lang"), ModuleName("scala3-compiler_3")), "3.2.0"),
)
.run()
val classLoader = new java.net.URLClassLoader(
files.map(_.toURI.toURL).toArray,
/*getClass.getClassLoader*/null // ignoring current classpath
)
new javax.script.ScriptEngineManager(classLoader)
.getEngineByName("scala")
.eval("""
type T = List[Option[A]] forSome {type A} // Scala 2
//type T = [A] =>> [B] =>> (A, B) // Scala 3
System.out.println("Hello, World!")
""")
// Hello, World!
- Sie können Eval in Scala 2 selbst mit dem aktuellen Compiler implementieren
import scala.reflect.internal.util.{AbstractFileClassLoader, BatchSourceFile}
import scala.reflect.io.{AbstractFile, VirtualDirectory}
import scala.reflect.runtime.universe
import scala.reflect.runtime
import scala.reflect.runtime.universe.{Mirror, TermName}
import scala.tools.nsc.{Global, Settings}
val code =
s"""
|package mypackage
|
|object Main {
| def main(args: Array[String]): Unit = {
| println("Hello, World!")
| }
|}""".stripMargin
val directory = new VirtualDirectory("(memory)", None)
val runtimeMirror = createRuntimeMirror(directory, runtime.currentMirror)
compileCode(code, List(), directory)
runObjectMethod("mypackage.Main", runtimeMirror, "main", Array.empty[String])
// Hello, World!
def compileCode(
code: String,
classpathDirectories: List[AbstractFile],
outputDirectory: AbstractFile
): Unit = {
val settings = new Settings
classpathDirectories.foreach(dir => settings.classpath.prepend(dir.toString))
settings.outputDirs.setSingleOutput(outputDirectory)
settings.usejavacp.value = true
val global = new Global(settings)
val run = new global.Run
run.compileSources(List(new BatchSourceFile("(inline)", code)))
// val unit = run.units.next()
// println("source=" + unit.source.content.mkString)
// println("typed tree=" + unit.body)
}
def runObjectMethod(
objectName: String,
runtimeMirror: Mirror,
methodName: String,
arguments: Any*
): Any = {
val objectSymbol = runtimeMirror.staticModule(objectName)
val objectModuleMirror = runtimeMirror.reflectModule(objectSymbol)
val objectInstance = objectModuleMirror.instance
val objectType = objectSymbol.typeSignature
val methodSymbol = objectType.decl(TermName(methodName)).asMethod
val objectInstanceMirror = runtimeMirror.reflect(objectInstance)
val methodMirror = objectInstanceMirror.reflectMethod(methodSymbol)
methodMirror(arguments: _*)
}
def createRuntimeMirror(directory: AbstractFile, parentMirror: Mirror): Mirror = {
val classLoader = new AbstractFileClassLoader(directory, parentMirror.classLoader)
universe.runtimeMirror(classLoader)
}
build.sbt
scalaVersion := "2.13.8"
libraryDependencies ++= scalaOrganization.value % "scala-compiler" % scalaVersion.value
Scala-Reflexion: Akka-Actor mit Protobuf kompilieren
Dynamische Kompilierung mehrerer Scala-Klassen zur Laufzeit
Scala Presentation Compiler – Minimales Beispiel
Was ist “Scala Presentation Compiler”?
Beantwortet von – Dmytro Mitin
Antwort geprüft von – Mary Flores (FixError Volunteer)