2013-06-17 4 views
3

J'ai besoin d'aide pour écrire une macro qui produit une correspondance de motif.Ecriture d'une macro de correspondance de motif

Ceci est aussi loin que je suis:

import scala.reflect.macros.Context 
import language.experimental.macros 

trait JsValue 

object SealedTraitFormat { 
    def writesImpl[A: c.WeakTypeTag](c: Context)(value: c.Expr[A]): c.Expr[JsValue] = { 
    val aTpeW = c.weakTypeOf[A] 
    val aClazz = aTpeW.typeSymbol.asClass 
    require(aClazz.isSealed, s"Type $aTpeW is not sealed") 
    val subs = aClazz.knownDirectSubclasses 
    require(subs.nonEmpty , s"Type $aTpeW does not have known direct subclasses") 
    import c.universe._ 

    val cases = subs.toList.map { sub => 
     val pat = Bind(newTermName("x"), Typed(Ident("_"), 
     c.reifyRuntimeClass(sub.asClass.toType))) 
     val body = Ident("???") // TODO 
     CaseDef(pat, body) 
    } 
    val m = Match(value.tree, cases) 
    c.Expr[JsValue](m) 
    } 
} 
trait SealedTraitFormat[A] { 
    def writes(value: A): JsValue = macro SealedTraitFormat.writesImpl[A] 
} 

est un exemple:

sealed trait Foo 
case class Bar() extends Foo 
case class Baz() extends Foo 

object FooFmt extends SealedTraitFormat[Foo] { 
    val test = writes(Bar()) 
} 

L'erreur actuelle est:

[warn] .../FooTest.scala:8: fruitless type test: a value of type play.api.libs.json.Bar cannot also be a Class[play.api.libs.json.Bar] 
[warn] val test = writes(Bar()) 
[warn]     ^
[error] .../FooTest.scala:8: pattern type is incompatible with expected type; 
[error] found : Class[play.api.libs.json.Bar](classOf[play.api.libs.json.Bar]) 
[error] required: play.api.libs.json.Bar 
[error] val test = writes(Bar()) 
[error]     ^

(notez que play.api.libs.json est mon paquet , donc c'est correct). Je ne sais pas quoi faire de cette erreur ...


La macro élargi devrait ressembler à ceci

def writes(value: Foo): JsValue = value match { 
    case x: Bar => ??? 
    case x: Baz => ??? 
} 

Il me semble, qu'il ressemble probablement case x: Class[Bar] => ??? maintenant. Donc je suppose que je dois utiliser reifyType au lieu de reifyRuntimeClass. Fondamentalement, comment puis-je obtenir l'arbre d'un Type?

Répondre

2

Ce qui suit semble fonctionner, ou au moins compilez:

val cases = subs.toList.map { sub => 
    val pat = Bind(newTermName("x"), Typed(Ident("_"), Ident(sub.asClass))) 
    val body = reify(???).tree // TODO 
    CaseDef(pat, body) 
} 
+0

Cela devrait fonctionner, oui. S'il vous plaît laissez-moi savoir si vous avez d'autres problèmes. –

Questions connexes