実行時の複数のScalaクラスの動的コンパイル

3
John Reese 2019-07-07 14:13.

次のようなツールボックスを使用して、Scalaで個々の「スニペット」をコンパイルできることを知っています。

import scala.reflect.runtime.universe
import scala.tools.reflect.ToolBox

object Compiler {
  val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()

  def main(args: Array[String]): Unit = {
    tb.eval(tb.parse("""println("hello!")"""))
  }
}

「スニペット」、つまり相互に参照するクラス以外のものをコンパイルする方法はありますか?このような:

import scala.reflect.runtime.universe
import scala.tools.reflect.ToolBox

object Compiler {
  private val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()

  val a: String =
    """
      |package pkg {
      |
      |class A {
      |def compute(): Int = 42
      |}}
    """.stripMargin

  val b: String =
    """
      |import pkg._
      |
      |class B {
      |def fun(): Unit = {
      |    new A().compute()
      |}
      |}
    """.stripMargin

  def main(args: Array[String]): Unit = {
    val compiledA = tb.parse(a)
    val compiledB = tb.parse(b)
    tb.eval(compiledB)
  }
}

どういうわけか「A」を解決する方法をツールボックスに指示する必要があるため、明らかに私のスニペットは機能しません。

スレッド「メイン」の例外scala.tools.reflect.ToolBoxError:リフレクティブコンパイルが失敗しました:

見つかりません:タイプA

1 answers

3
Dmytro Mitin 2019-07-07 21:35.

試してみてください

import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe
import scala.tools.reflect.ToolBox

val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()

val a = q"""
          class A {
            def compute(): Int = 42
          }"""

val symbA = tb.define(a)

val b = q"""
          class B {
            def fun(): Unit = {
              new $symbA().compute()
            }
          }"""

tb.eval(b)

https://github.com/scala/scala/blob/2.13.x/src/compiler/scala/tools/reflect/ToolBox.scala#L131-L138


ツールボックスで処理できるよりも複雑な場合は、いつでも手動でコンパイラを実行できます

import scala.reflect.internal.util.{AbstractFileClassLoader, BatchSourceFile}
import scala.reflect.io.{AbstractFile, VirtualDirectory}
import scala.tools.nsc.{Global, Settings}
import scala.reflect.runtime
import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._

val a: String =
  """
    |package pkg {
    |
    |class A {
    |  def compute(): Int = 42
    |}}
""".stripMargin

val b: String =
  """
    |import pkg._
    |
    |class B {
    |  def fun(): Unit = {
    |    println(new A().compute())
    |  }
    |}
""".stripMargin

val directory = new VirtualDirectory("(memory)", None)
compileCode(List(a, b), List(), directory)
val runtimeMirror = createRuntimeMirror(directory, runtime.currentMirror)
val bInstance = instantiateClass("B", runtimeMirror)
runClassMethod("B", runtimeMirror, "fun", bInstance) // 42

def compileCode(sources: List[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 files = sources.zipWithIndex.map { case (code, i) => new BatchSourceFile(s"(inline-$i)", code) }
  (new global.Run).compileSources(files)
}

def instantiateClass(className: String, runtimeMirror: Mirror, arguments: Any*): Any = {
  val classSymbol = runtimeMirror.staticClass(className)
  val classType = classSymbol.typeSignature
  val constructorSymbol = classType.decl(termNames.CONSTRUCTOR).asMethod
  val classMirror = runtimeMirror.reflectClass(classSymbol)
  val constructorMirror = classMirror.reflectConstructor(constructorSymbol)
  constructorMirror(arguments: _*)
}

def runClassMethod(className: String, runtimeMirror: Mirror, methodName: String, classInstance: Any, arguments: Any*): Any = {
  val classSymbol = runtimeMirror.staticClass(className)
  val classType = classSymbol.typeSignature
  val methodSymbol = classType.decl(TermName(methodName)).asMethod
  val instanceMirror = runtimeMirror.reflect(classInstance)
  val methodMirror = instanceMirror.reflectMethod(methodSymbol)
  methodMirror(arguments: _*)
}

//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)
}

flinkマップでjsonを動的に解析します

ScalaリフレクションのTensorflow

InterfaceStabilityアノテーションを使用するコードを評価する方法(「クラスInterfaceStabilityを含む違法な循環参照」で失敗する)?

Related questions

MORE COOL STUFF

ダイアナ妃は、8歳でウィリアム王子を寄宿学校に送るという決定に「涙を流した」

ダイアナ妃は、8歳でウィリアム王子を寄宿学校に送るという決定に「涙を流した」

ウィリアム王子が 8 歳のときに寄宿学校に通わせたことについて、ダイアナ妃がどのように感じたかを学びましょう。

シャキール・オニールは、レイカーズのスターが彼のチキン帝国を北テキサスに拡大するにつれて、ダラスの外に永住権を購入しました

シャキール・オニールは、レイカーズのスターが彼のチキン帝国を北テキサスに拡大するにつれて、ダラスの外に永住権を購入しました

Shaquille O'Neal は最近、Big Chicken レストラン帝国を拡大するため、ダラス郊外に住居を購入しました。

「90 日間の婚約者」: イヴが逮捕され、浮気スキャンダルの後、モハメドに対する家庭内暴力の容疑に直面している — 何が起こったのか?

