Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

690 lines (591 sloc) 24.431 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 emptyValDef: AnyRef if emptyValDef eq self.emptyValDef =>
print("emptyValDef")
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.