summaryrefslogtreecommitdiff
path: root/src/scalap
diff options
context:
space:
mode:
Diffstat (limited to 'src/scalap')
-rw-r--r--src/scalap/scala/tools/scalap/Classfile.scala1
-rw-r--r--src/scalap/scala/tools/scalap/Decode.scala43
-rw-r--r--src/scalap/scala/tools/scalap/Main.scala58
-rw-r--r--src/scalap/scala/tools/scalap/Properties.scala1
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/Functors.scala4
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/Memoisable.scala2
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/Result.scala10
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/Rules.scala2
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/SeqRule.scala4
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala57
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala11
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala252
12 files changed, 304 insertions, 141 deletions
diff --git a/src/scalap/scala/tools/scalap/Classfile.scala b/src/scalap/scala/tools/scalap/Classfile.scala
index 44f687bd85..c4f273c5aa 100644
--- a/src/scalap/scala/tools/scalap/Classfile.scala
+++ b/src/scalap/scala/tools/scalap/Classfile.scala
@@ -26,6 +26,7 @@ class Classfile(in: ByteArrayReader) {
val fields = readMembers(true)
val methods = readMembers(false)
val attribs = readAttribs
+ def scalaSigAttribute = attribs find (_.toString == Main.SCALA_SIG)
def readAttribs = {
val n = in.nextChar
diff --git a/src/scalap/scala/tools/scalap/Decode.scala b/src/scalap/scala/tools/scalap/Decode.scala
index d859ac5766..e9f9a390c5 100644
--- a/src/scalap/scala/tools/scalap/Decode.scala
+++ b/src/scalap/scala/tools/scalap/Decode.scala
@@ -10,7 +10,9 @@
package scala.tools.scalap
import scala.tools.scalap.scalax.rules.scalasig._
+import scala.tools.nsc.util.ScalaClassLoader
import scala.tools.nsc.util.ScalaClassLoader.getSystemLoader
+import Main.SCALA_SIG
/** Temporary decoder. This would be better off in the scala.tools.nsc
* but right now the compiler won't acknowledge scala.tools.scalap
@@ -23,15 +25,52 @@ object Decode {
case _ => NoSymbol
}
+ /** Return the classfile bytes representing the scala sig attribute.
+ */
+ def scalaSigBytes(name: String): Option[Array[Byte]] = scalaSigBytes(name, getSystemLoader())
+ def scalaSigBytes(name: String, classLoader: ScalaClassLoader): Option[Array[Byte]] = {
+ val bytes = classLoader.findBytesForClassName(name)
+ val reader = new ByteArrayReader(bytes)
+ val cf = new Classfile(reader)
+ cf.scalaSigAttribute map (_.data)
+ }
+
+ /** private[scala] so nobody gets the idea this is a supported interface.
+ */
+ private[scala] def caseParamNames(path: String): Option[List[String]] = {
+ val (outer, inner) = (path indexOf '$') match {
+ case -1 => (path, "")
+ case x => (path take x, path drop (x + 1))
+ }
+
+ for {
+ clazz <- getSystemLoader.tryToLoadClass[AnyRef](outer)
+ ssig <- ScalaSigParser.parse(clazz)
+ }
+ yield {
+ val f: PartialFunction[Symbol, List[String]] =
+ if (inner.isEmpty) {
+ case x: MethodSymbol if x.isCaseAccessor && (x.name endsWith " ") => List(x.name dropRight 1)
+ }
+ else {
+ case x: ClassSymbol if x.name == inner =>
+ val xs = x.children filter (child => child.isCaseAccessor && (child.name endsWith " "))
+ xs.toList map (_.name dropRight 1)
+ }
+
+ (ssig.symbols collect f).flatten toList
+ }
+ }
+
/** Returns a map of Alias -> Type for the given package.
*/
- def typeAliases(pkg: String) = {
+ private[scala] def typeAliases(pkg: String) = {
for {
clazz <- getSystemLoader.tryToLoadClass[AnyRef](pkg + ".package")
ssig <- ScalaSigParser.parse(clazz)
}
yield {
- val typeAliases = ssig.symbols partialMap { case x: AliasSymbol => x }
+ val typeAliases = ssig.symbols collect { case x: AliasSymbol => x }
Map(typeAliases map (x => (x.name, getAliasSymbol(x.infoType).path)): _*)
}
}
diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala
index 59c46df25f..69a91dafce 100644
--- a/src/scalap/scala/tools/scalap/Main.scala
+++ b/src/scalap/scala/tools/scalap/Main.scala
@@ -9,10 +9,14 @@
package scala.tools.scalap
-import java.io.{File, PrintStream, OutputStreamWriter, ByteArrayOutputStream}
+import java.io.{PrintStream, OutputStreamWriter, ByteArrayOutputStream}
import scalax.rules.scalasig._
-import tools.nsc.io.AbstractFile
-import tools.nsc.util.{ClassPath, JavaClassPath}
+import scalax.rules.scalasig.ClassFileParser.{ConstValueIndex, Annotation}
+import tools.nsc.util.{ ClassPath }
+import tools.util.PathResolver
+import ClassPath.DefaultJavaContext
+import tools.nsc.io.{PlainFile, AbstractFile}
+import scala.reflect.generic.ByteCodecs
/**The main object used to execute scalap on the command-line.
*
@@ -20,6 +24,9 @@ import tools.nsc.util.{ClassPath, JavaClassPath}
*/
object Main {
val SCALA_SIG = "ScalaSig"
+ val SCALA_SIG_ANNOTATION = "Lscala/reflect/ScalaSignature;"
+ val BYTES_VALUE = "bytes"
+
val versionMsg = "Scala classfile decoder " +
Properties.versionString + " -- " +
Properties.copyrightString + "\n"
@@ -33,7 +40,8 @@ object Main {
*/
def usage {
Console.println("usage: scalap {<option>} <name>")
- Console.println("where <option> is")
+ Console.println("where <name> is fully-qualified class name or <package_name>.package for package objects")
+ Console.println("and <option> is")
Console.println(" -private print private definitions")
Console.println(" -verbose print out additional information")
Console.println(" -version print out the version number of scalap")
@@ -94,17 +102,34 @@ object Main {
baos.toString
}
-
- def decompileScala(bytes: Array[Byte], isPackageObject: Boolean) = {
+ def decompileScala(bytes: Array[Byte], isPackageObject: Boolean): String = {
val byteCode = ByteCode(bytes)
val classFile = ClassFileParser.parse(byteCode)
classFile.attribute(SCALA_SIG).map(_.byteCode).map(ScalaSigAttributeParsers.parse) match {
- case Some(scalaSig) => Console.println(parseScalaSignature(scalaSig, isPackageObject))
- case None => //Do nothing
+ // No entries in ScalaSig attribute implies that the signature is stored in the annotation
+ case Some(ScalaSig(_, _, entries)) if entries.length == 0 => unpickleFromAnnotation(classFile, isPackageObject)
+ case Some(scalaSig) => parseScalaSignature(scalaSig, isPackageObject)
+ case None => ""
+ }
+ }
+
+ def unpickleFromAnnotation(classFile: ClassFile, isPackageObject: Boolean): String = {
+ import classFile._
+ classFile.annotation(SCALA_SIG_ANNOTATION) match {
+ case None => ""
+ case Some(Annotation(_, elements)) =>
+ val bytesElem = elements.find(elem => constant(elem.elementNameIndex) == BYTES_VALUE).get
+ val bytes = ((bytesElem.elementValue match {case ConstValueIndex(index) => constantWrapped(index)})
+ .asInstanceOf[StringBytesPair].bytes)
+ val length = ByteCodecs.decode(bytes)
+ val scalaSig = ScalaSigAttributeParsers.parse(ByteCode(bytes.take(length)))
+ parseScalaSignature(scalaSig, isPackageObject)
}
}
+
+
/**Executes scalap with the given arguments and classpath for the
* class denoted by <code>classname</code>.
*
@@ -125,7 +150,7 @@ object Main {
}
val bytes = cfile.toByteArray
if (isScalaFile(bytes)) {
- decompileScala(bytes, isPackageObjectFile(encName))
+ Console.println(decompileScala(bytes, isPackageObjectFile(encName)))
} else {
// construct a reader for the classfile content
val reader = new ByteArrayReader(cfile.toByteArray)
@@ -262,13 +287,8 @@ object Main {
verbose = arguments contains "-verbose"
printPrivates = arguments contains "-private"
// construct a custom class path
- val path = arguments.getArgument("-classpath") match {
- case None => arguments.getArgument("-cp") match {
- case None => EmptyClasspath
- case Some(path) => new JavaClassPath("", "", path, "", "")
- }
- case Some(path) => new JavaClassPath("", "", path, "", "")
- }
+ def cparg = List("-classpath", "-cp") map (arguments getArgument _) reduceLeft (_ orElse _)
+ val path = cparg map (PathResolver fromPathString _) getOrElse EmptyClasspath
// print the classpath if output is verbose
if (verbose) {
Console.println(Console.BOLD + "CLASSPATH" + Console.RESET + " = " + path)
@@ -279,12 +299,14 @@ object Main {
}
object EmptyClasspath extends ClassPath[AbstractFile] {
- import tools.nsc.util.ClassRep
/**
* The short name of the package (without prefix)
*/
def name: String = ""
- val classes: List[ClassRep[AbstractFile]] = Nil
+ def asURLs = Nil
+ def asClasspathString = ""
+ val context = DefaultJavaContext
+ val classes: List[ClassRep] = Nil
val packages: List[ClassPath[AbstractFile]] = Nil
val sourcepaths: List[AbstractFile] = Nil
}
diff --git a/src/scalap/scala/tools/scalap/Properties.scala b/src/scalap/scala/tools/scalap/Properties.scala
index f433737896..315b81cb3e 100644
--- a/src/scalap/scala/tools/scalap/Properties.scala
+++ b/src/scalap/scala/tools/scalap/Properties.scala
@@ -14,5 +14,4 @@ object Properties extends scala.util.PropertiesTrait
{
protected def propCategory = "decoder"
protected def pickJarBasedOn = classOf[Classfile]
- val cmdName = scala.tools.nsc.Properties.cmdName
}
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Functors.scala b/src/scalap/scala/tools/scalap/scalax/rules/Functors.scala
index aa95b48d44..aa852c1e63 100644
--- a/src/scalap/scala/tools/scalap/scalax/rules/Functors.scala
+++ b/src/scalap/scala/tools/scalap/scalax/rules/Functors.scala
@@ -60,7 +60,7 @@ trait Functors {
}
}
-/** One of the 'unit' definitions must be overriden in concrete subclasses */
+/** One of the 'unit' definitions must be overridden in concrete subclasses */
trait UnitFunctors extends Units with Functors {
def unit : M[Unit] = unit(())
def unit[A](a : => A) : M[A] = unit map { Unit => a }
@@ -73,7 +73,7 @@ trait Monoidals extends UnitFunctors {
implicit def app[A, B](fab : M[A => B]) = (fa : M[A]) => fa applyTo fab
implicit def appUnit[A, B](a2b : A => B) = app(unit(a2b))
- /** One of 'and' and 'applyTo' definitions must be overriden in concrete subclasses */
+ /** One of 'and' and 'applyTo' definitions must be overridden in concrete subclasses */
trait Monoidal[+A] extends Functor[A] { self : M[A] =>
def and[B](fb : => M[B]) : M[(A, B)] = ((a : A) => (b : B) => (a, b))(this)(fb)
def applyTo[B](fab : M[A => B]) : M[B] = fab and this map { case (f, a) => f(a) }
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Memoisable.scala b/src/scalap/scala/tools/scalap/scalax/rules/Memoisable.scala
index 1324ea695a..827c2dfff7 100644
--- a/src/scalap/scala/tools/scalap/scalax/rules/Memoisable.scala
+++ b/src/scalap/scala/tools/scalap/scalax/rules/Memoisable.scala
@@ -44,7 +44,7 @@ trait DefaultMemoisable extends Memoisable {
map.getOrElseUpdate(key, compute(key, a)).asInstanceOf[A]
}
- protected def compute[A](key : AnyRef, a : => A) = a match {
+ protected def compute[A](key : AnyRef, a : => A): Any = a match {
case success : Success[_, _] => onSuccess(key, success); success
case other =>
if(DefaultMemoisable.debug) println(key + " -> " + other)
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Result.scala b/src/scalap/scala/tools/scalap/scalax/rules/Result.scala
index 6befbb83c8..17ad4bd053 100644
--- a/src/scalap/scala/tools/scalap/scalax/rules/Result.scala
+++ b/src/scalap/scala/tools/scalap/scalax/rules/Result.scala
@@ -42,11 +42,11 @@ case class Success[+Out, +A](out : Out, value : A) extends Result[Out, A, Nothin
def toOption = Some(value)
- def map[B](f : A => B) = Success(out, f(value))
- def mapOut[Out2](f : Out => Out2) = Success(f(out), value)
- def map[Out2, B](f : (Out, A) => (Out2, B)) = f(out, value) match { case (out2, b) => Success(out2, b) }
- def flatMap[Out2, B](f : (Out, A) => Result[Out2, B, Nothing]) = f(out, value)
- def orElse[Out2 >: Out, B >: A](other : => Result[Out2, B, Nothing]) = this
+ def map[B](f : A => B) : Result[Out, B, Nothing] = Success(out, f(value))
+ def mapOut[Out2](f : Out => Out2) : Result[Out2, A, Nothing] = Success(f(out), value)
+ def map[Out2, B](f : (Out, A) => (Out2, B)) : Success[Out2, B] = f(out, value) match { case (out2, b) => Success(out2, b) }
+ def flatMap[Out2, B](f : (Out, A) => Result[Out2, B, Nothing]) : Result[Out2, B, Nothing]= f(out, value)
+ def orElse[Out2 >: Out, B >: A](other : => Result[Out2, B, Nothing]) : Result[Out2, B, Nothing] = this
}
sealed abstract class NoSuccess[+X] extends Result[Nothing, Nothing, X] {
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala b/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala
index 4e8ddc8dbe..43f9c20b1d 100644
--- a/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala
+++ b/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala
@@ -98,7 +98,7 @@ trait StateRules {
def nil = unit(Nil)
def none = unit(None)
- /** Create a rule that suceeds if f(in) is true. */
+ /** Create a rule that identities if f(in) is true. */
def cond(f : S => Boolean) = get filter f
/** Create a rule that succeeds if all of the given rules succeed.
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/SeqRule.scala b/src/scalap/scala/tools/scalap/scalax/rules/SeqRule.scala
index 54f2c70bdc..34f52a1e19 100644
--- a/src/scalap/scala/tools/scalap/scalax/rules/SeqRule.scala
+++ b/src/scalap/scala/tools/scalap/scalax/rules/SeqRule.scala
@@ -24,7 +24,7 @@ class InRule[In, +Out, +A, +X](rule : Rule[In, Out, A, X]) {
in : In => f(rule(in))(in)
}
- /** Creates a rule that suceeds only if the original rule would fail on the given context. */
+ /** Creates a rule that succeeds only if the original rule would fail on the given context. */
def unary_! : Rule[In, In, Unit, Nothing] = mapRule {
case Success(_, _) => in : In => Failure
case _ => in : In => Success(in, ())
@@ -82,7 +82,7 @@ class SeqRule[S, +A, +X](rule : Rule[S, S, A, X]) {
/** Repeats this rule num times */
def times(num : Int) : Rule[S, S, Seq[A], X] = from[S] {
- val result = new collection.mutable.GenericArray[A](num)
+ val result = new collection.mutable.ArraySeq[A](num)
// more compact using HoF but written this way so it's tail-recursive
def rep(i : Int, in : S) : Result[S, Seq[A], X] = {
if (i == num) Success(in, result)
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala
index 37bfa9cfea..01652a50b9 100644
--- a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala
+++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala
@@ -9,8 +9,6 @@ import java.io.IOException
import scala._
import scala.Predef._
-import scalax.rules.Error
-
object ByteCode {
def apply(bytes : Array[Byte]) = new ByteCode(bytes, 0, bytes.length)
@@ -62,11 +60,23 @@ class ByteCode(val bytes : Array[Byte], val pos : Int, val length : Int) {
def toInt = fold(0) { (x, b) => (x << 8) + (b & 0xFF)}
def toLong = fold(0L) { (x, b) => (x << 8) + (b & 0xFF)}
- def toUTF8String = io.Codec toUTF8 (bytes drop pos take length) mkString
+ /**
+ * Transforms array subsequence of the current buffer into the UTF8 String and
+ * stores and array of bytes for the decompiler
+ */
+ def toUTF8StringAndBytes = {
+ val chunk: Array[Byte] = bytes drop pos take length
+ StringBytesPair(io.Codec.toUTF8(chunk).mkString, chunk)
+ }
def byte(i : Int) = bytes(pos) & 0xFF
}
+/**
+ * The wrapper for decode UTF-8 string
+ */
+case class StringBytesPair(string: String, bytes: Array[Byte])
+
/** Provides rules for parsing byte-code.
*/
trait ByteCodeReader extends RulesWithState {
@@ -84,6 +94,7 @@ trait ByteCodeReader extends RulesWithState {
object ClassFileParser extends ByteCodeReader {
def parse(byteCode : ByteCode) = expect(classFile)(byteCode)
+ def parseAnnotations(byteCode: ByteCode) = expect(annotations)(byteCode)
val magicNumber = (u4 filter (_ == 0xCAFEBABE)) | error("Not a valid class file")
val version = u2 ~ u2 ^^ { case minor ~ major => (major, minor) }
@@ -91,7 +102,7 @@ object ClassFileParser extends ByteCodeReader {
// NOTE currently most constants just evaluate to a string description
// TODO evaluate to useful values
- val utf8String = (u2 >> bytes) ^^ add1 { raw => pool => raw.toUTF8String }
+ val utf8String = (u2 >> bytes) ^^ add1 { raw => pool => raw.toUTF8StringAndBytes }
val intConstant = u4 ^^ add1 { x => pool => x }
val floatConstant = bytes(4) ^^ add1 { raw => pool => "Float: TODO" }
val longConstant = bytes(8) ^^ add2 { raw => pool => raw.toLong }
@@ -119,9 +130,32 @@ object ClassFileParser extends ByteCodeReader {
val interfaces = u2 >> u2.times
+ // bytes are parametrizes by the length, declared in u4 section
val attribute = u2 ~ (u4 >> bytes) ^~^ Attribute
+ // parse attributes u2 times
val attributes = u2 >> attribute.times
+ // parse runtime-visible annotations
+ abstract class ElementValue
+ case class AnnotationElement(elementNameIndex: Int, elementValue: ElementValue)
+ case class ConstValueIndex(index: Int) extends ElementValue
+ case class EnumConstValue(typeNameIndex: Int, constNameIndex: Int) extends ElementValue
+ case class ClassInfoIndex(index: Int) extends ElementValue
+ case class Annotation(typeIndex: Int, elementValuePairs: Seq[AnnotationElement]) extends ElementValue
+ case class ArrayValue(values: Seq[ElementValue]) extends ElementValue
+
+ def element_value: Parser[ElementValue] = u1 >> {
+ case 'B'|'C'|'D'|'F'|'I'|'J'|'S'|'Z'|'s' => u2 ^^ ConstValueIndex
+ case 'e' => u2 ~ u2 ^~^ EnumConstValue
+ case 'c' => u2 ^^ ClassInfoIndex
+ case '@' => annotation //nested annotation
+ case '[' => u2 >> element_value.times ^^ ArrayValue
+ }
+
+ val element_value_pair = u2 ~ element_value ^~^ AnnotationElement
+ val annotation: Parser[Annotation] = u2 ~ (u2 >> element_value_pair.times) ^~^ Annotation
+ val annotations = u2 >> annotation.times
+
val field = u2 ~ u2 ~ u2 ~ attributes ^~~~^ Field
val fields = u2 >> field.times
@@ -153,9 +187,20 @@ case class ClassFile(
def superClass = constant(header.superClassIndex)
def interfaces = header.interfaces.map(constant)
- def constant(index : Int) = header.constants(index)
+ def constant(index : Int) = header.constants(index) match {
+ case StringBytesPair(str, _) => str
+ case z => z
+ }
+
+ def constantWrapped(index: Int) = header.constants(index)
+
+ def attribute(name : String) = attributes.find {attrib => constant(attrib.nameIndex) == name }
+
+ val RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"
+ def annotations = (attributes.find(attr => constant(attr.nameIndex) == RUNTIME_VISIBLE_ANNOTATIONS)
+ .map(attr => ClassFileParser.parseAnnotations(attr.byteCode)))
- def attribute(name : String) = attributes.find { attrib => constant(attrib.nameIndex) == name }
+ def annotation(name: String) = annotations.flatMap(seq => seq.find(annot => constant(annot.typeIndex) == name))
}
case class Attribute(nameIndex : Int, byteCode : ByteCode)
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala
index a97494ed6d..e0f95c8bbb 100644
--- a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala
+++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala
@@ -55,7 +55,7 @@ object ScalaSigAttributeParsers extends ByteCodeReader {
val symtab = nat >> entry.times
val scalaSig = nat ~ nat ~ symtab ^~~^ ScalaSig
- val utf8 = read(_ toUTF8String)
+ val utf8 = read(x => x.toUTF8StringAndBytes.string)
val longValue = read(_ toLong)
}
@@ -164,21 +164,21 @@ object ScalaSigEntryParsers extends RulesWithState with MemoisableRules {
* | 5 ALIASsym len_Nat SymbolInfo
* | 6 CLASSsym len_Nat SymbolInfo [thistype_Ref]
* | 7 MODULEsym len_Nat SymbolInfo
- * | 8 VALsym len_Nat [defaultGetter_Ref] SymbolInfo [alias_Ref]
+ * | 8 VALsym len_Nat [defaultGetter_Ref /* no longer needed*/] SymbolInfo [alias_Ref]
* | 9 EXTref len_Nat name_Ref [owner_Ref]
* | 10 EXTMODCLASSref len_Nat name_Ref [owner_Ref]
* | 11 NOtpe len_Nat
* | 12 NOPREFIXtpe len_Nat
* | 13 THIStpe len_Nat sym_Ref
* | 14 SINGLEtpe len_Nat type_Ref sym_Ref
- * | 15 CONSTANTtpe len_Nat type_Ref constant_Ref
+ * | 15 CONSTANTtpe len_Nat constant_Ref
* | 16 TYPEREFtpe len_Nat type_Ref sym_Ref {targ_Ref}
* | 17 TYPEBOUNDStpe len_Nat tpe_Ref tpe_Ref
* | 18 REFINEDtpe len_Nat classsym_Ref {tpe_Ref}
* | 19 CLASSINFOtpe len_Nat classsym_Ref {tpe_Ref}
* | 20 METHODtpe len_Nat tpe_Ref {sym_Ref}
* | 21 POLYTtpe len_Nat tpe_Ref {sym_Ref}
- * | 22 IMPLICITMETHODtpe len_Nat tpe_Ref {tpe_Ref}
+ * | 22 IMPLICITMETHODtpe len_Nat tpe_Ref {sym_Ref} /* no longer needed */
* | 52 SUPERtpe len_Nat tpe_Ref tpe_Ref
* | 24 LITERALunit len_Nat
* | 25 LITERALboolean len_Nat value_Long
@@ -195,13 +195,12 @@ object ScalaSigEntryParsers extends RulesWithState with MemoisableRules {
* | 36 LITERALenum len_Nat sym_Ref
* | 40 SYMANNOT len_Nat sym_Ref AnnotInfoBody
* | 41 CHILDREN len_Nat sym_Ref {sym_Ref}
- * | 42 ANNOTATEDtpe len_Nat [sym_Ref] tpe_Ref {annotinfo_Ref}
+ * | 42 ANNOTATEDtpe len_Nat [sym_Ref /* no longer needed */] tpe_Ref {annotinfo_Ref}
* | 43 ANNOTINFO len_Nat AnnotInfoBody
* | 44 ANNOTARGARRAY len_Nat {constAnnotArg_Ref}
* | 47 DEBRUIJNINDEXtpe len_Nat level_Nat index_Nat
* | 48 EXISTENTIALtpe len_Nat type_Ref {symbol_Ref}
*/
-
val noSymbol = 3 -^ NoSymbol
val typeSymbol = symbolEntry(4) ^^ TypeSymbol as "typeSymbol"
val aliasSymbol = symbolEntry(5) ^^ AliasSymbol as "alias"
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala
index da268f4e44..26b01634f5 100644
--- a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala
+++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala
@@ -16,6 +16,7 @@ import java.io.{PrintStream, ByteArrayOutputStream}
import java.util.regex.Pattern
import scala.tools.scalap.scalax.util.StringUtil
+import reflect.NameTransformer
class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
import stream._
@@ -24,13 +25,24 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
case class TypeFlags(printRep: Boolean)
- def printSymbol(symbol: Symbol) { printSymbol(0, symbol) }
+ def printSymbol(symbol: Symbol) {printSymbol(0, symbol)}
+
+ def printSymbolAttributes(s: Symbol, onNewLine: Boolean, indent: => Unit) = s match {
+ case t: SymbolInfoSymbol => {
+ for (a <- t.attributes) {
+ indent; print(toString(a))
+ if (onNewLine) print("\n") else print(" ")
+ }
+ }
+ case _ =>
+ }
def printSymbol(level: Int, symbol: Symbol) {
if (!symbol.isLocal &&
- !(symbol.isPrivate && !printPrivates)) {
+ !(symbol.isPrivate && !printPrivates)) {
def indent() {for (i <- 1 to level) print(" ")}
+ printSymbolAttributes(symbol, true, indent)
symbol match {
case o: ObjectSymbol =>
if (!isCaseClassObject(o)) {
@@ -50,8 +62,9 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
case a: AliasSymbol =>
indent
printAlias(level, a)
- case t: TypeSymbol =>
- ()
+ case t: TypeSymbol if !t.isParam && !t.name.matches("_\\$\\d+")=>
+ indent
+ printTypeSymbol(level, t)
case s =>
}
}
@@ -82,11 +95,20 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
}
def printModifiers(symbol: Symbol) {
+ // print private access modifier
+ if (symbol.isPrivate) print("private ")
+ else if (symbol.isProtected) print("protected ")
+ else symbol match {
+ case sym: SymbolInfoSymbol => sym.symbolInfo.privateWithin match {
+ case Some(t: Symbol) => print("private[" + t.name +"] ")
+ case _ =>
+ }
+ case _ =>
+ }
+
if (symbol.isSealed) print("sealed ")
if (symbol.isImplicit) print("implicit ")
if (symbol.isFinal && !symbol.isInstanceOf[ObjectSymbol]) print("final ")
- if (symbol.isPrivate) print("private ")
- else if (symbol.isProtected) print("protected ")
if (symbol.isOverride) print("override ")
if (symbol.isAbstract) symbol match {
case c@(_: ClassSymbol | _: ObjectSymbol) if !c.isTrait => print("abstract ")
@@ -98,30 +120,34 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
private def refinementClass(c: ClassSymbol) = c.name == "<refinement>"
def printClass(level: Int, c: ClassSymbol) {
- printModifiers(c)
- val defaultConstructor = if (c.isCase) getPrinterByConstructor(c) else ""
- if (c.isTrait) print("trait ") else print("class ")
- print(processName(c.name))
- val it = c.infoType
- val classType = it match {
- case PolyType(typeRef, symbols) => PolyTypeWithCons(typeRef, symbols, defaultConstructor)
- case _ => it
- }
- printType(classType)
- print(" {")
- //Print class selftype
- c.selfType match {
- case Some(t: Type) => print("\n"); print(" this : " + toString(t) + " =>")
- case None =>
+ if (c.name == "<local child>" /*scala.tools.nsc.symtab.StdNames.LOCALCHILD.toString()*/ ) {
+ print("\n")
+ } else {
+ printModifiers(c)
+ val defaultConstructor = if (c.isCase) getPrinterByConstructor(c) else ""
+ if (c.isTrait) print("trait ") else print("class ")
+ print(processName(c.name))
+ val it = c.infoType
+ val classType = it match {
+ case PolyType(typeRef, symbols) => PolyTypeWithCons(typeRef, symbols, defaultConstructor)
+ case _ => it
+ }
+ printType(classType)
+ print(" {")
+ //Print class selftype
+ c.selfType match {
+ case Some(t: Type) => print("\n"); print(" this : " + toString(t) + " =>")
+ case None =>
+ }
+ print("\n")
+ printChildren(level, c)
+ printWithIndent(level, "}\n")
}
- print("\n")
- printChildren(level, c)
- printWithIndent(level, "}\n")
}
def getPrinterByConstructor(c: ClassSymbol) = {
- c.children.find{
- case m : MethodSymbol if m.name == CONSTRUCTOR_NAME => true
+ c.children.find {
+ case m: MethodSymbol if m.name == CONSTRUCTOR_NAME => true
case _ => false
} match {
case Some(m: MethodSymbol) =>
@@ -170,7 +196,7 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
if (res.length > 1) StringUtil.decapitalize(res.substring(0, 1)) else res.toLowerCase
})
- def printMethodType(t: Type, printResult: Boolean)(implicit cont : => Unit): Unit = {
+ def printMethodType(t: Type, printResult: Boolean)(cont: => Unit): Unit = {
def _pmt(mt: Type {def resultType: Type; def paramSymbols: Seq[Symbol]}) = {
@@ -179,9 +205,9 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
case _ => "^___^"
})
- // Printe parameter clauses
+ // Print parameter clauses
print(paramEntries.mkString(
- "(" + (mt match {case _ : ImplicitMethodType => "implicit "; case _ => ""})
+ "(" + (mt match {case _: ImplicitMethodType => "implicit "; case _ => ""})
, ", ", ")"))
// Print result type
@@ -215,13 +241,14 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
val n = m.name
if (underCaseClass(m) && n == CONSTRUCTOR_NAME) return
+ if (n.matches(".+\\$default\\$\\d+")) return // skip default function parameters
if (n.startsWith("super$")) return // do not print auxiliary qualified super accessors
if (m.isAccessor && n.endsWith("_$eq")) return
indent()
printModifiers(m)
if (m.isAccessor) {
val indexOfSetter = m.parent.get.children.indexWhere(x => x.isInstanceOf[MethodSymbol] &&
- x.asInstanceOf[MethodSymbol].name == n + "_$eq")
+ x.asInstanceOf[MethodSymbol].name == n + "_$eq")
print(if (indexOfSetter > 0) "var " else "val ")
} else {
print("def ")
@@ -234,7 +261,7 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
val nn = processName(name)
print(nn)
printMethodType(m.infoType, true)(
- {if (!m.isDeferred) print(" = { /* compiled code */ }" /* Print body only for non-abstract metods */ )}
+ {if (!m.isDeferred) print(" = { /* compiled code */ }" /* Print body only for non-abstract methods */ )}
)
}
print("\n")
@@ -248,35 +275,43 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
printChildren(level, a)
}
- def printAttributes(sym: SymbolInfoSymbol) {
- for (attrib <- sym.attributes) printAttribute(attrib)
+ def printTypeSymbol(level: Int, t: TypeSymbol) {
+ print("type ")
+ print(processName(t.name))
+ printType(t.infoType)
+ print("\n")
}
- def printAttribute(attrib: AttributeInfo) {
- printType(attrib.typeRef, "@")
+ def toString(attrib: AttributeInfo): String = {
+ val buffer = new StringBuffer
+ buffer.append(toString(attrib.typeRef, "@"))
if (attrib.value.isDefined) {
- print("(")
- printValue(attrib.value.get)
- print(")")
+ buffer.append("(")
+ val value = attrib.value.get
+ val stringVal = value.isInstanceOf[String]
+ if (stringVal) buffer.append("\"")
+ buffer.append(valueToString(value))
+ if (stringVal) buffer.append("\"")
+ buffer.append(")")
}
if (!attrib.values.isEmpty) {
- print(" {")
+ buffer.append(" {")
for (name ~ value <- attrib.values) {
- print(" val ")
- print(processName(name))
- print(" = ")
- printValue(value)
+ buffer.append(" val ")
+ buffer.append(processName(name))
+ buffer.append(" = ")
+ buffer.append(valueToString(value))
}
- printValue(attrib.value)
- print(" }")
+ buffer.append(valueToString(attrib.value))
+ buffer.append(" }")
}
- print(" ")
+ buffer.toString
}
- def printValue(value: Any): Unit = value match {
- case t: Type => printType(t)
+ def valueToString(value: Any): String = value match {
+ case t: Type => toString(t)
// TODO string, char, float, etc.
- case _ => print(value)
+ case _ => value.toString
}
implicit object _tf extends TypeFlags(false)
@@ -289,57 +324,72 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
def toString(t: Type)(implicit flags: TypeFlags): String = toString(t, "")(flags)
- def toString(t: Type, sep: String)(implicit flags: TypeFlags): String = t match {
- case ThisType(symbol) => sep + symbol.path + ".type"
- case SingleType(typeRef, symbol) => sep + symbol.path + ".type"
- case ConstantType(constant) => sep + (constant match {
- case null => "scala.Null"
- case _: Unit => "scala.Unit"
- case _: Boolean => "scala.Boolean"
- case _: Byte => "scala.Byte"
- case _: Char => "scala.Char"
- case _: Short => "scala.Short"
- case _: Int => "scala.Int"
- case _: Long => "scala.Long"
- case _: Float => "scala.Float"
- case _: Double => "scala.Double"
- case _: String => "java.lang.String"
- case c: Class[_] => "java.lang.Class[" + c.getComponentType.getCanonicalName.replace("$", ".") + "]"
- })
- case TypeRefType(prefix, symbol, typeArgs) => sep + (symbol.path match {
- case "scala.<repeated>" => flags match {
- case TypeFlags(true) => toString(typeArgs.head) + "*"
- case _ => "scala.Seq" + typeArgString(typeArgs)
+ def toString(t: Type, sep: String)(implicit flags: TypeFlags): String = {
+ // print type itself
+ t match {
+ case ThisType(symbol) => sep + processName(symbol.path) + ".type"
+ case SingleType(typeRef, symbol) => sep + processName(symbol.path) + ".type"
+ case ConstantType(constant) => sep + (constant match {
+ case null => "scala.Null"
+ case _: Unit => "scala.Unit"
+ case _: Boolean => "scala.Boolean"
+ case _: Byte => "scala.Byte"
+ case _: Char => "scala.Char"
+ case _: Short => "scala.Short"
+ case _: Int => "scala.Int"
+ case _: Long => "scala.Long"
+ case _: Float => "scala.Float"
+ case _: Double => "scala.Double"
+ case _: String => "java.lang.String"
+ case c: Class[_] => "java.lang.Class[" + c.getComponentType.getCanonicalName.replace("$", ".") + "]"
+ })
+ case TypeRefType(prefix, symbol, typeArgs) => sep + (symbol.path match {
+ case "scala.<repeated>" => flags match {
+ case TypeFlags(true) => toString(typeArgs.head) + "*"
+ case _ => "scala.Seq" + typeArgString(typeArgs)
+ }
+ case "scala.<byname>" => "=> " + toString(typeArgs.head)
+ case _ => {
+ val path = StringUtil.cutSubstring(symbol.path)(".package") //remove package object reference
+ StringUtil.trimStart(processName(path) + typeArgString(typeArgs), "<empty>.")
+ }
+ })
+ case TypeBoundsType(lower, upper) => {
+ val lb = toString(lower)
+ val ub = toString(upper)
+ val lbs = if (!lb.equals("scala.Nothing")) " >: " + lb else ""
+ val ubs = if (!ub.equals("scala.Any")) " <: " + ub else ""
+ lbs + ubs
}
- case "scala.<byname>" => "=> " + toString(typeArgs.head)
- case _ => {
- val path = StringUtil.cutSubstring(symbol.path)(".package") //remove package object reference
- StringUtil.trimStart(processName(path) + typeArgString(typeArgs), "<empty>.")
+ case RefinedType(classSym, typeRefs) => sep + typeRefs.map(toString).mkString("", " with ", "")
+ case ClassInfoType(symbol, typeRefs) => sep + typeRefs.map(toString).mkString(" extends ", " with ", "")
+
+ case ImplicitMethodType(resultType, _) => toString(resultType, sep)
+ case MethodType(resultType, _) => toString(resultType, sep)
+
+ case PolyType(typeRef, symbols) => typeParamString(symbols) + toString(typeRef, sep)
+ case PolyTypeWithCons(typeRef, symbols, cons) => typeParamString(symbols) + processName(cons) + toString(typeRef, sep)
+ case AnnotatedType(typeRef, attribTreeRefs) => {
+ toString(typeRef, sep)
}
- })
- case TypeBoundsType(lower, upper) => " >: " + toString(lower) + " <: " + toString(upper)
- case RefinedType(classSym, typeRefs) => sep + typeRefs.map(toString).mkString("", " with ", "")
- case ClassInfoType(symbol, typeRefs) => sep + typeRefs.map(toString).mkString(" extends ", " with ", "")
-
- case ImplicitMethodType(resultType, _) => toString(resultType, sep)
- case MethodType(resultType, _) => toString(resultType, sep)
-
- case PolyType(typeRef, symbols) => typeParamString(symbols) + toString(typeRef, sep)
- case PolyTypeWithCons(typeRef, symbols, cons) => typeParamString(symbols) + cons + toString(typeRef, sep)
- case AnnotatedType(typeRef, attribTreeRefs) => toString(typeRef, sep)
- case AnnotatedWithSelfType(typeRef, symbol, attribTreeRefs) => toString(typeRef, sep)
- //case DeBruijnIndexType(typeLevel, typeIndex) =>
- case ExistentialType(typeRef, symbols) => {
- val refs = symbols.map(toString _).filter(!_.startsWith("_ ")).map("type " + _)
- toString(typeRef, sep) + (if (refs.size > 0) refs.mkString(" forSome {", "; ", "}") else "")
+ case AnnotatedWithSelfType(typeRef, symbol, attribTreeRefs) => toString(typeRef, sep)
+ //case DeBruijnIndexType(typeLevel, typeIndex) =>
+ case ExistentialType(typeRef, symbols) => {
+ val refs = symbols.map(toString _).filter(!_.startsWith("_")).map("type " + _)
+ toString(typeRef, sep) + (if (refs.size > 0) refs.mkString(" forSome {", "; ", "}") else "")
+ }
+ case _ => sep + t.toString
}
- case _ => sep + t.toString
}
def getVariance(t: TypeSymbol) = if (t.isCovariant) "+" else if (t.isContravariant) "-" else ""
def toString(symbol: Symbol): String = symbol match {
- case symbol: TypeSymbol => getVariance(symbol) + processName(symbol.name) + toString(symbol.infoType)
+ case symbol: TypeSymbol => {
+ val attrs = (for (a <- symbol.attributes) yield toString(a)).mkString(" ")
+ val atrs = if (attrs.length > 0) attrs.trim + " " else ""
+ atrs + getVariance(symbol) + processName(symbol.name) + toString(symbol.infoType)
+ }
case s => symbol.toString
}
@@ -356,19 +406,27 @@ class ScalaSigPrinter(stream: PrintStream, printPrivates: Boolean) {
"\\$minus" -> "-", "\\$eq" -> "=", "\\$less" -> "<",
"\\$times" -> "*", "\\$div" -> "/", "\\$bslash" -> "\\\\",
"\\$greater" -> ">", "\\$qmark" -> "?", "\\$percent" -> "%",
- "\\$amp" -> "&", "\\$colon" -> ":", "\\$u2192" -> "→")
- val pattern = Pattern.compile(_syms.keysIterator.foldLeft("")((x, y) => if (x == "") y else x + "|" + y))
+ "\\$amp" -> "&", "\\$colon" -> ":", "\\$u2192" -> "→",
+ "\\$hash" -> "#")
+ val pattern = Pattern.compile(_syms.keys.foldLeft("")((x, y) => if (x == "") y else x + "|" + y))
val placeholderPattern = "_\\$(\\d)+"
+ private def stripPrivatePrefix(name: String) = {
+ val i = name.lastIndexOf("$$")
+ if (i > 0) name.substring(i + 2) else name
+ }
+
def processName(name: String) = {
- val m = pattern.matcher(name)
- var temp = name
+ val stripped = stripPrivatePrefix(name)
+ val m = pattern.matcher(stripped)
+ var temp = stripped
while (m.find) {
val key = m.group
val re = "\\" + key
temp = temp.replaceAll(re, _syms(re))
}
- temp.replaceAll(placeholderPattern, "_")
+ val result = temp.replaceAll(placeholderPattern, "_")
+ NameTransformer.decode(result)
}
}