1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
package cask.main
import cask.internal.Router.EntryPoint
import cask.model.ParamContext
import scala.reflect.macros.blackbox.Context
import language.experimental.macros
object Routes{
case class EndpointMetadata[T](decorators: Seq[BaseDecorator],
endpoint: Endpoint[_],
entryPoint: EntryPoint[T, ParamContext])
case class RoutesEndpointsMetadata[T](value: EndpointMetadata[T]*)
object RoutesEndpointsMetadata{
implicit def initialize[T] = macro initializeImpl[T]
implicit def initializeImpl[T: c.WeakTypeTag](c: Context): c.Expr[RoutesEndpointsMetadata[T]] = {
import c.universe._
val router = new cask.internal.Router[c.type](c)
val routeParts = for{
m <- c.weakTypeOf[T].members
val annotations = m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[BaseDecorator]).reverse
if annotations.nonEmpty
} yield {
if(!(annotations.head.tree.tpe <:< weakTypeOf[Endpoint[_]])) c.abort(
annotations.head.tree.pos,
s"Last annotation applied to a function must be an instance of Endpoint, " +
s"not ${annotations.head.tree.tpe}"
)
val allEndpoints = annotations.filter(_.tree.tpe <:< weakTypeOf[Endpoint[_]])
if(allEndpoints.length > 1) c.abort(
annotations.head.tree.pos,
s"You can only apply one Endpoint annotation to a function, not " +
s"${allEndpoints.length} in ${allEndpoints.map(_.tree.tpe).mkString(", ")}"
)
val annotObjects =
for(annot <- annotations)
yield q"new ${annot.tree.tpe}(..${annot.tree.children.tail})"
val annotObjectSyms =
for(_ <- annotations.indices)
yield c.universe.TermName(c.freshName("annotObject"))
val route = router.extractMethod(
m.asInstanceOf[MethodSymbol],
weakTypeOf[T],
(ctx: c.Tree, t: c.Tree) => q"${annotObjectSyms.head}.wrapMethodOutput($ctx, $t)",
c.weakTypeOf[ParamContext],
annotObjectSyms.map(annotObjectSym => q"$annotObjectSym.getParamParser"),
annotObjectSyms.map(annotObjectSym => tq"$annotObjectSym.Input")
)
val declarations =
for((sym, obj) <- annotObjectSyms.zip(annotObjects))
yield q"val $sym = $obj"
val res = q"""{
..$declarations
cask.main.Routes.EndpointMetadata(
Seq(..${annotObjectSyms.drop(1)}),
${annotObjectSyms.head},
$route
)
}"""
res
}
c.Expr[RoutesEndpointsMetadata[T]](q"""cask.main.Routes.RoutesEndpointsMetadata(..$routeParts)""")
}
}
}
trait Routes{
private[this] var metadata0: Routes.RoutesEndpointsMetadata[this.type] = null
def caskMetadata =
if (metadata0 != null) metadata0
else throw new Exception("Routes not yet initialize")
protected[this] def initialize()(implicit routes: Routes.RoutesEndpointsMetadata[this.type]): Unit = {
metadata0 = routes
}
}
|