public
Created

Creating a Nat type from a compile-time literal

  • Download Gist
nat-example.scala
Scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
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
)
)
)
}
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.