diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2012-06-15 13:35:54 +0200 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2012-06-19 04:26:38 +0200 |
commit | 3be520bcfc84f207d172934f9b147e31355cd877 (patch) | |
tree | 94422d1e31d2f6adaba527a90bd8d46a22ecb3a5 /src/reflect | |
parent | 885d64dce1c3a34b01f4ffcbd2132838d3c60443 (diff) | |
download | scala-3be520bcfc84f207d172934f9b147e31355cd877.tar.gz scala-3be520bcfc84f207d172934f9b147e31355cd877.tar.bz2 scala-3be520bcfc84f207d172934f9b147e31355cd877.zip |
improves showRaw
addresses concerns raised in http://groups.google.com/group/scala-user/browse_thread/thread/de5a5be2e083cf8e
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/scala/reflect/api/Printers.scala | 94 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/Symbols.scala | 19 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/TreePrinters.scala | 87 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/Universe.scala | 2 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Printers.scala (renamed from src/reflect/scala/reflect/internal/TreePrinters.scala) | 176 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/SymbolTable.scala | 2 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Trees.scala | 2 | ||||
-rw-r--r-- | src/reflect/scala/reflect/makro/Universe.scala | 19 |
8 files changed, 286 insertions, 115 deletions
diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala new file mode 100644 index 0000000000..7f4ff8a7fb --- /dev/null +++ b/src/reflect/scala/reflect/api/Printers.scala @@ -0,0 +1,94 @@ +package scala.reflect +package api + +import java.io.{ PrintWriter, StringWriter } + +trait Printers { self: Universe => + + trait TreePrinter { + def print(args: Any*) + protected var printTypes = false + protected var printIds = false + protected var printKinds = false + def withTypes: this.type = { printTypes = true; this } + def withoutTypes: this.type = { printTypes = false; this } + def withIds: this.type = { printIds = true; this } + def withoutIds: this.type = { printIds = false; this } + def withKinds: this.type = { printKinds = true; this } + def withoutKinds: this.type = { printKinds = false; this } + } + + case class BooleanFlag(val value: Option[Boolean]) + object BooleanFlag { + import language.implicitConversions + implicit def booleanToBooleanFlag(value: Boolean): BooleanFlag = BooleanFlag(Some(value)) + implicit def optionToBooleanFlag(value: Option[Boolean]): BooleanFlag = BooleanFlag(value) + } + + protected def render(what: Any, mkPrinter: PrintWriter => TreePrinter, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None): String = { + val buffer = new StringWriter() + val writer = new PrintWriter(buffer) + var printer = mkPrinter(writer) + printTypes.value.map(printTypes => if (printTypes) printer.withTypes else printer.withoutTypes) + printIds.value.map(printIds => if (printIds) printer.withIds else printer.withoutIds) + printKinds.value.map(printKinds => if (printKinds) printer.withKinds else printer.withoutKinds) + printer.print(what) + writer.flush() + buffer.toString + } + + /** By default trees are printed with `show` */ + override protected def treeToString(tree: Tree) = show(tree) + + /** Renders a prettified representation of a tree. + * Typically it looks very close to the Scala code it represents. + * This function is used in Tree.toString. + */ + def show(tree: Tree, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None): String = + render(tree, newTreePrinter(_), printTypes, printIds, printKinds) + + /** Hook to define what `show(tree)` means. + */ + def newTreePrinter(out: PrintWriter): TreePrinter + + /** Renders internal structure of a tree. + */ + def showRaw(tree: Tree, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None): String = + render(tree, newRawTreePrinter(_), printTypes, printIds, printKinds) + + /** Hook to define what `showRaw(tree)` means. + */ + def newRawTreePrinter(out: PrintWriter): TreePrinter + + /** Renders a prettified representation of a symbol. + */ + def show(sym: Symbol): String = sym.toString + + /** Renders internal structure of a symbol. + */ + def showRaw(sym: Symbol): String = render(sym, newRawTreePrinter(_)) + + /** Renders a prettified representation of a type. + */ + def show(tpe: Type): String = tpe.toString + + /** Renders internal structure of a type. + */ + def showRaw(tpe: Type): String = render(tpe, newRawTreePrinter(_)) + + /** Renders a prettified representation of a name. + */ + def show(name: Name): String + + /** Renders internal structure of a name. + */ + def showRaw(name: Name): String = name.toString + + /** Renders a prettified representation of a flag set. + */ + def show(flags: FlagSet): String + + /** Renders internal structure of a flag set. + */ + def showRaw(flags: FlagSet): String = flags.toString +} diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index 1d266dc778..130f9e612a 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -177,6 +177,25 @@ trait Symbols extends base.Symbols { self: Universe => */ def isErroneous : Boolean + /** Can this symbol be loaded by a reflective mirror? + * + * Scalac relies on `ScalaSignature' annotation to retain symbols across compilation runs. + * Such annotations (also called "pickles") are applied on top-level classes and include information + * about all symbols reachable from the annotee. However, local symbols (e.g. classes or definitions local to a block) + * are typically unreachable and information about them gets lost. + * + * This method is useful for macro writers who wish to save certain ASTs to be used at runtime. + * With `isLocatable' it's possible to check whether a tree can be retained as is, or it needs special treatment. + */ + def isLocatable: Boolean + + /** Is this symbol static (i.e. with no outer instance)? + * Q: When exactly is a sym marked as STATIC? + * A: If it's a member of a toplevel object, or of an object contained in a toplevel object, or any number of levels deep. + * http://groups.google.com/group/scala-internals/browse_thread/thread/d385bcd60b08faf6 + */ + def isStatic: Boolean + /** The type signature of this symbol seen as a member of given type `site`. */ def typeSignatureIn(site: Type): Type diff --git a/src/reflect/scala/reflect/api/TreePrinters.scala b/src/reflect/scala/reflect/api/TreePrinters.scala deleted file mode 100644 index 08a08e7b90..0000000000 --- a/src/reflect/scala/reflect/api/TreePrinters.scala +++ /dev/null @@ -1,87 +0,0 @@ -package scala.reflect -package api - -import java.io.{ PrintWriter, StringWriter } - -trait TreePrinters { self: Universe => - - trait TreePrinter { - def print(args: Any*) - protected var typesPrinted = false - protected var uniqueIds = false - def withTypesPrinted: this.type = { typesPrinted = true; this } - def withUniqueIds: this.type = { uniqueIds = true; this } - } - - def show(tree: Tree): String = show(tree, newTreePrinter) - - def show(tree: Tree, mkPrinter: PrintWriter => TreePrinter): String = { - val buffer = new StringWriter() - val writer = new PrintWriter(buffer) - val printer = mkPrinter(writer) - printer.print(tree) - writer.flush() - buffer.toString - } - - def showRaw(tree: Tree): String = show(tree, new RawTreePrinter(_)) - - /** Hook to define what `show(tree)` means. - */ - def newTreePrinter(out: PrintWriter): TreePrinter - - // emits more or less verbatim representation of the provided tree - // [Eugene] todo. needs to be refined - // http://groups.google.com/group/scala-user/browse_thread/thread/de5a5be2e083cf8e - class RawTreePrinter(out: PrintWriter) extends TreePrinter { - def print(args: Any*): Unit = args foreach { - case EmptyTree => - print("EmptyTree") - case tree @ TypeTree() => - print("TypeTree()") - if (tree.tpe != null) - print(".setType(", tree.tpe, ")") - else if (tree.original != null) - print(".setOriginal(", tree.original, ")") - case Literal(Constant(s: String)) => - print("Literal(Constant(\"" + s + "\"))") - case tree: Tree => - print(tree.productPrefix+"(") - val it = tree.productIterator - while (it.hasNext) { - it.next() match { - case name: Name if uniqueIds && tree.hasSymbol && tree.symbol != NoSymbol => - print(tree.symbol.name, "#", tree.symbol.id) - case arg => - print(arg) - } - print(if (it.hasNext) ", " else "") - } - print(")") - if (typesPrinted) - print(".setType(", tree.tpe, ")") - case list: List[_] => - print("List(") - val it = list.iterator - while (it.hasNext) { - print(it.next()) - print(if (it.hasNext) ", " else "") - } - print(")") - case mods: Modifiers => - val parts = collection.mutable.ListBuffer[String]() - parts += mods.flagString - if (mods.privateWithin.toString.nonEmpty) - parts += "newTypeName(\"" + mods.privateWithin.toString + "\")" - if (mods.annotations.nonEmpty) - parts += mods.annotations map showRaw mkString ("List(", ", ", ")") - print(parts mkString ("Modifiers(", ", ", ")")) - case name: Name => - if (name.isTermName) print("newTermName(\"") else print("newTypeName(\"") - print(name.toString) - print("\")") - case arg => - out.print(arg) - } - } -} diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala index 002cd2e673..85d8adc44f 100644 --- a/src/reflect/scala/reflect/api/Universe.scala +++ b/src/reflect/scala/reflect/api/Universe.scala @@ -9,7 +9,7 @@ abstract class Universe extends base.Universe with FlagSets with Names with Trees - with TreePrinters + with Printers with Constants with Positions with Mirrors diff --git a/src/reflect/scala/reflect/internal/TreePrinters.scala b/src/reflect/scala/reflect/internal/Printers.scala index 6d035c8b9d..82a8c42f7c 100644 --- a/src/reflect/scala/reflect/internal/TreePrinters.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -11,7 +11,7 @@ package internal import java.io.{ OutputStream, PrintWriter, StringWriter, Writer } import Flags._ -trait TreePrinters extends api.TreePrinters { self: SymbolTable => +trait Printers extends api.Printers { self: SymbolTable => //nsc import treeInfo.{ IsTrue, IsFalse } @@ -62,8 +62,9 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => protected val indentStep = 2 protected var indentString = " " // 40 - typesPrinted = settings.printtypes.value - uniqueIds = settings.uniqid.value + printTypes = settings.printtypes.value + printIds = settings.uniqid.value + printKinds = settings.Yshowsymkinds.value protected def doPrintPositions = settings.Xprintpos.value def indent() = indentMargin += indentStep @@ -320,7 +321,7 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => case Function(vparams, body) => print("("); printValueParams(vparams); print(" => ", body, ")") - if (uniqueIds && tree.symbol != null) print("#"+tree.symbol.id) + if (printIds && tree.symbol != null) print("#"+tree.symbol.id) case Assign(lhs, rhs) => print(lhs, " = ", rhs) @@ -429,7 +430,7 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => printColumn(whereClauses, " forSome { ", ";", "}") // SelectFromArray is no longer visible in reflect.internal. -// eliminated until we figure out what we will do with both TreePrinters and +// 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)) @@ -437,7 +438,7 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => case tree => xprintTree(this, tree) } - if (typesPrinted && tree.isTerm && !tree.isEmpty) { + if (printTypes && tree.isTerm && !tree.isEmpty) { print("{", if (tree.tpe eq null) "<null>" else tree.tpe.toString, "}") } } @@ -475,4 +476,167 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => def close = { /* do nothing */ } def flush = { /* do nothing */ } } + + // provides footnotes for types + private var typeCounter = 0 + private val typeMap = collection.mutable.WeakHashMap[Type, Int]() + + def newRawTreePrinter(writer: PrintWriter): RawTreePrinter = new RawTreePrinter(writer) + def newRawTreePrinter(stream: OutputStream): RawTreePrinter = newRawTreePrinter(new PrintWriter(stream)) + def newRawTreePrinter(): RawTreePrinter = newRawTreePrinter(new PrintWriter(ConsoleWriter)) + + // emits more or less verbatim representation of the provided tree + class RawTreePrinter(out: PrintWriter) extends super.TreePrinter { + private var depth = 0 + private var footnotes = collection.mutable.Map[Int, Type]() + private var printingFootnotes = false + private var printTypesInFootnotes = true + + def print(args: Any*): Unit = { + if (depth == 0 && args.length == 1 && args(0) != null && args(0).isInstanceOf[Type]) + printTypesInFootnotes = false + + depth += 1 + args foreach { + case EmptyTree => + print("EmptyTree") + case emptyValDef: AnyRef if emptyValDef eq self.emptyValDef => + print("emptyValDef") + case Literal(Constant(value)) => + def print(s: String) = this.print("Literal(Constant(" + s + "))") + value match { + case s: String => print("\"" + s + "\"") + case null => print(null) + case _ => print(value.toString) + } + 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 _: Ident | _: Select | _: SelectFromTypeTree => print(tree.symbol) + case _ => print(tree.symbol.name) + } + } else { + print(name) + } + case arg => + print(arg) + }, + postamble = { + case tree @ TypeTree() if tree.original != null => print(".setOriginal(", tree.original, ")") + case _ => // do nothing + }) + case sym: Symbol => + if (sym.isStatic && (sym.isClass || sym.isModule)) print(sym.fullName) + else print(sym.name) + if (printIds) print("#", sym.id) + if (printKinds) print("#", sym.abbreviatedKindString) + case NoType => + print("NoType") + case NoPrefix => + print("NoPrefix") + case tpe: Type if printTypesInFootnotes && !printingFootnotes => + val index = typeMap.getOrElseUpdate(tpe, { typeCounter += 1; typeCounter }) + footnotes(index) = tpe + print("[", index, "]") + 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 list: List[_] => + print("List") + printIterable(list) + case product: Product => + printProduct(product) + case arg => + out.print(arg) + } + depth -= 1 + if (depth == 0 && footnotes.nonEmpty && !printingFootnotes) { + printingFootnotes = true + out.println() + val typeIndices = footnotes.keys.toList.sorted + typeIndices.zipWithIndex foreach { + case (typeIndex, i) => + print("[" + typeIndex + "] ") + print(footnotes(typeIndex)) + if (i < typeIndices.length - 1) out.println() + } + } + } + + 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 { + // base.StandardNames + case tpnme.EMPTY => "tpnme.EMPTY" + case tpnme.ROOT => "tpnme.ROOT" + case tpnme.EMPTY_PACKAGE_NAME => "tpnme.EMPTY_PACKAGE_NAME" + case tpnme.WILDCARD => "tpnme.WILDCARD" + case nme.CONSTRUCTOR => "nme.CONSTRUCTOR" + case nme.NO_NAME => "nme.NO_NAME" + // api.StandardNames + case tpnme.ERROR => "tpnme.ERROR" + case nme.ERROR => "nme.ERROR" + case nme.EMPTY => "nme.EMPTY" + case tpnme.PACKAGE => "tpnme.PACKAGE" + case nme.PACKAGE => "nme.PACKAGE" + 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 collection.mutable.ListBuffer[String] + for (i <- 0 to 63 if (flags containsAll (1L << i))) + s_flags += flagToString(1L << i).replace("<", "").replace(">", "").toUpperCase + s_flags mkString " | " + } + } } diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index cadd76b1ba..6def4d9409 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -28,7 +28,7 @@ abstract class SymbolTable extends makro.Universe with AnnotationInfos with AnnotationCheckers with Trees - with TreePrinters + with Printers with Positions with TypeDebugging with Importers diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 75bb0e6d49..562a49519f 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -809,7 +809,7 @@ trait Trees extends api.Trees { self: SymbolTable => } } - // Belongs in TreeInfo but then I can't reach it from TreePrinters. + // Belongs in TreeInfo but then I can't reach it from Printers. def isReferenceToScalaMember(t: Tree, Id: Name) = t match { case Ident(Id) => true case Select(Ident(nme.scala_), Id) => true diff --git a/src/reflect/scala/reflect/makro/Universe.scala b/src/reflect/scala/reflect/makro/Universe.scala index ffc4042a0a..98046be555 100644 --- a/src/reflect/scala/reflect/makro/Universe.scala +++ b/src/reflect/scala/reflect/makro/Universe.scala @@ -15,25 +15,6 @@ abstract class Universe extends scala.reflect.api.Universe { // [Eugene++ to Martin] should we also add mutability methods here (similarly to what's done below for trees)? // I'm talking about `setAnnotations` and friends - - /** Can this symbol be loaded by a reflective mirror? - * - * Scalac relies on `ScalaSignature' annotation to retain symbols across compilation runs. - * Such annotations (also called "pickles") are applied on top-level classes and include information - * about all symbols reachable from the annotee. However, local symbols (e.g. classes or definitions local to a block) - * are typically unreachable and information about them gets lost. - * - * This method is useful for macro writers who wish to save certain ASTs to be used at runtime. - * With `isLocatable' it's possible to check whether a tree can be retained as is, or it needs special treatment. - */ - def isLocatable: Boolean - - /** Is this symbol static (i.e. with no outer instance)? - * Q: When exactly is a sym marked as STATIC? - * A: If it's a member of a toplevel object, or of an object contained in a toplevel object, or any number of levels deep. - * http://groups.google.com/group/scala-internals/browse_thread/thread/d385bcd60b08faf6 - */ - def isStatic: Boolean } // Tree extensions --------------------------------------------------------------- |