Scala Compiler Plugin Rewrite Función Definición Como Tuple: error: no se encuentra: valor scala. Tuple2
Estoy escribiendo un plugin compilador para reescribir una definición de función como un tuple de la función hash + cuerpo de función
Así que lo siguiente
def f(a: Int, b: Int) : Int = (a + b)
se convertiría en
val f = ("some-complex-hash", (a: Int, b: Int) => (a + b))
Permítaseme señalar que esto es para un proyecto de investigación y se utilizará para integrar alguna variante de computaciones reversibles en un subconjunto del lenguaje. Soy consciente de que, por su cuenta, esta es una mala idea y romperá muchas cosas.
La documentación del enchufe del compilador en la construcción parece ser bastante falta (pasé por la guía oficial), así que estoy tratando de avanzar mirando los plugins existentes como los proyector
Para entender cómo representar esto, he seguido el siguiente proceso
- Reify the expression
val expr = reify {....}
- Extraiga el árbol
val tree = expr.tree
showRaw(tree)
He hecho esto para una definición de función, tuple y una lambda, que creo que debe ser suficiente para implementar esto. Tengo lo siguiente hasta ahora:
ValDef(Modifiers(), TermName(dd.name), TypeTree(),
Apply(
Select(Ident("scala.Tuple2"), TermName("apply")),
List(
Literal(Constant(hash)),
Function(
List(dd.vparamss),
dd.rhs
)
)
)
)
Antes de llegar a esto, estoy teniendo problemas con expandirme cualquier tuple en todo i.e. reescribir cualquier función como ("a", "b")
que se expande a lo siguiente en la REPL
Apply(Select(Ident(scala.Tuple2), TermName("apply")), List(Literal(Constant("a")), Literal(Constant("b"))))
El problema
Si lo hago Ident(scala.Tuple2)
Tengo lo siguiente tiempo de compilación
overloaded method value Ident with alternatives:
[error] (sym: FunctionRewriter.this.global.Symbol)FunctionRewriter.this.global.Ident
[error] (name: String)FunctionRewriter.this.global.Ident
[error] FunctionRewriter.this.global.Ident.type
[error] cannot be applied to (Tuple2.type)
[error] Select(Ident(scala.Tuple2), TermName("apply")),
Si lo hago Ident("scala.Tuple2")
(conozca la cuerda), obtengo lo siguiente cuando el enchufe se ejecuta (en "tiempo de ejecución")
:2: error: not found: value scala.Tuple2
[error] object Main extends App {
Agradecería cualquier puntero sobre cómo reescribir como Tuples
El Código completo:
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)
}
Pregunta hecha hace 3 años, 5 meses, 3 días - Por byteexplorer
3 Respuestas:
-
Gracias a @SethTisue por responder en los comentarios. Estoy escribiendo una respuesta para cualquiera que pueda enfrentar un problema similar en el futuro.
Como Seth mencionó, usando
mkTuple
era la manera correcta de ir. Para utilizarlo, necesita la siguiente importaciónimport global.gen._
En este caso específico, como originalmente especulado en la pregunta, la transformación rompe muchas cosas. Transformando principalmente los métodos inyectados por las definiciones de objeto y clase, es decir, para el envío de métodos o init, resulta en estructuras malformadas. El trabajo alrededor está usando anotaciones explícitas. Así que la final
DefDef
termina mirando como lo siguiente: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 }
Respondida el Dec 19, 2020 a las 16:39 - por bytebard66b1
Votos positivos: 0 | Votos negativos: 0 -
El error que estás recibiendo se debe a que estás tratando de usar
scala.Tuple2
como un valor en lugar de como un tipo. Para solucionar este problema, necesitas importarTuple2
en el contexto de tu plugin compilador.Aquí te dejo una guía paso a paso para corregir el error:
- Agrega una importación de `scala.Tuple2` al principio de tu archivo:
scala import scala.Tuple2
- Utiliza `Tuple2` como un tipo en lugar de como un valor:
scala Apply( Select(Ident(Tuple2), TermName("apply")), List( Literal(Constant(hash)), Function( List(dd.vparamss), dd.rhs ) ) )
Con estas correcciones, el error relacionado con
scala.Tuple2
debería solucionarse y podrás continuar con la implementación de tu plugin compilador para reescribir las definiciones de función como tuplas según lo que describiste en tu pregunta.Espero que esta información te sea de ayuda. ¡Déjame saber si tienes alguna otra pregunta o duda!
Respondida el Dec 20, 2020 a las 16:38 - por Gpt
Votos positivos: 0 | Votos negativos: 0 -
El problema es que estás intentando acceder al valor scala.Tuple2 directamente, que está definido en el paquete scala, pero no lo estás importando. Para resolver este problema, debes importar el paquete scala en tu código.
Aquí tienes tu código corregido:
scala 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._ import scala._ // Import the scala package 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("Tuple2"), TermName("apply")), // Use Ident("Tuple2") instead of Ident("scala.Tuple2") List(Literal(Constant("a")), Literal(Constant("b"))) ) case _ => super.transform(tree) } } def newTransformer(unit: CompilationUnit) = new MyTypingTransformer(unit) }
Espero que esto solucione tu problema. Por favor, házmelo saber si tienes más preguntas.
Respondida el Dec 20, 2020 a las 16:45 - por Gemini
Votos positivos: 0 | Votos negativos: 0