|
4 | 4 |
|
5 | 5 | import org.python.core.stringlib.FloatFormatter; |
6 | 6 | import org.python.core.stringlib.InternalFormat; |
| 7 | +import org.python.core.stringlib.InternalFormat.Formatter; |
7 | 8 | import org.python.core.stringlib.InternalFormat.Spec; |
8 | 9 | import org.python.expose.ExposedGet; |
9 | 10 | import org.python.expose.ExposedMethod; |
@@ -174,7 +175,9 @@ final PyString complex___repr__() { |
174 | 175 | * @return formatted value |
175 | 176 | */ |
176 | 177 | private String formatComplex(Spec spec) { |
177 | | - FloatFormatter f = new FloatFormatter(spec, 2, 3); // Two elements + "(j)".length |
| 178 | + int size = 2 * FloatFormatter.size(spec) + 3; // 2 floats + "(j)" |
| 179 | + FloatFormatter f = new FloatFormatter(new StringBuilder(size), spec); |
| 180 | + f.setBytes(true); |
178 | 181 | // Even in r-format, complex strips *all* the trailing zeros. |
179 | 182 | f.setMinFracDigits(0); |
180 | 183 | if (Double.doubleToLongBits(real) == 0L) { |
@@ -816,42 +819,87 @@ public PyObject __format__(PyObject formatSpec) { |
816 | 819 |
|
817 | 820 | @ExposedMethod(doc = BuiltinDocs.complex___format___doc) |
818 | 821 | final PyObject complex___format__(PyObject formatSpec) { |
819 | | - if (!(formatSpec instanceof PyString)) { |
820 | | - throw Py.TypeError("__format__ requires str or unicode"); |
821 | | - } |
822 | 822 |
|
| 823 | + // Parse the specification |
| 824 | + Spec spec = InternalFormat.fromText(formatSpec, "__format__"); |
| 825 | + |
| 826 | + // fromText will have thrown if formatSpecStr is not a PyString (including PyUnicode) |
823 | 827 | PyString formatSpecStr = (PyString)formatSpec; |
824 | 828 | String result; |
825 | | - try { |
826 | | - String specString = formatSpecStr.getString(); |
827 | | - Spec spec = InternalFormat.fromText(specString); |
828 | | - if (spec.type != Spec.NONE && "efgEFGn%".indexOf(spec.type) < 0) { |
829 | | - throw FloatFormatter.unknownFormat(spec.type, "complex"); |
830 | | - } else if (spec.alternate) { |
831 | | - throw FloatFormatter.alternateFormNotAllowed("complex"); |
832 | | - } else if (spec.fill == '0') { |
833 | | - throw FloatFormatter.zeroPaddingNotAllowed("complex"); |
834 | | - } else if (spec.align == '=') { |
835 | | - throw FloatFormatter.alignmentNotAllowed('=', "complex"); |
836 | | - } else { |
837 | | - if (spec.type == Spec.NONE) { |
838 | | - // In none-format, we take the default type and precision from __str__. |
839 | | - spec = spec.withDefaults(SPEC_STR); |
840 | | - // And then we use the __str__ mechanism to get parentheses or real 0 elision. |
841 | | - result = formatComplex(spec); |
| 829 | + |
| 830 | + // Validate the specification and detect the special case for none-format |
| 831 | + switch (checkSpecification(spec)) { |
| 832 | + |
| 833 | + case 0: // None-format |
| 834 | + // In none-format, we take the default type and precision from __str__. |
| 835 | + spec = spec.withDefaults(SPEC_STR); |
| 836 | + // And then we use the __str__ mechanism to get parentheses or real 0 elision. |
| 837 | + result = formatComplex(spec); |
| 838 | + break; |
| 839 | + |
| 840 | + case 1: // Floating-point formats |
| 841 | + // In any other format, defaults are those commonly used for numeric formats. |
| 842 | + spec = spec.withDefaults(Spec.NUMERIC); |
| 843 | + int size = 2 * FloatFormatter.size(spec) + 1; // 2 floats + "j" |
| 844 | + FloatFormatter f = new FloatFormatter(new StringBuilder(size), spec); |
| 845 | + f.setBytes(!(formatSpecStr instanceof PyUnicode)); |
| 846 | + // Convert both parts as per specification |
| 847 | + f.format(real).format(imag, "+").append('j'); |
| 848 | + result = f.pad().getResult(); |
| 849 | + break; |
| 850 | + |
| 851 | + default: // The type code was not recognised |
| 852 | + throw Formatter.unknownFormat(spec.type, "complex"); |
| 853 | + } |
| 854 | + |
| 855 | + // Wrap the result in the same type as the format string |
| 856 | + return formatSpecStr.createInstance(result); |
| 857 | + } |
| 858 | + |
| 859 | + /** |
| 860 | + * Validate a parsed specification, for <code>PyComplex</code>, returning 0 if it is a valid |
| 861 | + * none-format specification, 1 if it is a valid float specification, and some other value if it |
| 862 | + * not a valid type. If it has any other faults (e.g. alternate form was specified) the method |
| 863 | + * raises a descriptive exception. |
| 864 | + * |
| 865 | + * @param spec a parsed PEP-3101 format specification. |
| 866 | + * @return 0, 1, or other value for none-format, a float format, or incorrect type. |
| 867 | + * @throws PyException(ValueError) if the specification is faulty. |
| 868 | + */ |
| 869 | + @SuppressWarnings("fallthrough") |
| 870 | + private static int checkSpecification(Spec spec) { |
| 871 | + |
| 872 | + // Slight differences between format types |
| 873 | + switch (spec.type) { |
| 874 | + |
| 875 | + case 'n': |
| 876 | + if (spec.grouping) { |
| 877 | + throw Formatter.notAllowed("Grouping", "complex", spec.type); |
| 878 | + } |
| 879 | + // Fall through |
| 880 | + |
| 881 | + case Spec.NONE: |
| 882 | + case 'e': |
| 883 | + case 'f': |
| 884 | + case 'g': |
| 885 | + case 'E': |
| 886 | + case 'F': |
| 887 | + case 'G': |
| 888 | + // Check for disallowed parts of the specification |
| 889 | + if (spec.alternate) { |
| 890 | + throw FloatFormatter.alternateFormNotAllowed("complex"); |
| 891 | + } else if (spec.fill == '0') { |
| 892 | + throw FloatFormatter.zeroPaddingNotAllowed("complex"); |
| 893 | + } else if (spec.align == '=') { |
| 894 | + throw FloatFormatter.alignmentNotAllowed('=', "complex"); |
842 | 895 | } else { |
843 | | - // In any other format, defaults are those commonly used for numeric formats. |
844 | | - spec = spec.withDefaults(Spec.NUMERIC); |
845 | | - FloatFormatter f = new FloatFormatter(spec, 2, 1);// 2 floats + "j" |
846 | | - // Convert both parts as per specification |
847 | | - f.format(real).format(imag, "+").append('j'); |
848 | | - result = f.pad().getResult(); |
| 896 | + return (spec.type == Spec.NONE) ? 0 : 1; |
849 | 897 | } |
850 | | - } |
851 | | - } catch (IllegalArgumentException e) { |
852 | | - throw Py.ValueError(e.getMessage()); // XXX Can this be reached? |
| 898 | + |
| 899 | + default: |
| 900 | + // spec.type is invalid for complex |
| 901 | + return 2; |
853 | 902 | } |
854 | | - return formatSpecStr.createInstance(result); |
855 | 903 | } |
856 | 904 |
|
857 | 905 | @Override |
|
0 commit comments