I have following macro, which is constucting some Field class for given accessor of source class:
case class Field[S, F](name: String, lens: Lens[S, F])
class Fields[S] {
def field[D](property: S => D): Field[S, D] = macro FieldsMacro.impl[S, D]
}
class FieldsMacro(val c: whitebox.Context) {
import c.universe._
def impl[S: c.WeakTypeTag, D: c.WeakTypeTag](property: c.Expr[S => D]): c.Expr[Field[S, D]] = {
val sourceType = weakTypeOf[S]
val destinationType = weakTypeOf[D]
val field = sourceType.decls.collect {
case m: MethodSymbol if m.isCaseAccessor =>
val methodName = m.name.decodedName.toString
val q"($x) => $x2.$name" = property.tree
if (name.toString().equals(methodName)) {
Some(q"Field($methodName, Lens[${sourceType.typeSymbol}, ${destinationType.typeSymbol}]($property)(_ => x => x))")
} else None
}.filter(_.isDefined).map(_.get).head
val result =
q"""
//some imports
$field
"""
println(showCode(result))
c.Expr[Field[S, D]](result)
}
}
example of usage:
case class TestClass(i: Int, s: String, seq: Seq[Int])
object TestObject extends Fields[TestClass] {
val i = field[Int](_.i)
val seq = field[Seq[Int]](_.seq)
}
The problem is that weakTypeOf[D]
returns Seq
instead of desired Seq[Int]
. So i need to pass complex full types in macro like Map[String,Int]
or List[Option[SomeClass]]
, so i can substitute it in quasiquotes.
I just need to remove
.typeSymbol
call