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;
}