scala.meta.internal.transversers.transformer.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of common_2.11 Show documentation
Show all versions of common_2.11 Show documentation
Bag of private and public helpers used in scala.meta's APIs and implementations
package scala.meta
package internal
package transversers
import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
class transformer extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro TransformerMacros.impl
}
class TransformerMacros(val c: Context) extends TransverserMacros {
import c.universe._
def transformField(treeName: TermName)(f: Field): ValDef = {
def treeTransformer(input: Tree, tpe: Type): Tree = {
val from = c.freshName(TermName("from"))
val to = c.freshName(TermName("to"))
q"""
val $from = $input
val $to = apply($from)
$to match {
case $to: ${hygienicRef(tpe.typeSymbol)} =>
if ($from ne $to) same = false
$to
case $to =>
this.fail(${f.owner.prefix + "." + f.name}, $from, $to)
}
"""
}
def optionTransformer(input: Tree, tpe: Type, nested: (Tree, Type) => Tree): Tree = {
val fromopt = c.freshName(TermName("fromopt"))
val from = c.freshName(TermName("from"))
val to = c.freshName(TermName("to"))
q"""
val $fromopt = $input
$fromopt match {
case $SomeModule($from) =>
val $to = ${nested(q"$from", tpe.typeArgs.head)}
if ($from eq $to) $fromopt
else $SomeModule($to)
case $NoneModule =>
$NoneModule
}
"""
}
def listTransformer(input: Tree, tpe: Type, nested: (Tree, Type) => Tree): Tree = {
val fromlist = c.freshName(TermName("fromlist"))
val elemTpe = tpe.typeArgs.head
q"""
val $fromlist = $input
var samelist = true
val tolist = $ListModule.newBuilder[$elemTpe]
$fromlist.foreach { src =>
val dst = ${nested(q"src", elemTpe)}
if (src ne dst) samelist = false
tolist += dst
}
if (samelist) $fromlist
else tolist.result()
"""
}
val fname = q"$treeName.${f.name}"
val rhs = f.tpe match {
case tpe @ TreeTpe() => treeTransformer(fname, tpe)
case tpe @ OptionTreeTpe(_) => optionTransformer(fname, tpe, treeTransformer)
case tpe @ ListTreeTpe(_) => listTransformer(fname, tpe, treeTransformer)
case tpe @ OptionListTreeTpe(_) =>
optionTransformer(fname, tpe, listTransformer(_, _, treeTransformer))
case tpe @ ListListTreeTpe(_) =>
listTransformer(fname, tpe, listTransformer(_, _, treeTransformer))
case _ => fname
}
q"val ${TermName(f.name.toString + "1")} = $rhs"
}
def leafHandler(l: Leaf, treeName: TermName): Tree = {
val constructor = hygienicRef(l.sym.companion)
val relevantFields = l.fields
.filter(f => !(f.tpe =:= typeOf[Any]) && !(f.tpe =:= typeOf[String]))
if (relevantFields.isEmpty) return q"$treeName"
val transformedFields: List[ValDef] = relevantFields.map(transformField(treeName))
q"""
var same = true
..$transformedFields
if (same) $treeName
else {
val newTree = $constructor(..${transformedFields.map(_.name)})
newTree
}
"""
}
def leafHandlerType(): Tree = TreeClass
def generatedMethods(): Tree = q"""
def apply(treeopt: $OptionClass[$TreeClass]): $OptionClass[$TreeClass] = treeopt match {
case $SomeModule(tree) =>
val tree1 = apply(tree)
if (tree eq tree1) treeopt
else $SomeModule(tree1)
case $NoneModule =>
$NoneModule
}
def apply(trees: $ListClass[$TreeClass]): $ListClass[$TreeClass] = {
var same = true
val buf = $ListModule.newBuilder[$TreeClass]
trees.foreach { tree =>
val tree1 = apply(tree)
if (tree ne tree1) same = false
buf += tree1
}
if (same) trees
else buf.result()
}
def apply(trees: $SeqClass[$TreeClass]): $SeqClass[$TreeClass] = {
var same = true
val buf = $SeqModule.newBuilder[$TreeClass]
trees.foreach { tree =>
val tree1 = apply(tree)
if (tree ne tree1) same = false
buf += tree1
}
if (same) trees
else buf.result()
}
def apply(treesopt: $OptionClass[$ListClass[$TreeClass]])(implicit hack: $Hack1Class): $OptionClass[$ListClass[$TreeClass]] = treesopt match {
case $SomeModule(trees) =>
val trees1 = apply(trees)
if (trees eq trees1) treesopt
else $SomeModule(trees1)
case $NoneModule =>
$NoneModule
}
def apply(treesopt: $OptionClass[$SeqClass[$TreeClass]])(implicit hack: $Hack3Class): $OptionClass[$SeqClass[$TreeClass]] =
treesopt match {
case $SomeModule(trees) =>
val trees1 = apply(trees)
if (trees eq trees1) treesopt
else $SomeModule(trees1)
case $NoneModule =>
$NoneModule
}
def apply(treess: $ListClass[$ListClass[$TreeClass]])(implicit hack: $Hack2Class): $ListClass[$ListClass[$TreeClass]] = {
var same = true
val buf = $ListModule.newBuilder[$ListClass[$TreeClass]]
treess.foreach { trees =>
val trees1 = apply(trees)
if (trees ne trees1) same = false
buf += trees1
}
if (same) treess
else buf.result()
}
def apply(treess: $SeqClass[$SeqClass[$TreeClass]])(implicit hack: $Hack4Class): $SeqClass[$SeqClass[$TreeClass]] = {
var same = true
val buf = $SeqModule.newBuilder[$SeqClass[$TreeClass]]
treess.foreach { trees =>
val trees1 = apply(trees)
if (trees ne trees1) same = false
buf += trees1
}
if (same) treess
else buf.result()
}
private def fail(field: String, from: $TreeClass, to: $TreeClass): $NothingClass = {
import scala.meta.prettyprinters._
val errorPrefix = "Invalid transformation of " + field + ": "
val errorHeader = errorPrefix + from.productPrefix + " -> " + to.productPrefix + ". "
val errorDetails = "From: " + from.structure + ", to: " + to.structure
throw new UnsupportedOperationException(errorHeader + errorDetails)
}
"""
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy