summaryrefslogblamecommitdiff
path: root/sources/scalac/symtab/classfile/AttributeParser.java
blob: a6ae0a90834d91bccb4b140d9a5e48ea3775ad19 (plain) (tree)























































































































































                                                                                              






































































































                                                                                     


                                                                                        














                                                                                               


                                                                                 












































                                                                                                      
                                               





































                                                                            




                                                    



                                                         
                                                                         






































































                                                                                            
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    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, Type.MethodType(Symbol.EMPTY_ARRAY, 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;
                        }
                        //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 clazz.typeConstructor();
	    }
	}

        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;
			int flags = Modifiers.PARAM;
			if ("def".equals(token)) {
			    nextToken();
			    flags |= Modifiers.DEF;
			}
                        params.add(new TermSymbol(
                            Position.NOPOS,
                            Name.fromString("x" + (i++)),
                            owner,
                            flags).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;
            }
        }
    }
}