Skip to content

Instantly share code, notes, and snippets.

@malcolmgreaves
Forked from travisbrown/FreeMacros.scala
Last active August 29, 2015 14:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save malcolmgreaves/eb6d65efcc440576f1aa to your computer and use it in GitHub Desktop.
Save malcolmgreaves/eb6d65efcc440576f1aa to your computer and use it in GitHub Desktop.
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
class FreeMacros(val c: whitebox.Context) {
import c.universe._
def smartName(name: String): String = (
name.toList match {
case h :: t => h.toLower :: t
case Nil => Nil
}
).mkString
def liftedImpl[F[_]](implicit t: c.WeakTypeTag[F[_]]): Tree = {
val atc = t.tpe.typeConstructor
val constructors = t.tpe.typeSymbol.asClass.knownDirectSubclasses.map {
case constructor: ClassSymbol =>
val companion = constructor.companion
val ctpe = constructor.typeSignature
val ctc = ctpe.typeConstructor
val methodName = TermName(smartName(constructor.name.toString))
val A = TypeName(c.freshName())
val (params, names) = ctpe.decls.collect {
case m: MethodSymbol if m.isCaseAccessor =>
m.typeSignatureIn(atc) match {
case NullaryMethodType(returnType) =>
val param =
if (returnType.typeSymbol == ctc.typeParams.head)
q"val ${m.name}: $A"
else
q"val ${m.name}: $returnType"
(param, m.name)
}
}.unzip
q"""
def $methodName[$A](..$params): _root_.cats.free.FreeC[$atc, $A] =
_root_.cats.free.Free.liftFC[$atc, $A](
$companion.apply[$A](..$names)
)
"""
}
q"new { ..$constructors }"
}
}
object FreeMacros {
def liftConstructors[F[_]]: Any = macro FreeMacros.liftedImpl[F]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment