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

scala.meta.internal.trees.quasiquote.scala Maven / Gradle / Ivy

package scala.meta
package internal
package trees

import org.scalameta.internal.MacroHelpers

import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context

// Generates quasiquote definition boilerplate for a given interpolator
// and then injects it into the annottee.
// See usage examples in the `quasiquotes` project.
class quasiquote[T](qname: String) extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro QuasiquoteMacros.impl
}

class QuasiquoteMacros(val c: Context) extends MacroHelpers {
  import c.universe._
  val ReificationMacros = q"_root_.scala.meta.internal.quasiquotes.ReificationMacros"
  def impl(annottees: c.Tree*): c.Tree = annottees.transformAnnottees(new ImplTransformer {
    val q"new $_[..$qtypes](${qname: String}).macroTransform(..$_)" = c.macroApplication
    override def transformClass(cdef: ClassDef, mdef: ModuleDef): List[ImplDef] = {
      val q"$mods class $name[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }" =
        cdef
      val q"$mmods object $mname extends { ..$mearlydefns } with ..$mparents { $mself => ..$mstats }" =
        mdef
      val mmods1 = Modifiers(mmods.flags, TypeName("meta"), mmods.annotations)
      if (stats.nonEmpty) c.abort(cdef.pos, "@quasiquote classes must have empty bodies")
      val qmodule = {
        val qtypesLub = lub(qtypes.map(_.duplicate).map { qtype =>
          try c.typecheck(qtype, c.TYPEmode).tpe
          catch {
            case c.TypecheckException(pos, msg) => c.abort(pos.asInstanceOf[c.Position], msg)
          }
        })
        q"""
          object ${TermName(qname)} {
            import scala.language.experimental.macros
            def apply[T >: Any](args: T*)(implicit dialect: _root_.scala.meta.Dialect): $qtypesLub = macro $ReificationMacros.apply
            def unapply(scrutinee: Any)(implicit dialect: _root_.scala.meta.Dialect): Any = macro $ReificationMacros.unapply
          }
        """
      }
      val qparser = {
        val qmonadicResults = qtypes.map(qtype =>
          q"""
          type Parse[T] = _root_.scala.meta.parsers.Parse[T]
          val parse = _root_.scala.Predef.implicitly[Parse[$qtype]]
          parse(input, dialect)
        """
        )
        val qmonadicResult = qmonadicResults.reduce((acc, curr) => q"$acc.orElse($curr)")
        val qresult = q"""
          $qmonadicResult match {
            case x: _root_.scala.meta.parsers.Parsed.Success[_] => x.tree
            case x: _root_.scala.meta.parsers.Parsed.Error => throw x.details
          }
        """
        q"private[meta] def parse(input: _root_.scala.meta.inputs.Input, dialect: _root_.scala.meta.Dialect) = $qresult"
      }
      val stats1 = stats :+ qmodule
      val mstats1 = mstats :+ qparser
      val cdef1 =
        q"$mods class $name[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats1 }"
      val mdef1 =
        q"$mmods1 object $mname extends { ..$mearlydefns } with ..$mparents { $mself => ..$mstats1 }"
      List(cdef1, mdef1)
    }
  })
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy