Unapply/patter matching with scala macros and quasiquotes for knownDirectSubclasses -
i'm trying create match statement using macros, matches subclasses of given type. have trouble extracting field values of case classes. example:
sealed abstract class foobar case class foo(x:int,f:foobar) extends foobar case class bar(s:string, f:foobar) extends foobar
now want create code looks this, when foobar given:
e1 match { case foo(args) => args.tostring case bar(args) => args.tostring }
thats got far:
def eqimpl[a: c.weaktypetag](c: context)(e1: c.expr[a], e2: c.expr[a]): c.expr[boolean] = { import c.universe._ val tpe = c.weaktypeof[a].typesymbol.asclass tpe.typesignature // si-7046 val subclasses = tpe.knowndirectsubclasses val cases = subclasses.map{ clazz => cq"x: $clazz => x " } println(cases) reify(true) }
this code match foo , bar, can not extract fields, need on right hand side.
so got working, here example:
def eqimpl[a: c.weaktypetag](c: context)(e1: c.expr[a], e2: c.expr[a]): c.expr[boolean] = { import c.universe._ val tpe = c.weaktypeof[a].typesymbol.asclass tpe.typesignature // si-7046 workaround val subclasses = tpe.knowndirectsubclasses val cases = subclasses.map{ case clazz : classsymbol => require (clazz.iscaseclass) val name = clazz.companionsymbol.name val fields = clazz.typesignature.declarations.collect { case m: methodsymbol if m.iscaseaccessor => m.name} //pattern fields of left , right side side val lfields = fields.map{ m => pq"""${m+"l":termname}"""} val rfields = fields.map{ m => pq"""${m+"r":termname}"""} side //right hand side of case statment val eqfields = fields.map{ m => q"""${m+"r":termname} == ${m+"l":termname}"""}.reduce[tree]{ case (acc,n) => q"$acc && $n"} cq"($name(..$lfields),$name(..$rfields)) => $eqfields " } val matchstmt = q"""tuple2[$tpe,$tpe]($e1,$e2) match { case ..$cases case _ => false }""" c.expr[boolean](matchstmt) } }
this code creates match statement, matches tuple. if both sides of tuple instances of same case class, fields compared. true returned, if fields equal. know not particularly realistic example, hope helps. example question generate:
tuple2[foobar,foobar](e1,e2) match { case (foo(xl,fl),foo(xr,fr) => xl == xr && fl == fr case (bar(sl,fl),bar(sr,fr) => sl == sr && fl == fr case _ => false }
Comments
Post a Comment