Clover coverage report - DynamicJava Test Coverage (dynamicjava-20110903-r5436)
Coverage timestamp: Sat Sep 3 2011 03:02:20 CDT
file stats: LOC: 827   Methods: 188
NCLOC: 642   Classes: 5
 
 Source file Conditionals Statements Methods TOTAL
ExpressionEvaluator.java 57.2% 46.1% 33% 44.8%
coverage coverage
 1    package edu.rice.cs.dynamicjava.interpreter;
 2   
 3    import java.lang.reflect.Array;
 4    import edu.rice.cs.plt.lambda.Lambda;
 5    import edu.rice.cs.plt.lambda.Lambda2;
 6    import edu.rice.cs.plt.lambda.Box;
 7    import edu.rice.cs.plt.lambda.WrappedException;
 8    import edu.rice.cs.plt.iter.IterUtil;
 9   
 10    import koala.dynamicjava.tree.*;
 11    import koala.dynamicjava.tree.visitor.*;
 12   
 13    import edu.rice.cs.dynamicjava.Options;
 14    import edu.rice.cs.dynamicjava.symbol.LocalVariable;
 15   
 16    import static koala.dynamicjava.interpreter.NodeProperties.*;
 17   
 18    /** Evaluates the given expression. The expression is assumed to have been
 19    * checked without any errors. Note that the result of a visitor method is not necessarily
 20    * the value of the expression -- for example, a primitive casting conversion might be required.
 21    * The {@link #value} method contains additional checks and conversions, and should be used exclusively
 22    * by clients to evaluate an expression.
 23    */
 24    public class ExpressionEvaluator extends AbstractVisitor<Object> implements Lambda<Node, Object> {
 25   
 26    private final RuntimeBindings _bindings;
 27    private final Options _options;
 28   
 29  902 public ExpressionEvaluator(RuntimeBindings bindings, Options options) {
 30  902 _bindings = bindings;
 31  902 _options = options;
 32    }
 33   
 34  3297 public Object value(Node n) {
 35  3297 Object result;
 36  543 if (hasValue(n)) { result = getValue(n); }
 37  776 else if (hasTranslation(n)) { result = value(getTranslation(n)); }
 38  1978 else { result = n.acceptVisitor(this); }
 39  25 if (hasConvertedType(n)) { result = convert(result, getConvertedType(n).value()); }
 40  3297 if (hasCheckedType(n)) {
 41  3 Class<?> expected = getCheckedType(n).value();
 42  3 if (result != null && !expected.isInstance(result)) {
 43  0 throw new WrappedException(new EvaluatorException(
 44    new ClassCastException("From " + result.getClass().getName() + " to " + expected.getName())));
 45    }
 46    }
 47  3297 return result;
 48    }
 49   
 50  0 @Override public Object visit(Literal node) { return node.getValue(); }
 51   
 52  785 @Override public Object visit(VariableAccess node) { return new LValueVisitor().visit(node).value(); }
 53   
 54  8 @Override public Object visit(SimpleFieldAccess node) { return new LValueVisitor().visit(node).value(); }
 55   
 56  38 @Override public Object visit(ObjectFieldAccess node) { return new LValueVisitor().visit(node).value(); }
 57   
 58  0 @Override public Object visit(SuperFieldAccess node) { return new LValueVisitor().visit(node).value(); }
 59   
 60  0 @Override public Object visit(StaticFieldAccess node) { return new LValueVisitor().visit(node).value(); }
 61   
 62  0 @Override public Object visit(ThisExpression node) {
 63  0 return _bindings.getThis(getDJClass(node));
 64    }
 65   
 66  108 @Override public Object visit(SimpleMethodCall node) {
 67  108 if (hasDJClass(node)) {
 68  0 return handleMethodCall(node, _bindings.getThis(getDJClass(node)));
 69    }
 70    else {
 71  108 return handleMethodCall(node, null);
 72    }
 73    }
 74   
 75  90 @Override public Object visit(ObjectMethodCall node) {
 76  90 return handleMethodCall(node, value(node.getExpression()));
 77    }
 78   
 79  0 @Override public Object visit(SuperMethodCall node) {
 80  0 return handleMethodCall(node, _bindings.getThis(getDJClass(node)));
 81    }
 82   
 83  47 @Override public Object visit(StaticMethodCall node) {
 84  47 return handleMethodCall(node, null);
 85    }
 86   
 87  245 private Object handleMethodCall(MethodCall node, Object receiver) {
 88  245 Iterable<Object> args;
 89  0 if (node.getArguments() == null) { args = IterUtil.empty(); }
 90  245 else { args = IterUtil.mapSnapshot(node.getArguments(), this); }
 91   
 92  245 try { return getMethod(node).evaluate(receiver, args, _bindings, _options); }
 93  0 catch (EvaluatorException e) { throw new WrappedException(e); }
 94    }
 95   
 96   
 97  141 @Override public Object visit(SimpleAllocation node) {
 98  141 return handleConstructor(node, null, node.getArguments());
 99    }
 100   
 101  0 @Override public Object visit(AnonymousAllocation node) {
 102  0 return handleConstructor(node, null, null);
 103    }
 104   
 105  0 @Override public Object visit(InnerAllocation node) {
 106  0 return handleConstructor(node, node.getExpression(), node.getArguments());
 107    }
 108   
 109  0 @Override public Object visit(AnonymousInnerAllocation node) {
 110  0 return handleConstructor(node, null, null);
 111    }
 112   
 113    /**
 114    * @param args May be null, meaning there are no arguments
 115    */
 116  141 private Object handleConstructor(Expression node, Expression outer, Iterable<Expression> args) {
 117  141 Object outerVal;
 118  141 if (outer == null) {
 119  0 if (hasEnclosingThis(node)) { outerVal = _bindings.getThis(getEnclosingThis(node)); }
 120  141 else { outerVal = null; }
 121    }
 122  0 else { outerVal = value(outer); }
 123   
 124  141 Iterable<Object> argVals;
 125  0 if (args == null) { argVals = IterUtil.empty(); }
 126  141 else { argVals = IterUtil.mapSnapshot(args, this); }
 127   
 128  141 try { return getConstructor(node).evaluate(outerVal, argVals, _bindings, _options); }
 129  0 catch (EvaluatorException e) { throw new WrappedException(e); }
 130    }
 131   
 132   
 133  128 @Override public Object visit(SimpleAssignExpression node) {
 134  128 Box<Object> left = node.getLeftExpression().acceptVisitor(new LValueVisitor());
 135  128 Object val = value(node.getRightExpression());
 136  128 left.set(val);
 137  128 return val;
 138    }
 139   
 140  13 @Override public Object visit(TypeExpression node) { return getErasedType(node.getType()).value(); }
 141   
 142  34 @Override public Object visit(ArrayAllocation node) {
 143  34 if (node.getInitialization() != null) {
 144  34 return node.getInitialization().acceptVisitor(this);
 145    }
 146    else {
 147  0 Class<?> component = getErasedType(node).value();
 148  0 int[] dims = new int[node.getSizes().size()];
 149  0 int i = 0;
 150  0 for (Object dim : IterUtil.map(node.getSizes(), this)) {
 151  0 dims[i] = (Integer) dim;
 152  0 component = component.getComponentType();
 153  0 i++;
 154    }
 155  0 return Array.newInstance(component, dims);
 156    }
 157    }
 158   
 159  34 @Override public Object visit(ArrayInitializer node) {
 160  34 Object result = Array.newInstance(getErasedType(node).value().getComponentType(),
 161    node.getCells().size());
 162  34 int i = 0;
 163  34 for (Object elt : IterUtil.map(node.getCells(), this)) {
 164  67 Array.set(result, i, elt);
 165  67 i++;
 166    }
 167  34 return result;
 168    }
 169   
 170  24 @Override public Object visit(ArrayAccess node) { return new LValueVisitor().visit(node).value(); }
 171   
 172   
 173    /* * * PRIMITIVE EXPRESSIONS * * */
 174   
 175  124 @Override public Object visit(NotExpression node) { return NOT.value(value(node.getExpression())); }
 176  0 @Override public Object visit(ComplementExpression node) { return COMPLEMENT.value(value(node.getExpression())); }
 177  0 @Override public Object visit(PlusExpression node) { return PLUS.value(value(node.getExpression())); }
 178  4 @Override public Object visit(MinusExpression node) { return MINUS.value(value(node.getExpression())); }
 179   
 180  75 @Override public Object visit(AddExpression node) {
 181  75 return getOperation(node).value(value(node.getLeftExpression()), value(node.getRightExpression()));
 182    }
 183   
 184  0 @Override public Object visit(AddAssignExpression node) {
 185  0 return handleOpAssignExpression(node, getOperation(node));
 186    }
 187   
 188  1 @Override public Object visit(SubtractExpression node) {
 189  1 return SUBTRACT.value(value(node.getLeftExpression()), value(node.getRightExpression()));
 190    }
 191   
 192  0 @Override public Object visit(SubtractAssignExpression node) {
 193  0 return handleOpAssignExpression(node, SUBTRACT);
 194    }
 195   
 196  0 @Override public Object visit(MultiplyExpression node) {
 197  0 return MULTIPLY.value(value(node.getLeftExpression()), value(node.getRightExpression()));
 198    }
 199   
 200  0 @Override public Object visit(MultiplyAssignExpression node) {
 201  0 return handleOpAssignExpression(node, MULTIPLY);
 202    }
 203   
 204  4 @Override public Object visit(DivideExpression node) {
 205  4 try { return DIVIDE.value(value(node.getLeftExpression()), value(node.getRightExpression())); }
 206    catch (ArithmeticException e) {
 207  0 throw new WrappedException(new EvaluatorException(e,
 208    "edu.rice.cs.dynamicjava.interpreter.ExpressionEvaluator$MatchingPrimitiveBinaryOperation.value",
 209    "edu.rice.cs.dynamicjava.interpreter.ExpressionEvaluator$15.value"));
 210    }
 211    }
 212   
 213  0 @Override public Object visit(DivideAssignExpression node) {
 214  0 return handleOpAssignExpression(node, DIVIDE);
 215    }
 216   
 217  0 @Override public Object visit(RemainderExpression node) {
 218  0 try { return REMAINDER.value(value(node.getLeftExpression()), value(node.getRightExpression())); }
 219    catch (ArithmeticException e) {
 220  0 throw new WrappedException(new EvaluatorException(e,
 221    "edu.rice.cs.dynamicjava.interpreter.ExpressionEvaluator$MatchingPrimitiveBinaryOperation.value",
 222    "edu.rice.cs.dynamicjava.interpreter.ExpressionEvaluator$16.value"));
 223    }
 224    }
 225   
 226  0 @Override public Object visit(RemainderAssignExpression node) {
 227  0 return handleOpAssignExpression(node, REMAINDER);
 228    }
 229   
 230  50 @Override public Object visit(EqualExpression node) {
 231  50 return getOperation(node).value(value(node.getLeftExpression()), value(node.getRightExpression()));
 232    }
 233   
 234  4 @Override public Object visit(NotEqualExpression node) {
 235  4 return getOperation(node).value(value(node.getLeftExpression()), value(node.getRightExpression()));
 236    }
 237   
 238  111 @Override public Object visit(LessExpression node) {
 239  111 return LESS.value(value(node.getLeftExpression()), value(node.getRightExpression()));
 240    }
 241   
 242  0 @Override public Object visit(LessOrEqualExpression node) {
 243  0 return LESS_OR_EQUAL.value(value(node.getLeftExpression()), value(node.getRightExpression()));
 244    }
 245   
 246  12 @Override public Object visit(GreaterExpression node) {
 247  12 return GREATER.value(value(node.getLeftExpression()), value(node.getRightExpression()));
 248    }
 249   
 250  0 @Override public Object visit(GreaterOrEqualExpression node) {
 251  0 return GREATER_OR_EQUAL.value(value(node.getLeftExpression()), value(node.getRightExpression()));
 252    }
 253   
 254  0 @Override public Object visit(BitAndExpression node) {
 255  0 return BIT_AND.value(value(node.getLeftExpression()), value(node.getRightExpression()));
 256    }
 257   
 258  0 @Override public Object visit(BitAndAssignExpression node) {
 259  0 return handleOpAssignExpression(node, BIT_AND);
 260    }
 261   
 262  0 @Override public Object visit(ExclusiveOrExpression node) {
 263  0 return EXCLUSIVE_OR.value(value(node.getLeftExpression()), value(node.getRightExpression()));
 264    }
 265   
 266  0 @Override public Object visit(ExclusiveOrAssignExpression node) {
 267  0 return handleOpAssignExpression(node, EXCLUSIVE_OR);
 268    }
 269   
 270  0 @Override public Object visit(BitOrExpression node) {
 271  0 return BIT_OR.value(value(node.getLeftExpression()), value(node.getRightExpression()));
 272    }
 273   
 274  0 @Override public Object visit(BitOrAssignExpression node) {
 275  0 return handleOpAssignExpression(node, BIT_OR);
 276    }
 277   
 278  0 @Override public Object visit(ShiftLeftExpression node) {
 279  0 return SHIFT_LEFT.value(value(node.getLeftExpression()), value(node.getRightExpression()));
 280    }
 281   
 282  0 @Override public Object visit(ShiftLeftAssignExpression node) {
 283  0 return handleOpAssignExpression(node, SHIFT_LEFT);
 284    }
 285   
 286  0 @Override public Object visit(ShiftRightExpression node) {
 287  0 return SHIFT_RIGHT.value(value(node.getLeftExpression()), value(node.getRightExpression()));
 288    }
 289   
 290  0 @Override public Object visit(ShiftRightAssignExpression node) {
 291  0 return handleOpAssignExpression(node, SHIFT_RIGHT);
 292    }
 293   
 294  0 @Override public Object visit(UnsignedShiftRightExpression node) {
 295  0 return UNSIGNED_SHIFT_RIGHT.value(value(node.getLeftExpression()), value(node.getRightExpression()));
 296    }
 297   
 298  0 @Override public Object visit(UnsignedShiftRightAssignExpression node) {
 299  0 return handleOpAssignExpression(node, UNSIGNED_SHIFT_RIGHT);
 300    }
 301   
 302   
 303    /**
 304    * Evaluate the given operator-assignment expression by invoking the given operation and setting
 305    * the variable to its result
 306    */
 307  0 private Object handleOpAssignExpression(AssignExpression node, Lambda2<Object, Object, Object> op) {
 308    // TODO: This implementation incorrectly evaluates the left twice. For example:
 309    // foo().x += 3
 310    // (Should call "foo" only once)
 311    // The problem arises from our current strategy of tagging node with a LEFT_EXPRESSION,
 312    // which is node.leftExpression wrapped in any conversions. We could either use a different
 313    // strategy or somehow detect on the first evaluation that the expression (possibly a nested
 314    // component of LEFT_EXPRESSION) needs to be tagged with VALUE for the second evaluation.
 315  0 Box<Object> setter = node.getLeftExpression().acceptVisitor(new LValueVisitor());
 316  0 Object left = value(getLeftExpression(node)); // not to be confused with node.getLeft...
 317  0 Object right = value(node.getRightExpression());
 318  0 try {
 319  0 Object result = op.value(left, right);
 320    // The result might need to be boxed, but the representation of boxed values
 321    // and primitive values is identical, so nothing needs to be done
 322  0 setter.set(result);
 323  0 return result;
 324    }
 325    catch (ArithmeticException e) {
 326  0 String[] divStack = new String[]{
 327    "edu.rice.cs.dynamicjava.interpreter.ExpressionEvaluator$MatchingPrimitiveBinaryOperation.value",
 328    "edu.rice.cs.dynamicjava.interpreter.ExpressionEvaluator$15.value"
 329    };
 330  0 String[] modStack = new String[]{
 331    "edu.rice.cs.dynamicjava.interpreter.ExpressionEvaluator$MatchingPrimitiveBinaryOperation.value",
 332    "edu.rice.cs.dynamicjava.interpreter.ExpressionEvaluator$16.value"
 333    };
 334  0 throw new WrappedException(new EvaluatorException(e, divStack, modStack));
 335    }
 336    }
 337   
 338  0 @Override public Object visit(AndExpression node) {
 339  0 return (Boolean) value(node.getLeftExpression()) && (Boolean) value(node.getRightExpression());
 340    }
 341   
 342  0 @Override public Object visit(OrExpression node) {
 343  0 return (Boolean) value(node.getLeftExpression()) || (Boolean) value(node.getRightExpression());
 344    }
 345   
 346  0 @Override public Object visit(InstanceOfExpression node) {
 347  0 Object v = value(node.getExpression());
 348  0 return getErasedType(node.getReferenceType()).value().isInstance(v);
 349    }
 350   
 351  62 @Override public Object visit(CastExpression node) {
 352    // cast checks/conversions are handled by value()
 353  62 return value(node.getExpression());
 354    }
 355   
 356  0 @Override public Object visit(ConditionalExpression node) {
 357  0 if ((Boolean) value(node.getConditionExpression())) { return value(node.getIfTrueExpression()); }
 358  0 else { return value(node.getIfFalseExpression()); }
 359    }
 360   
 361  109 @Override public Object visit(PostIncrement node) {
 362  109 Box<Object> setter = node.getExpression().acceptVisitor(new LValueVisitor());
 363  109 Object result = value(getLeftExpression(node)); // not to be confused with node.getLeft...
 364    // The result might need to be boxed, but the representation of boxed values
 365    // and primitive values is identical, so nothing needs to be done
 366  109 setter.set(INCREMENT.value(result));
 367  109 return result;
 368    }
 369   
 370  2 @Override public Object visit(PreIncrement node) {
 371  2 Box<Object> setter = node.getExpression().acceptVisitor(new LValueVisitor());
 372  2 Object val = value(getLeftExpression(node)); // not to be confused with node.getLeft...
 373  2 Object result = INCREMENT.value(val);
 374    // The result might need to be boxed, but the representation of boxed values
 375    // and primitive values is identical, so nothing needs to be done
 376  2 setter.set(result);
 377  2 return result;
 378    }
 379   
 380  2 @Override public Object visit(PostDecrement node) {
 381  2 Box<Object> setter = node.getExpression().acceptVisitor(new LValueVisitor());
 382  2 Object result = value(getLeftExpression(node)); // not to be confused with node.getLeft...
 383    // The result might need to be boxed, but the representation of boxed values
 384    // and primitive values is identical, so nothing needs to be done
 385  2 setter.set(DECREMENT.value(result));
 386  2 return result;
 387    }
 388   
 389    /**
 390    * Visits a PreDecrement
 391    * @param node the node to visit
 392    */
 393  2 @Override public Object visit(PreDecrement node) {
 394  2 Box<Object> setter = node.getExpression().acceptVisitor(new LValueVisitor());
 395  2 Object val = value(getLeftExpression(node)); // not to be confused with node.getLeft...
 396  2 Object result = DECREMENT.value(val);
 397    // The result might need to be boxed, but the representation of boxed values
 398    // and primitive values is identical, so nothing needs to be done
 399  2 setter.set(result);
 400  2 return result;
 401    }
 402   
 403   
 404    /**
 405    * Evaluates a left-hand side of an assignment. In the undefined cases, this returns null.
 406    * (The type checker ensures that such cases will never be called.)
 407    */
 408    private class LValueVisitor extends AbstractVisitor<Box<Object>> {
 409   
 410  243 @Override public Box<Object> visit(AmbiguousName node) {
 411  243 return getTranslation(node).acceptVisitor(this);
 412    }
 413   
 414  1003 @Override public Box<Object> visit(VariableAccess node) {
 415  1003 final LocalVariable var = getVariable(node);
 416  1003 return new Box<Object>() {
 417  785 public Object value() { return _bindings.get(var); }
 418  218 public void set(Object val) { _bindings.set(var, val); }
 419    };
 420    }
 421   
 422  33 @Override public Box<Object> visit(SimpleFieldAccess node) {
 423  33 Object receiver = hasDJClass(node) ? _bindings.getThis(getDJClass(node)) : null;
 424  33 return getField(node).boxForReceiver(receiver);
 425    }
 426   
 427  38 @Override public Box<Object> visit(ObjectFieldAccess node) {
 428  0 if (hasTranslation(node)) { return getTranslation(node).acceptVisitor(this); }
 429  38 else { return getField(node).boxForReceiver(ExpressionEvaluator.this.value(node.getExpression())); }
 430    }
 431   
 432  0 @Override public Box<Object> visit(SuperFieldAccess node) {
 433  0 return getField(node).boxForReceiver(_bindings.getThis(getDJClass(node)));
 434    }
 435   
 436  0 @Override public Box<Object> visit(StaticFieldAccess node) {
 437  0 return getField(node).boxForReceiver(null);
 438    }
 439   
 440  24 @Override public Box<Object> visit(ArrayAccess node) {
 441  24 final Object array = ExpressionEvaluator.this.value(node.getExpression());
 442  24 final Integer index = (Integer) ExpressionEvaluator.this.value(node.getCellNumber());
 443  24 return new Box<Object>() {
 444  24 public Object value() {
 445  24 try { return Array.get(array, index); }
 446    catch (NullPointerException e) {
 447  0 throw new WrappedException(new EvaluatorException(e, "java.lang.reflect.Array.get"));
 448    }
 449    catch (ArrayIndexOutOfBoundsException e) {
 450  0 throw new WrappedException(new EvaluatorException(e, "java.lang.reflect.Array.get"));
 451    }
 452    }
 453  0 public void set(Object val) {
 454  0 try { Array.set(array, index, val); }
 455    catch (NullPointerException e) {
 456  0 throw new WrappedException(new EvaluatorException(e, "java.lang.reflect.Array.set"));
 457    }
 458    catch (IllegalArgumentException e) {
 459  0 Exception newE = new ArrayStoreException();
 460  0 newE.setStackTrace(e.getStackTrace());
 461  0 throw new WrappedException(new EvaluatorException(newE, "java.lang.reflect.Array.set"));
 462    }
 463    catch (ArrayIndexOutOfBoundsException e) {
 464  0 throw new WrappedException(new EvaluatorException(e, "java.lang.reflect.Array.set"));
 465    }
 466    }
 467    };
 468    }
 469   
 470    }
 471   
 472   
 473    /** Convert a primitive to the appropriate type */
 474  26 public static Object convert(Object obj, Class<?> target) {
 475  26 if (target.equals(boolean.class)) {
 476  0 if (obj instanceof Boolean) { return obj; }
 477  0 else { throw new IllegalArgumentException(); }
 478    }
 479  26 else if (target.equals(char.class)) {
 480  0 if (obj instanceof Character) { return obj; }
 481  0 else if (obj instanceof Number) { return (char) ((Number) obj).intValue(); }
 482  0 else { throw new IllegalArgumentException(); }
 483    }
 484  26 else if (target.equals(byte.class)) {
 485  0 if (obj instanceof Byte) { return obj; }
 486  0 else if (obj instanceof Character) { return (byte) (char) (Character) obj; }
 487  5 else if (obj instanceof Number) { return ((Number) obj).byteValue(); }
 488  0 else { throw new IllegalArgumentException(); }
 489    }
 490  21 else if (target.equals(short.class)) {
 491  0 if (obj instanceof Short) { return obj; }
 492  0 else if (obj instanceof Character) { return (short) (char) (Character) obj; }
 493  5 else if (obj instanceof Number) { return ((Number) obj).shortValue(); }
 494  0 else { throw new IllegalArgumentException(); }
 495    }
 496  16 else if (target.equals(int.class)) {
 497  0 if (obj instanceof Integer) { return obj; }
 498  3 else if (obj instanceof Character) { return (int) (char) (Character) obj; }
 499  6 else if (obj instanceof Number) { return ((Number) obj).intValue(); }
 500  0 else { throw new IllegalArgumentException(); }
 501    }
 502  7 else if (target.equals(long.class)) {
 503  1 if (obj instanceof Long) { return obj; }
 504  1 else if (obj instanceof Character) { return (long) (char) (Character) obj; }
 505  1 else if (obj instanceof Number) { return ((Number) obj).longValue(); }
 506  0 else { throw new IllegalArgumentException(); }
 507    }
 508  4 else if (target.equals(float.class)) {
 509  0 if (obj instanceof Float) { return obj; }
 510  1 else if (obj instanceof Character) { return (float) (char) (Character) obj; }
 511  0 else if (obj instanceof Number) { return ((Number) obj).floatValue(); }
 512  0 else { throw new IllegalArgumentException(); }
 513    }
 514  3 else if (target.equals(double.class)) {
 515  0 if (obj instanceof Double) { return obj; }
 516  1 else if (obj instanceof Character) { return (double) (char) (Character) obj; }
 517  2 else if (obj instanceof Number) { return ((Number) obj).doubleValue(); }
 518  0 else { throw new IllegalArgumentException(); }
 519    }
 520  0 else { throw new IllegalArgumentException(); }
 521    }
 522   
 523    /**
 524    * Parent class for primitive unary operations; the correct primitive {@code value()} method is
 525    * called based on the type of the arguments. If an operation does not apply to
 526    * a certain primitive type, that version of the {@code value()} method made be left
 527    * out, and the default implementation will just throw an exception.
 528    */
 529    private static abstract class PrimitiveUnaryOperation implements Lambda<Object, Object> {
 530  243 public Object value(Object val) {
 531  243 if (val instanceof Boolean) {
 532  124 return value((boolean)(Boolean) val);
 533    }
 534  119 else if (val instanceof Character) {
 535  0 return value((char)(Character) val);
 536    }
 537  119 else if (val instanceof Byte) {
 538  0 return value((byte)(Byte) val);
 539    }
 540  119 else if (val instanceof Short) {
 541  0 return value((short)(Short) val);
 542    }
 543  119 else if (val instanceof Integer) {
 544  111 return value((int)(Integer) val);
 545    }
 546  8 else if (val instanceof Long) {
 547  0 return value((long)(Long) val);
 548    }
 549  8 else if (val instanceof Float) {
 550  7 return value((float)(Float) val);
 551    }
 552  1 else if (val instanceof Double) {
 553  1 return value((double)(Double) val);
 554    }
 555  0 else { throw new IllegalArgumentException(); }
 556    }
 557   
 558  0 public Object value(boolean val) { throw new IllegalArgumentException(); }
 559  0 public Object value(char val) { throw new IllegalArgumentException(); }
 560  0 public Object value(byte val) { throw new IllegalArgumentException(); }
 561  0 public Object value(short val) { throw new IllegalArgumentException(); }
 562  0 public Object value(int val) { throw new IllegalArgumentException(); }
 563  0 public Object value(long val) { throw new IllegalArgumentException(); }
 564  0 public Object value(float val) { throw new IllegalArgumentException(); }
 565  0 public Object value(double val) { throw new IllegalArgumentException(); }
 566    }
 567   
 568    /**
 569    * Parent class for primitive operations in which the types of {@code left} and
 570    * {@code right} are assumed to match; the correct primitive {@code value()} method is
 571    * called based on the type of the arguments. If an operation does not apply to
 572    * a certain primitive type, that version of the {@code value()} method made be left
 573    * out, and the default implementation will just throw an exception.
 574    */
 575    private static abstract class MatchingPrimitiveBinaryOperation implements Lambda2<Object, Object, Object> {
 576  155 public Object value(Object left, Object right) {
 577  155 if (left instanceof Boolean) {
 578  0 return value((boolean)(Boolean) left, (boolean)(Boolean) right);
 579    }
 580  155 else if (left instanceof Character) {
 581  0 return value((char)(Character) left, (char)(Character) right);
 582    }
 583  155 else if (left instanceof Byte) {
 584  0 return value((byte)(Byte) left, (byte)(Byte) right);
 585    }
 586  155 else if (left instanceof Short) {
 587  0 return value((short)(Short) left, (short)(Short) right);
 588    }
 589  155 else if (left instanceof Integer) {
 590  142 return value((int)(Integer) left, (int)(Integer) right);
 591    }
 592  13 else if (left instanceof Long) {
 593  1 return value((long)(Long) left, (long)(Long) right);
 594    }
 595  12 else if (left instanceof Float) {
 596  3 return value((float)(Float) left, (float)(Float) right);
 597    }
 598  9 else if (left instanceof Double) {
 599  9 return value((double)(Double) left, (double)(Double) right);
 600    }
 601  0 else { throw new IllegalArgumentException(); }
 602    }
 603   
 604  0 public Object value(boolean left, boolean right) { throw new IllegalArgumentException(); }
 605  0 public Object value(char left, char right) { throw new IllegalArgumentException(); }
 606  0 public Object value(byte left, byte right) { throw new IllegalArgumentException(); }
 607  0 public Object value(short left, short right) { throw new IllegalArgumentException(); }
 608  0 public Object value(int left, int right) { throw new IllegalArgumentException(); }
 609  0 public Object value(long left, long right) { throw new IllegalArgumentException(); }
 610  0 public Object value(float left, float right) { throw new IllegalArgumentException(); }
 611  0 public Object value(double left, double right) { throw new IllegalArgumentException(); }
 612    }
 613   
 614    /**
 615    * Parent class for shift operations -- each operand is the result of *unary* numeric
 616    * promotion, so each may be an int or a long
 617    */
 618    private static abstract class ShiftOperation implements Lambda2<Object, Object, Object> {
 619  0 public Object value(Object left, Object right) {
 620  0 if (left instanceof Integer) {
 621  0 if (right instanceof Integer) { return value((int)(Integer) left, (int)(Integer) right); }
 622  0 else if (right instanceof Long) { return value((int)(Integer) left, (long)(Long) right); }
 623  0 else { throw new IllegalArgumentException(); }
 624    }
 625  0 else if (left instanceof Long) {
 626  0 if (right instanceof Integer) { return value((long)(Long) left, (int)(Integer) right); }
 627  0 else if (right instanceof Long) { return value((long)(Long) left, (long)(Long) right); }
 628  0 else { throw new IllegalArgumentException(); }
 629    }
 630  0 else { throw new IllegalArgumentException(); }
 631    }
 632   
 633  0 public Object value(int left, int right) { throw new IllegalArgumentException(); }
 634  0 public Object value(int left, long right) { throw new IllegalArgumentException(); }
 635  0 public Object value(long left, int right) { throw new IllegalArgumentException(); }
 636  0 public Object value(long left, long right) { throw new IllegalArgumentException(); }
 637    }
 638   
 639   
 640   
 641    public static final Lambda<Object, Object> NOT = new PrimitiveUnaryOperation() {
 642  124 @Override public Object value(boolean val) { return !val; }
 643    };
 644   
 645    public static final Lambda<Object, Object> COMPLEMENT = new PrimitiveUnaryOperation() {
 646  0 @Override public Object value(int val) { return ~val; }
 647  0 @Override public Object value(long val) { return ~val; }
 648    };
 649   
 650    public static final Lambda<Object, Object> PLUS = new PrimitiveUnaryOperation() {
 651  0 @Override public Object value(int val) { return +val; }
 652  0 @Override public Object value(long val) { return +val; }
 653  0 @Override public Object value(float val) { return +val; }
 654  0 @Override public Object value(double val) { return +val; }
 655    };
 656   
 657    public static final Lambda<Object, Object> MINUS = new PrimitiveUnaryOperation() {
 658  0 @Override public Object value(int val) { return -val; }
 659  0 @Override public Object value(long val) { return -val; }
 660  3 @Override public Object value(float val) { return -val; }
 661  1 @Override public Object value(double val) { return -val; }
 662    };
 663   
 664    public static final Lambda<Object, Object> INCREMENT = new PrimitiveUnaryOperation() {
 665  0 @Override public Object value(char val) { return ++val; }
 666  0 @Override public Object value(byte val) { return ++val; }
 667  0 @Override public Object value(short val) { return ++val; }
 668  109 @Override public Object value(int val) { return ++val; }
 669  0 @Override public Object value(long val) { return ++val; }
 670  2 @Override public Object value(float val) { return ++val; }
 671  0 @Override public Object value(double val) { return ++val; }
 672    };
 673   
 674    public static final Lambda<Object, Object> DECREMENT = new PrimitiveUnaryOperation() {
 675  0 @Override public Object value(char val) { return --val; }
 676  0 @Override public Object value(byte val) { return --val; }
 677  0 @Override public Object value(short val) { return --val; }
 678  2 @Override public Object value(int val) { return --val; }
 679  0 @Override public Object value(long val) { return --val; }
 680  2 @Override public Object value(float val) { return --val; }
 681  0 @Override public Object value(double val) { return --val; }
 682    };
 683   
 684    public static final Lambda2<Object, Object, Object> OBJECT_EQUAL = new Lambda2<Object, Object, Object>() {
 685  0 public Object value(Object left, Object right) { return left == right; }
 686    };
 687   
 688    public static final Lambda2<Object, Object, Object> PRIMITIVE_EQUAL = new Lambda2<Object, Object, Object>() {
 689  54 public Object value(Object left, Object right) {
 690    // we have special cases for float and double so
 691    // that 0.0==-0.0 and Double.NaN==Double.NaN get
 692    // treated correctly
 693  54 if ((left instanceof Float) && (right instanceof Float)) {
 694  5 float l = ((Float)left).floatValue();
 695  5 float r = ((Float)right).floatValue();
 696  5 return l==r;
 697    }
 698  49 else if ((left instanceof Double) && (right instanceof Double)) {
 699  5 double l = ((Double)left).doubleValue();
 700  5 double r = ((Double)right).doubleValue();
 701  5 return l==r;
 702    }
 703  44 else return left.equals(right);
 704    }
 705    };
 706   
 707    public static final Lambda2<Object, Object, Object> OBJECT_NOT_EQUAL = new Lambda2<Object, Object, Object>() {
 708  0 public Object value(Object left, Object right) { return left != right; }
 709    };
 710   
 711    public static final Lambda2<Object, Object, Object> PRIMITIVE_NOT_EQUAL = new Lambda2<Object, Object, Object>() {
 712  4 public Object value(Object left, Object right) {
 713  4 return !((Boolean)PRIMITIVE_EQUAL.value(left, right));
 714    }
 715    };
 716   
 717    public static final Lambda2<Object, Object, Object> CONCATENATE = new Lambda2<Object, Object, Object>() {
 718  48 public Object value(Object left, Object right) {
 719  48 return
 720  48 (left == null ? "null" : left.toString()) +
 721  48 (right == null ? "null" : right.toString());
 722    }
 723    };
 724   
 725    public static final Lambda2<Object, Object, Object> ADD = new MatchingPrimitiveBinaryOperation() {
 726  24 @Override public Object value(int l, int r) { return l + r; }
 727  1 @Override public Object value(long l, long r) { return l + r; }
 728  1 @Override public Object value(float l, float r) { return l + r; }
 729  1 @Override public Object value(double l, double r) { return l + r; }
 730    };
 731   
 732    public static final Lambda2<Object, Object, Object> SUBTRACT = new MatchingPrimitiveBinaryOperation() {
 733  1 @Override public Object value(int l, int r) { return l - r; }
 734  0 @Override public Object value(long l, long r) { return l - r; }
 735  0 @Override public Object value(float l, float r) { return l - r; }
 736  0 @Override public Object value(double l, double r) { return l - r; }
 737    };
 738   
 739    public static final Lambda2<Object, Object, Object> MULTIPLY = new MatchingPrimitiveBinaryOperation() {
 740  0 @Override public Object value(int l, int r) { return l * r; }
 741  0 @Override public Object value(long l, long r) { return l * r; }
 742  0 @Override public Object value(float l, float r) { return l * r; }
 743  0 @Override public Object value(double l, double r) { return l * r; }
 744    };
 745   
 746    public static final Lambda2<Object, Object, Object> DIVIDE = new MatchingPrimitiveBinaryOperation() {
 747  0 @Override public Object value(int l, int r) { return l / r; }
 748  0 @Override public Object value(long l, long r) { return l / r; }
 749  2 @Override public Object value(float l, float r) { return l / r; }
 750  2 @Override public Object value(double l, double r) { return l / r; }
 751    };
 752   
 753    public static final Lambda2<Object, Object, Object> REMAINDER = new MatchingPrimitiveBinaryOperation() {
 754  0 @Override public Object value(int l, int r) { return l % r; }
 755  0 @Override public Object value(long l, long r) { return l % r; }
 756  0 @Override public Object value(float l, float r) { return l % r; }
 757  0 @Override public Object value(double l, double r) { return l % r; }
 758    };
 759   
 760    public static final Lambda2<Object, Object, Object> LESS = new MatchingPrimitiveBinaryOperation() {
 761  108 @Override public Object value(int l, int r) { return l < r; }
 762  0 @Override public Object value(long l, long r) { return l < r; }
 763  0 @Override public Object value(float l, float r) { return l < r; }
 764  3 @Override public Object value(double l, double r) { return l < r; }
 765    };
 766   
 767    public static final Lambda2<Object, Object, Object> LESS_OR_EQUAL = new MatchingPrimitiveBinaryOperation() {
 768  0 @Override public Object value(int l, int r) { return l <= r; }
 769  0 @Override public Object value(long l, long r) { return l <= r; }
 770  0 @Override public Object value(float l, float r) { return l <= r; }
 771  0 @Override public Object value(double l, double r) { return l <= r; }
 772    };
 773   
 774    public static final Lambda2<Object, Object, Object> GREATER = new MatchingPrimitiveBinaryOperation() {
 775  9 @Override public Object value(int l, int r) { return l > r; }
 776  0 @Override public Object value(long l, long r) { return l > r; }
 777  0 @Override public Object value(float l, float r) { return l > r; }
 778  3 @Override public Object value(double l, double r) { return l > r; }
 779    };
 780   
 781    public static final Lambda2<Object, Object, Object> GREATER_OR_EQUAL = new MatchingPrimitiveBinaryOperation() {
 782  0 @Override public Object value(int l, int r) { return l >= r; }
 783  0 @Override public Object value(long l, long r) { return l >= r; }
 784  0 @Override public Object value(float l, float r) { return l >= r; }
 785  0 @Override public Object value(double l, double r) { return l >= r; }
 786    };
 787   
 788    public static final Lambda2<Object, Object, Object> BIT_AND = new MatchingPrimitiveBinaryOperation() {
 789  0 @Override public Object value(boolean l, boolean r) { return l & r; }
 790  0 @Override public Object value(int l, int r) { return l & r; }
 791  0 @Override public Object value(long l, long r) { return l & r; }
 792    };
 793   
 794    public static final Lambda2<Object, Object, Object> BIT_OR = new MatchingPrimitiveBinaryOperation() {
 795  0 @Override public Object value(boolean l, boolean r) { return l | r; }
 796  0 @Override public Object value(int l, int r) { return l | r; }
 797  0 @Override public Object value(long l, long r) { return l | r; }
 798    };
 799   
 800    public static final Lambda2<Object, Object, Object> EXCLUSIVE_OR = new MatchingPrimitiveBinaryOperation() {
 801  0 @Override public Object value(boolean l, boolean r) { return l ^ r; }
 802  0 @Override public Object value(int l, int r) { return l ^ r; }
 803  0 @Override public Object value(long l, long r) { return l ^ r; }
 804    };
 805   
 806    public static final Lambda2<Object, Object, Object> SHIFT_LEFT = new ShiftOperation() {
 807  0 @Override public Object value(int l, int r) { return l << r; }
 808  0 @Override public Object value(int l, long r) { return l << r; }
 809  0 @Override public Object value(long l, int r) { return l << r; }
 810  0 @Override public Object value(long l, long r) { return l << r; }
 811    };
 812   
 813    public static final Lambda2<Object, Object, Object> SHIFT_RIGHT = new ShiftOperation() {
 814  0 @Override public Object value(int l, int r) { return l >> r; }
 815  0 @Override public Object value(int l, long r) { return l >> r; }
 816  0 @Override public Object value(long l, int r) { return l >> r; }
 817  0 @Override public Object value(long l, long r) { return l >> r; }
 818    };
 819   
 820    public static final Lambda2<Object, Object, Object> UNSIGNED_SHIFT_RIGHT = new ShiftOperation() {
 821  0 @Override public Object value(int l, int r) { return l >>> r; }
 822  0 @Override public Object value(int l, long r) { return l >>> r; }
 823  0 @Override public Object value(long l, int r) { return l >>> r; }
 824  0 @Override public Object value(long l, long r) { return l >>> r; }
 825    };
 826   
 827    }