「90 日間の婚約者」: イヴが逮捕され、浮気スキャンダルの後、モハメドに対する家庭内暴力の容疑に直面している — 何が起こったのか?

「90日の婚約者」シーズン9のスター、イヴ・アレラーノが逮捕され、モハメド・アブデルハメドへの暴行容疑で家庭内暴力の罪に問われている.

ナターシャ・リオンは、ピーウィー・ハーマンは「ビジネスで最高のGIFを送る」と言います

ナターシャ・リオンは、ピーウィー・ハーマンは「ビジネスで最高のGIFを送る」と言います

ナターシャ・リオンは、ピーウィー・ハーマン自身、ポール・ルーベンスと親密です。彼らの友情について彼女が言ったことを発見してください。

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セント ヘレナ島のジェイコブズ ラダーは 699 段の真っ直ぐ上る階段で、頂上に到達すると証明書が発行されるほどの難易度です。

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ショーン・ハニティーは「南北戦争」の意味を知らないようです

ショーン・ハニティーは「南北戦争」の意味を知らないようです

写真:APショーン・ハニティーは、彼の悪いテレビ番組を使って、私たちの悪い大統領のために毎晩サクラをしますが、彼はまた、毎日午後3時間の耐え難いほど放送されるラジオ番組を持っています。今日、彼はそのラジオ番組を使って、来たるべき内戦への恐れについて話しました。

シャーロッツビルの攻撃の目撃者を中傷するための訴訟で平手打ちされたインフォウォーズ

シャーロッツビルの攻撃の目撃者を中傷するための訴訟で平手打ちされたインフォウォーズ

バージニア州シャーロッツビルで開催された白人至上主義者集会での反対運動者の恐ろしい殺人の目撃者は、InfoWarsや他のいくつかのメディアを名誉毀損で訴えています。国務省の外交官であるブレナン・ギルモアは、彼が「深い国家」の陰謀の一部であったと主張することによって、アウトレットが彼のキャリアを傷つけたと主張している。

フェラーリは、ディーラーが中古フェラーリの走行距離計を変更することを故意に許可していることを認めています

フェラーリは、ディーラーが中古フェラーリの走行距離計を変更することを故意に許可していることを認めています

昨年、フェラーリが使用済みのフェラーリの走行距離計をロールバックしてその価値を劇的に(そして違法に)増加させる可能性のあるデバイスの使用を許可したと主張した、フェラーリの長年の営業担当者からの訴訟について報告したことを思い出してください。さて、デイリーメールの報告によると、フェラーリが何が起こっているのかを知っていて、それを承認したという証拠があります。

カニエ・ウェストは、私が今あなたに嘘をついているので、私が決して見るつもりはないという有名人の家族の確執のエピソードをちょうど録音しました

カニエ・ウェストは、私が今あなたに嘘をついているので、私が決して見るつもりはないという有名人の家族の確執のエピソードをちょうど録音しました

キム・カーダシアンとカニエ・ウェストは、2016年5月2日にニューヨーク市で開催されたメトロポリタン美術館のManus x Machina:Fashion In a Age ofTechnologyコスチュームインスティテュートガラに出席します。カーダシアン家のお騒がせ、クロエ&ラマー、私はケイト、カイリー、ケンダル・ゴー・ブラックボーイ・フィッシングのエピソードや、カーダシアンのショーの他の反復を見たことがありません。

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、子供向けのパズルの本の序文を書き、ジョージ王子、シャーロット王女、ルイ王子と一緒にテキストを読むと述べた.

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

Yak's Produce は、数十個のつぶれたメロンを野生動物のリハビリ専門家であるレスリー グリーンと彼女のルイジアナ州の救助施設で暮らす 42 匹の動物に寄付しました。

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

8 枚目のスタジオ アルバムのリリースに向けて準備を進めているデミ ロヴァートは、「スーパー グレート ガイ」と付き合っている、と情報筋は PEOPLE に確認しています。

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

イーサン プラスの誕生日のお祝いは、TLC のウェルカム トゥ プラスビルのシーズン 4 のフィナーレで、戦争中の母親のキム プラスと妻のオリビア プラスを結びつけました。

水門の修理

水門の修理

天王星と海王星の間の領域に向かって宇宙を 3/4 g の低温で航行しながら、私たちは数週間燃え続けていました。Dawson Trawler の科学者が Yggdrasil ポータルと呼んだもの。

美しいもの

美しいもの

女性として、私は通常、関係を築くことをためらっています。私はいつも彼らに負けないように苦労しました。私は誰かと共有したいという衝動と戦わなければなりません。

逃走中の女性からの発信

最も家が必要なときに家のように感じる場所はありません。

逃走中の女性からの発信

私は誰よりも移動しました。父が住んでいた土地には、父が 1 歳馬を折るミニチュアの競馬場がありました。

死にゆく男から学んだ最大の人生の教訓

彼は、私たちが持っているのはこの現在の瞬間だけであることを知るのが遅すぎました。

死にゆく男から学んだ最大の人生の教訓

ブラッドは、カーキ色のショート パンツとポロ シャツを着たまま、白いゴルフ グローブを両手で高く引っ張ったまま、ベッドルームに入ってきました。彼は満面の笑みを浮かべながら、「今年は私の人生で最高の年だったと思います!」と言いました。通常は保守的な消費者である私たちは、通常とは異なることをしました。

Language