summaryrefslogtreecommitdiff
path: root/sources
diff options
context:
space:
mode:
authorMatthias Zenger <mzenger@gmail.com>2003-09-23 00:32:46 +0000
committerMatthias Zenger <mzenger@gmail.com>2003-09-23 00:32:46 +0000
commit8c650924748b9433bf4b3e51d5be97fcdff2e67f (patch)
tree5b314c7808ea1c46919546976ac3a6aed4f856d1 /sources
parentb77cc54fa830d241a1ac7bf22426995ae907882c (diff)
downloadscala-8c650924748b9433bf4b3e51d5be97fcdff2e67f.tar.gz
scala-8c650924748b9433bf4b3e51d5be97fcdff2e67f.tar.bz2
scala-8c650924748b9433bf4b3e51d5be97fcdff2e67f.zip
Initial implementation of scalap.
Diffstat (limited to 'sources')
-rw-r--r--sources/scala/tools/scalap/AbstractFile.scala265
-rw-r--r--sources/scala/tools/scalap/ByteArrayReader.scala133
-rw-r--r--sources/scala/tools/scalap/ClassPath.scala175
-rw-r--r--sources/scala/tools/scalap/Classfile.scala116
-rw-r--r--sources/scala/tools/scalap/Classfiles.scala47
-rw-r--r--sources/scala/tools/scalap/CodeWriter.scala131
-rw-r--r--sources/scala/tools/scalap/Entity.scala123
-rw-r--r--sources/scala/tools/scalap/EntityTable.scala141
-rw-r--r--sources/scala/tools/scalap/FileCache.scala37
-rw-r--r--sources/scala/tools/scalap/Flags.scala112
-rw-r--r--sources/scala/tools/scalap/Main.scala46
-rw-r--r--sources/scala/tools/scalap/Names.scala85
-rw-r--r--sources/scala/tools/scalap/ScalaAttribute.scala95
-rw-r--r--sources/scala/tools/scalap/ScalaWriter.scala219
14 files changed, 1725 insertions, 0 deletions
diff --git a/sources/scala/tools/scalap/AbstractFile.scala b/sources/scala/tools/scalap/AbstractFile.scala
new file mode 100644
index 0000000000..38e2acebf6
--- /dev/null
+++ b/sources/scala/tools/scalap/AbstractFile.scala
@@ -0,0 +1,265 @@
+// AbstractFile
+// 04-Feb-2002, Matthias Zenger
+
+package scalap;
+
+import scala.collection._;
+import java.io._;
+import java.util.jar._;
+
+
+trait AbstractFile {
+
+ /** separator
+ */
+ protected val separator: Char = File.separatorChar;
+
+ /** get name of the file
+ */
+ def getName: String;
+
+ /** get path of the file
+ */
+ def getPath: String;
+
+ /** does the file exist?
+ */
+ def exists: Boolean;
+
+ /** is the file a directory?
+ */
+ def isDirectory: Boolean;
+
+ /** read content of the file into a byte[] buffer
+ */
+ def content: Array[Byte];
+
+ /** list contents of a directory
+ */
+ def elements: Iterator[String];
+
+ /** open a new file
+ */
+ def open(name: String): AbstractFile;
+
+ /** return an input stream for the file
+ */
+ def getInputStream: InputStream = new ByteArrayInputStream(content);
+}
+
+class PlainFile(f: File) with AbstractFile {
+
+ def getName = f.getName();
+
+ def getPath = f.getPath();
+
+ def exists = f.exists();
+
+ def isDirectory = f.isDirectory();
+
+ def content = {
+ val in = new FileInputStream(f);
+ var rest = f.length().asInstanceOf[Int];
+ val buf = new Array[Byte](rest);
+ do {
+ val res = in.read(buf, buf.length - rest, rest);
+ if (res == -1)
+ error("read error");
+ rest = rest - res;
+ } while (rest > 0);
+ in.close();
+ buf;
+ }
+
+ def elements = {
+ val fs = f.listFiles();
+ if (fs == null)
+ Iterator.empty[String]
+ else
+ new Iterator[String] {
+ var i = 0;
+ def hasNext = (i < fs.length);
+ def next = {
+ val res = fs(i).getName();
+ i = i + 1;
+ if (fs(i - 1).isDirectory() &&
+ !res.endsWith("/")) res + "/" else res;
+ }
+ }
+ }
+
+ def open(name: String) = new PlainFile(new File(f, name));
+}
+
+class JarArchive(f: File) with AbstractFile {
+ val jarFile = try { new JarFile(f) } catch { case e => null };
+ var entries: mutable.Map[String, JarArchiveEntry] = _;
+
+ def getName = f.getName();
+
+ def getPath = f.getPath();
+
+ def exists = (jarFile != null);
+
+ def isDirectory = (jarFile != null);
+
+ def content: Array[Byte] = error("cannot read archive");
+
+ private def load = {
+ //entries = new mutable.HashMap[String, JarArchiveEntry];
+ entries = new mutable.JavaMapAdaptor(new java.util.HashMap());
+ if (jarFile != null) {
+ val enum = jarFile.entries();
+ while (enum.hasMoreElements()) {
+ val candidate = enum.nextElement().asInstanceOf[JarEntry].getName();
+ var i = candidate.indexOf('/');
+ var j = 0;
+ var files = entries;
+ while (i >= 0) {
+ val dirname = candidate.substring(j, i + 1);
+ j = i + 1;
+ if (!files.isDefinedAt(dirname))
+ files(dirname) = new JarDirEntry(candidate.substring(0, j));
+ files = files(dirname).entries;
+ i = candidate.indexOf('/', j);
+ }
+ if (j < (candidate.length() - 1)) {
+ val filename = candidate.substring(j);
+ if (!files.isDefinedAt(filename))
+ files(filename) = new JarFileEntry(candidate);
+ }
+ }
+ }
+ }
+
+ def list(prefix: String) = {
+ val pref = prefix.replace(File.separatorChar, '/');
+ if (entries == null)
+ load;
+ var i = pref.indexOf('/');
+ var j = 0;
+ var files = entries;
+ var continue = true;
+ while (continue && (i >= 0)) {
+ val dirname = pref.substring(j, i + 1);
+ j = i + 1;
+ continue = files.isDefinedAt(dirname);
+ if (continue) {
+ files = files(dirname).entries;
+ i = pref.indexOf('/', j);
+ }
+ }
+ if (!continue)
+ Iterator.empty;
+ else if (j < (pref.length() - 1)) {
+ if (files.isDefinedAt(pref.substring(j)))
+ List(pref).elements;
+ else
+ Iterator.empty;
+ } else
+ files.keys;
+ }
+
+ def elements = list("");
+
+ def open(fname: String) = {
+ if (entries == null)
+ load;
+ val name = fname.replace(File.separatorChar, '/');
+ var i = name.indexOf('/');
+ var j = 0;
+ var namelen = name.length();
+ var files = entries;
+ var res: AbstractFile = null;
+ while ((res == null) && (i >= 0)) {
+ val dirname = name.substring(j, i + 1);
+ j = i + 1;
+ if (files != null) {
+ if (files.isDefinedAt(dirname)) {
+ if (j == namelen)
+ res = files(dirname);
+ else
+ files = files(dirname).entries;
+ } else
+ files = null;
+ }
+ i = name.indexOf('/', j);
+ }
+ if (res != null)
+ res
+ else if (j < (namelen - 1)) {
+ if (files == null)
+ new JarArchiveEntry(name, false);
+ else {
+ val filename = name.substring(j);
+ if (files.isDefinedAt(filename))
+ files(filename)
+ else
+ new JarArchiveEntry(name, false)
+ }
+ } else
+ new JarArchiveEntry(name, true);
+ }
+
+ class JarArchiveEntry(name: String, dir: Boolean) with AbstractFile {
+
+ def getName = name.substring(
+ name.lastIndexOf('/', name.length() - (if (dir) 2 else 1)) + 1);
+
+ def getPath = name;
+
+ def getFullName = name;
+
+ def exists = false;
+
+ def isDirectory = dir;
+
+ def elements: Iterator[String] = error("nothing to iterate over");
+
+ def content: Array[Byte] = error("cannot read archive");
+
+ def open(n: String): AbstractFile = error("cannot open archive entry");
+
+ def entries: mutable.Map[String, JarArchiveEntry] = error("no entries");
+ }
+
+ final class JarDirEntry(name: String) extends JarArchiveEntry(name, true) {
+ //val entr = new mutable.HashMap[String, JarArchiveEntry];
+ val entr = new mutable.JavaMapAdaptor[String, JarArchiveEntry](new java.util.HashMap());
+
+ override def getPath = JarArchive.this.getPath + "(" + name + ")";
+
+ override def exists = true;
+
+ override def elements = JarArchive.this.list(name);
+
+ override def open(fname: String) = JarArchive.this.open(
+ name + fname.replace(File.separatorChar, '/'));
+
+ override def entries: mutable.Map[String, JarArchiveEntry] = entr;
+ }
+
+ final class JarFileEntry(name: String) extends JarArchiveEntry(name, false) {
+
+ override def getPath = JarArchive.this.getPath + "(" + name + ")";
+
+ override def exists = true;
+
+ override def content: Array[Byte] = {
+ val jarEntry = jarFile.getJarEntry(name);
+ if (jarEntry == null)
+ error("unable to read " + name);
+ val in = jarFile.getInputStream(jarEntry);
+ var rest = jarEntry.getSize().asInstanceOf[Int];
+ val buf = new Array[Byte](rest);
+ do {
+ val res = in.read(buf, buf.length - rest, rest);
+ if (res == -1)
+ error("read error");
+ rest = rest - res;
+ } while (rest > 0);
+ in.close();
+ buf;
+ }
+ }
+}
diff --git a/sources/scala/tools/scalap/ByteArrayReader.scala b/sources/scala/tools/scalap/ByteArrayReader.scala
new file mode 100644
index 0000000000..71938dbe82
--- /dev/null
+++ b/sources/scala/tools/scalap/ByteArrayReader.scala
@@ -0,0 +1,133 @@
+package scalap;
+
+class ByteArrayReader(content: Array[Byte]) {
+ import java.io._;
+
+ /** the buffer containing the file
+ */
+ val buf: Array[Byte] = content;
+
+ /** the current input pointer
+ */
+ var bp: Int = 0;
+
+ /** return byte at offset 'pos'
+ */
+ def byteAt(pos: Int): Byte = buf(pos);
+
+ /** read a byte
+ */
+ def nextByte: Byte = {
+ bp = bp + 1;
+ buf(bp - 1)
+ }
+
+ /** read some bytes
+ */
+ def nextBytes(len: Int): Array[Byte] = {
+ val res = new Array[Byte](len);
+ System.arraycopy(buf, bp, res, 0, len);
+ bp = bp + len;
+ res
+ }
+
+ /** read a character
+ */
+ def nextChar: Char = {
+ bp = bp + 2;
+ (((buf(bp - 2) & 0xff) << 8) + (buf(bp - 1) & 0xff)).asInstanceOf[Char];
+ }
+
+ /** read an integer
+ */
+ def nextInt: Int = {
+ bp = bp + 4;
+ ((buf(bp - 4) & 0xff) << 24) +
+ ((buf(bp - 3) & 0xff) << 16) +
+ ((buf(bp - 2) & 0xff) << 8) +
+ (buf(bp - 1) & 0xff);
+ }
+
+ /** read a long
+ */
+ def nextLong: Long =
+ (nextInt.asInstanceOf[Long] << 32) + (nextInt.asInstanceOf[Long] & 0xffffffffL);
+
+ /** read a float
+ */
+ def nextFloat: Float = java.lang.Float.intBitsToFloat(nextInt);
+
+ /** read a double
+ */
+ def nextDouble: Double = java.lang.Double.longBitsToDouble(nextLong);
+
+ /** read the next integer number
+ */
+ def nextNat: Int = {
+ var x = 0;
+ var b: Byte = 0;
+ do {
+ b = buf(bp);
+ bp = bp + 1;
+ x = (x << 7) + (b & 0x7f);
+ } while ((b & 0x80) != 0);
+ x
+ }
+
+ /** read an UTF8 encoded string
+ */
+ def nextUTF8(len: Int): String = {
+ val cs: Array[Char] = new Array(len);
+ var i = bp;
+ var j = 0;
+ bp = bp + len;
+ while (i < bp) {
+ var b: Int = buf(i) & 0xFF;
+ i = i + 1;
+ if (b >= 0xE0) {
+ b = ((b & 0x0F) << 12) | (buf(i) & 0x3F) << 6;
+ i = i + 1;
+ b = b | (buf(i) & 0x3F);
+ i = i + 1;
+ } else if (b >= 0xC0) {
+ b = ((b & 0x1F) << 6) | (buf(i) & 0x3F);
+ i = i + 1;
+ }
+ cs(j) = b.asInstanceOf[Char];
+ j = j + 1;
+ }
+ new String(cs, 0, j)
+ }
+
+ /** extract a character at position bp from buf
+ */
+ def getChar(bp: Int): Char =
+ (((buf(bp) & 0xff) << 8) + (buf(bp + 1) & 0xff)).asInstanceOf[Char];
+
+ /** extract an integer at position bp from buf
+ */
+ def getInt(bp: Int): Int =
+ ((buf(bp ) & 0xff) << 24) +
+ ((buf(bp + 1) & 0xff) << 16) +
+ ((buf(bp + 2) & 0xff) << 8) +
+ (buf(bp + 3) & 0xff);
+
+ /** extract a long integer at position bp from buf
+ */
+ def getLong(bp: Int): Long =
+ (getInt(bp).asInstanceOf[Long] << 32) + (getInt(bp + 4).asInstanceOf[Long] & 0xffffffffL);
+
+ /** extract a float at position bp from buf
+ */
+ def getFloat(bp: Int): Float = java.lang.Float.intBitsToFloat(getInt(bp));
+
+ /** extract a double at position bp from buf
+ */
+ def getDouble(bp: Int): Double = java.lang.Double.longBitsToDouble(getLong(bp));
+
+ /** skip next 'n' bytes
+ */
+ def skip(n: Int): Unit = {
+ bp = bp + n;
+ }
+}
diff --git a/sources/scala/tools/scalap/ClassPath.scala b/sources/scala/tools/scalap/ClassPath.scala
new file mode 100644
index 0000000000..74c81de732
--- /dev/null
+++ b/sources/scala/tools/scalap/ClassPath.scala
@@ -0,0 +1,175 @@
+// ClassPath
+// 04-Mar-2002, Matthias Zenger
+
+package scalap;
+
+import java.io._;
+import scala.collection._;
+
+
+class ClassPath {
+
+ /** the character separating files
+ */
+ protected val FILE_SEP = File.separator;
+
+ /** the separator in class path specifications
+ */
+ protected val PATH_SEP = System.getProperty("path.separator");
+
+ /** the default class path
+ */
+ val classPath = System.getProperty("java.class.path");
+
+ /** the default boot class path
+ */
+ val bootPath = System.getProperty("sun.boot.class.path");
+
+ /** the default extension path
+ */
+ val extensionPath = System.getProperty("java.ext.dirs");
+
+ /** the corresponding file cache (for not reading .jar files over
+ * and over again)
+ */
+ val cache = new FileCache;
+
+ /** the various class path roots
+ */
+ protected var root: List[String] = decompose(bootPath) :::
+ expand(extensionPath) :::
+ decompose(classPath);
+
+
+ /** append files from the extension directories
+ */
+ protected def expand(edirs: String): List[String] =
+ if (edirs == null)
+ Nil
+ else {
+ val extdirs = edirs + PATH_SEP;
+ val length = extdirs.length();
+ var i = 0;
+ var path: List[String] = Nil;
+ while (i < length) {
+ val k = extdirs.indexOf(PATH_SEP, i);
+ val dirname = extdirs.substring(i, k);
+ if ((dirname != null) && (dirname.length() > 0)) {
+ val iter = Iterator.fromArray(new File(dirname).list());
+ val dname = if (dirname.endsWith(FILE_SEP)) dirname else dirname + FILE_SEP;
+ while (iter.hasNext) {
+ val entry = iter.next;
+ if (entry.endsWith(".jar"))
+ path = (dname + entry) :: path;
+ }
+ }
+ i = k + 1;
+ }
+ path
+ };
+
+ /** parse a class path specification and return an array
+ * of existing class file locations
+ */
+ protected def decompose(p: String): List[String] = {
+ val path = if (p.endsWith(PATH_SEP)) p else p + PATH_SEP;
+ var components: List[String] = Nil;
+ var i = 0;
+ while (i < path.length()) {
+ val j = path.indexOf(PATH_SEP, i);
+ val subpath = path.substring(i, j);
+ if (new File(subpath).exists())
+ components = subpath :: components;
+ i = j + 1;
+ }
+ components.reverse;
+ }
+
+ /** find file with given name in class path and return an abstract
+ * file representation together with the originating class path
+ * component.
+ */
+ def findFile(name: String): Pair[AbstractFile, String] = {
+ val iter = root.elements;
+ var entry: AbstractFile = null;
+ var continue: Boolean = true;
+ var origin: String = null;
+ while (continue && iter.hasNext) {
+ origin = iter.next;
+ entry = cache.open(origin, name);
+ if (entry.exists)
+ continue = false;
+ }
+ Pair(entry, origin)
+ }
+
+ /** find file with given name in class path and return an abstract
+ * file representation.
+ */
+ def openFile(name: String): AbstractFile = findFile(name)._1;
+
+ /** find class with given name in class path and return an abstract
+ * file representation.
+ */
+ def openClass(name: String): AbstractFile =
+ openFile(name.replace('.', File.separatorChar) + ".class");
+
+ def elements: Iterator[String] = root.elements;
+
+ def classes: Iterator[String] = new Iterator[String] {
+ val todo: mutable.Stack[Pair[AbstractFile, String]] = new mutable.Stack;
+ var iter: Iterator[String] = Iterator.empty;
+ var file: AbstractFile = null;
+ var path: String = null;
+ var clazz: String = null;
+ root.foreach { component => {
+ val f = cache.open(component, null);
+ if (f.exists && f.isDirectory)
+ todo.push(Pair(f, null));
+ }};
+ scan;
+ def hasNext = (clazz != null);
+ def next =
+ if (clazz == null)
+ error("no next element");
+ else {
+ val res = clazz; scan; res
+ };
+ def scan: Unit = {
+ if (!iter.hasNext) {
+ if (todo.isEmpty)
+ clazz = null;
+ else {
+ val Pair(f, p) = todo.top;
+ todo.pop;
+ iter = f.elements;
+ file = f;
+ path = if ((p != null) && p.endsWith("/"))
+ p.substring(0, p.length() - 1) else p;
+ scan;
+ }
+ } else {
+ var continue = true;
+ while (continue && iter.hasNext) {
+ val g = file.open(iter.next);
+ clazz = if (path == null) g.getName else path + "." + g.getName;
+ if (clazz.endsWith(".class")) {
+ clazz = clazz.substring(0, clazz.length() - 6);
+ continue = false;
+ } else if (g.exists && g.isDirectory)
+ todo.push(Pair(g, clazz));
+ }
+ if (continue)
+ scan;
+ }
+ }
+ }
+
+ /** return a textual representation of this class path
+ */
+ override def toString() = root match {
+ case Nil => ""
+ case x :: Nil => x
+ case x :: xs => xs.foldLeft(x)((s, e) => s + PATH_SEP + e);
+ }
+}
diff --git a/sources/scala/tools/scalap/Classfile.scala b/sources/scala/tools/scalap/Classfile.scala
new file mode 100644
index 0000000000..c37459ba92
--- /dev/null
+++ b/sources/scala/tools/scalap/Classfile.scala
@@ -0,0 +1,116 @@
+package scalap;
+
+class Classfile(in: ByteArrayReader) {
+ import Classfiles._;
+
+ assert(in.nextInt == JAVA_MAGIC);
+ val minorVersion = in.nextChar;
+ val majorVersion = in.nextChar;
+ val pool = readPool;
+ val flags = in.nextChar;
+ val classname = in.nextChar;
+ val superclass = in.nextChar;
+ val interfaces = readInterfaces;
+ val fields = readMembers(true);
+ val methods = readMembers(false);
+ val attribs = readAttribs;
+
+ def readAttribs = {
+ val n = in.nextChar;
+ var attribs: List[Attribute] = Nil;
+ var i = 0;
+ while (i < n) {
+ attribs = Attribute(in.nextChar, in.nextBytes(in.nextInt)) :: attribs;
+ i = i + 1;
+ }
+ attribs
+ }
+
+ def readMembers(field: Boolean) = {
+ val n = in.nextChar;
+ var members: List[Member] = Nil;
+ var i = 0;
+ while (i < n) {
+ members = Member(field, in.nextChar, in.nextChar, in.nextChar, readAttribs) :: members;
+ i = i + 1;
+ }
+ members
+ }
+
+ def readInterfaces = {
+ val n = in.nextChar;
+ var intfs: List[Int] = Nil;
+ var i = 0;
+ while (i < n) {
+ intfs = in.nextChar :: intfs;
+ i = i + 1;
+ }
+ intfs
+ }
+
+ def readPool = {
+ val pool = new Array[PoolEntry](in.nextChar);
+ var i = 1;
+ while (i < pool.length) {
+ val tag: Int = in.nextByte;
+ tag match {
+ case 1 => // CONSTANT_UTF8
+ pool(i) = UTF8(in.nextUTF8(in.nextChar));
+ case 2 => // CONSTANT_UNICODE
+ in.skip(in.nextChar);
+ pool(i) = Empty();
+ case 7 => // CONSTANT_CLASS
+ pool(i) = ClassRef(in.nextChar);
+ case 8 => // CONSTANT_STRING
+ pool(i) = StringConst(in.nextChar);
+ case 9 => // CONSTANT_FIELDREF
+ pool(i) = FieldRef(in.nextChar, in.nextChar);
+ case 10 => // CONSTANT_METHODREF
+ pool(i) = MethodRef(in.nextChar, in.nextChar);
+ case 11 => // CONSTANT_INTFMETHODREF
+ pool(i) = IntfMethodRef(in.nextChar, in.nextChar);
+ case 12 => // CONSTANT_NAMEANDTYPE
+ pool(i) = NameAndType(in.nextChar, in.nextChar);
+ case 3 => // CONSTANT_INTEGER
+ pool(i) = IntegerConst(in.nextInt);
+ case 4 => // CONSTANT_FLOAT
+ pool(i) = FloatConst(in.nextFloat);
+ case 5 => // CONSTANT_LONG
+ pool(i) = LongConst(in.nextLong);
+ i = i + 1;
+ pool(i) = Empty();
+ case 6 => // CONSTANT_DOUBLE
+ pool(i) = DoubleConst(in.nextDouble);
+ i = i + 1;
+ pool(i) = Empty();
+ }
+ i = i + 1;
+ }
+ pool
+ }
+
+ class PoolEntry;
+ case class UTF8(str: String) extends PoolEntry;
+ case class ClassRef(classId: Int) extends PoolEntry;
+ case class FieldRef(classId: Int, memberId: Int) extends PoolEntry;
+ case class MethodRef(classId: Int, memberId: Int) extends PoolEntry;
+ case class IntfMethodRef(classId: Int, memberId: Int) extends PoolEntry;
+ case class StringConst(strId: Int) extends PoolEntry;
+ case class IntegerConst(x: Int) extends PoolEntry;
+ case class FloatConst(x: Float) extends PoolEntry;
+ case class LongConst(x: Long) extends PoolEntry;
+ case class DoubleConst(x: Double) extends PoolEntry;
+ case class NameAndType(nameId: Int, typeId: Int) extends PoolEntry;
+ case class Empty() extends PoolEntry;
+
+ case class Member(field: Boolean, flags: Int, name: Int, tpe: Int, attribs: List[Attribute]);
+ case class Attribute(name: Int, data: Array[Byte]) {
+
+ override def toString(): String = pool(name) match {
+ case UTF8(str: String) => str
+ }
+
+ def reader: ByteArrayReader = new ByteArrayReader(data);
+ }
+
+}
diff --git a/sources/scala/tools/scalap/Classfiles.scala b/sources/scala/tools/scalap/Classfiles.scala
new file mode 100644
index 0000000000..ea3526131c
--- /dev/null
+++ b/sources/scala/tools/scalap/Classfiles.scala
@@ -0,0 +1,47 @@
+package scalap;
+
+
+object Classfiles {
+ final val JAVA_MAGIC = 0xCAFEBABE;
+ final val JAVA_MAJOR_VERSION = 45;
+ final val JAVA_MINOR_VERSION = 3;
+
+ final val CONSTANT_UTF8 = 1;
+ final val CONSTANT_UNICODE = 2;
+ final val CONSTANT_INTEGER = 3;
+ final val CONSTANT_FLOAT = 4;
+ final val CONSTANT_LONG = 5;
+ final val CONSTANT_DOUBLE = 6;
+ final val CONSTANT_CLASS = 7;
+ final val CONSTANT_STRING = 8;
+ final val CONSTANT_FIELDREF = 9;
+ final val CONSTANT_METHODREF = 10;
+ final val CONSTANT_INTFMETHODREF = 11;
+ final val CONSTANT_NAMEANDTYPE = 12;
+
+ final val BAD_ATTR = 0x00000;
+ final val SOURCEFILE_ATTR = 0x00001;
+ final val SYNTHETIC_ATTR = 0x00002;
+ final val DEPRECATED_ATTR = 0x00004;
+ final val CODE_ATTR = 0x00008;
+ final val EXCEPTIONS_ATTR = 0x00010;
+ final val CONSTANT_VALUE_ATTR = 0x00020;
+ final val LINE_NUM_TABLE_ATTR = 0x00040;
+ final val LOCAL_VAR_TABLE_ATTR = 0x00080;
+ final val INNERCLASSES_ATTR = 0x08000;
+ final val META_ATTR = 0x10000;
+ final val SCALA_ATTR = 0x20000;
+
+ final val SOURCEFILE_N = "SourceFile";
+ final val SYNTHETIC_N = "Synthetic";
+ final val DEPRECATED_N = "Deprecated";
+ final val CODE_N = "Code";
+ final val EXCEPTIONS_N = "Exceptions";
+ final val CONSTANT_VALUE_N = "ConstantValue";
+ final val LINE_NUM_TABLE_N = "LineNumberTable";
+ final val LOCAL_VAR_TABLE_N = "LocalVariableTable";
+ final val INNERCLASSES_N = "InnerClasses";
+ final val META_N = "JacoMeta";
+ final val SCALA_N = "ScalaSignature";
+ final val CONSTR_N = "<init>";
+}
diff --git a/sources/scala/tools/scalap/CodeWriter.scala b/sources/scala/tools/scalap/CodeWriter.scala
new file mode 100644
index 0000000000..d0f5bb99a8
--- /dev/null
+++ b/sources/scala/tools/scalap/CodeWriter.scala
@@ -0,0 +1,131 @@
+package scalap;
+
+import java.io._;
+
+
+class CodeWriter(writer: Writer) {
+
+ private val nl = System.getProperty("line.separator");
+ private var step = " ";
+ private var level = 0;
+ private var align = false;
+ private var space = false;
+ private var line = false;
+
+ def getWriter = writer;
+
+ def getIndentLevel = level;
+
+ def setIndentLevel(level: Int): CodeWriter = {
+ this.level = level;
+ this
+ }
+
+ def getIndentWidth = if (step == null) -1 else step.length();
+
+ def setIndentWidth(width: Int): CodeWriter = {
+ val buffer = new StringBuffer(width);
+ var i = 0;
+ while (i < width)
+ buffer.append(' ');
+ setIndentString(buffer.toString())
+ }
+
+ def getIndentString = step;
+
+ def setIndentString(step: String): CodeWriter = {
+ this.step = step;
+ this
+ }
+
+ def indent: CodeWriter = {
+ level = level + 1;
+ this
+ }
+
+ def undent: CodeWriter = {
+ level = level - 1;
+ this
+ }
+
+ def newline: CodeWriter = {
+ if (step == null)
+ newspace;
+ else if (!line) {
+ try {
+ writer.write(nl);
+ } catch {
+ case e => error("IO error")
+ }
+ line = align;
+ align = true;
+ space = false;
+ this
+ } else
+ this
+ }
+
+ def newspace: CodeWriter = {
+ space = !align;
+ this
+ }
+
+ def * : Unit = {}
+
+ def println: CodeWriter = newline;
+
+ def println(value: Boolean): CodeWriter = print(value).newline;
+
+ def println(value: Byte): CodeWriter = print(value).newline;
+
+ def println(value: Short): CodeWriter = print(value).newline;
+
+ def println(value: Char): CodeWriter = print(value).newline;
+
+ def println(value: Int): CodeWriter = print(value).newline;
+
+ def println(value: Long): CodeWriter = print(value).newline;
+
+ def println(value: Float): CodeWriter = print(value).newline;
+
+ def println(value: Double): CodeWriter = print(value).newline;
+
+ def println(value: String): CodeWriter = print(value).newline;
+
+ def print(value: Boolean): CodeWriter = print(String.valueOf(value));
+
+ def print(value: Byte): CodeWriter = print(String.valueOf(value));
+
+ def print(value: Short): CodeWriter = print(String.valueOf(value));
+
+ def print(value: Char): CodeWriter = print(String.valueOf(value));
+
+ def print(value: Int): CodeWriter = print(String.valueOf(value));
+
+ def print(value: Long): CodeWriter = print(String.valueOf(value));
+
+ def print(value: Float): CodeWriter = print(String.valueOf(value));
+
+ def print(value: Double): CodeWriter = print(String.valueOf(value));
+
+ def print(value: String): CodeWriter = try {
+ if (align) {
+ var i = 0;
+ while (i < level) {
+ writer.write(step);
+ i = i + 1;
+ }
+ }
+ if (space)
+ writer.write(" ");
+ writer.write(value);
+ align = false;
+ space = false;
+ line = false;
+ this
+ } catch {
+ case e => error("IO error")
+ }
+
+ override def toString(): String = writer.toString();
+}
diff --git a/sources/scala/tools/scalap/Entity.scala b/sources/scala/tools/scalap/Entity.scala
new file mode 100644
index 0000000000..6475894845
--- /dev/null
+++ b/sources/scala/tools/scalap/Entity.scala
@@ -0,0 +1,123 @@
+package scalap;
+
+import java.io._;
+import scala.collection.mutable._;
+
+
+/** Entities are either text, symbols, or types.
+ */
+trait Entity {
+ def isText: Boolean = false;
+ def isType: Boolean = false;
+ def isSymbol: Boolean = false;
+ def toSource: String = toString();
+}
+
+/** Text refers to a single string.
+ */
+case class Text(str: String) extends Entity {
+ override def isText: Boolean = true;
+ override def toString(): String = str;
+}
+
+/** Types
+ */
+trait Type extends Entity {
+ override def isType: Boolean = true;
+ override def toSource: String = {
+ val writer = new ScalaWriter(new StringWriter());
+ writer.setIndentString(null)*;
+ writer.printType(this);
+ writer.toString()
+ }
+}
+
+case object NoType extends Type;
+
+case class ThisType(sym: Symbol) extends Type;
+
+case class SingletonType(tpe: Type, sym: Symbol) extends Type;
+
+case class TypeRef(tpe: Type, sym: Symbol, args: List[Type]) extends Type;
+
+case class CompoundType(clazz: Symbol, components: List[Type]) extends Type;
+
+case class MethodType(argtpe: List[Type], restpe: Type) extends Type;
+
+case class PolyType(tpe: Type, tvars: List[Symbol]) extends Type;
+
+case class OverloadedType(members: List[Symbol], tpes: List[Type]) extends Type;
+
+case class TypeFlag(tpe: Type, flags: Int) extends Type;
+
+/** Symbols
+ */
+abstract case class Symbol(name: String, flags: Int) extends Entity {
+ var tpe: Type = NoType;
+ var owner: Symbol = NoSymbol;
+ def fullname: String = owner match {
+ case s: ClassSymbol => {
+ val prefix = s.fullname;
+ if (prefix.length() == 0) name else (prefix + "." + name)
+ }
+ case s: ExternalSymbol => {
+ val prefix = s.fullname;
+ if (prefix.length() == 0) name else (prefix + "." + name)
+ }
+ case _ => name
+ }
+ def fix(tpe: Type, owner: Symbol): Unit = {
+ this.tpe = tpe;
+ this.owner = owner;
+ owner.enter(this);
+ }
+ override def isSymbol: Boolean = true;
+ override def toString(): String = name;
+ def fix(tpe: Type): Unit = {}
+ def fix(sym: Symbol): Unit = {}
+ def enter(sym: Symbol): Unit = {}
+ def members: Buffer[Symbol] = error("symbol does not have members");
+}
+
+object NoSymbol extends Symbol("<nosymbol>", 0) {
+ override def fix(tpe: Type, owner: Symbol): Unit = {}
+}
+
+class TypeSymbol(name: String, flags: Int) extends Symbol(name, flags) {
+ var lower: Type = NoType;
+ override def fix(tpe: Type): Unit = {
+ lower = tpe;
+ }
+}
+
+class AliasSymbol(name: String, flags: Int) extends Symbol(name, flags) {
+ var constr: Symbol = NoSymbol;
+ override def fix(sym: Symbol): Unit = {
+ constr = sym;
+ }
+}
+
+class ClassSymbol(name: String, flags: Int) extends Symbol(name, flags) {
+ var thistpe: Type = NoType;
+ var constr: Symbol = NoSymbol;
+ var scope: Buffer[Symbol] = new Buffer;
+ override def fix(tpe: Type): Unit = {
+ thistpe = tpe;
+ }
+ override def fix(sym: Symbol): Unit = {
+ constr = sym;
+ }
+ override def enter(sym: Symbol): Unit = scope += sym;
+ override def members: Buffer[Symbol] = scope;
+}
+
+class ValSymbol(name: String, flags: Int) extends Symbol(name, flags) {
+ var clazz: Symbol = NoSymbol;
+ override def fix(sym: Symbol): Unit = {
+ clazz = sym;
+ }
+}
+
+class ExternalSymbol(name: String, mod: Boolean) extends Symbol(name, 0) {
+ override def fix(sym: Symbol): Unit = { owner = sym; }
+}
diff --git a/sources/scala/tools/scalap/EntityTable.scala b/sources/scala/tools/scalap/EntityTable.scala
new file mode 100644
index 0000000000..77a7decf84
--- /dev/null
+++ b/sources/scala/tools/scalap/EntityTable.scala
@@ -0,0 +1,141 @@
+package scalap;
+
+import scala.collection.mutable._;
+
+
+class EntityTable(attrib: ScalaAttribute) {
+ import attrib._;
+
+ val table: Array[Entity] = new Array(attrib.table.length);
+ var root: Buffer[Symbol] = new Buffer;
+
+ {
+ //Console.println("created table");
+ var i = 0;
+ while (i < attrib.table.length) {
+ table(i) = attrib.table(i) match {
+ case TermName(str) => Text(Names.decode(str));
+ case TypeName(str) => Text(Names.decode(str));
+ case _ => null;
+ }
+ i = i + 1;
+ }
+ //Console.println("decoded names");
+ i = 0;
+ var fixupIds: List[Int] = Nil;
+ while (i < attrib.table.length) {
+ table(i) = attrib.table(i) match {
+ case NoneSym() =>
+ NoSymbol
+ case TypeSym(SymbolInfo(nameId, _, flags, _), _) =>
+ fixupIds = i :: fixupIds;
+ new TypeSymbol(getText(nameId), flags)
+ case AliasSym(SymbolInfo(nameId, _, flags, _), _) =>
+ fixupIds = i :: fixupIds;
+ new AliasSymbol(getText(nameId), flags)
+ case ClassSym(SymbolInfo(nameId, _, flags, _), _, _) =>
+ fixupIds = i :: fixupIds;
+ new ClassSymbol(getText(nameId), flags)
+ case ValSym(SymbolInfo(nameId, _, flags, _), _) =>
+ fixupIds = i :: fixupIds;
+ new ValSymbol(getText(nameId), flags)
+ case ExtRef(mod, nameId, _) =>
+ fixupIds = i :: fixupIds;
+ new ExternalSymbol(getText(nameId), mod)
+ case _ =>
+ table(i)
+ }
+ i = i + 1;
+ }
+ //Console.println("created symbols");
+ i = 0;
+ while (i < attrib.table.length) {
+ val x = getType(i);
+ i = i + 1;
+ }
+ //Console.println("created types");
+ def fix(i: Int, info: SymbolInfo): Symbol = {
+ val sym = getSymbol(i);
+ sym.fix(getType(info.info), getSymbol(info.owner));
+ sym
+ }
+ fixupIds foreach {
+ i => attrib.table(i) match {
+ case TypeSym(info, loId) =>
+ fix(i, info).fix(getType(loId));
+ case AliasSym(info, constrId) =>
+ fix(i, info).fix(getSymbol(constrId));
+ case ClassSym(info, typeId, constrId) =>
+ val sym = fix(i, info);
+ sym.fix(getType(typeId));
+ sym.fix(getSymbol(constrId));
+ sym.owner match {
+ case x: ExternalSymbol => root += sym;
+ case _ =>
+ }
+ case ValSym(info, classId) =>
+ fix(i, info).fix(getSymbol(classId));
+ case ExtRef(_, _, ownerId) =>
+ getSymbol(i).fix(getSymbol(ownerId));
+ }
+ }
+ }
+
+ def getText(i: Int): String = table(i) match {
+ case Text(str) => str;
+ }
+
+ def getSymbol(i: Int): Symbol =
+ if (i < 0) NoSymbol else table(i).asInstanceOf[Symbol];
+
+ def getSymbols(is: List[Int]): List[Symbol] = is map {i => getSymbol(i)};
+
+ def getType(i: Int): Type = {
+ if (i < 0)
+ NoType
+ else if (table(i) != null) {
+ if (table(i).isInstanceOf[Type])
+ table(i).asInstanceOf[Type]
+ else
+ NoType
+ } else {
+ val res: Type = attrib.table(i) match {
+ case NoneType() =>
+ NoType
+ case SelfType(symId) =>
+ ThisType(getSymbol(symId))
+ case SingleType(typeId, symId) =>
+ SingletonType(getType(typeId), getSymbol(symId))
+ case TypeReference(typeId, symId, argIds) =>
+ TypeRef(getType(typeId), getSymbol(symId), getTypes(argIds))
+ case CompoundTypeRef(symId, typeIds) =>
+ CompoundType(getSymbol(symId), getTypes(typeIds))
+ case MethodTypeRef(restypeId, argtypeIds) =>
+ MethodType(getTypes(argtypeIds), getType(restypeId))
+ case PolyTypeRef(typeId, symIds) =>
+ PolyType(getType(typeId), getSymbols(symIds))
+ case OverloadedTypeRef(ids) =>
+ val Pair(symIds, typeIds) = ids partition {
+ i => (table(i) != null) && table(i).isSymbol
+ }
+ OverloadedType(getSymbols(symIds), getTypes(typeIds))
+ case FlaggedType(flags, typeId) =>
+ TypeFlag(getType(typeId), flags)
+ }
+ table(i) = res;
+ res
+ }
+ }
+
+ def getTypes(is: List[Int]): List[Type] = is map {i => getType(i)};
+
+ def print: Unit = {
+ Console.println("ROOT = " + root);
+ var i = 0;
+ while (i < table.length) {
+ Console.println("" + i + ": " + table(i).toSource);
+ Console.println(" " + table(i));
+ i = i + 1;
+ }
+ }
+}
diff --git a/sources/scala/tools/scalap/FileCache.scala b/sources/scala/tools/scalap/FileCache.scala
new file mode 100644
index 0000000000..9021d0ab98
--- /dev/null
+++ b/sources/scala/tools/scalap/FileCache.scala
@@ -0,0 +1,37 @@
+// FileCache
+// 20-Mar-2002, Matthias Zenger
+
+package scalap;
+
+import scala.collection._;
+import java.io._;
+import java.util.jar._;
+
+
+class FileCache {
+
+ /** table of all opened jar-files
+ */
+ protected val opened: mutable.Map[String, AbstractFile] =
+ //new mutable.HashMap[String, AbstractFile];
+ new mutable.JavaMapAdaptor(new java.util.HashMap());
+
+ def open(name: String): AbstractFile = open(null, name);
+
+ /** open file 'name' in directory 'dirname'; 'name' is a path
+ * relative to 'dirname'; 'dirname' might also refer to a .zip
+ * or .jar file
+ */
+ def open(dirname: String, name: String): AbstractFile = {
+ if (dirname == null)
+ new PlainFile(new File(name))
+ else if (dirname.endsWith(".jar")) {
+ if (!opened.isDefinedAt(dirname))
+ opened(dirname) = new JarArchive(new File(dirname));
+ if (name == null) opened(dirname) else opened(dirname).open(name)
+ } else if (name == null)
+ new PlainFile(new File(dirname))
+ else
+ new PlainFile(new File(dirname, name))
+ }
+}
diff --git a/sources/scala/tools/scalap/Flags.scala b/sources/scala/tools/scalap/Flags.scala
new file mode 100644
index 0000000000..004228340b
--- /dev/null
+++ b/sources/scala/tools/scalap/Flags.scala
@@ -0,0 +1,112 @@
+package scalap;
+
+object Flags {
+
+ final val DEFERRED = 0x00000001;
+ final val FINAL = 0x00000002;
+ final val PRIVATE = 0x00000004;
+ final val PROTECTED = 0x00000008;
+
+ final val SEALED = 0x00000010;
+ final val OVERRIDE = 0x00000020;
+ final val CASE = 0x00000040;
+ final val ABSTRACT = 0x00000080; // abstract class
+
+ final val DEF = 0x00000100; // a def parameter
+ final val REPEATED = 0x00000200; // a repeated parameter
+ final val SYNTHETIC = 0x00000400;
+ final val DEPRECATED = 0x00000800;
+
+ final val JAVA = 0x00001000; // symbol was defined by a Java class
+ final val OBJECT = 0x00002000; // symbol is module or class implementing a module
+ final val MUTABLE = 0x00004000; // symbol is a mutable variable.
+ final val PARAM = 0x00008000; // symbol is a (type) parameter to a method
+
+ final val INITIALIZED = 0x00010000; // symbol's definition is complete
+ final val LOCKED = 0x00020000; // temporary flag to catch cyclic dependencies
+ final val ACCESSED = 0x00040000; // symbol was accessed at least once
+ final val SELECTOR = 0x00080000; // symbol was used as selector in Select
+
+ final val PACKAGE = 0x00100000; // symbol is a java package.
+ final val LABEL = 0x00200000; // symbol is a label symbol
+ final val STATIC = 0x00400000; // "static" inner classes (i.e. after class norm.)
+ final val STABLE = 0x00800000; // functions that are assumed to be stable
+ // (typically, access methods for valdefs)
+
+ final val CAPTURED = 0x01000000; // variables is accessed from nested function.
+ final val CASEACCESSOR = 0x02000000; // function is a case constructor
+
+ final val ACCESSOR = 0x04000000; // function is an access function for a
+ // value or variable
+ final val BRIDGE = 0x08000000; // function is a bridge method.
+
+ final val INTERFACE = 0x10000000; // symbol is a Java interface
+ final val TRAIT = 0x20000000; // symbol is a Trait
+
+ final val COVAR = 0x40000000; // symbol is a covariant type variable
+ final val CONTRAVAR = 0x80000000; // symbol is a contravariant type variable
+
+ // masks
+ final val SOURCEFLAGS = 0x00000077
+ | DEF | REPEATED | OBJECT | MUTABLE
+ | PACKAGE | PARAM | TRAIT | COVAR
+ | CONTRAVAR; // these modifiers can be set in source programs
+ final val ACCESSFLAGS = PRIVATE | PROTECTED;
+ final val VARIANCES = COVAR | CONTRAVAR;
+
+ def isDeferred(flags: Int): Boolean = (flags & DEFERRED) != 0;
+
+ def isAbstract(flags: Int): Boolean = (flags & ABSTRACT) != 0;
+
+ def isFinal(flags: Int): Boolean = (flags & FINAL) != 0;
+
+ def isPrivate(flags: Int): Boolean = (flags & PRIVATE) != 0;
+
+ def isProtected(flags: Int): Boolean = (flags & PROTECTED) != 0;
+
+ def isSealed(flags: Int): Boolean = (flags & SEALED) != 0;
+
+ def isOverride(flags: Int): Boolean = (flags & OVERRIDE) != 0;
+
+ def isCase(flags: Int): Boolean = (flags & CASE) != 0;
+
+ def isCaseAccessor(flags: Int): Boolean = (flags & CASEACCESSOR) != 0;
+
+ def isInterface(flags: Int): Boolean = (flags & INTERFACE) != 0;
+
+ def isTrait(flags: Int): Boolean = (flags & TRAIT) != 0;
+
+ def isObj(flags: Int): Boolean = (flags & OBJECT) != 0;
+
+ def isDef(flags: Int): Boolean = (flags & DEF) != 0;
+
+ def isObjClass(flags: Int): Boolean = (flags & OBJECT) != 0;
+
+ def isStatic(flags: Int): Boolean = (flags & STATIC) != 0;
+
+ def isJava(flags: Int): Boolean = (flags & JAVA) != 0;
+
+ def isNoVal(flags: Int): Boolean = (flags & PACKAGE) != 0;
+
+ def toString(flags: Int): String = {
+ val buffer = new StringBuffer();
+ var x: StringBuffer = buffer;
+ if (isPrivate(flags))
+ x = buffer.append("private ");
+ if (isProtected(flags))
+ x = buffer.append("protected ");
+ if (isAbstract(flags) && !isTrait(flags))
+ x = buffer.append("abstract ");
+ if (isFinal(flags) && !isObj(flags))
+ x = buffer.append("final ");
+ if (isSealed(flags))
+ x = buffer.append("sealed ");
+ if (isCase(flags))
+ x = buffer.append("case ");
+ if (isDef(flags))
+ x = buffer.append("def ");
+ if (isOverride(flags))
+ x = buffer.append("override ");
+ buffer.toString()
+ }
+}
diff --git a/sources/scala/tools/scalap/Main.scala b/sources/scala/tools/scalap/Main.scala
new file mode 100644
index 0000000000..bd44bfb732
--- /dev/null
+++ b/sources/scala/tools/scalap/Main.scala
@@ -0,0 +1,46 @@
+// ClassPath
+// 04-Mar-2002, Matthias Zenger
+
+package scalap;
+
+import java.io._;
+import scala.collection._;
+
+
+object Main {
+
+ def usage: Unit = {
+ Console.println("usage: scalap <name>");
+ }
+
+ def main(args: Array[String]) = {
+ if (args.length == 0)
+ usage;
+ else {
+ val path = new ClassPath;
+ val file = path.openClass(Names.encode(args(0)));
+ if (file.exists) {
+ val reader = new ByteArrayReader(file.content);
+ val clazz = new Classfile(reader);
+ val attrib = clazz.attribs.find(a => a.toString() == "ScalaSignature");
+ attrib match {
+ case Some(a) =>
+ val info = new ScalaAttribute(a.reader);
+ //Console.println("read attribute");
+ val symtab = new EntityTable(info);
+ //Console.println("read entities");
+ //symtab.print;
+ val out = new OutputStreamWriter(System.out);
+ val writer = new ScalaWriter(out);
+ symtab.root.elements foreach (
+ sym => { writer.printSymbol(sym);
+ writer.println*; });
+ out.flush();
+ case None =>
+ Console.println("Java classes not supported yet.");
+ }
+ } else
+ Console.println("class/object not found.");
+ }
+ }
+}
diff --git a/sources/scala/tools/scalap/Names.scala b/sources/scala/tools/scalap/Names.scala
new file mode 100644
index 0000000000..bc3d79eba1
--- /dev/null
+++ b/sources/scala/tools/scalap/Names.scala
@@ -0,0 +1,85 @@
+package scalap;
+
+object Names {
+
+ val operatorName = new Array[String](128);
+ operatorName('$') = "$";
+ operatorName('~') = "$tilde";
+ operatorName('=') = "$eq";
+ operatorName('<') = "$less";
+ operatorName('>') = "$greater";
+ operatorName('!') = "$bang";
+ operatorName('#') = "$hash";
+ operatorName('%') = "$percent";
+ operatorName('^') = "$up";
+ operatorName('&') = "$amp";
+ operatorName('|') = "$bar";
+ operatorName('*') = "$times";
+ operatorName('/') = "$div";
+ operatorName('+') = "$plus";
+ operatorName('-') = "$minus";
+ operatorName(':') = "$colon";
+
+ /** Replace operator symbols by corresponding "$op_name" in names.
+ */
+ def encode(name: String): String = {
+ var i = 0;
+ val len = name.length();
+ val res = new StringBuffer();
+ while (i < len) {
+ val c = name.charAt(i);
+ if (c < 128) {
+ val nop = operatorName(c);
+ if (nop == null)
+ res.append(c);
+ else
+ res.append(nop);
+ } else
+ res.append(c);
+ i = i + 1;
+ }
+ res.toString()
+ }
+
+ /** Replace "$op_name" by corresponding operator symbols in names.
+ */
+ def decode(name: String): String = {
+ var i = 0;
+ val len = name.length();
+ val res = new StringBuffer();
+ while (i < len) {
+ val c = name.charAt(i);
+ if (c == '$') {
+ var j = len;
+ while (j > i) {
+ val prefix = name.substring(i, j);
+ val c = lookup(prefix);
+ if (c != null) {
+ i = j;
+ res.append(c);
+ } else
+ j = j - 1;
+ }
+ } else {
+ i = i + 1;
+ res.append(c);
+ }
+ }
+ res.toString()
+ }
+
+ /** Looks up the array entry for the operator name.
+ */
+ def lookup(string: String): String = {
+ var i = 0;
+ var res: String = null;
+ while (i < 128) {
+ if (string.equals(operatorName(i))) {
+ res = String.valueOf(i.asInstanceOf[Char]);
+ i = 128;
+ }
+ i = i + 1;
+ }
+ res
+ }
+}
diff --git a/sources/scala/tools/scalap/ScalaAttribute.scala b/sources/scala/tools/scalap/ScalaAttribute.scala
new file mode 100644
index 0000000000..f4aa413b52
--- /dev/null
+++ b/sources/scala/tools/scalap/ScalaAttribute.scala
@@ -0,0 +1,95 @@
+package scalap;
+
+import scala.collection.mutable._;
+
+
+class ScalaAttribute(in: ByteArrayReader) {
+
+ val table = readTable;
+
+ def readTable: Array[AttribEntry] = {
+ val res = new Array[AttribEntry](in.nextNat);
+ var i = 0;
+ while (i < res.length) {
+ res(i) = readTableEntry;
+ i = i + 1;
+ }
+ res
+ }
+
+ def readTableEntry: AttribEntry = {
+ val tag = in.nextByte;
+ val len = in.nextNat;
+ //Console.println("" + tag + ": " + len);
+ val end = in.bp + len;
+ tag match {
+ case 1 /* TERMname */ =>
+ TermName(in.nextUTF8(len))
+ case 2 /* TYPEname */ =>
+ TypeName(in.nextUTF8(len))
+ case 3 /* NONEsym */ =>
+ NoneSym()
+ case 4 /* TYPEsym */ =>
+ TypeSym(readSymInfo, in.nextNat)
+ case 5 /* ALIASsym */ =>
+ AliasSym(readSymInfo, in.nextNat)
+ case 6 /* CLASSsym */ =>
+ ClassSym(readSymInfo, in.nextNat, in.nextNat)
+ case 7 /* VALsym */ =>
+ ValSym(readSymInfo, if (in.bp < end) in.nextNat else -1)
+ case 8 /* EXTref */ =>
+ ExtRef(false, in.nextNat, if (in.bp < end) in.nextNat else -1)
+ case 9 /* EXTMODCLASSref */ =>
+ ExtRef(true, in.nextNat, if (in.bp < end) in.nextNat else -1)
+ case 10 /* NOtpe */ =>
+ NoneType()
+ case 11 /* THIStpe */ =>
+ SelfType(in.nextNat)
+ case 12 /* SINGLEtpe */ =>
+ SingleType(in.nextNat, in.nextNat)
+ case 13 /* TYPEREFtpe */ =>
+ TypeReference(in.nextNat, in.nextNat, readRefs(end))
+ case 14 /* COMPOUNDtpe */ =>
+ CompoundTypeRef(in.nextNat, readRefs(end))
+ case 15 /* METHODtpe */ =>
+ MethodTypeRef(in.nextNat, readRefs(end))
+ case 16 /* POLYtpe */ =>
+ PolyTypeRef(in.nextNat, readRefs(end))
+ case 17 /* OVERLOADEDtpe */ =>
+ OverloadedTypeRef(readRefs(end))
+ case 20 /* FLAGGEDtpe */ =>
+ FlaggedType(in.nextNat, in.nextNat)
+ }
+ }
+
+ def readSymInfo: SymbolInfo =
+ SymbolInfo(in.nextNat, in.nextNat, in.nextNat, in.nextNat);
+
+ def readRefs(end: Int): List[Int] = {
+ var res = new Buffer[Int];
+ while (in.bp < end)
+ res += in.nextNat;
+ res.toList
+ }
+
+ class AttribEntry;
+ case class TermName(name: String) extends AttribEntry;
+ case class TypeName(name: String) extends AttribEntry;
+ case class NoneSym() extends AttribEntry;
+ case class TypeSym(info: SymbolInfo, lobound: Int) extends AttribEntry;
+ case class AliasSym(info: SymbolInfo, constr: Int) extends AttribEntry;
+ case class ClassSym(info: SymbolInfo, thistpe: Int, constr: Int) extends AttribEntry;
+ case class ValSym(info: SymbolInfo, classsym: Int) extends AttribEntry;
+ case class ExtRef(mod: Boolean, name: Int, owner: Int) extends AttribEntry;
+ case class NoneType() extends AttribEntry;
+ case class SelfType(sym: Int) extends AttribEntry;
+ case class SingleType(typeref: Int, sym: Int) extends AttribEntry;
+ case class TypeReference(typeref: Int, sym: Int, args: List[Int]) extends AttribEntry;
+ case class CompoundTypeRef(sym: Int, components: List[Int]) extends AttribEntry;
+ case class MethodTypeRef(res: Int, args: List[Int]) extends AttribEntry;
+ case class PolyTypeRef(tpe: Int, sym: List[Int]) extends AttribEntry;
+ case class OverloadedTypeRef(symandtpe: List[Int]) extends AttribEntry;
+ case class FlaggedType(flags: Int, tpe: Int) extends AttribEntry;
+
+ case class SymbolInfo(name: Int, owner: Int, flags: Int, info: Int);
+}
diff --git a/sources/scala/tools/scalap/ScalaWriter.scala b/sources/scala/tools/scalap/ScalaWriter.scala
new file mode 100644
index 0000000000..c829abb892
--- /dev/null
+++ b/sources/scala/tools/scalap/ScalaWriter.scala
@@ -0,0 +1,219 @@
+package scalap;
+
+import java.io._;
+import scala.collection.mutable._;
+
+
+class ScalaWriter(writer: Writer) extends CodeWriter(writer) {
+
+ def printFlags(flags: Int): Unit = {
+ val buffer = new StringBuffer();
+ var x: StringBuffer = buffer;
+ if (Flags.isPrivate(flags))
+ x = buffer.append("private ");
+ if (Flags.isProtected(flags))
+ x = buffer.append("protected ");
+ if (Flags.isAbstract(flags) && !Flags.isTrait(flags))
+ x = buffer.append("abstract ");
+ if (Flags.isFinal(flags) && !Flags.isObj(flags))
+ x = buffer.append("final ");
+ if (Flags.isSealed(flags))
+ x = buffer.append("sealed ");
+ if (Flags.isCase(flags))
+ x = buffer.append("case ");
+ if (Flags.isDef(flags))
+ x = buffer.append("def ");
+ if (Flags.isOverride(flags))
+ x = buffer.append("override ");
+ print(buffer.toString())*
+ }
+
+ def printType(tpe: Type): Unit = {
+ printType0(tpe);
+ tpe match {
+ case ThisType(_) => print(".type")*
+ case SingletonType(_, _) => print(".type")*
+ case _ =>
+ }
+ }
+
+ def printTypes(tpes: List[Type], begin: String, infix: String, end: String): Unit = {
+ if (!tpes.isEmpty)
+ printTypes0(tpes, begin, infix, end);
+ }
+
+ def printTypes0(tpes: List[Type], begin: String, infix: String, end: String): Unit = {
+ print(begin)*;
+ if (!tpes.isEmpty) {
+ printType(tpes.head);
+ tpes.tail foreach (t => { print(infix)*; printType(t) });
+ }
+ print(end)*;
+ }
+
+ def printType0(tpe: Type): Unit = tpe match {
+ case NoType =>
+ case ThisType(sym) => sym match {
+ case x: ExternalSymbol => print(sym.fullname)*
+ case NoSymbol => print("this")*
+ case _ => print(sym.fullname).print(".this")*
+ }
+ case SingletonType(tpe, sym) =>
+ printPrefix(tpe);
+ print(sym.name)*
+ case TypeRef(tpe, sym, args) =>
+ printPrefix(tpe);
+ print(sym.name)*;
+ printTypes(args, "[", ", ", "]");
+ case CompoundType(clazz, components) =>
+ printTypes(components, "", " with ", "");
+ if (clazz != NoSymbol)
+ printScope(clazz.members);
+ case MethodType(_, _) =>
+ var tpe0 = tpe;
+ while (tpe0.isInstanceOf[MethodType]) {
+ tpe0 match {
+ case MethodType(argtpes, restpe) =>
+ printTypes0(argtpes, "(", ", ", ")");
+ tpe0 = restpe;
+ }
+ }
+ print(":").newspace*;
+ printType(tpe0);
+ case PolyType(tpe, tvars) =>
+ print("[")*;
+ if (!tvars.isEmpty) {
+ printTVar(tvars.head);
+ tvars.tail foreach (sym => {print(", ")*; printTVar(sym);});
+ }
+ print("]")*;
+ printType(tpe);
+ case OverloadedType(_, tpes) =>
+ printTypes(tpes, "", " <and> ", "");
+ case TypeFlag(TypeRef(_, _, List(tpe0)), flags) =>
+ if ((flags & 8) != 0)
+ print("def ")*;
+ printType(tpe0);
+ if ((flags & 4) != 0)
+ print("*")*;
+ case TypeFlag(tpe0, flags) =>
+ if ((flags & 8) != 0)
+ print("def ")*;
+ printType(tpe0);
+ case _ => print("<unknown type>")*;
+ }
+
+ def printPrefix(tpe: Type): Unit = tpe match {
+ case NoType =>
+ case ThisType(NoSymbol) =>
+ case ThisType(sym) =>
+ if (sym.name.length() != 0) {
+ printType0(tpe);
+ print(".")*
+ }
+ case TypeRef(_, _, _) =>
+ printType0(tpe);
+ print("#")*
+ case _ =>
+ printType0(tpe);
+ print(".")*
+ }
+
+ def printTVar(tvar: Symbol): Unit = tvar match {
+ case sym: TypeSymbol => print(sym.name);
+ if (!isExternalType(sym.tpe, "Any")) {
+ print(" <: ")*;
+ printType(sym.tpe);
+ }
+ if (!isExternalType(sym.lower, "All")) {
+ print(" >: ")*;
+ printType(sym.lower);
+ }
+ }
+
+ def isExternalType(tpe: Type, name: String): Boolean = tpe match {
+ case TypeRef(SingletonType(ThisType(root), pck), sym, Nil) =>
+ (root.name.length() == 0) &&
+ pck.name.equals("scala") &&
+ sym.name.equals(name)
+ case _ => false
+ }
+
+ def printSymbol(sym: Symbol): Unit = sym match {
+ case NoSymbol =>
+ print("<nosymbol>")*
+ case s: TypeSymbol =>
+ print(Flags.toString(s.flags))*;
+ print("type ")*;
+ printTVar(s);
+ case s: AliasSymbol =>
+ print(Flags.toString(s.flags))*;
+ print("type " + s.name + " = ")*;
+ printType(s.tpe);
+ case s: ClassSymbol =>
+ print(Flags.toString(s.flags))*;
+ if (Flags.isDeferred(s.flags))
+ print("/*deferred*/ ")*;
+ if (Flags.isObj(s.flags))
+ print("object " + s.name);
+ else if (Flags.isTrait(s.flags))
+ print("trait " + s.name)*;
+ else
+ print("class " + s.name)*;
+ printConstr(s.constr);
+ print(" extends ");
+ printType(s.tpe);
+ case s: ValSymbol =>
+ s.tpe match {
+ case PolyType(tpe, Nil) =>
+ print("def " + s.name + ": ")*;
+ printType(tpe);
+ case PolyType(_, _) =>
+ print("def " + s.name)*;
+ printType(s.tpe);
+ case MethodType(_, _) =>
+ print("def " + s.name)*;
+ printType(s.tpe);
+ case _ =>
+ print("val " + s.name + ": ")*;
+ printType(s.tpe);
+ }
+ case s: ExternalSymbol =>
+ print("<externalsymbol: " + s.fullname + ">")*
+ }
+
+ def printConstr(sym: Symbol): Unit = sym match {
+ case s: ValSymbol =>
+ s.tpe match {
+ case PolyType(MethodType(argtpes, _), tvars) =>
+ print("[")*;
+ if (!tvars.isEmpty) {
+ printTVar(tvars.head);
+ tvars.tail foreach (sym => {print(", ")*; printTVar(sym);});
+ }
+ print("]")*;
+ printTypes(argtpes, "(", ", ", ")");
+ case MethodType(argtpes, _) =>
+ printTypes(argtpes, "(", ", ", ")");
+ case _ =>
+ }
+ }
+
+ def printScope(scope: Buffer[Symbol]): Unit = {
+ var first = true;
+ scope.elements foreach (
+ sym => { sym match {
+ case s: ValSymbol if
+ (s.tpe.isInstanceOf[OverloadedType] ||
+ (Flags.isCaseAccessor(s.flags) &&
+ !s.tpe.isInstanceOf[PolyType])) =>
+ case _ =>
+ if (first) print(" {").indent* else print(";")*;
+ first = false;
+ newline*;
+ printSymbol(sym);
+ }});
+ if (!first)
+ newline.undent.print("}")*
+ }
+}