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
|
import reflect.api.Modifier
import reflect.macro.Context
abstract class RangeDefault {
val from, to: Int
def foreach(f: Int => Unit) = {
var i = from
while (i < to) { f(i); i += 1 }
}
}
/** This class should go into reflect.macro once it is a bit more stable. */
abstract class Utils {
val context: Context
import context._
class TreeSubstituter(from: List[Symbol], to: List[Tree]) extends Transformer {
override def transform(tree: Tree): Tree = tree match {
case Ident(_) =>
def subst(from: List[Symbol], to: List[Tree]): Tree =
if (from.isEmpty) tree
else if (tree.symbol == from.head) to.head.duplicate // TODO: does it ever make sense *not* to perform a shallowDuplicate on `to.head`?
else subst(from.tail, to.tail);
subst(from, to)
case _ =>
val tree1 = super.transform(tree)
if (tree1 ne tree) tree1.tpe = null
tree1
}
}
def makeApply(fn: Tree, args: List[Tree]): Tree = fn match {
case Function(vparams, body) =>
new TreeSubstituter(vparams map (_.symbol), args) transform body
case Block(stats, expr) =>
Block(stats, makeApply(expr, args))
case _ =>
println("no beta on "+fn+" "+fn.getClass)
Apply(fn, args)
}
def makeWhile(lname: TermName, cond: Tree, body: Tree): Tree = {
val continu = Apply(Ident(lname), Nil)
val rhs = If(cond, Block(List(body), continu), Literal(Constant()))
LabelDef(lname, Nil, rhs)
}
def makeBinop(left: Tree, op: String, right: Tree): Tree =
Apply(Select(left, newTermName(op)), List(right))
}
class Range(val from: Int, val to: Int) extends RangeDefault {
override def macro foreach(f: Int => Unit): Unit = {
println("macro-expand, _this = "+ _this)
import _context._
object utils extends Utils {
val context: _context.type = _context
}
import utils._
val initName = newTermName("<init>")
// Either:
// scala"{ var i = $low; val h = $hi; while (i < h) { $f(i); i = i + 1 } }
// or:
// scala"($_this: RangeDefault).foreach($f)"
_this match {
case Apply(Select(New(tpt), initName), List(lo, hi)) if tpt.symbol.fullName == "Range" =>
val iname = newTermName("$i")
val hname = newTermName("$h")
def iref = Ident(iname)
def href = Ident(hname)
val labelname = newTermName("$while")
val cond = makeBinop(iref, "$less", href)
val body = Block(
List(makeApply(f, List(iref))),
Assign(iref, makeBinop(iref, "$plus", Literal(Constant(1)))))
tools.nsc.util.trace("generated: ")(
Block(
List(
ValDef(Modifiers(Set(Modifier.mutable)), iname, TypeTree(), lo),
ValDef(Modifiers(), hname, TypeTree(), hi)),
makeWhile(labelname, cond, body)))
case _ =>
Apply(
Select(
Typed(_this, Ident(newTypeName("RangeDefault"))),
newTermName("foreach")),
List(f))
}
}
}
object Test extends App {
new Range(1, 10) foreach println
}
|