summaryrefslogtreecommitdiff
path: root/sources/scalac/symtab/classfile
diff options
context:
space:
mode:
Diffstat (limited to 'sources/scalac/symtab/classfile')
-rw-r--r--sources/scalac/symtab/classfile/AttributeParser.java439
-rw-r--r--sources/scalac/symtab/classfile/ClassParser.java111
-rw-r--r--sources/scalac/symtab/classfile/ClassfileConstants.java57
-rw-r--r--sources/scalac/symtab/classfile/ClassfileParser.java239
-rw-r--r--sources/scalac/symtab/classfile/ConstantPool.java183
-rw-r--r--sources/scalac/symtab/classfile/JavaTypeCreator.java82
-rw-r--r--sources/scalac/symtab/classfile/JavaTypeFactory.java28
-rw-r--r--sources/scalac/symtab/classfile/PackageParser.java129
-rw-r--r--sources/scalac/symtab/classfile/Signatures.java122
9 files changed, 1390 insertions, 0 deletions
diff --git a/sources/scalac/symtab/classfile/AttributeParser.java b/sources/scalac/symtab/classfile/AttributeParser.java
new file mode 100644
index 0000000000..0ed09b44d0
--- /dev/null
+++ b/sources/scalac/symtab/classfile/AttributeParser.java
@@ -0,0 +1,439 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.*;
+import scalac.symtab.*;
+import scalac.util.*;
+import java.util.*;
+
+public class AttributeParser implements ClassfileConstants {
+
+ /** the classfile input buffer
+ */
+ protected AbstractFileReader in;
+
+ /** the constant pool
+ */
+ protected ConstantPool pool;
+
+ protected ClassfileParser parser;
+
+ /** constructor
+ */
+ public AttributeParser(AbstractFileReader in, ConstantPool pool, ClassfileParser parser) {
+ this.in = in;
+ this.pool = pool;
+ this.parser = parser;
+ }
+
+ public int nameToId(Name name) {
+ if (name == SOURCEFILE_N)
+ return SOURCEFILE_ATTR;
+ if (name == SYNTHETIC_N)
+ return SYNTHETIC_ATTR;
+ if (name == DEPRECATED_N)
+ return DEPRECATED_ATTR;
+ if (name == CODE_N)
+ return CODE_ATTR;
+ if (name == EXCEPTIONS_N)
+ return EXCEPTIONS_ATTR;
+ if (name == CONSTANT_VALUE_N)
+ return CONSTANT_VALUE_ATTR;
+ if (name == LINE_NUM_TABLE_N)
+ return LINE_NUM_TABLE_ATTR;
+ if (name == LOCAL_VAR_TABLE_N)
+ return LOCAL_VAR_TABLE_ATTR;
+ if (name == INNERCLASSES_N)
+ return INNERCLASSES_ATTR;
+ if (name == META_N)
+ return META_ATTR;
+ if (name == SCALA_N)
+ return SCALA_ATTR;
+ return BAD_ATTR;
+ }
+
+ public Symbol readAttributes(Symbol def, Type type, int attrs) {
+ char nattr = in.nextChar();
+ for (int i = 0; i < nattr; i++) {
+ Name attrName = (Name)pool.readPool(in.nextChar());
+ int attr = nameToId(attrName);
+ int attrLen = in.nextInt();
+ if ((attrs & attr) == 0) {
+ //System.out.println("# skipping " + attrName + " of " + def);
+ in.skip(attrLen);
+ } else {
+ //System.out.println("# reading " + attrName + " of " + def);
+ readAttribute(def, type, attr, attrLen);
+ }
+ }
+ return def;
+ }
+
+ public void readAttribute(Symbol sym, Type type, int attr, int attrLen) {
+ switch (attr) {
+ // class attributes
+ case SCALA_ATTR:
+ in.skip(attrLen);
+ /* not yet
+ Name sourcefile = (Name)pool.readPool(in.nextChar());
+ new UnPickle(
+ (JavaClassSymbol) sym, in.nextBytes(attrLen - 2), sourcefile);
+ */
+ return;
+
+ case SOURCEFILE_ATTR:
+ // ((ClassDef)def).sourcefile = (Name)reader.readPool(in.nextChar());
+ in.skip(attrLen);
+ return;
+
+ case INNERCLASSES_ATTR:
+ /* int n = in.nextChar();
+ for (int i = 0; i < n; i++) {
+ Symbol inner = (Symbol)pool.readPool(in.nextChar());
+ Symbol outer = (Symbol)pool.readPool(in.nextChar());
+ Name name = (Name)pool.readPool(in.nextChar());
+ int flags = in.nextChar();
+ if (name != null) {
+ inner.owner(outer);
+ inner.mangled(name);
+ inner.flags = flags;
+ }
+ } */
+ in.skip(attrLen);
+ return;
+
+ // method attributes
+ case CODE_ATTR:
+ in.skip(attrLen);
+ return;
+
+ case EXCEPTIONS_ATTR:
+ //int nexceptions = in.nextChar();
+ //Type[] thrown = new Type[nexceptions];
+ //for (int j = 0; j < nexceptions; j++)
+ // thrown[j] = make.classType(reader.readClassName(in.nextChar()));
+ //((MethodType)def.type).thrown = thrown;
+ in.skip(attrLen);
+ return;
+
+ case LINE_NUM_TABLE_ATTR:
+ in.skip(attrLen);
+ return;
+
+ case LOCAL_VAR_TABLE_ATTR:
+ in.skip(attrLen);
+ return;
+
+ // general attributes
+ case SYNTHETIC_ATTR:
+ sym.flags |= Modifiers.SYNTHETIC;
+ return;
+
+ case DEPRECATED_ATTR:
+ sym.flags |= Modifiers.DEPRECATED;
+ return;
+
+ case CONSTANT_VALUE_ATTR:
+ // Type ctype = (Type)reader.readPool(in.nextChar());
+ // def.type = types.coerce(ctype, def.type);
+ in.skip(attrLen);
+ return;
+
+ case META_ATTR:
+ //System.out.println("parsing meta data for " + sym);
+ String meta = pool.readPool(in.nextChar()).toString().trim();
+ sym.setInfo(new MetaParser(meta, tvars, sym, type).parse(), parser.phaseId);
+
+ return;
+ }
+ throw new RuntimeException("unknown classfile attribute");
+ }
+
+ Scope tvars = new Scope();
+
+ class MetaParser {
+
+ Symbol owner;
+ StringTokenizer scanner;
+ Type defaultType;
+ String token;
+ Scope tvars;
+ Scope locals;
+
+ MetaParser(String meta, Scope tvars, Symbol owner, Type defaultType) {
+ //System.out.println("meta = " + meta);
+ this.scanner = new StringTokenizer(meta, "()[], \t<;", true);
+ this.defaultType = defaultType;
+ this.owner = owner;
+ this.tvars = tvars;
+ }
+
+ private Symbol getTVar(String name) {
+ return getTVar(name, parser.c.constructor());
+ }
+
+ private Symbol getTVar(String name, Symbol owner) {
+ if (name.startsWith("?")) {
+ if (locals != null) {
+ Symbol s = locals.lookup(Name.fromString(name).toTypeName());
+ if (s != Symbol.NONE)
+ return s;
+ }
+ Symbol s = tvars.lookup(Name.fromString(name).toTypeName());
+ if (s == Symbol.NONE) {
+ s = new TypeSymbol(Kinds.TYPE,
+ Position.NOPOS,
+ Name.fromString(token).toTypeName(),
+ owner,
+ Modifiers.PARAM);
+ s.setInfo(parser.defs.ANY_TYPE, parser.phaseId);
+ tvars.enter(s);
+ }
+ return s;
+ } else
+ return Symbol.NONE;
+ }
+
+ private String nextToken() {
+ do {
+ token = scanner.nextToken().trim();
+ } while (token.length() == 0);
+ return token;
+ }
+
+ protected Type parse() {
+ if (scanner.hasMoreTokens()) {
+ nextToken();
+ if (!scanner.hasMoreTokens())
+ return defaultType;
+ if ("class".equals(token))
+ return parseMetaClass();
+ if ("method".equals(token))
+ return parseMetaMethod();
+ if ("field".equals(token))
+ return parseMetaField();
+ if ("constr".equals(token))
+ return parseConstrField();
+ }
+ return defaultType;
+ }
+
+ protected Type parseMetaClass() {
+ nextToken();
+ //System.out.println("parse meta class " + token);//DEBUG
+ if ("[".equals(token)) {
+ try {
+ Vector syms = new Vector();
+ do {
+ nextToken();
+ assert token.startsWith("?");
+ Symbol s = getTVar(token);
+ if (s == Symbol.NONE)
+ return defaultType;
+ nextToken();
+ //System.out.println("new var " + s + ", " + token);//DEBUG
+ if (token.equals("<")) {
+ nextToken();
+ s.setInfo(parseType(), parser.phaseId);
+ }
+ syms.add(s);
+ } while (token.equals(","));
+ assert "]".equals(token);
+ nextToken();
+ Symbol[] smbls = (Symbol[])syms.toArray(new Symbol[syms.size()]);
+ //System.out.println("*** " + syms);//DEBUG
+ Type constrtype = Type.appliedType(
+ parser.ctype, Symbol.type(smbls));
+
+ if ((parser.c.flags & Modifiers.INTERFACE) != 0) {
+ parser.c.constructor().setInfo(
+ Type.PolyType(smbls, constrtype), parser.phaseId);
+ //System.out.println("info = " + parser.c.constructor().info());//DEBUG
+ }
+ Symbol[] constrs;
+ switch (parser.c.constructor().rawInfo()) {
+ case OverloadedType(Symbol[] alts, _):
+ constrs = alts;
+ break;
+ default:
+ constrs = new Symbol[]{parser.c.constructor()};
+ }
+ for (int i = 0; i < constrs.length; i++) {
+ //System.out.println("info = " + e.sym.info());
+ switch (constrs[i].rawInfo()) {
+ case MethodType(Symbol[] vparams, _):
+ constrs[i].setInfo(
+ Type.PolyType(smbls,
+ Type.MethodType(
+ vparams, constrtype)), parser.phaseId);
+ break;
+ case PolyType(_, _):
+ constrs[i].setInfo(
+ Type.PolyType(smbls, constrtype), parser.phaseId);
+ break;
+ }
+ //System.out.println("*** constructor " + e.sym + ": " + e.sym.info());//DEBUG
+ }
+ } catch (NoSuchElementException e) {
+ }
+ }
+ Type res = defaultType;
+ if ("extends".equals(token)) {
+ Vector basetpes = new Vector();
+ do {
+ nextToken();
+ basetpes.add(parseType());
+ } while (token.equals("with"));
+ switch (defaultType) {
+ case CompoundType(_, Scope scope):
+ res = Type.compoundType(
+ (Type[])basetpes.toArray(new Type[basetpes.size()]),
+ scope,
+ defaultType.symbol());
+ }
+ }
+ assert ";".equals(token);
+ return res;
+ }
+
+ protected Type parseType() {
+ String name = token;
+ Symbol s = getTVar(name);
+ nextToken();
+ if (s != Symbol.NONE)
+ return s.type();
+ Symbol clazz = parser.defs.getClass(Name.fromString(name));
+ if (token.equals("[")) {
+ Vector types = new Vector();
+ do {
+ nextToken();
+ types.add(parseType());
+ } while (token.equals(","));
+ assert "]".equals(token);
+ nextToken();
+ Type[] args = new Type[types.size()];
+ types.toArray(args);
+ return Type.TypeRef(clazz.owner().thisType(), clazz, args);
+ } else {
+ return parser.defs.monoType(clazz);
+ }
+ }
+
+ protected Type parseMetaMethod() {
+ locals = new Scope();
+ try {
+ nextToken();
+ Symbol[] smbls = null;
+ //System.out.println("parse meta method " + token);
+ if ("[".equals(token)) {
+ Vector syms = new Vector();
+ do {
+ nextToken();
+ if ("]".equals(token))
+ break;
+ assert token.startsWith("?");
+ Symbol s = getTVar(token, owner);
+ if (s == Symbol.NONE)
+ return defaultType;
+ nextToken();
+ //System.out.println("new var " + s + ", " + token);
+ if (token.equals("<")) {
+ nextToken();
+ s.setInfo(parseType(), parser.phaseId);
+ }
+ syms.add(s);
+ } while (token.equals(","));
+ assert "]".equals(token);
+ nextToken();
+ smbls = (Symbol[])syms.toArray(new Symbol[syms.size()]);
+ }
+ if ("(".equals(token)) {
+ int i = 0;
+ Vector params = new Vector();
+ do {
+ nextToken();
+ if (")".equals(token))
+ break;
+ params.add(new TermSymbol(
+ Position.NOPOS,
+ Name.fromString("x" + (i++)),
+ owner,
+ Modifiers.PARAM).setInfo(parseType(), parser.phaseId));
+ //System.out.println(" + " + token);
+ } while (token.equals(","));
+ assert ")".equals(token);
+ nextToken();
+ //System.out.println("+++ method " + token);
+ Type restpe = parseType();
+ assert ";".equals(token);
+ if (smbls == null)
+ return Type.MethodType(
+ (Symbol[])params.toArray(new Symbol[params.size()]),
+ restpe);
+ else
+ return Type.PolyType(
+ smbls,
+ Type.MethodType(
+ (Symbol[])params.toArray(new Symbol[params.size()]),
+ restpe));
+ } else {
+ Type res = parseType();
+ assert ";".equals(token);
+ if (smbls == null)
+ return Type.PolyType(Symbol.EMPTY_ARRAY, res);
+ else
+ return Type.PolyType(smbls, res);
+ }
+ } catch (NoSuchElementException e) {
+ return defaultType;
+ } finally {
+ locals = null;
+ }
+ }
+
+ protected Type parseMetaField() {
+ nextToken();
+ return parseType();
+ }
+
+ protected Type parseConstrField() {
+ try {
+ nextToken();
+ //System.out.println("+++ constr " + token);
+ if ("(".equals(token)) {
+ int i = 0;
+ Vector params = new Vector();
+ do {
+ nextToken();
+ if (")".equals(token))
+ break;
+ params.add(new TermSymbol(
+ Position.NOPOS,
+ Name.fromString("x" + (i++)),
+ owner,
+ Modifiers.PARAM).setInfo(parseType(), parser.phaseId));
+ //System.out.println(" + " + token);
+ } while (token.equals(","));
+ assert ")".equals(token);
+ nextToken();
+ assert ";".equals(token);
+ return Type.MethodType(
+ (Symbol[])params.toArray(new Symbol[params.size()]),
+ parser.ctype);
+ } else {
+ assert ";".equals(token);
+ return Type.PolyType(Symbol.EMPTY_ARRAY, parser.ctype);
+ }
+ } catch (NoSuchElementException e) {
+ return defaultType;
+ }
+ }
+ }
+}
diff --git a/sources/scalac/symtab/classfile/ClassParser.java b/sources/scalac/symtab/classfile/ClassParser.java
new file mode 100644
index 0000000000..9948ba33cf
--- /dev/null
+++ b/sources/scalac/symtab/classfile/ClassParser.java
@@ -0,0 +1,111 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.*;
+import scalac.symtab.*;
+import scalac.util.*;
+import java.io.*;
+
+
+public class ClassParser extends Type.LazyType {
+
+ /** the global compilation environment
+ */
+ protected Global global;
+
+ public ClassParser(Global global) {
+ this.global = global;
+ }
+
+ /** complete class symbol c by loading the class
+ */
+ public void complete(Symbol c) {
+ //System.out.println("loading " + c);//DEBUG
+ try {
+ long msec = System.currentTimeMillis();
+ String filename = externalizeFileName(c.fullName()) + ".class";
+ AbstractFile f = global.classPath.openFile(filename);
+ if (f == null)
+ global.error("could not read class " + c);
+ else {
+ new ClassfileParser(global, new AbstractFileReader(f), c).parse();
+ global.operation("loaded " + f.getPath() + " in " +
+ (System.currentTimeMillis() - msec) + "ms");
+ //for (Definition e = c.locals().elems; e != null; e = e.sibling)
+ // if (e.def.kind == TYP)
+ // e.def.complete();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ global.error("i/o error while loading " + c);
+ c.setInfo(Type.ErrorType);
+ }
+ }
+
+ /** return external representation of file name s,
+ * converting '.' to File.separatorChar
+ */
+ public String externalizeFileName(Name n) {
+ if ((n == null) || (n.length() == 0))
+ return ".";
+ byte[] ascii = n.toAscii();
+ String s = SourceRepresentation.ascii2string(
+ ascii, 0, ascii.length);
+ return s.replace('.', File.separatorChar);
+ }
+
+ public Type.LazyType staticsParser(Symbol clazz) {
+ return new StaticsParser(clazz);
+ }
+
+ public Type.LazyType aliasParser(Symbol alias) {
+ return new AliasParser(alias);
+ }
+
+ class StaticsParser extends Type.LazyType {
+ Symbol clazz;
+
+ StaticsParser(Symbol clazz) {
+ this.clazz = clazz;
+ }
+
+ public void complete(Symbol statics) {
+ ClassParser.this.complete(clazz);
+ }
+ }
+
+ class AliasParser extends Type.LazyType {
+ Symbol alias;
+
+ AliasParser(Symbol alias) {
+ this.alias = alias;
+ }
+
+ public void complete(Symbol c) {
+ try {
+ long msec = System.currentTimeMillis();
+ String filename = externalizeFileName(alias.fullName()) + ".class";
+ AbstractFile f = global.classPath.openFile(filename);
+ if (f == null)
+ global.error("could not read class " + c);
+ else {
+ new ClassfileParser(global, new AbstractFileReader(f), c).parse();
+ global.operation("loaded " + f.getPath() + " in " +
+ (System.currentTimeMillis() - msec) + "ms");
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ global.error("i/o error while loading " + c);
+ c.setInfo(Type.ErrorType);
+ }
+ }
+ }
+}
+
diff --git a/sources/scalac/symtab/classfile/ClassfileConstants.java b/sources/scalac/symtab/classfile/ClassfileConstants.java
new file mode 100644
index 0000000000..16b9f5af44
--- /dev/null
+++ b/sources/scalac/symtab/classfile/ClassfileConstants.java
@@ -0,0 +1,57 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.util.Name;
+
+public interface ClassfileConstants {
+
+ int JAVA_MAGIC = 0xCAFEBABE;
+ int JAVA_MAJOR_VERSION = 45;
+ int JAVA_MINOR_VERSION = 3;
+
+ int CONSTANT_UTF8 = 1;
+ int CONSTANT_UNICODE = 2;
+ int CONSTANT_INTEGER = 3;
+ int CONSTANT_FLOAT = 4;
+ int CONSTANT_LONG = 5;
+ int CONSTANT_DOUBLE = 6;
+ int CONSTANT_CLASS = 7;
+ int CONSTANT_STRING = 8;
+ int CONSTANT_FIELDREF = 9;
+ int CONSTANT_METHODREF = 10;
+ int CONSTANT_INTFMETHODREF = 11;
+ int CONSTANT_NAMEANDTYPE = 12;
+
+ int BAD_ATTR = 0x00000;
+ int SOURCEFILE_ATTR = 0x00001;
+ int SYNTHETIC_ATTR = 0x00002;
+ int DEPRECATED_ATTR = 0x00004;
+ int CODE_ATTR = 0x00008;
+ int EXCEPTIONS_ATTR = 0x00010;
+ int CONSTANT_VALUE_ATTR = 0x00020;
+ int LINE_NUM_TABLE_ATTR = 0x00040;
+ int LOCAL_VAR_TABLE_ATTR = 0x00080;
+ int INNERCLASSES_ATTR = 0x08000;
+ int META_ATTR = 0x10000;
+ int SCALA_ATTR = 0x20000;
+
+ Name SOURCEFILE_N = Name.fromString("SourceFile");
+ Name SYNTHETIC_N = Name.fromString("Synthetic");
+ Name DEPRECATED_N = Name.fromString("Deprecated");
+ Name CODE_N = Name.fromString("Code");
+ Name EXCEPTIONS_N = Name.fromString("Exceptions");
+ Name CONSTANT_VALUE_N = Name.fromString("ConstantValue");
+ Name LINE_NUM_TABLE_N = Name.fromString("LineNumberTable");
+ Name LOCAL_VAR_TABLE_N = Name.fromString("LocalVariableTable");
+ Name INNERCLASSES_N = Name.fromString("InnerClasses");
+ Name META_N = Name.fromString("JacoMeta");
+ Name SCALA_N = Name.fromString("ScalaSignature");
+ Name CONSTR_N = Name.fromString("<init>");
+}
diff --git a/sources/scalac/symtab/classfile/ClassfileParser.java b/sources/scalac/symtab/classfile/ClassfileParser.java
new file mode 100644
index 0000000000..956c83968f
--- /dev/null
+++ b/sources/scalac/symtab/classfile/ClassfileParser.java
@@ -0,0 +1,239 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.*;
+import scalac.util.*;
+import scalac.symtab.*;
+import java.io.*;
+import java.util.*;
+
+//todo: don't keep statics module in scope.
+
+public class ClassfileParser implements ClassfileConstants {
+
+ static final int CLASS_ATTR = SOURCEFILE_ATTR
+ | INNERCLASSES_ATTR
+ | SYNTHETIC_ATTR
+ | DEPRECATED_ATTR
+ | META_ATTR
+ | SCALA_ATTR;
+ static final int METH_ATTR = CODE_ATTR
+ | EXCEPTIONS_ATTR
+ | SYNTHETIC_ATTR
+ | DEPRECATED_ATTR
+ | META_ATTR;
+ static final int FIELD_ATTR = CONSTANT_VALUE_ATTR
+ | SYNTHETIC_ATTR
+ | DEPRECATED_ATTR
+ | META_ATTR;
+
+ protected Global global;
+ protected AbstractFileReader in;
+ protected Symbol c;
+ protected Type ctype;
+ protected Scope locals;
+ protected Scope statics;
+ protected Scope constr;
+ protected JavaTypeFactory make;
+ protected Signatures sigs;
+ protected ConstantPool pool;
+ protected AttributeParser attrib;
+ protected Definitions defs;
+ protected int phaseId;
+
+
+ public ClassfileParser(Global global, AbstractFileReader in, Symbol c) {
+ this.global = global;
+ this.in = in;
+ this.c = c;
+ this.ctype = Type.TypeRef(c.owner().thisType(), c, Type.EMPTY_ARRAY);
+ this.make = new JavaTypeCreator(global);
+ this.sigs = new Signatures(global, make);
+ this.pool = new ConstantPool(in, sigs);
+ this.attrib = new AttributeParser(in, pool, this);
+ this.defs = global.definitions;
+ this.phaseId = global.POST_ANALYZER_PHASE_ID;
+ }
+
+
+ /** parse the classfile and throw IO exception if there is an
+ * error in the classfile structure
+ */
+ public void parse() throws IOException {
+ try {
+ if (in.nextInt() != JAVA_MAGIC)
+ throw new IOException("illegal start of class file");
+ int minorVersion = in.nextChar();
+ int majorVersion = in.nextChar();
+ if ((majorVersion < JAVA_MAJOR_VERSION) ||
+ ((majorVersion == JAVA_MAJOR_VERSION) &&
+ (minorVersion < JAVA_MINOR_VERSION)))
+ throw new IOException("class file has wrong version " +
+ majorVersion + "." + minorVersion + ", should be " +
+ JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION);
+ pool.indexPool();
+ int flags = in.nextChar();
+ Name name = readClassName(in.nextChar());
+ if (c.fullName() != name)
+ throw new IOException("class file '" + c.fullName() +
+ "' contains wrong class " + name);
+ // todo: correct flag transition
+ c.flags = transFlags(flags);
+ if ((c.flags & Modifiers.ABSTRACT) != 0)
+ c.flags = c.flags & ~Modifiers.ABSTRACT | Modifiers.ABSTRACTCLASS;
+ Type supertpe = readClassType(in.nextChar());
+ Type[] basetpes = new Type[in.nextChar() + 1];
+ this.locals = new Scope();
+ this.statics = new Scope();
+ this.constr = new Scope();
+ // set type of class
+ Type classType = Type.compoundType(basetpes, locals, c);
+ c.setInfo(classType, phaseId);
+ // set type of statics
+ Symbol staticsClass = c.module().moduleClass();
+ Type staticsInfo = Type.compoundType(Type.EMPTY_ARRAY, statics, staticsClass);
+ staticsClass.setInfo(staticsInfo, phaseId);
+ c.module().setInfo(Type.TypeRef(staticsClass.owner().thisType(),
+ staticsClass, Type.EMPTY_ARRAY));
+ basetpes[0] = supertpe;
+ for (int i = 1; i < basetpes.length; i++)
+ basetpes[i] = readClassType(in.nextChar());
+ int fieldCount = in.nextChar();
+ for (int i = 0; i < fieldCount; i++)
+ parseField();
+ int methodCount = in.nextChar();
+ for (int i = 0; i < methodCount; i++)
+ parseMethod();
+ // set constructor type to the declared type
+ Symbol[] constrs = constr.elements();
+ if (constrs.length != 0) {
+ assert constrs.length == 1;
+ c.constructor().setInfo(constrs[0].info(), phaseId);
+ } else {
+ Type constrtype = ((c.flags & Modifiers.INTERFACE) != 0)
+ ? Type.PolyType(Symbol.EMPTY_ARRAY, ctype)
+ : Type.MethodType(new Symbol[]{Symbol.NONE}, ctype);
+ c.constructor().setInfo(constrtype, phaseId);
+ }
+ attrib.readAttributes(c, classType, CLASS_ATTR);
+ //System.out.println("dynamic class: " + c);
+ //System.out.println("statics class: " + staticsClass);
+ //System.out.println("module: " + c.module());
+ //System.out.println("modules class: " + c.module().type().symbol());
+ } catch (RuntimeException e) {
+ e.printStackTrace();
+ throw new IOException("bad class file (" + e.getMessage() + ")");
+ }
+ }
+
+ /** convert Java modifiers into Scala flags
+ */
+ public int transFlags(int flags) {
+ int res = 0;
+ if (((flags & 0x0007) == 0) ||
+ ((flags & 0x0002) != 0))
+ res |= Modifiers.PRIVATE;
+ else if ((flags & 0x0004) != 0)
+ res |= Modifiers.PROTECTED;
+ if ((flags & 0x0400) != 0)
+ res |= Modifiers.ABSTRACT;
+ if ((flags & 0x0010) != 0)
+ res |= Modifiers.FINAL;
+ if ((flags & 0x0200) != 0)
+ res |= Modifiers.INTERFACE | Modifiers.ABSTRACTCLASS;
+ return res | Modifiers.JAVA;
+ }
+
+ /** read a class name
+ */
+ protected Name readClassName(int i) {
+ return (Name)pool.readPool(i);
+ }
+
+ /** read a class name and return the corresponding class type
+ */
+ protected Type readClassType(int i) {
+ if (i == 0)
+ return defs.ANY_TYPE;
+ Type res = defs.getJavaType((Name)pool.readPool(i));
+ if (res == Type.ErrorType)
+ global.error("unknown class reference " + pool.readPool(i));
+ if (res.symbol() == defs.JAVA_OBJECT_TYPE.symbol())
+ return defs.ANYREF_TYPE;
+ else
+ return res;
+ }
+
+ /** read a signature and return it as a type
+ */
+ protected Type readType(int i) {
+ Name sig = pool.readExternal(i);
+ return sigs.sigToType(Name.names, sig.index, sig.length());
+ }
+
+ /** read a field
+ */
+ protected void parseField() {
+ int flags = in.nextChar();
+ Name name = (Name)pool.readPool(in.nextChar());
+ Type type = readType(in.nextChar());
+ int mods = transFlags(flags);
+ if ((flags & 0x0010) == 0)
+ mods |= Modifiers.MUTABLE;
+ Symbol owner = c;
+ if ((flags & 0x0008) != 0)
+ owner = c.module().moduleClass();
+ Symbol s = new TermSymbol(Position.NOPOS, name, owner, mods);
+ s.setInfo(type, phaseId);
+ attrib.readAttributes(s, type, FIELD_ATTR);
+ ((flags & 0x0008) != 0 ? statics : locals).enterOrOverload(s);
+ }
+
+ /** read a method
+ */
+ protected void parseMethod() {
+ int flags = in.nextChar();
+ Name name = (Name)pool.readPool(in.nextChar());
+ Type type = readType(in.nextChar());
+ if (CONSTR_N.equals(name)) {
+ Symbol s = TermSymbol.newConstructor(c, transFlags(flags));
+ // kick out protected, package visible or
+ // private constructors
+ if (((flags & 0x0004) != 0) ||
+ ((flags & 0x0002) != 0) ||
+ ((flags & 0x0007) == 0)) {
+ attrib.readAttributes(s, type, METH_ATTR);
+ return;
+ }
+ switch (type) {
+ case MethodType(Symbol[] vparams, _):
+ if (c == defs.OBJECT_CLASS)
+ type = Type.PolyType(Symbol.EMPTY_ARRAY, ctype);
+ else
+ type = Type.MethodType(vparams, ctype);
+ break;
+ default:
+ throw new ApplicationError();
+ }
+ s.setInfo(type, phaseId);
+ attrib.readAttributes(s, type, METH_ATTR);
+ //System.out.println("-- enter " + s);
+ constr.enterOrOverload(s);
+ } else {
+ Symbol s = new TermSymbol(
+ Position.NOPOS, name,
+ ((flags & 0x0008) != 0) ? c.module().moduleClass() : c,
+ transFlags(flags));
+ s.setInfo(type, phaseId);
+ attrib.readAttributes(s, type, METH_ATTR);
+ ((flags & 0x0008) != 0 ? statics : locals).enterOrOverload(s);
+ }
+ }
+}
diff --git a/sources/scalac/symtab/classfile/ConstantPool.java b/sources/scalac/symtab/classfile/ConstantPool.java
new file mode 100644
index 0000000000..4260b9e6ad
--- /dev/null
+++ b/sources/scalac/symtab/classfile/ConstantPool.java
@@ -0,0 +1,183 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.*;
+import scalac.symtab.*;
+import scalac.util.*;
+
+public class ConstantPool implements ClassfileConstants {
+
+ AbstractFileReader in;
+ Signatures sigparser;
+
+ /** the objects of the constant pool
+ */
+ protected Object[] poolObj;
+
+ /** for every constant pool entry, an index into in.buf where the
+ * defining section of the entry is found
+ */
+ protected int[] poolIdx;
+
+ /** constructor
+ */
+ protected ConstantPool(AbstractFileReader in, Signatures sigparser) {
+ this.in = in;
+ this.sigparser = sigparser;
+ }
+
+ /** index all constant pool entries, writing their start
+ * addresses into poolIdx
+ */
+ public void indexPool() {
+ poolIdx = new int[in.nextChar()];
+ poolObj = new Object[poolIdx.length];
+ int i = 1;
+ while (i < poolIdx.length) {
+ poolIdx[i++] = in.bp;
+ byte tag = in.nextByte();
+ switch (tag) {
+ case CONSTANT_UTF8:
+ case CONSTANT_UNICODE: {
+ int len = in.nextChar();
+ in.skip(len);
+ break;
+ }
+ case CONSTANT_CLASS:
+ case CONSTANT_STRING:
+ in.skip(2);
+ break;
+ case CONSTANT_FIELDREF:
+ case CONSTANT_METHODREF:
+ case CONSTANT_INTFMETHODREF:
+ case CONSTANT_NAMEANDTYPE:
+ case CONSTANT_INTEGER:
+ case CONSTANT_FLOAT:
+ in.skip(4);
+ break;
+ case CONSTANT_LONG:
+ case CONSTANT_DOUBLE:
+ in.skip(8);
+ i++;
+ break;
+ default:
+ throw new RuntimeException("bad constant pool tag: " + tag +
+ " at " + (in.bp - 1));
+ }
+ }
+ }
+
+ /** if name is an array type or class signature, return the
+ * corresponding type; otherwise return a class definition with given name
+ */
+ protected Object classOrType(Name name) {
+ if ((name.sub(0) == '[') || (name.sub(name.length() - 1) == ';')) {
+ byte[] ascii = name.toAscii();
+ return sigparser.sigToType(ascii, 0, ascii.length);
+ } else
+ return name;
+ }
+
+ /** read constant pool entry at start address i, use poolObj as a cache.
+ */
+ public Object readPool(int i) {
+ if (poolObj[i] != null)
+ return poolObj[i];
+ int index = poolIdx[i];
+ if (index == 0)
+ return null;
+ switch (in.byteAt(index)) {
+ case CONSTANT_UTF8:
+ poolObj[i] = Name.fromAscii(in.buf, index + 3, in.getChar(index + 1));
+ break;
+
+ case CONSTANT_UNICODE:
+ throw new RuntimeException("can't read unicode strings in classfiles");
+
+ case CONSTANT_CLASS:
+ poolObj[i] = classOrType(readExternal(in.getChar(index + 1)));
+ break;
+
+ case CONSTANT_FIELDREF: {
+ //Symbol owner = (Symbol)readPool(in.getChar(index + 1));
+ //NameAndType nt = (NameAndType)readPool(in.getChar(index + 3));
+ //poolObj[i] = new TermSymbol(Kinds.VAR, Position.NOPOS, nt.name, owner, 0)
+ // .type(sigparser.sigToType(Name.names, nt.sig.index, nt.sig.length()));
+ throw new RuntimeException("can't read constant_fieldrefs in classfiles");
+ }
+
+ case CONSTANT_METHODREF:
+ case CONSTANT_INTFMETHODREF: {
+ //Symbol owner = (Symbol)readPool(in.getChar(index + 1));
+ //NameAndType nt = (NameAndType)readPool(in.getChar(index + 3));
+ //poolObj[i] = new TermSymbol(Kinds.FUN, Position.NOPOS, nt.name, owner, 0)
+ // .type(sigparser.sigToType(Name.names, nt.sig.index, nt.sig.length()));
+ throw new RuntimeException("can't read constant_methodrefs in classfiles");
+ }
+
+ case CONSTANT_NAMEANDTYPE:
+ poolObj[i] = new NameAndType((Name)readPool(in.getChar(index + 1)),
+ readExternal(in.getChar(index + 3)));
+ break;
+
+ case CONSTANT_STRING:
+ case CONSTANT_INTEGER:
+ case CONSTANT_FLOAT:
+ case CONSTANT_LONG:
+ case CONSTANT_DOUBLE:
+ throw new RuntimeException("can't read constants in classfiles");
+
+ default:
+ throw new RuntimeException("bad constant pool tag: " + in.byteAt(index));
+ }
+ return poolObj[i];
+ }
+
+ /** return internal representation of buf[offset..offset+len-1],
+ * converting '/' to '.'
+ */
+ public byte[] internalize(byte[] buf, int offset, int len) {
+ byte[] translated = new byte[len];
+ for (int j = 0; j < len; j++) {
+ byte b = buf[offset + j];
+ if (b == '/')
+ translated[j] = '.';
+ else
+ translated[j] = b;
+ }
+ return translated;
+ }
+
+ /** read a constant pool string and convert to internal representation.
+ */
+ public Name readExternal(int i) {
+ if (poolObj[i] == null) {
+ int index = poolIdx[i];
+ if (in.byteAt(index) == CONSTANT_UTF8) {
+ int len = in.getChar(index + 1);
+ byte[] translated = internalize(in.buf, index + 3, len);
+ poolObj[i] = Name.fromAscii(translated, 0, len);
+ }
+ }
+ return (Name)poolObj[i];
+ }
+
+ /** the name and type signature of a method or field
+ */
+ public static final class NameAndType {
+ public Name name;
+ public Name sig;
+
+ public NameAndType(Name name, Name sig) {
+ this.name = name;
+ this.sig = sig;
+ }
+ }
+}
diff --git a/sources/scalac/symtab/classfile/JavaTypeCreator.java b/sources/scalac/symtab/classfile/JavaTypeCreator.java
new file mode 100644
index 0000000000..5bdc9402ba
--- /dev/null
+++ b/sources/scalac/symtab/classfile/JavaTypeCreator.java
@@ -0,0 +1,82 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.Global;
+import scalac.util.*;
+import scalac.symtab.*;
+import Type.*;
+
+
+public class JavaTypeCreator implements JavaTypeFactory {
+
+ protected Global global;
+
+ public JavaTypeCreator(Global global) {
+ this.global = global;
+ }
+
+ public Type byteType() {
+ return global.definitions.BYTE_TYPE;
+ }
+
+ public Type shortType() {
+ return global.definitions.SHORT_TYPE;
+ }
+
+ public Type charType() {
+ return global.definitions.CHAR_TYPE;
+ }
+
+ public Type intType() {
+ return global.definitions.INT_TYPE;
+ }
+
+ public Type longType() {
+ return global.definitions.LONG_TYPE;
+ }
+
+ public Type floatType() {
+ return global.definitions.FLOAT_TYPE;
+ }
+
+ public Type doubleType() {
+ return global.definitions.DOUBLE_TYPE;
+ }
+
+ public Type booleanType() {
+ return global.definitions.BOOLEAN_TYPE;
+ }
+
+ public Type voidType() {
+ return global.definitions.UNIT_TYPE;
+ }
+
+ public Type classType(Name classname) {
+ return global.definitions.getJavaType(classname);
+ }
+
+ public Type arrayType(Type elemtpe) {
+ return global.definitions.arrayType(elemtpe);
+ }
+
+ public Type methodType(Type[] argtpes, Type restpe, Type[] thrown) {
+ Symbol[] args = new Symbol[argtpes.length];
+ for (int i = 0; i < args.length; i++) {
+ args[i] = new TermSymbol(
+ Position.NOPOS, Name.fromString("x" + i), Symbol.NONE, Modifiers.PARAM);
+ args[i].setInfo(argtpes[i]);
+ }
+ return new MethodType(args, restpe);
+ }
+
+ public Type packageType(Name packagename) {
+ return null;
+ }
+}
diff --git a/sources/scalac/symtab/classfile/JavaTypeFactory.java b/sources/scalac/symtab/classfile/JavaTypeFactory.java
new file mode 100644
index 0000000000..8205055bc9
--- /dev/null
+++ b/sources/scalac/symtab/classfile/JavaTypeFactory.java
@@ -0,0 +1,28 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.symtab.Type;
+import scalac.util.Name;
+
+public interface JavaTypeFactory {
+ Type byteType();
+ Type shortType();
+ Type charType();
+ Type intType();
+ Type longType();
+ Type floatType();
+ Type doubleType();
+ Type booleanType();
+ Type voidType();
+ Type classType(Name classname);
+ Type arrayType(Type elemtpe);
+ Type methodType(Type[] argtpes, Type restpe, Type[] thrown);
+ Type packageType(Name packagename);
+}
diff --git a/sources/scalac/symtab/classfile/PackageParser.java b/sources/scalac/symtab/classfile/PackageParser.java
new file mode 100644
index 0000000000..50fcb46b00
--- /dev/null
+++ b/sources/scalac/symtab/classfile/PackageParser.java
@@ -0,0 +1,129 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.*;
+import scalac.symtab.*;
+import scalac.util.*;
+import java.io.*;
+
+public class PackageParser extends Type.LazyType {
+
+ /** the global compilation environment
+ */
+ protected Global global;
+
+ /** the class parser
+ */
+ public ClassParser classCompletion;
+
+ public PackageParser(Global global) {
+ this.global = global;
+ this.classCompletion = new ClassParser(global);
+ }
+
+ /** complete package type symbol p by loading all package members
+ */
+ public void complete(Symbol p) {
+ long msec = System.currentTimeMillis();
+ Scope members = new Scope();
+ String dirname = null;
+ Name name = p.fullName();
+ if (name.length() == 0) {
+ // includeMembers(AbstractFile.open(null, "."), p, members, false);
+ } else {
+ dirname = externalizeFileName(name);
+ assert !dirname.startsWith("com") : p;//debug
+ if (!dirname.endsWith("/"))
+ dirname += "/";
+ }
+ String[] base = global.classPath.components();
+ for (int i = 0; i < base.length; i++) {
+ includeMembers(
+ AbstractFile.open(base[i], dirname), p, members, dirname != null);
+ }
+ p.setInfo(Type.compoundType(Type.EMPTY_ARRAY, members, p));
+ if (dirname == null)
+ dirname = "anonymous package";
+ global.operation("scanned " + dirname + " in " +
+ (System.currentTimeMillis() - msec) + "ms");
+ }
+
+ /** read directory of a classpath directory and include members
+ * in package/module scope
+ */
+ protected void includeMembers(AbstractFile dir, Symbol p, Scope locals,
+ boolean inclClasses) {
+ if (dir == null)
+ return;
+ String[] filenames = null;
+ try {
+ if ((filenames = dir.list()) == null)
+ return;
+ for (int j = 0; j < filenames.length; j++) {
+ String fname = filenames[j];
+ if (inclClasses && fname.endsWith(".class")) {
+ Name n = Name.fromString(fname.substring(0, fname.length() - 6))
+ .toTypeName();
+ ClassSymbol clazz = new ClassSymbol(n, p, classCompletion);
+ clazz.constructor().setInfo(
+ classCompletion.staticsParser(clazz));
+ // enter class
+ locals.enter(clazz);
+ locals.enter(clazz.constructor());
+ // enter module, except for scala.Object class
+ // todo: why not there also?.
+ if (!(n == Names.Object.toTypeName() &&
+ p.fullName().toTermName() == Names.scala)) {
+ Scope.Entry e = locals.lookupEntry(clazz.module().name);
+ if (e != Scope.Entry.NONE) {
+ // we already have a package of the same name; delete it
+ locals.unlink(e);
+ }
+ locals.enter(clazz.module());
+ }
+ } else if (fname.endsWith("/") && !fname.equals("META-INF/")) {
+ Name n = Name.fromString(fname.substring(0, fname.length() - 1));
+ if (locals.lookup(n) == Symbol.NONE) {
+ TermSymbol module = TermSymbol.newJavaPackageModule(n, p, this);
+ locals.enter(module);
+ }
+ } else if (fname.endsWith(".scala")) {
+ Name n = Name.fromString(fname.substring(0, fname.length() - 6))
+ .toTypeName();
+ if (locals.lookup(n) == Symbol.NONE) {
+ SourceCompleter completer = new SourceCompleter(global,
+ dir.getPath() + File.separatorChar + fname);
+ ClassSymbol clazz = new ClassSymbol(n, p, completer);
+ clazz.constructor().setInfo(completer);
+ clazz.module().setInfo(completer);
+ // enter class
+ locals.enter(clazz);
+ locals.enter(clazz.constructor());
+ locals.enter(clazz.module());
+ }
+ }
+ }
+ } catch (IOException e) {
+ }
+ }
+
+ /** return external representation of file name s,
+ * converting '.' to File.separatorChar
+ */
+
+ public String externalizeFileName(Name n) {
+ if ((n == null) || (n.length() == 0))
+ return ".";
+ byte[] ascii = n.toAscii();
+ String s = SourceRepresentation.ascii2string(
+ ascii, 0, ascii.length);
+ return s.replace('.', File.separatorChar);
+ }
+}
diff --git a/sources/scalac/symtab/classfile/Signatures.java b/sources/scalac/symtab/classfile/Signatures.java
new file mode 100644
index 0000000000..9676882aed
--- /dev/null
+++ b/sources/scalac/symtab/classfile/Signatures.java
@@ -0,0 +1,122 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.symtab.classfile;
+
+import scalac.*;
+import scalac.symtab.*;
+import scalac.util.*;
+import java.util.*;
+import Type.*;
+
+public class Signatures {
+
+ /** signature constants
+ */
+ Name BYTE_SIG = Name.fromString("B");
+ Name SHORT_SIG = Name.fromString("S");
+ Name CHAR_SIG = Name.fromString("C");
+ Name INT_SIG = Name.fromString("I");
+ Name LONG_SIG = Name.fromString("J");
+ Name FLOAT_SIG = Name.fromString("F");
+ Name DOUBLE_SIG = Name.fromString("D");
+ Name BOOLEAN_SIG = Name.fromString("Z");
+ Name VOID_SIG = Name.fromString("V");
+ Name CLASS_SIG = Name.fromString("L");
+ Name ARRAY_SIG = Name.fromString("[");
+ Name ARGBEGIN_SIG = Name.fromString("(");
+ Name ARGEND_SIG = Name.fromString(")");
+
+ Global global;
+ JavaTypeFactory make;
+
+
+ public Signatures(Global global, JavaTypeFactory make) {
+ this.make = make;
+ this.global = global;
+ }
+
+ /** the type represented by signature[offset..].
+ */
+ protected byte[] signature;
+ protected int sigp;
+ protected int limit;
+
+ public Type sigToType(byte[] sig, int offset, int len) {
+ signature = sig;
+ sigp = offset;
+ limit = offset + len;
+ return sigToType();
+ }
+
+ protected Type sigToType() {
+ switch (signature[sigp]) {
+ case 'B':
+ sigp++;
+ return make.byteType();
+ case 'C':
+ sigp++;
+ return make.charType();
+ case 'D':
+ sigp++;
+ return make.doubleType();
+ case 'F':
+ sigp++;
+ return make.floatType();
+ case 'I':
+ sigp++;
+ return make.intType();
+ case 'J':
+ sigp++;
+ return make.longType();
+ case 'L':
+ sigp++;
+ int start = sigp;
+ while (signature[sigp] != ';')
+ sigp++;
+ return make.classType(Name.fromAscii(signature, start, (sigp++) - start));
+ case 'S':
+ sigp++;
+ return make.shortType();
+ case 'V':
+ sigp++;
+ return make.voidType();
+ case 'Z':
+ sigp++;
+ return make.booleanType();
+ case '[':
+ sigp++;
+ while (('0' <= signature[sigp]) && (signature[sigp] <= '9'))
+ sigp++;
+ return make.arrayType(sigToType());
+ case '(':
+ return make.methodType(sigToTypes(')'), sigToType(), Type.EMPTY_ARRAY);
+ default:
+ global.error("bad signature: " +
+ SourceRepresentation.ascii2string(signature, sigp, 1));
+ return Type.ErrorType;
+ }
+ }
+
+ protected Type[] sigToTypes(char terminator) {
+ sigp++;
+ return sigToTypes(terminator, 0);
+ }
+
+ protected Type[] sigToTypes(char terminator, int i) {
+ if (signature[sigp] == terminator) {
+ sigp++;
+ return new Type[i];
+ } else {
+ Type t = sigToType();
+ Type[] vec = sigToTypes(terminator, i+1);
+ vec[i] = t;
+ return vec;
+ }
+ }
+}