typeprovider宏扩展期间的StackOverflow

时间:2017-11-11 15:23:42

标签: scala scala-macros type-providers

我正在玩一些宏,我认为写一个json类型的提供程序将是一个很好的开始,可以更深入地了解这一切是如何工作的,但我遇到了一个奇怪的错误,我似乎无法做到找出自己。如果您想查看整个内容,可以在GitHub上找到代码:https://github.com/qwe2/json-typeprovider/

有问题的部分是,我试图尽可能地将其作为类型安全,这意味着我想以这种方式实现json数组,索引到它们将返回正确的类型(作为后续的宏调用)。相关的代码方法:

json to Tree方法:

def jsonToTpe(value: JValue): Option[Tree] = value match {
  case JNothing => None
  case JNull => None
  case JString(s) => Some(q"$s")
  case JDouble(d) => Some(q"$d")
  case JDecimal(d) => Some(q"scala.BigDecimal(${d.toString})")
  case JInt(i) => Some(q"scala.BigInt(${i.toByteArray})")
  case JLong(l) => Some(q"$l")
  case JBool(b) => Some(q"$b")
  case JArray(arr) =>
    val arrTree = arr.flatMap(jsonToTpe)

    val clsName = c.freshName[TypeName](TypeName("harraycls"))
    val hArray =
      q"""
         class $clsName {
           @_root_.com.example.json.provider.body(scala.Array[Any](..$arrTree))
           def apply(i: Int): Any = macro _root_.com.example.json.provider.DelegatedMacros.arrApply_impl

           @_root_.com.example.json.provider.body(scala.Array[Any](..$arrTree))
           def toArray: scala.Array[Any] = macro _root_.com.example.json.provider.DelegatedMacros.selectField_impl
         }
         new $clsName {}
       """

    Some(hArray)
  case JSet(set) => Some(q"scala.Set(..${set.flatMap(jsonToTpe)})")
  case JObject(fields) =>
    val fs = fields.flatMap { case (k, v) =>
      jsonToTpe(v).map(v => q"""
        @_root_.com.example.json.provider.body($v) def ${TermName(k)}: Any =
          macro _root_.com.example.json.provider.DelegatedMacros.selectField_impl""")
    }

    val clsName = c.freshName[TypeName](TypeName("jsoncls"))
    Some(q"""
       class $clsName {
        ..$fs
       }
       new $clsName {}
     """)
}

阅读注释:

class body(tree: Any) extends StaticAnnotation

def arrApply_impl(c: whitebox.Context)(i: c.Expr[Int]): c.Tree = {
  import c.universe._

  def bail(msg: String): Nothing = {
    c.abort(c.enclosingPosition, msg)
  }

  def error(msg: String): Unit = {
    c.error(c.enclosingPosition, msg)
  }

  val arrValue = selectField_impl(c)
  val arrElems = arrValue match {
    case q"scala.Array.apply[$tpe](..$elems)($cls)" => elems
    case _ => bail("arr needs to be an array of constants")
  }
  val idx = i.tree match {
    case Literal(Constant(ix: Int)) => ix
    case _ => bail(s"i needs to be a constant Int, got ${showRaw(i.tree)}")
  }

  arrElems(idx)
}

def selectField_impl(c: whitebox.Context) : c.Tree = {
  c.macroApplication.symbol.annotations.filter(
    _.tree.tpe <:< c.typeOf[body]
  ).head.tree.children.tail.head
}

正如你可以看到我试图这样做的方式,基本上把实际的数组推到静态注释中,当索引它时,我会把它发送到另一个可以找出类型的宏。我从阅读有关vampire methods的内容中得到了这个想法。

这是我试图解析的json:

[
  {"id": 1},
  {"id": 2}
]

这就是我调用它的方式:

val tpe3 = TypeProvider("arrayofobj.json")
println(tpe3.toArray.mkString(", "))

读取一个int数组或一个原始字段的对象按预期工作,但是一个对象数组在编译期间抛出一个堆栈溢出:

