Last active
December 15, 2015 17:39
-
-
Save clhodapp/5297934 to your computer and use it in GitHub Desktop.
Most of the macros needed to create a single tuple class that could hold an arbitrary number of items and retain typesafety
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is an example usage | |
object Test extends App { | |
import Macros._ | |
println(countRefs[Int~Int~String~List[Int]~Double]) // prints 2 | |
println(countInts[Int~Int~String~List[Int]~Double]) // prints 2 | |
println(countDoubles[Int~Int~String~List[Int]~Double]) // prints 1 | |
println(whichArray[Int~Int~String~List[Int]~Double]("_0")) // prints Ints | |
println(whichArray[Int~Int~String~List[Int]~Double]("_2")) // prints References | |
println(whichArray[Int~Int~String~List[Int]~Double]("_4")) // prints Doubles | |
println(whichIndex[Int~Int~String~List[Int]~Double]("_0")) // prints 0 | |
println(whichIndex[Int~Int~String~List[Int]~Double]("_1")) // prints 1 | |
println(whichIndex[Int~Int~String~List[Int]~Double]("_2")) // prints 0 (started over b/c in references) | |
println(whichIndex[Int~String~Int]("_2")) // prints 1 | |
println(whichIndex[Int~Int~Int]("_2")) // prints 2 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import language.experimental.macros | |
import reflect.macros._ | |
sealed trait ~[+A, +B] | |
sealed trait Arrays | |
case object References extends Arrays | |
case object Units extends Arrays | |
case object Booleans extends Arrays | |
case object Bytes extends Arrays | |
case object Chars extends Arrays | |
case object Shorts extends Arrays | |
case object Ints extends Arrays | |
case object Longs extends Arrays | |
case object Floats extends Arrays | |
case object Doubles extends Arrays | |
object Macros { | |
def countRefsImpl[T: c.WeakTypeTag](c: Context): c.Expr[Int] = { | |
import c.universe._ | |
val primitiveValueTypes = Set( | |
typeOf[Unit], | |
typeOf[Boolean], | |
typeOf[Byte], | |
typeOf[Char], | |
typeOf[Short], | |
typeOf[Int], | |
typeOf[Long], | |
typeOf[Float], | |
typeOf[Double] | |
) | |
val tildeType = weakTypeOf[~[_, _]].typeConstructor | |
def isTildeType(tpe: Type) = tpe.erasure =:= tildeType.erasure | |
var current = weakTypeOf[T] | |
var count = 0 | |
while (isTildeType(current)) { | |
val TypeRef(_, _, List(first, second)) = current | |
if (!primitiveValueTypes.exists(_ =:= second)) count += 1 | |
current = first | |
} | |
if (!primitiveValueTypes.exists(_ =:= current)) count += 1 | |
c.Expr[Int](Literal(Constant(count))) | |
} | |
def countUnitsImpl[T: c.WeakTypeTag](c: Context): c.Expr[Int] = { | |
import c.universe._ | |
val tildeType = weakTypeOf[~[_, _]].typeConstructor | |
val unitType = typeOf[Double] | |
def isTildeType(tpe: Type) = tpe.erasure =:= tildeType.erasure | |
var current = weakTypeOf[T] | |
var count = 0 | |
while (isTildeType(current)) { | |
val TypeRef(_, _, List(first, second)) = current | |
if (second <:< unitType) count += 1 | |
current = first | |
} | |
if (current <:< unitType) count += 1 | |
c.Expr[Int](Literal(Constant(count))) | |
} | |
def countBooleansImpl[T: c.WeakTypeTag](c: Context): c.Expr[Int] = { | |
import c.universe._ | |
val tildeType = weakTypeOf[~[_, _]].typeConstructor | |
val booleanType = typeOf[Double] | |
def isTildeType(tpe: Type) = tpe.erasure =:= tildeType.erasure | |
var current = weakTypeOf[T] | |
var count = 0 | |
while (isTildeType(current)) { | |
val TypeRef(_, _, List(first, second)) = current | |
if (second <:< booleanType) count += 1 | |
current = first | |
} | |
if (current <:< booleanType) count += 1 | |
c.Expr[Int](Literal(Constant(count))) | |
} | |
def countBytesImpl[T: c.WeakTypeTag](c: Context): c.Expr[Int] = { | |
import c.universe._ | |
val tildeType = weakTypeOf[~[_, _]].typeConstructor | |
val byteType = typeOf[Byte] | |
def isTildeType(tpe: Type) = tpe.erasure =:= tildeType.erasure | |
var current = weakTypeOf[T] | |
var count = 0 | |
while (isTildeType(current)) { | |
val TypeRef(_, _, List(first, second)) = current | |
if (second <:< byteType) count += 1 | |
current = first | |
} | |
if (current <:< byteType) count += 1 | |
c.Expr[Int](Literal(Constant(count))) | |
} | |
def countCharsImpl[T: c.WeakTypeTag](c: Context): c.Expr[Int] = { | |
import c.universe._ | |
val tildeType = weakTypeOf[~[_, _]].typeConstructor | |
val charType = typeOf[Char] | |
def isTildeType(tpe: Type) = tpe.erasure =:= tildeType.erasure | |
var current = weakTypeOf[T] | |
var count = 0 | |
while (isTildeType(current)) { | |
val TypeRef(_, _, List(first, second)) = current | |
if (second <:< charType) count += 1 | |
current = first | |
} | |
if (current <:< charType) count += 1 | |
c.Expr[Int](Literal(Constant(count))) | |
} | |
def countShortsImpl[T: c.WeakTypeTag](c: Context): c.Expr[Int] = { | |
import c.universe._ | |
val tildeType = weakTypeOf[~[_, _]].typeConstructor | |
val shortType = typeOf[Short] | |
def isTildeType(tpe: Type) = tpe.erasure =:= tildeType.erasure | |
var current = weakTypeOf[T] | |
var count = 0 | |
while (isTildeType(current)) { | |
val TypeRef(_, _, List(first, second)) = current | |
if (second <:< shortType) count += 1 | |
current = first | |
} | |
if (current <:< shortType) count += 1 | |
c.Expr[Int](Literal(Constant(count))) | |
} | |
def countIntsImpl[T: c.WeakTypeTag](c: Context): c.Expr[Int] = { | |
import c.universe._ | |
val tildeType = weakTypeOf[~[_, _]].typeConstructor | |
val intType = typeOf[Int] | |
def isTildeType(tpe: Type) = tpe.erasure =:= tildeType.erasure | |
var current = weakTypeOf[T] | |
var count = 0 | |
while (isTildeType(current)) { | |
val TypeRef(_, _, List(first, second)) = current | |
if (second <:< intType) count += 1 | |
current = first | |
} | |
if (current <:< intType) count += 1 | |
c.Expr[Int](Literal(Constant(count))) | |
} | |
def countLongsImpl[T: c.WeakTypeTag](c: Context): c.Expr[Int] = { | |
import c.universe._ | |
val tildeType = weakTypeOf[~[_, _]].typeConstructor | |
val longType = typeOf[Double] | |
def isTildeType(tpe: Type) = tpe.erasure =:= tildeType.erasure | |
var current = weakTypeOf[T] | |
var count = 0 | |
while (isTildeType(current)) { | |
val TypeRef(_, _, List(first, second)) = current | |
if (second <:< longType) count += 1 | |
current = first | |
} | |
if (current <:< longType) count += 1 | |
c.Expr[Int](Literal(Constant(count))) | |
} | |
def countFloatsImpl[T: c.WeakTypeTag](c: Context): c.Expr[Int] = { | |
import c.universe._ | |
val tildeType = weakTypeOf[~[_, _]].typeConstructor | |
val floatType = typeOf[Float] | |
def isTildeType(tpe: Type) = tpe.erasure =:= tildeType.erasure | |
var current = weakTypeOf[T] | |
var count = 0 | |
while (isTildeType(current)) { | |
val TypeRef(_, _, List(first, second)) = current | |
if (second <:< floatType) count += 1 | |
current = first | |
} | |
if (current <:< floatType) count += 1 | |
c.Expr[Int](Literal(Constant(count))) | |
} | |
def countDoublesImpl[T: c.WeakTypeTag](c: Context): c.Expr[Int] = { | |
import c.universe._ | |
val tildeType = weakTypeOf[~[_, _]].typeConstructor | |
val doubleType = typeOf[Double] | |
def isTildeType(tpe: Type) = tpe.erasure =:= tildeType.erasure | |
var current = weakTypeOf[T] | |
var count = 0 | |
while (isTildeType(current)) { | |
val TypeRef(_, _, List(first, second)) = current | |
if (second <:< doubleType) count += 1 | |
current = first | |
} | |
if (current <:< doubleType) count += 1 | |
c.Expr[Int](Literal(Constant(count))) | |
} | |
def whichArrayImpl[T: c.WeakTypeTag](c: Context)(name: c.Expr[String]) = { | |
import c.universe._ | |
val Literal(Constant(value)) = name.tree | |
if (value.toString.head != '_') throw new IllegalArgumentException() | |
val index = value.toString.tail.toInt | |
val tildeType = weakTypeOf[~[_, _]].typeConstructor | |
def isTildeType(tpe: Type) = tpe.erasure =:= tildeType.erasure | |
def listify(tpe: Type, current: List[Type]): List[Type] = tpe match { | |
case TypeRef(_, _, List(first, second)) if isTildeType(tpe) => listify(first, second :: current) | |
case end => end :: current | |
} | |
val list = listify(weakTypeOf[T], Nil) | |
val chosen = list(index) | |
if (chosen =:= typeOf[Int]) reify{ Ints } | |
else if (chosen =:= typeOf[Unit]) reify { Units } | |
else if (chosen =:= typeOf[Boolean]) reify { Booleans } | |
else if (chosen =:= typeOf[Char]) reify { Chars } | |
else if (chosen =:= typeOf[Short]) reify { Shorts } | |
else if (chosen =:= typeOf[Long]) reify { Longs } | |
else if (chosen =:= typeOf[Float]) reify { Floats } | |
else if (chosen =:= typeOf[Double]) reify { Doubles } | |
else reify { References } | |
} | |
def whichIndexImpl[T: c.WeakTypeTag](c: Context)(name: c.Expr[String]): c.Expr[Int] = { | |
import c.universe._ | |
val Literal(Constant(value)) = name.tree | |
if (value.toString.head != '_') throw new IllegalArgumentException() | |
val index = value.toString.tail.toInt | |
val tildeType = weakTypeOf[~[_, _]].typeConstructor | |
def isTildeType(tpe: Type) = tpe.erasure =:= tildeType.erasure | |
def listify(tpe: Type, current: List[Type]): List[Type] = tpe match { | |
case TypeRef(_, _, List(first, second)) if isTildeType(tpe) => listify(first, second :: current) | |
case end => end :: current | |
} | |
val list = listify(weakTypeOf[T], Nil) | |
val chosen = list(index) | |
val primitiveValueTypes = Set( | |
typeOf[Unit], | |
typeOf[Boolean], | |
typeOf[Byte], | |
typeOf[Char], | |
typeOf[Short], | |
typeOf[Int], | |
typeOf[Long], | |
typeOf[Float], | |
typeOf[Double] | |
) | |
if (primitiveValueTypes.exists(_ =:= chosen)) c.Expr[Int](Literal(Constant(list.take(index).count(_ =:= chosen)))) | |
else c.Expr[Int](Literal(Constant(list.take(index).count(x => !primitiveValueTypes.exists(_ =:= x))))) | |
} | |
def countRefs[T] = macro countRefsImpl[T] | |
def countUnits[T] = macro countUnitsImpl[T] | |
def countBooleans[T] = macro countBooleansImpl[T] | |
def countChars[T] = macro countCharsImpl[T] | |
def countBytes[T] = macro countBytesImpl[T] | |
def countShorts[T] = macro countShortsImpl[T] | |
def countInts[T] = macro countIntsImpl[T] | |
def countLongs[T] = macro countLongsImpl[T] | |
def countFloats[T] = macro countFloatsImpl[T] | |
def countDoubles[T] = macro countDoublesImpl[T] | |
def whichArray[T](name: String) = macro whichArrayImpl[T] | |
def whichIndex[T](name: String) = macro whichIndexImpl[T] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment