Scala Compiler Plugin Rewrite Function Definition As A Tuple: error: not found: value scala.Tuple2
Scala Compiler Plugin Rewrite Function Definition As A Tuple: error: not found: value scala.Tuple2
我正在编写一个编译器插件来将函数定义重写为函数散列 + 函数体的元组
所以下面
def f(a: Int, b: Int) : Int = (a + b)
会变成
val f = ("some-complex-hash", (a: Int, b: Int) => (a + b))
请注意,这是一个研究项目,将用于将可逆计算的某些变体集成到该语言的一个子集中。我知道,就其本身而言,这是一个坏主意,会破坏很多东西。
构建编译器插件的文档似乎比较缺乏(我确实看过官方指南),所以我正在努力寻找现有的插件,例如kind-projector
为了理解如何表示这个,我遵循了以下过程
- 具体化表达式
val expr = reify {....}
- 提取树
val tree = expr.tree
showRaw(tree)
我已经为一个函数定义、元组和一个 lambda 做了这个,我相信这应该足以实现它。到目前为止我得到了以下信息:
ValDef(Modifiers(), TermName(dd.name), TypeTree(),
Apply(
Select(Ident("scala.Tuple2"), TermName("apply")),
List(
Literal(Constant(hash)),
Function(
List(dd.vparamss),
dd.rhs
)
)
)
)
在我开始之前,我在扩展到 任何元组 时遇到了麻烦,即将任何函数重写为 ("a", "b")
在 REPL
中扩展为以下内容
Apply(Select(Ident(scala.Tuple2), TermName("apply")), List(Literal(Constant("a")), Literal(Constant("b"))))
问题
如果我这样做 Ident(scala.Tuple2)
我会在 编译时得到以下结果
overloaded method value Ident with alternatives:
[error] (sym: FunctionRewriter.this.global.Symbol)FunctionRewriter.this.global.Ident <and>
[error] (name: String)FunctionRewriter.this.global.Ident <and>
[error] FunctionRewriter.this.global.Ident.type
[error] cannot be applied to (Tuple2.type)
[error] Select(Ident(scala.Tuple2), TermName("apply")),
如果我做 Ident("scala.Tuple2")
(注意字符串),当插入 运行s(在“运行 时间”)
时,我会得到以下结果
<test>:2: error: not found: value scala.Tuple2
[error] object Main extends App {
对于如何重写为元组的任何指示,我将不胜感激
完整代码:
class CompilerPlugin(override val global: Global) extends Plugin {
val name = "provenance-expander"
val components = new FunctionRewriter(global) :: Nil
}
class FunctionRewriter(val global: Global) extends PluginComponent with TypingTransformers {
import global._
override val phaseName = "compiler-plugin-phase"
override val runsAfter = List("parser")
override def newPhase(prev: Phase) = new StdPhase(prev) {
override def apply(unit: CompilationUnit) {
unit.body = new MyTypingTransformer(unit).transform(unit.body)
}
}
class MyTypingTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
override def transform(tree: Tree) : Tree = tree match {
case dd: DefDef =>
val hash: String = "do some complex recursive hashing"
Apply(
Select(Ident("scala.Tuple2"), TermName("apply")),
List(Literal(Constant("a")), Literal(Constant("b")))
)
case _ => super.transform(tree)
}
}
def newTransformer(unit: CompilationUnit) = new MyTypingTransformer(unit)
}
感谢@SethTisue 在评论中的回答。我正在为将来可能遇到类似问题的任何人写一个答案。
正如 Seth 提到的,使用 mkTuple
是正确的方法。为了使用它,您需要以下导入
import global.gen._
在这种特定情况下,正如最初在问题中推测的那样,转换破坏了很多东西。主要转换对象注入的方法和 class 定义,即方法分派或初始化,导致格式错误的结构。解决方法是使用显式注释。所以最后的 DefDef
最终看起来像下面这样:
case dd: DefDef =>
if (dd.mods.hasAnnotationNamed(TypeName(typeOf[policyFunction].typeSymbol.name.toString))) {
val hash: String = md5HashString(dd.rhs.toString())
val tup =
atPos(tree.pos.makeTransparent)(mkTuple(List(Literal(Constant(hash)), Function(dd.vparamss(0), dd.rhs))))
val q = ValDef(Modifiers(), dd.name, TypeTree(), tup)
println(s"Re-written Function: $q")
q
} else {
dd
}
我正在编写一个编译器插件来将函数定义重写为函数散列 + 函数体的元组
所以下面
def f(a: Int, b: Int) : Int = (a + b)
会变成
val f = ("some-complex-hash", (a: Int, b: Int) => (a + b))
请注意,这是一个研究项目,将用于将可逆计算的某些变体集成到该语言的一个子集中。我知道,就其本身而言,这是一个坏主意,会破坏很多东西。
构建编译器插件的文档似乎比较缺乏(我确实看过官方指南),所以我正在努力寻找现有的插件,例如kind-projector
为了理解如何表示这个,我遵循了以下过程
- 具体化表达式
val expr = reify {....}
- 提取树
val tree = expr.tree
showRaw(tree)
我已经为一个函数定义、元组和一个 lambda 做了这个,我相信这应该足以实现它。到目前为止我得到了以下信息:
ValDef(Modifiers(), TermName(dd.name), TypeTree(),
Apply(
Select(Ident("scala.Tuple2"), TermName("apply")),
List(
Literal(Constant(hash)),
Function(
List(dd.vparamss),
dd.rhs
)
)
)
)
在我开始之前,我在扩展到 任何元组 时遇到了麻烦,即将任何函数重写为 ("a", "b")
在 REPL
Apply(Select(Ident(scala.Tuple2), TermName("apply")), List(Literal(Constant("a")), Literal(Constant("b"))))
问题
如果我这样做 Ident(scala.Tuple2)
我会在 编译时得到以下结果
overloaded method value Ident with alternatives:
[error] (sym: FunctionRewriter.this.global.Symbol)FunctionRewriter.this.global.Ident <and>
[error] (name: String)FunctionRewriter.this.global.Ident <and>
[error] FunctionRewriter.this.global.Ident.type
[error] cannot be applied to (Tuple2.type)
[error] Select(Ident(scala.Tuple2), TermName("apply")),
如果我做 Ident("scala.Tuple2")
(注意字符串),当插入 运行s(在“运行 时间”)
<test>:2: error: not found: value scala.Tuple2
[error] object Main extends App {
对于如何重写为元组的任何指示,我将不胜感激
完整代码:
class CompilerPlugin(override val global: Global) extends Plugin {
val name = "provenance-expander"
val components = new FunctionRewriter(global) :: Nil
}
class FunctionRewriter(val global: Global) extends PluginComponent with TypingTransformers {
import global._
override val phaseName = "compiler-plugin-phase"
override val runsAfter = List("parser")
override def newPhase(prev: Phase) = new StdPhase(prev) {
override def apply(unit: CompilationUnit) {
unit.body = new MyTypingTransformer(unit).transform(unit.body)
}
}
class MyTypingTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
override def transform(tree: Tree) : Tree = tree match {
case dd: DefDef =>
val hash: String = "do some complex recursive hashing"
Apply(
Select(Ident("scala.Tuple2"), TermName("apply")),
List(Literal(Constant("a")), Literal(Constant("b")))
)
case _ => super.transform(tree)
}
}
def newTransformer(unit: CompilationUnit) = new MyTypingTransformer(unit)
}
感谢@SethTisue 在评论中的回答。我正在为将来可能遇到类似问题的任何人写一个答案。
正如 Seth 提到的,使用 mkTuple
是正确的方法。为了使用它,您需要以下导入
import global.gen._
在这种特定情况下,正如最初在问题中推测的那样,转换破坏了很多东西。主要转换对象注入的方法和 class 定义,即方法分派或初始化,导致格式错误的结构。解决方法是使用显式注释。所以最后的 DefDef
最终看起来像下面这样:
case dd: DefDef =>
if (dd.mods.hasAnnotationNamed(TypeName(typeOf[policyFunction].typeSymbol.name.toString))) {
val hash: String = md5HashString(dd.rhs.toString())
val tup =
atPos(tree.pos.makeTransparent)(mkTuple(List(Literal(Constant(hash)), Function(dd.vparamss(0), dd.rhs))))
val q = ValDef(Modifiers(), dd.name, TypeTree(), tup)
println(s"Re-written Function: $q")
q
} else {
dd
}