在REPL中将代码扩展到原始AST Scala 3

j2qf4p5b  于 2022-11-09  发布在  Scala
关注(0)|答案(1)|浏览(138)

我目前正在做大量的编译器研究。这不仅需要编写编译器插件,还需要将Dotty编译器从解析器修改为类型器。因此,我需要不断地查看原始的AST来绘制必要的转换。
在Scala 2中,反射库提供了以下功能:

val expression = ....
   val tree = reify{expression}.tree
   showRaw(tree)

现在,根据我对from the docs的理解,最后一步已经被Printer.TreeStructure.show(tree)取代
然而,我在元编程文档中找不到任何可以替代reify的东西。现在,我显然可以在Scala程序中使用各种元编程技术,并将树打印到stdout,但与在REPL中展开以进行快速手动验证相比,这是一个非常耗时的过程。
在Scala3REPL中有什么方法可以做到这一点吗?

y53ybaqx

y53ybaqx1#

您可以在项目中定义自己的reify

import scala.quoted.*

object App {
  inline def reify(inline a: Any) = ${reifyImpl('a)}

  def reifyImpl(a: Expr[Any])(using Quotes): Expr[String] = {
    import quotes.reflect.*
    Literal(StringConstant(Printer.TreeStructure.show(a.asTerm))).asExprOf[String]
  }
}

并在REPL中使用它

sbt console

scala> import App.reify

scala> reify{ class A }                                                                                                                                                             
val res0: String = Inlined(None, Nil, Block(List(ClassDef("A", DefDef("<init>", List(TermParamClause(Nil)), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), None, Nil)), Literal(UnitConstant())))

遗憾的是,在REPL中直接定义reify似乎不起作用

scala> import scala.quoted.*; inline def reify(inline a: Any) = ${reifyImpl('a)}; def reifyImpl(a: Expr[Any])(using Quotes): Expr[String] = {import quotes.reflect.*; Literal(StringConstant(Printer.TreeStructure.show(a.asTerm))).asExprOf[String]}
def reify(a: Any): String
def reifyImpl
  (a: quoted.Expr[Any])(using x$2: quoted.Quotes): quoted.Expr[String]

scala> reify{class A}
-- Error:
1 |reify{class A}
  |^^^^^^^^^^^^^^
  |Failed to evaluate macro.
  |  Caused by class java.lang.ClassNotFoundException: rs$line$6
  |    java.lang.ClassLoader.loadClass(ClassLoader.java:418)
  |    java.lang.ClassLoader.loadClass(ClassLoader.java:351)
  |    dotty.tools.repl.AbstractFileClassLoader.loadClass(AbstractFileClassLoader.scala:55)
  |    dotty.tools.dotc.transform.Splicer$Interpreter.loadReplLineClass(Splicer.scala:402)
  |    dotty.tools.dotc.transform.Splicer$Interpreter.interpretedStaticMethodCall(Splicer.scala:354)
  |    dotty.tools.dotc.transform.Splicer$Interpreter.interpretTree(Splicer.scala:260)
  |    dotty.tools.dotc.transform.Splicer$Interpreter.interpretTree$$anonfun$2(Splicer.scala:281)
  |             
  | This location contains code that was inlined from rs$line$7:1

在3.2.0中,可以在REPL(scala-cli)中直接定义reify

$ scala-cli

Welcome to Scala 3.2.0 (1.8.0_231, Java Java HotSpot(TM) 64-Bit GraalVM EE 19.3.0).
Type in expressions for evaluation. Or try :help.

scala> import scala.quoted.*; inline def reify(inline a: Any) = ${reifyImpl('a)}; def reifyImpl(a: Expr[Any])(using Quotes): Expr[String] = {import quotes.reflect.*; Literal(StringConstant(Printer.TreeStructure.show(a.asTerm))).asExprOf[String]}
def reify(a: Any): String
def reifyImpl
  (a: quoted.Expr[Any])(using x$2: quoted.Quotes): quoted.Expr[String]

scala> reify{class A}
val res0: String = Inlined(None, Nil, Block(List(ClassDef("A", DefDef("<init>", List(TermParamClause(Nil)), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), None, Nil)), Literal(UnitConstant())))

相关问题