ExpressionEvaluatorImpl implements ExpressionEvaluator { private <T extends Comparable<? super T>> T evaluateBinaryArithmeticExpression(BinaryArithmeticExpression binaryArithmeticExpression, DataRow dataRow) { Object left = binaryArithmeticExpression.getLeft(); Object right = binaryArithmeticExpression.getRight(); BinaryArithmeticOperator binaryArithmeticOperator = binaryArithmeticExpression.getBinaryArithmeticOperator(); if (oneOfIsNull(left, right)) { throw new IllegalArgumentException(String.format( "Nulls are not allowed in arithmetic expressions: %s %s %s", left, binaryArithmeticOperator.getText(), right )); } if (!isConstant(left.getClass())) { return evaluateBinaryArithmeticExpression(new BinaryArithmeticExpression(evaluate(left, dataRow), binaryArithmeticOperator, right), dataRow); } if (!isConstant(right.getClass())) { return evaluateBinaryArithmeticExpression(new BinaryArithmeticExpression(left, binaryArithmeticOperator, evaluate(right, dataRow)), dataRow); } Class<?> leftClass = left.getClass(); Class<?> rightClass = right.getClass(); if (!bothAreNumbers(leftClass, rightClass)) { throw new IllegalArgumentException(String.format( "Arithmetic expression can contain only numbers: %s %s %s", left, binaryArithmeticOperator.getText(), right )); } switch (binaryArithmeticOperator) { default: case PLUS: return bothAreIntegers(leftClass, rightClass) ? cast(asInt(left) + asInt(right), Integer.class, Comparable.class) : cast(asDouble(left) + asDouble(right), Double.class, Comparable.class); case MINUS: return bothAreIntegers(leftClass, rightClass) ? cast(asInt(left) - asInt(right), Integer.class, Comparable.class) : cast(asDouble(left) - asDouble(right), Double.class, Comparable.class); case MULTIPLY: return bothAreIntegers(leftClass, rightClass) ? cast(asInt(left) * asInt(right), Integer.class, Comparable.class) : cast(asDouble(left) * asDouble(right), Double.class, Comparable.class); case DIVIDE: return bothAreIntegers(leftClass, rightClass) ? cast(asInt(left) / asInt(right), Integer.class, Comparable.class) : cast(asDouble(left) / asDouble(right), Double.class, Comparable.class); case MOD: return bothAreIntegers(leftClass, rightClass) ? cast(asInt(left) % asInt(right), Integer.class, Comparable.class) : cast(asDouble(left) % asDouble(right), Double.class, Comparable.class); case BIT_AND: { if (!bothAreIntegers(leftClass, rightClass)) { throw new IllegalArgumentException(String.format( "Bitwise AND operation is only applicable to integers: %s %s %s", left, binaryArithmeticOperator.getText(), right )); } return cast(asInt(left) & asInt(right), Integer.class, Comparable.class); } case BIT_OR: { if (!bothAreIntegers(leftClass, rightClass)) { throw new IllegalArgumentException(String.format( "Bitwise OR operation is only applicable to integers: %s %s %s", left, binaryArithmeticOperator.getText(), right )); } return cast(asInt(left) | asInt(right), Integer.class, Comparable.class); } case BIT_XOR: { if (!bothAreIntegers(leftClass, rightClass)) { throw new IllegalArgumentException(String.format( "Bitwise XOR operation is only applicable to integers: %s %s %s", left, binaryArithmeticOperator.getText(), right )); } return cast(asInt(left) ^ asInt(right), Integer.class, Comparable.class); } case SHIFT_LEFT: { if (!bothAreIntegers(leftClass, rightClass)) { throw new IllegalArgumentException(String.format( "Bitwise SHIFT LEFT operation is only applicable to integers: %s %s %s", left, binaryArithmeticOperator.getText(), right )); } return cast(asInt(left) << asInt(right), Integer.class, Comparable.class); } case SHIFT_RIGHT: { if (!bothAreIntegers(leftClass, rightClass)) { throw new IllegalArgumentException(String.format( "Bitwise SHIFT RIGHT operation is only applicable to integers: %s %s %s", left, binaryArithmeticOperator.getText(), right )); } return cast(asInt(left) >> asInt(right), Integer.class, Comparable.class); } } }  @Override Map<String, Set<String>> getColumnNames(Object expression); @Override T evaluate(Object expression, DataRow dataRow); @Override T evaluateAs(Object expression, DataRow dataRow, Class<T> cls);  }
@Test public void testEvaluateBinaryArithmeticExpression() { assertThat(arithmetic(2, BinaryArithmeticOperator.PLUS, 1, Integer.class), equalTo(3)); assertThat(arithmetic(3d, BinaryArithmeticOperator.PLUS, absFunction(), ROW_WITH_VALUES, Double.class), equalTo(6d)); assertThat(arithmetic(2, BinaryArithmeticOperator.MINUS, 1, Integer.class), equalTo(1)); assertThat(arithmetic(3d, BinaryArithmeticOperator.MINUS, 1.5d, Double.class), equalTo(1.5)); assertThat(arithmetic(2, MULTIPLY, 1, Integer.class), equalTo(2)); assertThat(arithmetic(2d, MULTIPLY, 1.5d, Double.class), equalTo(3d)); assertThat(arithmetic(2, DIVIDE, 1, Integer.class), equalTo(2)); assertThat(arithmetic(3d, DIVIDE, 1.5d, Double.class), equalTo(2d)); assertThat(arithmetic(4, MOD, 3, Integer.class), equalTo(1)); assertThat(arithmetic(5d, MOD, 3d, Double.class), equalTo(2d)); assertThat(arithmetic(0b101, BIT_AND, 0b100, Integer.class), equalTo(0b100)); assertThat(arithmetic(0b101, BIT_OR, 0b100, Integer.class), equalTo(0b101)); assertThat(arithmetic(0b101, BIT_XOR, 0b100, Integer.class), equalTo(0b001)); assertThat(arithmetic(0b001, SHIFT_LEFT, 2, Integer.class), equalTo(0b100)); assertThat(arithmetic(0b100, SHIFT_RIGHT, 2, Integer.class), equalTo(0b001)); }