@@ -918,6 +918,7 @@ public Object reversed(VirtualFrame frame, Object cls, Object sequence,
918
918
public abstract static class FloatNode extends PythonBuiltinNode {
919
919
@ Child private BytesNodes .ToBytesNode toByteArrayNode ;
920
920
@ Child private LookupAndCallUnaryNode callFloatNode ;
921
+ @ Child private LookupAndCallUnaryNode callReprNode ;
921
922
922
923
@ Child private IsBuiltinClassProfile isPrimitiveProfile = IsBuiltinClassProfile .create ();
923
924
private ConditionProfile isNanProfile ;
@@ -973,8 +974,8 @@ Object floatFromDouble(Object cls, double arg) {
973
974
}
974
975
975
976
@ 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 );
978
979
if (isPrimitiveFloat (cls )) {
979
980
return value ;
980
981
}
@@ -991,18 +992,38 @@ Object floatFromBytes(VirtualFrame frame, Object cls, PIBytesLike arg) {
991
992
}
992
993
993
994
private double convertBytesToDouble (VirtualFrame frame , PIBytesLike arg ) {
994
- return convertStringToDouble (createString (getByteArray (frame , arg )));
995
+ return convertStringToDouble (frame , createString (getByteArray (frame , arg )), arg );
995
996
}
996
997
997
998
@ TruffleBoundary
998
999
private static String createString (byte [] bytes ) {
999
1000
return new String (bytes );
1000
1001
}
1001
1002
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
1004
1025
@ TruffleBoundary
1005
- private double convertStringToDouble (String str ) {
1026
+ private double convertStringToDoubleOrThrow (String str ) throws NumberFormatException {
1006
1027
StringBuilder s = null ;
1007
1028
int n = str .length ();
1008
1029
@@ -1023,23 +1044,17 @@ private double convertStringToDouble(String str) {
1023
1044
if (s != null ) {
1024
1045
sval = s .toString ();
1025
1046
}
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 ;
1042
1056
}
1057
+ return Double .parseDouble (sval );
1043
1058
}
1044
1059
1045
1060
@ Specialization (guards = "!isNativeClass(cls)" )
@@ -1058,7 +1073,7 @@ Object floatFromNone(Object cls, @SuppressWarnings("unused") PNone arg) {
1058
1073
return 0.0 ;
1059
1074
}
1060
1075
if (obj instanceof String ) {
1061
- return convertStringToDouble ((String ) obj );
1076
+ return convertStringToDouble (frame , (String ) obj , obj );
1062
1077
}
1063
1078
// Follows logic from PyNumber_Float:
1064
1079
// lib.asJavaDouble cannot be used here because it models PyFloat_AsDouble,
@@ -1086,12 +1101,12 @@ Object floatFromNone(Object cls, @SuppressWarnings("unused") PNone arg) {
1086
1101
}
1087
1102
// Follows logic from PyFloat_FromString:
1088
1103
if (obj instanceof PString ) {
1089
- return convertStringToDouble (((PString ) obj ).getValue ());
1104
+ return convertStringToDouble (frame , ((PString ) obj ).getValue (), obj );
1090
1105
} else if (obj instanceof PIBytesLike ) {
1091
1106
return convertBytesToDouble (frame , (PIBytesLike ) obj );
1092
1107
} else if (lib .isBuffer (obj )) {
1093
1108
try {
1094
- return convertStringToDouble (createString (lib .getBufferBytes (obj )));
1109
+ return convertStringToDouble (frame , createString (lib .getBufferBytes (obj )), obj );
1095
1110
} catch (UnsupportedMessageException e ) {
1096
1111
CompilerDirectives .transferToInterpreterAndInvalidate ();
1097
1112
throw new IllegalStateException ("Object claims to be a buffer but does not support getBufferBytes()" );
0 commit comments