Я думаю, что ваше основное замешательство состоит в том, что вы, похоже, не полностью понимаете, как обрабатываются макросы. Это полностью время компиляции. Когда ваш макрос работает, он имеет доступ к информации о скомпилированной программе, включая Symbol
. Затем макрос генерирует некоторый код, который станет частью вашей программы, но сам сгенерированный код не имеет доступа к Symbol
или что-либо еще, к которому имел доступ макрос.
Так MsonType.apply
в вашем примере не будет никакой пользы, потому что вход является Symbol
, который доступен в макрос только (во время компиляции), и выход является MsonSchema
, что вам нужно в время выполнения. Что бы иметь смысл, чтобы изменить тип возвращаемого из MsonType
в c.Expr[MsonType]
(или просто c.universe.Tree
), или другими словами MsonType.apply
бы сейчас взять символ и возвращает дерево, представляющее экземпляр MsonType
(в отличие от возвращения в MsonType
экземпляр), и ваш макрос может затем вызвать это и включить его в окончательное дерево, возвращаемое компилятору (который компилятор затем включит в вашу программу на сайте вызова). В этом конкретном случае, я думаю, что лучше всего удалить MsonType.apply
вообще и реализовать преобразование от Symbol
до c.universe.Tree
прямо в макросе writerImpl
.
Это преобразование на самом деле очень просто. Все, что вам нужно построить MsonType
это имя поля, а Class
экземпляр, так что вы идете:
q"""org.bibble.MsonType(${f.name.decoded}, classOf[${f.typeSignature}])"""
Для поля foo
типа Bar
это будет генерировать дерево, представляющее следующее выражение:
org.bibble.MsonType("foo", classOf[Bar])
Так оно и есть, мы должны идти.
Ниже вы найдете полную реализацию. Обратите внимание, что я взял на себя смелость изменить определение типов вашей схемы таким образом, что это намного логичнее и универсальнее для меня. И, в частности, каждое поле теперь имеет связанную с ним схему (учитывая ваш предыдущий вопрос, это явно то, что вы хотели в первую очередь).
scala> :paste
// Entering paste mode (ctrl-D to finish)
import scala.language.experimental.macros
import scala.reflect.macros._
case class MsonSchema(`type`: Class[_], fields: Seq[MsonField])
case class MsonField(name: String, schema: MsonSchema)
trait SchemaWriter[T] {
def schema: MsonSchema
}
object SchemaWriter {
def apply[T:SchemaWriter]: SchemaWriter[T] = implicitly
implicit def defaultWriter[T] = macro Macros.writerImpl[T]
}
object Macros {
def writerImpl[T: c.WeakTypeTag](c: Context): c.Expr[SchemaWriter[T]] = {
import c.universe._
c.Expr[SchemaWriter[T]](generateSchemaWriterTree(c)(weakTypeOf[T]))
}
private def generateSchemaWriterTree(c: Context)(T: c.universe.Type): c.universe.Tree = {
import c.universe._
val fields = T.declarations.collectFirst {
case m: MethodSymbol if m.isPrimaryConstructor => m
}.get.paramss.head
val MsonFieldSym = typeOf[MsonField].typeSymbol
val SchemaWriterSym = typeOf[SchemaWriter[_]].typeSymbol
val fieldTrees: Seq[Tree] = fields.map { f =>
q"""new $MsonFieldSym(
${f.name.decoded},
_root_.scala.Predef.implicitly[$SchemaWriterSym[${f.typeSignature}]].schema
)"""
}
c.resetLocalAttrs(q"""
new $SchemaWriterSym[$T] {
val schema = MsonSchema(classOf[$T], Seq(..$fieldTrees))
}
""")
}
}
// Exiting paste mode, now interpreting.
warning: there were 7 deprecation warnings; re-run with -deprecation for details
warning: there was one feature warning; re-run with -feature for details
import scala.language.experimental.macros
import scala.reflect.macros._
defined class MsonSchema
defined class MsonField
defined trait SchemaWriter
defined object SchemaWriter
defined object Macros
scala> case class Foo(ab: String, cd: Int)
defined class Foo
scala> SchemaWriter[Foo].schema
res0: MsonSchema = MsonSchema(class Foo,List(MsonField(ab,MsonSchema(class java.lang.String,List())), MsonField(cd,MsonSchema(int,List()))))
Практически невозможно помочь, не зная определения «Поле». В частности, что такое подпись конструктора «Поле». Вообще говоря, при размещении вопроса вы должны попытаться опубликовать [минимальный, полный и проверяемый пример] (http://stackoverflow.com/help/mcve). Да, я знаю, что вы не можете опубликовать пример компиляции, учитывая, что вы точно просите, как исправить ваш код, но, по крайней мере, предоставить все необходимые зависимости. –
Я уточню правильное определение схемы и поля – monkjack
Обновлено для конкретного типа схемы. Что касается этой схемы Mson, это не ключевой бит, но если я смогу получить то, что сейчас есть, чтобы скомпилировать, остальное должно быть легко. – monkjack