Milán Major

netscape-revival

1 branch
Code

sun-java/classsrc/sun/tools/tree/IdentifierExpression.java

/*
 * @(#)IdentifierExpression.java	1.25 95/12/03 Arthur van Hoff
 *
 * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

package sun.tools.tree;

import sun.tools.java.*;
import sun.tools.asm.Assembler;
import sun.tools.asm.LocalVariable;
import java.io.PrintStream;
import java.util.Hashtable;

public
class IdentifierExpression extends Expression {
    Identifier id;
    FieldDefinition field;
    
    /**
     * Constructor
     */
    public IdentifierExpression(int where, Identifier id) {
	super(IDENT, where, Type.tError);
	this.id = id;
    }

    /**
     * Check if the expression is equal to a value
     */
    public boolean equals(Identifier id) {
	return this.id.equals(id);
    }


    /**
     * Assign a value to this identifier.  [It must already be "bound"]
     */
    private long assign(Environment env, long vset) {
	if (field.isLocal()) {
	    LocalField local = (LocalField)field;
	    vset |= (long)1 << local.number;
	    local.writecount++;
	}
	if (field.isFinal()) {
	    env.error(where, "assign.to.final", id);
	}
	return vset;
    }

    /** 
     * Get the value of this identifier.  [ It must already be "bound"]
     */
    private long get(Environment env, long vset) {
	if (field.isLocal()) {
	    LocalField local = (LocalField)field;
	    if ((vset & ((long)1 << local.number)) == 0) {
		env.error(where, "var.not.initialized", id);
		vset |= (long)1 << local.number;
	    }
	    local.readcount++;
	} else if (!field.isStatic()) {
	    if ((vset & 1) == 0) {
		env.error(where, "access.inst.before.super", id);
	    }
	}
	return vset;
    }

    /**
     * Bind to a field
     */
    boolean bind(Environment env, Context ctx) {
	try {
	    field = ctx.getField(env, id);
	    if (field == null) {
		env.error(where, "undef.var", id);
		return false;
	    }

	    type = field.getType();

	    // Check access permission
	    if (!ctx.field.getClassDefinition().canAccess(env, field)) {
		env.error(where, "no.field.access", id, field.getClassDeclaration(), ctx.field.getClassDeclaration());
		return false;
	    }

	    // Check acces of static variables
	    if (!ctx.field.canAccess(env, field)) {
		env.error(where, "no.static.field.access", id, field.getClassDeclaration());
		return false;
	    }

	    // Since the reference to the field is implicitly this.field, it
	    // must be a reasonable reference to a protected field.  No need
	    // to check for invalid.protected.use
	    ;


	    // Check forward reference
	    if (!ctx.field.canReach(env, field)) {
		env.error(where, "forward.ref", id, field.getClassDeclaration());
		return false;
	    }
	    return true;
	} catch (ClassNotFound e) {
	    env.error(where, "class.not.found", e.name, ctx.field);
	} catch (AmbiguousField e) {
	    env.error(where, "ambig.field", id, e.field1.getClassDeclaration(), e.field2.getClassDeclaration());
	}
	return false;
    }

    /**
     * Check expression
     */
    public long checkValue(Environment env, Context ctx, long vset, Hashtable exp) {
	if (bind(env, ctx)) {
	    vset = get(env, vset);
	    ctx.field.getClassDefinition().addDependency(field.getClassDeclaration());
	}
	return vset;
    }

    /**
     * Check the expression if it appears on the LHS of an assignment
     */
    public long checkLHS(Environment env, Context ctx, 
			 long vset, Hashtable exp) {
	if (bind(env, ctx)) 
	    return assign(env, vset);
	else 
	    return vset;
    }

    /**
     * Check the expression if it appears on the LHS of an op= expression 
     */
    public long checkAssignOp(Environment env, Context ctx, 
			      long vset, Hashtable exp, Expression outside) {
	if (bind(env, ctx)) 
	    return assign(env, get(env, vset));
	else 
	    return vset;
    }

    /**
     * Convert an identifier to a type
     */
    Type toType(Environment env, Context ctx) {
	try {
	    return Type.tClass(ctx.field.resolve(env, id));
	} catch (AmbiguousClass ee) {
	    env.error(where, "ambig.class", ee.name1, ee.name2);
	} catch (ClassNotFound ee) {
	}
	ClassDefinition currentClass = ctx.field.getClassDefinition();
	Identifier pkg = currentClass.getName().getQualifier();
	Identifier fullID = ((pkg == null || pkg == idNull)) 
	                            ? id : Identifier.lookup(pkg, id);
	return Type.tClass(fullID);
    }

    /**
     * Inline
     */
    public Expression inline(Environment env, Context ctx) {
	return null;
    }
    public Expression inlineValue(Environment env, Context ctx) {
	if (field == null) {
	    return this;
	}
	try {
	    if (field.isLocal()) {
		if (field.isFinal()) {
		    Expression e = (Expression)field.getValue(env);
		    return (e != null) ? e : this;
		}
		return this;
	    }
	    return new FieldExpression(where, ctx, field).inlineValue(env, ctx);
	} catch (ClassNotFound e) {
	    throw new CompilerError(e);
	}
    }
    public Expression inlineLHS(Environment env, Context ctx) {
	if (field.isLocal()) {
	    return this;
	}
	return new FieldExpression(where, ctx, field).inlineValue(env, ctx);
    }

    /**
     * Code
     */
    int codeLValue(Environment env, Context ctx, Assembler asm) {
	return 0;
    }
    void codeLoad(Environment env, Context ctx, Assembler asm) {
	asm.add(where, opc_iload + type.getTypeCodeOffset(),
		new Integer(((LocalField)field).number));
    }
    void codeStore(Environment env, Context ctx, Assembler asm) {
	LocalField local = (LocalField)field;
	asm.add(where, opc_istore + type.getTypeCodeOffset(),
		new LocalVariable(local, local.number));
    }
    public void codeValue(Environment env, Context ctx, Assembler asm) {
	codeLValue(env, ctx, asm);
	codeLoad(env, ctx, asm);
    }

    /**
     * Print
     */
    public void print(PrintStream out) {
	out.print(id + "#" + ((field != null) ? field.hashCode() : 0));
    }
}