Merge pull request #18847 from rmuir/refactor_def_math
painless: refactor def math
This commit is contained in:
commit
f8738c853b
|
@ -655,625 +655,6 @@ public final class Def {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE: Below methods are not cached, instead invoked directly because they are performant.
|
||||
// We also check for Long values first when possible since the type is more
|
||||
// likely to be a Long than a Float.
|
||||
|
||||
public static Object not(final Object unary) {
|
||||
if (unary instanceof Double || unary instanceof Long || unary instanceof Float) {
|
||||
return ~((Number)unary).longValue();
|
||||
} else if (unary instanceof Number) {
|
||||
return ~((Number)unary).intValue();
|
||||
} else if (unary instanceof Character) {
|
||||
return ~(int)(char)unary;
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [~] operation to type " +
|
||||
"[" + unary.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
public static Object neg(final Object unary) {
|
||||
if (unary instanceof Double) {
|
||||
return -(double)unary;
|
||||
} else if (unary instanceof Float) {
|
||||
return -(float)unary;
|
||||
} else if (unary instanceof Long) {
|
||||
return -(long)unary;
|
||||
} else if (unary instanceof Number) {
|
||||
return -((Number)unary).intValue();
|
||||
} else if (unary instanceof Character) {
|
||||
return -(char)unary;
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [-] operation to type " +
|
||||
"[" + unary.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
public static Object mul(final Object left, final Object right) {
|
||||
if (left instanceof Number) {
|
||||
if (right instanceof Number) {
|
||||
if (left instanceof Double || right instanceof Double) {
|
||||
return ((Number)left).doubleValue() * ((Number)right).doubleValue();
|
||||
} else if (left instanceof Float || right instanceof Float) {
|
||||
return ((Number)left).floatValue() * ((Number)right).floatValue();
|
||||
} else if (left instanceof Long || right instanceof Long) {
|
||||
return ((Number)left).longValue() * ((Number)right).longValue();
|
||||
} else {
|
||||
return ((Number)left).intValue() * ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
if (left instanceof Double) {
|
||||
return ((Number)left).doubleValue() * (char)right;
|
||||
} else if (left instanceof Long) {
|
||||
return ((Number)left).longValue() * (char)right;
|
||||
} else if (left instanceof Float) {
|
||||
return ((Number)left).floatValue() * (char)right;
|
||||
} else {
|
||||
return ((Number)left).intValue() * (char)right;
|
||||
}
|
||||
}
|
||||
} else if (left instanceof Character) {
|
||||
if (right instanceof Number) {
|
||||
if (right instanceof Double) {
|
||||
return (char)left * ((Number)right).doubleValue();
|
||||
} else if (right instanceof Long) {
|
||||
return (char)left * ((Number)right).longValue();
|
||||
} else if (right instanceof Float) {
|
||||
return (char)left * ((Number)right).floatValue();
|
||||
} else {
|
||||
return (char)left * ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
return (char)left * (char)right;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [*] operation to types " +
|
||||
"[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
public static Object div(final Object left, final Object right) {
|
||||
if (left instanceof Number) {
|
||||
if (right instanceof Number) {
|
||||
if (left instanceof Double || right instanceof Double) {
|
||||
return ((Number)left).doubleValue() / ((Number)right).doubleValue();
|
||||
} else if (left instanceof Float || right instanceof Float) {
|
||||
return ((Number)left).floatValue() / ((Number)right).floatValue();
|
||||
} else if (left instanceof Long || right instanceof Long) {
|
||||
return ((Number)left).longValue() / ((Number)right).longValue();
|
||||
} else {
|
||||
return ((Number)left).intValue() / ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
if (left instanceof Double) {
|
||||
return ((Number)left).doubleValue() / (char)right;
|
||||
} else if (left instanceof Long) {
|
||||
return ((Number)left).longValue() / (char)right;
|
||||
} else if (left instanceof Float) {
|
||||
return ((Number)left).floatValue() / (char)right;
|
||||
} else {
|
||||
return ((Number)left).intValue() / (char)right;
|
||||
}
|
||||
}
|
||||
} else if (left instanceof Character) {
|
||||
if (right instanceof Number) {
|
||||
if (right instanceof Double) {
|
||||
return (char)left / ((Number)right).doubleValue();
|
||||
} else if (right instanceof Long) {
|
||||
return (char)left / ((Number)right).longValue();
|
||||
} else if (right instanceof Float) {
|
||||
return (char)left / ((Number)right).floatValue();
|
||||
} else {
|
||||
return (char)left / ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
return (char)left / (char)right;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [/] operation to types " +
|
||||
"[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
public static Object rem(final Object left, final Object right) {
|
||||
if (left instanceof Number) {
|
||||
if (right instanceof Number) {
|
||||
if (left instanceof Double || right instanceof Double) {
|
||||
return ((Number)left).doubleValue() % ((Number)right).doubleValue();
|
||||
} else if (left instanceof Float || right instanceof Float) {
|
||||
return ((Number)left).floatValue() % ((Number)right).floatValue();
|
||||
} else if (left instanceof Long || right instanceof Long) {
|
||||
return ((Number)left).longValue() % ((Number)right).longValue();
|
||||
} else {
|
||||
return ((Number)left).intValue() % ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
if (left instanceof Double) {
|
||||
return ((Number)left).doubleValue() % (char)right;
|
||||
} else if (left instanceof Long) {
|
||||
return ((Number)left).longValue() % (char)right;
|
||||
} else if (left instanceof Float) {
|
||||
return ((Number)left).floatValue() % (char)right;
|
||||
} else {
|
||||
return ((Number)left).intValue() % (char)right;
|
||||
}
|
||||
}
|
||||
} else if (left instanceof Character) {
|
||||
if (right instanceof Number) {
|
||||
if (right instanceof Double) {
|
||||
return (char)left % ((Number)right).doubleValue();
|
||||
} else if (right instanceof Long) {
|
||||
return (char)left % ((Number)right).longValue();
|
||||
} else if (right instanceof Float) {
|
||||
return (char)left % ((Number)right).floatValue();
|
||||
} else {
|
||||
return (char)left % ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
return (char)left % (char)right;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [%] operation to types " +
|
||||
"[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
public static Object add(final Object left, final Object right) {
|
||||
if (left instanceof String || right instanceof String) {
|
||||
return "" + left + right;
|
||||
} else if (left instanceof Number) {
|
||||
if (right instanceof Number) {
|
||||
if (left instanceof Double || right instanceof Double) {
|
||||
return ((Number)left).doubleValue() + ((Number)right).doubleValue();
|
||||
} else if (left instanceof Float || right instanceof Float) {
|
||||
return ((Number)left).floatValue() + ((Number)right).floatValue();
|
||||
} else if (left instanceof Long || right instanceof Long) {
|
||||
return ((Number)left).longValue() + ((Number)right).longValue();
|
||||
} else {
|
||||
return ((Number)left).intValue() + ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
if (left instanceof Double) {
|
||||
return ((Number)left).doubleValue() + (char)right;
|
||||
} else if (left instanceof Long) {
|
||||
return ((Number)left).longValue() + (char)right;
|
||||
} else if (left instanceof Float) {
|
||||
return ((Number)left).floatValue() + (char)right;
|
||||
} else {
|
||||
return ((Number)left).intValue() + (char)right;
|
||||
}
|
||||
}
|
||||
} else if (left instanceof Character) {
|
||||
if (right instanceof Number) {
|
||||
if (right instanceof Double) {
|
||||
return (char)left + ((Number)right).doubleValue();
|
||||
} else if (right instanceof Long) {
|
||||
return (char)left + ((Number)right).longValue();
|
||||
} else if (right instanceof Float) {
|
||||
return (char)left + ((Number)right).floatValue();
|
||||
} else {
|
||||
return (char)left + ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
return (char)left + (char)right;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [+] operation to types " +
|
||||
"[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
public static Object sub(final Object left, final Object right) {
|
||||
if (left instanceof Number) {
|
||||
if (right instanceof Number) {
|
||||
if (left instanceof Double || right instanceof Double) {
|
||||
return ((Number)left).doubleValue() - ((Number)right).doubleValue();
|
||||
} else if (left instanceof Float || right instanceof Float) {
|
||||
return ((Number)left).floatValue() - ((Number)right).floatValue();
|
||||
} else if (left instanceof Long || right instanceof Long) {
|
||||
return ((Number)left).longValue() - ((Number)right).longValue();
|
||||
} else {
|
||||
return ((Number)left).intValue() - ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
if (left instanceof Double) {
|
||||
return ((Number)left).doubleValue() - (char)right;
|
||||
} else if (left instanceof Long) {
|
||||
return ((Number)left).longValue() - (char)right;
|
||||
} else if (left instanceof Float) {
|
||||
return ((Number)left).floatValue() - (char)right;
|
||||
} else {
|
||||
return ((Number)left).intValue() - (char)right;
|
||||
}
|
||||
}
|
||||
} else if (left instanceof Character) {
|
||||
if (right instanceof Number) {
|
||||
if (right instanceof Double) {
|
||||
return (char)left - ((Number)right).doubleValue();
|
||||
} else if (right instanceof Long) {
|
||||
return (char)left - ((Number)right).longValue();
|
||||
} else if (right instanceof Float) {
|
||||
return (char)left - ((Number)right).floatValue();
|
||||
} else {
|
||||
return (char)left - ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
return (char)left - (char)right;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [-] operation to types " +
|
||||
"[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
public static Object lsh(final Object left, final int right) {
|
||||
if (left instanceof Double || left instanceof Long || left instanceof Float) {
|
||||
return ((Number)left).longValue() << right;
|
||||
} else if (left instanceof Number) {
|
||||
return ((Number)left).intValue() << right;
|
||||
} else if (left instanceof Character) {
|
||||
return (char)left << right;
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [<<] operation to types [" + left.getClass().getCanonicalName() + "] and [int].");
|
||||
}
|
||||
|
||||
public static Object rsh(final Object left, final int right) {
|
||||
if (left instanceof Double || left instanceof Long || left instanceof Float) {
|
||||
return ((Number)left).longValue() >> right;
|
||||
} else if (left instanceof Number) {
|
||||
return ((Number)left).intValue() >> right;
|
||||
} else if (left instanceof Character) {
|
||||
return (char)left >> right;
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [>>] operation to types [" + left.getClass().getCanonicalName() + "] and [int].");
|
||||
}
|
||||
|
||||
public static Object ush(final Object left, final int right) {
|
||||
if (left instanceof Double || left instanceof Long || left instanceof Float) {
|
||||
return ((Number)left).longValue() >>> right;
|
||||
} else if (left instanceof Number) {
|
||||
return ((Number)left).intValue() >>> right;
|
||||
} else if (left instanceof Character) {
|
||||
return (char)left >>> right;
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [>>>] operation to types [" + left.getClass().getCanonicalName() + "] and [int].");
|
||||
}
|
||||
|
||||
public static Object and(final Object left, final Object right) {
|
||||
if (left instanceof Boolean && right instanceof Boolean) {
|
||||
return (boolean)left && (boolean)right;
|
||||
} else if (left instanceof Number) {
|
||||
if (right instanceof Number) {
|
||||
if (left instanceof Double || right instanceof Double ||
|
||||
left instanceof Long || right instanceof Long ||
|
||||
left instanceof Float || right instanceof Float) {
|
||||
return ((Number)left).longValue() & ((Number)right).longValue();
|
||||
} else {
|
||||
return ((Number)left).intValue() & ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
if (left instanceof Double || left instanceof Long || left instanceof Float) {
|
||||
return ((Number)left).longValue() & (char)right;
|
||||
} else {
|
||||
return ((Number)left).intValue() & (char)right;
|
||||
}
|
||||
}
|
||||
} else if (left instanceof Character) {
|
||||
if (right instanceof Number) {
|
||||
if (right instanceof Double || right instanceof Long || right instanceof Float) {
|
||||
return (char)left & ((Number)right).longValue();
|
||||
} else {
|
||||
return (char)left & ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
return (char)left & (char)right;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [&] operation to types " +
|
||||
"[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
public static Object xor(final Object left, final Object right) {
|
||||
if (left instanceof Boolean && right instanceof Boolean) {
|
||||
return (boolean)left ^ (boolean)right;
|
||||
} else if (left instanceof Number) {
|
||||
if (right instanceof Number) {
|
||||
if (left instanceof Double || right instanceof Double ||
|
||||
left instanceof Long || right instanceof Long ||
|
||||
left instanceof Float || right instanceof Float) {
|
||||
return ((Number)left).longValue() ^ ((Number)right).longValue();
|
||||
} else {
|
||||
return ((Number)left).intValue() ^ ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
if (left instanceof Double || left instanceof Long || left instanceof Float) {
|
||||
return ((Number)left).longValue() ^ (char)right;
|
||||
} else {
|
||||
return ((Number)left).intValue() ^ (char)right;
|
||||
}
|
||||
}
|
||||
} else if (left instanceof Character) {
|
||||
if (right instanceof Number) {
|
||||
if (right instanceof Double || right instanceof Long || right instanceof Float) {
|
||||
return (char)left ^ ((Number)right).longValue();
|
||||
} else {
|
||||
return (char)left ^ ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
return (char)left ^ (char)right;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [^] operation to types " +
|
||||
"[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
public static Object or(final Object left, final Object right) {
|
||||
if (left instanceof Boolean && right instanceof Boolean) {
|
||||
return (boolean)left || (boolean)right;
|
||||
} else if (left instanceof Number) {
|
||||
if (right instanceof Number) {
|
||||
if (left instanceof Double || right instanceof Double ||
|
||||
left instanceof Long || right instanceof Long ||
|
||||
left instanceof Float || right instanceof Float) {
|
||||
return ((Number)left).longValue() | ((Number)right).longValue();
|
||||
} else {
|
||||
return ((Number)left).intValue() | ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
if (left instanceof Double || left instanceof Long || left instanceof Float) {
|
||||
return ((Number)left).longValue() | (char)right;
|
||||
} else {
|
||||
return ((Number)left).intValue() | (char)right;
|
||||
}
|
||||
}
|
||||
} else if (left instanceof Character) {
|
||||
if (right instanceof Number) {
|
||||
if (right instanceof Double || right instanceof Long || right instanceof Float) {
|
||||
return (char)left | ((Number)right).longValue();
|
||||
} else {
|
||||
return (char)left | ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
return (char)left | (char)right;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [|] operation to types " +
|
||||
"[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
public static boolean eq(final Object left, final Object right) {
|
||||
if (left != null && right != null) {
|
||||
if (left instanceof Double) {
|
||||
if (right instanceof Number) {
|
||||
return (double)left == ((Number)right).doubleValue();
|
||||
} else if (right instanceof Character) {
|
||||
return (double)left == (char)right;
|
||||
}
|
||||
} else if (right instanceof Double) {
|
||||
if (left instanceof Number) {
|
||||
return ((Number)left).doubleValue() == (double)right;
|
||||
} else if (left instanceof Character) {
|
||||
return (char)left == ((Number)right).doubleValue();
|
||||
}
|
||||
} else if (left instanceof Float) {
|
||||
if (right instanceof Number) {
|
||||
return (float)left == ((Number)right).floatValue();
|
||||
} else if (right instanceof Character) {
|
||||
return (float)left == (char)right;
|
||||
}
|
||||
} else if (right instanceof Float) {
|
||||
if (left instanceof Number) {
|
||||
return ((Number)left).floatValue() == (float)right;
|
||||
} else if (left instanceof Character) {
|
||||
return (char)left == ((Number)right).floatValue();
|
||||
}
|
||||
} else if (left instanceof Long) {
|
||||
if (right instanceof Number) {
|
||||
return (long)left == ((Number)right).longValue();
|
||||
} else if (right instanceof Character) {
|
||||
return (long)left == (char)right;
|
||||
}
|
||||
} else if (right instanceof Long) {
|
||||
if (left instanceof Number) {
|
||||
return ((Number)left).longValue() == (long)right;
|
||||
} else if (left instanceof Character) {
|
||||
return (char)left == ((Number)right).longValue();
|
||||
}
|
||||
} else if (left instanceof Number) {
|
||||
if (right instanceof Number) {
|
||||
return ((Number)left).intValue() == ((Number)right).intValue();
|
||||
} else if (right instanceof Character) {
|
||||
return ((Number)left).intValue() == (char)right;
|
||||
}
|
||||
} else if (right instanceof Number && left instanceof Character) {
|
||||
return (char)left == ((Number)right).intValue();
|
||||
} else if (left instanceof Character && right instanceof Character) {
|
||||
return (char)left == (char)right;
|
||||
}
|
||||
|
||||
return left.equals(right);
|
||||
}
|
||||
|
||||
return left == null && right == null;
|
||||
}
|
||||
|
||||
public static boolean lt(final Object left, final Object right) {
|
||||
if (left instanceof Number) {
|
||||
if (right instanceof Number) {
|
||||
if (left instanceof Double || right instanceof Double) {
|
||||
return ((Number)left).doubleValue() < ((Number)right).doubleValue();
|
||||
} else if (left instanceof Float || right instanceof Float) {
|
||||
return ((Number)left).floatValue() < ((Number)right).floatValue();
|
||||
} else if (left instanceof Long || right instanceof Long) {
|
||||
return ((Number)left).longValue() < ((Number)right).longValue();
|
||||
} else {
|
||||
return ((Number)left).intValue() < ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
if (left instanceof Double) {
|
||||
return ((Number)left).doubleValue() < (char)right;
|
||||
} else if (left instanceof Long) {
|
||||
return ((Number)left).longValue() < (char)right;
|
||||
} else if (left instanceof Float) {
|
||||
return ((Number)left).floatValue() < (char)right;
|
||||
} else {
|
||||
return ((Number)left).intValue() < (char)right;
|
||||
}
|
||||
}
|
||||
} else if (left instanceof Character) {
|
||||
if (right instanceof Number) {
|
||||
if (right instanceof Double) {
|
||||
return (char)left < ((Number)right).doubleValue();
|
||||
} else if (right instanceof Long) {
|
||||
return (char)left < ((Number)right).longValue();
|
||||
} else if (right instanceof Float) {
|
||||
return (char)left < ((Number)right).floatValue();
|
||||
} else {
|
||||
return (char)left < ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
return (char)left < (char)right;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [<] operation to types " +
|
||||
"[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
public static boolean lte(final Object left, final Object right) {
|
||||
if (left instanceof Number) {
|
||||
if (right instanceof Number) {
|
||||
if (left instanceof Double || right instanceof Double) {
|
||||
return ((Number)left).doubleValue() <= ((Number)right).doubleValue();
|
||||
} else if (left instanceof Float || right instanceof Float) {
|
||||
return ((Number)left).floatValue() <= ((Number)right).floatValue();
|
||||
} else if (left instanceof Long || right instanceof Long) {
|
||||
return ((Number)left).longValue() <= ((Number)right).longValue();
|
||||
} else {
|
||||
return ((Number)left).intValue() <= ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
if (left instanceof Double) {
|
||||
return ((Number)left).doubleValue() <= (char)right;
|
||||
} else if (left instanceof Long) {
|
||||
return ((Number)left).longValue() <= (char)right;
|
||||
} else if (left instanceof Float) {
|
||||
return ((Number)left).floatValue() <= (char)right;
|
||||
} else {
|
||||
return ((Number)left).intValue() <= (char)right;
|
||||
}
|
||||
}
|
||||
} else if (left instanceof Character) {
|
||||
if (right instanceof Number) {
|
||||
if (right instanceof Double) {
|
||||
return (char)left <= ((Number)right).doubleValue();
|
||||
} else if (right instanceof Long) {
|
||||
return (char)left <= ((Number)right).longValue();
|
||||
} else if (right instanceof Float) {
|
||||
return (char)left <= ((Number)right).floatValue();
|
||||
} else {
|
||||
return (char)left <= ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
return (char)left <= (char)right;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [<=] operation to types " +
|
||||
"[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
public static boolean gt(final Object left, final Object right) {
|
||||
if (left instanceof Number) {
|
||||
if (right instanceof Number) {
|
||||
if (left instanceof Double || right instanceof Double) {
|
||||
return ((Number)left).doubleValue() > ((Number)right).doubleValue();
|
||||
} else if (left instanceof Float || right instanceof Float) {
|
||||
return ((Number)left).floatValue() > ((Number)right).floatValue();
|
||||
} else if (left instanceof Long || right instanceof Long) {
|
||||
return ((Number)left).longValue() > ((Number)right).longValue();
|
||||
} else {
|
||||
return ((Number)left).intValue() > ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
if (left instanceof Double) {
|
||||
return ((Number)left).doubleValue() > (char)right;
|
||||
} else if (left instanceof Long) {
|
||||
return ((Number)left).longValue() > (char)right;
|
||||
} else if (left instanceof Float) {
|
||||
return ((Number)left).floatValue() > (char)right;
|
||||
} else {
|
||||
return ((Number)left).intValue() > (char)right;
|
||||
}
|
||||
}
|
||||
} else if (left instanceof Character) {
|
||||
if (right instanceof Number) {
|
||||
if (right instanceof Double) {
|
||||
return (char)left > ((Number)right).doubleValue();
|
||||
} else if (right instanceof Long) {
|
||||
return (char)left > ((Number)right).longValue();
|
||||
} else if (right instanceof Float) {
|
||||
return (char)left > ((Number)right).floatValue();
|
||||
} else {
|
||||
return (char)left > ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
return (char)left > (char)right;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [>] operation to types " +
|
||||
"[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
public static boolean gte(final Object left, final Object right) {
|
||||
if (left instanceof Number) {
|
||||
if (right instanceof Number) {
|
||||
if (left instanceof Double || right instanceof Double) {
|
||||
return ((Number)left).doubleValue() >= ((Number)right).doubleValue();
|
||||
} else if (left instanceof Float || right instanceof Float) {
|
||||
return ((Number)left).floatValue() >= ((Number)right).floatValue();
|
||||
} else if (left instanceof Long || right instanceof Long) {
|
||||
return ((Number)left).longValue() >= ((Number)right).longValue();
|
||||
} else {
|
||||
return ((Number)left).intValue() >= ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
if (left instanceof Double) {
|
||||
return ((Number)left).doubleValue() >= (char)right;
|
||||
} else if (left instanceof Long) {
|
||||
return ((Number)left).longValue() >= (char)right;
|
||||
} else if (left instanceof Float) {
|
||||
return ((Number)left).floatValue() >= (char)right;
|
||||
} else {
|
||||
return ((Number)left).intValue() >= (char)right;
|
||||
}
|
||||
}
|
||||
} else if (left instanceof Character) {
|
||||
if (right instanceof Number) {
|
||||
if (right instanceof Double) {
|
||||
return (char)left >= ((Number)right).doubleValue();
|
||||
} else if (right instanceof Long) {
|
||||
return (char)left >= ((Number)right).longValue();
|
||||
} else if (right instanceof Float) {
|
||||
return (char)left >= ((Number)right).floatValue();
|
||||
} else {
|
||||
return (char)left >= ((Number)right).intValue();
|
||||
}
|
||||
} else if (right instanceof Character) {
|
||||
return (char)left >= (char)right;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ClassCastException("Cannot apply [>] operation to types " +
|
||||
"[" + left.getClass().getCanonicalName() + "] and [" + right.getClass().getCanonicalName() + "].");
|
||||
}
|
||||
|
||||
// Conversion methods for Def to primitive types.
|
||||
|
||||
|
|
|
@ -31,9 +31,9 @@ import java.lang.invoke.MutableCallSite;
|
|||
/**
|
||||
* Painless invokedynamic bootstrap for the call site.
|
||||
* <p>
|
||||
* Has 5 flavors (passed as static bootstrap parameters): dynamic method call,
|
||||
* Has 7 flavors (passed as static bootstrap parameters): dynamic method call,
|
||||
* dynamic field load (getter), and dynamic field store (setter), dynamic array load,
|
||||
* and dynamic array store.
|
||||
* dynamic array store, iterator, and method reference.
|
||||
* <p>
|
||||
* When a new type is encountered at the call site, we lookup from the appropriate
|
||||
* whitelist, and cache with a guard. If we encounter too many types, we stop caching.
|
||||
|
@ -62,6 +62,12 @@ public final class DefBootstrap {
|
|||
public static final int ITERATOR = 5;
|
||||
/** static bootstrap parameter indicating a dynamic method reference, e.g. foo::bar */
|
||||
public static final int REFERENCE = 6;
|
||||
/** static bootstrap parameter indicating a unary math operator, e.g. ~foo */
|
||||
public static final int UNARY_OPERATOR = 7;
|
||||
/** static bootstrap parameter indicating a binary math operator, e.g. foo / bar */
|
||||
public static final int BINARY_OPERATOR = 8;
|
||||
/** static bootstrap parameter indicating a shift operator, e.g. foo >> bar */
|
||||
public static final int SHIFT_OPERATOR = 9;
|
||||
|
||||
/**
|
||||
* CallSite that implements the polymorphic inlining cache (PIC).
|
||||
|
@ -83,6 +89,12 @@ public final class DefBootstrap {
|
|||
this.flavor = flavor;
|
||||
this.args = args;
|
||||
|
||||
// For operators use a monomorphic cache, fallback is fast.
|
||||
// Just start with a depth of MAX-1, to keep it a constant.
|
||||
if (flavor == UNARY_OPERATOR || flavor == BINARY_OPERATOR || flavor == SHIFT_OPERATOR) {
|
||||
depth = MAX_DEPTH - 1;
|
||||
}
|
||||
|
||||
final MethodHandle fallback = FALLBACK.bindTo(this)
|
||||
.asCollector(Object[].class, type.parameterCount())
|
||||
.asType(type);
|
||||
|
@ -98,50 +110,125 @@ public final class DefBootstrap {
|
|||
return receiver.getClass() == clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* guard method for inline caching: checks the receiver's class and the first argument
|
||||
* are the same as the cached receiver and first argument.
|
||||
*/
|
||||
static boolean checkBinary(Class<?> left, Class<?> right, Object leftObject, Object rightObject) {
|
||||
return leftObject.getClass() == left && rightObject.getClass() == right;
|
||||
}
|
||||
|
||||
/**
|
||||
* guard method for inline caching: checks the first argument is the same
|
||||
* as the cached first argument.
|
||||
*/
|
||||
static boolean checkBinaryArg(Class<?> left, Class<?> right, Object leftObject, Object rightObject) {
|
||||
return rightObject.getClass() == right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a slow lookup against the whitelist.
|
||||
*/
|
||||
private MethodHandle lookup(int flavor, Class<?> clazz, String name, Object[] args) throws Throwable {
|
||||
private MethodHandle lookup(int flavor, String name, Object[] args) throws Throwable {
|
||||
switch(flavor) {
|
||||
case METHOD_CALL:
|
||||
return Def.lookupMethod(lookup, type(), clazz, name, args, (Long) this.args[0]);
|
||||
return Def.lookupMethod(lookup, type(), args[0].getClass(), name, args, (Long) this.args[0]);
|
||||
case LOAD:
|
||||
return Def.lookupGetter(clazz, name);
|
||||
return Def.lookupGetter(args[0].getClass(), name);
|
||||
case STORE:
|
||||
return Def.lookupSetter(clazz, name);
|
||||
return Def.lookupSetter(args[0].getClass(), name);
|
||||
case ARRAY_LOAD:
|
||||
return Def.lookupArrayLoad(clazz);
|
||||
return Def.lookupArrayLoad(args[0].getClass());
|
||||
case ARRAY_STORE:
|
||||
return Def.lookupArrayStore(clazz);
|
||||
return Def.lookupArrayStore(args[0].getClass());
|
||||
case ITERATOR:
|
||||
return Def.lookupIterator(clazz);
|
||||
return Def.lookupIterator(args[0].getClass());
|
||||
case REFERENCE:
|
||||
return Def.lookupReference(lookup, (String) this.args[0], clazz, name);
|
||||
return Def.lookupReference(lookup, (String) this.args[0], args[0].getClass(), name);
|
||||
case UNARY_OPERATOR:
|
||||
case SHIFT_OPERATOR:
|
||||
// shifts are treated as unary, as java allows long arguments without a cast (but bits are ignored)
|
||||
return DefMath.lookupUnary(args[0].getClass(), name);
|
||||
case BINARY_OPERATOR:
|
||||
if (args[0] == null || args[1] == null) {
|
||||
return getGeneric(flavor, name); // can handle nulls
|
||||
} else {
|
||||
return DefMath.lookupBinary(args[0].getClass(), args[1].getClass(), name);
|
||||
}
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a permanent, generic solution that works with any parameter types, if possible.
|
||||
*/
|
||||
private MethodHandle getGeneric(int flavor, String name) throws Throwable {
|
||||
switch(flavor) {
|
||||
case UNARY_OPERATOR:
|
||||
case BINARY_OPERATOR:
|
||||
case SHIFT_OPERATOR:
|
||||
return DefMath.lookupGeneric(name);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a new type is encountered (or, when we have encountered more than {@code MAX_DEPTH}
|
||||
* types at this call site and given up on caching).
|
||||
*/
|
||||
@SuppressForbidden(reason = "slow path")
|
||||
Object fallback(Object[] args) throws Throwable {
|
||||
final MethodType type = type();
|
||||
final Object receiver = args[0];
|
||||
final Class<?> receiverClass = receiver.getClass();
|
||||
final MethodHandle target = lookup(flavor, receiverClass, name, args).asType(type);
|
||||
|
||||
if (depth >= MAX_DEPTH) {
|
||||
// revert to a vtable call
|
||||
setTarget(target);
|
||||
return target.invokeWithArguments(args);
|
||||
// caching defeated
|
||||
MethodHandle generic = getGeneric(flavor, name);
|
||||
if (generic != null) {
|
||||
setTarget(generic.asType(type()));
|
||||
return generic.invokeWithArguments(args);
|
||||
} else {
|
||||
return lookup(flavor, name, args).invokeWithArguments(args);
|
||||
}
|
||||
}
|
||||
|
||||
MethodHandle test = CHECK_CLASS.bindTo(receiverClass);
|
||||
test = test.asType(test.type().changeParameterType(0, type.parameterType(0)));
|
||||
final MethodType type = type();
|
||||
final MethodHandle target = lookup(flavor, name, args).asType(type);
|
||||
|
||||
final MethodHandle guard = MethodHandles.guardWithTest(test, target, getTarget());
|
||||
final MethodHandle test;
|
||||
if (flavor == BINARY_OPERATOR || flavor == SHIFT_OPERATOR) {
|
||||
// some binary operators support nulls, we handle them separate
|
||||
Class<?> clazz0 = args[0] == null ? null : args[0].getClass();
|
||||
Class<?> clazz1 = args[1] == null ? null : args[1].getClass();
|
||||
if (type.parameterType(1) != Object.class) {
|
||||
// case 1: only the receiver is unknown, just check that
|
||||
MethodHandle unaryTest = CHECK_CLASS.bindTo(clazz0);
|
||||
test = unaryTest.asType(unaryTest.type()
|
||||
.changeParameterType(0, type.parameterType(0)));
|
||||
} else if (type.parameterType(0) != Object.class) {
|
||||
// case 2: only the argument is unknown, just check that
|
||||
MethodHandle unaryTest = CHECK_BINARY_ARG.bindTo(clazz0).bindTo(clazz1);
|
||||
test = unaryTest.asType(unaryTest.type()
|
||||
.changeParameterType(0, type.parameterType(0))
|
||||
.changeParameterType(1, type.parameterType(1)));
|
||||
} else {
|
||||
// case 3: check both receiver and argument
|
||||
MethodHandle binaryTest = CHECK_BINARY.bindTo(clazz0).bindTo(clazz1);
|
||||
test = binaryTest.asType(binaryTest.type()
|
||||
.changeParameterType(0, type.parameterType(0))
|
||||
.changeParameterType(1, type.parameterType(1)));
|
||||
}
|
||||
} else {
|
||||
MethodHandle receiverTest = CHECK_CLASS.bindTo(args[0].getClass());
|
||||
test = receiverTest.asType(receiverTest.type()
|
||||
.changeParameterType(0, type.parameterType(0)));
|
||||
}
|
||||
|
||||
MethodHandle guard = MethodHandles.guardWithTest(test, target, getTarget());
|
||||
// very special cases, where even the receiver can be null (see JLS rules for string concat)
|
||||
// we wrap + with an NPE catcher, and use our generic method in that case.
|
||||
if (flavor == BINARY_OPERATOR && "add".equals(name) || "eq".equals(name)) {
|
||||
MethodHandle handler = MethodHandles.dropArguments(getGeneric(flavor, name).asType(type()), 0, NullPointerException.class);
|
||||
guard = MethodHandles.catchException(guard, NullPointerException.class, handler);
|
||||
}
|
||||
|
||||
depth++;
|
||||
|
||||
|
@ -150,12 +237,18 @@ public final class DefBootstrap {
|
|||
}
|
||||
|
||||
private static final MethodHandle CHECK_CLASS;
|
||||
private static final MethodHandle CHECK_BINARY;
|
||||
private static final MethodHandle CHECK_BINARY_ARG;
|
||||
private static final MethodHandle FALLBACK;
|
||||
static {
|
||||
final Lookup lookup = MethodHandles.lookup();
|
||||
try {
|
||||
CHECK_CLASS = lookup.findStatic(lookup.lookupClass(), "checkClass",
|
||||
MethodType.methodType(boolean.class, Class.class, Object.class));
|
||||
CHECK_BINARY = lookup.findStatic(lookup.lookupClass(), "checkBinary",
|
||||
MethodType.methodType(boolean.class, Class.class, Class.class, Object.class, Object.class));
|
||||
CHECK_BINARY_ARG = lookup.findStatic(lookup.lookupClass(), "checkBinaryArg",
|
||||
MethodType.methodType(boolean.class, Class.class, Class.class, Object.class, Object.class));
|
||||
FALLBACK = lookup.findVirtual(lookup.lookupClass(), "fallback",
|
||||
MethodType.methodType(Object.class, Object[].class));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -35,15 +35,7 @@ import java.util.Deque;
|
|||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.painless.WriterConstants.CHAR_TO_STRING;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_ADD_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_AND_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_DIV_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_LSH_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_MUL_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_OR_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_REM_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_RSH_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_SUB_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_HANDLE;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_TO_BOOLEAN;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_TO_BYTE_EXPLICIT;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_TO_BYTE_IMPLICIT;
|
||||
|
@ -59,9 +51,7 @@ import static org.elasticsearch.painless.WriterConstants.DEF_TO_LONG_EXPLICIT;
|
|||
import static org.elasticsearch.painless.WriterConstants.DEF_TO_LONG_IMPLICIT;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_TO_SHORT_EXPLICIT;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_TO_SHORT_IMPLICIT;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_USH_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_UTIL_TYPE;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_XOR_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.INDY_STRING_CONCAT_BOOTSTRAP_HANDLE;
|
||||
import static org.elasticsearch.painless.WriterConstants.MAX_INDY_STRING_CONCAT_ARGS;
|
||||
import static org.elasticsearch.painless.WriterConstants.PAINLESS_ERROR_TYPE;
|
||||
|
@ -283,18 +273,44 @@ public final class MethodWriter extends GeneratorAdapter {
|
|||
}
|
||||
|
||||
if (sort == Sort.DEF) {
|
||||
// XXX: move this out, so we can populate descriptor with what we really have (instead of casts/boxing!)
|
||||
org.objectweb.asm.Type objectType = org.objectweb.asm.Type.getType(Object.class);
|
||||
org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(objectType, objectType, objectType);
|
||||
|
||||
switch (operation) {
|
||||
case MUL: invokeStatic(DEF_UTIL_TYPE, DEF_MUL_CALL); break;
|
||||
case DIV: invokeStatic(DEF_UTIL_TYPE, DEF_DIV_CALL); break;
|
||||
case REM: invokeStatic(DEF_UTIL_TYPE, DEF_REM_CALL); break;
|
||||
case ADD: invokeStatic(DEF_UTIL_TYPE, DEF_ADD_CALL); break;
|
||||
case SUB: invokeStatic(DEF_UTIL_TYPE, DEF_SUB_CALL); break;
|
||||
case LSH: invokeStatic(DEF_UTIL_TYPE, DEF_LSH_CALL); break;
|
||||
case USH: invokeStatic(DEF_UTIL_TYPE, DEF_RSH_CALL); break;
|
||||
case RSH: invokeStatic(DEF_UTIL_TYPE, DEF_USH_CALL); break;
|
||||
case BWAND: invokeStatic(DEF_UTIL_TYPE, DEF_AND_CALL); break;
|
||||
case XOR: invokeStatic(DEF_UTIL_TYPE, DEF_XOR_CALL); break;
|
||||
case BWOR: invokeStatic(DEF_UTIL_TYPE, DEF_OR_CALL); break;
|
||||
case MUL:
|
||||
invokeDynamic("mul", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
break;
|
||||
case DIV:
|
||||
invokeDynamic("div", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
break;
|
||||
case REM:
|
||||
invokeDynamic("rem", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
break;
|
||||
case ADD:
|
||||
invokeDynamic("add", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
break;
|
||||
case SUB:
|
||||
invokeDynamic("sub", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
break;
|
||||
case LSH:
|
||||
invokeDynamic("lsh", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.SHIFT_OPERATOR);
|
||||
break;
|
||||
case USH:
|
||||
invokeDynamic("ush", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.SHIFT_OPERATOR);
|
||||
break;
|
||||
case RSH:
|
||||
invokeDynamic("rsh", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.SHIFT_OPERATOR);
|
||||
break;
|
||||
case BWAND:
|
||||
invokeDynamic("and", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
break;
|
||||
case XOR:
|
||||
invokeDynamic("xor", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
break;
|
||||
case BWOR:
|
||||
invokeDynamic("or", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
break;
|
||||
default:
|
||||
throw location.createError(new IllegalStateException("Illegal tree structure."));
|
||||
}
|
||||
|
|
|
@ -37,13 +37,5 @@ public class Utility {
|
|||
return value.charAt(0);
|
||||
}
|
||||
|
||||
public static boolean checkEquals(final Object left, final Object right) {
|
||||
if (left != null) {
|
||||
return left.equals(right);
|
||||
}
|
||||
|
||||
return right == null || right.equals(null);
|
||||
}
|
||||
|
||||
private Utility() {}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.lang.invoke.MethodType;
|
|||
import java.util.BitSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
|
@ -102,24 +103,6 @@ public final class WriterConstants {
|
|||
public final static Method DEF_TO_LONG_EXPLICIT = getAsmMethod(long.class , "DefTolongExplicit" , Object.class);
|
||||
public final static Method DEF_TO_FLOAT_EXPLICIT = getAsmMethod(float.class , "DefTofloatExplicit" , Object.class);
|
||||
public final static Method DEF_TO_DOUBLE_EXPLICIT = getAsmMethod(double.class , "DefTodoubleExplicit", Object.class);
|
||||
public final static Method DEF_NOT_CALL = getAsmMethod(Object.class , "not", Object.class);
|
||||
public final static Method DEF_NEG_CALL = getAsmMethod(Object.class , "neg", Object.class);
|
||||
public final static Method DEF_MUL_CALL = getAsmMethod(Object.class , "mul", Object.class, Object.class);
|
||||
public final static Method DEF_DIV_CALL = getAsmMethod(Object.class , "div", Object.class, Object.class);
|
||||
public final static Method DEF_REM_CALL = getAsmMethod(Object.class , "rem", Object.class, Object.class);
|
||||
public final static Method DEF_ADD_CALL = getAsmMethod(Object.class , "add", Object.class, Object.class);
|
||||
public final static Method DEF_SUB_CALL = getAsmMethod(Object.class , "sub", Object.class, Object.class);
|
||||
public final static Method DEF_LSH_CALL = getAsmMethod(Object.class , "lsh", Object.class, int.class);
|
||||
public final static Method DEF_RSH_CALL = getAsmMethod(Object.class , "rsh", Object.class, int.class);
|
||||
public final static Method DEF_USH_CALL = getAsmMethod(Object.class , "ush", Object.class, int.class);
|
||||
public final static Method DEF_AND_CALL = getAsmMethod(Object.class , "and", Object.class, Object.class);
|
||||
public final static Method DEF_XOR_CALL = getAsmMethod(Object.class , "xor", Object.class, Object.class);
|
||||
public final static Method DEF_OR_CALL = getAsmMethod(Object.class , "or" , Object.class, Object.class);
|
||||
public final static Method DEF_EQ_CALL = getAsmMethod(boolean.class, "eq" , Object.class, Object.class);
|
||||
public final static Method DEF_LT_CALL = getAsmMethod(boolean.class, "lt" , Object.class, Object.class);
|
||||
public final static Method DEF_LTE_CALL = getAsmMethod(boolean.class, "lte", Object.class, Object.class);
|
||||
public final static Method DEF_GT_CALL = getAsmMethod(boolean.class, "gt" , Object.class, Object.class);
|
||||
public final static Method DEF_GTE_CALL = getAsmMethod(boolean.class, "gte", Object.class, Object.class);
|
||||
|
||||
/** invokedynamic bootstrap for lambda expression/method references */
|
||||
public final static MethodType LAMBDA_BOOTSTRAP_TYPE =
|
||||
|
@ -163,7 +146,8 @@ public final class WriterConstants {
|
|||
public final static Method STRINGBUILDER_APPEND_OBJECT = getAsmMethod(StringBuilder.class, "append", Object.class);
|
||||
public final static Method STRINGBUILDER_TOSTRING = getAsmMethod(String.class, "toString");
|
||||
|
||||
public final static Method CHECKEQUALS = getAsmMethod(boolean.class, "checkEquals", Object.class, Object.class);
|
||||
public final static Type OBJECTS_TYPE = Type.getType(Objects.class);
|
||||
public final static Method EQUALS = getAsmMethod(boolean.class, "equals", Object.class, Object.class);
|
||||
|
||||
private static Method getAsmMethod(final Class<?> rtype, final String name, final Class<?>... ptypes) {
|
||||
return new Method(name, MethodType.methodType(rtype, ptypes).toMethodDescriptorString());
|
||||
|
|
|
@ -284,22 +284,27 @@ public final class EBinary extends AExpression {
|
|||
left.analyze(variables);
|
||||
right.analyze(variables);
|
||||
|
||||
Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
|
||||
Type lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false);
|
||||
Type rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false);
|
||||
|
||||
if (promote == null) {
|
||||
if (lhspromote == null || rhspromote == null) {
|
||||
throw createError(new ClassCastException("Cannot apply left shift [<<] to types " +
|
||||
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
|
||||
}
|
||||
|
||||
left.expected = promote;
|
||||
left.expected = lhspromote;
|
||||
if (rhspromote.sort == Sort.LONG) {
|
||||
right.expected = Definition.INT_TYPE;
|
||||
right.explicit = true;
|
||||
} else {
|
||||
right.expected = rhspromote;
|
||||
}
|
||||
|
||||
left = left.cast(variables);
|
||||
right = right.cast(variables);
|
||||
|
||||
if (left.constant != null && right.constant != null) {
|
||||
Sort sort = promote.sort;
|
||||
Sort sort = lhspromote.sort;
|
||||
|
||||
if (sort == Sort.INT) {
|
||||
constant = (int)left.constant << (int)right.constant;
|
||||
|
@ -310,29 +315,34 @@ public final class EBinary extends AExpression {
|
|||
}
|
||||
}
|
||||
|
||||
actual = promote;
|
||||
actual = lhspromote;
|
||||
}
|
||||
|
||||
private void analyzeRSH(Locals variables) {
|
||||
left.analyze(variables);
|
||||
right.analyze(variables);
|
||||
|
||||
Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
|
||||
Type lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false);
|
||||
Type rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false);
|
||||
|
||||
if (promote == null) {
|
||||
if (lhspromote == null || rhspromote == null) {
|
||||
throw createError(new ClassCastException("Cannot apply right shift [>>] to types " +
|
||||
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
|
||||
}
|
||||
|
||||
left.expected = promote;
|
||||
left.expected = lhspromote;
|
||||
if (rhspromote.sort == Sort.LONG) {
|
||||
right.expected = Definition.INT_TYPE;
|
||||
right.explicit = true;
|
||||
} else {
|
||||
right.expected = rhspromote;
|
||||
}
|
||||
|
||||
left = left.cast(variables);
|
||||
right = right.cast(variables);
|
||||
|
||||
if (left.constant != null && right.constant != null) {
|
||||
Sort sort = promote.sort;
|
||||
Sort sort = lhspromote.sort;
|
||||
|
||||
if (sort == Sort.INT) {
|
||||
constant = (int)left.constant >> (int)right.constant;
|
||||
|
@ -343,29 +353,34 @@ public final class EBinary extends AExpression {
|
|||
}
|
||||
}
|
||||
|
||||
actual = promote;
|
||||
actual = lhspromote;
|
||||
}
|
||||
|
||||
private void analyzeUSH(Locals variables) {
|
||||
left.analyze(variables);
|
||||
right.analyze(variables);
|
||||
|
||||
Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
|
||||
Type lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false);
|
||||
Type rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false);
|
||||
|
||||
if (promote == null) {
|
||||
if (lhspromote == null || rhspromote == null) {
|
||||
throw createError(new ClassCastException("Cannot apply unsigned shift [>>>] to types " +
|
||||
"[" + left.actual.name + "] and [" + right.actual.name + "]."));
|
||||
}
|
||||
|
||||
left.expected = promote;
|
||||
left.expected = lhspromote;
|
||||
if (rhspromote.sort == Sort.LONG) {
|
||||
right.expected = Definition.INT_TYPE;
|
||||
right.explicit = true;
|
||||
} else {
|
||||
right.expected = rhspromote;
|
||||
}
|
||||
|
||||
left = left.cast(variables);
|
||||
right = right.cast(variables);
|
||||
|
||||
if (left.constant != null && right.constant != null) {
|
||||
Sort sort = promote.sort;
|
||||
Sort sort = lhspromote.sort;
|
||||
|
||||
if (sort == Sort.INT) {
|
||||
constant = (int)left.constant >>> (int)right.constant;
|
||||
|
@ -376,7 +391,7 @@ public final class EBinary extends AExpression {
|
|||
}
|
||||
}
|
||||
|
||||
actual = promote;
|
||||
actual = lhspromote;
|
||||
}
|
||||
|
||||
private void analyzeBWAnd(Locals variables) {
|
||||
|
|
|
@ -87,7 +87,7 @@ public class ECapturingFunctionRef extends AExpression {
|
|||
// typed interface, dynamic implementation
|
||||
writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.slot);
|
||||
String descriptor = Type.getMethodType(expected.type, captured.type.type).getDescriptor();
|
||||
writer.invokeDynamic(call, descriptor, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.REFERENCE, expected.name);
|
||||
writer.invokeDynamic(call, descriptor, DEF_BOOTSTRAP_HANDLE, DefBootstrap.REFERENCE, expected.name);
|
||||
} else {
|
||||
// typed interface, typed implementation
|
||||
writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.slot);
|
||||
|
|
|
@ -24,19 +24,15 @@ import org.elasticsearch.painless.Definition.Sort;
|
|||
import org.elasticsearch.painless.Definition.Type;
|
||||
import org.elasticsearch.painless.Location;
|
||||
import org.elasticsearch.painless.AnalyzerCaster;
|
||||
import org.elasticsearch.painless.DefBootstrap;
|
||||
import org.elasticsearch.painless.Operation;
|
||||
import org.elasticsearch.painless.Locals;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.elasticsearch.painless.MethodWriter;
|
||||
|
||||
import static org.elasticsearch.painless.WriterConstants.CHECKEQUALS;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_EQ_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_GTE_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_GT_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_LTE_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_LT_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_UTIL_TYPE;
|
||||
import static org.elasticsearch.painless.WriterConstants.UTILITY_TYPE;
|
||||
import static org.elasticsearch.painless.WriterConstants.OBJECTS_TYPE;
|
||||
import static org.elasticsearch.painless.WriterConstants.EQUALS;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_HANDLE;
|
||||
|
||||
/**
|
||||
* Represents a comparison expression.
|
||||
|
@ -456,11 +452,15 @@ public final class EComp extends AExpression {
|
|||
|
||||
break;
|
||||
case DEF:
|
||||
// XXX: move this out, so we can populate descriptor with what we really have (instead of casts/boxing!)
|
||||
org.objectweb.asm.Type booleanType = org.objectweb.asm.Type.getType(boolean.class);
|
||||
org.objectweb.asm.Type objectType = org.objectweb.asm.Type.getType(Object.class);
|
||||
org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(booleanType, objectType, objectType);
|
||||
if (eq) {
|
||||
if (right.isNull) {
|
||||
writer.ifNull(jump);
|
||||
} else if (!left.isNull && (operation == Operation.EQ || operation == Operation.NE)) {
|
||||
writer.invokeStatic(DEF_UTIL_TYPE, DEF_EQ_CALL);
|
||||
writer.invokeDynamic("eq", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
writejump = false;
|
||||
} else {
|
||||
writer.ifCmp(rtype, MethodWriter.EQ, jump);
|
||||
|
@ -469,22 +469,22 @@ public final class EComp extends AExpression {
|
|||
if (right.isNull) {
|
||||
writer.ifNonNull(jump);
|
||||
} else if (!left.isNull && (operation == Operation.EQ || operation == Operation.NE)) {
|
||||
writer.invokeStatic(DEF_UTIL_TYPE, DEF_EQ_CALL);
|
||||
writer.invokeDynamic("eq", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
writer.ifZCmp(MethodWriter.EQ, jump);
|
||||
} else {
|
||||
writer.ifCmp(rtype, MethodWriter.NE, jump);
|
||||
}
|
||||
} else if (lt) {
|
||||
writer.invokeStatic(DEF_UTIL_TYPE, DEF_LT_CALL);
|
||||
writer.invokeDynamic("lt", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
writejump = false;
|
||||
} else if (lte) {
|
||||
writer.invokeStatic(DEF_UTIL_TYPE, DEF_LTE_CALL);
|
||||
writer.invokeDynamic("lte", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
writejump = false;
|
||||
} else if (gt) {
|
||||
writer.invokeStatic(DEF_UTIL_TYPE, DEF_GT_CALL);
|
||||
writer.invokeDynamic("gt", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
writejump = false;
|
||||
} else if (gte) {
|
||||
writer.invokeStatic(DEF_UTIL_TYPE, DEF_GTE_CALL);
|
||||
writer.invokeDynamic("gte", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.BINARY_OPERATOR);
|
||||
writejump = false;
|
||||
} else {
|
||||
throw createError(new IllegalStateException("Illegal tree structure."));
|
||||
|
@ -500,7 +500,7 @@ public final class EComp extends AExpression {
|
|||
if (right.isNull) {
|
||||
writer.ifNull(jump);
|
||||
} else if (operation == Operation.EQ || operation == Operation.NE) {
|
||||
writer.invokeStatic(UTILITY_TYPE, CHECKEQUALS);
|
||||
writer.invokeStatic(OBJECTS_TYPE, EQUALS);
|
||||
|
||||
if (branch) {
|
||||
writer.ifZCmp(MethodWriter.NE, jump);
|
||||
|
@ -514,7 +514,7 @@ public final class EComp extends AExpression {
|
|||
if (right.isNull) {
|
||||
writer.ifNonNull(jump);
|
||||
} else if (operation == Operation.EQ || operation == Operation.NE) {
|
||||
writer.invokeStatic(UTILITY_TYPE, CHECKEQUALS);
|
||||
writer.invokeStatic(OBJECTS_TYPE, EQUALS);
|
||||
writer.ifZCmp(MethodWriter.EQ, jump);
|
||||
} else {
|
||||
writer.ifCmp(rtype, MethodWriter.NE, jump);
|
||||
|
|
|
@ -24,14 +24,13 @@ import org.elasticsearch.painless.Location;
|
|||
import org.elasticsearch.painless.Definition.Sort;
|
||||
import org.elasticsearch.painless.Definition.Type;
|
||||
import org.elasticsearch.painless.AnalyzerCaster;
|
||||
import org.elasticsearch.painless.DefBootstrap;
|
||||
import org.elasticsearch.painless.Operation;
|
||||
import org.elasticsearch.painless.Locals;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.elasticsearch.painless.MethodWriter;
|
||||
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_NEG_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_NOT_CALL;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_UTIL_TYPE;
|
||||
import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_HANDLE;
|
||||
|
||||
/**
|
||||
* Represents a unary math expression.
|
||||
|
@ -194,7 +193,8 @@ public final class EUnary extends AExpression {
|
|||
|
||||
if (operation == Operation.BWNOT) {
|
||||
if (sort == Sort.DEF) {
|
||||
writer.invokeStatic(DEF_UTIL_TYPE, DEF_NOT_CALL);
|
||||
org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(expected.type, child.actual.type);
|
||||
writer.invokeDynamic("not", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.UNARY_OPERATOR);
|
||||
} else {
|
||||
if (sort == Sort.INT) {
|
||||
writer.push(-1);
|
||||
|
@ -208,11 +208,17 @@ public final class EUnary extends AExpression {
|
|||
}
|
||||
} else if (operation == Operation.SUB) {
|
||||
if (sort == Sort.DEF) {
|
||||
writer.invokeStatic(DEF_UTIL_TYPE, DEF_NEG_CALL);
|
||||
org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(expected.type, child.actual.type);
|
||||
writer.invokeDynamic("neg", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.UNARY_OPERATOR);
|
||||
} else {
|
||||
writer.math(MethodWriter.NEG, type);
|
||||
}
|
||||
} else if (operation != Operation.ADD) {
|
||||
} else if (operation == Operation.ADD) {
|
||||
if (sort == Sort.DEF) {
|
||||
org.objectweb.asm.Type descriptor = org.objectweb.asm.Type.getMethodType(expected.type, child.actual.type);
|
||||
writer.invokeDynamic("plus", descriptor.getDescriptor(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.UNARY_OPERATOR);
|
||||
}
|
||||
} else {
|
||||
throw createError(new IllegalStateException("Illegal tree structure."));
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ final class LDefArray extends ALink implements IDefLink {
|
|||
writer.writeDebugInfo(location);
|
||||
|
||||
String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type, index.actual.type);
|
||||
writer.invokeDynamic("arrayLoad", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_LOAD);
|
||||
writer.invokeDynamic("arrayLoad", desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.ARRAY_LOAD);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -70,6 +70,6 @@ final class LDefArray extends ALink implements IDefLink {
|
|||
writer.writeDebugInfo(location);
|
||||
|
||||
String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type, index.actual.type, after.type);
|
||||
writer.invokeDynamic("arrayStore", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_STORE);
|
||||
writer.invokeDynamic("arrayStore", desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.ARRAY_STORE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ final class LDefCall extends ALink implements IDefLink {
|
|||
// return value
|
||||
signature.append(after.type.getDescriptor());
|
||||
|
||||
writer.invokeDynamic(name, signature.toString(), DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.METHOD_CALL, recipe);
|
||||
writer.invokeDynamic(name, signature.toString(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.METHOD_CALL, recipe);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -59,7 +59,7 @@ final class LDefField extends ALink implements IDefLink {
|
|||
writer.writeDebugInfo(location);
|
||||
|
||||
String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type);
|
||||
writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.LOAD);
|
||||
writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.LOAD);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -67,6 +67,6 @@ final class LDefField extends ALink implements IDefLink {
|
|||
writer.writeDebugInfo(location);
|
||||
|
||||
String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type, after.type);
|
||||
writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.STORE);
|
||||
writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.STORE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -195,7 +195,7 @@ public class SEach extends AStatement {
|
|||
if (method == null) {
|
||||
Type itr = Definition.getType("Iterator");
|
||||
String desc = org.objectweb.asm.Type.getMethodDescriptor(itr.type, Definition.DEF_TYPE.type);
|
||||
writer.invokeDynamic("iterator", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ITERATOR);
|
||||
writer.invokeDynamic("iterator", desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.ITERATOR);
|
||||
} else if (java.lang.reflect.Modifier.isInterface(method.owner.clazz.getModifiers())) {
|
||||
writer.invokeInterface(method.owner.type, method.method);
|
||||
} else {
|
||||
|
|
|
@ -45,4 +45,13 @@ public class AndTests extends ScriptTestCase {
|
|||
assertEquals(5L & -12L, exec("return 5L & -12L;"));
|
||||
assertEquals(7L & 15L & 3L, exec("return 7L & 15L & 3L;"));
|
||||
}
|
||||
|
||||
public void testIllegal() throws Exception {
|
||||
expectScriptThrows(ClassCastException.class, () -> {
|
||||
exec("float x = (float)4; int y = 1; return x & y");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, () -> {
|
||||
exec("double x = (double)4; int y = 1; return x & y");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,13 +45,12 @@ public class BinaryOperatorTests extends ScriptTestCase {
|
|||
}
|
||||
|
||||
public void testLongShifts() {
|
||||
// note: we always promote the results of shifts too (unlike java)
|
||||
assertEquals(1L << 2, exec("long x = 1L; int y = 2; return x << y;"));
|
||||
assertEquals(1L << 2L, exec("long x = 1L; long y = 2L; return x << y;"));
|
||||
assertEquals(4L >> 2L, exec("long x = 4L; long y = 2L; return x >> y;"));
|
||||
assertEquals(1 << 2L, exec("int x = 1; long y = 2L; return x << y;"));
|
||||
assertEquals(4 >> 2L, exec("int x = 4; long y = 2L; return x >> y;"));
|
||||
assertEquals(4L >> 2, exec("long x = 4L; int y = 2; return x >> y;"));
|
||||
assertEquals(-1L >>> 29, exec("long x = -1L; int y = 29; return x >>> y;"));
|
||||
assertEquals(-1L >>> 29L, exec("long x = -1L; long y = 29L; return x >>> y;"));
|
||||
assertEquals(-1 >>> 29L, exec("int x = -1; long y = 29L; return x >>> y;"));
|
||||
}
|
||||
|
||||
public void testLongShiftsConst() {
|
||||
|
@ -63,6 +62,36 @@ public class BinaryOperatorTests extends ScriptTestCase {
|
|||
assertEquals(-1 >>> 29L, exec("return -1 >>> 29L;"));
|
||||
}
|
||||
|
||||
public void testBogusShifts() {
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("long x = 1L; float y = 2; return x << y;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("int x = 1; double y = 2L; return x << y;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("float x = 1F; int y = 2; return x << y;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("double x = 1D; int y = 2L; return x << y;");
|
||||
});
|
||||
}
|
||||
|
||||
public void testBogusShiftsConst() {
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("return 1L << 2F;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("return 1L << 2.0;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("return 1F << 2;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("return 1D << 2L");
|
||||
});
|
||||
}
|
||||
|
||||
public void testMixedTypes() {
|
||||
assertEquals(8, exec("int x = 4; char y = 2; return x*y;"));
|
||||
assertEquals(0.5, exec("double x = 1; float y = 2; return x / y;"));
|
||||
|
|
|
@ -23,6 +23,8 @@ import java.lang.invoke.CallSite;
|
|||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
|
@ -90,6 +92,19 @@ public class DefBootstrapTests extends ESTestCase {
|
|||
assertDepthEquals(site, 5);
|
||||
}
|
||||
|
||||
/** test that we really revert to a "generic" method that can handle any receiver types */
|
||||
public void testMegamorphic() throws Throwable {
|
||||
DefBootstrap.PIC site = (DefBootstrap.PIC) DefBootstrap.bootstrap(MethodHandles.publicLookup(),
|
||||
"size",
|
||||
MethodType.methodType(int.class, Object.class),
|
||||
DefBootstrap.METHOD_CALL, 0L);
|
||||
site.depth = DefBootstrap.PIC.MAX_DEPTH; // mark megamorphic
|
||||
MethodHandle handle = site.dynamicInvoker();
|
||||
// arguments are cast to object here, or IDE compilers eat it :)
|
||||
assertEquals(2, handle.invoke((Object) Arrays.asList("1", "2")));
|
||||
assertEquals(1, handle.invoke((Object) Collections.singletonMap("a", "b")));
|
||||
}
|
||||
|
||||
static void assertDepthEquals(CallSite site, int expected) {
|
||||
DefBootstrap.PIC dsite = (DefBootstrap.PIC) site;
|
||||
assertEquals(expected, dsite.depth);
|
||||
|
|
|
@ -50,6 +50,16 @@ public class DefOperationTests extends ScriptTestCase {
|
|||
assertEquals(-1.0, exec("def x = 1.0; return -x"));
|
||||
}
|
||||
|
||||
public void testPlus() {
|
||||
assertEquals(-1, exec("def x = (byte)-1; return +x"));
|
||||
assertEquals(-1, exec("def x = (short)-1; return +x"));
|
||||
assertEquals(65535, exec("def x = (char)-1; return +x"));
|
||||
assertEquals(-1, exec("def x = -1; return +x"));
|
||||
assertEquals(-1L, exec("def x = -1L; return +x"));
|
||||
assertEquals(-1.0F, exec("def x = -1F; return +x"));
|
||||
assertEquals(-1.0D, exec("def x = -1.0; return +x"));
|
||||
}
|
||||
|
||||
public void testMul() {
|
||||
assertEquals(4, exec("def x = (byte)2; def y = (byte)2; return x * y"));
|
||||
assertEquals(4, exec("def x = (short)2; def y = (byte)2; return x * y"));
|
||||
|
@ -314,6 +324,29 @@ public class DefOperationTests extends ScriptTestCase {
|
|||
assertEquals(2D, exec("def x = (double)1; def y = (double)1; return x + y"));
|
||||
}
|
||||
|
||||
public void testAddConcat() {
|
||||
assertEquals("a" + (byte)2, exec("def x = 'a'; def y = (byte)2; return x + y"));
|
||||
assertEquals("a" + (short)2, exec("def x = 'a'; def y = (short)2; return x + y"));
|
||||
assertEquals("a" + (char)2, exec("def x = 'a'; def y = (char)2; return x + y"));
|
||||
assertEquals("a" + 2, exec("def x = 'a'; def y = (int)2; return x + y"));
|
||||
assertEquals("a" + 2L, exec("def x = 'a'; def y = (long)2; return x + y"));
|
||||
assertEquals("a" + 2F, exec("def x = 'a'; def y = (float)2; return x + y"));
|
||||
assertEquals("a" + 2D, exec("def x = 'a'; def y = (double)2; return x + y"));
|
||||
assertEquals("ab", exec("def x = 'a'; def y = 'b'; return x + y"));
|
||||
assertEquals((byte)2 + "a", exec("def x = 'a'; def y = (byte)2; return y + x"));
|
||||
assertEquals((short)2 + "a", exec("def x = 'a'; def y = (short)2; return y + x"));
|
||||
assertEquals((char)2 + "a", exec("def x = 'a'; def y = (char)2; return y + x"));
|
||||
assertEquals(2 + "a", exec("def x = 'a'; def y = (int)2; return y + x"));
|
||||
assertEquals(2L + "a", exec("def x = 'a'; def y = (long)2; return y + x"));
|
||||
assertEquals(2F + "a", exec("def x = 'a'; def y = (float)2; return y + x"));
|
||||
assertEquals(2D + "a", exec("def x = 'a'; def y = (double)2; return y + x"));
|
||||
assertEquals("anull", exec("def x = 'a'; def y = null; return x + y"));
|
||||
assertEquals("nullb", exec("def x = null; def y = 'b'; return x + y"));
|
||||
expectScriptThrows(NullPointerException.class, () -> {
|
||||
exec("def x = null; def y = null; return x + y");
|
||||
});
|
||||
}
|
||||
|
||||
public void testSub() {
|
||||
assertEquals(0, exec("def x = (byte)1; def y = (byte)1; return x - y"));
|
||||
assertEquals(0, exec("def x = (short)1; def y = (byte)1; return x - y"));
|
||||
|
@ -386,64 +419,36 @@ public class DefOperationTests extends ScriptTestCase {
|
|||
assertEquals(2, exec("def x = (char)1; def y = (byte)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (int)1; def y = (byte)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (long)1; def y = (byte)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (float)1; def y = (byte)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (double)1; def y = (byte)1; return x << y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)1; def y = (short)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (short)1; def y = (short)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (char)1; def y = (short)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (int)1; def y = (short)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (long)1; def y = (short)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (float)1; def y = (short)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (double)1; def y = (short)1; return x << y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)1; def y = (char)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (short)1; def y = (char)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (char)1; def y = (char)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (int)1; def y = (char)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (long)1; def y = (char)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (float)1; def y = (char)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (double)1; def y = (char)1; return x << y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)1; def y = (int)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (short)1; def y = (int)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (char)1; def y = (int)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (int)1; def y = (int)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (long)1; def y = (int)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (float)1; def y = (int)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (double)1; def y = (int)1; return x << y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)1; def y = (long)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (short)1; def y = (long)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (char)1; def y = (long)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (int)1; def y = (long)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (long)1; def y = (long)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (float)1; def y = (long)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (double)1; def y = (long)1; return x << y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)1; def y = (float)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (short)1; def y = (float)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (char)1; def y = (float)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (int)1; def y = (float)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (long)1; def y = (float)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (float)1; def y = (float)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (double)1; def y = (float)1; return x << y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)1; def y = (double)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (short)1; def y = (double)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (char)1; def y = (double)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (int)1; def y = (double)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (long)1; def y = (double)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (float)1; def y = (double)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (double)1; def y = (double)1; return x << y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)1; def y = (byte)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (short)1; def y = (short)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (char)1; def y = (char)1; return x << y"));
|
||||
assertEquals(2, exec("def x = (int)1; def y = (int)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (long)1; def y = (long)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (float)1; def y = (float)1; return x << y"));
|
||||
assertEquals(2L, exec("def x = (double)1; def y = (double)1; return x << y"));
|
||||
}
|
||||
|
||||
public void testRsh() {
|
||||
|
@ -452,64 +457,36 @@ public class DefOperationTests extends ScriptTestCase {
|
|||
assertEquals(2, exec("def x = (char)4; def y = (byte)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (byte)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (byte)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (byte)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (byte)1; return x >> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (short)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (short)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (short)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (short)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (short)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (short)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (short)1; return x >> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (char)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (char)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (char)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (char)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (char)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (char)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (char)1; return x >> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (int)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (int)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (int)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (int)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (int)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (int)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (int)1; return x >> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (long)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (long)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (long)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (long)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (long)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (long)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (long)1; return x >> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (float)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (float)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (float)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (float)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (float)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (float)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (float)1; return x >> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (double)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (double)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (double)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (double)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (double)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (double)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (double)1; return x >> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (byte)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (short)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (char)1; return x >> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (int)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (long)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (float)1; return x >> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (double)1; return x >> y"));
|
||||
}
|
||||
|
||||
public void testUsh() {
|
||||
|
@ -518,262 +495,224 @@ public class DefOperationTests extends ScriptTestCase {
|
|||
assertEquals(2, exec("def x = (char)4; def y = (byte)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (byte)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (byte)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (byte)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (byte)1; return x >>> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (short)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (short)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (short)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (short)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (short)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (short)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (short)1; return x >>> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (char)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (char)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (char)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (char)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (char)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (char)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (char)1; return x >>> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (int)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (int)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (int)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (int)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (int)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (int)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (int)1; return x >>> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (long)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (long)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (long)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (long)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (long)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (long)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (long)1; return x >>> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (float)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (float)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (float)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (float)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (float)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (float)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (float)1; return x >>> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (double)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (double)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (double)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (double)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (double)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (double)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (double)1; return x >>> y"));
|
||||
|
||||
assertEquals(2, exec("def x = (byte)4; def y = (byte)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (short)4; def y = (short)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (char)4; def y = (char)1; return x >>> y"));
|
||||
assertEquals(2, exec("def x = (int)4; def y = (int)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (long)4; def y = (long)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (float)4; def y = (float)1; return x >>> y"));
|
||||
assertEquals(2L, exec("def x = (double)4; def y = (double)1; return x >>> y"));
|
||||
}
|
||||
|
||||
public void testBogusShifts() {
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("def x = 1L; def y = 2F; return x << y;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("def x = 1; def y = 2D; return x << y;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("def x = 1F; def y = 2; return x << y;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("def x = 1D; def y = 2L; return x << y;");
|
||||
});
|
||||
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("def x = 1L; def y = 2F; return x >> y;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("def x = 1; def y = 2D; return x >> y;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("def x = 1F; def y = 2; return x >> y;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("def x = 1D; def y = 2L; return x >> y;");
|
||||
});
|
||||
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("def x = 1L; def y = 2F; return x >>> y;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("def x = 1; def y = 2D; return x >>> y;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("def x = 1F; def y = 2; return x >>> y;");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, ()-> {
|
||||
exec("def x = 1D; def y = 2L; return x >>> y;");
|
||||
});
|
||||
}
|
||||
|
||||
public void testAnd() {
|
||||
expectScriptThrows(ClassCastException.class, () -> {
|
||||
exec("def x = (float)4; def y = (byte)1; return x & y");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, () -> {
|
||||
exec("def x = (double)4; def y = (byte)1; return x & y");
|
||||
});
|
||||
assertEquals(0, exec("def x = (byte)4; def y = (byte)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (short)4; def y = (byte)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (char)4; def y = (byte)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (int)4; def y = (byte)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (long)4; def y = (byte)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (float)4; def y = (byte)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (double)4; def y = (byte)1; return x & y"));
|
||||
|
||||
assertEquals(0, exec("def x = (byte)4; def y = (short)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (short)4; def y = (short)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (char)4; def y = (short)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (int)4; def y = (short)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (long)4; def y = (short)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (float)4; def y = (short)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (double)4; def y = (short)1; return x & y"));
|
||||
|
||||
assertEquals(0, exec("def x = (byte)4; def y = (char)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (short)4; def y = (char)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (char)4; def y = (char)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (int)4; def y = (char)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (long)4; def y = (char)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (float)4; def y = (char)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (double)4; def y = (char)1; return x & y"));
|
||||
|
||||
assertEquals(0, exec("def x = (byte)4; def y = (int)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (short)4; def y = (int)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (char)4; def y = (int)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (int)4; def y = (int)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (long)4; def y = (int)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (float)4; def y = (int)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (double)4; def y = (int)1; return x & y"));
|
||||
|
||||
assertEquals(0L, exec("def x = (byte)4; def y = (long)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (short)4; def y = (long)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (char)4; def y = (long)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (int)4; def y = (long)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (long)4; def y = (long)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (float)4; def y = (long)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (double)4; def y = (long)1; return x & y"));
|
||||
|
||||
assertEquals(0L, exec("def x = (byte)4; def y = (float)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (short)4; def y = (float)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (char)4; def y = (float)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (int)4; def y = (float)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (long)4; def y = (float)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (float)4; def y = (float)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (double)4; def y = (float)1; return x & y"));
|
||||
|
||||
assertEquals(0L, exec("def x = (byte)4; def y = (double)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (short)4; def y = (double)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (char)4; def y = (double)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (int)4; def y = (double)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (long)4; def y = (double)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (float)4; def y = (double)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (double)4; def y = (double)1; return x & y"));
|
||||
|
||||
assertEquals(0, exec("def x = (byte)4; def y = (byte)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (short)4; def y = (short)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (char)4; def y = (char)1; return x & y"));
|
||||
assertEquals(0, exec("def x = (int)4; def y = (int)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (long)4; def y = (long)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (float)4; def y = (float)1; return x & y"));
|
||||
assertEquals(0L, exec("def x = (double)4; def y = (double)1; return x & y"));
|
||||
|
||||
assertEquals(true, exec("def x = true; def y = true; return x & y"));
|
||||
assertEquals(false, exec("def x = true; def y = false; return x & y"));
|
||||
assertEquals(false, exec("def x = false; def y = true; return x & y"));
|
||||
assertEquals(false, exec("def x = false; def y = false; return x & y"));
|
||||
}
|
||||
|
||||
public void testXor() {
|
||||
expectScriptThrows(ClassCastException.class, () -> {
|
||||
exec("def x = (float)4; def y = (byte)1; return x ^ y");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, () -> {
|
||||
exec("def x = (double)4; def y = (byte)1; return x ^ y");
|
||||
});
|
||||
assertEquals(5, exec("def x = (byte)4; def y = (byte)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (short)4; def y = (byte)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (char)4; def y = (byte)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (int)4; def y = (byte)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (byte)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (byte)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (byte)1; return x ^ y"));
|
||||
|
||||
assertEquals(5, exec("def x = (byte)4; def y = (short)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (short)4; def y = (short)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (char)4; def y = (short)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (int)4; def y = (short)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (short)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (short)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (short)1; return x ^ y"));
|
||||
|
||||
assertEquals(5, exec("def x = (byte)4; def y = (char)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (short)4; def y = (char)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (char)4; def y = (char)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (int)4; def y = (char)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (char)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (char)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (char)1; return x ^ y"));
|
||||
|
||||
assertEquals(5, exec("def x = (byte)4; def y = (int)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (short)4; def y = (int)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (char)4; def y = (int)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (int)4; def y = (int)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (int)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (int)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (int)1; return x ^ y"));
|
||||
|
||||
assertEquals(5L, exec("def x = (byte)4; def y = (long)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (short)4; def y = (long)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (char)4; def y = (long)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (int)4; def y = (long)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (long)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (long)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (long)1; return x ^ y"));
|
||||
|
||||
assertEquals(5L, exec("def x = (byte)4; def y = (float)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (short)4; def y = (float)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (char)4; def y = (float)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (int)4; def y = (float)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (float)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (float)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (float)1; return x ^ y"));
|
||||
|
||||
assertEquals(5L, exec("def x = (byte)4; def y = (double)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (short)4; def y = (double)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (char)4; def y = (double)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (int)4; def y = (double)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (double)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (double)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (double)1; return x ^ y"));
|
||||
|
||||
assertEquals(5, exec("def x = (byte)4; def y = (byte)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (short)4; def y = (short)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (char)4; def y = (char)1; return x ^ y"));
|
||||
assertEquals(5, exec("def x = (int)4; def y = (int)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (long)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (float)1; return x ^ y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (double)1; return x ^ y"));
|
||||
|
||||
assertEquals(false, exec("def x = true; def y = true; return x ^ y"));
|
||||
assertEquals(true, exec("def x = true; def y = false; return x ^ y"));
|
||||
assertEquals(true, exec("def x = false; def y = true; return x ^ y"));
|
||||
assertEquals(false, exec("def x = false; def y = false; return x ^ y"));
|
||||
}
|
||||
|
||||
public void testOr() {
|
||||
expectScriptThrows(ClassCastException.class, () -> {
|
||||
exec("def x = (float)4; def y = (byte)1; return x | y");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, () -> {
|
||||
exec("def x = (double)4; def y = (byte)1; return x | y");
|
||||
});
|
||||
assertEquals(5, exec("def x = (byte)4; def y = (byte)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (short)4; def y = (byte)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (char)4; def y = (byte)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (int)4; def y = (byte)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (byte)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (byte)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (byte)1; return x | y"));
|
||||
|
||||
assertEquals(5, exec("def x = (byte)4; def y = (short)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (short)4; def y = (short)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (char)4; def y = (short)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (int)4; def y = (short)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (short)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (short)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (short)1; return x | y"));
|
||||
|
||||
assertEquals(5, exec("def x = (byte)4; def y = (char)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (short)4; def y = (char)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (char)4; def y = (char)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (int)4; def y = (char)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (char)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (char)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (char)1; return x | y"));
|
||||
|
||||
assertEquals(5, exec("def x = (byte)4; def y = (int)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (short)4; def y = (int)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (char)4; def y = (int)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (int)4; def y = (int)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (int)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (int)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (int)1; return x | y"));
|
||||
|
||||
assertEquals(5L, exec("def x = (byte)4; def y = (long)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (short)4; def y = (long)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (char)4; def y = (long)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (int)4; def y = (long)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (long)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (long)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (long)1; return x | y"));
|
||||
|
||||
assertEquals(5L, exec("def x = (byte)4; def y = (float)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (short)4; def y = (float)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (char)4; def y = (float)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (int)4; def y = (float)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (float)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (float)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (float)1; return x | y"));
|
||||
|
||||
assertEquals(5L, exec("def x = (byte)4; def y = (double)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (short)4; def y = (double)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (char)4; def y = (double)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (int)4; def y = (double)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (double)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (double)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (double)1; return x | y"));
|
||||
|
||||
assertEquals(5, exec("def x = (byte)4; def y = (byte)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (short)4; def y = (short)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (char)4; def y = (char)1; return x | y"));
|
||||
assertEquals(5, exec("def x = (int)4; def y = (int)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (long)4; def y = (long)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (float)4; def y = (float)1; return x | y"));
|
||||
assertEquals(5L, exec("def x = (double)4; def y = (double)1; return x | y"));
|
||||
|
||||
assertEquals(true, exec("def x = true; def y = true; return x | y"));
|
||||
assertEquals(true, exec("def x = true; def y = false; return x | y"));
|
||||
assertEquals(true, exec("def x = false; def y = true; return x | y"));
|
||||
assertEquals(false, exec("def x = false; def y = false; return x | y"));
|
||||
}
|
||||
|
||||
public void testEq() {
|
||||
|
@ -793,10 +732,22 @@ public class DefOperationTests extends ScriptTestCase {
|
|||
assertEquals(false, exec("def x = (float)6; def y = (double)2; return x == y"));
|
||||
assertEquals(false, exec("def x = (double)7; def y = (double)1; return x == y"));
|
||||
|
||||
assertEquals(false, exec("def x = false; def y = true; return x == y"));
|
||||
assertEquals(false, exec("def x = true; def y = false; return x == y"));
|
||||
assertEquals(false, exec("def x = true; def y = null; return x == y"));
|
||||
assertEquals(false, exec("def x = null; def y = true; return x == y"));
|
||||
assertEquals(true, exec("def x = true; def y = true; return x == y"));
|
||||
assertEquals(true, exec("def x = false; def y = false; return x == y"));
|
||||
|
||||
assertEquals(true, exec("def x = new HashMap(); def y = new HashMap(); return x == y"));
|
||||
assertEquals(false, exec("def x = new HashMap(); x.put(3, 3); def y = new HashMap(); return x == y"));
|
||||
assertEquals(true, exec("def x = new HashMap(); x.put(3, 3); def y = new HashMap(); y.put(3, 3); return x == y"));
|
||||
assertEquals(true, exec("def x = new HashMap(); def y = x; x.put(3, 3); y.put(3, 3); return x == y"));
|
||||
|
||||
assertEquals(true, exec("def x = true; def y = true; return x == y"));
|
||||
assertEquals(false, exec("def x = true; def y = false; return x == y"));
|
||||
assertEquals(false, exec("def x = false; def y = true; return x == y"));
|
||||
assertEquals(true, exec("def x = false; def y = false; return x == y"));
|
||||
}
|
||||
|
||||
public void testEqr() {
|
||||
|
@ -807,6 +758,7 @@ public class DefOperationTests extends ScriptTestCase {
|
|||
assertEquals(false, exec("def x = (long)5; def y = (int)3; return x === y"));
|
||||
assertEquals(false, exec("def x = (float)6; def y = (int)2; return x === y"));
|
||||
assertEquals(false, exec("def x = (double)7; def y = (int)1; return x === y"));
|
||||
assertEquals(false, exec("def x = false; def y = true; return x === y"));
|
||||
|
||||
assertEquals(false, exec("def x = new HashMap(); def y = new HashMap(); return x === y"));
|
||||
assertEquals(false, exec("def x = new HashMap(); x.put(3, 3); def y = new HashMap(); return x === y"));
|
||||
|
@ -835,6 +787,11 @@ public class DefOperationTests extends ScriptTestCase {
|
|||
assertEquals(true, exec("def x = new HashMap(); x.put(3, 3); def y = new HashMap(); return x != y"));
|
||||
assertEquals(false, exec("def x = new HashMap(); x.put(3, 3); def y = new HashMap(); y.put(3, 3); return x != y"));
|
||||
assertEquals(false, exec("def x = new HashMap(); def y = x; x.put(3, 3); y.put(3, 3); return x != y"));
|
||||
|
||||
assertEquals(false, exec("def x = true; def y = true; return x != y"));
|
||||
assertEquals(true, exec("def x = true; def y = false; return x != y"));
|
||||
assertEquals(true, exec("def x = false; def y = true; return x != y"));
|
||||
assertEquals(false, exec("def x = false; def y = false; return x != y"));
|
||||
}
|
||||
|
||||
public void testNer() {
|
||||
|
|
|
@ -45,4 +45,13 @@ public class OrTests extends ScriptTestCase {
|
|||
assertEquals(5L | -12L, exec("return 5L | -12L;"));
|
||||
assertEquals(7L | 15L | 3L, exec("return 7L | 15L | 3L;"));
|
||||
}
|
||||
|
||||
public void testIllegal() throws Exception {
|
||||
expectScriptThrows(ClassCastException.class, () -> {
|
||||
exec("float x = (float)4; int y = 1; return x | y");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, () -> {
|
||||
exec("double x = (double)4; int y = 1; return x | y");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,4 +39,14 @@ public class UnaryTests extends ScriptTestCase {
|
|||
assertEquals(1, exec("return -(-1);"));
|
||||
assertEquals(0, exec("return -0;"));
|
||||
}
|
||||
|
||||
public void testPlus() {
|
||||
assertEquals(-1, exec("byte x = (byte)-1; return +x"));
|
||||
assertEquals(-1, exec("short x = (short)-1; return +x"));
|
||||
assertEquals(65535, exec("char x = (char)-1; return +x"));
|
||||
assertEquals(-1, exec("int x = -1; return +x"));
|
||||
assertEquals(-1L, exec("long x = -1L; return +x"));
|
||||
assertEquals(-1.0F, exec("float x = -1F; return +x"));
|
||||
assertEquals(-1.0, exec("double x = -1.0; return +x"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,4 +59,13 @@ public class XorTests extends ScriptTestCase {
|
|||
assertEquals(true, exec("return false ^ true;"));
|
||||
assertEquals(false, exec("return false ^ false;"));
|
||||
}
|
||||
|
||||
public void testIllegal() throws Exception {
|
||||
expectScriptThrows(ClassCastException.class, () -> {
|
||||
exec("float x = (float)4; int y = 1; return x ^ y");
|
||||
});
|
||||
expectScriptThrows(ClassCastException.class, () -> {
|
||||
exec("double x = (double)4; int y = 1; return x ^ y");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue