Skip to content

Instantly share code, notes, and snippets.

@travisbrown
Created January 7, 2013 12:26
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save travisbrown/4474632 to your computer and use it in GitHub Desktop.
Save travisbrown/4474632 to your computer and use it in GitHub Desktop.
Creating a Nat type from a compile-time literal
import scala.language.experimental.macros
import scala.reflect.macros.Context
import shapeless._
object NatExample {
def toNat(n: Int): Any = macro toNat_impl
def toNat_impl(c: Context)(n: c.Expr[Int]) = {
import c.universe._
val anon = newTypeName(c.fresh)
n.tree match {
case Literal(Constant(n: Int)) =>
val typeN = (0 until n).foldLeft(
Select(Select(Ident("shapeless"), "Nat"), newTypeName("_0")): Tree
) {
case (t, _) => AppliedTypeTree(
Select(Ident("shapeless"), newTypeName("Succ")), t :: Nil
)
}
c.Expr(
Block(
ClassDef(
Modifiers(Flag.FINAL),
anon,
Nil,
Template(
Ident(newTypeName("AnyRef")) :: Nil,
emptyValDef,
List(
constructor(c),
TypeDef(
Modifiers(),
newTypeName("N"),
Nil,
typeN
)
)
)
),
Apply(Select(New(Ident(anon)), nme.CONSTRUCTOR), List())
)
)
case _ => c.abort(
c.enclosingPosition,
"Argument must be a compile-time constant!"
)
}
}
def constructor(c: Context) = {
import c.universe._
DefDef(
Modifiers(),
nme.CONSTRUCTOR,
Nil,
Nil :: Nil,
TypeTree(),
Block(
Apply(
Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR),
Nil
)
)
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment