diff options
-rw-r--r-- | sources/scalac/symtab/classfile/CLRClassParser.java | 309 | ||||
-rw-r--r-- | sources/scalac/symtab/classfile/CLRPackageParser.java | 275 |
2 files changed, 584 insertions, 0 deletions
diff --git a/sources/scalac/symtab/classfile/CLRClassParser.java b/sources/scalac/symtab/classfile/CLRClassParser.java new file mode 100644 index 0000000000..8f6e792428 --- /dev/null +++ b/sources/scalac/symtab/classfile/CLRClassParser.java @@ -0,0 +1,309 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2003, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scalac.symtab.classfile; + +import scalac.Global; +import scalac.symtab.Symbol; +import scalac.symtab.TermSymbol; +import scalac.symtab.ClassSymbol; +import scalac.symtab.Scope; +import scalac.symtab.Modifiers; +import scalac.util.Name; +import scalac.util.Names; +import scalac.util.Debug; + +import ch.epfl.lamp.util.Position; +import ch.epfl.lamp.compiler.msil.*; + +public class CLRClassParser extends ClassParser { + + protected JavaTypeFactory make; + + protected final CLRPackageParser importer; + + public CLRClassParser(Global global, CLRPackageParser importer) { + super(global); + this.importer = importer; + } + + protected void doComplete(Symbol clazz) { + try { doComplete0(clazz); } + catch (AssertionError e) { + System.err.println("While processing " + Debug.show(clazz)); + throw e; + } + } + + protected void doComplete0(Symbol clazz) { + clazz.owner().initialize(); //??? + + if (make == null) + make = new JavaTypeCreator(global.definitions); + + Type type = Type.GetType(clazz.fullNameString()); +// System.out.println("completing class " + clazz.fullNameString() +// + " from type " + type); + clazz.flags = translateAttributes(type); + Type[] ifaces = type.GetInterfaces(); // FIXME: ensure only the declared interfaces are taken into account + scalac.symtab.Type[] baseTypes = new scalac.symtab.Type[ifaces.length+1]; + baseTypes[0] = type.BaseType == null ? global.definitions.ANYREF_TYPE() + : getCLRType(type.BaseType); + for (int i = 0; i < ifaces.length; i++) + baseTypes[i + 1] = getCLRType(ifaces[i]); + Scope members = new Scope(); + Scope statics = new Scope(); + scalac.symtab.Type classType = + scalac.symtab.Type.compoundType(baseTypes, members, clazz); + clazz.setFirstInfo(classType); + Symbol staticsClass = clazz.module().moduleClass(); + if (staticsClass.isModuleClass()) { + scalac.symtab.Type staticsInfo = scalac.symtab.Type.compoundType + (scalac.symtab.Type.EMPTY_ARRAY, statics, staticsClass); + staticsClass.setFirstInfo(staticsInfo); + clazz.module().setInfo(scalac.symtab.Type.TypeRef + (staticsClass.owner().thisType(), + staticsClass, scalac.symtab.Type.EMPTY_ARRAY)); + } + scalac.symtab.Type ctype = clazz.typeConstructor(); + // read field information + int bindingFlags = BindingFlags.DeclaredOnly + | BindingFlags.Instance | BindingFlags.Static + | BindingFlags.Public | BindingFlags.NonPublic; + FieldInfo[] fields = type.GetFields(bindingFlags); + for (int i = 0; i < fields.length; i++) { + int mods = translateAttributes(fields[i]); + Name name = Name.fromString(fields[i].Name); + scalac.symtab.Type fieldType = getCLRType(fields[i].FieldType); + Symbol owner = fields[i].IsStatic ? staticsClass : clazz; + Symbol field = new TermSymbol(Position.NOPOS, name, owner, mods); + field.setFirstInfo(fieldType); + (fields[i].IsStatic ? statics : members).enterOrOverload(field); + importer.map(field, fields[i]); + } + + PropertyInfo[] props = type.GetProperties(bindingFlags); + for (int i = 0; i < props.length; i++) { + MethodInfo getter = props[i].GetGetMethod(true); + MethodInfo setter = props[i].GetSetMethod(true); + if (getter == null || getter.GetParameters().length > 0) + continue; + assert props[i].PropertyType == getter.ReturnType; + scalac.symtab.Type proptype = getCLSType(props[i].PropertyType); + if (proptype == null) + continue; +// if (type.FullName.equals("System.Collections.ArrayList")) +// System.out.println("getter found: " + getter); + Name n = Name.fromString(props[i].Name); + scalac.symtab.Type mtype = + scalac.symtab.Type.PolyType(Symbol.EMPTY_ARRAY, proptype); + int mods = translateAttributes(getter); + Symbol owner = getter.IsStatic ? staticsClass : clazz; + Symbol method = new TermSymbol(Position.NOPOS, n, owner, mods); + setParamOwners(mtype, method); + method.setFirstInfo(mtype); + (getter.IsStatic ? statics : members).enterOrOverload(method); + importer.map(method, getter); + + if (setter == null) + continue; + assert getter.IsStatic == setter.IsStatic; + assert setter.ReturnType == importer.VOID; + mtype = methodType(setter, getCLSType(importer.VOID)); + if (mtype == null) + continue; + n = n.append(Names._EQ); + mods = translateAttributes(setter); + method = new TermSymbol(Position.NOPOS, n, owner, mods); + setParamOwners(mtype, method); + method.setFirstInfo(mtype); + (setter.IsStatic ? statics : members).enterOrOverload(method); + importer.map(method, setter); + } + + MethodInfo[] methods = type.GetMethods(bindingFlags); + for (int i = 0; i < methods.length; i++) { + if (importer.getSymbol(methods[i]) != null) + continue; + scalac.symtab.Type rettype = getCLSType(methods[i].ReturnType); + if (rettype == null) + continue; + scalac.symtab.Type mtype = methodType(methods[i], rettype); + if (mtype == null) + continue; + String name = methods[i].Name; + Name n; + if (name.equals("GetHashCode")) n = Names.hashCode; + else if (name.equals("Equals")) n = Names.equals; + else if (name.equals("ToString")) n = Names.toString; + else n = Name.fromString(name); + int mods = translateAttributes(methods[i]); + Symbol owner = methods[i].IsStatic ? staticsClass : clazz; + Symbol method = new TermSymbol(Position.NOPOS, n, owner, mods); + setParamOwners(mtype, method); + method.setFirstInfo(mtype); + (methods[i].IsStatic ? statics : members).enterOrOverload(method); + importer.map(method, methods[i]); + } + + ConstructorInfo[] constrs = type.GetConstructors(bindingFlags); + for (int i = 0; i < constrs.length; i++) { + if (constrs[i].IsStatic || constrs[i].IsPrivate + || constrs[i].IsAssembly || constrs[i].IsFamilyAndAssembly) + continue; + scalac.symtab.Type mtype = methodType(constrs[i], ctype); + if (mtype == null) + continue; + Symbol constr = clazz.primaryConstructor(); + if (constr.isInitialized()) constr = clazz.addConstructor(); + int mods = translateAttributes(methods[i]); + TermSymbol.newConstructor(clazz, mods).copyTo(constr); + setParamOwners(mtype, constr); + constr.setFirstInfo(mtype); +// System.out.println(clazz.allConstructors() + ": " +// + clazz.allConstructors().info()); + importer.map(constr, constrs[i]); + } + + Symbol constr = clazz.primaryConstructor(); + if (!constr.isInitialized()) { + constr.setFirstInfo(scalac.symtab.Type.MethodType + (Symbol.EMPTY_ARRAY, ctype)); + if ((clazz.flags & Modifiers.INTERFACE) == 0) + constr.flags |= Modifiers.PRIVATE; + } + + // import nested types + Type[] nestedTypes = type.GetNestedTypes(); + for (int i = 0; i < nestedTypes.length; i++) { + Name n = Name.fromString(nestedTypes[i].Name).toTypeName(); + ClassSymbol nclazz = new ClassSymbol(n, clazz, this); + nclazz.allConstructors().setInfo(staticsParser(nclazz)); + nclazz.module().setInfo(staticsParser(nclazz)); + members.enter(nclazz); + Scope.Entry e = members.lookupEntry(clazz.module().name); + if (e != Scope.Entry.NONE) + members.unlink(e); + members.enter(nclazz.module()); + } + } + + /** Return a method type for */ + protected scalac.symtab.Type methodType(MethodBase method, + scalac.symtab.Type rettype) { + ParameterInfo[] params = method.GetParameters(); + scalac.symtab.Type[] ptypes = new scalac.symtab.Type[params.length]; + for (int j = 0; j < params.length; j++) { + ptypes[j] = getCLSType(params[j].ParameterType); + if (ptypes[j] == null) + return null; + } + return make.methodType(ptypes, rettype, scalac.symtab.Type.EMPTY_ARRAY); + } + + protected void setParamOwners(scalac.symtab.Type type, Symbol owner) { + switch (type) { + case PolyType(Symbol[] params, scalac.symtab.Type restype): + for (int i = 0; i < params.length; i++) params[i].setOwner(owner); + setParamOwners(restype, owner); + return; + case MethodType(Symbol[] params, scalac.symtab.Type restype): + for (int i = 0; i < params.length; i++) params[i].setOwner(owner); + setParamOwners(restype, owner); + return; + } + } + + protected scalac.symtab.Type getClassType(Type type) { + assert type != null; + scalac.symtab.Type res = make.classType(Name.fromString(type.FullName)); + if (res == scalac.symtab.Type.ErrorType) + global.error("unknown class reference " + type.FullName); + return res; + } + + protected scalac.symtab.Type getCLSType(Type type) { + if (type == importer.BYTE || type == importer.USHORT + || type == importer.UINT || type == importer.ULONG + || type.IsPointer + || (type.IsArray && getCLSType(type.GetElementType()) == null)) + return null; + return getCLRType(type); + } + + protected scalac.symtab.Type getCLRType(Type type) { + if (type == importer.OBJECT) + return global.definitions.JAVA_OBJECT_TYPE(); + if (type == importer.STRING) + return global.definitions.JAVA_STRING_TYPE(); + if (type == importer.VOID) + return make.voidType(); + if (type == importer.BOOLEAN) + return make.booleanType(); + if (type == importer.CHAR) + return make.charType(); + if (type == importer.BYTE || type == importer.UBYTE) + return make.byteType(); + if (type == importer.SHORT || type == importer.USHORT) + return make.shortType(); + if (type == importer.INT || type == importer.UINT) + return make.intType(); + if (type == importer.LONG || type == importer.ULONG) + return make.longType(); + if (type == importer.FLOAT) + return make.floatType(); + if (type == importer.DOUBLE) + return make.doubleType(); + if (type.IsArray) + return make.arrayType(getCLRType(type.GetElementType())); + return getClassType(type); + } + + protected static int translateAttributes(Type type) { + int mods = 0; + if (type.IsNotPublic || type.IsNestedPrivate + || type.IsNestedAssembly || type.IsNestedFamANDAssem) + mods |= Modifiers.PRIVATE; + else if (type.IsNestedFamily || type.IsNestedFamORAssem) + mods |= Modifiers.PROTECTED; + if (type.IsAbstract) + mods |= Modifiers.ABSTRACT; + if (type.IsSealed) + mods |= Modifiers.FINAL; + if (type.IsInterface) + mods |= Modifiers.INTERFACE | Modifiers.TRAIT | Modifiers.ABSTRACT; + + return mods | Modifiers.JAVA; + } + + protected static int translateAttributes(FieldInfo field) { + int mods = 0; + if (field.IsPrivate || field.IsAssembly || field.IsFamilyAndAssembly) + mods |= Modifiers.PRIVATE; + else if (field.IsFamily || field.IsFamilyOrAssembly) + mods |= Modifiers.PROTECTED; + if (field.IsInitOnly) + mods |= Modifiers.FINAL; + else + mods |= Modifiers.MUTABLE; + + return mods | Modifiers.JAVA; + } + + protected static int translateAttributes(MethodInfo method) { + int mods = 0; + if (method.IsPrivate || method.IsAssembly || method.IsFamilyAndAssembly) + mods |= Modifiers.PRIVATE; + else if (method.IsFamily || method.IsFamilyOrAssembly) + mods |= Modifiers.PROTECTED; + if (method.IsAbstract) + mods |= Modifiers.DEFERRED; + + return mods | Modifiers.JAVA; + } +} diff --git a/sources/scalac/symtab/classfile/CLRPackageParser.java b/sources/scalac/symtab/classfile/CLRPackageParser.java new file mode 100644 index 0000000000..bf2e6971e2 --- /dev/null +++ b/sources/scalac/symtab/classfile/CLRPackageParser.java @@ -0,0 +1,275 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scalac.symtab.classfile; + +import java.util.List; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.HashMap; + +import java.io.File; + +import ch.epfl.lamp.compiler.msil.*; +import scalac.symtab.Symbol; +import scalac.symtab.TermSymbol; +import scalac.symtab.ClassSymbol; +import scalac.symtab.Scope; +import scalac.util.Debug; +import scalac.util.Name; +import scalac.Global; + +/** + */ +public class CLRPackageParser extends MetadataParser { + + //########################################################################## + + Type BYTE; + Type UBYTE; + Type CHAR; + Type SHORT; + Type USHORT; + Type INT; + Type UINT; + Type LONG; + Type ULONG; + Type FLOAT; + Type DOUBLE; + Type BOOLEAN; + Type VOID; + + Type OBJECT; + Type STRING; + Type STRING_ARRAY; + + protected CLRClassParser completer; + + private CLRPackageParser(Global global) { + super(global); + } + + public static CLRPackageParser instance; + public static CLRPackageParser create(Global global) { + if (instance != null) + return instance; + instance = new CLRPackageParser(global); + instance.completer = new CLRClassParser(global, instance); + instance.init(); + return instance; + } + + Type[] types; + + public Type[] getTypes() { return types; } + + private boolean initialized = false; + public void init() { + if (initialized) return; + String[] asnames = scalac.util.ClassPath.parse(global.args.assemrefs.value); + for (int i = 0; i < asnames.length; i++) + assemrefs.add(asnames[i]); + Assembly mscorlib = findAssembly("mscorlib.dll"); + Type.initMSCORLIB(mscorlib); + + BYTE = Type.GetType("System.SByte"); + UBYTE = Type.GetType("System.Byte"); + CHAR = Type.GetType("System.Char"); + SHORT = Type.GetType("System.Int16"); + USHORT = Type.GetType("System.UInt16"); + INT = Type.GetType("System.Int32"); + UINT = Type.GetType("System.UInt32"); + LONG = Type.GetType("System.Int64"); + ULONG = Type.GetType("System.UInt64"); + FLOAT = Type.GetType("System.Single"); + DOUBLE = Type.GetType("System.Double"); + BOOLEAN = Type.GetType("System.Boolean"); + VOID = Type.GetType("System.Void"); + + OBJECT = Type.GetType("System.Object"); + STRING = Type.GetType("System.String"); + STRING_ARRAY = Type.GetType("System.String[]"); + + findAssembly("vjslib.dll"); + findAssembly("scala.dll"); + findAssembly("scala_sc.dll"); + findAllAssemblies(); + + 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++) + if (/*atypes[i].IsPublic && */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; + } + this.types = types; + +// for (int i = 0; i < types.length; i++) +// System.out.println(types[i]); + + initialized = true; + } + + + java.util.Map syms2members = new HashMap(); + java.util.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) { + return Type.GetType(name); + } + + public Type mkArrayType(Type elemType) { + return getType(elemType.FullName + "[]"); + } + + //########################################################################## + // assembly loading methods + + protected final java.util.List assemblies = new LinkedList(); + + protected final java.util.List assemrefs = new LinkedList(); + + /** Load the assembly with the given name + */ + Assembly findAssembly(String name) { + // see if the assembly is referenced directly + for (Iterator assems = assemrefs.iterator(); assems.hasNext();) { + String assemname = (String)assems.next(); + File f = new File(assemname); + if (!f.getName().equals(name)) + continue; + Assembly assem = Assembly.LoadFrom(f.getPath()); + if (assem != null) { + assems.remove(); + assemblies.add(assem); + return assem; + } + } + for (Iterator assems = assemrefs.iterator(); assems.hasNext();) { + File d = new File((String)assems.next()); + if (!d.isDirectory()) + continue; + File f = new File(d, name); + if (f.exists()) { + Assembly assem = Assembly.LoadFrom(f.getPath()); + if (assem != null) { + assemblies.add(assem); + return assem; + } + } + } + global.fail("Cannot find assembly " + name + + "; use the -r option to specify its location"); + return null; + } + + /** Load the rest of the assemblies specified with the '-r' option + */ + void findAllAssemblies() { + //System.out.println("assembly references left: " + assemrefs); + for (Iterator assems = assemrefs.iterator(); assems.hasNext();) { + File f = new File((String)assems.next()); + if (f.isFile()) { + Assembly assem = Assembly.LoadFrom(f.getPath()); + if (assem != null) { + assemblies.add(assem); + //System.out.println("Loaded assembly " + assem); + } + } + assems.remove(); + } + assert assemrefs.isEmpty(); + } + + //########################################################################## + // main functionality + + protected void doComplete(Symbol p) { + // for future use + } + + /** + */ + public void importCLRTypes(Symbol p, Scope members, PackageParser pp) { + if (p.fullNameString().startsWith("scala") + || p.fullNameString().startsWith("java")) + return; + if (p.isRoot()) { + for (int i = 0; i < types.length; i++) { + int j = types[i].FullName.indexOf('.'); + if (j < 0) continue; + String namespace = types[i].FullName.substring(0, j); + importCLRNamespace(namespace, p, members, pp); + } + return; + } + String n1 = p.fullNameString() + "."; + for (int i = 0; i < types.length; i++) { + String fullname = types[i].FullName; + if (!fullname.startsWith(n1)) + continue; + //System.out.println("importing type: " + fullname); + int j = n1.length(); + int k = fullname.indexOf('.', j); + String name = fullname.substring(j, k < 0 ? fullname.length() : k); + Name n = Name.fromString(name); + if (k < 0) { + // it's a class + ClassSymbol clazz = new ClassSymbol(n.toTypeName(), p, completer); + clazz.allConstructors().setInfo(completer.staticsParser(clazz)); + clazz.module().setInfo(completer.staticsParser(clazz)); + members.enter(clazz); + // ATTENTION: only if not scala.Object! + Scope.Entry e = members.lookupEntry(clazz.module().name); + if (e != Scope.Entry.NONE) + members.unlink(e); + members.enter(clazz.module()); + } else { + importCLRNamespace(name, p, members, pp); + } + } + } + + /** Imports a CLR namespace as a scala package. + */ + protected void importCLRNamespace(String namespace, Symbol p, + Scope members, PackageParser pp) + { + Name n = Name.fromString(namespace); + if (members.lookup(n) == Symbol.NONE) { + //System.out.println("importing namespace " + namespace); + TermSymbol module = TermSymbol.newJavaPackageModule(n, p, pp); + members.enter(module); + members.enter(module.moduleClass()); + } + } + + //########################################################################## +} |