trabajo sirve seguridad riesgo realizar qué prevencion pemex para llenar ejemplo definicion correctamente como ats ast art analisis scala macros scala-2.10

scala - seguridad - ¿qué es el ast y para qué sirve?



¿Cuál es la forma más fácil de usar reify(obtener un AST de) una expresión en Scala? (2)

Estoy buscando alternativas a la -print o javap como una forma de averiguar qué está haciendo el compilador en Scala. Con la nueva biblioteca de reflexión / macros, reify parece ser un buen candidato para eso, como se muestra en el macroáz de retronym ''s desugar . Incluso muestra cómo se solía hacer eso, antes de M4.

Entonces la pregunta es, ¿cuál es la cosa más corta / más fácil que puedo escribir en el REPL de Scala para obtener el AST para una expresión, post-Scala 2.10.0-M4?


Hay una mejora de la nueva versión de Scala

scala> import scala.tools.reflect.ToolBox import scala.tools.reflect.ToolBox scala> import scala.reflect.runtime.{currentMirror => m} import scala.reflect.runtime.{currentMirror=>m} scala> val tb = m.mkToolBox() tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@78dc5f15 scala> val tree = tb.parseExpr("1 to 3 map (_+1)") <console>:10: error: value parseExpr is not a member of scala.tools.reflect.ToolBox[reflect.runtime.universe.type] val tree = tb.parseExpr("1 to 3 map (_+1)") ^ scala> val tree = tb.parse("1 to 3 map (_+1)") tree: tb.u.Tree = 1.to(3).map(((x$1) => x$1.$plus(1))) scala> val eval = tb.eval(tree) eval: Any = Vector(2, 3, 4)


Muchas cosas previamente definidas en el paquete scala.reflect.mirror han movido a scala.reflect.runtime.universe :

scala> import scala.reflect.runtime.{universe => u} import scala.reflect.runtime.{universe=>u} scala> val expr = u reify { 1 to 3 map (_+1) } expr: reflect.runtime.universe.Expr[scala.collection.immutable.IndexedSeq[Int]] = Expr[scala.collection.immutable.IndexedSeq[Int]](scala.this.Predef.intWrapper(1).to(3).map(((x$1) => x$1.$plus(1)))(immutable.this.IndexedSeq.canBuildFrom)) scala> u show expr.tree res57: String = scala.this.Predef.intWrapper(1).to(3).map(((x$1) => x$1.$plus(1)))(immutable.this.IndexedSeq.canBuildFrom) scala> u showRaw expr.tree res58: String = Apply(Apply(Select(Apply(Select(Apply(Select(Select(This(newTypeName("scala")), newTermName("Predef")), newTermName("intWrapper")), List(Literal(Constant(1)))), newTermName("to")), List(Literal(Constant(3)))), newTermName("map")), List(Function(List(ValDef(Modifiers(<param> <synthetic>), newTermName("x$1"), TypeTree(), EmptyTree)), Apply(Select(Ident(newTermName("x$1")), newTermName("$plus")), List(Literal(Constant(1))))))), List(Select(Select(This(newTypeName("immutable")), newTermName("IndexedSeq")), newTermName("canBuildFrom"))))

Además, es posible verificar si una cadena que contiene algún código de Scala es una expresión de Scala válida y, aún mejor, hacer alguna evaluación:

Editar . En 2.10.0-RC1 algunos métodos de ToolBox han sido renombrados. parseExpr ahora se acaba de parse , y runExpr ahora se llama eval .

scala> import scala.tools.reflect.ToolBox import scala.tools.reflect.ToolBox scala> import scala.reflect.runtime.{currentMirror => m} import scala.reflect.runtime.{currentMirror=>m} scala> val tb = m.mkToolBox() tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@9293709 scala> val tree = tb.parse("1 to 3 map (_+1)") tree: tb.u.Tree = 1.to(3).map(((x$1) => x$1.$plus(1))) scala> val eval = tb.eval(tree) eval: Any = Vector(2, 3, 4)

Lo más complicado aquí es la representación en árbol sin formato de una expresión. Cuando uno quiere usar macros, las macros deben definirse de la misma manera que se muestra con showRaw . Pero con algunos métodos de ayuda es posible definir algunas implementaciones de macro no tan feas:

object IntMacro { import language.experimental.macros import scala.reflect.makro.Context import scala.reflect.NameTransformer.encode def isEven(i: Int): Boolean = macro isEvenImpl def isEvenImpl(c: Context)(i: c.Expr[Int]): c.Expr[Boolean] = { import c.universe._ implicit val cc: c.type = c val `x = i%2` = Apply(Select(i.tree, op("%")), const(2)) val `x == 0` = Apply(Select(`x = i%2`, op("==")), const(0)) c.Expr(`x == 0`) } def op(s: String)(implicit c: Context): c.universe.TermName = c.universe.newTermName(encode(s)) def const(a: Any)(implicit c: Context): List[c.universe.Literal] = List(c.universe.Literal(c.universe.Constant(a))) } scala> import IntMacro._ import IntMacro._ scala> isEven(2) res60: Boolean = true scala> isEven(3) res61: Boolean = false

Pero ahora tenemos problemas con los tipos dependientes de la ruta: debemos escribir sus rutas explícitamente si no queremos importarlas.