public Value computeBinaryExpr()

in modules/asc/src/java/macromedia/asc/semantics/ConstantEvaluator.java [1885:2104]


    public Value computeBinaryExpr(Context cx, int op, ObjectValue lv, ObjectValue rv, NumberUsage numberUsage)
    {
        ObjectValue val = null;
        TypeInfo lt = lv.getType(cx);
        TypeInfo rt = rv.getType(cx);

        TypeValue ltval = lt.getTypeValue();
        TypeValue rtval = rt.getTypeValue();

        switch ( op )
        {
            case MINUS_TOKEN:
            case MULT_TOKEN:
            case DIV_TOKEN:
            case PLUS_TOKEN:
            case MODULUS_TOKEN:
            {
                if( (ltval != null) && ltval.isNumeric(cx) && rtval.isNumeric(cx) )
                {
                    TypeValue[] ltype = new TypeValue[1];
                    TypeValue[] rtype = new TypeValue[1];
                    NumberConstant lval = cx.getEmitter().getValueOfNumberLiteral( lv.getValue(), ltype, numberUsage);
                    NumberConstant rval = cx.getEmitter().getValueOfNumberLiteral( rv.getValue(), rtype, numberUsage);
                    
                    boolean forceType = true;
                    int usage = numberUsage.get_usage();
                    if (usage == NumberUsage.use_Number ) {
                       	/* in this case, the types of the operands determine the type of the result */
                    	forceType = false;
                    	if (cx.statics.es4_numerics && ((ltype[0] == cx.decimalType()) || (rtype[0] == cx.decimalType()))) {
                    		usage = NumberUsage.use_decimal;
                    	}
                    	//else usage = Context.NU_DOUBLE; // we could overflow
                    	
                    	else if ((ltype[0] == cx.doubleType()) || (rtype[0] == cx.doubleType()) ||
                    			(ltype[0] == cx.numberType()) || (rtype[0] == cx.numberType())) {
                    		usage = NumberUsage.use_double;
                    	}
                    	else if ((ltype[0] == cx.intType()) || (rtype[0] == cx.uintType())) {
                    		if (lval.intValue() >= 0)
                    			usage = NumberUsage.use_uint;
                    		else
                    			usage = NumberUsage.use_double;
                    	}
                    	else if ((ltype[0] == cx.uintType()) || (rtype[0] == cx.intType())) {
                    		if (rval.intValue() >= 0)
                    			usage = NumberUsage.use_uint;
                    		else
                    			usage = NumberUsage.use_double;
                    	}
                    	else
                    		usage = NumberUsage.use_int;

                        if( !cx.statics.es4_numerics )
                            usage = NumberUsage.use_double;
                    }
                    switch (usage) {
                    case NumberUsage.use_decimal: {
                    	Decimal128 d = Decimal128.NaN;
                    	Decimal128 ld = lval.decimalValue();
                    	Decimal128 rd = rval.decimalValue();
                    	currentDecimalContext.setPrecision(numberUsage.get_precision());
                    	currentDecimalContext.setRoundingMode(numberUsage.get_java_roundingMode());
                    	switch ( op ) {
                    	case MINUS_TOKEN:
                    		d = ld.subtract(rd, currentDecimalContext);
                    		break;
                    	case PLUS_TOKEN:
                    		d = ld.add(rd, currentDecimalContext);
                    		break;
                    	case MULT_TOKEN:
                    		d = ld.multiply(rd, currentDecimalContext);
                    		break;
                    	case DIV_TOKEN:
                    		d = ld.divide(rd, currentDecimalContext);
                    		break;
                    	case MODULUS_TOKEN:
                    		d = ld.remainder(rd, currentDecimalContext);
                    		break;
                    	default: // shouldn't be possible
                    	}
                    	// we won't be here unless cx.statics.es4_numerics is true
                    	val = new ObjectValue(d.toString() + "m", cx.decimalType());
                    	break;
                    } // case NU_DECIMAL
                    case NumberUsage.use_double: {
                    	double d = Double.NaN;
                    	double ld = lval.doubleValue();
                    	double rd = rval.doubleValue();
                    	switch ( op ) {
                    	case MINUS_TOKEN:
                    		d = ld - rd;
                    		break;
                    	case PLUS_TOKEN:
                    		d = ld + rd;
                    		break;
                    	case MULT_TOKEN:
                    		d = ld * rd;
                    		break;
                    	case DIV_TOKEN:
                    		d = ld / rd;
                    		break;
                    	case MODULUS_TOKEN:
                    		d = ld % rd;
                    		break;
                    	default: // shouldn't be possible
                    	}
                    	val = new ObjectValue(Double.toString(d), cx.doubleType());
                    	break;
                    } // case NU_DOUBLE
                    case NumberUsage.use_int: {
                    	int i = 0;
                    	int li = lval.intValue();
                    	int ri = rval.intValue();
                    	double d = 0;
                    	double ld = lval.doubleValue();
                    	double rd = rval.doubleValue();
                    	switch ( op ) {
                    	case MINUS_TOKEN:
                    		i = li - ri;
                    		d = ld - rd;
                    		break;
                    	case PLUS_TOKEN:
                    		i = li + ri;
                    		d = ld + rd;
                    		break;
                    	case MULT_TOKEN:
                    		i = li * ri;
                    		d = ld * rd;
                    		break;
                    	case DIV_TOKEN:
                    		i = li / ri;
                    		d = ld / rd;
                    		break;
                    	case MODULUS_TOKEN:
                    		if (ri == 0) {
                    			return new ObjectValue("NaN", cx.doubleType());
                    		}
                    		i = li % ri;
                    		d = ld % rd;
                    		break;
                    	default: // shouldn't be possible
                    	}
                    	if (forceType || (((int)d) == i))
                    		val = new ObjectValue(Integer.toString(i), cx.intType());
                    	else
                        	val = new ObjectValue(Double.toString(d), cx.doubleType());
                    	break;
                    } // case NU_INT
                    case NumberUsage.use_uint: {
                     	long d = 0;
                    	long ld = lval.uintValue();
                    	long rd = rval.uintValue();
                    	switch ( op ) {
                    	case MINUS_TOKEN:
                    		d = ld - rd;
                    		break;
                    	case PLUS_TOKEN:
                    		d = ld + rd;
                    		break;
                    	case MULT_TOKEN:
                    		d = ld * rd;
                    		break;
                    	case DIV_TOKEN:
                    		if (rd == 0) {
                    			// divide by 0
                    			String sval;
                    			if (ld == 0)
                    				sval = "NaN";
                    			else if (ld < 0)
                    				sval = "-Infinity";
                    			else 
                    				sval = "Infinity";
                    			return new ObjectValue(sval, cx.doubleType());
                    		}
                    		d = ld / rd;
                    		break;
                    	case MODULUS_TOKEN:
                    		if (rd == 0) {
                    			return new ObjectValue("NaN", cx.doubleType());
                    		}
                    		d = ld % rd;
                    		break;
                    	default: // shouldn't be possible
                    	}
                    	if (forceType || ((d >= 0) && (d <= 0xFFFFFFFFL))) {
                    		d &= 0xFFFFFFFFL; // truncate to 32 bits in the forceType case
                    		val = new ObjectValue(Long.toString(d), cx.uintType());
                    	}
                    	else {
                    		double dval;
                    		if ((op == MULT_TOKEN) && (d > 0xFFFFFFFFL || (d < 0))) {
                    			// could be from overflow in multiply.  Redo in double
                    			dval = lval.doubleValue() * rval.doubleValue();
                    		}
                    		else
                    			dval = d;
                    		val = new ObjectValue(Double.toString(dval), cx.doubleType());
                    	}
                    	break;
                    } // case NU_UINT
                    default: 

                    } // switch cx.numeric_usage
                    
                } // both types numeric
                else {
                	if (op == PLUS_TOKEN) {
                		val = cx.noType().prototype;
                	}
                }
                break;
            }
            default:
                val = cx.noType().prototype;
                break;
        }

        return val;
    }