@@ -10,12 +10,17 @@ import reporting.Reporter
10
10
import transform .TreeChecker
11
11
import rewrite .Rewrites
12
12
import java .io .{BufferedWriter , OutputStreamWriter }
13
+
14
+ import scala .annotation .tailrec
13
15
import scala .reflect .io .VirtualFile
14
16
import scala .util .control .NonFatal
15
17
16
18
/** A compiler run. Exports various methods to compile source files */
17
19
class Run (comp : Compiler )(implicit ctx : Context ) {
18
20
21
+ private final val ANSI_DEFAULT = " \u001B [0m"
22
+ private final val ANSI_YELLOW = " \u001B [33m"
23
+
19
24
assert(comp.phases.last.last.id <= Periods .MaxPossiblePhaseId )
20
25
assert(ctx.runId <= Periods .MaxPossibleRunId )
21
26
@@ -56,26 +61,89 @@ class Run(comp: Compiler)(implicit ctx: Context) {
56
61
val phases = ctx.squashPhases(ctx.phasePlan,
57
62
ctx.settings.Yskip .value, ctx.settings.YstopBefore .value, ctx.settings.YstopAfter .value, ctx.settings.Ycheck .value)
58
63
ctx.usePhases(phases)
64
+ var lastPrintedTree : PrintedTree = NoPrintedTree
59
65
for (phase <- ctx.allPhases)
60
66
if (! ctx.reporter.hasErrors) {
61
67
val start = System .currentTimeMillis
62
68
units = phase.runOn(units)
63
- def foreachUnit (op : Context => Unit )(implicit ctx : Context ): Unit =
64
- for (unit <- units) op(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit))
65
- if (ctx.settings.Xprint .value.containsPhase(phase))
66
- foreachUnit(printTree)
69
+ if (ctx.settings.Xprint .value.containsPhase(phase)) {
70
+ for (unit <- units) {
71
+ lastPrintedTree =
72
+ printTree(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit), lastPrintedTree)
73
+ }
74
+ }
67
75
ctx.informTime(s " $phase " , start)
68
76
}
69
77
if (! ctx.reporter.hasErrors) Rewrites .writeBack()
70
78
}
71
79
72
- private def printTree (ctx : Context ) = {
80
+ private sealed trait PrintedTree
81
+ private final case class SomePrintedTree (phase : String , tree : String ) extends PrintedTree
82
+ private object NoPrintedTree extends PrintedTree
83
+
84
+ private def printTree (ctx : Context , last : PrintedTree ): PrintedTree = {
73
85
val unit = ctx.compilationUnit
74
86
val prevPhase = ctx.phase.prev // can be a mini-phase
75
87
val squashedPhase = ctx.squashed(prevPhase)
88
+ val treeString = unit.tpdTree.show(ctx)
89
+
90
+ ctx.echo(s " result of $unit after $squashedPhase: " )
91
+
92
+ last match {
93
+ case SomePrintedTree (phase, lastTreeSting) if lastTreeSting != treeString =>
94
+ ctx.echo(mkColoredDiffTree(treeString, lastTreeSting))
95
+ SomePrintedTree (squashedPhase.toString, treeString)
96
+
97
+ case SomePrintedTree (phase, lastTreeSting) =>
98
+ ctx.echo(" Unchanged since " + phase)
99
+ last
100
+
101
+ case NoPrintedTree =>
102
+ ctx.echo(treeString)
103
+ SomePrintedTree (squashedPhase.toString, treeString)
104
+ }
105
+ }
106
+
107
+ private def mkColoredDiffTree (treeString : String , lastTreeSting : String ): String = {
108
+ import difflib ._
109
+ import scala .collection .JavaConversions ._
110
+
111
+ @ tailrec def split (str : String , acc : List [String ]): List [String ] = {
112
+ if (str == " " ) {
113
+ acc.reverse
114
+ } else {
115
+ val head = str.charAt(0 )
116
+ val (token, rest) = if (Character .isAlphabetic(head) || Character .isDigit(head)) {
117
+ str.span(c => Character .isAlphabetic(c) || Character .isDigit(c))
118
+ } else if (Character .isMirrored(head) || Character .isWhitespace(head)) {
119
+ str.splitAt(1 )
120
+ } else {
121
+ str.span { c =>
122
+ ! Character .isAlphabetic(c) && ! Character .isDigit(c) &&
123
+ ! Character .isMirrored(c) && ! Character .isWhitespace(c)
124
+ }
125
+ }
126
+ split(rest, token :: acc)
127
+ }
128
+ }
129
+
130
+ val lines = split(treeString, Nil ).toArray
131
+
132
+ val diff = DiffUtils .diff(split(lastTreeSting, Nil ), lines.toList)
133
+ for (delta <- diff.getDeltas) {
134
+ val pos = delta.getRevised.getPosition
135
+ val endPos = pos + delta.getRevised.getLines.size - 1
136
+
137
+ delta.getType match {
138
+ case Delta .TYPE .CHANGE | Delta .TYPE .INSERT =>
139
+ lines(pos) = ANSI_YELLOW + lines(pos)
140
+ lines(endPos) = lines(endPos) + ANSI_DEFAULT
141
+
142
+ case Delta .TYPE .DELETE =>
143
+ }
144
+ }
76
145
77
- ctx.echo(s " result of $unit after ${squashedPhase}: " )
78
- ctx.echo(unit.tpdTree.show(ctx))
146
+ lines.mkString
79
147
}
80
148
81
149
def compile (sourceCode : String ): Unit = {
0 commit comments