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
|
package forge
import scala.annotation.compileTimeOnly
import scala.language.experimental.macros
import scala.reflect.macros.blackbox._
final case class DefCtx(baseLabel: String, anonId: Option[Int]){
def label = baseLabel + anonId.getOrElse("")
}
object DefCtx{
@compileTimeOnly("A DefCtx can only be provided directly within a T{} macro")
implicit def dummy: DefCtx with Int = ???
}
object T{
def apply[T](expr: T): T = macro applyImpl[T]
def applyImpl[T: c.WeakTypeTag](c: Context)(expr: c.Expr[T]): c.Expr[T] = {
import c.universe._
var count = 0
object transformer extends c.universe.Transformer {
override def transform(tree: c.Tree): c.Tree = {
if (tree.toString.startsWith("forge.") && tree.toString.endsWith(".DefCtx.dummy")) {
count += 1
c.typecheck(q"forge.DefCtx(sourcecode.Enclosing(), Some($count))")
}else tree match{
case Apply(fun, args) =>
val extendedParams = fun.tpe.paramLists.head.padTo(
args.length,
fun.tpe.paramLists.head.lastOption.getOrElse(null)
)
val newArgs =
for((sym, tree) <- extendedParams.zip(args))
yield {
if (sym.asTerm.isByNameParam) tree
else transform(tree)
}
treeCopy.Apply(tree, transform(fun), newArgs)
case t: DefDef => t
case t: ClassDef => t
case t: Function => t
case t: LabelDef => t
case t => super.transform(t)
}
}
}
def transformTerminal(tree: c.Tree): c.Tree = tree match{
case Block(stats, returnExpr) =>
treeCopy.Block(
tree,
stats.map(transformer.transform(_)),
transformTerminal(returnExpr)
)
case Apply(fun, args) =>
var isTransformed = false
val newArgs = for(x <- args) yield {
if (x.toString.startsWith("forge.") && x.toString.endsWith(".DefCtx.dummy")) {
isTransformed = true
c.typecheck(q"forge.DefCtx(sourcecode.Enclosing(), None)")
}else transformer.transform(x)
}
assert(isTransformed)
treeCopy.Apply(tree, transformer.transform(fun), newArgs)
case _ => ???
}
val transformed = transformTerminal(expr.tree)
c.Expr[T](transformed)
}
}
|