PageRenderTime 396ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/src/scalap/scala/tools/scalap/Main.scala

https://github.com/benjaminjackman/scala
Scala | 292 lines | 221 code | 16 blank | 55 comment | 51 complexity | aa85983b0161f2532dff994b85d15dcb MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /* ___ ____ ___ __ ___ ___
  2. ** / _// __// _ | / / / _ | / _ \ Scala classfile decoder
  3. ** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2010, LAMP/EPFL
  4. ** /____/\___/_/ |_/____/_/ |_/_/ http://scala-lang.org/
  5. **
  6. */
  7. // $Id$
  8. package scala.tools.scalap
  9. import java.io.{File, PrintStream, OutputStreamWriter, ByteArrayOutputStream}
  10. import scalax.rules.scalasig._
  11. import tools.nsc.io.AbstractFile
  12. import tools.nsc.util.{ClassPath, JavaClassPath}
  13. /**The main object used to execute scalap on the command-line.
  14. *
  15. * @author Matthias Zenger, Stephane Micheloud, Burak Emir, Ilya Sergey
  16. */
  17. object Main {
  18. val SCALA_SIG = "ScalaSig"
  19. val versionMsg = "Scala classfile decoder " +
  20. Properties.versionString + " -- " +
  21. Properties.copyrightString + "\n"
  22. /**Verbose program run?
  23. */
  24. var verbose = false
  25. var printPrivates = false
  26. /**Prints usage information for scalap.
  27. */
  28. def usage {
  29. Console.println("usage: scalap {<option>} <name>")
  30. Console.println("where <option> is")
  31. Console.println(" -private print private definitions")
  32. Console.println(" -verbose print out additional information")
  33. Console.println(" -version print out the version number of scalap")
  34. Console.println(" -help display this usage message")
  35. Console.println(" -classpath <path> specify where to find user class files")
  36. Console.println(" -cp <path> specify where to find user class files")
  37. }
  38. def isScalaFile(bytes: Array[Byte]): Boolean = {
  39. val byteCode = ByteCode(bytes)
  40. val classFile = ClassFileParser.parse(byteCode)
  41. classFile.attribute("ScalaSig").isDefined
  42. }
  43. /**Processes the given Java class file.
  44. *
  45. * @param clazz the class file to be processed.
  46. */
  47. def processJavaClassFile(clazz: Classfile) {
  48. // construct a new output stream writer
  49. val out = new OutputStreamWriter(Console.out)
  50. val writer = new JavaWriter(clazz, out)
  51. // print the class
  52. writer.printClass
  53. out.flush()
  54. }
  55. def isPackageObjectFile(s: String) = s != null && (s.endsWith(".package") || s == "package")
  56. def parseScalaSignature(scalaSig: ScalaSig, isPackageObject: Boolean) = {
  57. val baos = new ByteArrayOutputStream
  58. val stream = new PrintStream(baos)
  59. val syms = scalaSig.topLevelClasses ::: scalaSig.topLevelObjects
  60. syms.head.parent match {
  61. //Partial match
  62. case Some(p) if (p.name != "<empty>") => {
  63. val path = p.path
  64. if (!isPackageObject) {
  65. stream.print("package ");
  66. stream.print(path);
  67. stream.print("\n")
  68. } else {
  69. val i = path.lastIndexOf(".")
  70. if (i > 0) {
  71. stream.print("package ");
  72. stream.print(path.substring(0, i))
  73. stream.print("\n")
  74. }
  75. }
  76. }
  77. case _ =>
  78. }
  79. // Print classes
  80. val printer = new ScalaSigPrinter(stream, printPrivates)
  81. for (c <- syms) {
  82. printer.printSymbol(c)
  83. }
  84. baos.toString
  85. }
  86. def decompileScala(bytes: Array[Byte], isPackageObject: Boolean) = {
  87. val byteCode = ByteCode(bytes)
  88. val classFile = ClassFileParser.parse(byteCode)
  89. classFile.attribute(SCALA_SIG).map(_.byteCode).map(ScalaSigAttributeParsers.parse) match {
  90. case Some(scalaSig) => Console.println(parseScalaSignature(scalaSig, isPackageObject))
  91. case None => //Do nothing
  92. }
  93. }
  94. /**Executes scalap with the given arguments and classpath for the
  95. * class denoted by <code>classname</code>.
  96. *
  97. * @param args...
  98. * @param path...
  99. * @param classname...
  100. */
  101. def process(args: Arguments, path: ClassPath[AbstractFile])(classname: String): Unit = {
  102. // find the classfile
  103. val encName = Names.encode(
  104. if (classname == "scala.AnyRef") "java.lang.Object"
  105. else classname)
  106. val cls = path.findClass(encName)
  107. if (cls.isDefined && cls.get.binary.isDefined) {
  108. val cfile = cls.get.binary.get
  109. if (verbose) {
  110. Console.println(Console.BOLD + "FILENAME" + Console.RESET + " = " + cfile.path)
  111. }
  112. val bytes = cfile.toByteArray
  113. if (isScalaFile(bytes)) {
  114. decompileScala(bytes, isPackageObjectFile(encName))
  115. } else {
  116. // construct a reader for the classfile content
  117. val reader = new ByteArrayReader(cfile.toByteArray)
  118. // parse the classfile
  119. val clazz = new Classfile(reader)
  120. processJavaClassFile(clazz)
  121. }
  122. // if the class corresponds to the artificial class scala.All.
  123. // (to be removed after update of the STARR libraries)
  124. } else if (classname == "scala.All") {
  125. Console.println("package scala")
  126. Console.println("/* Deprecated. Use scala.Nothing instead. */")
  127. Console.println("sealed abstract class All")
  128. // if the class corresponds to the artificial class scala.AllRef.
  129. // (to be removed after update of the STARR libraries)
  130. } else if (classname == "scala.AllRef") {
  131. Console.println("package scala")
  132. Console.println("/* Deprecated. Use scala.Null instead. */")
  133. Console.println("sealed abstract class AllRef")
  134. // if the class corresponds to the artificial class scala.Any.
  135. // (see member list in class scala.tool.nsc.symtab.Definitions)
  136. } else if (classname == "scala.Any") {
  137. Console.println("package scala")
  138. Console.println("class Any {")
  139. Console.println(" final def ==(scala.Any): scala.Boolean")
  140. Console.println(" final def !=(scala.Any): Boolean")
  141. Console.println(" def equals(scala.Any): scala.Boolean")
  142. Console.println(" def hashCode(): scala.Int")
  143. Console.println(" def toString(): java.lang.String")
  144. Console.println(" final def isInstanceOf[a]: scala.Boolean")
  145. Console.println(" final def asInstanceOf[a]: a")
  146. Console.println("}")
  147. // if the class corresponds to the artificial class scala.AnyRef.
  148. } else if (classname == "scala.AnyRef") {
  149. Console.println("package scala")
  150. Console.println("class AnyRef extends Any {")
  151. Console.println(" def equals(scala.Any): scala.Boolean")
  152. Console.println(" def hashCode(): scala.Int")
  153. Console.println(" def toString(): java.lang.String")
  154. Console.println("}")
  155. // if the class corresponds to the artificial class scala.AnyVal.
  156. } else if (classname == "scala.AnyVal") {
  157. Console.println("package scala")
  158. Console.println("sealed class AnyVal extends Any")
  159. // if the class corresponds to the artificial class scala.Boolean.
  160. } else if (classname == "scala.Boolean") {
  161. Console.println("package scala")
  162. Console.println("sealed abstract class Boolean extends AnyVal {")
  163. Console.println(" def &&(p: => scala.Boolean): scala.Boolean // boolean and")
  164. Console.println(" def ||(p: => scala.Boolean): scala.Boolean // boolean or")
  165. Console.println(" def & (x: scala.Boolean): scala.Boolean // boolean strict and")
  166. Console.println(" def | (x: scala.Boolean): scala.Boolean // boolean stric or")
  167. Console.println(" def ==(x: scala.Boolean): scala.Boolean // boolean equality")
  168. Console.println(" def !=(x: scala.Boolean): scala.Boolean // boolean inequality")
  169. Console.println(" def !: scala.Boolean // boolean negation")
  170. Console.println("}")
  171. // if the class corresponds to the artificial class scala.Int.
  172. } else if (classname == "scala.Int") {
  173. Console.println("package scala")
  174. Console.println("sealed abstract class Int extends AnyVal {")
  175. Console.println(" def ==(that: scala.Double): scala.Boolean")
  176. Console.println(" def ==(that: scala.Float): scala.Boolean")
  177. Console.println(" def ==(that: scala.Long): scala.Boolean")
  178. Console.println(" def ==(that: scala.Int): scala.Boolean")
  179. Console.println(" def ==(that: scala.Short): scala.Boolean")
  180. Console.println(" def ==(that: scala.Byte): scala.Boolean")
  181. Console.println(" def ==(that: scala.Char): scala.Boolean")
  182. Console.println(" /* analogous for !=, <, >, <=, >= */")
  183. Console.println
  184. Console.println(" def + (that: scala.Double): scala.Double // double addition")
  185. Console.println(" def + (that: scala.Float): scala.Float // float addition")
  186. Console.println(" def + (that: scala.Long): scala.Long // long addition")
  187. Console.println(" def + (that: scala.Int): scala.Int // int addition")
  188. Console.println(" def + (that: scala.Short): scala.Int // int addition")
  189. Console.println(" def + (that: scala.Byte): scala.Int // int addition")
  190. Console.println(" def + (that: scala.Char): scala.Int // int addition")
  191. Console.println(" /* analogous for -, *, /, % */")
  192. Console.println
  193. Console.println(" def & (that: scala.Long): scala.Long // long bitwise and")
  194. Console.println(" def & (that: scala.Int): scala.Int // int bitwise and")
  195. Console.println(" def & (that: scala.Short): scala.Int // int bitwise and")
  196. Console.println(" def & (that: scala.Byte): scala.Int // int bitwise and")
  197. Console.println(" def & (that: scala.Char): scala.Int // int bitwise and")
  198. Console.println(" /* analogous for |, ^ */")
  199. Console.println
  200. Console.println(" def <<(cnt: scala.Int): scala.Int // int left shift")
  201. Console.println(" def <<(cnt: scala.Long): scala.Int // long left shift")
  202. Console.println(" /* analogous for >>, >>> */")
  203. Console.println
  204. Console.println(" def + : scala.Int // int identity")
  205. Console.println(" def - : scala.Int // int negation")
  206. Console.println(" def ~ : scala.Int // int bitwise negation")
  207. Console.println
  208. Console.println(" def toByte: scala.Byte // convert to Byte")
  209. Console.println(" def toShort: scala.Short // convert to Short")
  210. Console.println(" def toChar: scala.Char // convert to Char")
  211. Console.println(" def toInt: scala.Int // convert to Int")
  212. Console.println(" def toLong: scala.Long // convert to Long")
  213. Console.println(" def toFloat: scala.Float // convert to Float")
  214. Console.println(" def toDouble: scala.Double // convert to Double")
  215. Console.println("}")
  216. // if the class corresponds to the artificial class scala.Nothing.
  217. } else if (classname == "scala.Nothing") {
  218. Console.println("package scala")
  219. Console.println("sealed abstract class Nothing")
  220. // if the class corresponds to the artificial class scala.Null.
  221. } else if (classname == "scala.Null") {
  222. Console.println("package scala")
  223. Console.println("sealed abstract class Null")
  224. } else
  225. Console.println("class/object " + classname + " not found.")
  226. }
  227. /**The main method of this object.
  228. */
  229. def main(args: Array[String]) {
  230. // print usage information if there is no command-line argument
  231. if (args.length == 0)
  232. usage
  233. // otherwise parse the arguments...
  234. else {
  235. val arguments = Arguments.Parser('-')
  236. .withOption("-private")
  237. .withOption("-verbose")
  238. .withOption("-version")
  239. .withOption("-help")
  240. .withOptionalArg("-classpath")
  241. .withOptionalArg("-cp")
  242. .parse(args);
  243. if (arguments contains "-version")
  244. Console.println(versionMsg)
  245. if (arguments contains "-help")
  246. usage
  247. verbose = arguments contains "-verbose"
  248. printPrivates = arguments contains "-private"
  249. // construct a custom class path
  250. val path = arguments.getArgument("-classpath") match {
  251. case None => arguments.getArgument("-cp") match {
  252. case None => EmptyClasspath
  253. case Some(path) => new JavaClassPath("", "", path, "", "", false)
  254. }
  255. case Some(path) => new JavaClassPath("", "", path, "", "", false)
  256. }
  257. // print the classpath if output is verbose
  258. if (verbose) {
  259. Console.println(Console.BOLD + "CLASSPATH" + Console.RESET + " = " + path)
  260. }
  261. // process all given classes
  262. arguments.getOthers.foreach(process(arguments, path))
  263. }
  264. }
  265. object EmptyClasspath extends ClassPath[AbstractFile] {
  266. import tools.nsc.util.ClassRep
  267. /**
  268. * The short name of the package (without prefix)
  269. */
  270. def name: String = ""
  271. val classes: List[ClassRep[AbstractFile]] = Nil
  272. val packages: List[ClassPath[AbstractFile]] = Nil
  273. val sourcepaths: List[AbstractFile] = Nil
  274. def isOptimized = false
  275. }
  276. }