plugin.OnCreateEventsPhase.scala Maven / Gradle / Ivy
The newest version!
package dfhdl.plugin
import dotty.tools.dotc.*
import plugins.*
import core.*
import Contexts.*
import Symbols.*
import Flags.*
import SymDenotations.*
import Decorators.*
import ast.Trees.*
import ast.{tpd, untpd}
import StdNames.nme
import Names.*
import Types.*
import Constants.Constant
import annotation.tailrec
import scala.language.implicitConversions
import scala.compiletime.uninitialized
import collection.mutable
class OnCreateEventsPhase(setting: Setting) extends CommonPhase:
import tpd._
val phaseName = "OnCreateEvents"
// override val debugFilter: String => Boolean = _.contains("PluginSpec.scala")
override val runsAfter = Set("CustomControl")
override val runsBefore = Set(transform.FirstTransform.name)
val ignore = mutable.Set.empty[Tree]
var onCreateEventsTpe: TypeRef = uninitialized
var clsStack = List.empty[TypeDef]
var dfcClsStack = List.empty[TypeDef]
override def prepareForTypeDef(tree: TypeDef)(using Context): Context =
tree.rhs match
case _: Template =>
if (tree.tpe <:< hasDFCTpe)
dfcClsStack = tree :: dfcClsStack
clsStack = tree :: clsStack
case _ =>
ctx
override def transformTypeDef(tree: TypeDef)(using Context): Tree =
tree.rhs match
case template: Template =>
if (tree.tpe <:< hasDFCTpe)
dfcClsStack = dfcClsStack.drop(1)
clsStack = clsStack.drop(1)
val clsTpe = tree.tpe
val clsSym = clsTpe.typeSymbol
if (clsTpe <:< onCreateEventsTpe && clsSym.isAnonymousClass)
val onCreateStartLateTree =
This(clsSym.asClass)
.select("onCreateStartLate".toTermName)
val newTemplate = cpy.Template(template)(
template.constr,
template.parents,
template.derived,
template.self,
onCreateStartLateTree :: template.body
)
cpy.TypeDef(tree)(tree.name, newTemplate)
else tree
end if
case _ =>
tree
end match
end transformTypeDef
private object OnCreateEventsInstance:
def mkThisOwner(using Context): Tree =
dfcClsStack.headOption.map(h => mkSome(This(h.tpe.classSymbol.asClass))).getOrElse(mkNone)
def apply(tree: ValDef)(using Context): Tree =
val clsSym = tree.tpe.classSymbol.asClass
Select(This(clsStack.head.tpe.classSymbol.asClass), tree.name)
.select(clsSym.requiredMethod("onCreate")).appliedTo(mkThisOwner)
end apply
def apply(clsSym: ClassSymbol, tpe: Type, tree: Tree)(using Context): Tree =
tree
.select(clsSym.requiredMethodRef("onCreate"))
.withType(TermRef(tpe, clsSym.requiredMethod("onCreate"))).appliedTo(mkThisOwner)
@tailrec def unapply(tree: Tree)(using Context): Option[ClassSymbol] =
tree match
case Select(clsTree @ New(id), _) if clsTree.tpe <:< onCreateEventsTpe =>
// An object's onCreate is handled under `transformStats`
if (!id.symbol.is(Module))
Some(clsTree.tpe.classSymbol.asClass)
else None
case Apply(tree, _) => unapply(tree)
case TypeApply(tree, _) => unapply(tree)
case _ => None
end OnCreateEventsInstance
override def prepareForTemplate(tree: Template)(using Context): Context =
ignore ++= tree.parents
ctx
override def transformStats(trees: List[Tree])(using Context): List[Tree] =
trees.foldRight(List.empty[Tree]) {
case (tree: ValDef, next :: stats) =>
val tpe = tree.tpe
if (tpe <:< onCreateEventsTpe && tpe.typeSymbol.is(Module))
tree :: next :: OnCreateEventsInstance(tree) :: stats
else tree :: next :: stats
case (tree, stats) =>
tree :: stats
}
end transformStats
override def transformApply(tree: Apply)(using Context): Tree =
if (tree.tpe.isParameterless && !ignore.exists(i => i.sameTree(tree)))
tree match
case OnCreateEventsInstance(clsSym) =>
OnCreateEventsInstance(clsSym, tree.tpe, tree)
case _ => tree
else tree
override def prepareForUnit(tree: Tree)(using Context): Context =
super.prepareForUnit(tree)
onCreateEventsTpe = requiredClassRef("dfhdl.internals.OnCreateEvents")
ignore.clear()
dfcClsStack = Nil
clsStack = Nil
ctx
end OnCreateEventsPhase