From dae85e321aaf121d83e2b3824e47ab7c525ed2cd Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 1 Mar 2010 19:47:48 +0000 Subject: Whipped ShowPickled until it would print out pr... Whipped ShowPickled until it would print out private[scope] from the signature, and infrastructure created along the way. Only now at this late hour do I realize that this work would be a lot better aimed at creating a fake Universe and then adapting UnPickler.Scan so you can reuse the real logic. My advice to the next guy: do that instead. No review. --- .../scala/tools/nsc/util/ShowPickled.scala | 100 +++++++++++++++++---- .../scala/reflect/generic/PickleBuffer.scala | 23 +++++ 2 files changed, 108 insertions(+), 15 deletions(-) diff --git a/src/compiler/scala/tools/nsc/util/ShowPickled.scala b/src/compiler/scala/tools/nsc/util/ShowPickled.scala index bc33f2156b..260c048b8a 100644 --- a/src/compiler/scala/tools/nsc/util/ShowPickled.scala +++ b/src/compiler/scala/tools/nsc/util/ShowPickled.scala @@ -17,9 +17,42 @@ import scala.reflect.generic.{ PickleBuffer, PickleFormat } import interpreter.ByteCode.scalaSigBytesForPath object ShowPickled extends Names { - import PickleFormat._ + case class PickleBufferEntry(num: Int, startIndex: Int, tag: Int, bytes: Array[Byte]) { + def isName = tag == TERMname || tag == TYPEname + def hasName = tag match { + case TYPEsym | ALIASsym | CLASSsym | MODULEsym | VALsym | EXTref | EXTMODCLASSref => true + case _ => false + } + def readName = + if (isName) new String(bytes, "UTF-8") + else error("%s is no name" format tagName) + def nameIndex = + if (hasName) readNat(bytes, 0) + else error("%s has no name" format tagName) + + def tagName = tag2string(tag) + override def toString = "%d,%d: %s".format(num, startIndex, tagName) + } + + case class PickleBufferEntryList(entries: IndexedSeq[PickleBufferEntry]) { + def nameAt(idx: Int) = { + val entry = entries(idx) + if (entry.isName) entry.readName + else if (entry.hasName) entries(entry.nameIndex).readName + else "?" + } + } + + def makeEntryList(buf: PickleBuffer, index: Array[Int]) = { + val entries = buf.toIndexedSeq.zipWithIndex map { + case ((tag, data), num) => PickleBufferEntry(num, index(num), tag, data) + } + + PickleBufferEntryList(entries) + } + def tag2string(tag: Int): String = tag match { case TERMname => "TERMname" case TYPEname => "TYPEname" @@ -70,30 +103,42 @@ object ShowPickled extends Names { case _ => "***BAD TAG***(" + tag + ")" } + /** Extremely regrettably, essentially copied from PickleBuffer. + */ + def readNat(data: Array[Byte], index: Int): Int = { + var idx = index + var result = 0L + var b = 0L + do { + b = data(idx) + idx += 1 + result = (result << 7) + (b & 0x7f) + } while((b & 0x80) != 0L) + + result.toInt + } + def printFile(buf: PickleBuffer, out: PrintStream): Unit = printFile(buf, out, false) def printFile(buf: PickleBuffer, out: PrintStream, bare: Boolean) { out.println("Version " + buf.readNat() + "." + buf.readNat()) val index = buf.createIndex + val entryList = makeEntryList(buf, index) + buf.readIndex = 0 /** A print wrapper which discards everything if bare is true. */ def p(s: String) = if (!bare) out print s def printNameRef() { - val x = buf.readNat() - val savedIndex = buf.readIndex - buf.readIndex = index(x) - val tag = buf.readByte() - val len = buf.readNat() - val name = newTermName(buf.bytes, buf.readIndex, len) + val idx = buf.readNat() + val name = entryList nameAt idx + val toPrint = if (bare) " " + name else " %s(%s)".format(idx, name) - val toPrint = if (bare) " " + name else " %s(%s)".format(x, name) out print toPrint - - buf.readIndex = savedIndex } def printNat() = p(" " + buf.readNat()) + def printReadNat(x: Int) = p(" " + x) def printSymbolRef() = printNat() def printTypeRef() = printNat() @@ -102,13 +147,38 @@ object ShowPickled extends Names { def printConstAnnotArgRef() = printNat() def printAnnotArgRef() = printNat() - def printSymInfo() { + def printSymInfo(end: Int) { printNameRef() printSymbolRef() val pflags = buf.readLongNat() - out.print(" " + toHexString(pflags) + - "[" + Flags.flagsToString(Flags.pickledToRawFlags(pflags)) + "] ") - printTypeRef() + def printFlags(privateWithin: Option[Int]) = { + val accessBoundary = ( + for (idx <- privateWithin) yield { + val s = entryList nameAt idx + if (bare) s else idx + "(" + s + ")" + } + ) + val flagString = { + val arg1 = Flags.pickledToRawFlags(pflags) + accessBoundary match { + case Some(pw) => Flags.flagsToString(arg1, pw) + case _ => Flags.flagsToString(arg1) + } + } + + out.print(" %s[%s]".format(toHexString(pflags), flagString)) + } + + /** Might be info or privateWithin */ + val x = buf.readNat() + if (buf.readIndex == end) { + printFlags(None) + printReadNat(x) + } + else { + printFlags(Some(x)) + printTypeRef() + } } /** Note: the entries which require some semantic analysis to be correctly @@ -133,7 +203,7 @@ object ShowPickled extends Names { out.print(newTypeName(buf.bytes, buf.readIndex, len)) buf.readIndex = end case TYPEsym | ALIASsym | CLASSsym | MODULEsym | VALsym => - printSymInfo() + printSymInfo(end) if (tag == CLASSsym && (buf.readIndex < end)) printTypeRef() case EXTref | EXTMODCLASSref => printNameRef() diff --git a/src/library/scala/reflect/generic/PickleBuffer.scala b/src/library/scala/reflect/generic/PickleBuffer.scala index 584b94578e..2fab02bcfe 100755 --- a/src/library/scala/reflect/generic/PickleBuffer.scala +++ b/src/library/scala/reflect/generic/PickleBuffer.scala @@ -128,6 +128,29 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) { x << leading >> leading } + /** Returns the buffer as a sequence of (Int, Array[Byte]) representing + * (tag, data) of the individual entries. Saves and restores buffer state. + */ + + def toIndexedSeq: IndexedSeq[(Int, Array[Byte])] = { + val saved = readIndex + readIndex = 0 + readNat() ; readNat() // discarding version + val result = new Array[(Int, Array[Byte])](readNat()) + + result.indices foreach { index => + val tag = readNat() + val len = readNat() + val bytes = data.slice(readIndex, len + readIndex) + readIndex += len + + result(index) = tag -> bytes + } + + readIndex = saved + result.toIndexedSeq + } + /** Perform operation op until the condition * readIndex == end is satisfied. * Concatenate results into a list. -- cgit v1.2.3