|
4 | 4 |
|
5 | 5 | import java.io.Serializable; |
6 | 6 | import java.math.BigInteger; |
7 | | -import java.text.NumberFormat; |
8 | | -import java.util.Locale; |
9 | 7 |
|
10 | 8 | import org.python.core.stringlib.IntegerFormatter; |
| 9 | +import org.python.core.stringlib.InternalFormat; |
11 | 10 | import org.python.core.stringlib.InternalFormat.Spec; |
12 | | -import org.python.core.stringlib.InternalFormatSpec; |
13 | | -import org.python.core.stringlib.InternalFormatSpecParser; |
14 | 11 | import org.python.expose.ExposedGet; |
15 | 12 | import org.python.expose.ExposedMethod; |
16 | 13 | import org.python.expose.ExposedNew; |
@@ -1022,151 +1019,68 @@ public PyObject __format__(PyObject formatSpec) { |
1022 | 1019 | return int___format__(formatSpec); |
1023 | 1020 | } |
1024 | 1021 |
|
| 1022 | + @SuppressWarnings("fallthrough") |
1025 | 1023 | @ExposedMethod(doc = BuiltinDocs.int___format___doc) |
1026 | 1024 | final PyObject int___format__(PyObject formatSpec) { |
1027 | | - return formatImpl(getValue(), formatSpec); |
1028 | | - } |
1029 | | - |
1030 | | - static PyObject formatImpl(Object value, PyObject formatSpec) { |
1031 | | - if (!(formatSpec instanceof PyString)) { |
1032 | | - throw Py.TypeError("__format__ requires str or unicode"); |
1033 | | - } |
1034 | | - |
1035 | | - PyString formatSpecStr = (PyString)formatSpec; |
1036 | | - String result; |
1037 | | - try { |
1038 | | - String specString = formatSpecStr.getString(); |
1039 | | - InternalFormatSpec spec = new InternalFormatSpecParser(specString).parse(); |
1040 | | - result = formatIntOrLong(value, spec); |
1041 | | - } catch (IllegalArgumentException e) { |
1042 | | - throw Py.ValueError(e.getMessage()); |
1043 | | - } |
1044 | | - return formatSpecStr.createInstance(result); |
| 1025 | + // Get a formatter for the specification |
| 1026 | + IntegerFormatter f = prepareFormatter(formatSpec); |
| 1027 | + // Convert as per specification. |
| 1028 | + f.format(value); |
| 1029 | + // Return a result that has the same type (str or unicode) as the formatSpec argument. |
| 1030 | + return f.pad().getPyResult(); |
1045 | 1031 | } |
1046 | 1032 |
|
1047 | 1033 | /** |
1048 | | - * Formats an integer or long number according to a PEP-3101 format specification. |
| 1034 | + * Common code for PyInteger and PyLong to prepare an IntegerFormatter. This object has an |
| 1035 | + * overloaded format method {@link IntegerFormatter#format(int)} and |
| 1036 | + * {@link IntegerFormatter#format(BigInteger)} to support the two types. |
1049 | 1037 | * |
1050 | | - * @param value Integer or BigInteger object specifying the value to format. |
1051 | | - * @param spec parsed PEP-3101 format specification. |
1052 | | - * @return result of the formatting. |
| 1038 | + * @param formatSpec PEP-3101 format specification. |
| 1039 | + * @return a formatter ready to use. |
| 1040 | + * @throws PyException(ValueError) if the specification is faulty. |
1053 | 1041 | */ |
1054 | | - public static String formatIntOrLong(Object value, InternalFormatSpec spec) { |
1055 | | - if (spec.precision != -1) { |
1056 | | - throw new IllegalArgumentException("Precision not allowed in integer format specifier"); |
1057 | | - } |
1058 | | - |
1059 | | - int sign; |
1060 | | - if (value instanceof Integer) { |
1061 | | - int intValue = (Integer)value; |
1062 | | - sign = intValue < 0 ? -1 : intValue == 0 ? 0 : 1; |
1063 | | - } else { |
1064 | | - sign = ((BigInteger)value).signum(); |
1065 | | - } |
| 1042 | + static IntegerFormatter prepareFormatter(PyObject formatSpec) throws PyException { |
1066 | 1043 |
|
1067 | | - String strValue; |
1068 | | - String strPrefix = ""; |
1069 | | - String strSign = ""; |
| 1044 | + // Parse the specification |
| 1045 | + Spec spec = InternalFormat.fromText(formatSpec, "__format__"); |
| 1046 | + IntegerFormatter f; |
1070 | 1047 |
|
1071 | | - if (spec.type == 'c') { |
1072 | | - if (spec.sign != '\0') { |
1073 | | - throw new IllegalArgumentException("Sign not allowed with integer format " |
1074 | | - + "specifier 'c'"); |
1075 | | - } |
1076 | | - if (value instanceof Integer) { |
1077 | | - int intValue = (Integer)value; |
1078 | | - if (intValue > 0xffff) { |
1079 | | - throw new IllegalArgumentException("%c arg not in range(0x10000)"); |
1080 | | - } |
1081 | | - strValue = Character.toString((char)intValue); |
1082 | | - } else { |
1083 | | - BigInteger bigInt = (BigInteger)value; |
1084 | | - if (bigInt.intValue() > 0xffff || bigInt.bitCount() > 16) { |
1085 | | - throw new IllegalArgumentException("%c arg not in range(0x10000)"); |
1086 | | - } |
1087 | | - strValue = Character.toString((char)bigInt.intValue()); |
1088 | | - } |
1089 | | - } else { |
1090 | | - int radix = 10; |
1091 | | - if (spec.type == 'o') { |
1092 | | - radix = 8; |
1093 | | - } else if (spec.type == 'x' || spec.type == 'X') { |
1094 | | - radix = 16; |
1095 | | - } else if (spec.type == 'b') { |
1096 | | - radix = 2; |
1097 | | - } |
1098 | | - |
1099 | | - if (spec.type == 'n') { |
1100 | | - strValue = NumberFormat.getNumberInstance().format(value); |
1101 | | - } else if (spec.thousands_separators) { |
1102 | | - NumberFormat format = NumberFormat.getNumberInstance(Locale.US); |
1103 | | - format.setGroupingUsed(true); |
1104 | | - strValue = format.format(value); |
1105 | | - } else if (value instanceof BigInteger) { |
1106 | | - switch (radix) { |
1107 | | - case 2: |
1108 | | - strValue = toBinString((BigInteger)value); |
1109 | | - break; |
1110 | | - case 8: |
1111 | | - strValue = toOctString((BigInteger)value); |
1112 | | - break; |
1113 | | - case 16: |
1114 | | - strValue = toHexString((BigInteger)value); |
1115 | | - break; |
1116 | | - default: |
1117 | | - // General case (v.slow in known implementations up to Java 7). |
1118 | | - strValue = ((BigInteger)value).toString(radix); |
1119 | | - break; |
1120 | | - } |
1121 | | - } else { |
1122 | | - strValue = Integer.toString((Integer)value, radix); |
1123 | | - } |
1124 | | - |
1125 | | - if (spec.alternate) { |
1126 | | - switch (radix) { |
1127 | | - case 2: |
1128 | | - strPrefix = "0b"; |
1129 | | - break; |
1130 | | - case 8: |
1131 | | - strPrefix = "0o"; |
1132 | | - break; |
1133 | | - case 16: |
1134 | | - strPrefix = "0x"; |
1135 | | - break; |
1136 | | - } |
1137 | | - |
1138 | | - if (sign < 0) { |
1139 | | - assert (strValue.startsWith("-")); |
1140 | | - strSign = "-"; |
1141 | | - strValue = strValue.substring(1); |
1142 | | - } |
1143 | | - } |
1144 | | - |
1145 | | - if (spec.type == 'X') { |
1146 | | - strPrefix = strPrefix.toUpperCase(); |
1147 | | - strValue = strValue.toUpperCase(); |
1148 | | - } |
1149 | | - |
1150 | | - if (sign >= 0) { |
1151 | | - switch (spec.sign) { |
1152 | | - case '+': |
1153 | | - case ' ': |
1154 | | - strSign = Character.toString(spec.sign); |
1155 | | - break; |
1156 | | - } |
1157 | | - } |
| 1048 | + // Check for disallowed parts of the specification |
| 1049 | + if (Spec.specified(spec.precision)) { |
| 1050 | + throw IntegerFormatter.precisionNotAllowed("integer"); |
1158 | 1051 | } |
1159 | 1052 |
|
1160 | | - if (spec.align == '=' && (spec.sign == '-' || spec.sign == '+' || spec.sign == ' ')) { |
1161 | | - assert (strSign.length() == 1); |
1162 | | - return strSign + strPrefix + spec.pad(strValue, '>', 1 + strPrefix.length()); |
1163 | | - } |
| 1053 | + // Slight differences between format types |
| 1054 | + switch (spec.type) { |
| 1055 | + case 'c': |
| 1056 | + // Character data |
| 1057 | + if (Spec.specified(spec.sign)) { |
| 1058 | + throw IntegerFormatter.notAllowed("Sign", "integer", spec.type); |
| 1059 | + } else if (spec.alternate) { |
| 1060 | + throw IntegerFormatter.alternateFormNotAllowed("integer", spec.type); |
| 1061 | + } |
| 1062 | + // Fall through |
| 1063 | + |
| 1064 | + case Spec.NONE: |
| 1065 | + case 'd': |
| 1066 | + case 'x': |
| 1067 | + case 'X': |
| 1068 | + case 'o': |
| 1069 | + case 'b': |
| 1070 | + case 'n': |
| 1071 | + // spec may be incomplete. The defaults are those commonly used for numeric formats. |
| 1072 | + spec = spec.withDefaults(Spec.NUMERIC); |
| 1073 | + // Get a formatter for the spec. |
| 1074 | + f = new IntegerFormatter(spec, 1); |
| 1075 | + // Bytes mode if formatSpec argument is not unicode. |
| 1076 | + f.setBytes(!(formatSpec instanceof PyUnicode)); |
| 1077 | + break; |
1164 | 1078 |
|
1165 | | - if (spec.fill_char == 0) { |
1166 | | - return spec.pad(strSign + strPrefix + strValue, '>', 0); |
| 1079 | + default: |
| 1080 | + throw IntegerFormatter.unknownFormat(spec.type, "integer"); |
1167 | 1081 | } |
1168 | 1082 |
|
1169 | | - return strSign + strPrefix + spec.pad(strValue, '>', strSign.length() + strPrefix.length()); |
| 1083 | + return f; |
1170 | 1084 | } |
1171 | 1085 |
|
1172 | 1086 | /** |
|
0 commit comments