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



                                                                          

                                                                          

       

                                
                                 
                                           


                            
                        
                         
                                        
                         
 
                                                                  

                         



























                                                                              
                             

                         

     





                                                                              
       




                                                   

     
























                                                                              













                                                                 
                               
                                                      
                                                                 





















                                                                    


         





                                                                             

     






                                                                              

                               



                                                    

         









                                                                             
                                                               


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

// $Id$

package scalac.symtab.classfile;

import scala.tools.util.Position;
import scala.tools.util.AbstractFileReader;
import scalac.Global;
import scalac.symtab.Symbol;
import scalac.symtab.Type;
import scalac.util.Name;
import scalac.util.Names;
import scalac.util.SourceRepresentation;
import scalac.util.Debug;

/** This class implements the parsing of class file signatures. */
public class Signatures {

    //########################################################################
    // Private Fields

    /** The global environment */
    private final Global global;

    /** The Java type factory */
    private final JavaTypeFactory make;

    /** The input file */
    private final AbstractFileReader in;

    /** The address of the first byte of the current signature */
    private int first;

    /** The address of the last byte of the current signature */
    private int last;

    /** The current address (first <= current <= last) */
    private int current;

    //########################################################################
    // Public Constructors

    /** Initializes this instance. */
    public Signatures(Global global, JavaTypeFactory make,
        AbstractFileReader in)
    {
        this.global = global;
        this.make = make;
        this.in = in;
    }

    //########################################################################
    // Public Methods

    /**
     * Sets the address of the next signature to read. The address
     * must point to the first byte of a CONSTANT_Utf8_info.
     */
    public Signatures at(int address) {
        first = address + 3;
        last = first + in.getChar(address + 1) - 1;
        current = first;
        return this;
    }

    /** Returns the current signature. */
    public String getSignature() {
        return SourceRepresentation.ascii2string(in.buf, first, last-first+1);
    }

    /** Reads the class signature at current address. */
    public Symbol readClassName() {
        Symbol owner = global.definitions.ROOT_CLASS;
        int start = current;
        for (; current <= last; current++) {
            int b = in.byteAt(current);
            if (b == ';') break;
            if (b != '/') continue;
            Name name = Name.fromAscii(in.buf, start, current - start);
            Symbol module = owner.members().lookup(name);
            if (!module.isModule()) {
                Symbol symbol = owner.newModule(Position.NOPOS, 0, name);
                symbol.moduleClass().setInfo(Type.ErrorType);
                error("could not find module " + symbol.staticType());
                if (module.isNone()) owner.members().enterNoHide(symbol);
                module = symbol;
            }
            owner = module.moduleClass();
            start = current + 1;
        }

	Symbol clasz = null;
        Name name = Name.fromAscii(in.buf, start, current-start);
	if (owner == global.definitions.JAVALANG.moduleClass()) {
	    if (name == Names.String)
		clasz = global.definitions.STRING_CLASS;
	    else if (name == Names.Object)
		clasz = global.definitions.OBJECT_CLASS;
	}
	if (clasz == null) {
	    name = name.toTypeName();
	    clasz = owner.members().lookup(name);
	}

        if (!clasz.isClass()) {
            Symbol symbol = owner.newErrorClass(name);
            error("could not find class " + symbol.staticType());
            if (clasz.isNone()) owner.members().enterNoHide(symbol);
            clasz = symbol;
        }
        current++;
        return clasz;
    }

    /** Reads the value type signature at current address. */
    public Type readValueType() {
        switch (in.byteAt(current++)) {
        case 'V': return make.voidType();
        case 'Z': return make.booleanType();
        case 'B': return make.byteType();
        case 'S': return make.shortType();
        case 'C': return make.charType();
        case 'I': return make.intType();
        case 'J': return make.longType();
        case 'F': return make.floatType();
        case 'D': return make.doubleType();
        case 'L': return make.classType(readClassName());
        case '[': return make.arrayType(readValueType());
        default : return errorBadTypeTag(current - 1);
        }
    }

    /** Reads the method type signature at current address. */
    public Type readMethodType() {
        if (in.byteAt(current++) != '(') return errorBadTypeTag(current - 1);
        Type[] parameters = readParamterTypes(0);
        Type result = readValueType();
        return make.methodType(parameters, result, Type.EMPTY_ARRAY);
    }

    //########################################################################
    // Private Methods

    /** Reads the parameter types at current address. */
    private Type[] readParamterTypes(int i) {
        if (in.byteAt(current) == ')') {
            current++;
            return new Type[i];
        } else {
            Type type = readValueType();
            Type[] types = readParamterTypes(i + 1);
            types[i] = type;
            return types;
        }
    }

    /** Signals a bad tag at given address. Return ErrorType. */
    private Type errorBadTypeTag(int address) {
        char tag = (char)in.byteAt(address);
        error("bad tag '" + tag + "' in signature '" + getSignature() + "'");
        return Type.ErrorType;
    }

    /** Signals the given error. */
    private void error(String error) {
        global.error("class file '" + in.file + "': " + error);
    }

    //########################################################################
}