Nod*_*.JS 0 jvm code-generation scala sbt
我想知道是否有办法绕过这个限制。显然,这个限制是由于 JVM 而不是 Scala 造成的。该代码是自动生成的,因此不可能将其拆分为多个方法。
scalac: Error while emitting M_SEMANT
Method too large: M_SEMANT.visit_1_1_0 (LNode;)V
Run Code Online (Sandbox Code Playgroud)
我设法(几乎)编译了您自动生成的源代码。唯一可以击败代码生成器的是另一个代码生成器:)
该代码是自动生成的,因此不可能将其拆分为多个方法。
我想这并不完全正确。只是最好自动拆分代码。
我用的是斯卡拉梅塔。您的visit_1_1_0类方法M_SEMANT有许多分支if (...) ... else ...(以及自动生成的代码的其余部分)。我把一个分支改造if ($condExpr) $thenExpr else $elseExpr成
def $condName(): Boolean = $condExpr
def $thenName() = $thenExpr
def $elseName() = $elseExpr
if ($condName()) $thenName() else $elseName()
Run Code Online (Sandbox Code Playgroud)
使if、then、else成为嵌套方法。编译后,嵌套方法将移至类级别
您可以对所有内容递归地应用此转换if-else(然后您应该取消注释中的行ScalametaTransformer),但事实证明重写最外层的if-else内容就足够了visit_1_1_0。获取的方法似乎受到 JVM 限制。
这是结果sbt transformed/clean transform transformed/compile
matches M_SEMANT
matches template
matches visit_1_1_0
matches if-else
[error] /media/data/Projects1/cool-aps-semant1/cool-aps-semant/transformed/target/scala-2.13/src_managed/main/cool-semant.scala:31:15: type mismatch;
[error] found : Unit
[error] required: Int
[error] if (!cond) {
[error] ^
[error] /media/data/Projects1/cool-aps-semant1/cool-aps-semant/transformed/target/scala-2.13/src_managed/main/cool-semant.scala:25:11: type mismatch;
[error] found : Unit
[error] required: Int
[error] if (!cond) {
[error] ^
[error] two errors found
[error] (transformed / Compile / compileIncremental) Compilation failed
Run Code Online (Sandbox Code Playgroud)
由于这两个地方在你的原始代码中是相同的,我猜那些编译错误就在那里。但我们已经没有了Method too large。
变换前的源在 中src/main/scala,变换后的源在 中transformed/target/scala-2.13/src_managed/main。
项目/build.sbt
libraryDependencies ++= Seq(
"org.scalameta" %% "scalameta" % "4.7.7"
)
Run Code Online (Sandbox Code Playgroud)
构建.sbt
ThisBuild / scalaVersion := "2.13.10"
lazy val root = (project in file("."))
.settings(
name := "aps-cool"
)
lazy val transformed = project
.settings(
Compile / unmanagedSourceDirectories += (Compile / sourceManaged).value
)
lazy val transform = taskKey[Unit]("Transform sources")
transform := {
val inputDir = (root / Compile / scalaSource).value
val outputDir = (transformed / Compile / sourceManaged).value
Generator.gen(inputDir, outputDir, Seq("cool-semant.scala"), Map("cool-semant.scala" -> Seq(960)))
}
Run Code Online (Sandbox Code Playgroud)
项目/Generator.scala
import sbt.*
object Generator {
def gen(inputDir: File, outputDir: File, filesToTransform: Seq[String] = Seq(), emptyLineIndices: Map[String, Seq[Int]] = Map()): Unit = {
val finder: PathFinder = inputDir ** "*.scala"
for (inputFile <- finder.get) yield {
val inputStr = IO.read(inputFile)
val outputFile = outputDir / inputFile.relativeTo(inputDir).get.toString
val outputStr =
if (filesToTransform.isEmpty || filesToTransform.contains(inputFile.name))
ScalametaTransformer.transform(inputStr, emptyLineIndices.getOrElse(inputFile.name, Seq()))
else inputStr
IO.write(outputFile, outputStr)
}
}
}
Run Code Online (Sandbox Code Playgroud)
项目/ScalametaTransformer.scala
import scala.meta.*
import scala.util.Properties
object ScalametaTransformer {
private val ifElseTransformer = new Transformer {
override def apply(tree: Tree): Tree = tree match {
case q"if ($condExpr) $thenExpr else $elseExpr" =>
println(s"matches if-else")
val condName = Term.fresh("cond")
val thenName = Term.fresh("then")
val elseName = Term.fresh("else")
q"""
def $condName(): Boolean = $condExpr
def $thenName() = $thenExpr
def $elseName() = $elseExpr
if ($condName()) $thenName() else $elseName()
"""
// apply recursively:
// val condExpr1 = super.apply(condExpr).asInstanceOf[Term]
// val thenExpr1 = super.apply(thenExpr).asInstanceOf[Term]
// val elseExpr1 = super.apply(elseExpr).asInstanceOf[Term]
// q"""
// def $condName() = $condExpr1
// def $thenName() = $thenExpr1
// def $elseName() = $elseExpr1
// if ($condName()) $thenName() else $elseName()
// """
case _ => super.apply(tree)
}
}
private val classMethodTransformer = new Transformer {
override def apply(tree: Tree): Tree = tree match {
case q"..$mods class M_SEMANT[..$tparams] ..$ctorMods (...$paramss) $template" =>
println("matches M_SEMANT")
val template1 = template match {
case template"{ ..$earlyStats } with ..$inits { $self => ..$stats }" =>
println("matches template")
val stats1 = stats.map {
case q"..$mods def visit_1_1_0[..$tparams](...$paramss): $tpeopt = $expr" =>
println("matches visit_1_1_0")
val expr1 = ifElseTransformer(expr).asInstanceOf[Term]
q"..$mods def visit_1_1_0[..$tparams](...$paramss): $tpeopt = $expr1"
case t => t
}
template"{ ..$earlyStats } with ..$inits { $self => ..$stats1 }"
}
q"..$mods class M_SEMANT[..$tparams] ..$ctorMods (...$paramss) $template1"
case _ => super.apply(tree)
}
}
def transform(str: String, emptyLineIndices: Seq[Int] = Seq()): String = {
val origTree = str.parse[Source].get
val newTree = classMethodTransformer(origTree)
insertEmptyLines(newTree.toString, emptyLineIndices)
}
private def insertEmptyLines(str: String, indices: Seq[Int]): String =
indices.foldLeft(str)(insertEmptyLine)
private def insertEmptyLine(str: String, index: Int): String =
str.linesIterator.patch(index, Iterator.fill(1)(""), 0).mkString(Properties.lineSeparator)
}
Run Code Online (Sandbox Code Playgroud)
https://github.com/amir734jj/cool-aps-semant/pull/1
插入空行是https://github.com/scalameta/scalameta/issues/2046的解决方法
| 归档时间: |
|
| 查看次数: |
238 次 |
| 最近记录: |