summaryrefslogtreecommitdiff
path: root/src/scalap
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@epfl.ch>2009-02-09 16:06:06 +0000
committerLukas Rytz <lukas.rytz@epfl.ch>2009-02-09 16:06:06 +0000
commit76009173e08545c346d4a66eb847a75120649ad2 (patch)
treead271feec9a4411bd9e4d67a7d93ee35b32d0bca /src/scalap
parent9191eb8dd882e04bee79907bda69d5018ee5ed99 (diff)
downloadscala-76009173e08545c346d4a66eb847a75120649ad2.tar.gz
scala-76009173e08545c346d4a66eb847a75120649ad2.tar.bz2
scala-76009173e08545c346d4a66eb847a75120649ad2.zip
added build scripts for scalap
Diffstat (limited to 'src/scalap')
-rw-r--r--src/scalap/scala/tools/scalap/Arguments.scala202
-rw-r--r--src/scalap/scala/tools/scalap/ByteArrayReader.scala157
-rw-r--r--src/scalap/scala/tools/scalap/Classfile.scala126
-rw-r--r--src/scalap/scala/tools/scalap/Classfiles.scala56
-rw-r--r--src/scalap/scala/tools/scalap/CodeWriter.scala140
-rw-r--r--src/scalap/scala/tools/scalap/JavaWriter.scala234
-rw-r--r--src/scalap/scala/tools/scalap/Main.scala266
-rw-r--r--src/scalap/scala/tools/scalap/MetaParser.scala184
-rw-r--r--src/scalap/scala/tools/scalap/Names.scala97
-rw-r--r--src/scalap/scala/tools/scalap/Properties.scala50
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/Arrows.scala35
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/Functors.scala79
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/Input.scala66
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/Memoisable.scala59
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/Monad.scala44
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/Result.scala70
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/Rule.scala175
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/Rules.scala144
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/SeqRule.scala99
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala221
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/scalasig/Flags.scala66
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala269
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala322
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/scalasig/SourceFileAttributeParser.scala25
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/scalasig/Symbol.scala70
-rw-r--r--src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala22
-rw-r--r--src/scalap/scala/tools/scalap/scalax/util/StringUtil.scala15
27 files changed, 3293 insertions, 0 deletions
diff --git a/src/scalap/scala/tools/scalap/Arguments.scala b/src/scalap/scala/tools/scalap/Arguments.scala
new file mode 100644
index 0000000000..4810adf1af
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/Arguments.scala
@@ -0,0 +1,202 @@
+/* ___ ____ ___ __ ___ ___
+** / _// __// _ | / / / _ | / _ \ Scala classfile decoder
+** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2006, LAMP/EPFL
+** /____/\___/_/ |_/____/_/ |_/_/
+**
+*/
+
+// $Id: Arguments.scala 5837 2006-02-23 17:37:25 +0000 (Thu, 23 Feb 2006) michelou $
+
+package scala.tools.scalap
+
+import scala.collection.mutable._
+
+
+object Arguments {
+
+ case class Parser(optionPrefix: Char) {
+
+ val options: Set[String] = new HashSet
+ val prefixes: Set[String] = new HashSet
+ val optionalArgs: Set[String] = new HashSet
+ val prefixedBindings: Map[String, Char] = new HashMap
+ val optionalBindings: Map[String, Char] = new HashMap
+
+ def error(message: String): Unit = Console.println(message)
+
+ def withOption(option: String): Parser = {
+ options += option
+ this
+ }
+
+ def withOptionalArg(option: String): Parser = {
+ optionalArgs += option
+ this
+ }
+
+ def withOptionalBinding(option: String, separator: Char): Parser = {
+ optionalBindings(option) = separator
+ this
+ }
+
+ def withPrefixedArg(prefix: String): Parser = {
+ prefixes += prefix
+ this
+ }
+
+ def withPrefixedBinding(prefix: String, separator: Char): Parser = {
+ prefixedBindings(prefix) = separator
+ this
+ }
+
+ def parseBinding(str: String, separator: Char): Pair[String, String] = {
+ val eqls = str.indexOf(separator)
+ if (eqls < 0) {
+ error("missing '" + separator + "' in binding '" + str + "'")
+ Pair("", "")
+ } else
+ Pair(str.substring(0, eqls).trim(),
+ str.substring(eqls + 1).trim())
+ }
+
+ def parse(args: Array[String]): Arguments = {
+ val res = new Arguments
+ parse(args, res)
+ res
+ }
+
+ def parse(args: Array[String], res: Arguments): Unit = {
+ if (args != null) {
+ var i = 0;
+ while (i < args.length)
+ if ((args(i) == null) || (args(i).length() == 0))
+ i = i + 1
+ else if (args(i).charAt(0) != optionPrefix) {
+ res.addOther(args(i))
+ i = i + 1
+ } else if (options contains args(i)) {
+ res.addOption(args(i))
+ i = i + 1
+ } else if (optionalArgs contains args(i)) {
+ if ((i + 1) == args.length) {
+ error("missing argument for '" + args(i) + "'")
+ i = i + 1
+ } else {
+ res.addArgument(args(i), args(i + 1))
+ i = i + 2
+ }
+ } else if (optionalBindings contains args(i)) {
+ if ((i + 1) == args.length) {
+ error("missing argument for '" + args(i) + "'")
+ i = i + 1
+ } else {
+ res.addBinding(args(i),
+ parseBinding(args(i + 1), optionalBindings(args(i))));
+ i = i + 2
+ }
+ } else {
+ var iter = prefixes.elements
+ val j = i
+ while ((i == j) && iter.hasNext) {
+ val prefix = iter.next
+ if (args(i) startsWith prefix) {
+ res.addPrefixed(prefix, args(i).substring(prefix.length()).trim());
+ i = i + 1
+ }
+ }
+ if (i == j) {
+ val iter = prefixedBindings.keys;
+ while ((i == j) && iter.hasNext) {
+ val prefix = iter.next
+ if (args(i) startsWith prefix) {
+ val arg = args(i).substring(prefix.length()).trim()
+ i = i + 1
+ res.addBinding(prefix,
+ parseBinding(arg, prefixedBindings(prefix)));
+ }
+ }
+ if (i == j) {
+ error("unknown option '" + args(i) + "'")
+ i = i + 1
+ }
+ }
+ }
+ }
+ }
+ }
+
+ def parse(options: String*)(args: Array[String]): Arguments = {
+ val parser = new Parser('-')
+ val iter = options.elements
+ while (iter.hasNext)
+ parser withOption iter.next
+ parser.parse(args)
+ }
+}
+
+class Arguments {
+
+ private val options: Set[String] = new HashSet
+ private val arguments: Map[String, String] = new HashMap
+ private val prefixes: Map[String, Set[String]] = new HashMap
+ private val bindings: Map[String, Map[String, String]] = new HashMap
+ private val others: Buffer[String] = new ListBuffer
+
+ def addOption(option: String): Unit = options += option
+
+ def addArgument(option: String, arg: String): Unit = arguments(option) = arg
+
+ def addPrefixed(prefix: String, arg: String): Unit =
+ if (prefixes isDefinedAt prefix)
+ prefixes(prefix) += arg
+ else {
+ prefixes(prefix) = new HashSet
+ prefixes(prefix) += arg
+ }
+
+ def addBinding(tag: String, key: String, value: String): Unit =
+ if (key.length() > 0) {
+ if (bindings isDefinedAt tag)
+ bindings(tag)(key) = value
+ else {
+ bindings(tag) = new HashMap
+ bindings(tag)(key) = value
+ }
+ }
+
+ def addBinding(tag: String, binding: Pair[String, String]): Unit =
+ addBinding(tag, binding._1, binding._2)
+
+ def addOther(arg: String): Unit = others += arg
+
+ def contains(option: String): Boolean = options contains option
+
+ def getArgument(option: String): Option[String] = arguments get option
+
+ def getSuffixes(prefix: String): Set[String] =
+ prefixes.get(prefix) match {
+ case None => new HashSet
+ case Some(set) => set
+ }
+
+ def containsSuffix(prefix: String, suffix: String): Boolean =
+ prefixes.get(prefix) match {
+ case None => false
+ case Some(set) => set contains suffix
+ }
+
+ def getBindings(tag: String): Map[String, String] =
+ bindings.get(tag) match {
+ case None => new HashMap
+ case Some(map) => map
+ }
+
+ def getBinding(option: String, key: String): Option[String] =
+ bindings.get(option) match {
+ case None => None
+ case Some(map) => map get key
+ }
+
+ def getOthers: List[String] = others.toList
+
+}
diff --git a/src/scalap/scala/tools/scalap/ByteArrayReader.scala b/src/scalap/scala/tools/scalap/ByteArrayReader.scala
new file mode 100644
index 0000000000..13f62ebfd9
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/ByteArrayReader.scala
@@ -0,0 +1,157 @@
+/* ___ ____ ___ __ ___ ___
+** / _// __// _ | / / / _ | / _ \ Scala classfile decoder
+** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2006, LAMP/EPFL
+** /____/\___/_/ |_/____/_/ |_/_/
+**
+*/
+
+// $Id: ByteArrayReader.scala 5837 2006-02-23 17:37:25 +0000 (Thu, 23 Feb 2006) michelou $
+
+package scala.tools.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 the next signed number in big endian format
+ */
+ def nextNum(n: Int): Long = {
+ var x: Long = 0
+ var i: Int = 0
+ while (i < n) {
+ x = (x << 8) + (nextByte & 0xff)
+ i = i + 1
+ }
+ val leading: Int = 64 - (n * 8)
+ x << leading >> leading
+ }
+
+ /** 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/src/scalap/scala/tools/scalap/Classfile.scala b/src/scalap/scala/tools/scalap/Classfile.scala
new file mode 100644
index 0000000000..795f4ec613
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/Classfile.scala
@@ -0,0 +1,126 @@
+/* ___ ____ ___ __ ___ ___
+** / _// __// _ | / / / _ | / _ \ Scala classfile decoder
+** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2006, LAMP/EPFL
+** /____/\___/_/ |_/____/_/ |_/_/
+**
+*/
+
+// $Id: Classfile.scala 5837 2006-02-23 17:37:25 +0000 (Thu, 23 Feb 2006) michelou $
+
+package scala.tools.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 CONSTANT_UTF8 =>
+ pool(i) = UTF8(in.nextUTF8(in.nextChar))
+ case CONSTANT_UNICODE =>
+ in.skip(in.nextChar)
+ pool(i) = Empty()
+ case CONSTANT_CLASS =>
+ pool(i) = ClassRef(in.nextChar)
+ case CONSTANT_STRING =>
+ pool(i) = StringConst(in.nextChar)
+ case CONSTANT_FIELDREF =>
+ pool(i) = FieldRef(in.nextChar, in.nextChar)
+ case CONSTANT_METHODREF =>
+ pool(i) = MethodRef(in.nextChar, in.nextChar)
+ case CONSTANT_INTFMETHODREF =>
+ pool(i) = IntfMethodRef(in.nextChar, in.nextChar)
+ case CONSTANT_NAMEANDTYPE =>
+ pool(i) = NameAndType(in.nextChar, in.nextChar)
+ case CONSTANT_INTEGER =>
+ pool(i) = IntegerConst(in.nextInt)
+ case CONSTANT_FLOAT =>
+ pool(i) = FloatConst(in.nextFloat)
+ case CONSTANT_LONG =>
+ pool(i) = LongConst(in.nextLong)
+ i = i + 1
+ pool(i) = Empty()
+ case 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/src/scalap/scala/tools/scalap/Classfiles.scala b/src/scalap/scala/tools/scalap/Classfiles.scala
new file mode 100644
index 0000000000..d9e85e9d9e
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/Classfiles.scala
@@ -0,0 +1,56 @@
+/* ___ ____ ___ __ ___ ___
+** / _// __// _ | / / / _ | / _ \ Scala classfile decoder
+** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2006, LAMP/EPFL
+** /____/\___/_/ |_/____/_/ |_/_/
+**
+*/
+
+// $Id: Classfiles.scala 5837 2006-02-23 17:37:25 +0000 (Thu, 23 Feb 2006) michelou $
+
+package scala.tools.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/src/scalap/scala/tools/scalap/CodeWriter.scala b/src/scalap/scala/tools/scalap/CodeWriter.scala
new file mode 100644
index 0000000000..b0ad39bd12
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/CodeWriter.scala
@@ -0,0 +1,140 @@
+/* ___ ____ ___ __ ___ ___
+** / _// __// _ | / / / _ | / _ \ Scala classfile decoder
+** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2006, LAMP/EPFL
+** /____/\___/_/ |_/____/_/ |_/_/
+**
+*/
+
+// $Id: CodeWriter.scala 5837 2006-02-23 17:37:25 +0000 (Thu, 23 Feb 2006) michelou $
+
+package scala.tools.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/src/scalap/scala/tools/scalap/JavaWriter.scala b/src/scalap/scala/tools/scalap/JavaWriter.scala
new file mode 100644
index 0000000000..46d1f0fb56
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/JavaWriter.scala
@@ -0,0 +1,234 @@
+/* ___ ____ ___ __ ___ ___
+** / _// __// _ | / / / _ | / _ \ Scala classfile decoder
+** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2006, LAMP/EPFL
+** /____/\___/_/ |_/____/_/ |_/_/
+**
+*/
+
+// $Id: JavaWriter.scala 5838 2006-02-23 17:54:21Z michelou $
+
+package scala.tools.scalap
+
+import java.io._
+
+
+class JavaWriter(classfile: Classfile, writer: Writer) extends CodeWriter(writer) {
+
+ val cf = classfile
+
+ def flagsToStr(clazz: Boolean, flags: Int) = {
+ val buffer = new StringBuffer()
+ var x: StringBuffer = buffer
+ if (((flags & 0x0007) == 0) &&
+ ((flags & 0x0002) != 0))
+ x = buffer.append("private ")
+ if ((flags & 0x0004) != 0)
+ x = buffer.append("protected ")
+ if ((flags & 0x0010) != 0)
+ x = buffer.append("final ")
+ if ((flags & 0x0400) != 0)
+ x = if (clazz) buffer.append("abstract ")
+ else buffer.append("/*deferred*/ ")
+ buffer.toString()
+ }
+
+ def nameToClass(str: String) = {
+ val res = Names.decode(str.replace('/', '.'))
+ if (res == "java.lang.Object") "scala.Any" else res
+ }
+
+ def nameToClass0(str: String) = {
+ val res = Names.decode(str.replace('/', '.'))
+ if (res == "java.lang.Object") "scala.AnyRef" else res
+ }
+
+ def nameToSimpleClass(str: String) =
+ Names.decode(str.substring(str.lastIndexOf('/') + 1))
+
+ def nameToPackage(str: String) = {
+ val inx = str.lastIndexOf('/')
+ val name = if (inx == -1) str else str.substring(0, inx).replace('/', '.')
+ Names.decode(name)
+ }
+
+ def sigToType(str: String): String =
+ sigToType(str, 0)._1
+
+ def sigToType(str: String, i: Int): Pair[String, Int] = str.charAt(i) match {
+ case 'B' => Pair("scala.Byte", i + 1)
+ case 'C' => Pair("scala.Char", i + 1)
+ case 'D' => Pair("scala.Double", i + 1)
+ case 'F' => Pair("scala.Float", i + 1)
+ case 'I' => Pair("scala.Int", i + 1)
+ case 'J' => Pair("scala.Long", i + 1)
+ case 'S' => Pair("scala.Short", i + 1)
+ case 'V' => Pair("scala.Unit", i + 1)
+ case 'Z' => Pair("scala.Boolean", i + 1)
+ case 'L' => val j = str.indexOf(';', i);
+ Pair(nameToClass(str.substring(i + 1, j)), j + 1)
+ case '[' => val Pair(tpe, j) = sigToType(str, i + 1);
+ Pair("scala.Array[" + tpe + "]", j)
+ case '(' => val Pair(tpe, j) = sigToType0(str, i + 1);
+ Pair("(" + tpe, j)
+ case ')' => val Pair(tpe, j) = sigToType(str, i + 1);
+ Pair("): " + tpe, j)
+ }
+
+ def sigToType0(str: String, i: Int): Pair[String, Int] =
+ if (str.charAt(i) == ')')
+ sigToType(str, i)
+ else {
+ val Pair(tpe, j) = sigToType(str, i)
+ if (str.charAt(j) == ')') {
+ val Pair(rest, k) = sigToType(str, j)
+ Pair(tpe + rest, k)
+ } else {
+ val Pair(rest, k) = sigToType0(str, j)
+ Pair(tpe + ", " + rest, k)
+ }
+ }
+
+ def getName(n: Int): String = cf.pool(n) match {
+ case cf.UTF8(str) => str
+ case cf.StringConst(m) => getName(m)
+ case cf.ClassRef(m) => getName(m)
+ case x => "<error>"
+ }
+
+ def getClassName(n: Int): String = nameToClass(getName(n))
+
+ def getSimpleClassName(n: Int): String = nameToSimpleClass(getName(n))
+
+ def getPackage(n: Int): String = nameToPackage(getName(n))
+
+ def getType(n: Int): String = sigToType(getName(n))
+
+ def isStatic(flags: Int) = (flags & 0x0008) != 0
+
+ def isInterface(flags: Int) = (flags & 0x0200) != 0
+
+ def isConstr(name: String) = (name == "<init>")
+
+ def printField(flags: Int, name: Int, tpe: Int, attribs: List[cf.Attribute]) = {
+ print(flagsToStr(false, flags))
+ if ((flags & 0x0010) != 0)
+ print("val " + Names.decode(getName(name)))
+ else
+ print("final var " + Names.decode(getName(name)))
+ print(": " + getType(tpe) + ";").newline
+ }
+
+ def printMethod(flags: Int, name: Int, tpe: Int, attribs: List[cf.Attribute]) = {
+ if (getName(name) == "<init>")
+ print(flagsToStr(false, flags))
+ attribs find {
+ case cf.Attribute(name, _) => getName(name) == "JacoMeta"
+ } match {
+ case Some(cf.Attribute(_, data)) =>
+ val mp = new MetaParser(getName(
+ ((data(0) & 0xff) << 8) + (data(1) & 0xff)).trim())
+ mp.parse match {
+ case None =>
+ if (getName(name) == "<init>") {
+ print("def this" + getType(tpe) + ";").newline
+ } else {
+ print("def " + Names.decode(getName(name)))
+ print(getType(tpe) + ";").newline
+ }
+ case Some(str) =>
+ if (getName(name) == "<init>")
+ print("def this" + str + ";").newline
+ else
+ print("def " + Names.decode(getName(name)) + str + ";").newline
+ }
+ case None =>
+ if (getName(name) == "<init>") {
+ print("def this" + getType(tpe) + ";").newline
+ } else {
+ print("def " + Names.decode(getName(name)))
+ print(getType(tpe) + ";").newline
+ }
+ }
+ attribs find {
+ case cf.Attribute(name, _) => getName(name) == "Exceptions"
+ } match {
+ case Some(cf.Attribute(_, data)) =>
+ val n = ((data(0) & 0xff) << 8) + (data(1) & 0xff)
+ indent.print("throws ")
+ for (val i <- Iterator.range(0, n) map {x => 2 * (x + 1)}) {
+ val inx = ((data(i) & 0xff) << 8) + (data(i+1) & 0xff)
+ if (i > 2) print(", ")
+ print(getClassName(inx).trim())
+ }
+ undent.newline
+ case None =>
+ }
+ }
+
+ def printClassHeader = {
+ if (isInterface(cf.flags)) {
+ print("trait " + getSimpleClassName(cf.classname))
+ } else {
+ print("class " + getSimpleClassName(cf.classname))
+ if (cf.pool(cf.superclass) != null)
+ print(" extends " + nameToClass0(getName(cf.superclass)))
+ }
+ cf.interfaces foreach {
+ n => print(" with " + getClassName(n))
+ }
+ }
+
+ def printClass = {
+ val pck = getPackage(cf.classname);
+ if (pck.length() > 0)
+ println("package " + pck + ";")
+ print(flagsToStr(true, cf.flags))
+ cf.attribs find {
+ case cf.Attribute(name, _) => getName(name) == "JacoMeta"
+ } match {
+ case None =>
+ printClassHeader;
+ case Some(cf.Attribute(_, data)) =>
+ val mp = new MetaParser(getName(
+ ((data(0) & 0xff) << 8) + (data(1) & 0xff)).trim());
+ mp.parse match {
+ case None => printClassHeader;
+ case Some(str) =>
+ if (isInterface(cf.flags))
+ print("trait " + getSimpleClassName(cf.classname) + str);
+ else
+ print("class " + getSimpleClassName(cf.classname) + str);
+ }
+ }
+ var statics: List[cf.Member] = Nil
+ print(" {").indent.newline
+ cf.fields foreach {
+ case m@cf.Member(_, flags, name, tpe, attribs) =>
+ if (isStatic(flags))
+ statics = m :: statics
+ else
+ printField(flags, name, tpe, attribs)
+ }
+ cf.methods foreach {
+ case m@cf.Member(_, flags, name, tpe, attribs) =>
+ if (isStatic(flags))
+ statics = m :: statics
+ else
+ printMethod(flags, name, tpe, attribs)
+ }
+ undent.print("}").newline
+ if (!statics.isEmpty) {
+ print("object " + getSimpleClassName(cf.classname) + " {")
+ indent.newline
+ statics foreach {
+ case cf.Member(true, flags, name, tpe, attribs) =>
+ printField(flags, name, tpe, attribs)
+ case cf.Member(false, flags, name, tpe, attribs) =>
+ if (getName(name) != "<clinit>")
+ printMethod(flags, name, tpe, attribs)
+ }
+ undent.print("}").newline
+ }
+ }
+
+}
diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala
new file mode 100644
index 0000000000..6e91e00234
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/Main.scala
@@ -0,0 +1,266 @@
+/* ___ ____ ___ __ ___ ___
+** / _// __// _ | / / / _ | / _ \ Scala classfile decoder
+** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2009, LAMP/EPFL
+** /____/\___/_/ |_/____/_/ |_/_/ http://scala-lang.org/
+**
+*/
+
+// $Id: Main.scala 9834 2007-01-31 16:31:25Z michelou $
+
+package scala.tools.scalap
+
+
+import java.io.{File, PrintStream, OutputStreamWriter, ByteArrayOutputStream}
+import scala.tools.nsc.util.ClassPath
+import scalax.rules.scalasig._
+
+/**The main object used to execute scalap on the command-line.
+ *
+ * @author Matthias Zenger, Stephane Micheloud, Burak Emir, Ilya Sergey
+ */
+object Main {
+ val SCALA_SIG = "ScalaSig"
+ val versionMsg = "Scala classfile decoder " +
+ Properties.versionString + " -- " +
+ Properties.copyrightString
+
+ /**Verbose program run?
+ */
+ var verbose = false
+
+ /**Prints usage information for scalap.
+ */
+ def usage: Unit = {
+ Console.println("usage: scalap {<option>} <name>")
+ Console.println("where <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")
+ Console.println(" -help display this usage message")
+ Console.println(" -classpath <path> specify where to find user class files")
+ Console.println(" -cp <path> specify where to find user class files")
+ }
+
+ def isScalaFile(bytes: Array[Byte]): Boolean = {
+ val byteCode = ByteCode(bytes)
+ val classFile = ClassFileParser.parse(byteCode)
+ classFile.attribute("ScalaSig") match {case Some(_) => true; case None => false}
+ }
+
+ /**Processes the given Java class file.
+ *
+ * @param clazz the class file to be processed.
+ */
+ def processJavaClassFile(clazz: Classfile): Unit = {
+ // construct a new output stream writer
+ val out = new OutputStreamWriter(Console.out)
+ val writer = new JavaWriter(clazz, out)
+ // print the class
+ writer.printClass
+ out.flush()
+ }
+
+ def parseScalaSignature(scalaSig: ScalaSig) = {
+ val baos = new ByteArrayOutputStream
+ val stream = new PrintStream(baos)
+ val syms = scalaSig.topLevelClasses ::: scalaSig.topLevelObjects
+ syms.first.parent match {
+ //Partial match
+ case Some(p) if (p.name != "<empty>") => {
+ stream.print("package ");
+ stream.print(p.path);
+ stream.print("\n")
+ }
+ case _ =>
+ }
+ // Print classes
+ val printer = new ScalaSigPrinter(stream)
+ for (c <- syms) {
+ printer.printSymbol(c)
+ }
+ baos.toString
+ }
+
+
+ def decompileScala(bytes: Array[Byte]) = {
+ 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))
+ case None => //Do nothing
+ }
+ }
+
+
+ /**Executes scalap with the given arguments and classpath for the
+ * class denoted by <code>classname</code>.
+ *
+ * @param args...
+ * @param path...
+ * @param classname...
+ */
+ def process(args: Arguments, path: ClassPath#Build)(classname: String): Unit = {
+ // find the classfile
+ val filename = Names.encode(
+ if (classname == "scala.AnyRef") "java.lang.Object"
+ else classname).replace('.', File.separatorChar)
+ val cfile = path.lookupPath(filename, /*isDir*/ false)
+ if (cfile != null) {
+ if (verbose) {
+ Console.println(Console.BOLD + "FILENAME" + Console.RESET + " = " + cfile.path)
+ }
+ val bytes = cfile.toByteArray
+ if (isScalaFile(bytes)) {
+ decompileScala(bytes)
+ } else {
+ // construct a reader for the classfile content
+ val reader = new ByteArrayReader(cfile.toByteArray)
+ // parse the classfile
+ val clazz = new Classfile(reader)
+ processJavaClassFile(clazz)
+ }
+ // if the class corresponds to the artificial class scala.All.
+ // (to be removed after update of the STARR libraries)
+ } else if (classname == "scala.All") {
+ Console.println("package scala")
+ Console.println("/* Deprecated. Use scala.Nothing instead. */")
+ Console.println("sealed abstract class All")
+ // if the class corresponds to the artificial class scala.AllRef.
+ // (to be removed after update of the STARR libraries)
+ } else if (classname == "scala.AllRef") {
+ Console.println("package scala")
+ Console.println("/* Deprecated. Use scala.Null instead. */")
+ Console.println("sealed abstract class AllRef")
+ // if the class corresponds to the artificial class scala.Any.
+ // (see member list in class scala.tool.nsc.symtab.Definitions)
+ } else if (classname == "scala.Any") {
+ Console.println("package scala")
+ Console.println("class Any {")
+ Console.println(" final def ==(scala.Any): scala.Boolean")
+ Console.println(" final def !=(scala.Any): Boolean")
+ Console.println(" def equals(scala.Any): scala.Boolean")
+ Console.println(" def hashCode(): scala.Int")
+ Console.println(" def toString(): java.lang.String")
+ Console.println(" final def isInstanceOf[a]: scala.Boolean")
+ Console.println(" final def asInstanceOf[a]: a")
+ Console.println("}")
+ // if the class corresponds to the artificial class scala.AnyRef.
+ } else if (classname == "scala.AnyRef") {
+ Console.println("package scala")
+ Console.println("class AnyRef extends Any {")
+ Console.println(" def equals(scala.Any): scala.Boolean")
+ Console.println(" def hashCode(): scala.Int")
+ Console.println(" def toString(): java.lang.String")
+ Console.println("}")
+ // if the class corresponds to the artificial class scala.AnyVal.
+ } else if (classname == "scala.AnyVal") {
+ Console.println("package scala")
+ Console.println("sealed class AnyVal extends Any")
+ // if the class corresponds to the artificial class scala.Boolean.
+ } else if (classname == "scala.Boolean") {
+ Console.println("package scala")
+ Console.println("sealed abstract class Boolean extends AnyVal {")
+ Console.println(" def &&(p: => scala.Boolean): scala.Boolean // boolean and")
+ Console.println(" def ||(p: => scala.Boolean): scala.Boolean // boolean or")
+ Console.println(" def & (x: scala.Boolean): scala.Boolean // boolean strict and")
+ Console.println(" def | (x: scala.Boolean): scala.Boolean // boolean stric or")
+ Console.println(" def ==(x: scala.Boolean): scala.Boolean // boolean equality")
+ Console.println(" def !=(x: scala.Boolean): scala.Boolean // boolean inequality")
+ Console.println(" def !: scala.Boolean // boolean negation")
+ Console.println("}")
+ // if the class corresponds to the artificial class scala.Int.
+ } else if (classname == "scala.Int") {
+ Console.println("package scala")
+ Console.println("sealed abstract class Int extends AnyVal {")
+ Console.println(" def ==(that: scala.Double): scala.Boolean")
+ Console.println(" def ==(that: scala.Float): scala.Boolean")
+ Console.println(" def ==(that: scala.Long): scala.Boolean")
+ Console.println(" def ==(that: scala.Int): scala.Boolean")
+ Console.println(" def ==(that: scala.Short): scala.Boolean")
+ Console.println(" def ==(that: scala.Byte): scala.Boolean")
+ Console.println(" def ==(that: scala.Char): scala.Boolean")
+ Console.println(" /* analogous for !=, <, >, <=, >= */")
+ Console.println
+ Console.println(" def + (that: scala.Double): scala.Double // double addition")
+ Console.println(" def + (that: scala.Float): scala.Float // float addition")
+ Console.println(" def + (that: scala.Long): scala.Long // long addition")
+ Console.println(" def + (that: scala.Int): scala.Int // int addition")
+ Console.println(" def + (that: scala.Short): scala.Int // int addition")
+ Console.println(" def + (that: scala.Byte): scala.Int // int addition")
+ Console.println(" def + (that: scala.Char): scala.Int // int addition")
+ Console.println(" /* analogous for -, *, /, % */")
+ Console.println
+ Console.println(" def & (that: scala.Long): scala.Long // long bitwise and")
+ Console.println(" def & (that: scala.Int): scala.Int // int bitwise and")
+ Console.println(" def & (that: scala.Short): scala.Int // int bitwise and")
+ Console.println(" def & (that: scala.Byte): scala.Int // int bitwise and")
+ Console.println(" def & (that: scala.Char): scala.Int // int bitwise and")
+ Console.println(" /* analogous for |, ^ */")
+ Console.println
+ Console.println(" def <<(cnt: scala.Int): scala.Int // int left shift")
+ Console.println(" def <<(cnt: scala.Long): scala.Int // long left shift")
+ Console.println(" /* analogous for >>, >>> */")
+ Console.println
+ Console.println(" def + : scala.Int // int identity")
+ Console.println(" def - : scala.Int // int negation")
+ Console.println(" def ~ : scala.Int // int bitwise negation")
+ Console.println
+ Console.println(" def toByte: scala.Byte // convert to Byte")
+ Console.println(" def toShort: scala.Short // convert to Short")
+ Console.println(" def toChar: scala.Char // convert to Char")
+ Console.println(" def toInt: scala.Int // convert to Int")
+ Console.println(" def toLong: scala.Long // convert to Long")
+ Console.println(" def toFloat: scala.Float // convert to Float")
+ Console.println(" def toDouble: scala.Double // convert to Double")
+ Console.println("}")
+ // if the class corresponds to the artificial class scala.Nothing.
+ } else if (classname == "scala.Nothing") {
+ Console.println("package scala")
+ Console.println("sealed abstract class Nothing")
+ // if the class corresponds to the artificial class scala.Null.
+ } else if (classname == "scala.Null") {
+ Console.println("package scala")
+ Console.println("sealed abstract class Null")
+ } else
+ Console.println("class/object " + classname + " not found.")
+ }
+
+ /**The main method of this object.
+ */
+ def main(args: Array[String]) {
+ // print usage information if there is no command-line argument
+ if (args.length == 0)
+ usage
+ // otherwise parse the arguments...
+ else {
+ val arguments = Arguments.Parser('-')
+ .withOption("-private")
+ .withOption("-verbose")
+ .withOption("-version")
+ .withOption("-help")
+ .withOptionalArg("-classpath")
+ .withOptionalArg("-cp")
+ .parse(args);
+ if (arguments contains "-version")
+ Console.println(versionMsg)
+ if (arguments contains "-help")
+ usage
+ verbose = arguments contains "-verbose"
+ // construct a custom class path
+ val classPath0 = new ClassPath(false)
+ val path = arguments.getArgument("-classpath") match {
+ case None => arguments.getArgument("-cp") match {
+ case None => new classPath0.Build()
+ case Some(path) => new classPath0.Build(path)
+ }
+ case Some(path) => new classPath0.Build(path)
+ }
+ // print the classpath if output is verbose
+ if (verbose) {
+ Console.println(Console.BOLD + "CLASSPATH" + Console.RESET + " = " + path)
+ }
+ // process all given classes
+ arguments.getOthers.foreach(process(arguments, path))
+ }
+ }
+}
diff --git a/src/scalap/scala/tools/scalap/MetaParser.scala b/src/scalap/scala/tools/scalap/MetaParser.scala
new file mode 100644
index 0000000000..1d3bf419db
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/MetaParser.scala
@@ -0,0 +1,184 @@
+/* ___ ____ ___ __ ___ ___
+** / _// __// _ | / / / _ | / _ \ Scala classfile decoder
+** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2006, LAMP/EPFL
+** /____/\___/_/ |_/____/_/ |_/_/
+**
+*/
+
+// $Id: MetaParser.scala 5838 2006-02-23 17:54:21Z michelou $
+
+package scala.tools.scalap
+
+import java.io._
+import java.util._
+
+
+/** a parser class for parsing meta type information in classfiles
+ * generated by pico.
+ */
+class MetaParser(meta: String) {
+ val scanner = new StringTokenizer(meta, "()[], \t<;", true)
+ var token: String = _
+ val res = new StringBuffer
+
+ private def nextToken: String = {
+ do {
+ token = scanner.nextToken().trim()
+ } while (token.length() == 0)
+ token
+ }
+
+ protected def parseType: Unit = {
+ if (token.startsWith("?"))
+ res.append(token.substring(1))
+ else
+ res.append(token)
+ nextToken
+ if (token == "[") {
+ do {
+ res.append(if (token == ",") ", " else "[")
+ nextToken
+ parseType
+ } while (token == ",")
+ nextToken
+ res.append("]")
+ }
+ }
+
+ def parse: Option[String] =
+ if (scanner.hasMoreTokens()) {
+ nextToken
+ try {
+ if (!scanner.hasMoreTokens())
+ None
+ else if (token == "class")
+ Some(parseMetaClass)
+ else if (token == "method")
+ Some(parseMetaMethod)
+ else if (token == "field")
+ Some(parseMetaField)
+ else if (token == "constr")
+ Some(parseConstrField)
+ else
+ None;
+ } catch {
+ case _ => None
+ }
+ } else
+ None;
+
+ protected def parseMetaClass: String = {
+ nextToken
+ if (token == "[") {
+ do {
+ res.append(if (token == "[") "[" else ", ")
+ nextToken
+ if (token == "+") {
+ nextToken
+ res.append('+')
+ } else if (token == "-") {
+ nextToken
+ res.append('-')
+ }
+ res.append(token.substring(1))
+ nextToken
+ if (token == "<") {
+ nextToken
+ res.append(" <: ")
+ parseType
+ }
+ } while (token == ",")
+ nextToken
+ res.append("]")
+ }
+ if (token == "extends") {
+ do {
+ if (token == "extends")
+ res.append(" extends ")
+ else
+ res.append(" with ")
+ nextToken
+ parseType
+ } while (token == "with")
+ }
+ res.toString();
+ }
+
+ protected def parseMetaMethod: String = {
+ nextToken
+ if (token == "[") {
+ nextToken
+ if (token == "]") {
+ nextToken
+ } else {
+ var loop = true
+ res.append("[")
+ while (loop) {
+ res.append(token.substring(1));
+ nextToken;
+ if (token == "<") {
+ nextToken;
+ res.append(" <: ")
+ parseType
+ }
+ if (token == ",") {
+ nextToken
+ res.append(", ")
+ } else
+ loop = false
+ }
+ nextToken
+ res.append("]")
+ }
+ }
+ if (token == "(") {
+ do {
+ if (token == ",") {
+ nextToken;
+ if (token != ")")
+ res.append(", ")
+ } else {
+ nextToken;
+ res.append("(")
+ }
+ if (token != ")") {
+ if (token == "def") {
+ nextToken;
+ res.append("def ")
+ }
+ parseType
+ }
+ } while (token == ",")
+ nextToken
+ res.append("): ")
+ parseType
+ } else {
+ res.append(": ")
+ parseType
+ }
+ res.toString()
+ }
+
+ protected def parseMetaField: String = {
+ nextToken
+ res.append(": ")
+ parseType
+ res.toString()
+ }
+
+ protected def parseConstrField: String = {
+ nextToken
+ if (token == "(") {
+ do {
+ res.append(if (token == "(") "(" else ", ")
+ nextToken
+ if (token != ")")
+ parseType
+ } while (token == ",")
+ nextToken
+ res.append(")")
+ } else {
+ }
+ res.toString()
+ }
+}
diff --git a/src/scalap/scala/tools/scalap/Names.scala b/src/scalap/scala/tools/scalap/Names.scala
new file mode 100644
index 0000000000..8bbc30a0b8
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/Names.scala
@@ -0,0 +1,97 @@
+/* ___ ____ ___ __ ___ ___
+** / _// __// _ | / / / _ | / _ \ Scala classfile decoder
+** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2006, LAMP/EPFL
+** /____/\___/_/ |_/____/_/ |_/_/
+**
+*/
+
+// $Id: Names.scala 5838 2006-02-23 17:54:21 +0000 (Thu, 23 Feb 2006) michelou $
+
+package scala.tools.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('\\') = "$bslash"
+ 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/src/scalap/scala/tools/scalap/Properties.scala b/src/scalap/scala/tools/scalap/Properties.scala
new file mode 100644
index 0000000000..1c23626aae
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/Properties.scala
@@ -0,0 +1,50 @@
+/* ___ ____ ___ __ ___ ___
+** / _// __// _ | / / / _ | / _ \ Scala classfile decoder
+** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2007, LAMP/EPFL
+** /____/\___/_/ |_/____/_/ |_/_/ http://scala-lang.org/
+**
+*/
+
+// $Id: Properties.scala 9834 2007-01-31 16:31:25Z michelou $
+
+package scala.tools.scalap
+
+/** A utility to load the compiler properties from a Java properties file
+ * included in the jar.
+ */
+object Properties {
+
+ /** The name of the properties file */
+ private val propFilename = "/decoder.properties"
+
+ /** The loaded properties */
+ private val props = {
+ val props = new java.util.Properties
+ val stream = classOf[Classfile].getResourceAsStream(propFilename)
+ if (stream != null)
+ props.load(stream)
+ props
+ }
+
+ /** The version number of the jar this was loaded from, or
+ * "(unknown)" if it cannot be determined.
+ */
+ val versionString: String = {
+ val defaultString = "(unknown)"
+ "version " + props.getProperty("version.number")
+ }
+
+ val copyrightString: String = {
+ val defaultString = "(c) 2002-2006 LAMP/EPFL"
+ props.getProperty("copyright.string", defaultString)
+ }
+
+ val scalaHome: String =
+ System.getProperty("scala.home")
+
+ val cmdName: String = {
+ val isWin = System.getProperty("os.name") startsWith "Windows"
+ if (isWin) "scala.bat" else "scala"
+ }
+
+}
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Arrows.scala b/src/scalap/scala/tools/scalap/scalax/rules/Arrows.scala
new file mode 100644
index 0000000000..2bc2cf5380
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/Arrows.scala
@@ -0,0 +1,35 @@
+package scala.tools.scalap.scalax.rules
+
+trait Arrows extends UnitFunctors {
+ type Arr[-A, +B] <: Arrow[A, B]
+ type M[+B] = Arr[Nothing, B]
+
+ def arrow[A, B](f : A => B) : Arr[A, B]
+ def diag[A] = arrow[A, (A, A)] { a => (a, a) }
+
+ override def unit[B](b : => B) : M[B] = arrow { any : Any => b }
+
+ trait Arrow[-A, +B] extends Functor[B] { this : Arr[A, B] =>
+
+ def map[C](f : B => C) = comp(arrow(f))
+ def comp[C](bc : => Arr[B, C]) : Arr[A, C]
+ def fst[C] : Arr[(A, C), (B, C)]
+ }
+}
+
+trait ApplicativeArrows extends Arrows {
+ type Arr[-A, +B] <: ApplicativeArrow[A, B]
+
+ def app[A, B] : Arr[(Arr[A, B], A), B]
+
+ trait ApplicativeArrow[-A, +B] extends Arrow[A, B] { self : Arr[A, B] =>
+ def flatMap[SubA <: A, C](f : B => Arr[SubA, C]) : Arr[SubA, C] =
+ diag[SubA].comp(map(f).fst[SubA]).comp(app[SubA, C])
+ }
+}
+
+trait ArrowMonads extends ApplicativeArrows with Monads {
+ type Arr[-A, +B] <: ApplicativeArrow[A, B] with Monad[B]
+
+ override def unit[A](a : => A) : M[A] = arrow[Unit, A](Unit => a)
+}
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Functors.scala b/src/scalap/scala/tools/scalap/scalax/rules/Functors.scala
new file mode 100644
index 0000000000..b9de5c71da
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/Functors.scala
@@ -0,0 +1,79 @@
+// -----------------------------------------------------------------------------
+//
+// Scalax - The Scala Community Library
+// Copyright (c) 2005-8 The Scalax Project. All rights reserved.
+//
+// The primary distribution site is http://scalax.scalaforge.org/
+//
+// This software is released under the terms of the Revised BSD License.
+// There is NO WARRANTY. See the file LICENSE for the full text.
+//
+// -----------------------------------------------------------------------------
+
+package scala.tools.scalap.scalax.rules
+
+trait Functor[+A] {
+ type M[+A] <: Functor[A]
+ def map[B](f : A => B) : M[B]
+}
+
+trait Filter[+A] {
+ type M[+A] <: Filter[A]
+ def filter(f : A => Boolean) : M[A]
+}
+
+trait Plus[+A] {
+ type M[+A] <: Plus[A]
+ def plus[B >: A](other : => M[B]) : M[B]
+}
+
+trait OrElse[+A] {
+ type M[+A] <: OrElse[A]
+ def orElse[B >: A](other : => M[B]) : M[B]
+}
+
+trait Units {
+ type M[+A]
+ def unit : M[Unit]
+ def unit[A](a : => A) : M[A]
+}
+
+trait Zero {
+ type M[+A]
+ def zero : M[Nothing]
+}
+
+trait Functors {
+ type M[+A] <: Functor[A]
+
+ trait Functor[+A] extends rules.Functor[A] { this : M[A] =>
+ type M[+A] = Functors.this.M[A]
+ }
+
+ trait ZeroFunctor extends Functor[Nothing] { this : M[Nothing] =>
+ override def map[B](f : Nothing => B) : M[B] = this
+ def filter(f : Nothing => Boolean) : M[Nothing] = this
+ def plus[B](other : => M[B]) : M[B] = other
+ def orElse[B](other : => M[B]) : M[B] = other
+ }
+}
+
+/** One of the 'unit' definitions must be overriden 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 }
+}
+
+
+trait Monoidals extends UnitFunctors {
+ type M[+A] <: Monoidal[A]
+
+ 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 */
+ 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/Input.scala b/src/scalap/scala/tools/scalap/scalax/rules/Input.scala
new file mode 100644
index 0000000000..af4ac39464
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/Input.scala
@@ -0,0 +1,66 @@
+// -----------------------------------------------------------------------------
+//
+// Scalax - The Scala Community Library
+// Copyright (c) 2005-8 The Scalax Project. All rights reserved.
+//
+// The primary distribution site is http://scalax.scalaforge.org/
+//
+// This software is released under the terms of the Revised BSD License.
+// There is NO WARRANTY. See the file LICENSE for the full text.
+//
+// -----------------------------------------------------------------------------
+
+package scala.tools.scalap.scalax.rules
+
+trait Input[+A] extends Iterable[A] {
+
+ def next : Result[Input[A], A, Nothing]
+ def index : Int
+
+ def elements = new Iterator[A] {
+ private var input : Input[A] = Input.this
+ private var result = input.next
+
+ def hasNext = result != Failure
+ def next = {
+ val Success(input, value) = result
+ this.input = input
+ this.result = input.next
+ value
+ }
+ }
+}
+
+
+class ArrayInput[A](val array : Array[A], val index : Int) extends Input[A] {
+ def this(array : Array[A]) = this(array, 0)
+
+ lazy val next : Result[ArrayInput[A], A, Nothing] = if (index >= array.length) Failure
+ else Success(new ArrayInput[A](array, index + 1), array(index))
+
+ override lazy val toString = elements.mkString("\"", "", "\"")
+}
+
+
+class IterableInput[A](iterator : Iterator[A], val index : Int) extends Input[A] {
+ def this(iterable : Iterable[A]) = this(iterable.elements, 0)
+
+ lazy val next : Result[IterableInput[A], A, Nothing] = if (!iterator.hasNext) Failure
+ else Success(new IterableInput(iterator, index + 1), iterator.next)
+
+ override lazy val toString = elements.mkString("\"", "", "\"")
+}
+
+
+/** View one type of input as another based on a transformation rule */
+class View[A, B](
+ transform : Input[A] => Result[Input[A], B, Nothing],
+ val input : Input[A],
+ val index : Int)
+ extends Input[B] {
+
+ def next : Result[Input[B], B, Nothing] = transform(input) match {
+ case Success(context, b) => Success(new View(transform, context, index + 1), b)
+ case _ => Failure
+ }
+}
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Memoisable.scala b/src/scalap/scala/tools/scalap/scalax/rules/Memoisable.scala
new file mode 100644
index 0000000000..0bcae2bded
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/Memoisable.scala
@@ -0,0 +1,59 @@
+// -----------------------------------------------------------------------------
+//
+// Scalax - The Scala Community Library
+// Copyright (c) 2005-8 The Scalax Project. All rights reserved.
+//
+// The primary distribution site is http://scalax.scalaforge.org/
+//
+// This software is released under the terms of the Revised BSD License.
+// There is NO WARRANTY. See the file LICENSE for the full text.
+//
+// -----------------------------------------------------------------------------
+
+package scala.tools.scalap.scalax.rules
+
+import scala.collection.mutable.HashMap
+
+trait MemoisableRules extends Rules {
+ def memo[In <: Memoisable, Out, A, X](key : AnyRef)(toRule : => In => Result[Out, A, X]) = {
+ lazy val rule = toRule
+ from[In] { in => in.memo(key, rule(in)) }
+ }
+
+ override def ruleWithName[In, Out, A, X](name : String, f : In => rules.Result[Out, A, X]) = super.ruleWithName(name, (in : In) => in match {
+ case s : Memoisable => s.memo(name, f(in))
+ case _ => f(in)
+ })
+}
+
+trait Memoisable {
+ def memo[A](key : AnyRef, a : => A) : A
+}
+
+
+object DefaultMemoisable {
+ var debug = false
+}
+
+trait DefaultMemoisable extends Memoisable {
+ protected val map = new HashMap[AnyRef, Any]
+
+ def memo[A](key : AnyRef, a : => A) = {
+ map.getOrElseUpdate(key, compute(key, a)).asInstanceOf[A]
+ }
+
+ protected def compute[A](key : AnyRef, a : => A) = a match {
+ case success : Success[_, _] => onSuccess(key, success); success
+ case other =>
+ if(DefaultMemoisable.debug) println(key + " -> " + other)
+ other
+ }
+
+ protected def onSuccess[S, T](key : AnyRef, result : Success[S, T]) {
+ val Success(out, t) = result
+ if(DefaultMemoisable.debug) println(key + " -> " + t + " (" + out + ")")
+ }
+}
+
+
+
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Monad.scala b/src/scalap/scala/tools/scalap/scalax/rules/Monad.scala
new file mode 100644
index 0000000000..1b03b5d3fa
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/Monad.scala
@@ -0,0 +1,44 @@
+// -----------------------------------------------------------------------------
+//
+// Scalax - The Scala Community Library
+// Copyright (c) 2005-8 The Scalax Project. All rights reserved.
+//
+// The primary distribution site is http://scalax.scalaforge.org/
+//
+// This software is released under the terms of the Revised BSD License.
+// There is NO WARRANTY. See the file LICENSE for the full text.
+//
+// -----------------------------------------------------------------------------
+
+package scala.tools.scalap.scalax.rules
+
+trait Monad[+A] extends Functor[A] {
+ type M[+A] <: Monad[A]
+ def flatMap[B](f : A => M[B]) : M[B]
+}
+
+trait Monads extends UnitFunctors {
+ type M[+A] <: Monad[A]
+
+ trait Monad[+A] extends Functor[A] with rules.Monad[A] { this : M[A] =>
+ def map[B](f : A => B) = flatMap { a => unit(f(a)) }
+ }
+
+ trait ZeroMonad extends Monad[Nothing] with ZeroFunctor { this : M[Nothing] =>
+ def flatMap[B](f : Nothing => M[B]) : M[B] = this
+ }
+}
+
+
+trait StateReader extends Monads {
+ type S
+
+ def get : M[S]
+ def read[A](f : S => A) : M[A]
+ def set(s : => S) : M[S]
+ def update(f : S => S) : M[S]
+}
+
+
+
+
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Result.scala b/src/scalap/scala/tools/scalap/scalax/rules/Result.scala
new file mode 100644
index 0000000000..cb8ec4b290
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/Result.scala
@@ -0,0 +1,70 @@
+// -----------------------------------------------------------------------------
+//
+// Scalax - The Scala Community Library
+// Copyright (c) 2005-8 The Scalax Project. All rights reserved.
+//
+// The primary distribution site is http://scalax.scalaforge.org/
+//
+// This software is released under the terms of the Revised BSD License.
+// There is NO WARRANTY. See the file LICENSE for the full text.
+//
+// -----------------------------------------------------------------------------
+
+package scala.tools.scalap.scalax.rules;
+
+/** Represents the combined value of two rules applied in sequence.
+ *
+ * @see the Scala parser combinator
+ */
+case class ~[+A, +B](_1 : A, _2 : B) {
+ override def toString = "(" + _1 + " ~ " + _2 + ")"
+}
+
+
+sealed abstract class Result[+Out, +A, +X] {
+ def out : Out
+ def value : A
+ def error : X
+
+ implicit def toOption : Option[A]
+
+ def map[B](f : A => B) : Result[Out, B, X]
+ def mapOut[Out2](f : Out => Out2) : Result[Out2, A, X]
+ def map[Out2, B](f : (Out, A) => (Out2, B)) : Result[Out2, B, X]
+ def flatMap[Out2, B](f : (Out, A) => Result[Out2, B, Nothing]) : Result[Out2, B, X]
+ def orElse[Out2 >: Out, B >: A](other : => Result[Out2, B, Nothing]) : Result[Out2, B, X]
+}
+
+case class Success[+Out, +A](out : Out, value : A) extends Result[Out, A, Nothing] {
+ def error = throw new ScalaSigParserError("No error")
+
+ 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
+}
+
+sealed abstract class NoSuccess[+X] extends Result[Nothing, Nothing, X] {
+ def out = throw new ScalaSigParserError("No output")
+ def value = throw new ScalaSigParserError("No value")
+
+ def toOption = None
+
+ def map[B](f : Nothing => B) = this
+ def mapOut[Out2](f : Nothing => Out2) = this
+ def map[Out2, B](f : (Nothing, Nothing) => (Out2, B)) = this
+ def flatMap[Out2, B](f : (Nothing, Nothing) => Result[Out2, B, Nothing]) = this
+ def orElse[Out2, B](other : => Result[Out2, B, Nothing]) = other
+}
+
+case object Failure extends NoSuccess[Nothing] {
+ def error = throw new ScalaSigParserError("No error")
+}
+
+case class ScalaSigParserError(msg: String) extends RuntimeException(msg)
+
+case class Error[+X](error : X) extends NoSuccess[X] {
+}
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Rule.scala b/src/scalap/scala/tools/scalap/scalax/rules/Rule.scala
new file mode 100644
index 0000000000..f540d9ad8d
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/Rule.scala
@@ -0,0 +1,175 @@
+// -----------------------------------------------------------------------------
+//
+// Scalax - The Scala Community Library
+// Copyright (c) 2005-8 The Scalax Project. All rights reserved.
+//
+// The primary distribution site is http://scalax.scalaforge.org/
+//
+// This software is released under the terms of the Revised BSD License.
+// There is NO WARRANTY. See the file LICENSE for the full text.
+//
+// -----------------------------------------------------------------------------
+
+package scala.tools.scalap.scalax.rules
+
+/** A Rule is a function from some input to a Result. The result may be:
+ * <ul>
+ * <li>Success, with a value of some type and an output that may serve as the input to subsequent rules.</li>
+ * <li>Failure. A failure may result in some alternative rule being applied.</li>
+ * <li>Error. No further rules should be attempted.</li>
+ * </ul>
+ *
+ * @author Andrew Foggin
+ *
+ * Inspired by the Scala parser combinator.
+ */
+trait Rule[-In, +Out, +A, +X] extends (In => Result[Out, A, X]) {
+ val factory : Rules
+ import factory._
+
+ def as(name : String) = ruleWithName(name, this)
+
+ def flatMap[Out2, B, X2 >: X](fa2ruleb : A => Out => Result[Out2, B, X2]) = mapResult {
+ case Success(out, a) => fa2ruleb(a)(out)
+ case Failure => Failure
+ case err @ Error(_) => err
+ }
+
+ def map[B](fa2b : A => B) = flatMap { a => out => Success(out, fa2b(a)) }
+
+ def filter(f : A => Boolean) = flatMap { a => out => if(f(a)) Success(out, a) else Failure }
+
+ def mapResult[Out2, B, Y](f : Result[Out, A, X] => Result[Out2, B, Y]) = rule {
+ in : In => f(apply(in))
+ }
+
+ def orElse[In2 <: In, Out2 >: Out, A2 >: A, X2 >: X](other : => Rule[In2, Out2, A2, X2]) : Rule[In2, Out2, A2, X2] = new Choice[In2, Out2, A2, X2] {
+ val factory = Rule.this.factory
+ lazy val choices = Rule.this :: other :: Nil
+ }
+
+ def orError[In2 <: In] = this orElse(error[In2])
+
+ def |[In2 <: In, Out2 >: Out, A2 >: A, X2 >: X](other : => Rule[In2, Out2, A2, X2]) = orElse(other)
+
+ def ^^[B](fa2b : A => B) = map(fa2b)
+
+ def ^^?[B](pf : PartialFunction[A, B]) = filter (pf.isDefinedAt(_)) ^^ pf
+
+ def ??(pf : PartialFunction[A, Any]) = filter (pf.isDefinedAt(_))
+
+ def -^[B](b : B) = map { any => b }
+
+ /** Maps an Error */
+ def !^[Y](fx2y : X => Y) = mapResult {
+ case s @ Success(_, _) => s
+ case Failure => Failure
+ case Error(x) => Error(fx2y(x))
+ }
+
+ def >>[Out2, B, X2 >: X](fa2ruleb : A => Out => Result[Out2, B, X2]) = flatMap(fa2ruleb)
+
+ def >->[Out2, B, X2 >: X](fa2resultb : A => Result[Out2, B, X2]) = flatMap { a => any => fa2resultb(a) }
+
+ def >>?[Out2, B, X2 >: X](pf : PartialFunction[A, Rule[Out, Out2, B, X2]]) = filter(pf isDefinedAt _) flatMap pf
+
+ def >>&[B, X2 >: X](fa2ruleb : A => Out => Result[Any, B, X2]) = flatMap { a => out => fa2ruleb(a)(out) mapOut { any => out } }
+
+ def ~[Out2, B, X2 >: X](next : => Rule[Out, Out2, B, X2]) = for (a <- this; b <- next) yield new ~(a, b)
+
+ def ~-[Out2, B, X2 >: X](next : => Rule[Out, Out2, B, X2]) = for (a <- this; b <- next) yield a
+
+ def -~[Out2, B, X2 >: X](next : => Rule[Out, Out2, B, X2]) = for (a <- this; b <- next) yield b
+
+ def ~++[Out2, B >: A, X2 >: X](next : => Rule[Out, Out2, Seq[B], X2]) = for (a <- this; b <- next) yield a :: b.toList
+
+ /** Apply the result of this rule to the function returned by the next rule */
+ def ~>[Out2, B, X2 >: X](next : => Rule[Out, Out2, A => B, X2]) = for (a <- this; fa2b <- next) yield fa2b(a)
+
+ /** Apply the result of this rule to the function returned by the previous rule */
+ def <~:[InPrev, B, X2 >: X](prev : => Rule[InPrev, In, A => B, X2]) = for (fa2b <- prev; a <- this) yield fa2b(a)
+
+ def ~![Out2, B, X2 >: X](next : => Rule[Out, Out2, B, X2]) = for (a <- this; b <- next orError) yield new ~(a, b)
+
+ def ~-![Out2, B, X2 >: X](next : => Rule[Out, Out2, B, X2]) = for (a <- this; b <- next orError) yield a
+
+ def -~![Out2, B, X2 >: X](next : => Rule[Out, Out2, B, X2]) = for (a <- this; b <- next orError) yield b
+
+ def -[In2 <: In](exclude : => Rule[In2, Any, Any, Any]) = !exclude -~ this
+
+ /** ^~^(f) is equivalent to ^^ { case b1 ~ b2 => f(b1, b2) }
+ */
+ def ^~^[B1, B2, B >: A <% B1 ~ B2, C](f : (B1, B2) => C) = map { a =>
+ (a : B1 ~ B2) match { case b1 ~ b2 => f(b1, b2) }
+ }
+
+ /** ^~~^(f) is equivalent to ^^ { case b1 ~ b2 ~ b3 => f(b1, b2, b3) }
+ */
+ def ^~~^[B1, B2, B3, B >: A <% B1 ~ B2 ~ B3, C](f : (B1, B2, B3) => C) = map { a =>
+ (a : B1 ~ B2 ~ B3) match { case b1 ~ b2 ~ b3 => f(b1, b2, b3) }
+ }
+
+ /** ^~~~^(f) is equivalent to ^^ { case b1 ~ b2 ~ b3 ~ b4 => f(b1, b2, b3, b4) }
+ */
+ def ^~~~^[B1, B2, B3, B4, B >: A <% B1 ~ B2 ~ B3 ~ B4, C](f : (B1, B2, B3, B4) => C) = map { a =>
+ (a : B1 ~ B2 ~ B3 ~ B4) match { case b1 ~ b2 ~ b3 ~ b4 => f(b1, b2, b3, b4) }
+ }
+
+ /** ^~~~~^(f) is equivalent to ^^ { case b1 ~ b2 ~ b3 ~ b4 ~ b5 => f(b1, b2, b3, b4, b5) }
+ */
+ def ^~~~~^[B1, B2, B3, B4, B5, B >: A <% B1 ~ B2 ~ B3 ~ B4 ~ B5, C](f : (B1, B2, B3, B4, B5) => C) = map { a =>
+ (a : B1 ~ B2 ~ B3 ~ B4 ~ B5) match { case b1 ~ b2 ~ b3 ~ b4 ~ b5 => f(b1, b2, b3, b4, b5) }
+ }
+
+ /** ^~~~~~^(f) is equivalent to ^^ { case b1 ~ b2 ~ b3 ~ b4 ~ b5 ~ b6 => f(b1, b2, b3, b4, b5, b6) }
+ */
+ def ^~~~~~^[B1, B2, B3, B4, B5, B6, B >: A <% B1 ~ B2 ~ B3 ~ B4 ~ B5 ~ B6, C](f : (B1, B2, B3, B4, B5, B6) => C) = map { a =>
+ (a : B1 ~ B2 ~ B3 ~ B4 ~ B5 ~ B6) match { case b1 ~ b2 ~ b3 ~ b4 ~ b5 ~ b6 => f(b1, b2, b3, b4, b5, b6) }
+ }
+
+ /** ^~~~~~~^(f) is equivalent to ^^ { case b1 ~ b2 ~ b3 ~ b4 ~ b5 ~ b6 => f(b1, b2, b3, b4, b5, b6) }
+ */
+ def ^~~~~~~^[B1, B2, B3, B4, B5, B6, B7, B >: A <% B1 ~ B2 ~ B3 ~ B4 ~ B5 ~ B6 ~ B7, C](f : (B1, B2, B3, B4, B5, B6, B7) => C) = map { a =>
+ (a : B1 ~ B2 ~ B3 ~ B4 ~ B5 ~ B6 ~ B7) match { case b1 ~ b2 ~ b3 ~ b4 ~ b5 ~ b6 ~b7 => f(b1, b2, b3, b4, b5, b6, b7) }
+ }
+
+ /** >~>(f) is equivalent to >> { case b1 ~ b2 => f(b1, b2) }
+ */
+ def >~>[Out2, B1, B2, B >: A <% B1 ~ B2, C, X2 >: X](f : (B1, B2) => Out => Result[Out2, C, X2]) = flatMap { a =>
+ (a : B1 ~ B2) match { case b1 ~ b2 => f(b1, b2) }
+ }
+
+ /** ^-^(f) is equivalent to ^^ { b2 => b1 => f(b1, b2) }
+ */
+ def ^-^ [B1, B2 >: A, C](f : (B1, B2) => C) = map { b2 : B2 => b1 : B1 => f(b1, b2) }
+
+ /** ^~>~^(f) is equivalent to ^^ { case b2 ~ b3 => b1 => f(b1, b2, b3) }
+ */
+ def ^~>~^ [B1, B2, B3, B >: A <% B2 ~ B3, C](f : (B1, B2, B3) => C) = map { a =>
+ (a : B2 ~ B3) match { case b2 ~ b3 => b1 : B1 => f(b1, b2, b3) }
+ }
+}
+
+
+trait Choice[-In, +Out, +A, +X] extends Rule[In, Out, A, X] {
+ def choices : List[Rule[In, Out, A, X]]
+
+ def apply(in : In) = {
+ def oneOf(list : List[Rule[In, Out, A, X]]) : Result[Out, A, X] = list match {
+ case Nil => Failure
+ case first :: rest => first(in) match {
+ case Failure => oneOf(rest)
+ case result => result
+ }
+ }
+ oneOf(choices)
+ }
+
+ override def orElse[In2 <: In, Out2 >: Out, A2 >: A, X2 >: X](other : => Rule[In2, Out2, A2, X2]) : Rule[In2, Out2, A2, X2] = new Choice[In2, Out2, A2, X2] {
+ val factory = Choice.this.factory
+ lazy val choices = Choice.this.choices ::: other :: Nil
+ }
+}
+
+
+
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala b/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala
new file mode 100644
index 0000000000..fa6f959384
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/Rules.scala
@@ -0,0 +1,144 @@
+// -----------------------------------------------------------------------------
+//
+// Scalax - The Scala Community Library
+// Copyright (c) 2005-8 The Scalax Project. All rights reserved.
+//
+// The primary distribution site is http://scalax.scalaforge.org/
+//
+// This software is released under the terms of the Revised BSD License.
+// There is NO WARRANTY. See the file LICENSE for the full text.
+//
+// -----------------------------------------------------------------------------
+
+package scala.tools.scalap.scalax.rules
+
+trait Name {
+ def name : String
+ override def toString = name
+}
+
+/** A factory for rules.
+ *
+ * @author Andrew Foggin
+ *
+ * Inspired by the Scala parser combinator.
+ */
+trait Rules {
+ implicit def rule[In, Out, A, X](f : In => Result[Out, A, X]) : Rule[In, Out, A, X] = new DefaultRule(f)
+
+ implicit def inRule[In, Out, A, X](rule : Rule[In, Out, A, X]) : InRule[In, Out, A, X] = new InRule(rule)
+ implicit def seqRule[In, A, X](rule : Rule[In, In, A, X]) : SeqRule[In, A, X] = new SeqRule(rule)
+
+ def from[In] = new {
+ def apply[Out, A, X](f : In => Result[Out, A, X]) = rule(f)
+ }
+
+ def state[s] = new StateRules {
+ type S = s
+ val factory = Rules.this
+ }
+
+ def success[Out, A](out : Out, a : A) = rule { in : Any => Success(out, a) }
+
+ def failure = rule { in : Any => Failure }
+
+ def error[In] = rule { in : In => Error(in) }
+ def error[X](err : X) = rule { in : Any => Error(err) }
+
+ def oneOf[In, Out, A, X](rules : Rule[In, Out, A, X] *) : Rule[In, Out, A, X] = new Choice[In, Out, A, X] {
+ val factory = Rules.this
+ val choices = rules.toList
+ }
+
+ def ruleWithName[In, Out, A, X](_name : String, f : In => Result[Out, A, X]) : Rule[In, Out, A, X] with Name =
+ new DefaultRule(f) with Name {
+ val name = _name
+ }
+
+ class DefaultRule[In, Out, A, X](f : In => Result[Out, A, X]) extends Rule[In, Out, A, X] {
+ val factory = Rules.this
+ def apply(in : In) = f(in)
+ }
+
+ /** Converts a rule into a function that throws an Exception on failure. */
+ def expect[In, Out, A, Any](rule : Rule[In, Out, A, Any]) : In => A = (in) => rule(in) match {
+ case Success(_, a) => a
+ case Failure => throw new ScalaSigParserError("Unexpected failure")
+ case Error(x) => throw new ScalaSigParserError("Unexpected error: " + x)
+ }
+}
+
+/** A factory for rules that apply to a particular context.
+ *
+ * @requires S the context to which rules apply.
+ *
+ * @author Andrew Foggin
+ *
+ * Inspired by the Scala parser combinator.
+ */
+trait StateRules {
+ type S
+ type Rule[+A, +X] = rules.Rule[S, S, A, X]
+
+ val factory : Rules
+ import factory._
+
+ def apply[A, X](f : S => Result[S, A, X]) = rule(f)
+
+ def unit[A](a : => A) = apply { s => Success(s, a) }
+ def read[A](f : S => A) = apply { s => Success(s, f(s)) }
+
+ def get = apply { s => Success(s, s) }
+ def set(s : => S) = apply { oldS => Success(s, oldS) }
+
+ def update(f : S => S) = apply { s => Success(s, f(s)) }
+
+ def nil = unit(Nil)
+ def none = unit(None)
+
+ /** Create a rule that suceeds 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.
+ @param rules the rules to apply in sequence.
+ */
+ def allOf[A, X](rules : Seq[Rule[A, X]]) = {
+ def rep(in : S, rules : List[Rule[A, X]], results : List[A]) : Result[S, List[A], X] = {
+ rules match {
+ case Nil => Success(in, results.reverse)
+ case rule::tl => rule(in) match {
+ case Failure => Failure
+ case Error(x) => Error(x)
+ case Success(out, v) => rep(out, tl, v::results)
+ }
+ }
+ }
+ in : S => rep(in, rules.toList, Nil)
+ }
+
+
+ /** Create a rule that succeeds with a list of all the provided rules that succeed.
+ @param rules the rules to apply in sequence.
+ */
+ def anyOf[A, X](rules : Seq[Rule[A, X]]) = allOf(rules.map(_ ?)) ^^ { opts => opts.flatMap(x => x) }
+
+ /** Repeatedly apply a rule from initial value until finished condition is met. */
+ def repeatUntil[T, X](rule : Rule[T => T, X])(finished : T => Boolean)(initial : T) = apply {
+ // more compact using HoF but written this way so it's tail-recursive
+ def rep(in : S, t : T) : Result[S, T, X] = {
+ if (finished(t)) Success(in, t)
+ else rule(in) match {
+ case Success(out, f) => rep(out, f(t))
+ case Failure => Failure
+ case Error(x) => Error(x)
+ }
+ }
+ in => rep(in, initial)
+ }
+
+
+}
+
+trait RulesWithState extends Rules with StateRules {
+ val factory = this
+}
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/SeqRule.scala b/src/scalap/scala/tools/scalap/scalax/rules/SeqRule.scala
new file mode 100644
index 0000000000..d32300f832
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/SeqRule.scala
@@ -0,0 +1,99 @@
+// -----------------------------------------------------------------------------
+//
+// Scalax - The Scala Community Library
+// Copyright (c) 2005-8 The Scalax Project. All rights reserved.
+//
+// The primary distribution site is http://scalax.scalaforge.org/
+//
+// This software is released under the terms of the Revised BSD License.
+// There is NO WARRANTY. See the file LICENSE for the full text.
+//
+// -----------------------------------------------------------------------------
+
+package scala.tools.scalap.scalax.rules
+
+/**
+ * A workaround for the difficulties of dealing with
+ * a contravariant 'In' parameter type...
+ */
+class InRule[In, +Out, +A, +X](rule : Rule[In, Out, A, X]) {
+
+ def mapRule[Out2, B, Y](f : Result[Out, A, X] => In => Result[Out2, B, Y]) : Rule[In, Out2, B, Y] = rule.factory.rule {
+ in : In => f(rule(in))(in)
+ }
+
+ /** Creates a rule that suceeds 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, ())
+ }
+
+ /** Creates a rule that succeeds if the original rule succeeds, but returns the original input. */
+ def & : Rule[In, In, A, X] = mapRule {
+ case Success(_, a) => in : In => Success(in, a)
+ case Failure => in : In => Failure
+ case Error(x) => in : In => Error(x)
+ }
+}
+
+class SeqRule[S, +A, +X](rule : Rule[S, S, A, X]) {
+ import rule.factory._
+
+ def ? = rule mapRule {
+ case Success(out, a) => in : S => Success(out, Some(a))
+ case Failure => in : S => Success(in, None)
+ case Error(x) => in : S => Error(x)
+ }
+
+ /** Creates a rule that always succeeds with a Boolean value.
+ * Value is 'true' if this rule succeeds, 'false' otherwise */
+ def -? = ? map { _ isDefined }
+
+ def * = from[S] {
+ // tail-recursive function with reverse list accumulator
+ def rep(in : S, acc : List[A]) : Result[S, List[A], X] = rule(in) match {
+ case Success(out, a) => rep(out, a :: acc)
+ case Failure => Success(in, acc.reverse)
+ case err : Error[_] => err
+ }
+ in => rep(in, Nil)
+ }
+
+ def + = rule ~++ *
+
+ def ~>?[B >: A, X2 >: X](f : => Rule[S, S, B => B, X2]) = for (a <- rule; fs <- f?) yield fs.foldLeft[B](a) { (b, f) => f(b) }
+
+ def ~>*[B >: A, X2 >: X](f : => Rule[S, S, B => B, X2]) = for (a <- rule; fs <- f*) yield fs.foldLeft[B](a) { (b, f) => f(b) }
+
+ def ~*~[B >: A, X2 >: X](join : => Rule[S, S, (B, B) => B, X2]) = {
+ this ~>* (for (f <- join; a <- rule) yield f(_ : B, a))
+ }
+
+ /** Repeats this rule one or more times with a separator (which is discarded) */
+ def +/[X2 >: X](sep : => Rule[S, S, Any, X2]) = rule ~++ (sep -~ rule *)
+
+ /** Repeats this rule zero or more times with a separator (which is discarded) */
+ def */[X2 >: X](sep : => Rule[S, S, Any, X2]) = +/(sep) | state[S].nil
+
+ def *~-[Out, X2 >: X](end : => Rule[S, Out, Any, X2]) = (rule - end *) ~- end
+ def +~-[Out, X2 >: X](end : => Rule[S, Out, Any, X2]) = (rule - end +) ~- end
+
+ /** Repeats this rule num times */
+ def times(num : Int) : Rule[S, S, Seq[A], X] = from[S] {
+ val result = new Array[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)
+ else rule(in) match {
+ case Success(out, a) => {
+ result(i) = a
+ rep(i + 1, out)
+ }
+ case Failure => Failure
+ case err : Error[_] => err
+ }
+ }
+ in => rep(0, in)
+ }
+}
+
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala
new file mode 100644
index 0000000000..525217ed83
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala
@@ -0,0 +1,221 @@
+package scala.tools.scalap.scalax.rules.scalasig
+
+
+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)
+
+ def forClass(clazz : Class[_]) = {
+ val name = clazz.getName
+ val subPath = name.substring(name.lastIndexOf('.') + 1) + ".class"
+ val in = clazz.getResourceAsStream(subPath)
+
+ try {
+ var rest = in.available()
+ val bytes = new Array[Byte](rest)
+ while (rest > 0) {
+ val res = in.read(bytes, bytes.length - rest, rest)
+ if (res == -1) throw new IOException("read error")
+ rest -= res
+ }
+ ByteCode(bytes)
+
+ } finally {
+ in.close()
+ }
+ }
+}
+
+/** Represents a chunk of raw bytecode. Used as input for the parsers
+ */
+class ByteCode(val bytes : Array[Byte], val pos : Int, val length : Int) {
+
+ assert(pos >= 0 && length >= 0 && pos + length <= bytes.length)
+
+ def nextByte = if (length == 0) Failure else Success(drop(1), bytes(pos))
+ def next(n : Int) = if (length >= n) Success(drop(n), take(n)) else Failure
+
+ def take(n : Int) = new ByteCode(bytes, pos, n)
+ def drop(n : Int) = new ByteCode(bytes, pos + n, length - n)
+
+ def fold[X](x : X)(f : (X, Byte) => X) : X = {
+ var result = x
+ var i = pos
+ while (i < pos + length) {
+ result = f(result, bytes(i))
+ i += 1
+ }
+ result
+ }
+
+ override def toString = length + " bytes"
+
+ def toInt = fold(0) { (x, b) => (x << 8) + (b & 0xFF)}
+ def toLong = fold(0L) { (x, b) => (x << 8) + (b & 0xFF)}
+
+ // NOTE the UTF8 decoder in the Scala compiler is broken for pos > 0
+ // TODO figure out patch and submit
+ def toUTF8String = {
+ val sb = new StringBuilder(length)
+ var i = pos
+ val end = pos + length
+ while (i < end) {
+ var b = bytes(i) & 0xFF
+ i += 1
+ if (b >= 0xE0) {
+ b = ((b & 0x0F) << 12) | (bytes(i) & 0x3F) << 6
+ b = b | (bytes(i+1) & 0x3F)
+ i += 2
+ } else if (b >= 0xC0) {
+ b = ((b & 0x1F) << 6) | (bytes(i) & 0x3F)
+ i += 1
+ }
+ sb + b.toChar
+ }
+ sb.toString
+ }
+
+ def byte(i : Int) = bytes(pos) & 0xFF
+}
+
+/** Provides rules for parsing byte-code.
+*/
+trait ByteCodeReader extends RulesWithState {
+ type S = ByteCode
+ type Parser[A] = Rule[A, String]
+
+ val byte = apply(_ nextByte)
+
+ val u1 = byte ^^ (_ & 0xFF)
+ val u2 = bytes(2) ^^ (_ toInt)
+ val u4 = bytes(4) ^^ (_ toInt) // should map to Long??
+
+ def bytes(n : Int) = apply(_ next n)
+
+
+
+}
+
+object ClassFileParser extends ByteCodeReader {
+ def parse(byteCode : ByteCode) = expect(classFile)(byteCode)
+
+ val magicNumber = (u4 filter (_ == 0xCAFEBABE)) | error("Not a valid class file")
+ val version = u2 ~ u2 ^^ { case minor ~ major => (major, minor) }
+ val constantPool = (u2 ^^ ConstantPool) >> repeatUntil(constantPoolEntry)(_ isFull)
+
+ // 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 intConstant = u4 ^^ add1 { x => pool => x }
+ val floatConstant = bytes(4) ^^ add1 { raw => pool => "Float: TODO" }
+ val longConstant = bytes(8) ^^ add2 { raw => pool => raw.toLong }
+ val doubleConstant = bytes(8) ^^ add2 { raw => pool => "Double: TODO" }
+ val classRef = u2 ^^ add1 { x => pool => "Class: " + pool(x) }
+ val stringRef = u2 ^^ add1 { x => pool => "String: " + pool(x) }
+ val fieldRef = memberRef("Field")
+ val methodRef = memberRef("Method")
+ val interfaceMethodRef = memberRef("InterfaceMethod")
+ val nameAndType = u2 ~ u2 ^^ add1 { case name ~ descriptor => pool => "NameAndType: " + pool(name) + ", " + pool(descriptor) }
+
+ val constantPoolEntry = u1 >> {
+ case 1 => utf8String
+ case 3 => intConstant
+ case 4 => floatConstant
+ case 5 => longConstant
+ case 6 => doubleConstant
+ case 7 => classRef
+ case 8 => stringRef
+ case 9 => fieldRef
+ case 10 => methodRef
+ case 11 => interfaceMethodRef
+ case 12 => nameAndType
+ }
+
+ val interfaces = u2 >> u2.times
+
+ val attribute = u2 ~ (u4 >> bytes) ^~^ Attribute
+ val attributes = u2 >> attribute.times
+
+ val field = u2 ~ u2 ~ u2 ~ attributes ^~~~^ Field
+ val fields = u2 >> field.times
+
+ val method = u2 ~ u2 ~ u2 ~ attributes ^~~~^ Method
+ val methods = u2 >> method.times
+
+ val header = magicNumber -~ u2 ~ u2 ~ constantPool ~ u2 ~ u2 ~ u2 ~ interfaces ^~~~~~~^ ClassFileHeader
+ val classFile = header ~ fields ~ methods ~ attributes ~- !u1 ^~~~^ ClassFile
+
+ // TODO create a useful object, not just a string
+ def memberRef(description : String) = u2 ~ u2 ^^ add1 {
+ case classRef ~ nameAndTypeRef => pool => description + ": " + pool(classRef) + ", " + pool(nameAndTypeRef)
+ }
+
+ def add1[T](f : T => ConstantPool => Any)(raw : T)(pool : ConstantPool) = pool add f(raw)
+ def add2[T](f : T => ConstantPool => Any)(raw : T)(pool : ConstantPool) = pool add f(raw) add { pool => "<empty>" }
+}
+
+case class ClassFile(
+ header : ClassFileHeader,
+ fields : Seq[Field],
+ methods : Seq[Method],
+ attributes : Seq[Attribute]) {
+
+ def majorVersion = header.major
+ def minorVersion = header.minor
+
+ def className = constant(header.classIndex)
+ def superClass = constant(header.superClassIndex)
+ def interfaces = header.interfaces.map(constant)
+
+ def constant(index : Int) = header.constants(index)
+
+ def attribute(name : String) = attributes.find { attrib => constant(attrib.nameIndex) == name }
+}
+
+case class Attribute(nameIndex : Int, byteCode : ByteCode)
+case class Field(flags : Int, nameIndex : Int, descriptorIndex : Int, attributes : Seq[Attribute])
+case class Method(flags : Int, nameIndex : Int, descriptorIndex : Int, attributes : Seq[Attribute])
+
+case class ClassFileHeader(
+ minor : Int,
+ major : Int,
+ constants : ConstantPool,
+ flags : Int,
+ classIndex : Int,
+ superClassIndex : Int,
+ interfaces : Seq[Int]) {
+
+ def constant(index : Int) = constants(index)
+}
+
+case class ConstantPool(len : Int) {
+ val size = len - 1
+
+ private val buffer = new scala.collection.mutable.ArrayBuffer[ConstantPool => Any]
+ private val values = Array.make[Option[Any]](size, None)
+
+ def isFull = buffer.length >= size
+
+ def apply(index : Int) = {
+ // Note constant pool indices are 1-based
+ val i = index - 1
+ values(i) getOrElse {
+ val value = buffer(i)(this)
+ buffer(i) = null
+ values(i) = Some(value)
+ value
+ }
+ }
+
+ def add(f : ConstantPool => Any) = {
+ buffer + f
+ this
+ }
+}
+
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Flags.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Flags.scala
new file mode 100644
index 0000000000..c567cdf715
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Flags.scala
@@ -0,0 +1,66 @@
+package scala.tools.scalap.scalax.rules.scalasig
+
+trait Flags {
+ def hasFlag(flag : Long) : Boolean
+
+ def isImplicit = hasFlag(0x00000001)
+ def isFinal = hasFlag(0x00000002)
+ def isPrivate = hasFlag(0x00000004)
+ def isProtected = hasFlag(0x00000008)
+
+ def isSealed = hasFlag(0x00000010)
+ def isOverride = hasFlag(0x00000020)
+ def isCase = hasFlag(0x00000040)
+ def isAbstract = hasFlag(0x00000080)
+
+ def isDeferred = hasFlag(0x00000100)
+ def isMethod = hasFlag(0x00000200)
+ def isModule = hasFlag(0x00000400)
+ def isInterface = hasFlag(0x00000800)
+
+ def isMutable = hasFlag(0x00001000)
+ def isParam = hasFlag(0x00002000)
+ def isPackage = hasFlag(0x00004000)
+ def isDeprecated = hasFlag(0x00008000)
+
+ def isCovariant = hasFlag(0x00010000)
+ def isCaptured = hasFlag(0x00010000)
+
+ def isByNameParam = hasFlag(0x00010000)
+ def isContravariant = hasFlag(0x00020000)
+ def isLabel = hasFlag(0x00020000) // method symbol is a label. Set by TailCall
+ def isInConstructor = hasFlag(0x00020000) // class symbol is defined in this/superclass constructor
+
+ def isAbstractOverride = hasFlag(0x00040000)
+ def isLocal = hasFlag(0x00080000)
+
+ def isJava = hasFlag(0x00100000)
+ def isSynthetic = hasFlag(0x00200000)
+ def isStable = hasFlag(0x00400000)
+ def isStatic = hasFlag(0x00800000)
+
+ def isCaseAccessor = hasFlag(0x01000000)
+ def isTrait = hasFlag(0x02000000)
+ def isBridge = hasFlag(0x04000000)
+ def isAccessor = hasFlag(0x08000000)
+
+ def isSuperAccessor = hasFlag(0x10000000)
+ def isParamAccessor = hasFlag(0x20000000)
+
+ def isModuleVar = hasFlag(0x40000000) // for variables: is the variable caching a module value
+ def isSyntheticMethod = hasFlag(0x40000000) // for methods: synthetic method, but without SYNTHETIC flag
+ def isMonomorphic = hasFlag(0x40000000) // for type symbols: does not have type parameters
+ def isLazy = hasFlag(0x80000000L) // symbol is a lazy val. can't have MUTABLE unless transformed by typer
+
+ def isError = hasFlag(0x100000000L)
+ def isOverloaded = hasFlag(0x200000000L)
+ def isLifted = hasFlag(0x400000000L)
+
+ def isMixedIn = hasFlag(0x800000000L)
+ def isExistential = hasFlag(0x800000000L)
+
+ def isExpandedName = hasFlag(0x1000000000L)
+ def isImplementationClass = hasFlag(0x2000000000L)
+ def isPreSuper = hasFlag(0x2000000000L)
+
+}
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala
new file mode 100644
index 0000000000..c660bdd7c3
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala
@@ -0,0 +1,269 @@
+package scala.tools.scalap.scalax.rules.scalasig
+
+object ScalaSigParser {
+
+ def getScalaSig(clazz : Class[_]) : Option[ByteCode] = {
+ val byteCode = ByteCode.forClass(clazz)
+ val classFile = ClassFileParser.parse(byteCode)
+
+ /*
+ println("ClassFile version: " + classFile.majorVersion + "." + classFile.minorVersion)
+ println("Class: " + classFile.className)
+ println("Superclass: " + classFile.superClass)
+ println("Interfaces: " + classFile.interfaces.mkString(", "))
+ println("Constant pool:")
+ val constantPool = classFile.header.constants
+ for (i <- 1 to constantPool.size) println(i + "\t" + constantPool(i))
+ */
+
+ classFile.attribute("ScalaSig").map(_.byteCode)
+ }
+
+ def parse(clazz : Class[_]) : Option[ScalaSig] = {
+ getScalaSig(clazz).map(ScalaSigAttributeParsers.parse)
+ }
+}
+
+object ScalaSigAttributeParsers extends ByteCodeReader {
+ def parse(byteCode : ByteCode) = expect(scalaSig)(byteCode)
+
+ val nat = apply {
+ def natN(in : ByteCode, x : Int) : Result[ByteCode, Int, Nothing] = in.nextByte match {
+ case Success(out, b) => {
+ val y = (x << 7) + (b & 0x7f)
+ if ((b & 0x80) == 0) Success(out, y) else natN(out, y)
+ }
+ case _ => Failure
+ }
+ in => natN(in, 0)
+ }
+
+ val rawBytes = nat >> bytes
+ val entry = nat ~ rawBytes
+ val symtab = nat >> entry.times
+ val scalaSig = nat ~ nat ~ symtab ^~~^ ScalaSig
+
+ val utf8 = read(_ toUTF8String)
+ val longValue = read(_ toLong)
+}
+
+case class ScalaSig(majorVersion : Int, minorVersion : Int, table : Seq[Int ~ ByteCode]) extends DefaultMemoisable {
+
+ case class Entry(index : Int, entryType : Int, byteCode : ByteCode) extends DefaultMemoisable {
+ def scalaSig = ScalaSig.this
+
+ def setByteCode(byteCode : ByteCode) = Entry(index, entryType, byteCode)
+ }
+
+ def hasEntry(index : Int) = table isDefinedAt index
+
+ def getEntry(index : Int) = {
+ val entryType ~ byteCode = table(index)
+ Entry(index, entryType, byteCode)
+ }
+
+ def parseEntry(index : Int) = applyRule(ScalaSigParsers.parseEntry(ScalaSigEntryParsers.entry)(index))
+
+ implicit def applyRule[A](parser : ScalaSigParsers.Parser[A]) = ScalaSigParsers.expect(parser)(this)
+
+ override def toString = "ScalaSig version " + majorVersion + "." + minorVersion + {
+ for (i <- 0 until table.size) yield i + ":\t" + parseEntry(i) // + "\n\t" + getEntry(i)
+ }.mkString("\n", "\n", "")
+
+ lazy val symbols : Seq[Symbol] = ScalaSigParsers.symbols
+
+ lazy val topLevelClasses : List[ClassSymbol] = ScalaSigParsers.topLevelClasses
+ lazy val topLevelObjects : List[ObjectSymbol] = ScalaSigParsers.topLevelObjects
+}
+
+object ScalaSigParsers extends RulesWithState with MemoisableRules {
+ type S = ScalaSig
+ type Parser[A] = Rule[A, String]
+
+ val symTab = read(_.table)
+ val size = symTab ^^ (_.size)
+
+ def entry(index : Int) = memo(("entry", index)) {
+ cond(_ hasEntry index) -~ read(_ getEntry index) >-> { entry => Success(entry, entry.entryType) }
+ }
+
+ def parseEntry[A](parser : ScalaSigEntryParsers.EntryParser[A])(index : Int) : Parser[A] =
+ entry(index) -~ parser >> { a => entry => Success(entry.scalaSig, a) }
+
+ def allEntries[A](f : ScalaSigEntryParsers.EntryParser[A]) = size >> { n => anyOf((0 until n) map parseEntry(f)) }
+
+ lazy val entries = allEntries(ScalaSigEntryParsers.entry) as "entries"
+ lazy val symbols = allEntries(ScalaSigEntryParsers.symbol) as "symbols"
+ lazy val methods = allEntries(ScalaSigEntryParsers.methodSymbol) as "methods"
+ lazy val attributes = allEntries(ScalaSigEntryParsers.attributeInfo) as "attributes"
+
+ lazy val topLevelClasses = allEntries(ScalaSigEntryParsers.topLevelClass)
+ lazy val topLevelObjects = allEntries(ScalaSigEntryParsers.topLevelObject)
+}
+
+object ScalaSigEntryParsers extends RulesWithState with MemoisableRules {
+ import ScalaSigAttributeParsers.{nat, utf8, longValue}
+
+ type S = ScalaSig#Entry
+ type EntryParser[A] = Rule[A, String]
+
+ implicit def byteCodeEntryParser[A](rule : ScalaSigAttributeParsers.Parser[A]) : EntryParser[A] = apply { entry =>
+ rule(entry.byteCode) mapOut (entry setByteCode _)
+ }
+
+ def toEntry[A](index : Int) = apply { sigEntry => ScalaSigParsers.entry(index)(sigEntry.scalaSig) }
+
+ def parseEntry[A](parser : EntryParser[A])(index : Int) = (toEntry(index) -~ parser)
+
+ implicit def entryType(code : Int) = key filter (_ == code)
+
+ val index = read(_.index)
+ val key = read(_.entryType)
+
+ lazy val entry : EntryParser[Any] = symbol | typeEntry | literal | name | attributeInfo | annotInfo | children | get
+
+ val ref = byteCodeEntryParser(nat)
+
+ val termName = 1 -~ utf8
+ val typeName = 2 -~ utf8
+
+ val name = termName | typeName as "name"
+
+ def refTo[A](rule : EntryParser[A]) : EntryParser[A] = ref >>& parseEntry(rule)
+
+ lazy val nameRef = refTo(name)
+ lazy val symbolRef = refTo(symbol)
+ lazy val typeRef = refTo(typeEntry)
+ lazy val constantRef = refTo(literal)
+
+ val symbolInfo = nameRef ~ symbolRef ~ nat ~ (symbolRef?) ~ ref ~ get ^~~~~~^ SymbolInfo
+
+ def symbolEntry(key : Int) = (key -~ none | (key + 64) -~ nat) -~ symbolInfo
+
+ val noSymbol = 3 -^ NoSymbol
+ val typeSymbol = symbolEntry(4) ^^ TypeSymbol as "typeSymbol"
+ val aliasSymbol = symbolEntry(5) ^^ AliasSymbol as "alias"
+ val classSymbol = symbolEntry(6) ~ (ref?) ^~^ ClassSymbol as "class"
+ val objectSymbol = symbolEntry(7) ^^ ObjectSymbol as "object"
+ val methodSymbol = symbolEntry(8) ~ (ref?) ^~^ MethodSymbol as "method"
+ val extRef = 9 -~ nameRef ~ (symbolRef?) ~ get ^~~^ ExternalSymbol as "extRef"
+ val extModClassRef = 10 -~ nameRef ~ (symbolRef?) ~ get ^~~^ ExternalSymbol as "extModClassRef"
+
+ lazy val symbol : EntryParser[Symbol] = oneOf(
+ noSymbol,
+ typeSymbol,
+ aliasSymbol,
+ classSymbol,
+ objectSymbol,
+ methodSymbol,
+ extRef,
+ extModClassRef) as "symbol"
+
+ val classSymRef = refTo(classSymbol)
+ val attribTreeRef = ref
+ val typeLevel = nat
+ val typeIndex = nat
+
+ lazy val typeEntry : EntryParser[Type] = oneOf(
+ 11 -^ NoType,
+ 12 -^ NoPrefixType,
+ 13 -~ symbolRef ^^ ThisType,
+ 14 -~ typeRef ~ symbolRef ^~^ SingleType,
+ 15 -~ constantRef ^^ ConstantType,
+ 16 -~ typeRef ~ symbolRef ~ (typeRef*) ^~~^ TypeRefType,
+ 17 -~ typeRef ~ typeRef ^~^ TypeBoundsType,
+ 18 -~ classSymRef ~ (typeRef*) ^~^ RefinedType,
+ 19 -~ symbolRef ~ (typeRef*) ^~^ ClassInfoType,
+ 20 -~ typeRef ~ (typeRef*) ^~^ MethodType,
+ 21 -~ typeRef ~ (refTo(typeSymbol)*) ^~^ PolyType,
+ 22 -~ typeRef ~ (typeRef*) ^~^ ImplicitMethodType,
+ 42 -~ typeRef ~ (attribTreeRef*) ^~^ AnnotatedType,
+ 51 -~ typeRef ~ symbolRef ~ (attribTreeRef*) ^~~^ AnnotatedWithSelfType,
+ 47 -~ typeLevel ~ typeIndex ^~^ DeBruijnIndexType,
+ 48 -~ typeRef ~ (symbolRef*) ^~^ ExistentialType) as "type"
+
+ lazy val literal = oneOf(
+ 24 -^ (),
+ 25 -~ longValue ^^ (_ != 0),
+ 26 -~ longValue ^^ (_.asInstanceOf[Byte]),
+ 27 -~ longValue ^^ (_.asInstanceOf[Short]),
+ 28 -~ longValue ^^ (_.asInstanceOf[Char]),
+ 29 -~ longValue ^^ (_.asInstanceOf[Int]),
+ 30 -~ longValue ^^ (_.asInstanceOf[Long]),
+ 31 -~ longValue ^^ (l => java.lang.Float.intBitsToFloat(l.asInstanceOf[Int])),
+ 32 -~ longValue ^^ (java.lang.Double.longBitsToDouble),
+ 33 -~ nameRef,
+ 34 -^ null,
+ 35 -~ typeRef)
+
+ lazy val attributeInfo = 40 -~ symbolRef ~ typeRef ~ (constantRef?) ~ (nameRef ~ constantRef *) ^~~~^ AttributeInfo // sym_Ref info_Ref {constant_Ref} {nameRef constantRef}
+ lazy val children = 41 -~ (nat*) ^^ Children //sym_Ref {sym_Ref}
+ lazy val annotInfo = 43 -~ (nat*) ^^ AnnotInfo // attarg_Ref {constant_Ref attarg_Ref}
+
+ lazy val topLevelClass = classSymbol filter isTopLevelClass
+ lazy val topLevelObject = objectSymbol filter isTopLevel
+
+ def isTopLevel(symbol : Symbol) = symbol.parent match {
+ case Some(ext : ExternalSymbol) => true
+ case _ => false
+ }
+ def isTopLevelClass (symbol : Symbol) = !symbol.isModule && isTopLevel(symbol)
+}
+
+ case class AttributeInfo(symbol : Symbol, typeRef : Type, value : Option[Any], values : Seq[String ~ Any]) // sym_Ref info_Ref {constant_Ref} {nameRef constantRef}
+ case class Children(symbolRefs : Seq[Int]) //sym_Ref {sym_Ref}
+
+ case class AnnotInfo(refs : Seq[Int]) // attarg_Ref {constant_Ref attarg_Ref}
+
+ /* | 49 TREE len_Nat 1 EMPTYtree
+ * | 49 TREE len_Nat 2 PACKAGEtree type_Ref sym_Ref mods_Ref name_Ref {tree_Ref}
+ * | 49 TREE len_Nat 3 CLASStree type_Ref sym_Ref mods_Ref name_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 4 MODULEtree type_Ref sym_Ref mods_Ref name_Ref tree_Ref
+ * | 49 TREE len_Nat 5 VALDEFtree type_Ref sym_Ref mods_Ref name_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 6 DEFDEFtree type_Ref sym_Ref mods_Ref name_Ref numtparams_Nat {tree_Ref} numparamss_Nat {numparams_Nat {tree_Ref}} tree_Ref tree_Ref
+ * | 49 TREE len_Nat 7 TYPEDEFtree type_Ref sym_Ref mods_Ref name_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 8 LABELtree type_Ref sym_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 9 IMPORTtree type_Ref sym_Ref tree_Ref {name_Ref name_Ref}
+ * | 49 TREE len_Nat 10 ANNOTATIONtree type_Ref sym_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 11 DOCDEFtree type_Ref sym_Ref string_Ref tree_Ref
+ * | 49 TREE len_Nat 12 TEMPLATEtree type_Ref sym_Ref numparents_Nat {tree_Ref} tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 13 BLOCKtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 14 CASEtree type_Ref tree_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 15 SEQUENCEtree type_Ref {tree_Ref}
+ * | 49 TREE len_Nat 16 ALTERNATIVEtree type_Ref {tree_Ref}
+ * | 49 TREE len_Nat 17 STARtree type_Ref {tree_Ref}
+ * | 49 TREE len_Nat 18 BINDtree type_Ref sym_Ref name_Ref tree_Ref
+ * | 49 TREE len_Nat 19 UNAPPLYtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 20 ARRAYVALUEtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 21 FUNCTIONtree type_Ref sym_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 22 ASSIGNtree type_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 23 IFtree type_Ref tree_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 24 MATCHtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 25 RETURNtree type_Ref sym_Ref tree_Ref
+ * | 49 TREE len_Nat 26 TREtree type_Ref tree_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 27 THROWtree type_Ref tree_Ref
+ * | 49 TREE len_Nat 28 NEWtree type_Ref tree_Ref
+ * | 49 TREE len_Nat 29 TYPEDtree type_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 30 TYPEAPPLYtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 31 APPLYtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 32 APPLYDYNAMICtree type_Ref sym_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 33 SUPERtree type_Ref sym_Ref tree_Ref name_Ref
+ * | 49 TREE len_Nat 34 THIStree type_Ref sym_Ref name_Ref
+ * | 49 TREE len_Nat 35 SELECTtree type_Ref sym_Ref tree_Ref name_Ref
+ * | 49 TREE len_Nat 36 IDENTtree type_Ref sym_Ref name_Ref
+ * | 49 TREE len_Nat 37 LITERALtree type_Ref constant_Ref
+ * | 49 TREE len_Nat 38 TYPEtree type_Ref
+ * | 49 TREE len_Nat 39 ANNOTATEDtree type_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 40 SINGLETONTYPEtree type_Ref tree_Ref
+ * | 49 TREE len_Nat 41 SELECTFROMTYPEtree type_Ref tree_Ref name_Ref
+ * | 49 TREE len_Nat 42 COMPOUNDTYPEtree type_Ref tree_Ref
+ * | 49 TREE len_Nat 43 APPLIEDTYPEtree type_Ref tree_Ref {tree_Ref}
+ * | 49 TREE len_Nat 44 TYPEBOUNDStree type_Ref tree_Ref tree_Ref
+ * | 49 TREE len_Nat 45 EXISTENTIALTYPEtree type_Ref tree_Ref {tree_Ref}
+ * | 50 MODIFIERS len_Nat flags_Long privateWithin_Ref {Annotation_Ref}
+
+ * Attarg = Refltree | Constant
+ *
+ * len is remaining length after `len'.
+ */
+
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala
new file mode 100644
index 0000000000..abdb28e1f7
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSigPrinter.scala
@@ -0,0 +1,322 @@
+package scala.tools.scalap.scalax.rules.scalasig
+
+import _root_.scala.Symbol
+import java.io.{PrintStream, ByteArrayOutputStream}
+import util.StringUtil
+import java.util.regex.Pattern
+
+class ScalaSigPrinter(stream: PrintStream) {
+ import stream._
+
+ val CONSTRUCTOR_NAME = "<init>"
+
+ case class TypeFlags(printRep: Boolean)
+
+ def printSymbol(symbol: Symbol) {printSymbol(0, symbol)}
+
+ def printSymbol(level: Int, symbol: Symbol) {
+ if (!symbol.isLocal) {
+ def indent() {for (i <- 1 to level) print(" ")}
+
+ symbol match {
+ case o: ObjectSymbol => if (!isCaseClassObject(o)) {
+ indent
+ printObject(level, o)
+ }
+ case c: ClassSymbol if !refinementClass(c) && !c.isModule => indent; {
+ printClass(level, c)
+ }
+ case m: MethodSymbol => printMethod(level, m, indent)
+ case a: AliasSymbol => indent; printAlias(level, a)
+ case t: TypeSymbol => ()
+ case s => {}
+ }
+ }
+ }
+
+ def isCaseClassObject(o: ObjectSymbol): Boolean = {
+ val TypeRefType(prefix, classSymbol: ClassSymbol, typeArgs) = o.infoType
+ o.isFinal && (classSymbol.children.find(x => x.isCase && x.isInstanceOf[MethodSymbol]) match {
+ case Some(_) => true
+ case None => false
+ })
+ }
+
+ def underCaseClass(m: MethodSymbol) = m.parent match {
+ case Some(c: ClassSymbol) => c.isCase
+ case _ => false
+ }
+
+
+ def printChildren(level: Int, symbol: Symbol) {
+ for (child <- symbol.children) printSymbol(level + 1, child)
+ }
+
+ def printWithIndent(level: Int, s: String) {
+ def indent() {for (i <- 1 to level) print(" ")}
+ indent;
+ print(s)
+ }
+
+ def printModifiers(symbol: Symbol) {
+ if (symbol.isSealed) print("sealed ")
+ if (symbol.isImplicit) print("implicit ")
+ if (symbol.isFinal) 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 ")
+ case _ => ()
+ }
+ if (symbol.isCase && !symbol.isMethod) print("case ")
+ }
+
+ 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 =>
+ }
+ print("\n")
+ printChildren(level, c)
+ printWithIndent(level, "}\n")
+ }
+
+ def getPrinterByConstructor(c: ClassSymbol) = {
+ c.children.find{
+ case m : MethodSymbol if m.name == CONSTRUCTOR_NAME => true
+ case _ => false
+ } match {
+ case Some(m: MethodSymbol) => {
+ val baos = new ByteArrayOutputStream
+ val stream = new PrintStream(baos)
+ val printer = new ScalaSigPrinter(stream)
+ printer.printMethodType(m.infoType, false)
+ baos.toString
+ }
+ case None => ""
+ }
+ }
+
+ def printObject(level: Int, o: ObjectSymbol) {
+ printModifiers(o)
+ print("object ")
+ print(processName(o.name))
+ val TypeRefType(prefix, classSymbol: ClassSymbol, typeArgs) = o.infoType
+ printType(classSymbol)
+ print(" {\n")
+ printChildren(level, classSymbol)
+ printWithIndent(level, "}\n")
+ }
+
+ def genParamNames(t: {def paramTypes: Seq[Type]}): List[String] = t.paramTypes.toList.map(x => {
+ var str = toString(x)
+ val j = str.indexOf("[")
+ if (j > 0) str = str.substring(0, j)
+ str = StringUtil.trimStart(str, "=> ")
+ var i = str.lastIndexOf(".")
+ val res = if (i > 0) str.substring(i + 1) else str
+ if (res.length > 1) StringUtil.decapitalize(res.substring(0, 1)) else res.toLowerCase
+ })
+
+ def printMethodType(t: Type, printResult: Boolean): Unit = {
+ def _pmt(mt: Type {def resultType: Type; def paramTypes: Seq[Type]}) = {
+ print(genParamNames(mt).zip(mt.paramTypes.toList.map(toString(_)(TypeFlags(true)))).map(p => p._1 + " : " + p._2).mkString(
+ "(" + (mt match {case ImplicitMethodType(_, _) => "implicit "; case _ => ""})
+ , ", ", ")"))
+ mt.resultType match {
+ case mt: MethodType => printMethodType(mt, printResult)
+ case imt: ImplicitMethodType => printMethodType(imt, printResult)
+ case x => if (printResult) {
+ print(" : ");
+ printType(x)
+ }
+ }
+ }
+ t match {
+ case mt@MethodType(resType, paramTypes) => _pmt(mt)
+ case mt@ImplicitMethodType(resType, paramTypes) => _pmt(mt)
+ case pt@PolyType(mt, typeParams) => {
+ print(typeParamString(typeParams))
+ printMethodType(mt, printResult)
+ }
+ //todo consider another method types
+ case x => print(" : "); printType(x)
+ }
+ }
+
+ def printMethod(level: Int, m: MethodSymbol, indent : () => Unit): Unit = {
+ val n = m.name
+ if (underCaseClass(m) && n == CONSTRUCTOR_NAME) return
+ if (m.isAccessor && n.endsWith("_$eq")) return
+ indent()
+ printModifiers(m)
+ if (m.isAccessor) {
+ val indexOfSetter = m.parent.get.children.findIndexOf(x => x.isInstanceOf[MethodSymbol] &&
+ x.asInstanceOf[MethodSymbol].name == n + "_$eq")
+ print(if (indexOfSetter > 0) "var " else "val ")
+ } else {
+ print("def ")
+ }
+ n match {
+ case CONSTRUCTOR_NAME => {
+ print("this")
+ printMethodType(m.infoType, false)
+ print(" = { /* compiled code */ }")
+ }
+ case name => {
+ val nn = processName(name)
+ print(nn)
+ printMethodType(m.infoType, true)
+ if (!m.isDeferred) { // Print body only for non-abstract metods
+ print(" = { /* compiled code */ }")
+ }
+ }
+ }
+ print("\n")
+ printChildren(level, m)
+ }
+
+ def printAlias(level: Int, a: AliasSymbol) {
+ print("type ")
+ print(processName(a.name))
+ printType(a.infoType, " = ")
+ print("\n")
+ printChildren(level, a)
+ }
+
+ def printAttributes(sym: SymbolInfoSymbol) {
+ for (attrib <- sym.attributes) printAttribute(attrib)
+ }
+
+ def printAttribute(attrib: AttributeInfo) {
+ printType(attrib.typeRef, "@")
+ if (attrib.value.isDefined) {
+ print("(")
+ printValue(attrib.value.get)
+ print(")")
+ }
+ if (!attrib.values.isEmpty) {
+ print(" {")
+ for (name ~ value <- attrib.values) {
+ print(" val ")
+ print(processName(name))
+ print(" = ")
+ printValue(value)
+ }
+ printValue(attrib.value)
+ print(" }")
+ }
+ print(" ")
+ }
+
+ def printValue(value: Any): Unit = value match {
+ case t: Type => printType(t)
+ // TODO string, char, float, etc.
+ case _ => print(value)
+ }
+
+ implicit object _tf extends TypeFlags(false)
+
+ def printType(sym: SymbolInfoSymbol)(implicit flags: TypeFlags): Unit = printType(sym.infoType)(flags)
+
+ def printType(t: Type)(implicit flags: TypeFlags): Unit = print(toString(t)(flags))
+
+ def printType(t: Type, sep: String)(implicit flags: TypeFlags): Unit = print(toString(t, sep)(flags))
+
+ 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.first) + "*"
+ case _ => "scala.Seq" + typeArgString(typeArgs)
+ }
+ case "scala.<byname>" => "=> " + toString(typeArgs.first)
+ case _ => StringUtil.trimStart(processName(symbol.path) + typeArgString(typeArgs), "<empty>.")
+ })
+ 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 _ => 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 s => symbol.toString
+ }
+
+ def typeArgString(typeArgs: Seq[Type]): String =
+ if (typeArgs.isEmpty) ""
+ else typeArgs.map(toString).map(StringUtil.trimStart(_, "=> ")).mkString("[", ", ", "]")
+
+ def typeParamString(params: Seq[Symbol]): String =
+ if (params.isEmpty) ""
+ else params.map(toString).mkString("[", ", ", "]")
+
+ val _syms = Map("\\$bar" -> "|", "\\$tilde" -> "~",
+ "\\$bang" -> "!", "\\$up" -> "^", "\\$plus" -> "+",
+ "\\$minus" -> "-", "\\$eq" -> "=", "\\$less" -> "<",
+ "\\$times" -> "*", "\\$div" -> "/", "\\$bslash" -> "\\\\",
+ "\\$greater" -> ">", "\\$qmark" -> "?", "\\$percent" -> "%",
+ "\\$amp" -> "&", "\\$colon" -> ":", "\\$u2192" -> "→")
+ val pattern = Pattern.compile(_syms.keySet.foldLeft("")((x, y) => if (x == "") y else x + "|" + y))
+ val placeholderPattern = "_\\$(\\d)+"
+
+ def processName(name: String) = {
+ val m = pattern.matcher(name)
+ var temp = name
+ while (m.find) {
+ val key = m.group
+ val re = "\\" + key
+ temp = temp.replaceAll(re, _syms(re))
+ }
+ temp.replaceAll(placeholderPattern, "_")
+ }
+
+}
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/SourceFileAttributeParser.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/SourceFileAttributeParser.scala
new file mode 100644
index 0000000000..f02ca870b0
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/SourceFileAttributeParser.scala
@@ -0,0 +1,25 @@
+package scala.tools.scalap.scalax.rules.scalasig
+
+/**
+ * @author ilyas
+ */
+
+object SourceFileAttributeParser extends ByteCodeReader {
+ val sourceFile = u2 ^^ SourceFileInfo
+
+ def parse(byteCode: ByteCode) = expect(sourceFile)(byteCode)
+}
+
+/**
+ *
+ * SourceFile_attribute {
+ u2 attribute_name_index;
+ u4 attribute_length;
+ u2 sourcefile_index;
+ }
+ *
+ * Contains only file index in ConstantPool, first two fields are already treated
+ * by {@link scalax.rules.scalasig.ClassFile.attribute#attribute}
+ */
+case class SourceFileInfo(sourceFileIndex: Int)
+
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Symbol.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Symbol.scala
new file mode 100644
index 0000000000..f8c5e88db1
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Symbol.scala
@@ -0,0 +1,70 @@
+package scala.tools.scalap.scalax.rules.scalasig
+
+import ScalaSigEntryParsers._
+
+trait Symbol extends Flags {
+ def name : String
+ def parent : Option[Symbol]
+ def children : Seq[Symbol]
+
+ def path : String = parent.map(_.path + ".").getOrElse("") + name
+}
+
+case object NoSymbol extends Symbol {
+ def name = "<no symbol>"
+ def parent = None
+ def hasFlag(flag : Long) = false
+ def children = Nil
+}
+
+abstract class ScalaSigSymbol extends Symbol {
+ def applyRule[A](rule : EntryParser[A]) : A = expect(rule)(entry)
+ def applyScalaSigRule[A](rule : ScalaSigParsers.Parser[A]) = ScalaSigParsers.expect(rule)(entry.scalaSig)
+
+ def entry : ScalaSig#Entry
+ def index = entry.index
+
+ lazy val children : Seq[Symbol] = applyScalaSigRule(ScalaSigParsers.symbols) filter (_.parent == Some(this))
+ lazy val attributes : Seq[AttributeInfo] = applyScalaSigRule(ScalaSigParsers.attributes) filter (_.symbol == this)
+}
+
+case class ExternalSymbol(name : String, parent : Option[Symbol], entry : ScalaSig#Entry) extends ScalaSigSymbol {
+ override def toString = path
+ def hasFlag(flag : Long) = false
+}
+
+case class SymbolInfo(name : String, owner : Symbol, flags : Int, privateWithin : Option[AnyRef], info : Int, entry : ScalaSig#Entry) {
+ def symbolString(any : AnyRef) = any match {
+ case sym : SymbolInfoSymbol => sym.index.toString
+ case other => other.toString
+ }
+
+ override def toString = name + ", owner=" + symbolString(owner) + ", flags=" + flags.toHexString + ", info=" + info + (privateWithin match {
+ case Some(any) => ", privateWithin=" + symbolString(any)
+ case None => " "
+ })
+}
+
+abstract class SymbolInfoSymbol extends ScalaSigSymbol {
+ def symbolInfo : SymbolInfo
+
+ def entry = symbolInfo.entry
+ def name = symbolInfo.name
+ def parent = Some(symbolInfo.owner)
+ def hasFlag(flag : Long) = (symbolInfo.flags & flag) != 0
+
+ lazy val infoType = applyRule(parseEntry(typeEntry)(symbolInfo.info))
+}
+
+case class TypeSymbol(symbolInfo : SymbolInfo) extends SymbolInfoSymbol{
+ override def path = name
+}
+
+case class AliasSymbol(symbolInfo : SymbolInfo) extends SymbolInfoSymbol{
+ override def path = name
+}
+case class ClassSymbol(symbolInfo : SymbolInfo, thisTypeRef : Option[Int]) extends SymbolInfoSymbol {
+ lazy val selfType = thisTypeRef.map{(x: Int) => applyRule(parseEntry(typeEntry)(x))}
+}
+case class ObjectSymbol(symbolInfo : SymbolInfo) extends SymbolInfoSymbol
+case class MethodSymbol(symbolInfo : SymbolInfo, aliasRef : Option[Int]) extends SymbolInfoSymbol
diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala
new file mode 100644
index 0000000000..c812a94af7
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/Type.scala
@@ -0,0 +1,22 @@
+package scala.tools.scalap.scalax.rules.scalasig
+
+abstract class Type
+
+case object NoType extends Type
+case object NoPrefixType extends Type
+
+case class ThisType(symbol : Symbol) extends Type
+case class SingleType(typeRef : Type, symbol : Symbol) extends Type
+case class ConstantType(constant : Any) extends Type
+case class TypeRefType(prefix : Type, symbol : Symbol, typeArgs : Seq[Type]) extends Type
+case class TypeBoundsType(lower : Type, upper : Type) extends Type
+case class RefinedType(classSym : Symbol, typeRefs : List[Type]) extends Type
+case class ClassInfoType(symbol : Symbol, typeRefs : Seq[Type]) extends Type
+case class MethodType(resultType : Type, paramTypes : Seq[Type]) extends Type
+case class PolyType(typeRef : Type, symbols : Seq[TypeSymbol]) extends Type
+case class PolyTypeWithCons(typeRef : Type, symbols : Seq[TypeSymbol], cons: String) extends Type
+case class ImplicitMethodType(resultType : Type, paramTypes : Seq[Type]) extends Type
+case class AnnotatedType(typeRef : Type, attribTreeRefs : List[Int]) extends Type
+case class AnnotatedWithSelfType(typeRef : Type, symbol : Symbol, attribTreeRefs : List[Int]) extends Type
+case class DeBruijnIndexType(typeLevel : Int, typeIndex : Int) extends Type
+case class ExistentialType(typeRef : Type, symbols : Seq[Symbol]) extends Type \ No newline at end of file
diff --git a/src/scalap/scala/tools/scalap/scalax/util/StringUtil.scala b/src/scalap/scala/tools/scalap/scalax/util/StringUtil.scala
new file mode 100644
index 0000000000..d48597fd9a
--- /dev/null
+++ b/src/scalap/scala/tools/scalap/scalax/util/StringUtil.scala
@@ -0,0 +1,15 @@
+package scala.tools.scalap.scalax.util
+
+import java.beans.Introspector
+
+/**
+ * @author ilyas
+ */
+
+object StringUtil {
+
+ def trimStart(s: String, prefix: String) = if (s != null && s.startsWith(prefix)) s.substring(prefix.length) else s
+
+ def decapitalize(s: String) = Introspector.decapitalize(s)
+
+} \ No newline at end of file