Last active
July 4, 2016 11:45
-
-
Save dgouyette/e5867d2411fe01459d9dbbc6e076841f to your computer and use it in GitHub Desktop.
This file contains hidden or 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 scala.reflect.macros.blackbox | |
import scala.language.experimental.macros | |
import scala.annotation.StaticAnnotation | |
object union { | |
def impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { | |
import c.universe._ | |
def argByXY(idx: Int, i: Int) = if (idx == i) { | |
q"""Some(t)""" | |
} | |
else { | |
q"""None""" | |
} | |
val result = { | |
annottees.map(_.tree).toList match { | |
case q"class $name[..$tpes](..$lFields) extends ..$parents { ..$body }" :: Nil => | |
val typesName: Seq[c.universe.TypeName] = tpes.map { case TypeDef(_, typeName, _, _) => typeName } | |
q""" | |
class $name[..$tpes](..$lFields) extends ..$parents { | |
..$body | |
..${ | |
typesName.zipWithIndex.map { case (currentTypeName, y) => | |
val currentType2Union = TermName("toUnion" + y) | |
val unionTermName = TermName("Union" + tpes.size) | |
val constructorArgs = for (x <- typesName.indices) yield q"""${argByXY(x, y)}""" | |
q""" | |
implicit def $currentType2Union(t: $currentTypeName) = $unionTermName[..$typesName](..$constructorArgs); | |
""" | |
} | |
} | |
} | |
""" | |
} | |
} | |
println(result) | |
c.Expr[Any](result) | |
} | |
} | |
class union extends StaticAnnotation { | |
def macroTransform(annottees: Any*) = macro union.impl | |
} | |
//will generate the following code | |
/** | |
* class Union2Type[T1, T2] extends scala.AnyRef { | |
def <init>() = { | |
super.<init>(); | |
() | |
}; | |
implicit def toUnion0(t: T1) = Union2[T1, T2](Some(t), None); | |
implicit def toUnion1(t: T2) = Union2[T1, T2](None, Some(t)) | |
} | |
class Union3Type[T1, T2, T3] extends scala.AnyRef { | |
def <init>() = { | |
super.<init>(); | |
() | |
}; | |
implicit def toUnion0(t: T1) = Union3[T1, T2, T3](Some(t), None, None); | |
implicit def toUnion1(t: T2) = Union3[T1, T2, T3](None, Some(t), None); | |
implicit def toUnion2(t: T3) = Union3[T1, T2, T3](None, None, Some(t)) | |
} | |
class Union4Type[T1, T2, T3, T4] extends scala.AnyRef { | |
def <init>() = { | |
super.<init>(); | |
() | |
}; | |
implicit def toUnion0(t: T1) = Union4[T1, T2, T3, T4](Some(t), None, None, None); | |
implicit def toUnion1(t: T2) = Union4[T1, T2, T3, T4](None, Some(t), None, None); | |
implicit def toUnion2(t: T3) = Union4[T1, T2, T3, T4](None, None, Some(t), None); | |
implicit def toUnion3(t: T4) = Union4[T1, T2, T3, T4](None, None, None, Some(t)) | |
}**/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I wonder if it would be possible to get unions without "wasting" memory like the solution proposed here.
Where can I find an example of usage of these generated UnionX types ?