Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

216 lines (178 sloc) 8.414 kb
/* NSC -- new Scala compiler
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
*/
package scala.tools.nsc
package ast
import java.io.{ OutputStream, PrintWriter, StringWriter, Writer }
trait Printers extends scala.reflect.internal.Printers { this: Global =>
import treeInfo.{ IsTrue, IsFalse }
class TreePrinter(out: PrintWriter) extends super.TreePrinter(out) {
override def print(args: Any*): Unit = args foreach {
case tree: Tree =>
printPosition(tree)
printTree(
if (tree.isDef && tree.symbol != NoSymbol && tree.symbol.isInitialized) {
tree match {
case ClassDef(_, _, _, impl @ Template(ps, emptyValDef, body))
if (tree.symbol.thisSym != tree.symbol) =>
ClassDef(tree.symbol, Template(ps, ValDef(tree.symbol.thisSym), body))
case ClassDef(_, _, _, impl) => ClassDef(tree.symbol, impl)
case ModuleDef(_, _, impl) => ModuleDef(tree.symbol, impl)
case ValDef(_, _, _, rhs) => ValDef(tree.symbol, rhs)
case DefDef(_, _, _, vparamss, _, rhs) => DefDef(tree.symbol, vparamss, rhs)
case TypeDef(_, _, _, rhs) => TypeDef(tree.symbol, rhs)
case _ => tree
}
} else tree)
case unit: CompilationUnit =>
print("// Scala source: " + unit.source + "\n")
if (unit.body == null) print("<null>")
else { print(unit.body); println() }
println()
out.flush()
case arg =>
super.print(arg)
}
}
// overflow cases missing from TreePrinter in reflect.api
override def xprintTree(treePrinter: super.TreePrinter, tree: Tree) = tree match {
case DocDef(comment, definition) =>
treePrinter.print(comment.raw)
treePrinter.println()
treePrinter.print(definition)
case TypeTreeWithDeferredRefCheck() =>
treePrinter.print("<tree with deferred refcheck>")
case SelectFromArray(qualifier, name, _) =>
treePrinter.print(qualifier, ".<arr>", symName(tree, name))
case _ =>
super.xprintTree(treePrinter, tree)
}
/** A tree printer which is stingier about vertical whitespace and unnecessary
* punctuation than the standard one.
*/
class CompactTreePrinter(out: PrintWriter) extends TreePrinter(out) {
override def printRow(ts: List[Tree], start: String, sep: String, end: String) {
print(start)
printSeq(ts)(print(_))(print(sep))
print(end)
}
// drill down through Blocks and pull out the real statements.
def allStatements(t: Tree): List[Tree] = t match {
case Block(stmts, expr) => (stmts flatMap allStatements) ::: List(expr)
case _ => List(t)
}
def printLogicalOr(t1: (Tree, Boolean), t2: (Tree, Boolean)) =
printLogicalOp(t1, t2, "||")
def printLogicalAnd(t1: (Tree, Boolean), t2: (Tree, Boolean)) =
printLogicalOp(t1, t2, "&&")
def printLogicalOp(t1: (Tree, Boolean), t2: (Tree, Boolean), op: String) = {
def maybenot(tvalue: Boolean) = if (tvalue) "" else "!"
print("%s(" format maybenot(t1._2))
printTree(t1._1)
print(") %s %s(".format(op, maybenot(t2._2)))
printTree(t2._1)
print(")")
}
override def printTree(tree: Tree): Unit = {
// routing supercalls through this for debugging ease
def s() = super.printTree(tree)
tree match {
// labels used for jumps - does not map to valid scala code
case LabelDef(name, params, rhs) =>
print("labeldef %s(%s) = ".format(name, params mkString ","))
printTree(rhs)
case Ident(name) =>
print(decodedSymName(tree, name))
// target.method(arg) ==> target method arg
case Apply(Select(target, method), List(arg)) =>
if (method.decode.toString == "||")
printLogicalOr(target -> true, arg -> true)
else if (method.decode.toString == "&&")
printLogicalAnd(target -> true, arg -> true)
else (target, arg) match {
case (_: Ident, _: Literal | _: Ident) =>
printTree(target)
print(" ")
printTree(Ident(method))
print(" ")
printTree(arg)
case _ => s()
}
// target.unary_! ==> !target
case Select(qualifier, name) if (name.decode startsWith "unary_") =>
print(name.decode drop 6)
printTree(qualifier)
case Select(qualifier, name) =>
printTree(qualifier)
print(".")
print(quotedName(name, true))
// target.toString() ==> target.toString
case Apply(fn, Nil) => printTree(fn)
// if a Block only continues one actual statement, just print it.
case Block(stats, expr) =>
allStatements(tree) match {
case List(x) => printTree(x)
case xs => s()
}
// We get a lot of this stuff
case If( IsTrue(), x, _) => printTree(x)
case If(IsFalse(), _, x) => printTree(x)
case If(cond, IsTrue(), elsep) => printLogicalOr(cond -> true, elsep -> true)
case If(cond, IsFalse(), elsep) => printLogicalAnd(cond -> false, elsep -> true)
case If(cond, thenp, IsTrue()) => printLogicalOr(cond -> false, thenp -> true)
case If(cond, thenp, IsFalse()) => printLogicalAnd(cond -> true, thenp -> true)
// If thenp or elsep has only one statement, it doesn't need more than one line.
case If(cond, thenp, elsep) =>
def ifIndented(x: Tree) = {
indent ; println() ; printTree(x) ; undent
}
val List(thenStmts, elseStmts) = List(thenp, elsep) map allStatements
print("if ("); print(cond); print(") ")
thenStmts match {
case List(x: If) => ifIndented(x)
case List(x) => printTree(x)
case _ => printTree(thenp)
}
if (elseStmts.nonEmpty) {
print(" else")
indent ; println()
elseStmts match {
case List(x) => printTree(x)
case _ => printTree(elsep)
}
undent ; println()
}
case _ => s()
}
}
}
/** This must guarantee not to force any evaluation, so we can learn
* a little bit about trees in the midst of compilation without altering
* the natural course of events.
*/
class SafeTreePrinter(out: PrintWriter) extends TreePrinter(out) {
private def default(t: Tree) = t.getClass.getName.reverse.takeWhile(_ != '.').reverse
private def params(trees: List[Tree]): String = trees map safe mkString ", "
private def safe(name: Name): String = name.decode
private def safe(tree: Tree): String = tree match {
case Apply(fn, args) => "%s(%s)".format(safe(fn), params(args))
case Select(qual, name) => safe(qual) + "." + safe(name)
case This(qual) => safe(qual) + ".this"
case Ident(name) => safe(name)
case Literal(value) => value.stringValue
case _ => "(?: %s)".format(default(tree))
}
override def printTree(tree: Tree) { print(safe(tree)) }
}
def asString(t: Tree): String = render(t, newStandardTreePrinter, settings.printtypes.value, settings.uniqid.value, settings.Yshowsymkinds.value)
def asCompactString(t: Tree): String = render(t, newCompactTreePrinter, settings.printtypes.value, settings.uniqid.value, settings.Yshowsymkinds.value)
def asCompactDebugString(t: Tree): String = render(t, newCompactTreePrinter, true, true, true)
def newStandardTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer)
def newCompactTreePrinter(writer: PrintWriter): CompactTreePrinter = new CompactTreePrinter(writer)
override def newTreePrinter(writer: PrintWriter): TreePrinter =
if (settings.Ycompacttrees.value) newCompactTreePrinter(writer)
else newStandardTreePrinter(writer)
override def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream))
override def newTreePrinter(): TreePrinter = newTreePrinter(new PrintWriter(ConsoleWriter))
}
Jump to Line
Something went wrong with that request. Please try again.