/* NSC -- new Scala compiler * Copyright 2005-2009 LAMP/EPFL * @author Martin Odersky */ // $Id: ShowPickled.scala 18387 2009-07-24 15:28:37Z odersky $ package scala.tools.nsc package util import java.io.{File, FileInputStream, PrintStream, IOException} import java.lang.Long.toHexString import java.lang.Float.intBitsToFloat import java.lang.Double.longBitsToDouble import symtab.{Flags, Names} import symtab.classfile.{PickleBuffer, PickleFormat} object ShowPickled extends Names { import PickleFormat._ def tag2string(tag: Int): String = tag match { case TERMname => "TERMname" case TYPEname => "TYPEname" case NONEsym => "NONEsym" case TYPEsym => "TYPEsym" case ALIASsym => "ALIASsym" case CLASSsym => "CLASSsym" case MODULEsym => "MODULEsym" case VALsym => "VALsym" case EXTref => "EXTref" case EXTMODCLASSref => "EXTMODCLASSref" case NOtpe => "NOtpe" case NOPREFIXtpe => "NOPREFIXtpe" case THIStpe => "THIStpe" case SINGLEtpe => "SINGLEtpe" case CONSTANTtpe => "CONSTANTtpe" case TYPEREFtpe => "TYPEREFtpe" case TYPEBOUNDStpe => "TYPEBOUNDStpe" case REFINEDtpe => "REFINEDtpe" case CLASSINFOtpe => "CLASSINFOtpe" case METHODtpe => "METHODtpe" case POLYtpe => "POLYtpe" case LITERALunit => "LITERALunit" case LITERALboolean => "LITERALboolean" case LITERALbyte => "LITERALbyte" case LITERALshort => "LITERALshort" case LITERALchar => "LITERALchar" case LITERALint => "LITERALint" case LITERALlong => "LITERALlong" case LITERALfloat => "LITERALfloat" case LITERALdouble => "LITERALdouble" case LITERALstring => "LITERALstring" case LITERALnull => "LITERALnull" case LITERALclass => "LITERALclass" case CHILDREN => "CHILDREN" case _ => "***BAD TAG***(" + tag + ")" } def printFile(buf: PickleBuffer, out: PrintStream) { out.println("Version " + buf.readNat() + "." + buf.readNat()) val index = buf.createIndex def printNameRef() { val x = buf.readNat() val savedIndex = buf.readIndex buf.readIndex = index(x) val tag = buf.readByte() val len = buf.readNat() out.print(" " + x + "(" + newTermName(buf.bytes, buf.readIndex, len) + ")") buf.readIndex = savedIndex } def printNat() = out.print(" " + buf.readNat()) def printSymbolRef() = printNat() def printTypeRef() = printNat() def printConstantRef() = printNat() def printSymInfo() { printNameRef() printSymbolRef() val pflags = buf.readLongNat() out.print(" " + toHexString(pflags) + "[" + Flags.flagsToString(Flags.pickledToRawFlags(pflags)) + "] ") printTypeRef() } def printEntry(i: Int) { buf.readIndex = index(i) out.print(i + "," + buf.readIndex + ": ") val tag = buf.readByte() out.print(tag2string(tag)) val len = buf.readNat() val end = len + buf.readIndex out.print(" " + len + ":") tag match { case TERMname => out.print(" ") out.print(newTermName(buf.bytes, buf.readIndex, len).toString()) buf.readIndex = end case TYPEname => out.print(" ") out.print(newTypeName(buf.bytes, buf.readIndex, len)) buf.readIndex = end case TYPEsym | ALIASsym | CLASSsym | MODULEsym | VALsym => printSymInfo() if (tag == CLASSsym && (buf.readIndex < end)) printTypeRef() case EXTref | EXTMODCLASSref => printNameRef() if (buf.readIndex < end) { printSymbolRef() } case THIStpe => printSymbolRef() case SINGLEtpe => printTypeRef(); printSymbolRef() case CONSTANTtpe => printTypeRef(); printConstantRef() case TYPEREFtpe => printTypeRef(); printSymbolRef(); buf.until(end, printTypeRef) case TYPEBOUNDStpe => printTypeRef(); printTypeRef() case REFINEDtpe => printSymbolRef(); buf.until(end, printTypeRef) case CLASSINFOtpe => printSymbolRef(); buf.until(end, printTypeRef) case METHODtpe => printTypeRef(); buf.until(end, printTypeRef) case POLYtpe => printTypeRef(); buf.until(end, printSymbolRef) case LITERALboolean => out.print(if (buf.readLong(len) == 0) " false" else " true") case LITERALbyte => out.print(" " + buf.readLong(len).asInstanceOf[Byte]) case LITERALshort => out.print(" " + buf.readLong(len).asInstanceOf[Short]) case LITERALchar => out.print(" " + buf.readLong(len).asInstanceOf[Char]) case LITERALint => out.print(" " + buf.readLong(len).asInstanceOf[Int]) case LITERALlong => out.print(" " + buf.readLong(len)) case LITERALfloat => out.print(" " + intBitsToFloat(buf.readLong(len).asInstanceOf[Int])) case LITERALdouble => out.print(" " + longBitsToDouble(buf.readLong(len))) case LITERALstring => printNameRef() case LITERALnull => out.print(" <null>") case LITERALclass => printTypeRef() case CHILDREN => printSymbolRef(); buf.until(end, printSymbolRef) case _ => } out.println() if (buf.readIndex != end) out.println("BAD ENTRY END: , computed = " + end + ", factual = " + buf.readIndex) } for (i <- 0 until index.length) printEntry(i) } def main(args: Array[String]) { val file = new File(args(0)) try { val stream = new FileInputStream(file) val data = new Array[Byte](stream.available()) stream.read(data) val pickle = new PickleBuffer(data, 0, data.length) printFile(pickle, Console.out) } catch { case ex: IOException => Console.println("cannot read " + file + ": " + ex.getMessage()) } } }