diff options
Diffstat (limited to 'src/reflect/scala/reflect/internal/TreePrinters.scala')
-rw-r--r-- | src/reflect/scala/reflect/internal/TreePrinters.scala | 478 |
1 files changed, 478 insertions, 0 deletions
diff --git a/src/reflect/scala/reflect/internal/TreePrinters.scala b/src/reflect/scala/reflect/internal/TreePrinters.scala new file mode 100644 index 0000000000..6d035c8b9d --- /dev/null +++ b/src/reflect/scala/reflect/internal/TreePrinters.scala @@ -0,0 +1,478 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Martin Odersky + */ + +// [Eugene++ to Martin] we need to unify this prettyprinter with NodePrinters + +package scala.reflect +package internal + +import java.io.{ OutputStream, PrintWriter, StringWriter, Writer } +import Flags._ + +trait TreePrinters extends api.TreePrinters { 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 + + typesPrinted = settings.printtypes.value + uniqueIds = settings.uniqid.value + 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) { + if (!isCompilerUniverse && tree.symbol != null && tree.symbol != NoSymbol) + // [Eugene++] todo. this is not 100% correct, but is necessary for sane printing + // the problem is that getting annotations doesn't automatically initialize the symbol + // so we might easily print something as if it doesn't have annotations, whereas it does + tree.symbol.initialize + + 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 (uniqueIds && 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 TreePrinters and +// SelectFromArray. +// case SelectFromArray(qualifier, name, _) => +// print(qualifier); print(".<arr>"); print(symName(tree, name)) + + case tree => + xprintTree(this, tree) + } + if (typesPrinted && 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 */ } + } +} |