private static Boolean compareNumbers(Object o1, Object o2, IElementType op) {
    // JLS 15.20.1. Numerical Comparison Operators <, <=, >, and >=
    // JLS 15.21.1. Numerical Equality Operators == and !=
    // JLS 5.6.2 Binary Numeric Promotion
    if (o1 instanceof Character) o1 = (int)((Character)o1).charValue();
    if (o2 instanceof Character) o2 = (int)((Character)o2).charValue();
    if (!(o1 instanceof Number) || !(o2 instanceof Number)) return null;
    Number n1 = (Number)o1;
    Number n2 = (Number)o2;
    int result;
    if (n1 instanceof Double || n2 instanceof Double) {
      double v1 = n1.doubleValue();
      double v2 = n2.doubleValue();
      if (Double.isNaN(v1) || Double.isNaN(v2)) return op == JavaTokenType.NE;
      //Cannot use Double.compare as we don't need special treatment of 0.0 and -0.0 here
      //noinspection UseCompareMethod
      result = v1 < v2 ? -1 : v1 == v2 ? 0 : 1;
    } else if (n1 instanceof Float || n2 instanceof Float) {
      float v1 = n1.floatValue();
      float v2 = n2.floatValue();
      if (Float.isNaN(v1) || Float.isNaN(v2)) return op == JavaTokenType.NE;
      //Cannot use Float.compare as we don't need special treatment of 0.0 and -0.0 here
      //noinspection UseCompareMethod
      result = v1 < v2 ? -1 : v1 == v2 ? 0 : 1;
    } else if (n1 instanceof Long || n2 instanceof Long) {
      result = Long.compare(n1.longValue(), n2.longValue());
    } else {
      result = Integer.compare(n1.intValue(), n2.intValue());
    }
    if (op == JavaTokenType.EQEQ) return result == 0;
    if (op == JavaTokenType.LT) return result < 0;
    if (op == JavaTokenType.LE) return result <= 0;
    if (op == JavaTokenType.GT) return result > 0;
    if (op == JavaTokenType.GE) return result >= 0;
    if (op == JavaTokenType.NE) return result != 0;
    throw new IllegalArgumentException("Unexpected operator: " + op);
  }
private static Boolean compareNumbers(Object o1, Object o2, IElementType op)