/* ____ ____ ____ ____ ______ *\
** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
** /_____/\____/\___/\____/____/ **
\* */
// $Id$
package scalac.symtab.classfile;
import java.util.List;
import java.util.LinkedList;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.LinkedHashSet;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Comparator;
import java.io.File;
import scalac.Global;
import scalac.CompilerCommand;
import scalac.util.Debug;
import scalac.util.Name;
import scalac.symtab.Symbol;
import scalac.symtab.SymbolNameWriter;
import ch.epfl.lamp.compiler.msil.*;
/**
* Collects all types from all reference assemblies.
*/
public final class CLRTypes {
//##########################################################################
private static CLRTypes instance;
/** Return the unique instance of the CLRTypes class */
public static CLRTypes instance() {
assert instance != null;
return instance;
}
/** Initialize the CLRTypes */
public static void init(CompilerCommand args) {
instance = new CLRTypes(args);
}
//##########################################################################
public final Type BYTE;
public final Type UBYTE;
public final Type CHAR;
public final Type SHORT;
public final Type USHORT;
public final Type INT;
public final Type UINT;
public final Type LONG;
public final Type ULONG;
public final Type FLOAT;
public final Type DOUBLE;
public final Type BOOLEAN;
public final Type VOID;
public final Type ENUM;
public final Type DELEGATE;
public final Type OBJECT;
public final Type STRING;
public final Type STRING_ARRAY;
public final MethodInfo MEMBERWISE_CLONE;
public final Type PICO_META_ATTR;
public final Type SCALA_SYMTAB_ATTR;
public final ConstructorInfo SYMTAB_CONSTR;
public final ConstructorInfo SYMTAB_DEFAULT_CONSTR;
public final MethodInfo DELEGATE_COMBINE;
public final MethodInfo DELEGATE_REMOVE;
private final SymbolNameWriter snw = new SymbolNameWriter();
private Type[] types;
private final CompilerCommand args;
private CLRTypes(CompilerCommand args) {
this.args = args;
scala.tools.util.ClassPath.addFilesInPath(
assemrefs, args.assemrefs.value);
Assembly mscorlib = findAssembly("mscorlib.dll", true);
Type.initMSCORLIB(mscorlib);
findAssembly("scala.dll", false);
findAllAssemblies();
if (getType("scala.Int") == null) {
abort("scala.dll");
}
BYTE = getType("System.SByte");
UBYTE = getType("System.Byte");
CHAR = getType("System.Char");
SHORT = getType("System.Int16");
USHORT = getType("System.UInt16");
INT = getType("System.Int32");
UINT = getType("System.UInt32");
LONG = getType("System.Int64");
ULONG = getType("System.UInt64");
FLOAT = getType("System.Single");
DOUBLE = getType("System.Double");
BOOLEAN = getType("System.Boolean");
VOID = getType("System.Void");
ENUM = getType("System.Enum");
DELEGATE = getType("System.MulticastDelegate");
OBJECT = getType("System.Object");
STRING = getType("System.String");
STRING_ARRAY = getType("System.String[]");
MEMBERWISE_CLONE = OBJECT.GetMethod("MemberwiseClone", Type.EmptyTypes);
PICO_META_ATTR = Type.GetType("scala.runtime.MetaAttribute");
SCALA_SYMTAB_ATTR = Type.GetType("scala.runtime.SymtabAttribute");
final Type[] bytearray = new Type[]{ Type.GetType("System.Byte[]") };
SYMTAB_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(bytearray);
SYMTAB_DEFAULT_CONSTR =
SCALA_SYMTAB_ATTR.GetConstructor(Type.EmptyTypes);
Type delegate = Type.GetType("System.Delegate");
Type[] dargs = new Type[]{delegate, delegate};
DELEGATE_COMBINE = delegate.GetMethod("Combine", dargs);
DELEGATE_REMOVE = delegate.GetMethod("Remove", dargs);
assert PICO_META_ATTR != null;
assert SCALA_SYMTAB_ATTR != null;
assert DELEGATE_COMBINE != null;
assert DELEGATE_REMOVE != null;
Type[] types = Type.EmptyTypes;
Iterator as = assemblies.iterator();
while (as.hasNext()) {
Type[] atypes = ((Assembly)as.next()).GetTypes();
int j = 0;
for (int i = 0; i < atypes.length; i++)
// skip nested types
if (atypes[i].DeclaringType == null)
atypes[j++] = atypes[i];
Type[] btypes = new Type[types.length + j];
System.arraycopy(types, 0, btypes, 0, types.length);
System.arraycopy(atypes, 0, btypes, types.length, j);
types = btypes;
}
Comparator typeNameComparator =
new Comparator() {
public int compare(Object o1, Object o2) {
Type t1 = (Type)o1;
Type t2 = (Type)o2;
return t1.FullName.compareTo(t2.FullName);
}
};
Arrays.sort(types, typeNameComparator);
this.types = types;
}
//##########################################################################
// type mapping and lookup
private final Map syms2members = new HashMap();
private final Map members2syms = new HashMap();
public void map(Symbol sym, MemberInfo m) {
syms2members.put(sym, m);
members2syms.put(m, sym);
}
public MemberInfo getMember(Symbol sym) {
return (MemberInfo)syms2members.get(sym);
}
public Symbol getSymbol(MemberInfo m) {
return (Symbol)members2syms.get(m);
}
public Type getType(String name) {
Type t = Type.GetType(name);
//assert t != null : name;
return t;
}
public Type mkArrayType(Type elemType) {
return getType(elemType.FullName + "[]");
}
// Returns true if the given type is a delegate type.
public boolean isDelegateType(Type t) {
return t.BaseType() == DELEGATE;
}
//##########################################################################
// assembly loading methods
// a list of all loaded assemblies
private final List assemblies = new LinkedList();
// a set of all directories and assembly files
private final Set/*<File>*/ assemrefs = new LinkedHashSet();
/** Load the assembly with the given name
*/
private Assembly findAssembly(String name, boolean required) {
// see if the assembly is referenced directly
for (Iterator assems = assemrefs.iterator(); assems.hasNext();) {
File file = (File)assems.next();
if (!file.getName().equals(name))
continue;
Assembly assem = Assembly.LoadFrom(file.getPath());
if (assem != null) {
assems.remove();
assemblies.add(assem);
return assem;
}
}
// look in directories specified with the '-r' option
for (Iterator assems = assemrefs.iterator(); assems.hasNext();) {
File d = (File)assems.next();
if (!d.isDirectory())
continue;
File file = new File(d, name);
if (file.exists()) {
Assembly assem = Assembly.LoadFrom(file.getPath());
if (assem != null) {
assemblies.add(assem);
return assem;
}
}
}
// try in the current directory
File file = new File(".", name);
if (file.exists()) {
Assembly assem = Assembly.LoadFrom(file.getPath());
if (assem != null) {
assemblies.add(assem);
return assem;
}
}
if (required)
abort(name);
return null;
}
/** Load the rest of the assemblies specified with the '-r' option
*/
private void findAllAssemblies() {
for (Iterator assems = assemrefs.iterator(); assems.hasNext();) {
File f = (File)assems.next();
if (f.isFile()) {
Assembly assem = Assembly.LoadFrom(f.getPath());
if (assem != null) {
assemblies.add(assem);
}
}
assems.remove();
}
assert assemrefs.isEmpty();
}
private void abort(String name) {
//the Global instance is not yet constructed; use the Reporter from args
args.reporter().error(null, "cannot find assembly " + name +
"; use the -r option to specify its location");
throw Debug.abort();
}
//##########################################################################
// collect the members contained in a given namespace
/** Find the position of the first type whose name starts with
* the given prefix; return the length of the types array if no match
* is found so the result can be used to terminate loop conditions
*/
private int findFirst(String prefix) {
int m = 0, n = types.length - 1;
while (m < n) {
int l = (m + n) / 2;
int res = types[l].FullName.compareTo(prefix);
if (res < 0) m = l + 1;
else n = l;
}
return types[m].FullName.startsWith(prefix) ? m : types.length;
}
/** Collects the members contained in the given Scala package (namespace)
*/
void collectMembers(Symbol pakage, Map/*<String,Type>*/ typesMap,
Set/*<String>*/ namespacesSet)
{
String namespace = pakage.isRoot() ? "" : snw.toString(pakage) + ".";
int nl = namespace.length();
for (int i = findFirst(namespace);
i < types.length && types[i].FullName.startsWith(namespace);
i++)
{
Type type = types[i];
if (type.FullName.equals("java.lang.Object")
|| type.FullName.equals("java.lang.String")) {
continue;
}
int k = type.FullName.indexOf(".", nl);
if (k < 0) {
typesMap.put(type.Name, type);
} else {
namespacesSet.add(type.Namespace.substring(nl, k));
}
}
}
/** Returns the namespace of the given package */
String getNameSpaceOf(Symbol pakage) {
assert pakage.hasPackageFlag() || pakage.isRoot(): Debug.show(pakage);
return pakage.isRoot() ? "" : snw.toString(pakage);
}
//##########################################################################
} // CLRTypes