@@ -20,13 +20,18 @@ import dotty.tools.dotc.util.Spans.Span
2020import dotty .tools .dotc .util .SourceFile
2121import dotty .tools .io .{Path , VirtualFile }
2222
23- import scala .quoted .{Expr , Type , QuoteContext }
23+ import scala .annotation .tailrec
24+ import scala .concurrent .Promise
25+ import scala .quoted .{Expr , QuoteContext , Type }
2426
2527/** Compiler that takes the contents of a quoted expression `expr` and produces
2628 * a class file with `class ' { def apply: Object = expr }`.
2729 */
2830class QuoteCompiler extends Compiler {
2931
32+ /** Either `Left` with name of the classfile generated or `Right` with the value contained in the expression */
33+ private [this ] var result : Either [String , Any ] = null
34+
3035 override protected def frontendPhases : List [List [Phase ]] =
3136 List (List (new QuotedFrontend ))
3237
@@ -44,14 +49,36 @@ class QuoteCompiler extends Compiler {
4449 class QuotedFrontend extends Phase {
4550 import tpd ._
4651
52+
4753 def phaseName : String = " quotedFrontend"
4854
4955 override def runOn (units : List [CompilationUnit ])(implicit ctx : Context ): List [CompilationUnit ] = {
50- units.map {
56+ units.flatMap {
5157 case exprUnit : ExprCompilationUnit =>
52- val tree = inClass(exprUnit.exprBuilder)
53- val source = SourceFile .virtual(" <quoted.Expr>" , " " )
54- CompilationUnit (source, tree, forceTrees = true )
58+ val pos = Span (0 )
59+ val assocFile = new VirtualFile (" <quote>" )
60+
61+ // Places the contents of expr in a compilable tree for a class with the following format.
62+ // `package __root__ { class ' { def apply: Any = <expr> } }`
63+ val cls = ctx.newCompleteClassSymbol(defn.RootClass , outputClassName, EmptyFlags ,
64+ defn.ObjectType :: Nil , newScope, coord = pos, assocFile = assocFile).entered.asClass
65+ cls.enter(ctx.newDefaultConstructor(cls), EmptyScope )
66+ val meth = ctx.newSymbol(cls, nme.apply, Method , ExprType (defn.AnyType ), coord = pos).entered
67+
68+ val quoted = PickledQuotes .quotedExprToTree(checkValidRunExpr(exprUnit.exprBuilder.apply(new QuoteContext (ReflectionImpl (ctx)))))(ctx.withOwner(meth))
69+
70+ getLiteral(quoted) match {
71+ case Some (value) =>
72+ result = Right (value)
73+ None // Stop copilation here we already have the result
74+ case None =>
75+ val run = DefDef (meth, quoted)
76+ val classTree = ClassDef (cls, DefDef (cls.primaryConstructor.asTerm), run :: Nil )
77+ val tree = PackageDef (ref(defn.RootPackage ).asInstanceOf [Ident ], classTree :: Nil ).withSpan(pos)
78+ val source = SourceFile .virtual(" <quoted.Expr>" , " " )
79+ result = Left (outputClassName.toString)
80+ Some (CompilationUnit (source, tree, forceTrees = true ))
81+ }
5582 }
5683 }
5784
@@ -61,33 +88,25 @@ class QuoteCompiler extends Compiler {
6188 case _ => expr
6289 }
6390
64- /** Places the contents of expr in a compilable tree for a class
65- * with the following format.
66- * `package __root__ { class ' { def apply: Any = <expr> } }`
67- */
68- private def inClass (exprBuilder : QuoteContext => Expr [_])(implicit ctx : Context ): Tree = {
69- val pos = Span (0 )
70- val assocFile = new VirtualFile (" <quote>" )
71-
72- val cls = ctx.newCompleteClassSymbol(defn.RootClass , outputClassName, EmptyFlags ,
73- defn.ObjectType :: Nil , newScope, coord = pos, assocFile = assocFile).entered.asClass
74- cls.enter(ctx.newDefaultConstructor(cls), EmptyScope )
75- val meth = ctx.newSymbol(cls, nme.apply, Method , ExprType (defn.AnyType ), coord = pos).entered
76-
77- val quoted = PickledQuotes .quotedExprToTree(checkValidRunExpr(exprBuilder.apply(new QuoteContext (ReflectionImpl (ctx)))))(ctx.withOwner(meth))
78-
79- val run = DefDef (meth, quoted)
80- val classTree = ClassDef (cls, DefDef (cls.primaryConstructor.asTerm), run :: Nil )
81- PackageDef (ref(defn.RootPackage ).asInstanceOf [Ident ], classTree :: Nil ).withSpan(pos)
91+ /** Get the literal value if this tree only contains a literal tree */
92+ @ tailrec private def getLiteral (tree : Tree ): Option [Any ] = tree match {
93+ case Literal (lit) => Some (lit.value)
94+ case Block (Nil , expr) => getLiteral(expr)
95+ case Inlined (_, Nil , expr) => getLiteral(expr)
96+ case _ => None
8297 }
8398
8499 def run (implicit ctx : Context ): Unit = unsupported(" run" )
85100 }
86101
87- class ExprRun (comp : Compiler , ictx : Context ) extends Run (comp, ictx) {
88- def compileExpr (exprBuilder : QuoteContext => Expr [_]): Unit = {
102+ class ExprRun (comp : QuoteCompiler , ictx : Context ) extends Run (comp, ictx) {
103+ /** Unpickle and optionally compile the expression.
104+ * Returns either `Left` with name of the classfile generated or `Right` with the value contained in the expression.
105+ */
106+ def compileExpr (exprBuilder : QuoteContext => Expr [_]): Either [String , Any ] = {
89107 val units = new ExprCompilationUnit (exprBuilder) :: Nil
90108 compileUnits(units)
109+ result
91110 }
92111 }
93112}
0 commit comments