2222package fabric .rw
2323
2424import fabric .JsonWrapper
25- import fabric .define .DefType
25+ import fabric .define .{ Definition , DefType , Format }
2626
2727import scala .reflect .macros .blackbox
2828
2929object RWMacros {
30+ private def fullTypeName (context : blackbox.Context )(tpe : context.universe.Type ): String = {
31+ import context .universe ._
32+ val base = tpe.typeSymbol.fullName
33+ val args = tpe.typeArgs
34+ if (args.isEmpty) base
35+ else s " $base[ ${args.map(fullTypeName(context)(_)).mkString(" , " )}] "
36+ }
37+
38+ private def generateGenericTypes (context : blackbox.Context )(tpe : context.universe.Type ): List [context.universe.Tree ] = {
39+ import context .universe ._
40+ val typeArgs = tpe.typeArgs
41+ val typeParams = tpe.typeSymbol.asClass.typeParams
42+ if (typeArgs.isEmpty) Nil
43+ else typeParams.zip(typeArgs).map { case (param, arg) =>
44+ val name = param.name.decodedName.toString
45+ q " GenericType( $name, implicitly[RW[ $arg]].definition) "
46+ }
47+ }
48+
49+ private def extractFieldGenericNames (context : blackbox.Context )(tpe : context.universe.Type ): Map [String , String ] = {
50+ import context .universe ._
51+ val typeParams = tpe.typeSymbol.asClass.typeParams.map(_.name.decodedName.toString).toSet
52+ if (typeParams.isEmpty) Map .empty
53+ else {
54+ tpe.decls
55+ .collectFirst {
56+ case m : MethodSymbol if m.isPrimaryConstructor => m.paramLists.head
57+ }
58+ .getOrElse(Nil )
59+ .flatMap { field =>
60+ val fieldName = field.asTerm.name.decodedName.toString
61+ val fieldType = field.typeSignature
62+ findTypeParamName(context)(fieldType, typeParams).map(fieldName -> _)
63+ }
64+ .toMap
65+ }
66+ }
67+
68+ private def findTypeParamName (
69+ context : blackbox.Context
70+ )(tpe : context.universe.Type , typeParamNames : Set [String ]): Option [String ] = {
71+ val name = tpe.typeSymbol.name.decodedName.toString
72+ if (typeParamNames.contains(name)) Some (name)
73+ else tpe.typeArgs.flatMap(findTypeParamName(context)(_, typeParamNames)).headOption
74+ }
75+
76+ private def extractFieldFormats (
77+ context : blackbox.Context
78+ )(fields : List [context.universe.Symbol ]): Map [String , context.universe.Tree ] = {
79+ import context .universe ._
80+ fields.flatMap { field =>
81+ val key = field.asTerm.name.decodedName.toString
82+ field.annotations
83+ .collectFirst {
84+ case ann if ann.tree.tpe =:= typeOf[format] =>
85+ ann.tree.children.tail.headOption match {
86+ case Some (arg) => Some (key -> arg)
87+ case None => None
88+ }
89+ }
90+ .getOrElse(None )
91+ }.toMap
92+ }
93+
94+ private def extractDeprecatedFields (context : blackbox.Context )(fields : List [context.universe.Symbol ]): Set [String ] = {
95+ import context .universe ._
96+ fields.flatMap { field =>
97+ val isDeprecated = field.annotations.exists(_.tree.tpe =:= typeOf[fieldDeprecated])
98+ if (isDeprecated) Some (field.asTerm.name.decodedName.toString) else None
99+ }.toSet
100+ }
101+
102+ private def generateFieldDefaults (context : blackbox.Context )(
103+ fields : List [context.universe.Symbol ],
104+ defaults : Map [Int , context.universe.MethodSymbol ],
105+ companion : context.universe.Symbol ,
106+ tpe : context.universe.Type
107+ ): List [context.universe.Tree ] = {
108+ import context .universe ._
109+ fields.zipWithIndex.flatMap { case (field, index) =>
110+ defaults.get(index).map { m =>
111+ val key = field.asTerm.name.decodedName.toString
112+ val returnType = tpe.decl(field.asTerm.name).typeSignature.asSeenFrom(tpe, tpe.typeSymbol.asClass)
113+ q " $key -> implicitly[Reader[ $returnType]].read( $companion. $m) "
114+ }
115+ }
116+ }
117+
30118 def caseClassD [T ](
31119 context : blackbox.Context
32- )(implicit t : context.WeakTypeTag [T ]): context.Expr [DefType ] = {
120+ )(implicit t : context.WeakTypeTag [T ]): context.Expr [Definition ] = {
33121 import context .universe ._
34122
35123 val tpe = t.tpe
36- val className = tpe.typeSymbol.asClass.fullName
124+ val className = fullTypeName(context)( tpe)
37125 val companion : Symbol = tpe.typeSymbol.companion
38126 val defaults = defaultsFor(context)(companion)
39127 tpe.decls.collectFirst {
@@ -73,11 +161,32 @@ object RWMacros {
73161 q " $key -> implicitly[RW[ $returnType]].definition "
74162 }
75163 val allFieldDefs = fieldDefs ++ serializedDefs
76- context.Expr [DefType ](q """
164+ val genericTypes = generateGenericTypes(context)(tpe)
165+ val fieldGenericNames = extractFieldGenericNames(context)(tpe)
166+ val fieldGenericNamesEntries = fieldGenericNames.map { case (k, v) => q " $k -> $v" }.toList
167+ val fieldFormats = extractFieldFormats(context)(fields)
168+ val fieldFormatsEntries = fieldFormats.map { case (k, v) => q " $k -> $v" }.toList
169+ val deprecatedFields = extractDeprecatedFields(context)(fields)
170+ val deprecatedFieldsList = deprecatedFields.toList
171+ val fieldDefaultEntries = generateFieldDefaults(context)(fields, defaults, companion, tpe)
172+ context.Expr [Definition ](q """
77173 import _root_.fabric._
78174 import _root_.fabric.define._
175+ import _root_.scala.collection.immutable.VectorMap
79176
80- DefType.Obj(Some( $className), .. $allFieldDefs)
177+ Definition.applyFieldDefaults(
178+ Definition.applyFieldDeprecations(
179+ Definition.applyFieldFormats(
180+ Definition.applyGenericNames(
181+ Definition(DefType.Obj(VectorMap(.. $allFieldDefs)), className = Some( $className), genericTypes = List(.. $genericTypes)),
182+ Map(.. $fieldGenericNamesEntries)
183+ ),
184+ Map(.. $fieldFormatsEntries)
185+ ),
186+ Set(.. $deprecatedFieldsList)
187+ ),
188+ Map(.. $fieldDefaultEntries)
189+ )
81190 """ )
82191 case None =>
83192 val caseObjects = companion.typeSignature.members.collect {
@@ -87,8 +196,7 @@ object RWMacros {
87196 if (caseObjects.isEmpty) {
88197 context.abort(context.enclosingPosition, " Not a valid case class or sealed trait with case objects" )
89198 } else {
90- // Generate a DefType for an enumeration by delegating to RW.enumeration
91- context.Expr [DefType ](q """
199+ context.Expr [Definition ](q """
92200 import _root_.fabric._
93201 import _root_.fabric.define._
94202 import _root_.fabric.rw._
@@ -278,6 +386,7 @@ object RWMacros {
278386 val innerType = tpe.decl(name).typeSignature.asSeenFrom(tpe, tpe.typeSymbol.asClass)
279387 val companion = tpe.typeSymbol.companion
280388 val className = tpe.typeSymbol.fullName
389+ val genericTypes = generateGenericTypes(context)(tpe)
281390 return context.Expr [RW [T ]](q """
282391 import _root_.fabric._
283392 import _root_.fabric.rw._
@@ -287,7 +396,7 @@ object RWMacros {
287396 private val innerRW = implicitly[RW[ $innerType]]
288397 override def read(t: $tpe): Json = innerRW.read(t. $name)
289398 override def write(value: Json): $tpe = $companion(innerRW.write(value))
290- override val definition: DefType = innerRW.definition.withClassName( $className)
399+ override val definition: Definition = innerRW.definition.withClassName( $className).copy(genericTypes = List(.. $genericTypes ) )
291400 }
292401 """ )
293402 case _ => // fall through to normal path
@@ -308,7 +417,7 @@ object RWMacros {
308417
309418 override def read(t: $tpe): Json = r.read(t)
310419 override def write(value: Json): $tpe = w.write(value)
311- override def definition: DefType = $definition
420+ override def definition: Definition = $definition
312421 }
313422 """ )
314423 }
0 commit comments