All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dotty.tools.dotc.quoted.QuoteCompiler.scala Maven / Gradle / Ivy

package dotty.tools.dotc
package quoted

import dotty.tools.backend.jvm.GenBCode
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.core.Decorators._
import dotty.tools.dotc.core.Flags._
import dotty.tools.dotc.core.Mode
import dotty.tools.dotc.core.Names.TypeName
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.core.Scopes.{EmptyScope, newScope}
import dotty.tools.dotc.core.StdNames.nme
import dotty.tools.dotc.core.Symbols.defn
import dotty.tools.dotc.core.Types.ExprType
import dotty.tools.dotc.core.quoted.PickledQuotes
import dotty.tools.dotc.transform.ReifyQuotes
import dotty.tools.dotc.typer.FrontEnd
import dotty.tools.dotc.util.Positions.Position
import dotty.tools.dotc.util.SourceFile
import dotty.tools.io.{AbstractFile, Path, PlainFile}

import scala.quoted.{Expr, Type}

/** Compiler that takes the contents of a quoted expression `expr` and produces
 *  a class file with `class ' { def apply: Object = expr }`.
 */
class QuoteCompiler extends Compiler {
  import tpd._

  override protected def frontendPhases: List[List[Phase]] =
    List(List(new QuotedFrontend(putInClass = true)))

  override protected def picklerPhases: List[List[Phase]] =
    List(List(new ReifyQuotes))

  override def newRun(implicit ctx: Context): ExprRun = {
    reset()
    new ExprRun(this, ctx.addMode(Mode.ReadPositions))
  }

  def outputClassName: TypeName = "Quoted".toTypeName

  /** Frontend that receives a scala.quoted.Expr or scala.quoted.Type as input */
  class QuotedFrontend(putInClass: Boolean) extends FrontEnd {
    import tpd._

    override def isTyper = false

    override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
      units.map {
        case exprUnit: ExprCompilationUnit =>
          val tree =
            if (putInClass) inClass(exprUnit.expr)
            else PickledQuotes.quotedExprToTree(exprUnit.expr)
          val source = new SourceFile("", "")
          CompilationUnit.mkCompilationUnit(source, tree, forceTrees = true)
        case typeUnit: TypeCompilationUnit =>
          assert(!putInClass)
          val tree = PickledQuotes.quotedTypeToTree(typeUnit.tpe)
          val source = new SourceFile("", "")
          CompilationUnit.mkCompilationUnit(source, tree, forceTrees = true)
      }
    }

    /** Places the contents of expr in a compilable tree for a class
      *  with the following format.
      *  `package __root__ { class ' { def apply: Any =  } }`
      */
    private def inClass(expr: Expr[_])(implicit ctx: Context): Tree = {
      val pos = Position(0)
      val assocFile = new PlainFile(Path(""))

      val cls = ctx.newCompleteClassSymbol(defn.RootClass, outputClassName, EmptyFlags,
        defn.ObjectType :: Nil, newScope, coord = pos, assocFile = assocFile).entered.asClass
      cls.enter(ctx.newDefaultConstructor(cls), EmptyScope)
      val meth = ctx.newSymbol(cls, nme.apply, Method, ExprType(defn.AnyType), coord = pos).entered

      val quoted = PickledQuotes.quotedExprToTree(expr)(ctx.withOwner(meth))

      val run = DefDef(meth, quoted)
      val classTree = ClassDef(cls, DefDef(cls.primaryConstructor.asTerm), run :: Nil)
      PackageDef(ref(defn.RootPackage).asInstanceOf[Ident], classTree :: Nil).withPos(pos)
    }
  }

  class ExprRun(comp: Compiler, ictx: Context) extends Run(comp, ictx) {
    def compileExpr(expr: Expr[_]): Unit = {
      val units = new ExprCompilationUnit(expr) :: Nil
      compileUnits(units)
    }
    def compileType(tpe: Type[_]): Unit = {
      val units = new TypeCompilationUnit(tpe) :: Nil
      compileUnits(units)
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy