简体   繁体   English

编写模式匹配宏

[英]Writing a pattern matching macro

I need some help writing a macro that produces a pattern match. 我需要一些帮助来编写一个产生模式匹配的宏。

This is as far as I got: 这是我得到的:

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]
}

Here is an example: 这是一个例子:

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

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

The current error is: 目前的错误是:

[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]                    ^

(note that play.api.libs.json is my package, so that's correct). (注意play.api.libs.json是我的包,所以这是正确的)。 I'm not sure what to make of this error... 我不知道该怎么做这个错误......


The expanded macro should look like this 扩展的宏应该如下所示

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

It appears to me, that it probably looks like case x: Class[Bar] => ??? 在我看来,它可能看起来像case x: Class[Bar] => ??? now. 现在。 So my guess is I need to use reifyType instead of reifyRuntimeClass . 所以我的猜测是我需要使用reifyType而不是reifyRuntimeClass Basically, how do I get the tree from a Type ? 基本上,我如何从Type获取树?

The following seems to work, or at least compile: 以下似乎工作,或至少编译:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM