From 752884f1606320913ffe66f3bbf3db61746e2436 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 19 Mar 2012 15:08:43 -0700 Subject: Overhaul of NodePrinters. Drawing on the previous, a half-decade overdue overhaul of NodePrinters. Now with colors if you like colors. % scalac -Xprint:all -Yshow-trees -Dscala.colors a.scala Am heading toward general purpose color configuration. --- .../scala/tools/nsc/ast/NodePrinters.scala | 524 +++++++++++---------- .../scala/tools/nsc/ast/TreeBrowsers.scala | 147 +----- 2 files changed, 287 insertions(+), 384 deletions(-) diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index 9466d1c1f2..3d4253f941 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -9,14 +9,13 @@ package ast import compat.Platform.EOL import symtab.Flags._ -/** The object nodePrinter converts the internal tree - * representation to a string formatted as a Scala expression. +/** The object `nodePrinter` converts the internal tree + * representation to a string. * * @author Stephane Micheloud - * @version 1.0 + * @author Paul Phillips */ abstract class NodePrinters { - val global: Global import global._ @@ -25,262 +24,293 @@ abstract class NodePrinters { } var infolevel = InfoLevel.Quiet - object nodeToString extends Function1[Tree, String] { + def nodeToString: Tree => String = + if (sys.props contains "scala.colors") nodeToColorizedString + else nodeToRegularString + + object nodeToRegularString extends DefaultPrintAST with (Tree => String) { + def apply(tree: Tree) = stringify(tree) + } + + object nodeToColorizedString extends ColorPrintAST with (Tree => String) { + def apply(tree: Tree) = stringify(tree) + } + + trait ColorPrintAST extends DefaultPrintAST { + import scala.tools.util.color._ + + def keywordColor = Cyan + def typeColor = Yellow + def termColor = Blue + def flagColor = Red + def literalColor = Green + + override def showFlags(tree: MemberDef) = "" + ( + super.showFlags(tree) in flagColor.bright + ) + override def showDefTreeName(tree: DefTree) = "" + ( + if (tree.name.isTermName) tree.name.decode in termColor.bright + else tree.name.decode in typeColor.bright + ) + override def showName(name: Name): String = "" + ( + if (name == nme.EMPTY || name == tpnme.EMPTY) "" in keywordColor + else if (name.isTermName) name.decode in termColor + else name.decode in typeColor + ) + override def showLiteral(lit: Literal) = "" + ( + super.showLiteral(lit) in literalColor.bright + ) + } + + trait DefaultPrintAST extends PrintAST { + def showDefTreeName(tree: DefTree) = showName(tree.name) + def showFlags(tree: MemberDef) = flagsToString(tree.symbol.flags | tree.mods.flags) + def showLiteral(lit: Literal) = lit.value.escapedStringValue + def showTypeTree(tt: TypeTree) = "" + showAttributes(tt) + def showName(name: Name) = name match { + case nme.EMPTY | tpnme.EMPTY => "" + case name => "\"" + name + "\"" + } + + def showSymbol(tree: Tree): String = { + val sym = tree.symbol + if (sym == null || sym == NoSymbol) "" + else " sym/owner/tpe=%s %s/%s/%s".format(sym.accurateKindString, sym.name, sym.owner, sym.tpe) + } + def showType(tree: Tree): String = { + val tpe = tree.tpe + if (tpe == null || tpe == NoType) "" + else " tree.tpe=" + tpe + } + + def showAttributes(tree: Tree): String = { + if (infolevel == InfoLevel.Quiet) "" + else { + try { showSymbol(tree) + showType(tree) trim } + catch { case ex: Throwable => "sym= " + ex.getMessage } + } + } + } + + trait PrintAST { private val buf = new StringBuilder + private var level = 0 - def apply(tree: Tree): String = { - def traverse(tree: Tree, level: Int, comma: Boolean) { - def println(s: String) { - for (i <- 0 until level) buf.append(" ") - buf.append(s) - buf.append(EOL) - } - def printcln(s: String) { - for (i <- 0 until level) buf.append(" ") - buf.append(s) - if (comma) buf.append(",") - buf.append(EOL) - } - def annotationInfoToString(annot: AnnotationInfo): String = { - val str = new StringBuilder - str.append(annot.atp.toString()) - if (!annot.args.isEmpty) - str.append(annot.args.mkString("(", ",", ")")) - if (!annot.assocs.isEmpty) - for (((name, value), index) <- annot.assocs.zipWithIndex) { - if (index > 0) - str.append(", ") - str.append(name).append(" = ").append(value) - } - str.toString - } - def symflags(tree: Tree): String = { - val buf = new StringBuffer - val sym = tree.symbol - buf append flagsToString(sym.flags) + def showName(name: Name): String + def showDefTreeName(defTree: DefTree): String + def showFlags(tree: MemberDef): String + def showLiteral(lit: Literal): String + def showTypeTree(tt: TypeTree): String + def showAttributes(tree: Tree): String // symbol and type + + def showRefTreeName(tree: Tree): String = tree match { + case SelectFromTypeTree(qual, name) => showRefTreeName(qual) + "#" + showName(name) + case Select(qual, name) => showRefTreeName(qual) + "." + showName(name) + case Ident(name) => showName(name) + case _ => "" + tree + } + def showRefTree(tree: RefTree): String = { + def prefix0 = showRefTreeName(tree.qualifier) + def prefix = if (prefix0 == "") "" else (tree match { + case SelectFromTypeTree(_, _) => prefix0 + "#" + case Select(_, _) => prefix0 + "." + case _ => "" + }) + def attrs = showAttributes(tree) match { + case "" => "" + case s => " // " + s + } + prefix + showName(tree.name) + attrs + } + + def stringify(tree: Tree): String = { + buf.clear() + level = 0 + traverse(tree) + buf.toString + } + def traverseAny(x: Any) { + x match { + case t: Tree => traverse(t) + case xs: List[_] => printMultiline("List", "")(xs foreach traverseAny) + case _ => println("" + x) + } + } + def println(s: String) = printLine(s, "") + + def printLine(value: String, comment: String) { + buf append " " * level + buf append value + if (comment != "") { + buf append " // " + buf append comment + } + buf append EOL + } - val annots = ", annots=" + ( - if (!sym.annotations.isEmpty) - sym.annotations.map(annotationInfoToString).mkString("[", ",", "]") - else - tree.asInstanceOf[MemberDef].mods.annotations) - (if (buf.length() > 2) buf.substring(3) - else "0") + ", // flags=" + flagsToString(sym.flags) + annots + def annotationInfoToString(annot: AnnotationInfo): String = { + val str = new StringBuilder + str.append(annot.atp.toString()) + if (!annot.args.isEmpty) + str.append(annot.args.mkString("(", ",", ")")) + if (!annot.assocs.isEmpty) + for (((name, value), index) <- annot.assocs.zipWithIndex) { + if (index > 0) + str.append(", ") + str.append(name).append(" = ").append(value) } + str.toString + } + def printModifiers(tree: MemberDef) { + val annots0 = tree.symbol.annotations match { + case Nil => tree.mods.annotations + case xs => xs map annotationInfoToString + } + val annots = annots0 match { + case Nil => "" + case xs => " " + xs.mkString("@{ ", ", ", " }") + } + val flagString = showFlags(tree) match { + case "" => "0" + case s => s + } + println(flagString + annots) + } - def nodeinfo(tree: Tree): String = - if (infolevel == InfoLevel.Quiet) "" - else { - try { - val buf = new StringBuilder(" // sym=" + tree.symbol) - if (tree.hasSymbol) { - if (tree.symbol.isPrimaryConstructor) - buf.append(", isPrimaryConstructor") - else if (tree.symbol.isConstructor) - buf.append(", isConstructor") - if (tree.symbol != NoSymbol) - buf.append(", sym.owner=" + tree.symbol.owner) - buf.append(", sym.tpe=" + tree.symbol.tpe) - } - buf.append(", tpe=" + tree.tpe) - if (tree.tpe != null) { - var sym = tree.tpe.termSymbol - if (sym == NoSymbol) sym = tree.tpe.typeSymbol - buf.append(", tpe.sym=" + sym) - if (sym != NoSymbol) { - buf.append(", tpe.sym.owner=" + sym.owner) - if ((infolevel > InfoLevel.Normal) && - !(sym.owner eq definitions.ScalaPackageClass) && - !sym.isModuleClass && !sym.isPackageClass && - !sym.isJavaDefined) { - val members = for (m <- tree.tpe.decls) - yield m.toString() + ": " + m.tpe + ", " - buf.append(", tpe.decls=" + members) - } + def applyCommon(tree: Tree, fun: Tree, args: List[Tree]) { + printMultiline(tree) { + traverse(fun) + traverseList("Nil", _ + " arguments(s)")(args) + } + } + + def printMultiline(tree: Tree)(body: => Unit) { + printMultiline(tree.printingPrefix, showAttributes(tree))(body) + } + def printMultiline(prefix: String, comment: String)(body: => Unit) { + printLine(prefix + "(", comment) + indent(body) + println(")") + } + @inline private def indent[T](body: => T): T = { + level += 1 + try body + finally level -= 1 + } + + def traverseList(ifEmpty: String, comment: Int => String)(trees: List[Tree]) { + if (trees.isEmpty) + println(ifEmpty) + else + printMultiline("List", comment(trees.length))(trees foreach traverse) + } + + def traverse(tree: Tree) { + tree match { + case AppliedTypeTree(tpt, args) => applyCommon(tree, tpt, args) + case ApplyDynamic(fun, args) => applyCommon(tree, fun, args) + case Apply(fun, args) => applyCommon(tree, fun, args) + + case Block(stats, expr) => + printMultiline(tree) { + traverseList("{}", _ + " statement(s)")(stats) + traverse(expr) + } + case cd @ ClassDef(mods, name, tparams, impl) => + printMultiline(tree) { + printModifiers(cd) + println(showDefTreeName(cd)) + traverseList("[]", _ + " type parameter(s)")(tparams) + traverse(impl) + } + case md @ ModuleDef(mods, name, impl) => + printMultiline(tree) { + printModifiers(md) + println(showDefTreeName(md)) + traverse(impl) + } + case dd @ DefDef(mods, name, tparams, vparamss, tpt, rhs) => + printMultiline(tree) { + printModifiers(dd) + println(showDefTreeName(dd)) + traverseList("[]", _ + " type parameter(s)")(tparams) + vparamss match { + case Nil => println("Nil") + case Nil :: Nil => println("List(Nil)") + case xss => + printMultiline("List", xss.length + " parameter list(s)") { + xss foreach (xs => traverseList("()", _ + " parameter(s)")(xs)) } + } + traverse(tpt) + traverse(rhs) + } + case EmptyTree => + println(showName(nme.EMPTY)) + case lit @ Literal(value) => + println(showLiteral(lit)) + case New(tpt) => + printMultiline(tree)(traverse(tpt)) + case Super(This(qual), mix) => + println("Super(This(" + showName(qual) + "), " + showName(mix) + ")") + case Super(qual, mix) => + printMultiline(tree) { + traverse(qual) + showName(mix) + } + case Template(parents, self, body) => + printMultiline(tree) { + val ps0 = parents map { p => + if (p.tpe eq null) p match { + case x: RefTree => showRefTree(x) + case x => "" + x } - buf.toString - } catch { - case ex: Throwable => - return " // sym= " + ex.getMessage + else showName(newTypeName(p.tpe.typeSymbol.fullName)) } + printLine(ps0 mkString ", ", "parents") + traverse(self) + traverseList("{}", _ + " statements in body")(body) } - def nodeinfo2(tree: Tree): String = - (if (comma) "," else "") + nodeinfo(tree) - - def applyCommon(name: String, tree: Tree, fun: Tree, args: List[Tree]) { - println(name + "(" + nodeinfo(tree)) - traverse(fun, level + 1, true) - if (args.isEmpty) - println(" Nil // no argument") - else { - val n = args.length - println(" List( // " + n + " arguments(s)") - for (i <- 0 until n) - traverse(args(i), level + 2, i < n-1) - println(" )") + case This(qual) => + println("This(\"" + showName(qual) + "\")" + showAttributes(tree)) + case TypeApply(fun, args) => + printMultiline(tree) { + traverse(fun) + traverseList("[]", _ + " type argument(s)")(args) } - printcln(")") - } + case tt @ TypeTree() => + println(showTypeTree(tt)) - tree match { - case AppliedTypeTree(tpt, args) => applyCommon("AppliedTypeTree", tree, tpt, args) - case Apply(fun, args) => applyCommon("Apply", tree, fun, args) - case ApplyDynamic(fun, args) => applyCommon("ApplyDynamic", tree, fun, args) + case Typed(expr, tpt) => + printMultiline(tree) { + traverse(expr) + traverse(tpt) + } + case vd @ ValDef(mods, name, tpt, rhs) => + printMultiline(tree) { + printModifiers(vd) + println(showDefTreeName(vd)) + traverse(tpt) + traverse(rhs) + } + case td @ TypeDef(mods, name, tparams, rhs) => + printMultiline(tree) { + printModifiers(td) + println(showDefTreeName(td)) + traverseList("[]", _ + " type parameter(s)")(tparams) + traverse(rhs) + } + + case PackageDef(pid, stats) => + printMultiline("PackageDef", "")(pid :: stats foreach traverse) - case Block(stats, expr) => - println("Block(" + nodeinfo(tree)) - if (stats.isEmpty) - println(" List(), // no statement") - else { - val n = stats.length - println(" List( // " + n + " statement(s)") - for (i <- 0 until n) - traverse(stats(i), level + 2, i < n-1) - println(" ),") - } - traverse(expr, level + 1, false) - printcln(")") - case ClassDef(mods, name, tparams, impl) => - println("ClassDef(" + nodeinfo(tree)) - println(" " + symflags(tree)) - println(" \"" + name + "\",") - if (tparams.isEmpty) - println(" List(), // no type parameter") - else { - val n = tparams.length - println(" List( // " + n + " type parameter(s)") - for (i <- 0 until n) - traverse(tparams(i), level + 2, i < n-1) - println(" ),") - } - traverse(impl, level + 1, false) - printcln(")") - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - println("DefDef(" + nodeinfo(tree)) - println(" " + symflags(tree)) - println(" \"" + name + "\",") - if (tparams.isEmpty) - println(" List(), // no type parameter") - else { - val n = tparams.length - println(" List( // " + n + " type parameter(s)") - for (i <- 0 until n) - traverse(tparams(i), level + 2, i < n-1) - println(" ),") - } - val n = vparamss.length - if (n == 1 && vparamss(0).isEmpty) - println(" List(List()), // no parameter") - else { - println(" List(") - for (i <- 0 until n) { - val m = vparamss(i).length - println(" List( // " + m + " parameter(s)") - for (j <- 0 until m) - traverse(vparamss(i)(j), level + 3, j < m-1) - println(" )") - } - println(" ),") - } - println(" " + tpt + ",") - traverse(rhs, level + 1, false) - printcln(")") - case EmptyTree => - printcln("EmptyTree") - case Ident(name) => - printcln("Ident(\"" + name + "\")" + nodeinfo2(tree)) - case Literal(value) => - printcln("Literal(" + value + ")") - case New(tpt) => - println("New(" + nodeinfo(tree)) - traverse(tpt, level + 1, false) - printcln(")") - case Select(qualifier, selector) => - println("Select(" + nodeinfo(tree)) - traverse(qualifier, level + 1, true) - printcln(" \"" + selector + "\")") - case Super(qual, mix) => - println("Super(\"" + mix + "\")" + nodeinfo(tree)) - traverse(qual, level + 1, true) - case Template(parents, self, body) => - println("Template(" + nodeinfo(tree)) - println(" " + parents.map(p => - if (p.tpe ne null) p.tpe.typeSymbol else "null-" + p - ) + ", // parents") - traverse(self, level + 1, true) - if (body.isEmpty) - println(" List() // no body") - else { - val n = body.length - println(" List( // body") - for (i <- 0 until n) - traverse(body(i), level + 2, i < n-1) - println(" )") - } - printcln(")") - case This(qual) => - println("This(\"" + qual + "\")" + nodeinfo2(tree)) - case TypeApply(fun, args) => - println("TypeApply(" + nodeinfo(tree)) - traverse(fun, level + 1, true) - if (args.isEmpty) - println(" List() // no argument") - else { - val n = args.length - println(" List(") - for (i <- 0 until n) - traverse(args(i), level + 1, i < n-1) - println(" )") - } - printcln(")") - case TypeTree() => - printcln("TypeTree()" + nodeinfo2(tree)) - case Typed(expr, tpt) => - println("Typed(" + nodeinfo(tree)) - traverse(expr, level + 1, true) - traverse(tpt, level + 1, false) - printcln(")") - case ValDef(mods, name, tpt, rhs) => - println("ValDef(" + nodeinfo(tree)) - println(" " + symflags(tree)) - println(" \"" + name + "\",") - traverse(tpt, level + 1, true) - traverse(rhs, level + 1, false) - printcln(")") - case PackageDef(pid, stats) => - println("PackageDef(") - traverse(pid, level + 1, false) - println(",\n") - for (stat <- stats) - traverse(stat, level + 1, false) - printcln(")") - case _ => - tree match { - case p: Product => - if (p.productArity != 0) { - println(p.productPrefix+"(") - for (elem <- (0 until p.productArity) map p.productElement) { - def printElem(elem: Any, level: Int): Unit = elem match { - case t: Tree => - traverse(t, level, false) - case xs: List[_] => - print("List(") - for (x <- xs) printElem(x, level+1) - printcln(")") - case _ => - println(elem.toString) - } - printElem(elem, level+1) - } - printcln(")") - } else printcln(p.productPrefix) - } - } + case _ => + tree match { + case t: RefTree => println(showRefTree(t)) + case t if t.productArity == 0 => println(tree.printingPrefix) + case t => printMultiline(tree)(tree.productIterator foreach traverseAny) + } } - buf setLength 0 - traverse(tree, 0, false) - buf.toString } } diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala index c1d6c1a4d4..3302c11127 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala @@ -352,144 +352,17 @@ abstract class TreeBrowsers { * Tree. */ object TreeInfo { - /** Return the case class name and the Name, if the node defines one */ - def treeName(t: Tree): (String, Name) = t match { - case ProgramTree(units) => - ("Program", EMPTY) - - case UnitTree(unit) => - ("CompilationUnit", newTermName("" + unit)) - - case DocDef(comment, definition) => - ("DocDef", EMPTY) - - case ClassDef(mods, name, tparams, impl) => - ("ClassDef", name) - - case PackageDef(packaged, impl) => - ("PackageDef", EMPTY) - - case ModuleDef(mods, name, impl) => - ("ModuleDef", name) - - case ValDef(mods, name, tpe, rhs) => - ("ValDef", name) - - case DefDef(mods, name, tparams, vparams, tpe, rhs) => - ("DefDef", name) - - case TypeDef(mods, name, tparams, rhs) => - ("TypeDef", name) - - case Import(expr, selectors) => - ("Import", EMPTY) - - case CaseDef(pat, guard, body) => - ("CaseDef", EMPTY) - - case Template(parents, self, body) => - ("Template", EMPTY) - - case LabelDef(name, params, rhs) => - ("LabelDef", name) - - case Block(stats, expr) => - ("Block", EMPTY) - - case Alternative(trees) => - ("Alternative", EMPTY) - - case Bind(name, rhs) => - ("Bind", name) - - case UnApply(fun, args) => - ("UnApply", EMPTY) - - case Match(selector, cases) => - ("Visitor", EMPTY) - - case Function(vparams, body) => - ("Function", EMPTY) - - case Assign(lhs, rhs) => - ("Assign", EMPTY) - - case If(cond, thenp, elsep) => - ("If", EMPTY) - - case Return(expr) => - ("Return", EMPTY) - - case Throw(expr) => - ("Throw", EMPTY) - - case New(init) => - ("New", EMPTY) - - case Typed(expr, tpe) => - ("Typed", EMPTY) - - case TypeApply(fun, args) => - ("TypeApply", EMPTY) - - case Apply(fun, args) => - ("Apply", EMPTY) - - case ApplyDynamic(qual, args) => - ("Apply", EMPTY) - - case Super(qualif, mix) => - ("Super", newTermName("mix: " + mix)) - - case This(qualifier) => - ("This", qualifier) - - case Select(qualifier, selector) => - ("Select", selector) - - case Ident(name) => - ("Ident", name) - - case Literal(value) => - ("Literal", EMPTY) - - case TypeTree() => - ("TypeTree", EMPTY) - - case Annotated(annot, arg) => - ("Annotated", EMPTY) - - case SingletonTypeTree(ref) => - ("SingletonType", EMPTY) - - case SelectFromTypeTree(qualifier, selector) => - ("SelectFromType", selector) - - case CompoundTypeTree(template) => - ("CompoundType", EMPTY) - - case AppliedTypeTree(tpe, args) => - ("AppliedType", EMPTY) - - case TypeBoundsTree(lo, hi) => - ("TypeBoundsTree", EMPTY) - - case ExistentialTypeTree(tpt, whereClauses) => - ("ExistentialTypeTree", EMPTY) - - case Try(block, catcher, finalizer) => - ("Try", EMPTY) - - case EmptyTree => - ("Empty", EMPTY) - - case ArrayValue(elemtpt, trees) => - ("ArrayValue", EMPTY) - - case Star(t) => - ("Star", EMPTY) - } + def treeName(t: Tree): (String, Name) = ((t.printingPrefix, t match { + case UnitTree(unit) => newTermName("" + unit) + case Super(_, mix) => newTermName("mix: " + mix) + case This(qual) => qual + case Select(_, selector) => selector + case Ident(name) => name + case SelectFromTypeTree(_, selector) => selector + case x: DefTree => x.name + case _ => EMPTY + })) /** Return a list of children for the given tree node */ def children(t: Tree): List[Tree] = t match { -- cgit v1.2.3