[error] /home/isti/projects/json-typeprovider/core/src/main/scala/com/example/Hello.scala:7:14: Internal error: unable to find the outer accessor symbol of object Hello
[error] object Hello extends App {
[error]              ^
[error] ## Exception when compiling 1 sources to /home/isti/projects/json-typeprovider/core/target/scala-2.12/classes
[error] null
[error] java.lang.String.valueOf(String.java:2994)
[error] scala.collection.mutable.StringBuilder.append(StringBuilder.scala:200)
[error] scala.collection.TraversableOnce.$anonfun$addString$1(TraversableOnce.scala:359)
[error] scala.collection.immutable.List.foreach(List.scala:389)
[error] scala.collection.TraversableOnce.addString(TraversableOnce.scala:357)
[error] scala.collection.TraversableOnce.addString$(TraversableOnce.scala:353)
[error] scala.collection.AbstractTraversable.addString(Traversable.scala:104)
[error] scala.collection.TraversableOnce.mkString(TraversableOnce.scala:323)
[error] scala.collection.TraversableOnce.mkString$(TraversableOnce.scala:322)
[error] scala.collection.AbstractTraversable.mkString(Traversable.scala:104)
[error] scala.collection.TraversableOnce.mkString(TraversableOnce.scala:325)
[error] scala.collection.TraversableOnce.mkString$(TraversableOnce.scala:325)
[error] scala.collection.AbstractTraversable.mkString(Traversable.scala:104)
[error] scala.collection.TraversableOnce.mkString(TraversableOnce.scala:327)
[error] scala.collection.TraversableOnce.mkString$(TraversableOnce.scala:327)
[error] scala.collection.AbstractTraversable.mkString(Traversable.scala:104)
[error] xsbt.DelegatingReporter$.makePosition$1(DelegatingReporter.scala:89)
[error] xsbt.DelegatingReporter$.convert(DelegatingReporter.scala:94)
[error] xsbt.DelegatingReporter.info0(DelegatingReporter.scala:125)
[error] xsbt.DelegatingReporter.info0(DelegatingReporter.scala:102)
[error] scala.reflect.internal.Reporter.error(Reporting.scala:84)
[error] scala.reflect.internal.Reporting.globalError(Reporting.scala:69)
[error] scala.reflect.internal.Reporting.globalError$(Reporting.scala:69)
[error] scala.reflect.internal.SymbolTable.globalError(SymbolTable.scala:16)
[error] scala.tools.nsc.transform.ExplicitOuter$OuterPathTransformer.outerSelect(ExplicitOuter.scala:235)
[error] scala.tools.nsc.transform.ExplicitOuter$OuterPathTransformer.outerPath(ExplicitOuter.scala:267)
[error] scala.tools.nsc.transform.ExplicitOuter$OuterPathTransformer.outerPath(ExplicitOuter.scala:267)
[error] scala.tools.nsc.transform.ExplicitOuter$OuterPathTransformer.outerPath(ExplicitOuter.scala:267)
[error] scala.tools.nsc.transform.ExplicitOuter$OuterPathTransformer.outerPath(ExplicitOuter.scala:267)
[error] scala.tools.nsc.transform.ExplicitOuter$OuterPathTransformer.outerPath(ExplicitOuter.scala:267)
[error] scala.tools.nsc.transform.ExplicitOuter$OuterPathTransformer.outerPath(ExplicitOuter.scala:267)
[error] scala.tools.nsc.transform.ExplicitOuter$OuterPathTransformer.outerPath(ExplicitOuter.scala:267)
[error] scala.tools.nsc.transform.ExplicitOuter$OuterPathTransformer.outerPath(ExplicitOuter.scala:267)

编辑:这只是堆栈跟踪的顶部,还有更多的scala.tools.nsc.transform.ExplicitOuter$OuterPathTransformer.outerPath(ExplicitOuter.scala:267)

0 个答案:

没有答案