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

dataclass.ImplTransformers.scala Maven / Gradle / Ivy

package dataclass

import scala.reflect.macros.blackbox.Context

// from https://github.com/scalameta/scalameta/blob/232d56a457f92582ca2cc1ac5a8f96780a8415f4/scalameta/common/shared/src/main/scala/org/scalameta/internal/ImplTransformers.scala

private[dataclass] trait ImplTransformers {
  val c: Context
  import c.universe._
  import Flag._

  implicit class XtensionAnnotteeTransformer(annottees: Seq[Tree]) {
    def transformAnnottees(transformer: ImplTransformer): Tree = {
      transformer.transform(annottees: _*)
    }
  }

  class ImplTransformer {
    def transformClass(cdef: ClassDef, mdef: ModuleDef): List[ImplDef] = ???
    def transformTrait(cdef: ClassDef, mdef: ModuleDef): List[ImplDef] = ???
    def transformModule(mdef: ModuleDef): ModuleDef = ???

    def transform(annottees: Tree*): Tree = {
      def isImplemented(body: => Any): Boolean =
        try {
          body; true
        } catch {
          case _: NotImplementedError => false; case _: Throwable => true
        }
      val allowClasses = isImplemented(transformClass(null, null))
      val allowTraits = isImplemented(transformTrait(null, null))
      val allowModules = isImplemented(transformModule(null))
      if (!allowClasses && !allowTraits && !allowModules)
        sys.error("invalid ImplTransformer")

      def failUnexpectedAnnottees() = {
        var allowed = List[String]()
        if (allowClasses) allowed :+= "classes"
        if (allowTraits) allowed :+= "traits"
        if (allowModules) allowed :+= "modules"
        val s_allowed = {
          if (allowed.length > 1)
            allowed.dropRight(1).mkString(", ") + " and " + allowed.last
          else allowed.mkString
        }
        val q"new $s_name(...$_).macroTransform(..$_)" = c.macroApplication
        c.abort(annottees.head.pos, s"only $s_allowed can be $s_name")
      }

      val expanded = annottees match {
        case (cdef @ ClassDef(mods, _, _, _)) :: (mdef: ModuleDef) :: rest =>
          if (!(mods hasFlag TRAIT)) {
            if (!allowClasses) failUnexpectedAnnottees()
            transformClass(cdef, mdef) ++ rest
          } else {
            if (!allowTraits) failUnexpectedAnnottees()
            transformTrait(cdef, mdef) ++ rest
          }
        case (cdef @ ClassDef(mods, name, _, _)) :: rest =>
          val syntheticMdef = q"object ${name.toTermName}"
          if (!(mods hasFlag TRAIT)) {
            if (!allowClasses) failUnexpectedAnnottees()
            transformClass(cdef, syntheticMdef) ++ rest
          } else {
            if (!allowTraits) failUnexpectedAnnottees()
            transformTrait(cdef, syntheticMdef) ++ rest
          }
        case (mdef @ ModuleDef(_, _, _)) :: rest =>
          if (!allowModules) failUnexpectedAnnottees()
          transformModule(mdef) +: rest
        case annottee :: rest =>
          failUnexpectedAnnottees()
      }
      q"{ ..$expanded; () }"
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy