1
/* NSC -- new Scala compiler
2
* Copyright 2005-2011 LAMP/EPFL
3
* @author Martin Odersky
6
package scala.tools.nsc
9
import java.io.{ OutputStream, PrintWriter, StringWriter, Writer }
11
import symtab.SymbolTable
13
trait TreePrinters { trees: SymbolTable =>
15
import treeInfo.{ IsTrue, IsFalse }
17
final val showOuterTests = false
19
/** Adds backticks if the name is a scala keyword. */
20
def quotedName(name: Name, decode: Boolean): String = {
21
val s = if (decode) name.decode else name.toString
22
val term = name.toTermName
23
if (nme.keywords(term) && term != nme.USCOREkw) "`%s`" format s
26
def quotedName(name: Name): String = quotedName(name, false)
28
/** Turns a path into a String, introducing backquotes
31
def backquotedPath(t: Tree): String = t match {
32
case Select(qual, name) => "%s.%s".format(backquotedPath(qual), quotedName(name))
33
case Ident(name) => quotedName(name)
37
class TreePrinter(out: PrintWriter) extends trees.AbsTreePrinter(out) {
38
protected var indentMargin = 0
39
protected val indentStep = 2
40
protected var indentString = " " // 40
42
def flush() = out.flush()
44
def indent() = indentMargin += indentStep
45
def undent() = indentMargin -= indentStep
47
protected def doPrintPositions = settings.Xprintpos.value
48
def printPosition(tree: Tree) = if (doPrintPositions) print(tree.pos.show)
52
while (indentMargin > indentString.length())
53
indentString += indentString
55
out.write(indentString, 0, indentMargin)
58
def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit) {
61
case List(x) => printelem(x)
62
case x :: rest => printelem(x); printsep; printSeq(rest)(printelem)(printsep)
66
def printColumn(ts: List[Tree], start: String, sep: String, end: String) {
67
print(start); indent; println()
68
printSeq(ts){print}{print(sep); println()}; undent; println(); print(end)
71
def printRow(ts: List[Tree], start: String, sep: String, end: String) {
72
print(start); printSeq(ts){print}{print(sep)}; print(end)
75
def printRow(ts: List[Tree], sep: String) { printRow(ts, "", sep, "") }
77
def printTypeParams(ts: List[TypeDef]) {
79
print("["); printSeq(ts){ t =>
82
}{print(", ")}; print("]")
86
def printValueParams(ts: List[ValDef]) {
88
if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, "")
89
printSeq(ts){printParam}{print(", ")}
93
def printParam(tree: Tree) {
95
case ValDef(mods, name, tp, rhs) =>
97
printAnnotations(tree)
98
print(symName(tree, name)); printOpt(": ", tp); printOpt(" = ", rhs)
99
case TypeDef(mods, name, tparams, rhs) =>
101
print(symName(tree, name))
102
printTypeParams(tparams); print(rhs)
106
def printBlock(tree: Tree) {
111
printColumn(List(tree), "{", ";", "}")
115
private def symFn[T](tree: Tree, f: Symbol => T, orElse: => T): T = tree.symbol match {
116
case null | NoSymbol => orElse
119
private def ifSym(tree: Tree, p: Symbol => Boolean) = symFn(tree, p, false)
121
private def symNameInternal(tree: Tree, name: Name, decoded: Boolean): String = {
122
def nameFn(sym: Symbol) = {
123
val prefix = if (sym.isMixinConstructor) "/*%s*/".format(quotedName(sym.owner.name, decoded)) else ""
124
prefix + tree.symbol.nameString
126
symFn(tree, nameFn, quotedName(name, decoded))
129
def decodedSymName(tree: Tree, name: Name) = symNameInternal(tree, name, true)
130
def symName(tree: Tree, name: Name) = symNameInternal(tree, name, false)
132
def printOpt(prefix: String, tree: Tree) {
133
if (!tree.isEmpty) { print(prefix); print(tree) }
136
def printModifiers(tree: Tree, mods: Modifiers): Unit = printFlags(
137
if (tree.symbol == NoSymbol) mods.flags else tree.symbol.flags, "" + (
138
if (tree.symbol == NoSymbol) mods.privateWithin
139
else if (tree.symbol.hasAccessBoundary) tree.symbol.privateWithin.name
144
def printFlags(flags: Long, privateWithin: String) {
145
var mask: Long = if (settings.debug.value) -1L else PrintableFlags
146
val s = flagsToString(flags & mask, privateWithin)
147
if (s != "") print(s + " ")
150
def printAnnotations(tree: Tree) {
152
if (tree.symbol.hasAssignedAnnotations) tree.symbol.annotations
153
else tree.asInstanceOf[MemberDef].mods.annotations
155
annots foreach (annot => print("@"+annot+" "))
158
def print(str: String) { out.print(str) }
159
def print(name: Name) { print(quotedName(name)) }
161
private var currentOwner: Symbol = NoSymbol
162
private var selectorType: Type = NoType
164
def printRaw(tree: Tree) {
169
case ClassDef(mods, name, tparams, impl) =>
170
printAnnotations(tree)
171
printModifiers(tree, mods)
173
if (mods.hasTraitFlag) "trait"
174
else if (ifSym(tree, _.isModuleClass)) "object"
177
print(word + " " + symName(tree, name))
178
printTypeParams(tparams)
179
print(if (mods.isDeferred) " <: " else " extends "); print(impl)
181
case PackageDef(packaged, stats) =>
182
printAnnotations(tree)
183
print("package "); print(packaged); printColumn(stats, " {", ";", "}")
185
case ModuleDef(mods, name, impl) =>
186
printAnnotations(tree)
187
printModifiers(tree, mods); print("object " + symName(tree, name))
188
print(" extends "); print(impl)
190
case ValDef(mods, name, tp, rhs) =>
191
printAnnotations(tree)
192
printModifiers(tree, mods)
193
print(if (mods.isMutable) "var " else "val ")
194
print(symName(tree, name))
196
if (!mods.isDeferred) {
198
if (rhs.isEmpty) print("_") else print(rhs)
201
case DefDef(mods, name, tparams, vparamss, tp, rhs) =>
202
printAnnotations(tree)
203
printModifiers(tree, mods)
204
print("def " + symName(tree, name))
205
printTypeParams(tparams); vparamss foreach printValueParams
206
printOpt(": ", tp); printOpt(" = ", rhs)
208
case TypeDef(mods, name, tparams, rhs) =>
209
if (mods hasFlag (PARAM | DEFERRED)) {
210
printAnnotations(tree)
211
printModifiers(tree, mods); print("type "); printParam(tree)
213
printAnnotations(tree)
214
printModifiers(tree, mods); print("type " + symName(tree, name))
215
printTypeParams(tparams); printOpt(" = ", rhs)
218
case LabelDef(name, params, rhs) =>
219
print(symName(tree, name)); printRow(params, "(", ",", ")"); printBlock(rhs)
221
case Import(expr, selectors) =>
222
// Is this selector remapping a name (i.e, {name1 => name2})
223
def isNotRemap(s: ImportSelector) : Boolean = (s.name == nme.WILDCARD || s.name == s.rename)
224
def selectorToString(s: ImportSelector): String = {
225
val from = quotedName(s.name)
226
if (isNotRemap(s)) from
227
else from + "=>" + quotedName(s.rename)
229
print("import "); print(backquotedPath(expr))
233
// If there is just one selector and it is not remapping a name, no braces are needed
235
print(selectorToString(s))
237
print("{"); print(selectorToString(s)); print("}")
239
// If there is more than one selector braces are always needed
241
print(many.map(selectorToString).mkString("{", ", ", "}"))
244
case DocDef(comment, definition) =>
245
print(comment.raw); println(); print(definition)
247
case Template(parents, self, body) =>
248
val currentOwner1 = currentOwner
249
if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner
250
printRow(parents, " with ")
252
if (self.name != nme.WILDCARD) {
253
print(" { "); print(self.name); printOpt(": ", self.tpt); print(" => ")
254
} else if (!self.tpt.isEmpty) {
255
print(" { _ : "); print(self.tpt); print(" => ")
259
printColumn(body, "", ";", "}")
261
currentOwner = currentOwner1
263
case Block(stats, expr) =>
264
printColumn(stats ::: List(expr), "{", ";", "}")
266
case Match(selector, cases) =>
267
val selectorType1 = selectorType
268
selectorType = selector.tpe
269
print(selector); printColumn(cases, " match {", "", "}")
270
selectorType = selectorType1
272
case CaseDef(pat, guard, body) =>
274
def patConstr(pat: Tree): Tree = pat match {
275
case Apply(fn, args) => patConstr(fn)
278
if (showOuterTests &&
280
patConstr(pat).tpe.finalResultType, selectorType, currentOwner))
282
print(pat); printOpt(" if ", guard)
283
print(" => "); print(body)
285
case Alternative(trees) =>
286
printRow(trees, "(", "| ", ")")
289
print("("); print(elem); print(")*")
291
case Bind(name, t) =>
292
print("("); print(symName(tree, name)); print(" @ "); print(t); print(")")
294
case UnApply(fun, args) =>
295
print(fun); print(" <unapply> "); printRow(args, "(", ", ", ")")
297
case ArrayValue(elemtpt, trees) =>
298
print("Array["); print(elemtpt); printRow(trees, "]{", ", ", "}")
300
case Function(vparams, body) =>
301
print("("); printValueParams(vparams); print(" => "); print(body); print(")")
302
if (settings.uniqid.value && tree.symbol != null) print("#"+tree.symbol.id)
304
case Assign(lhs, rhs) =>
305
print(lhs); print(" = "); print(rhs)
307
case AssignOrNamedArg(lhs, rhs) =>
308
print(lhs); print(" = "); print(rhs)
310
case If(cond, thenp, elsep) =>
311
print("if ("); print(cond); print(")"); indent; println()
313
if (!elsep.isEmpty) {
314
println(); print("else"); indent; println(); print(elsep); undent
318
print("return "); print(expr)
320
case Try(block, catches, finalizer) =>
321
print("try "); printBlock(block)
322
if (!catches.isEmpty) printColumn(catches, " catch {", "", "}")
323
printOpt(" finally ", finalizer)
326
print("throw "); print(expr)
329
print("new "); print(tpe)
331
case Typed(expr, tp) =>
332
print("("); print(expr); print(": "); print(tp); print(")")
334
case TypeApply(fun, targs) =>
335
print(fun); printRow(targs, "[", ", ", "]")
337
case Apply(fun, vargs) =>
338
print(fun); printRow(vargs, "(", ", ", ")")
340
case ApplyDynamic(qual, vargs) =>
341
print("<apply-dynamic>("); print(qual); print("#"); print(tree.symbol.nameString)
342
printRow(vargs, ", (", ", ", "))")
344
case Super(This(qual), mix) =>
345
if (!qual.isEmpty || tree.symbol != NoSymbol) print(symName(tree, qual) + ".")
348
print("[" + mix + "]")
350
case Super(qual, mix) =>
354
print("[" + mix + "]")
357
if (!qual.isEmpty) print(symName(tree, qual) + ".")
360
case Select(qual @ New(tpe), name) if (!settings.debug.value) =>
363
case Select(qualifier, name) =>
364
print(backquotedPath(qualifier)); print("."); print(symName(tree, name))
367
print(symName(tree, name))
370
print(x.escapedStringValue)
373
if ((tree.tpe eq null) || (settings.Xprintpos.value && tt.original != null)) {
374
if (tt.original != null) { print("<type: "); print(tt.original); print(">") }
375
else print("<type ?>")
376
} else if ((tree.tpe.typeSymbol ne null) && tree.tpe.typeSymbol.isAnonymousClass) {
377
print(tree.tpe.typeSymbol.toString())
379
print(tree.tpe.toString())
382
case Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) =>
384
print("@"); print(tpt)
386
printRow(args, "(", ",", ")")
388
if (tree.isType) { print(tree); print(" "); printAnnot() }
389
else { print(tree); print(": "); printAnnot() }
391
case SingletonTypeTree(ref) =>
392
print(ref); print(".type")
394
case SelectFromTypeTree(qualifier, selector) =>
395
print(qualifier); print("#"); print(symName(tree, selector))
397
case CompoundTypeTree(templ) =>
400
case AppliedTypeTree(tp, args) =>
401
print(tp); printRow(args, "[", ", ", "]")
403
case TypeBoundsTree(lo, hi) =>
404
printOpt(" >: ", lo); printOpt(" <: ", hi)
406
case ExistentialTypeTree(tpt, whereClauses) =>
408
printColumn(whereClauses, " forSome { ", ";", "}")
410
case SelectFromArray(qualifier, name, _) =>
411
print(qualifier); print(".<arr>"); print(symName(tree, name))
413
case TypeTreeWithDeferredRefCheck() =>
414
print("<tree with deferred refcheck>")
417
print("<unknown tree of class "+tree.getClass+">")
419
if (settings.printtypes.value && tree.isTerm && !tree.isEmpty) {
420
print("{"); print(if (tree.tpe eq null) "<null>" else tree.tpe.toString()); print("}")
424
def print(tree: Tree) {
427
if (tree.isDef && tree.symbol != NoSymbol && tree.symbol.isInitialized) {
429
case ClassDef(_, _, _, impl @ Template(ps, emptyValDef, body))
430
if (tree.symbol.thisSym != tree.symbol) =>
431
ClassDef(tree.symbol, Template(ps, ValDef(tree.symbol.thisSym), body))
432
case ClassDef(_, _, _, impl) => ClassDef(tree.symbol, impl)
433
case ModuleDef(_, _, impl) => ModuleDef(tree.symbol, impl)
434
case ValDef(_, _, _, rhs) => ValDef(tree.symbol, rhs)
435
case DefDef(_, _, _, vparamss, _, rhs) => DefDef(tree.symbol, vparamss, rhs)
436
case TypeDef(_, _, _, rhs) => TypeDef(tree.symbol, rhs)
442
def print(unit: CompilationUnit) {
443
print("// Scala source: " + unit.source + "\n")
444
if (unit.body == null) print("<null>")
445
else { print(unit.body); println() }
452
/** A tree printer which is stingier about vertical whitespace and unnecessary
453
* punctuation than the standard one.
455
class CompactTreePrinter(out: PrintWriter) extends TreePrinter(out) {
456
override def printRow(ts: List[Tree], start: String, sep: String, end: String) {
458
printSeq(ts)(print)(print(sep))
462
// drill down through Blocks and pull out the real statements.
463
def allStatements(t: Tree): List[Tree] = t match {
464
case Block(stmts, expr) => (stmts flatMap allStatements) ::: List(expr)
468
def printLogicalOr(t1: (Tree, Boolean), t2: (Tree, Boolean)) =
469
printLogicalOp(t1, t2, "||")
471
def printLogicalAnd(t1: (Tree, Boolean), t2: (Tree, Boolean)) =
472
printLogicalOp(t1, t2, "&&")
474
def printLogicalOp(t1: (Tree, Boolean), t2: (Tree, Boolean), op: String) = {
475
def maybenot(tvalue: Boolean) = if (tvalue) "" else "!"
477
print("%s(" format maybenot(t1._2))
479
print(") %s %s(".format(op, maybenot(t2._2)))
484
override def printRaw(tree: Tree): Unit = {
485
// routing supercalls through this for debugging ease
486
def s() = super.printRaw(tree)
489
// labels used for jumps - does not map to valid scala code
490
case LabelDef(name, params, rhs) =>
491
print("labeldef %s(%s) = ".format(name, params mkString ","))
495
print(decodedSymName(tree, name))
497
// target.method(arg) ==> target method arg
498
case Apply(Select(target, method), List(arg)) =>
499
if (method.decode.toString == "||")
500
printLogicalOr(target -> true, arg -> true)
501
else if (method.decode.toString == "&&")
502
printLogicalAnd(target -> true, arg -> true)
503
else (target, arg) match {
504
case (_: Ident, _: Literal | _: Ident) =>
507
printRaw(Ident(method))
513
// target.unary_! ==> !target
514
case Select(qualifier, name) if (name.decode startsWith "unary_") =>
515
print(name.decode drop 6)
518
case Select(qualifier, name) =>
521
print(quotedName(name, true))
523
// target.toString() ==> target.toString
524
case Apply(fn, Nil) => printRaw(fn)
526
// if a Block only continues one actual statement, just print it.
527
case Block(stats, expr) =>
528
allStatements(tree) match {
529
case List(x) => printRaw(x)
533
// We get a lot of this stuff
534
case If( IsTrue(), x, _) => printRaw(x)
535
case If(IsFalse(), _, x) => printRaw(x)
537
case If(cond, IsTrue(), elsep) => printLogicalOr(cond -> true, elsep -> true)
538
case If(cond, IsFalse(), elsep) => printLogicalAnd(cond -> false, elsep -> true)
539
case If(cond, thenp, IsTrue()) => printLogicalOr(cond -> false, thenp -> true)
540
case If(cond, thenp, IsFalse()) => printLogicalAnd(cond -> true, thenp -> true)
542
// If thenp or elsep has only one statement, it doesn't need more than one line.
543
case If(cond, thenp, elsep) =>
544
def ifIndented(x: Tree) = {
545
indent ; println() ; printRaw(x) ; undent
548
val List(thenStmts, elseStmts) = List(thenp, elsep) map allStatements
549
print("if ("); print(cond); print(") ")
552
case List(x: If) => ifIndented(x)
553
case List(x) => printRaw(x)
554
case _ => printRaw(thenp)
557
if (elseStmts.nonEmpty) {
561
case List(x) => printRaw(x)
562
case _ => printRaw(elsep)
571
/** This must guarantee not to force any evaluation, so we can learn
572
* a little bit about trees in the midst of compilation without altering
573
* the natural course of events.
575
class SafeTreePrinter(out: PrintWriter) extends TreePrinter(out) {
576
override def print(tree: Tree) {
580
private def default(t: Tree) = t.getClass.getName.reverse.takeWhile(_ != '.').reverse
581
private def params(trees: List[Tree]): String = trees map safe mkString ", "
583
private def safe(name: Name): String = name.decode
584
private def safe(tree: Tree): String = tree match {
585
case Apply(fn, args) => "%s(%s)".format(safe(fn), params(args))
586
case Select(qual, name) => safe(qual) + "." + safe(name)
587
case This(qual) => safe(qual) + ".this"
588
case Ident(name) => safe(name)
589
case Literal(value) => value.stringValue
590
case _ => "(?: %s)".format(default(tree))
593
override def printRaw(tree: Tree) { print(safe(tree)) }
596
class TreeMatchTemplate {
597
// non-trees defined in Trees
599
// case class ImportSelector(name: Name, namePos: Int, rename: Name, renamePos: Int)
600
// case class Modifiers(flags: Long, privateWithin: Name, annotations: List[Tree], positions: Map[Long, Position])
602
def apply(t: Tree): Unit = t match {
603
// eliminated by typer
604
case Annotated(annot, arg) =>
605
case AssignOrNamedArg(lhs, rhs) =>
606
case DocDef(comment, definition) =>
607
case Import(expr, selectors) =>
609
// eliminated by refchecks
610
case ModuleDef(mods, name, impl) =>
611
case TypeTreeWithDeferredRefCheck() =>
613
// eliminated by erasure
614
case TypeDef(mods, name, tparams, rhs) =>
615
case Typed(expr, tpt) =>
617
// eliminated by cleanup
618
case ApplyDynamic(qual, args) =>
620
// eliminated by explicitouter
621
case Alternative(trees) =>
622
case Bind(name, body) =>
623
case CaseDef(pat, guard, body) =>
625
case UnApply(fun, args) =>
627
// eliminated by lambdalift
628
case Function(vparams, body) =>
630
// eliminated by uncurry
631
case AppliedTypeTree(tpt, args) =>
632
case CompoundTypeTree(templ) =>
633
case ExistentialTypeTree(tpt, whereClauses) =>
634
case SelectFromTypeTree(qual, selector) =>
635
case SingletonTypeTree(ref) =>
636
case TypeBoundsTree(lo, hi) =>
639
case Apply(fun, args) =>
640
case ArrayValue(elemtpt, trees) =>
641
case Assign(lhs, rhs) =>
642
case Block(stats, expr) =>
643
case ClassDef(mods, name, tparams, impl) =>
644
case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
647
case If(cond, thenp, elsep) =>
648
case LabelDef(name, params, rhs) =>
649
case Literal(value) =>
650
case Match(selector, cases) =>
652
case PackageDef(pid, stats) =>
654
case Select(qualifier, selector) =>
655
case Super(qual, mix) =>
656
case Template(parents, self, body) =>
659
case Try(block, catches, finalizer) =>
660
case TypeApply(fun, args) =>
662
case ValDef(mods, name, tpt, rhs) =>
664
// missing from the Trees comment
665
case Parens(args) => // only used during parsing
666
case SelectFromArray(qual, name, erasure) => // only used during erasure
670
private def asStringInternal(t: Tree, f: PrintWriter => TreePrinter): String = {
671
val buffer = new StringWriter()
672
val printer = f(new PrintWriter(buffer))
677
def asString(t: Tree): String = asStringInternal(t, newStandardTreePrinter)
678
def asCompactString(t: Tree): String = asStringInternal(t, newCompactTreePrinter)
680
def newStandardTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer)
681
def newStandardTreePrinter(stream: OutputStream): TreePrinter = newStandardTreePrinter(new PrintWriter(stream))
682
def newStandardTreePrinter(): TreePrinter = newStandardTreePrinter(new PrintWriter(ConsoleWriter))
684
def newCompactTreePrinter(writer: PrintWriter): CompactTreePrinter = new CompactTreePrinter(writer)
685
def newCompactTreePrinter(stream: OutputStream): CompactTreePrinter = newCompactTreePrinter(new PrintWriter(stream))
686
def newCompactTreePrinter(): CompactTreePrinter = newCompactTreePrinter(new PrintWriter(ConsoleWriter))
688
def newTreePrinter(writer: PrintWriter): TreePrinter =
689
if (settings.Ycompacttrees.value) newCompactTreePrinter(writer)
690
else newStandardTreePrinter(writer)
691
def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream))
692
def newTreePrinter(): TreePrinter = newTreePrinter(new PrintWriter(ConsoleWriter))
694
/** A writer that writes to the current Console and
695
* is sensitive to replacement of the Console's
698
object ConsoleWriter extends Writer {
699
override def write(str: String) { Console.print(str) }
701
def write(cbuf: Array[Char], off: Int, len: Int) {
702
write(new String(cbuf, off, len))
705
def close = { /* do nothing */ }
706
def flush = { /* do nothing */ }