scala 如何在脚本运行时运行生成的代码?

yzuktlbb  于 2022-11-23  发布在  Scala
关注(0)|答案(1)|浏览(164)

在scala脚本运行期间,我希望它生成一些代码并执行这些代码。
我以为我在网上找到了两个可能有用的例子,但它们都不成功

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)

  }

这些可能是过时的例子。
有没有人有一个工作或修复?

mkh04yzy

mkh04yzy1#

我将在Scala 2中采用我在How to compile and execute scala code at run-time in Scala3?中的答案

ammonite.Main(verboseOutput = false).runCode("""println("Hello, World!")""")
// Hello, World!
  • 构建. sbt *
scalaVersion := "2.13.8"
libraryDependencies += "com.lihaoyi" % "ammonite" % "2.5.4" cross CrossVersion.full
scala.tools.nsc.interpreter.shell.Scripted()
  .eval("""System.out.println("Hello, World!")""")
// Hello, World!
  • 构建. sbt *
scalaVersion := "2.13.8"
libraryDependencies ++= scalaOrganization.value % "scala-compiler" % scalaVersion.value
  • 您可以使用Scala 2反射工具箱
val tb = scala.tools.reflect.ToolBox(scala.reflect.runtime.currentMirror).mkToolBox()
tb.eval(tb.parse("""println("Hello, world!")"""))
// Hello, world!

import scala.tools.reflect.ToolBox // implicit

val tb = scala.reflect.runtime.currentMirror.mkToolBox()
tb.eval(tb.parse("""println("Hello, world!")"""))
// Hello, world!
  • 构建. sbt *
scalaVersion := "2.13.8"
libraryDependencies ++= scalaOrganization.value % "scala-compiler" % scalaVersion.value
  • 您可以使用scala.tools.nsc.interpreter
val settings = new scala.tools.nsc.Settings
settings.usejavacp.value = true
new scala.tools.nsc.interpreter.IMain(settings,
  new scala.tools.nsc.interpreter.shell.ReplReporterImpl(settings)
).interpret("""println("Hello, World!")""")
// Hello, World!
  • 构建. sbt *
scalaVersion := "2.13.8"
libraryDependencies ++= scalaOrganization.value % "scala-compiler" % scalaVersion.value
  • 如果你有一个scala.reflect.runtime.universe.Treeq"..."而不是普通字符串,那么你不需要解析
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!
  • 构建. sbt *
scalaVersion := "2.13.8"
libraryDependencies ++= scalaOrganization.value % "scala-compiler" % scalaVersion.value
  • 如果你有一个scala.reflect.runtime.universe.Exprreify {...}(一个静态类型的树 Package 器)而不是普通字符串,那么你也不需要解析
import scala.reflect.runtime.universe.reify
import scala.tools.reflect.ToolBox

scala.reflect.runtime.currentMirror.mkToolBox()
  .eval(reify{ println("Hello, World!") }.tree) 
// Hello, World!
  • 构建. sbt *
scalaVersion := "2.13.8"
libraryDependencies ++= scalaOrganization.value % "scala-compiler" % scalaVersion.value
  • 以上所有内容都是为了在Scala 2中运行Scala 2代码。如果我们想在Scala 2中运行Scala 3代码,那么我们可以使用标准的Scala 3 REPL interpreter
(new dotty.tools.repl.ScriptEngine).eval("""println("Hello, World!")""")
// Hello, World!
  • 构建. sbt *
scalaVersion := "2.13.8"
libraryDependencies += scalaOrganization.value %% "scala3-compiler" % "3.1.3" cross CrossVersion.for2_13Use3
scalacOptions += "-Ytasty-reader"
  • 您也可以使用JSR223脚本。根据您的类路径中是scala-compiler还是scala3-compiler,您将运行Scala 2或Scala 3(上述两个脚本引擎之一:Scala 2 scala.tools.nsc.interpreter.shell.Scripted或Scala 3 dotty.tools.repl.ScriptEngine)。如果同时添加了两个依赖项,则先添加的依赖项优先。
new javax.script.ScriptEngineManager(getClass.getClassLoader)
  .getEngineByName("scala")
  .eval("""println("Hello, World!")""")
// Hello, World!

如果您希望更好地控制所使用的依赖项(无需重新导入项目),则可以使用Coursier并指定类加载器

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!
  • 您可以使用实际的编译器在Scala 2中自己实现Eval
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)
}

  • 构建. sbt *
scalaVersion := "2.13.8"
libraryDependencies ++= scalaOrganization.value % "scala-compiler" % scalaVersion.value
  • 同样,ScalametaSemanticdb具有方法scala.meta.interactive.InteractiveSemanticdb.newCompiler(),该方法返回在scala.tools.nsc.Global之上扩展的scala.tools.nsc.interactive.Global
  • 构建. sbt *
scalaVersion := "2.13.8"
// adding as a dependency, not a compiler plugin
libraryDependencies += "org.scalameta" % "semanticdb-scalac" % "4.6.0" cross CrossVersion.full

Scala reflection: compile akka actor with protobuf
Dynamic compilation of multiple Scala classes at runtime
How to eval code that uses InterfaceStability annotation (that fails with "illegal cyclic reference involving class InterfaceStability")?显示器
Tensorflow in Scala reflection
Scala Presentation Compiler - Minimal Example
What is "Scala Presentation Compiler"?
"eval" in Scala

相关问题