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

692 lines (593 sloc) 24.467 kb
/* NSC -- new Scala compiler
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
*/
// todo. we need to unify this prettyprinter with NodePrinters
package scala.reflect
package internal
import java.io.{ OutputStream, PrintWriter, StringWriter, Writer }
import Flags._
import scala.compat.Platform.EOL
trait Printers extends api.Printers { self: SymbolTable =>
//nsc import treeInfo.{ IsTrue, IsFalse }
final val showOuterTests = false
/** Adds backticks if the name is a scala keyword. */
def quotedName(name: Name, decode: Boolean): String = {
val s = if (decode) name.decode else name.toString
val term = name.toTermName
if (nme.keywords(term) && term != nme.USCOREkw) "`%s`" format s
else s
}
def quotedName(name: Name): String = quotedName(name, false)
def quotedName(name: String): String = quotedName(newTermName(name), false)
private def symNameInternal(tree: Tree, name: Name, decoded: Boolean): String = {
val sym = tree.symbol
if (sym.name.toString == nme.ERROR.toString) {
"<" + quotedName(name, decoded) + ": error>"
} else if (sym != null && sym != NoSymbol) {
val prefix = if (sym.isMixinConstructor) "/*%s*/".format(quotedName(sym.owner.name, decoded)) else ""
var suffix = ""
if (settings.uniqid.value) suffix += ("#" + sym.id)
if (settings.Yshowsymkinds.value) suffix += ("#" + sym.abbreviatedKindString)
prefix + quotedName(tree.symbol.decodedName) + suffix
} else {
quotedName(name, decoded)
}
}
def decodedSymName(tree: Tree, name: Name) = symNameInternal(tree, name, true)
def symName(tree: Tree, name: Name) = symNameInternal(tree, name, false)
/** Turns a path into a String, introducing backquotes
* as necessary.
*/
def backquotedPath(t: Tree): String = {
t match {
case Select(qual, name) if name.isTermName => "%s.%s".format(backquotedPath(qual), symName(t, name))
case Select(qual, name) if name.isTypeName => "%s#%s".format(backquotedPath(qual), symName(t, name))
case Ident(name) => symName(t, name)
case _ => t.toString
}
}
class TreePrinter(out: PrintWriter) extends super.TreePrinter {
protected var indentMargin = 0
protected val indentStep = 2
protected var indentString = " " // 40
printTypes = settings.printtypes.value
printIds = settings.uniqid.value
printKinds = settings.Yshowsymkinds.value
printMirrors = false // typically there's no point to print mirrors inside the compiler, as there is only one mirror there
protected def doPrintPositions = settings.Xprintpos.value
def indent() = indentMargin += indentStep
def undent() = indentMargin -= indentStep
def printPosition(tree: Tree) = if (doPrintPositions) print(tree.pos.show)
def println() {
out.println()
while (indentMargin > indentString.length())
indentString += indentString
if (indentMargin > 0)
out.write(indentString, 0, indentMargin)
}
def printSeq[a](ls: List[a])(printelem: a => Unit)(printsep: => Unit) {
ls match {
case List() =>
case List(x) => printelem(x)
case x :: rest => printelem(x); printsep; printSeq(rest)(printelem)(printsep)
}
}
def printColumn(ts: List[Tree], start: String, sep: String, end: String) {
print(start); indent; println()
printSeq(ts){print(_)}{print(sep); println()}; undent; println(); print(end)
}
def printRow(ts: List[Tree], start: String, sep: String, end: String) {
print(start); printSeq(ts){print(_)}{print(sep)}; print(end)
}
def printRow(ts: List[Tree], sep: String) { printRow(ts, "", sep, "") }
def printTypeParams(ts: List[TypeDef]) {
if (!ts.isEmpty) {
print("["); printSeq(ts){ t =>
printAnnotations(t)
printParam(t)
}{print(", ")}; print("]")
}
}
def printLabelParams(ps: List[Ident]) {
print("(")
printSeq(ps){printLabelParam}{print(", ")}
print(")")
}
def printLabelParam(p: Ident) {
print(symName(p, p.name)); printOpt(": ", TypeTree() setType p.tpe)
}
def printValueParams(ts: List[ValDef]) {
print("(")
if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, "")
printSeq(ts){printParam}{print(", ")}
print(")")
}
def printParam(tree: Tree) {
tree match {
case ValDef(mods, name, tp, rhs) =>
printPosition(tree)
printAnnotations(tree)
print(symName(tree, name)); printOpt(": ", tp); printOpt(" = ", rhs)
case TypeDef(mods, name, tparams, rhs) =>
printPosition(tree)
print(symName(tree, name))
printTypeParams(tparams); print(rhs)
}
}
def printBlock(tree: Tree) {
tree match {
case Block(_, _) =>
print(tree)
case _ =>
printColumn(List(tree), "{", ";", "}")
}
}
private def symFn[T](tree: Tree, f: Symbol => T, orElse: => T): T = tree.symbol match {
case null | NoSymbol => orElse
case sym => f(sym)
}
private def ifSym(tree: Tree, p: Symbol => Boolean) = symFn(tree, p, false)
def printOpt(prefix: String, tree: Tree) {
if (!tree.isEmpty) { print(prefix, tree) }
}
def printModifiers(tree: Tree, mods: Modifiers): Unit = printFlags(
if (tree.symbol == NoSymbol) mods.flags else tree.symbol.flags, "" + (
if (tree.symbol == NoSymbol) mods.privateWithin
else if (tree.symbol.hasAccessBoundary) tree.symbol.privateWithin.name
else ""
)
)
def printFlags(flags: Long, privateWithin: String) {
var mask: Long = if (settings.debug.value) -1L else PrintableFlags
val s = flagsToString(flags & mask, privateWithin)
if (s != "") print(s + " ")
}
def printAnnotations(tree: Tree) {
// SI-5885: by default this won't print annotations of not yet initialized symbols
val annots = tree.symbol.annotations match {
case Nil => tree.asInstanceOf[MemberDef].mods.annotations
case anns => anns
}
annots foreach (annot => print("@"+annot+" "))
}
private var currentOwner: Symbol = NoSymbol
private var selectorType: Type = NoType
def printTree(tree: Tree) {
tree match {
case EmptyTree =>
print("<empty>")
case ClassDef(mods, name, tparams, impl) =>
printAnnotations(tree)
printModifiers(tree, mods)
val word =
if (mods.isTrait) "trait"
else if (ifSym(tree, _.isModuleClass)) "object"
else "class"
print(word, " ", symName(tree, name))
printTypeParams(tparams)
print(if (mods.isDeferred) " <: " else " extends ", impl)
case PackageDef(packaged, stats) =>
printAnnotations(tree)
print("package ", packaged); printColumn(stats, " {", ";", "}")
case ModuleDef(mods, name, impl) =>
printAnnotations(tree)
printModifiers(tree, mods);
print("object " + symName(tree, name), " extends ", impl)
case ValDef(mods, name, tp, rhs) =>
printAnnotations(tree)
printModifiers(tree, mods)
print(if (mods.isMutable) "var " else "val ", symName(tree, name))
printOpt(": ", tp)
if (!mods.isDeferred)
print(" = ", if (rhs.isEmpty) "_" else rhs)
case DefDef(mods, name, tparams, vparamss, tp, rhs) =>
printAnnotations(tree)
printModifiers(tree, mods)
print("def " + symName(tree, name))
printTypeParams(tparams); vparamss foreach printValueParams
printOpt(": ", tp); printOpt(" = ", rhs)
case TypeDef(mods, name, tparams, rhs) =>
if (mods hasFlag (PARAM | DEFERRED)) {
printAnnotations(tree)
printModifiers(tree, mods); print("type "); printParam(tree)
} else {
printAnnotations(tree)
printModifiers(tree, mods); print("type " + symName(tree, name))
printTypeParams(tparams); printOpt(" = ", rhs)
}
case LabelDef(name, params, rhs) =>
print(symName(tree, name)); printLabelParams(params); printBlock(rhs)
case Import(expr, selectors) =>
// Is this selector remapping a name (i.e, {name1 => name2})
def isNotRemap(s: ImportSelector) : Boolean = (s.name == nme.WILDCARD || s.name == s.rename)
def selectorToString(s: ImportSelector): String = {
val from = quotedName(s.name)
if (isNotRemap(s)) from
else from + "=>" + quotedName(s.rename)
}
print("import ", backquotedPath(expr), ".")
selectors match {
case List(s) =>
// If there is just one selector and it is not remapping a name, no braces are needed
if (isNotRemap(s)) print(selectorToString(s))
else print("{", selectorToString(s), "}")
// If there is more than one selector braces are always needed
case many =>
print(many.map(selectorToString).mkString("{", ", ", "}"))
}
case Template(parents, self, body) =>
val currentOwner1 = currentOwner
if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner
// if (parents exists isReferenceToAnyVal) {
// print("AnyVal")
// }
// else {
printRow(parents, " with ")
if (!body.isEmpty) {
if (self.name != nme.WILDCARD) {
print(" { ", self.name); printOpt(": ", self.tpt); print(" => ")
} else if (!self.tpt.isEmpty) {
print(" { _ : ", self.tpt, " => ")
} else {
print(" {")
}
printColumn(body, "", ";", "}")
}
// }
currentOwner = currentOwner1
case Block(stats, expr) =>
printColumn(stats ::: List(expr), "{", ";", "}")
case Match(selector, cases) =>
val selectorType1 = selectorType
selectorType = selector.tpe
print(selector); printColumn(cases, " match {", "", "}")
selectorType = selectorType1
case CaseDef(pat, guard, body) =>
print("case ")
def patConstr(pat: Tree): Tree = pat match {
case Apply(fn, args) => patConstr(fn)
case _ => pat
}
if (showOuterTests &&
needsOuterTest(
patConstr(pat).tpe.finalResultType, selectorType, currentOwner))
print("???")
print(pat); printOpt(" if ", guard)
print(" => ", body)
case Alternative(trees) =>
printRow(trees, "(", "| ", ")")
case Star(elem) =>
print("(", elem, ")*")
case Bind(name, t) =>
print("(", symName(tree, name), " @ ", t, ")")
case UnApply(fun, args) =>
print(fun, " <unapply> "); printRow(args, "(", ", ", ")")
case ArrayValue(elemtpt, trees) =>
print("Array[", elemtpt); printRow(trees, "]{", ", ", "}")
case Function(vparams, body) =>
print("("); printValueParams(vparams); print(" => ", body, ")")
if (printIds && tree.symbol != null) print("#"+tree.symbol.id)
case Assign(lhs, rhs) =>
print(lhs, " = ", rhs)
case AssignOrNamedArg(lhs, rhs) =>
print(lhs, " = ", rhs)
case If(cond, thenp, elsep) =>
print("if (", cond, ")"); indent; println()
print(thenp); undent
if (!elsep.isEmpty) {
println(); print("else"); indent; println(); print(elsep); undent
}
case Return(expr) =>
print("return ", expr)
case Try(block, catches, finalizer) =>
print("try "); printBlock(block)
if (!catches.isEmpty) printColumn(catches, " catch {", "", "}")
printOpt(" finally ", finalizer)
case Throw(expr) =>
print("throw ", expr)
case New(tpe) =>
print("new ", tpe)
case Typed(expr, tp) =>
print("(", expr, ": ", tp, ")")
case TypeApply(fun, targs) =>
print(fun); printRow(targs, "[", ", ", "]")
case Apply(fun, vargs) =>
print(fun); printRow(vargs, "(", ", ", ")")
case ApplyDynamic(qual, vargs) =>
print("<apply-dynamic>(", qual, "#", tree.symbol.nameString)
printRow(vargs, ", (", ", ", "))")
case Super(This(qual), mix) =>
if (!qual.isEmpty || tree.symbol != NoSymbol) print(symName(tree, qual) + ".")
print("super")
if (!mix.isEmpty)
print("[" + mix + "]")
case Super(qual, mix) =>
print(qual, ".super")
if (!mix.isEmpty)
print("[" + mix + "]")
case This(qual) =>
if (!qual.isEmpty) print(symName(tree, qual) + ".")
print("this")
case Select(qual @ New(tpe), name) if (!settings.debug.value) =>
print(qual)
case Select(qualifier, name) =>
print(backquotedPath(qualifier), ".", symName(tree, name))
case id @ Ident(name) =>
val str = symName(tree, name)
print( if (id.isBackquoted) "`" + str + "`" else str )
case Literal(x) =>
print(x.escapedStringValue)
case tt: TypeTree =>
if ((tree.tpe eq null) || (doPrintPositions && tt.original != null)) {
if (tt.original != null) print("<type: ", tt.original, ">")
else print("<type ?>")
} else if ((tree.tpe.typeSymbol ne null) && tree.tpe.typeSymbol.isAnonymousClass) {
print(tree.tpe.typeSymbol.toString)
} else {
print(tree.tpe.toString)
}
case Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) =>
def printAnnot() {
print("@", tpt)
if (!args.isEmpty)
printRow(args, "(", ",", ")")
}
print(tree, if (tree.isType) " " else ": ")
printAnnot()
case SingletonTypeTree(ref) =>
print(ref, ".type")
case SelectFromTypeTree(qualifier, selector) =>
print(qualifier, "#", symName(tree, selector))
case CompoundTypeTree(templ) =>
print(templ)
case AppliedTypeTree(tp, args) =>
print(tp); printRow(args, "[", ", ", "]")
case TypeBoundsTree(lo, hi) =>
printOpt(" >: ", lo); printOpt(" <: ", hi)
case ExistentialTypeTree(tpt, whereClauses) =>
print(tpt);
printColumn(whereClauses, " forSome { ", ";", "}")
// SelectFromArray is no longer visible in reflect.internal.
// eliminated until we figure out what we will do with both Printers and
// SelectFromArray.
// case SelectFromArray(qualifier, name, _) =>
// print(qualifier); print(".<arr>"); print(symName(tree, name))
case tree =>
xprintTree(this, tree)
}
if (printTypes && tree.isTerm && !tree.isEmpty) {
print("{", if (tree.tpe eq null) "<null>" else tree.tpe.toString, "}")
}
}
def print(args: Any*): Unit = args foreach {
case tree: Tree =>
printPosition(tree)
printTree(tree)
case name: Name =>
print(quotedName(name))
case arg =>
out.print(if (arg == null) "null" else arg.toString)
}
}
/** Hook for extensions */
def xprintTree(treePrinter: TreePrinter, tree: Tree) =
treePrinter.print(tree.productPrefix+tree.productIterator.mkString("(", ", ", ")"))
def newTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer)
def newTreePrinter(stream: OutputStream): TreePrinter = newTreePrinter(new PrintWriter(stream))
def newTreePrinter(): TreePrinter = newTreePrinter(new PrintWriter(ConsoleWriter))
/** A writer that writes to the current Console and
* is sensitive to replacement of the Console's
* output stream.
*/
object ConsoleWriter extends Writer {
override def write(str: String) { Console.print(str) }
def write(cbuf: Array[Char], off: Int, len: Int) {
write(new String(cbuf, off, len))
}
def close = { /* do nothing */ }
def flush = { /* do nothing */ }
}
def newRawTreePrinter(writer: PrintWriter): RawTreePrinter = new RawTreePrinter(writer)
def newRawTreePrinter(stream: OutputStream): RawTreePrinter = newRawTreePrinter(new PrintWriter(stream))
def newRawTreePrinter(): RawTreePrinter = newRawTreePrinter(new PrintWriter(ConsoleWriter))
// provides footnotes for types and mirrors
import scala.collection.mutable.{Map, WeakHashMap, SortedSet}
private val footnoteIndex = new FootnoteIndex
private class FootnoteIndex {
private val index = Map[Class[_], WeakHashMap[Any, Int]]()
private def classIndex[T: ClassTag] = index.getOrElseUpdate(classTag[T].runtimeClass, WeakHashMap[Any, Int]())
private val counters = Map[Class[_], Int]()
private def nextCounter[T: ClassTag] = {
val clazz = classTag[T].runtimeClass
counters.getOrElseUpdate(clazz, 0)
counters(clazz) = counters(clazz) + 1
counters(clazz)
}
def mkFootnotes() = new Footnotes
class Footnotes {
private val footnotes = Map[Class[_], SortedSet[Int]]()
private def classFootnotes[T: ClassTag] = footnotes.getOrElseUpdate(classTag[T].runtimeClass, SortedSet[Int]())
def put[T: ClassTag](any: T): Int = {
val index = classIndex[T].getOrElseUpdate(any, nextCounter[T])
classFootnotes[T] += index
index
}
def get[T: ClassTag]: List[(Int, Any)] =
classFootnotes[T].toList map (fi => (fi, classIndex[T].find{ case (any, ii) => ii == fi }.get._1))
def print[T: ClassTag](printer: Printers.super.TreePrinter): Unit = {
val footnotes = get[T]
if (footnotes.nonEmpty) {
printer.print(EOL)
footnotes.zipWithIndex foreach {
case ((fi, any), ii) =>
printer.print("[", fi, "] ", any)
if (ii < footnotes.length - 1) printer.print(EOL)
}
}
}
}
}
// emits more or less verbatim representation of the provided tree
class RawTreePrinter(out: PrintWriter) extends super.TreePrinter {
private var depth = 0
private var printTypesInFootnotes = true
private var printingFootnotes = false
private var footnotes = footnoteIndex.mkFootnotes()
def print(args: Any*): Unit = {
// don't print type footnotes if the argument is a mere type
if (depth == 0 && args.length == 1 && args(0) != null && args(0).isInstanceOf[Type])
printTypesInFootnotes = false
depth += 1
args foreach {
case expr: Expr[_] =>
print("Expr")
if (printTypes) print(expr.staticType)
print("(")
print(expr.tree)
print(")")
case EmptyTree =>
print("EmptyTree")
case self.emptyValDef =>
print("emptyValDef")
case self.pendingSuperCall =>
print("pendingSuperCall")
case tree: Tree =>
val hasSymbol = tree.hasSymbol && tree.symbol != NoSymbol
val isError = hasSymbol && tree.symbol.name.toString == nme.ERROR.toString
printProduct(
tree,
preamble = _ => {
print(tree.productPrefix)
if (printTypes && tree.tpe != null) print(tree.tpe)
},
body = {
case name: Name =>
if (isError) {
if (isError) print("<")
print(name)
if (isError) print(": error>")
} else if (hasSymbol) {
tree match {
case refTree: RefTree =>
if (tree.symbol.name != refTree.name) print("[", tree.symbol, " aka ", refTree.name, "]")
else print(tree.symbol)
case _ =>
print(tree.symbol.name)
}
} else {
print(name)
}
case Constant(s: String) =>
print("Constant(\"" + s + "\")")
case Constant(null) =>
print("Constant(null)")
case Constant(value) =>
print("Constant(" + value + ")")
case arg =>
print(arg)
},
postamble = {
case tree @ TypeTree() if tree.original != null => print(".setOriginal(", tree.original, ")")
case _ => // do nothing
})
case sym: Symbol =>
if (sym == NoSymbol) print("NoSymbol")
else if (sym.isStatic && (sym.isClass || sym.isModule)) print(sym.fullName)
else print(sym.name)
if (printIds) print("#", sym.id)
if (printKinds) print("#", sym.abbreviatedKindString)
if (printMirrors) print("%M", footnotes.put[scala.reflect.api.Mirror[_]](mirrorThatLoaded(sym)))
case tag: TypeTag[_] =>
print("TypeTag(", tag.tpe, ")")
case tag: WeakTypeTag[_] =>
print("WeakTypeTag(", tag.tpe, ")")
case tpe: Type =>
val defer = printTypesInFootnotes && !printingFootnotes
if (defer) print("[", footnotes.put(tpe), "]")
else tpe match {
case NoType => print("NoType")
case NoPrefix => print("NoPrefix")
case _ => printProduct(tpe.asInstanceOf[Product])
}
case mods: Modifiers =>
print("Modifiers(")
if (mods.flags != NoFlags || mods.privateWithin != tpnme.EMPTY || mods.annotations.nonEmpty) print(show(mods.flags))
if (mods.privateWithin != tpnme.EMPTY || mods.annotations.nonEmpty) { print(", "); print(mods.privateWithin) }
if (mods.annotations.nonEmpty) { print(", "); print(mods.annotations); }
print(")")
case name: Name =>
print(show(name))
case scope: Scope =>
print("Scope")
printIterable(scope.toList)
case list: List[_] =>
print("List")
printIterable(list)
case product: Product =>
printProduct(product)
case arg =>
out.print(arg)
}
depth -= 1
if (depth == 0 && !printingFootnotes) {
printingFootnotes = true
footnotes.print[Type](this)
footnotes.print[scala.reflect.api.Mirror[_]](this)
printingFootnotes = false
}
}
def printProduct(
p: Product,
preamble: Product => Unit = p => print(p.productPrefix),
body: Any => Unit = print(_),
postamble: Product => Unit = p => print("")): Unit =
{
preamble(p)
printIterable(p.productIterator.toList, body = body)
postamble(p)
}
def printIterable(
iterable: List[_],
preamble: => Unit = print(""),
body: Any => Unit = print(_),
postamble: => Unit = print("")): Unit =
{
preamble
print("(")
val it = iterable.iterator
while (it.hasNext) {
body(it.next)
print(if (it.hasNext) ", " else "")
}
print(")")
postamble
}
}
def show(name: Name): String = name match {
case tpnme.WILDCARD => "tpnme.WILDCARD"
case tpnme.EMPTY => "tpnme.EMPTY"
case tpnme.ERROR => "tpnme.ERROR"
case tpnme.PACKAGE => "tpnme.PACKAGE"
case tpnme.WILDCARD_STAR => "tpnme.WILDCARD_STAR"
case nme.WILDCARD => "nme.WILDCARD"
case nme.EMPTY => "nme.EMPTY"
case nme.ERROR => "tpnme.ERROR"
case nme.PACKAGE => "nme.PACKAGE"
case nme.CONSTRUCTOR => "nme.CONSTRUCTOR"
case nme.ROOTPKG => "nme.ROOTPKG"
case _ =>
val prefix = if (name.isTermName) "newTermName(\"" else "newTypeName(\""
prefix + name.toString + "\")"
}
def show(flags: FlagSet): String = {
if (flags == NoFlags) nme.NoFlags.toString
else {
val s_flags = new scala.collection.mutable.ListBuffer[String]
def hasFlag(left: Long, right: Long): Boolean = (left & right) != 0
for (i <- 0 to 63 if hasFlag(flags, 1L << i))
s_flags += flagToString(1L << i).replace("<", "").replace(">", "").toUpperCase
s_flags mkString " | "
}
}
}
Jump to Line
Something went wrong with that request. Please try again.