Библиотека для метапрограммирования на Scala
libraryDependencies += "org.scalameta" %% "scalameta" % "2.0.1"
case class User(name: String)
Defn.Class(List(Mod.Case()), Type.Name("User"), Nil,
Ctor.Primary(Nil, Name(""), List(List(Term.Param(Nil,
Term.Name("name"), Some(Type.Name("String")), None)))),
Template(Nil, Nil, Self(Name(""), None), Nil))
Defn.Class(
mods = List(Mod.Case()),
name = Type.Name("User"),
tparams = Nil,
ctor = Ctor.Primary(
mods = Nil,
name = Name(""),
paramss = List(List(
Term.Param(
mods = Nil,
name = Term.Name("name"),
decltpe = Some(Type.Name("String")),
default = None
)
))
),
templ = Template(Nil, Nil, Self(Name(""), None), Nil)
)
q"case class User(name: String)"
val method = q"def upperName: String = name.toUpperCase"
q"""case class User(name: String) {
$method
}"""
// meta.Defn.Class = case class User(name: String) {
// def upperName: String = name.toUpperCase
// }
q"case class User(name: String)" match {
case q"case class $className(..$paramss)" =>
val ageParam = param"age: Int"
val newParamss = paramss :+ ageParam
q"case class $className(..$newParamss)"
case other => other
}
// meta.Defn.Class =
// case class User(name: String, age: Int)
source"""
sealed trait Op[A]
object Op extends B {
case class Foo(i: Int) extends Op[Int]
case class Bar(s: String) extends Op[String]
}
""".collect {
case cls: Defn.Class => cls.name
}
// List[meta.Type.Name] = List(Foo, Bar)
libraryDependencies += "org.scalameta" %% "scalameta" % "1.8.0"
addCompilerPlugin("org.scalameta" % "paradise" % "3.0.0-M10" cross CrossVersion.full)
scalacOptions += "-Xplugin-require:macroparadise"
import scala.annotation.StaticAnnotation
import scala.meta._
class HelloWorld extends StaticAnnotation {
inline def apply(defn: Any): Any = meta {
defn // macro code
}
}
// before
class ToMapTest(a: String, b: Int)(c: Double)
// after
class ToMapTest(a: String, b: Int)(c: Double) {
def toMap: Map[String, String] = {
Map(("a", a.toString), ("b", b.toString), ("c", c.toString))
}
}
class ToMap extends StaticAnnotation {
inline def apply(defn: Any): Any = meta {
}
}
class ToMap extends StaticAnnotation {
inline def apply(defn: Any): Any = meta {
defn match {
}
}
}
class ToMap extends StaticAnnotation {
inline def apply(defn: Any): Any = meta {
defn match {
case cls @ Defn.Class(_, _, _, _, _) =>
case _ =>
}
}
}
class ToMap extends StaticAnnotation {
inline def apply(defn: Any): Any = meta {
defn match {
case cls @ Defn.Class(_, _, _, _, _) =>
case _ =>
abort("@ToMap must annotate a class")
}
}
}
class ToMap extends StaticAnnotation {
inline def apply(defn: Any): Any = meta {
defn match {
case cls @ Defn.Class(_, _, _, ctor, _) =>
val tuples: Seq[Term.Tuple] = ctor.paramss.flatten.map { param: Term.Param =>
q"(${Lit.String(param.name.value)}, ${Term.Name(param.name.value)}.toString)"
}
case _ =>
abort("@ToMap must annotate a class")
}
}
}
class ToMap extends StaticAnnotation {
inline def apply(defn: Any): Any = meta {
defn match {
case cls @ Defn.Class(_, _, _, ctor, _) =>
val tuples: Seq[Term.Tuple] = ctor.paramss.flatten.map { param: Term.Param =>
q"(${Lit.String(param.name.value)}, ${Term.Name(param.name.value)}.toString)"
}
val method: Defn.Def =
q"""def toMap: _root_.scala.collection.Map[String, String] = {
_root_.scala.collection.Map[String, String](..$tuples)
}"""
case _ =>
abort("@ToMap must annotate a class")
}
}
}
class ToMap extends StaticAnnotation {
inline def apply(defn: Any): Any = meta {
defn match {
case cls @ Defn.Class(_, _, _, ctor, template) =>
val tuples: Seq[Term.Tuple] = ctor.paramss.flatten.map { param: Term.Param =>
q"(${Lit.String(param.name.value)}, ${Term.Name(param.name.value)}.toString)"
}
val method: Defn.Def =
q"""def toMap: _root_.scala.collection.Map[String, String] = {
_root_.scala.collection.Map[String, String](..$tuples)
}"""
val templateStats: Seq[Stat] = method +: template.stats.getOrElse(Nil)
cls.copy(templ = template.copy(stats = Some(templateStats)))
case _ =>
abort("@ToMap must annotate a class")
}
}
}