Reputation: 21557
I need to convert a string value into an actual type, so i decided to try a macro-way to do this. I have a bunch of data types:
sealed abstract class Tag(val name: String)
case object Case1 extends Tag("case1")
case object Case2 extends Tag("case2")
case object Case3 extends Tag("case3")
etc...
I want to write a simple resolver:
val tag: Tag = TagResolver.fromString("case2")
This line should return Case2
respectively. I manager to do the following:
def typeFromString(c: Context)(name: c.Expr[String]): c.Expr[Tag] = {
import c.universe._
val tag = typeTag[Tag]
val accSymb = tag.tpe.typeSymbol.asClass
val subclasses = accSymb.knownDirectSubclasses // all my cases
subclasses.map { sub =>
val name = sub.typeSignature.member(newTermName("name")).asMethod // name field
???
}
}
But how can i match name: c.Expr[String]
against value of name
field and if matched return the appropriate tag?
Upvotes: 4
Views: 308
Reputation: 13048
I don't think there's reliable way of doing this, because knownDirectSubclasses can refer to classes that haven't been compiled yet, so we can't evaluate them.
If you can put these values as annotations on the classes, then these annotations can be read even when classes are being compiled in the current compilation run (via the Symbol.annotations API). Please note, however, that knownDirectSubclasses has known issues: https://issues.scala-lang.org/browse/SI-7046.
Upvotes: 1