Milán Major

netscape-revival

1 branch
Code

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

/*
 * @(#)Expression.java	1.35 95/11/26 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.Label;
import sun.tools.asm.Assembler;
import java.io.PrintStream;
import java.util.Hashtable;

public
class Expression extends Node {
    Type type;

    /**
     * Constructor
     */
    Expression(int op, int where, Type type) {
	super(op, where);
	this.type = type;
    }

    /**
     * Return the precedence of the operator
     */
    int precedence() {
	return (op < opPrecedence.length) ? opPrecedence[op] : 100;
    }

    /**
     * Order the expression based on precedence
     */
    public Expression order() {
	return this;
    }

    /**
     * Return true if constant
     */
    public boolean isConstant() {
        return false;
    }

    /**
     * Return the constant value
     */
    public Object getValue() {
        return null;
    }

    /**
     * Check if the expression is equal to a value
     */
    public boolean equals(int i) {
	return false;
    }
    public boolean equals(boolean b) {
	return false;
    }
    public boolean equals(Identifier id) {
	return false;
    }

    /**
     * Check if the expression is equal to its default static value
     */
    public boolean equalsDefault() {
        return false;
    }


    /**
     * Convert an expresion to a type
     */
    Type toType(Environment env, Context ctx) {
	env.error(where, "invalid.type.expr");
	return Type.tError;
    }

    /**
     * See if this expression fits in the given type.
     * This is useful because some larger number fit into
     * smaller types.
     */
    public boolean fitsType(Environment env, Type t) {
	try { 
	    return env.isMoreSpecific(this.type, t);
	} catch (ClassNotFound e) {
	    return false;
	}
    }

    /**
     * Check an expression
     */
    public long checkValue(Environment env, Context ctx, long vset, Hashtable exp) {
	return vset;
    }
    public long checkInitializer(Environment env, Context ctx, long vset, Type t, Hashtable exp) {
	return checkValue(env, ctx, vset, exp);
    }
    public long check(Environment env, Context ctx, long vset, Hashtable exp) {
	throw new CompilerError("check failed");
    }

    public long checkLHS(Environment env, Context ctx, 
			    long vset, Hashtable exp) {
	env.error(where, "invalid.lhs.assignment");
	type = Type.tError;
	return vset;
    }

    public long checkAssignOp(Environment env, Context ctx, 
			      long vset, Hashtable exp, Expression outside) {
	if (outside instanceof IncDecExpression) 
	    env.error(where, "invalid.arg", opNames[outside.op]);
	else 
	    env.error(where, "invalid.lhs.assignment");
	type = Type.tError;
	return vset;
    }


    /**
     * Check a condition.  Return a ConditionVars(), which indicates when
     * which variables are set if the condition is true, and which are set if
     * the condition is false. 
     */
    public ConditionVars checkCondition(Environment env, Context ctx, 
					long vset, Hashtable exp) {
	ConditionVars cvars = new ConditionVars();
	checkCondition(env, ctx, vset, exp, cvars);
	return cvars;
    }

    /*
     * Check a condition.  
     * 
     * cvars is modified so that 
     *    cvar.vsTrue indicates variables with a known value if result = true
     *    cvars.vsFalse indicates variables with a known value if !result
     *
     * The default action is to simply call checkValue on the expression, and
     * to see both vsTrue and vsFalse to the result.
     */

    public void checkCondition(Environment env, Context ctx, 
			       long vset, Hashtable exp, ConditionVars cvars) {
	cvars.vsTrue = cvars.vsFalse = checkValue(env, ctx, vset, exp);
    }



    /**
     * Evaluate
     */
    Expression eval() {
	return this;
    }

    /**
     * Simplify
     */
    Expression simplify() {
	return this;
    }

    /**
     * Inline
     */
    public Expression inline(Environment env, Context ctx) {
	return null;
    }
    public Expression inlineValue(Environment env, Context ctx) {
	return this;
    }
    public Expression inlineLHS(Environment env, Context ctx) {
	return null;
    }

    /**
     * The cost of inlining this expression
     */
    public int costInline(int thresh) {
	return 1;
    }

    /**
     * Code
     */
    void codeBranch(Environment env, Context ctx, Assembler asm, Label lbl, boolean whenTrue) {
	if (type.isType(TC_BOOLEAN)) {
	    codeValue(env, ctx, asm);
	    asm.add(where, whenTrue ? opc_ifne : opc_ifeq, lbl);
	} else {
	    throw new CompilerError("codeBranch " + opNames[op]);
	}
    }
    public void codeValue(Environment env, Context ctx, Assembler asm) {
	if (type.isType(TC_BOOLEAN)) {
	    Label l1 = new Label();
	    Label l2 = new Label();

	    codeBranch(env, ctx, asm, l1, true);
	    asm.add(where, opc_ldc, new Integer(0));
	    asm.add(where, opc_goto, l2);
	    asm.add(l1);
	    asm.add(where, opc_ldc, new Integer(1));
	    asm.add(l2);
	} else {
	    throw new CompilerError("codeValue");
	}
    }
    public void code(Environment env, Context ctx, Assembler asm) {
	codeValue(env, ctx, asm);

	switch (type.getTypeCode()) {
	  case TC_VOID:
	    break;

	  case TC_DOUBLE:
	  case TC_LONG:
	    asm.add(where, opc_pop2);
	    break;
	    
	  default:
	    asm.add(where, opc_pop);
	    break;
	}
    }
    int codeLValue(Environment env, Context ctx, Assembler asm) {
	print(System.out);
	throw new CompilerError("invalid lhs");
    }
    void codeLoad(Environment env, Context ctx, Assembler asm) {
	print(System.out);
	throw new CompilerError("invalid load");
    }
    void codeStore(Environment env, Context ctx, Assembler asm) {
	print(System.out);
	throw new CompilerError("invalid store");
    }
    void codeAppend(Environment env, Context ctx, Assembler asm, ClassDeclaration c) {
	try {
	    codeValue(env, ctx, asm);
	    Type argTypes[] = {type};
	    ClassDefinition sourceClass = ctx.field.getClassDefinition();
	    FieldDefinition f = c.getClassDefinition(env).matchMethod(env, sourceClass, idAppend, argTypes);
	    asm.add(where, opc_invokevirtual, f);
	} catch (ClassNotFound e) {
	    throw new CompilerError(e);
	} catch (AmbiguousField e) {
	    throw new CompilerError(e);
	}
    }

    /**
     * Code
     */
    void codeDup(Environment env, Context ctx, Assembler asm, int items, int depth) {
	switch (items) {
	  case 0:
	    return;
	    
	  case 1:
	    switch (depth) {
	      case 0:
		asm.add(where, opc_dup);
		return;
	      case 1:
		asm.add(where, opc_dup_x1);
		return;
	      case 2:
		asm.add(where, opc_dup_x2);
		return;
		
	    }
	    break;
	  case 2:
	    switch (depth) {
	      case 0:
		asm.add(where, opc_dup2);
		return;
	      case 1:
		asm.add(where, opc_dup2_x1);
		return;
	      case 2:
		asm.add(where, opc_dup2_x2);
		return;
		
	    }
	    break;
	}
 	throw new CompilerError("can't dup: " + items + ", " + depth);
    }

    void codeConversion(Environment env, Context ctx, Assembler asm, Type f, Type t) {
	int from = f.getTypeCode();
	int to = t.getTypeCode();

	switch (to) {
 	  case TC_BOOLEAN:
	    if (from != TC_BOOLEAN) {
		break;
	    }
	    return;
	  case TC_BYTE:
	    if (from != TC_BYTE) {
		codeConversion(env, ctx, asm, f, Type.tInt);
		asm.add(where, opc_int2byte);
	    }
	    return;
	  case TC_CHAR:
	    if (from != TC_CHAR) {
		codeConversion(env, ctx, asm, f, Type.tInt);
		asm.add(where, opc_int2char);
	    }
	    return;
	  case TC_SHORT:
	    if (from != TC_SHORT) {
		codeConversion(env, ctx, asm, f, Type.tInt);
		asm.add(where, opc_int2short);
	    }
	    return;
	  case TC_INT:
	    switch (from) {
	      case TC_BYTE:
	      case TC_CHAR:
	      case TC_SHORT:
	      case TC_INT:
		return;
	      case TC_LONG:
		asm.add(where, opc_l2i);
		return;
	      case TC_FLOAT:
		asm.add(where, opc_f2i);
		return;
	      case TC_DOUBLE:
		asm.add(where, opc_d2i);
		return;
	    }
	    break;
	  case TC_LONG:
	    switch (from) {
	      case TC_BYTE:
	      case TC_CHAR:
	      case TC_SHORT:
	      case TC_INT:
		asm.add(where, opc_i2l);
		return;
	      case TC_LONG:
		return;
	      case TC_FLOAT:
		asm.add(where, opc_f2l);
		return;
	      case TC_DOUBLE:
		asm.add(where, opc_d2l);
		return;
	    }
	    break;
	  case TC_FLOAT:
	    switch (from) {
	      case TC_BYTE:
	      case TC_CHAR:
	      case TC_SHORT:
	      case TC_INT:
		asm.add(where, opc_i2f);
		return;
	      case TC_LONG:
		asm.add(where, opc_l2f);
		return;
	      case TC_FLOAT:
		return;
	      case TC_DOUBLE:
		asm.add(where, opc_d2f);
		return;
	    }
	    break;
	  case TC_DOUBLE:
	    switch (from) {
	      case TC_BYTE:
	      case TC_CHAR:
	      case TC_SHORT:
	      case TC_INT:
		asm.add(where, opc_i2d);
		return;
	      case TC_LONG:
		asm.add(where, opc_l2d);
		return;
	      case TC_FLOAT:
		asm.add(where, opc_f2d);
		return;
	      case TC_DOUBLE:
		return;
	    }
	    break;

	  case TC_CLASS:
	    switch (from) {
	      case TC_NULL:
		return;
	      case TC_CLASS:
	      case TC_ARRAY:
		try {
		    if (!env.implicitCast(f, t)) {
			asm.add(where, opc_checkcast, env.getClassDeclaration(t));
		    }
		} catch (ClassNotFound e) {
		    throw new CompilerError(e);
		}
		return;
	    }
	    
	    break;
	    
	  case TC_ARRAY:
	    switch (from) {
	      case TC_NULL:
		return;
	      case TC_CLASS:
	      case TC_ARRAY:
		try {
		    if (!env.implicitCast(f, t)) {
			asm.add(where, opc_checkcast, t);
		    }
		    return;
		} catch (ClassNotFound e) {
		    throw new CompilerError(e);
		}
	    }
	    break;
	}
	throw new CompilerError("codeConversion: " + from + ", " + to);
    }

    /**
     * Check if the first thing is a constructor invocation
     */
    public boolean firstConstructor() {
	return false;
    }

    /**
     * Create a copy of the expression for method inlining
     */
    public Expression copyInline(Context ctx) {
	return (Expression)clone();
    }

    /**
     * Print
     */
    public void print(PrintStream out) {
	out.print(opNames[op]);
    }
}