/
RefineMacro.scala
94 lines (84 loc) · 2.87 KB
/
RefineMacro.scala
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
83
84
85
86
87
88
89
90
91
92
93
94
package eu.timepit.refined.macros
import eu.timepit.refined.api.{RefType, Validate}
import eu.timepit.refined.char.{Digit, Letter, LowerCase, UpperCase, Whitespace}
import eu.timepit.refined.collection.NonEmpty
import eu.timepit.refined.internal.Resources
import eu.timepit.refined.numeric.{Negative, NonNegative, NonPositive, Positive}
import macrocompat.bundle
import scala.reflect.macros.blackbox
@bundle
class RefineMacro(val c: blackbox.Context) extends MacroUtils with LiteralMatchers {
import c.universe._
def impl[F[_, _], T: c.WeakTypeTag, P: c.WeakTypeTag](t: c.Expr[T])(
rt: c.Expr[RefType[F]],
v: c.Expr[Validate[T, P]]
): c.Expr[F[T, P]] = {
val tValue: T = t.tree match {
case Literal(Constant(value)) => value.asInstanceOf[T]
case BigDecimalMatcher(value) => value.asInstanceOf[T]
case BigIntMatcher(value) => value.asInstanceOf[T]
case _ => abort(Resources.refineNonCompileTimeConstant)
}
val validate = validateInstance(v)
val res = validate.validate(tValue)
if (res.isFailed) {
abort(validate.showResult(tValue, res))
}
refTypeInstance(rt).unsafeWrapM(c)(t)
}
def implApplyRef[FTP, F[_, _], T: c.WeakTypeTag, P: c.WeakTypeTag](t: c.Expr[T])(
ev: c.Expr[F[T, P] =:= FTP],
rt: c.Expr[RefType[F]],
v: c.Expr[Validate[T, P]]
): c.Expr[FTP] =
c.Expr[FTP](impl(t)(rt, v).tree)
private def validateInstance[T, P](v: c.Expr[Validate[T, P]])(
implicit
T: c.WeakTypeTag[T],
P: c.WeakTypeTag[P]
): Validate[T, P] =
validateInstances
.collectFirst {
case (tpeT, instancesForT) if tpeT =:= T.tpe =>
instancesForT.collectFirst {
case (tpeP, validate) if tpeP =:= P.tpe =>
validate.asInstanceOf[Validate[T, P]]
}
}
.flatten
.getOrElse(eval(v))
private val validateInstances: List[(Type, List[(Type, Any)])] = {
def instance[T, P](implicit P: c.WeakTypeTag[P], v: Validate[T, P]): (Type, Validate[T, P]) =
P.tpe -> v
List(
weakTypeOf[Int] -> List(
instance[Int, Positive],
instance[Int, NonPositive],
instance[Int, Negative],
instance[Int, NonNegative]
),
weakTypeOf[Long] -> List(
instance[Long, Positive],
instance[Long, NonPositive],
instance[Long, Negative],
instance[Long, NonNegative]
),
weakTypeOf[Double] -> List(
instance[Double, Positive],
instance[Double, NonPositive],
instance[Double, Negative],
instance[Double, NonNegative]
),
weakTypeOf[String] -> List(
instance[String, NonEmpty]
),
weakTypeOf[Char] -> List(
instance[Char, Digit],
instance[Char, Letter],
instance[Char, LowerCase],
instance[Char, UpperCase],
instance[Char, Whitespace]
)
)
}
}