summaryrefslogblamecommitdiff
path: root/sources/scalac/symtab/classfile/CLRClassParser.java
blob: 9de9d1762987b42842ee524c10e05111a45c940f (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11










                                                                          
                              
                            
                                  

                               
                            



                         
                                 

                                    
                                                  




                                              




                                                                     

                                                                       
 

                                                         
 


                                                    
                             



                                                                         

                                
                               


         
                                                




                                                           

                                                    
                                                                          

                                                
                                                
                                             






                                                                                 
                                      
                                                                       
                                 

                                                          



                                                                        
                                                            
                                                         













                                                                                 
                                                                       
                                                                                      

                                                               

                                                                               
                                       

         
                                              
                                                 


                                                               


                                                                           
                                                                       

                                                                           
                                                                       
                                                                      
                                     
                                                                              


                                           
                                                    








                                                                            



                                                                          
                                                                    
                                                                     
                                          
                                  
                                                                            



                                         
                                                          



                                                                  
                                                          
                                               
                                                              
                                          
                                  
                                                                            


                                         
                                                 
                                                  



                                                        













                                                                           
                                                                        
                                                                     
                                          
                                  
                                                                                


                                             


                                                                                







                                                                             

                                                              



                                                     








                                                                      

         
                                                           
                                                  

                                                                               




                                                                     
                                                       





                                                                         
                                          
                                  




                                                   
                                                        




                                                             
                                                        





























                                                                                
                                
                                                            
                          






                                                                     

                                                                             
                        
                                              
                                                                                  




                                                        
                                     
                                    
                                     

















                                                              
                           
                                                                     
                                            
                                                                  

     





















                                                                           
                                                         


                                                                     
                                      
                                                                    
                                        
                              
                                       
                            
                                    
                               

                                                                               
                    


                                                               

                                                                                   
                                      
                                                                
                                        
                               



                                      
                    

     


                                                                                      
                                      
                                                                  
                                        
                                

                                       
                    

     
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2003, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
\*                                                                      */

// $Id$

package scalac.symtab.classfile;

import scalac.Global;
import scalac.atree.AConstant;
import scalac.symtab.Symbol;
import scalac.symtab.SymbolLoader;
import scalac.symtab.Scope;
import scalac.symtab.Modifiers;
import scalac.symtab.Type.*;
import scalac.util.Name;
import scalac.util.Names;
import scalac.util.Debug;

import scala.tools.util.Position;
import ch.epfl.lamp.compiler.msil.*;

public class CLRClassParser extends SymbolLoader {

    protected JavaTypeFactory make;

    protected final CLRPackageParser importer;

    public CLRClassParser(Global global, CLRPackageParser importer) {
	super(global);
	this.importer = importer;
    }

    private static Name[] ENUM_CMP_NAMES = new Name[]
	{ Names.EQ, Names.NE, Names.LT, Names.LE, Names.GT, Names.GE };

    private static Name[] ENUM_BIT_LOG_NAMES = new Name[]
	{ Names.OR, Names.AND, Names.XOR };

    protected String doComplete(Symbol root) {
        assert root.isClassType(): Debug.show(root);
	try { return doComplete0(root); }
	catch (Throwable e) {
            // !!! doComplete may throw an IOException which is then
            // caught by SymbolLoader and reported to the user as
            // normal error message
	    System.err.println("\nWhile processing " + Debug.show(root));
	    e.printStackTrace();
	    System.exit(1);
            return null; // !!!
	}
    }

    protected String doComplete0(Symbol clazz) {
	clazz.owner().initialize(); //???

	if (make == null)
	    make = new JavaTypeCreator(global.definitions);

	Type type = (Type)importer.getMember(clazz);
	if (type == null)
	    type = Type.GetType(global.primitives.getCLRClassName(clazz));
	assert type != null : Debug.show(clazz);

	clazz.flags = translateAttributes(type);
	Type[] ifaces = type.getInterfaces();
	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 classInfo =
	    scalac.symtab.Type.compoundType(baseTypes, members, clazz);
	clazz.setInfo(classInfo);
        Symbol staticsModule = clazz.linkedModule();
	Symbol staticsClass = staticsModule.moduleClass();
        assert staticsClass.isModuleClass(): Debug.show(staticsClass);
        scalac.symtab.Type staticsInfo = scalac.symtab.Type.compoundType
            (scalac.symtab.Type.EMPTY_ARRAY, statics, staticsClass);
        staticsClass.setInfo(staticsInfo);
        staticsModule.setInfo(make.classType(staticsClass));
        scalac.symtab.Type ctype = make.classType(clazz);

	// import nested types
	Type[] nestedTypes = type.getNestedTypes();
	for (int i = 0; i < nestedTypes.length; i++) {
	    Type ntype = nestedTypes[i];
	    if (ntype.IsNestedPrivate() || ntype.IsNestedAssembly()
		|| ntype.IsNestedFamANDAssem())
		continue;
	    int j = ntype.FullName.lastIndexOf('.');
	    String n = (j < 0 ? ntype.FullName : ntype.FullName.substring(j + 1))
		.replace('+', '#');
	    Name classname = Name.fromString(n).toTypeName();
	    Name aliasname = Name.fromString(ntype.Name).toTypeName();
	    // put the class at the level of its outermost class
	    // the owner of a class is always its most specific package
	    Symbol nclazz = clazz.owner().newLoadedClass(JAVA, classname, this, null);
	    importer.map(nclazz, ntype);
	    // create an alias in the module of the outer class
	    Symbol alias = staticsClass.newTypeAlias(Position.NOPOS,
                translateAttributes(ntype), aliasname, make.classType(nclazz));
	    statics.enterNoHide(alias);
	}

	FieldInfo[] fields = type.getFields();
	for (int i = 0; i < fields.length; i++) {
	    if (fields[i].IsPrivate() || fields[i].IsAssembly()
		|| fields[i].IsFamilyAndAssembly())
		continue;
	    int mods = translateAttributes(fields[i]);
	    Name name = Name.fromString(fields[i].Name);
	    scalac.symtab.Type fieldType = getCLRType(fields[i].FieldType);
	    if (fields[i].IsLiteral() && !fields[i].FieldType.IsEnum())
		fieldType = make.constantType(
                    getConstant(fieldType.symbol(), fields[i].getValue()));
	    Symbol owner = fields[i].IsStatic() ? staticsClass : clazz;
	    Symbol field = owner.newField(Position.NOPOS, mods, name);
	    field.setInfo(fieldType);
	    (fields[i].IsStatic() ? statics : members).enterOrOverload(field);
	    importer.map(field, fields[i]);
	}

	PropertyInfo[] props = type.getProperties();
	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;
	    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 = owner.newMethod(Position.NOPOS, mods, n);
	    setParamOwners(mtype, method);
	    method.setInfo(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 = Name.fromString(n.toString() + Names._EQ);
	    mods = translateAttributes(setter);
	    method = owner.newMethod(Position.NOPOS, mods, n);
	    setParamOwners(mtype, method);
	    method.setInfo(mtype);
	    (setter.IsStatic() ? statics : members).enterOrOverload(method);
	    importer.map(method, setter);
	}

	MethodInfo[] methods = type.getMethods();
	for (int i = 0; i < methods.length; i++) {
	    if ((importer.getSymbol(methods[i]) != null)
		|| methods[i].IsPrivate()
		|| methods[i].IsAssembly()
		|| methods[i].IsFamilyAndAssembly())
		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 = owner.newMethod(Position.NOPOS, mods, n);
	    setParamOwners(mtype, method);
	    method.setInfo(mtype);
	    (methods[i].IsStatic() ? statics : members).enterOrOverload(method);
	    importer.map(method, methods[i]);
	}

	// for enumerations introduce comparison and bitwise logical operations;
	// the backend should recognize and replace them with comparison or
	// bitwise logical operations on the primitive underlying type
	if (type.IsEnum()) {
	    scalac.symtab.Type[] argTypes = new scalac.symtab.Type[] {ctype};
	    int mods = Modifiers.JAVA | Modifiers.FINAL;
	    for (int i = 0; i < ENUM_CMP_NAMES.length; i++) {
		scalac.symtab.Type enumCmpType =
		    make.methodType(argTypes,
				    global.definitions.BOOLEAN_TYPE(),
				    scalac.symtab.Type.EMPTY_ARRAY);
		Symbol enumCmp = clazz.newMethod
		    (Position.NOPOS, mods, ENUM_CMP_NAMES[i]);
		setParamOwners(enumCmpType, enumCmp);
		enumCmp.setInfo(enumCmpType);
		members.enterOrOverload(enumCmp);
	    }
	    for (int i = 0; i < ENUM_BIT_LOG_NAMES.length; i++) {
		scalac.symtab.Type enumBitLogType = make.methodType
		    (argTypes, ctype, scalac.symtab.Type.EMPTY_ARRAY);
		Symbol enumBitLog = clazz.newMethod
		    (Position.NOPOS, mods, ENUM_BIT_LOG_NAMES[i]);
		setParamOwners(enumBitLogType, enumBitLog);
		enumBitLog.setInfo(enumBitLogType);
		members.enterOrOverload(enumBitLog);
	    }
	}

	ConstructorInfo[] constrs = type.getConstructors();
	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();
	    int mods = translateAttributes(constrs[i]);
	    if (constr.isInitialized()) {
                clazz.addConstructor(
                    constr = clazz.newConstructor(Position.NOPOS, mods));
            } else {
                constr.flags = mods;
            }
	    setParamOwners(mtype, constr);
	    constr.setInfo(mtype);
	    importer.map(constr, constrs[i]);
	}

	Symbol constr = clazz.primaryConstructor();
	if (!constr.isInitialized()) {
	    constr.setInfo(scalac.symtab.Type.MethodType
				(Symbol.EMPTY_ARRAY, ctype));
	    if ((clazz.flags & Modifiers.INTERFACE) == 0)
		constr.flags |= Modifiers.PRIVATE;
	}

	return type + " from assembly " + type.Assembly;
    }

    /** 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(type.FullName.replace('+', '.'));
	if (res.isError())
	    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;
	//Symbol s = importer.getSymbol(type);
	//scalac.symtab.Type t = s != null ? make.classType(s) : getCLRType(type);
	return getCLRType(type);
    }

    protected scalac.symtab.Type getCLRType(Type type) {
	if (type == importer.OBJECT)
	    return make.objectType();
	if (type == importer.STRING)
	    return make.stringType();
	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()));
	Symbol s = importer.getSymbol(type);
	return s != null ? make.classType(s) : getClassType(type);
    }

    public AConstant getConstant(Symbol base, Object value) {
        if (base == global.definitions.BOOLEAN_CLASS)
            return AConstant.BOOLEAN(((Number)value).intValue() != 0);
        if (base == global.definitions.BYTE_CLASS)
            return AConstant.BYTE(((Number)value).byteValue());
        if (base == global.definitions.SHORT_CLASS)
            return AConstant.SHORT(((Number)value).shortValue());
        if (base == global.definitions.CHAR_CLASS)
            return AConstant.CHAR((char)((Number)value).intValue());
        if (base == global.definitions.INT_CLASS)
            return AConstant.INT(((Number)value).intValue());
        if (base == global.definitions.LONG_CLASS)
            return AConstant.LONG(((Number)value).longValue());
        if (base == global.definitions.FLOAT_CLASS)
            return AConstant.FLOAT(((Number)value).floatValue());
        if (base == global.definitions.DOUBLE_CLASS)
            return AConstant.DOUBLE(((Number)value).doubleValue());
        if (base == global.definitions.STRING_CLASS)
            return AConstant.STRING((String)value);
    	throw Debug.abort("illegal value", Debug.show(value, " - ", base));
    }

    protected static int translateAttributes(Type type) {
	int mods = Modifiers.JAVA;
	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;
    }

    protected static int translateAttributes(FieldInfo field) {
	int mods = Modifiers.JAVA;
	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;
    }

    protected static int translateAttributes(MethodBase method) {
	int mods = Modifiers.JAVA;
	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;
    }
}