Skip to content

Commit 272c3ff

Browse files
committed
Use repr() when formatting the error message in float() constructor
1 parent 89ad7de commit 272c3ff

File tree

1 file changed

+40
-25
lines changed

1 file changed

+40
-25
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinConstructors.java

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,7 @@ public Object reversed(VirtualFrame frame, Object cls, Object sequence,
918918
public abstract static class FloatNode extends PythonBuiltinNode {
919919
@Child private BytesNodes.ToBytesNode toByteArrayNode;
920920
@Child private LookupAndCallUnaryNode callFloatNode;
921+
@Child private LookupAndCallUnaryNode callReprNode;
921922

922923
@Child private IsBuiltinClassProfile isPrimitiveProfile = IsBuiltinClassProfile.create();
923924
private ConditionProfile isNanProfile;
@@ -973,8 +974,8 @@ Object floatFromDouble(Object cls, double arg) {
973974
}
974975

975976
@Specialization(guards = "!isNativeClass(cls)")
976-
Object floatFromString(Object cls, String arg) {
977-
double value = convertStringToDouble(arg);
977+
Object floatFromString(VirtualFrame frame, Object cls, String arg) {
978+
double value = convertStringToDouble(frame, arg, arg);
978979
if (isPrimitiveFloat(cls)) {
979980
return value;
980981
}
@@ -991,18 +992,38 @@ Object floatFromBytes(VirtualFrame frame, Object cls, PIBytesLike arg) {
991992
}
992993

993994
private double convertBytesToDouble(VirtualFrame frame, PIBytesLike arg) {
994-
return convertStringToDouble(createString(getByteArray(frame, arg)));
995+
return convertStringToDouble(frame, createString(getByteArray(frame, arg)), arg);
995996
}
996997

997998
@TruffleBoundary
998999
private static String createString(byte[] bytes) {
9991000
return new String(bytes);
10001001
}
10011002

1002-
// Taken from Jython PyString's atof() method
1003-
// The last statement throw Py.ValueError is modified
1003+
private double convertStringToDouble(VirtualFrame frame, String str, Object origObj) {
1004+
try {
1005+
return convertStringToDoubleOrThrow(str);
1006+
} catch (NumberFormatException exc) {
1007+
if (callReprNode == null) {
1008+
CompilerDirectives.transferToInterpreterAndInvalidate();
1009+
callReprNode = insert(LookupAndCallUnaryNode.create(__REPR__));
1010+
}
1011+
Object strStr = callReprNode.executeObject(frame, origObj);
1012+
if (PGuards.isString(strStr)) {
1013+
throw raise(ValueError, ErrorMessages.COULD_NOT_CONVERT_STRING_TO_FLOAT, strStr);
1014+
} else {
1015+
// During the formatting of "ValueError: invalid literal ..." exception,
1016+
// CPython attempts to raise "TypeError: __repr__ returned non-string",
1017+
// which gets later overwitten with the original "ValueError",
1018+
// but without any message (since the message formatting failed)
1019+
throw raise(ValueError);
1020+
}
1021+
}
1022+
}
1023+
1024+
// Adapted from Jython PyString's atof() method
10041025
@TruffleBoundary
1005-
private double convertStringToDouble(String str) {
1026+
private double convertStringToDoubleOrThrow(String str) throws NumberFormatException {
10061027
StringBuilder s = null;
10071028
int n = str.length();
10081029

@@ -1023,23 +1044,17 @@ private double convertStringToDouble(String str) {
10231044
if (s != null) {
10241045
sval = s.toString();
10251046
}
1026-
try {
1027-
// Double.valueOf allows format specifier ("d" or "f") at the end
1028-
String lowSval = sval.toLowerCase(Locale.ENGLISH);
1029-
if (lowSval.equals("nan") || lowSval.equals("+nan")) {
1030-
return Double.NaN;
1031-
} else if (lowSval.equals("-nan")) {
1032-
return Math.copySign(Double.NaN, -1);
1033-
} else if (lowSval.equals("inf") || lowSval.equals("+inf") || lowSval.equals("infinity") || lowSval.equals("+infinity")) {
1034-
return Double.POSITIVE_INFINITY;
1035-
} else if (lowSval.equals("-inf") || lowSval.equals("-infinity")) {
1036-
return Double.NEGATIVE_INFINITY;
1037-
}
1038-
return Double.valueOf(sval).doubleValue();
1039-
} catch (NumberFormatException exc) {
1040-
// throw Py.ValueError("invalid literal for __float__: " + str);
1041-
throw raise(ValueError, ErrorMessages.COULD_NOT_CONVERT_STRING_TO_FLOAT, str);
1047+
String lowSval = sval.toLowerCase(Locale.ENGLISH);
1048+
if (lowSval.equals("nan") || lowSval.equals("+nan")) {
1049+
return Double.NaN;
1050+
} else if (lowSval.equals("-nan")) {
1051+
return Math.copySign(Double.NaN, -1);
1052+
} else if (lowSval.equals("inf") || lowSval.equals("+inf") || lowSval.equals("infinity") || lowSval.equals("+infinity")) {
1053+
return Double.POSITIVE_INFINITY;
1054+
} else if (lowSval.equals("-inf") || lowSval.equals("-infinity")) {
1055+
return Double.NEGATIVE_INFINITY;
10421056
}
1057+
return Double.parseDouble(sval);
10431058
}
10441059

10451060
@Specialization(guards = "!isNativeClass(cls)")
@@ -1058,7 +1073,7 @@ Object floatFromNone(Object cls, @SuppressWarnings("unused") PNone arg) {
10581073
return 0.0;
10591074
}
10601075
if (obj instanceof String) {
1061-
return convertStringToDouble((String) obj);
1076+
return convertStringToDouble(frame, (String) obj, obj);
10621077
}
10631078
// Follows logic from PyNumber_Float:
10641079
// lib.asJavaDouble cannot be used here because it models PyFloat_AsDouble,
@@ -1086,12 +1101,12 @@ Object floatFromNone(Object cls, @SuppressWarnings("unused") PNone arg) {
10861101
}
10871102
// Follows logic from PyFloat_FromString:
10881103
if (obj instanceof PString) {
1089-
return convertStringToDouble(((PString) obj).getValue());
1104+
return convertStringToDouble(frame, ((PString) obj).getValue(), obj);
10901105
} else if (obj instanceof PIBytesLike) {
10911106
return convertBytesToDouble(frame, (PIBytesLike) obj);
10921107
} else if (lib.isBuffer(obj)) {
10931108
try {
1094-
return convertStringToDouble(createString(lib.getBufferBytes(obj)));
1109+
return convertStringToDouble(frame, createString(lib.getBufferBytes(obj)), obj);
10951110
} catch (UnsupportedMessageException e) {
10961111
CompilerDirectives.transferToInterpreterAndInvalidate();
10971112
throw new IllegalStateException("Object claims to be a buffer but does not support getBufferBytes()");

0 commit comments

Comments
 (0)