Skip to content
This repository was archived by the owner on Jul 17, 2024. It is now read-only.

Commit 8fb60b9

Browse files
chore: Address sonar issues
1 parent ca4b7e4 commit 8fb60b9

File tree

5 files changed

+167
-150
lines changed

5 files changed

+167
-150
lines changed

jpyinterpreter/src/main/java/ai/timefold/jpyinterpreter/implementors/JavaPythonTypeConversionImplementor.java

+73-71
Original file line numberDiff line numberDiff line change
@@ -100,42 +100,41 @@ public static PythonLikeObject wrapJavaObject(Object object, Map<Object, PythonL
100100
return PythonString.valueOf(string);
101101
}
102102

103-
if (object instanceof Iterator iterator) {
103+
if (object instanceof Iterator<?> iterator) {
104104
return new DelegatePythonIterator<>(iterator);
105105
}
106106

107-
if (object instanceof List list) {
108-
PythonLikeList out = new PythonLikeList();
107+
if (object instanceof List<?> list) {
108+
PythonLikeList<?> out = new PythonLikeList<>();
109109
createdObjectMap.put(object, out);
110110
for (Object item : list) {
111111
out.add(wrapJavaObject(item));
112112
}
113113
return out;
114114
}
115115

116-
if (object instanceof Set set) {
117-
PythonLikeSet out = new PythonLikeSet();
116+
if (object instanceof Set<?> set) {
117+
PythonLikeSet<?> out = new PythonLikeSet<>();
118118
createdObjectMap.put(object, out);
119119
for (Object item : set) {
120120
out.add(wrapJavaObject(item));
121121
}
122122
return out;
123123
}
124124

125-
if (object instanceof Map map) {
126-
PythonLikeDict out = new PythonLikeDict();
125+
if (object instanceof Map<?, ?> map) {
126+
PythonLikeDict<?, ?> out = new PythonLikeDict<>();
127127
createdObjectMap.put(object, out);
128-
Set<Map.Entry<?, ?>> entrySet = map.entrySet();
129-
for (Map.Entry<?, ?> entry : entrySet) {
128+
var entrySet = map.entrySet();
129+
for (var entry : entrySet) {
130130
out.put(wrapJavaObject(entry.getKey()), wrapJavaObject(entry.getValue()));
131131
}
132132
return out;
133133
}
134134

135-
if (object instanceof Class maybeFunctionClass) {
136-
if (Set.of(maybeFunctionClass.getInterfaces()).contains(PythonLikeFunction.class)) {
137-
return new PythonCode((Class<? extends PythonLikeFunction>) maybeFunctionClass);
138-
}
135+
if (object instanceof Class<?> maybeFunctionClass &&
136+
Set.of(maybeFunctionClass.getInterfaces()).contains(PythonLikeFunction.class)) {
137+
return new PythonCode((Class<? extends PythonLikeFunction>) maybeFunctionClass);
139138
}
140139

141140
if (object instanceof OpaquePythonReference opaquePythonReference) {
@@ -263,8 +262,7 @@ public static <T> T convertPythonObjectToJavaType(Class<? extends T> type, Pytho
263262
return null;
264263
}
265264

266-
if (object instanceof JavaObjectWrapper) {
267-
JavaObjectWrapper wrappedObject = (JavaObjectWrapper) object;
265+
if (object instanceof JavaObjectWrapper wrappedObject) {
268266
Object javaObject = wrappedObject.getWrappedObject();
269267
if (!type.isAssignableFrom(javaObject.getClass())) {
270268
throw new TypeError("Cannot convert from (" + getPythonLikeType(javaObject.getClass()) + ") to ("
@@ -275,11 +273,10 @@ public static <T> T convertPythonObjectToJavaType(Class<? extends T> type, Pytho
275273

276274
if (type.equals(byte.class) || type.equals(short.class) || type.equals(int.class) || type.equals(long.class) ||
277275
type.equals(float.class) || type.equals(double.class) || Number.class.isAssignableFrom(type)) {
278-
if (!(object instanceof PythonNumber)) {
276+
if (!(object instanceof PythonNumber pythonNumber)) {
279277
throw new TypeError("Cannot convert from (" + getPythonLikeType(object.getClass()) + ") to ("
280278
+ getPythonLikeType(type) + ").");
281279
}
282-
PythonNumber pythonNumber = (PythonNumber) object;
283280
Number value = pythonNumber.getValue();
284281

285282
if (type.equals(BigInteger.class) || type.equals(BigDecimal.class)) {
@@ -312,11 +309,10 @@ public static <T> T convertPythonObjectToJavaType(Class<? extends T> type, Pytho
312309
}
313310

314311
if (type.equals(boolean.class) || type.equals(Boolean.class)) {
315-
if (!(object instanceof PythonBoolean)) {
312+
if (!(object instanceof PythonBoolean pythonBoolean)) {
316313
throw new TypeError("Cannot convert from (" + getPythonLikeType(object.getClass()) + ") to ("
317314
+ getPythonLikeType(type) + ").");
318315
}
319-
PythonBoolean pythonBoolean = (PythonBoolean) object;
320316
return (T) (Boolean) pythonBoolean.getBooleanValue();
321317
}
322318

@@ -344,6 +340,53 @@ public static void loadName(MethodVisitor methodVisitor, String name) {
344340
false);
345341
}
346342

343+
private record ReturnValueOpDescriptor(
344+
String wrapperClassName,
345+
String methodName,
346+
String methodDescriptor,
347+
int opcode,
348+
boolean noConversionNeeded) {
349+
public static ReturnValueOpDescriptor noConversion() {
350+
return new ReturnValueOpDescriptor("", "", "",
351+
Opcodes.ARETURN, true);
352+
}
353+
354+
public static ReturnValueOpDescriptor forNumeric(String methodName,
355+
String methodDescriptor,
356+
int opcode) {
357+
return new ReturnValueOpDescriptor(Type.getInternalName(Number.class), methodName, methodDescriptor, opcode,
358+
false);
359+
}
360+
}
361+
362+
private static final Map<Type, ReturnValueOpDescriptor> numericReturnValueOpDescriptorMap = Map.of(
363+
Type.BYTE_TYPE, ReturnValueOpDescriptor.forNumeric(
364+
"byteValue",
365+
Type.getMethodDescriptor(Type.BYTE_TYPE),
366+
Opcodes.IRETURN),
367+
Type.SHORT_TYPE, ReturnValueOpDescriptor.forNumeric(
368+
"shortValue",
369+
Type.getMethodDescriptor(Type.SHORT_TYPE),
370+
Opcodes.IRETURN),
371+
Type.INT_TYPE, ReturnValueOpDescriptor.forNumeric(
372+
"intValue",
373+
Type.getMethodDescriptor(Type.INT_TYPE),
374+
Opcodes.IRETURN),
375+
Type.LONG_TYPE, ReturnValueOpDescriptor.forNumeric(
376+
"longValue",
377+
Type.getMethodDescriptor(Type.LONG_TYPE),
378+
Opcodes.LRETURN),
379+
Type.FLOAT_TYPE, ReturnValueOpDescriptor.forNumeric(
380+
"floatValue",
381+
Type.getMethodDescriptor(Type.FLOAT_TYPE),
382+
Opcodes.FRETURN),
383+
Type.DOUBLE_TYPE, ReturnValueOpDescriptor.forNumeric(
384+
"doubleValue",
385+
Type.getMethodDescriptor(Type.DOUBLE_TYPE),
386+
Opcodes.DRETURN),
387+
Type.getType(BigInteger.class), ReturnValueOpDescriptor.noConversion(),
388+
Type.getType(BigDecimal.class), ReturnValueOpDescriptor.noConversion());
389+
347390
/**
348391
* If {@code method} return type is not void, convert TOS into its Java equivalent and return it.
349392
* If {@code method} return type is void, immediately return.
@@ -353,77 +396,36 @@ public static void loadName(MethodVisitor methodVisitor, String name) {
353396
public static void returnValue(MethodVisitor methodVisitor, MethodDescriptor method, StackMetadata stackMetadata) {
354397
Type returnAsmType = method.getReturnType();
355398

399+
if (Type.CHAR_TYPE.equals(returnAsmType)) {
400+
throw new IllegalStateException("Unhandled case for primitive type (char).");
401+
}
402+
356403
if (Type.VOID_TYPE.equals(returnAsmType)) {
357404
methodVisitor.visitInsn(Opcodes.RETURN);
358405
return;
359406
}
360407

361-
if (Type.BYTE_TYPE.equals(returnAsmType) ||
362-
Type.CHAR_TYPE.equals(returnAsmType) ||
363-
Type.SHORT_TYPE.equals(returnAsmType) ||
364-
Type.INT_TYPE.equals(returnAsmType) ||
365-
Type.LONG_TYPE.equals(returnAsmType) ||
366-
Type.FLOAT_TYPE.equals(returnAsmType) ||
367-
Type.DOUBLE_TYPE.equals(returnAsmType) ||
368-
Type.getType(BigInteger.class).equals(returnAsmType) ||
369-
Type.getType(BigDecimal.class).equals(returnAsmType)) {
408+
if (numericReturnValueOpDescriptorMap.containsKey(returnAsmType)) {
409+
var returnValueOpDescriptor = numericReturnValueOpDescriptorMap.get(returnAsmType);
370410
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(PythonNumber.class));
371411
methodVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE,
372412
Type.getInternalName(PythonNumber.class),
373413
"getValue",
374414
Type.getMethodDescriptor(Type.getType(Number.class)),
375415
true);
376416

377-
if (Type.getType(BigInteger.class).equals(returnAsmType) ||
378-
Type.getType(BigDecimal.class).equals(returnAsmType)) {
417+
if (returnValueOpDescriptor.noConversionNeeded) {
379418
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, returnAsmType.getInternalName());
380419
methodVisitor.visitInsn(Opcodes.ARETURN);
381420
return;
382421
}
383422

384-
String wrapperClassName = null;
385-
String methodName = null;
386-
String methodDescriptor = null;
387-
int returnOpcode = 0;
388-
389-
if (Type.BYTE_TYPE.equals(returnAsmType)) {
390-
wrapperClassName = Type.getInternalName(Number.class);
391-
methodName = "byteValue";
392-
methodDescriptor = Type.getMethodDescriptor(Type.BYTE_TYPE);
393-
returnOpcode = Opcodes.IRETURN;
394-
} else if (Type.CHAR_TYPE.equals(returnAsmType)) {
395-
throw new IllegalStateException("Unhandled case for primitive type (char).");
396-
// returnOpcode = Opcodes.IRETURN;
397-
} else if (Type.SHORT_TYPE.equals(returnAsmType)) {
398-
wrapperClassName = Type.getInternalName(Number.class);
399-
methodName = "shortValue";
400-
methodDescriptor = Type.getMethodDescriptor(Type.SHORT_TYPE);
401-
returnOpcode = Opcodes.IRETURN;
402-
} else if (Type.INT_TYPE.equals(returnAsmType)) {
403-
wrapperClassName = Type.getInternalName(Number.class);
404-
methodName = "intValue";
405-
methodDescriptor = Type.getMethodDescriptor(Type.INT_TYPE);
406-
returnOpcode = Opcodes.IRETURN;
407-
} else if (Type.FLOAT_TYPE.equals(returnAsmType)) {
408-
wrapperClassName = Type.getInternalName(Number.class);
409-
methodName = "floatValue";
410-
methodDescriptor = Type.getMethodDescriptor(Type.FLOAT_TYPE);
411-
returnOpcode = Opcodes.FRETURN;
412-
} else if (Type.LONG_TYPE.equals(returnAsmType)) {
413-
wrapperClassName = Type.getInternalName(Number.class);
414-
methodName = "longValue";
415-
methodDescriptor = Type.getMethodDescriptor(Type.LONG_TYPE);
416-
returnOpcode = Opcodes.LRETURN;
417-
} else if (Type.DOUBLE_TYPE.equals(returnAsmType)) {
418-
wrapperClassName = Type.getInternalName(Number.class);
419-
methodName = "doubleValue";
420-
methodDescriptor = Type.getMethodDescriptor(Type.DOUBLE_TYPE);
421-
returnOpcode = Opcodes.DRETURN;
422-
}
423423
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
424-
wrapperClassName, methodName, methodDescriptor,
424+
returnValueOpDescriptor.wrapperClassName,
425+
returnValueOpDescriptor.methodName,
426+
returnValueOpDescriptor.methodDescriptor,
425427
false);
426-
methodVisitor.visitInsn(returnOpcode);
428+
methodVisitor.visitInsn(returnValueOpDescriptor.opcode);
427429
return;
428430
}
429431

jpyinterpreter/src/main/java/ai/timefold/jpyinterpreter/types/collections/PythonLikeTuple.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,14 @@ public PythonLikeTuple<T> createNewInstance() {
113113
return new PythonLikeTuple<>();
114114
}
115115

116-
public static PythonLikeTuple fromItems(PythonLikeObject... items) {
117-
PythonLikeTuple result = new PythonLikeTuple();
116+
public static <T extends PythonLikeObject> PythonLikeTuple<T> fromItems(T... items) {
117+
PythonLikeTuple<T> result = new PythonLikeTuple<>();
118118
Collections.addAll(result, items);
119119
return result;
120120
}
121121

122-
public static PythonLikeTuple fromList(List<PythonLikeObject> other) {
123-
PythonLikeTuple result = new PythonLikeTuple();
122+
public static <T extends PythonLikeObject> PythonLikeTuple<T> fromList(List<T> other) {
123+
PythonLikeTuple<T> result = new PythonLikeTuple<>();
124124
result.addAll(other);
125125
return result;
126126
}

jpyinterpreter/src/main/java/ai/timefold/jpyinterpreter/types/numeric/PythonDecimal.java

+22-16
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,7 @@ private static PythonLikeType registerMethods() throws NoSuchMethodException {
3434
if (positionalArguments.size() == 0) {
3535
return new PythonDecimal(BigDecimal.ZERO);
3636
} else if (positionalArguments.size() == 1) {
37-
PythonLikeObject value = positionalArguments.get(0);
38-
if (value instanceof PythonInteger integer) {
39-
return PythonDecimal.valueOf(integer);
40-
} else if (value instanceof PythonFloat pythonFloat) {
41-
return PythonDecimal.valueOf(pythonFloat);
42-
} else if (value instanceof PythonString str) {
43-
return PythonDecimal.valueOf(str);
44-
} else {
45-
throw new TypeError(
46-
"conversion from %s to Decimal is not supported".formatted(value.$getType().getTypeName()));
47-
}
37+
return PythonDecimal.from(positionalArguments.get(0));
4838
} else if (positionalArguments.size() == 2) {
4939
// TODO: Support context
5040
throw new ValueError("context constructor not supported");
@@ -72,6 +62,19 @@ public PythonDecimal(BigDecimal value) {
7262
this.value = value;
7363
}
7464

65+
public static PythonDecimal from(PythonLikeObject value) {
66+
if (value instanceof PythonInteger integer) {
67+
return PythonDecimal.valueOf(integer);
68+
} else if (value instanceof PythonFloat pythonFloat) {
69+
return PythonDecimal.valueOf(pythonFloat);
70+
} else if (value instanceof PythonString str) {
71+
return PythonDecimal.valueOf(str);
72+
} else {
73+
throw new TypeError(
74+
"conversion from %s to Decimal is not supported".formatted(value.$getType().getTypeName()));
75+
}
76+
}
77+
7578
public static PythonDecimal $method$from_float(PythonFloat value) {
7679
return new PythonDecimal(new BigDecimal(value.value, threadMathContext.get()));
7780
}
@@ -129,6 +132,7 @@ public int hashCode() {
129132
return $method$__hash__().value.intValue();
130133
}
131134

135+
@Override
132136
public PythonInteger $method$__hash__() {
133137
var scale = value.scale();
134138
if (scale <= 0) {
@@ -352,7 +356,7 @@ public int hashCode() {
352356
return PythonInteger.valueOf(value.unscaledValue().toString().length() - 1 - value.scale());
353357
}
354358

355-
public PythonLikeTuple $method$as_integer_ratio() {
359+
public PythonLikeTuple<PythonInteger> $method$as_integer_ratio() {
356360
var parts = value.divideAndRemainder(BigDecimal.ONE);
357361
var integralPart = parts[0];
358362
var fractionPart = parts[1];
@@ -373,7 +377,7 @@ public int hashCode() {
373377
PythonInteger.valueOf(reducedDenominator));
374378
}
375379

376-
public PythonLikeTuple $method$as_tuple() {
380+
public PythonLikeTuple<PythonLikeObject> $method$as_tuple() {
377381
// TODO: Use named tuple
378382
return PythonLikeTuple.fromItems(PythonInteger.valueOf(value.signum() >= 0 ? 0 : 1),
379383
value.unscaledValue().abs().toString()
@@ -555,7 +559,7 @@ private static BigDecimal getEPower(BigDecimal value, int precision) {
555559
private static PythonDecimal logicalOp(BiPredicate<Boolean, Boolean> op,
556560
BigDecimal a, BigDecimal b) {
557561
if (a.scale() < 0 || b.scale() < 0) {
558-
throw new ValueError("Invalid Operation");
562+
throw new ValueError("Invalid Operation: both operands must be positive integers consisting of 1's and 0's");
559563
}
560564
var aText = a.toPlainString();
561565
var bText = b.toPlainString();
@@ -571,12 +575,14 @@ private static PythonDecimal logicalOp(BiPredicate<Boolean, Boolean> op,
571575
var aBit = switch (aText.charAt(i)) {
572576
case '0' -> false;
573577
case '1' -> true;
574-
default -> throw new ValueError("Invalid Operation");
578+
default -> throw new ValueError(("Invalid Operation: first operand (%s) is not a positive integer " +
579+
"consisting of 1's and 0's").formatted(a));
575580
};
576581
var bBit = switch (bText.charAt(i)) {
577582
case '0' -> false;
578583
case '1' -> true;
579-
default -> throw new ValueError("Invalid Operation");
584+
default -> throw new ValueError(("Invalid Operation: second operand (%s) is not a positive integer " +
585+
"consisting of 1's and 0's").formatted(b));
580586
};
581587
result.append(op.test(aBit, bBit) ? '1' : '0');
582588
}

0 commit comments

Comments
 (0)