|
77 | 77 | import com.oracle.graal.python.builtins.objects.bytes.BytesUtils;
|
78 | 78 | import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject;
|
79 | 79 | import com.oracle.graal.python.builtins.objects.common.FormatNodeBase;
|
| 80 | +import com.oracle.graal.python.builtins.objects.common.HashingCollectionNodes; |
80 | 81 | import com.oracle.graal.python.builtins.objects.common.HashingStorage;
|
81 | 82 | import com.oracle.graal.python.builtins.objects.common.HashingStorageLibrary;
|
82 | 83 | import com.oracle.graal.python.builtins.objects.common.SequenceNodes.GetObjectArrayNode;
|
@@ -773,50 +774,80 @@ private static String toUpperCase(String str) {
|
773 | 774 | }
|
774 | 775 | }
|
775 | 776 |
|
776 |
| - // static str.maketrans() |
| 777 | + // str.maketrans() |
777 | 778 | @Builtin(name = "maketrans", minNumOfPositionalArgs = 2, maxNumOfPositionalArgs = 4, isClassmethod = true)
|
778 | 779 | @GenerateNodeFactory
|
779 | 780 | public abstract static class MakeTransNode extends PythonQuaternaryBuiltinNode {
|
780 | 781 |
|
781 | 782 | @Specialization(guards = "!isNoValue(to)")
|
782 | 783 | @SuppressWarnings("unused")
|
783 |
| - PDict doString(VirtualFrame frame, Object cls, Object from, Object to, Object z, |
| 784 | + PDict doString(Object cls, Object from, Object to, Object z, |
784 | 785 | @Cached CastToJavaStringCheckedNode castFromNode,
|
785 | 786 | @Cached CastToJavaStringCheckedNode castToNode,
|
| 787 | + @Cached CastToJavaStringCheckedNode castZNode, |
| 788 | + @Cached ConditionProfile hasZProfile, |
786 | 789 | @CachedLibrary(limit = "2") HashingStorageLibrary lib) {
|
787 | 790 |
|
788 | 791 | String toStr = castToNode.cast(to, "argument 2 must be str, not %p", to);
|
789 | 792 | String fromStr = castFromNode.cast(from, "first maketrans argument must be a string if there is a second argument");
|
790 |
| - if (fromStr.length() != toStr.length()) { |
791 |
| - throw raise(PythonBuiltinClassType.ValueError, ErrorMessages.FIRST_TWO_MAKETRANS_ARGS_MUST_HAVE_EQ_LENGTH); |
| 793 | + boolean hasZ = hasZProfile.profile(z != PNone.NO_VALUE); |
| 794 | + String zString = null; |
| 795 | + if (hasZ) { |
| 796 | + zString = castZNode.cast(z, ErrorMessages.ARG_D_MUST_BE_S_NOT_P, "maketrans()", 3, "str", z); |
792 | 797 | }
|
793 | 798 |
|
794 | 799 | HashingStorage storage = PDict.createNewStorage(false, fromStr.length());
|
795 |
| - PDict translation = factory().createDict(storage); |
796 |
| - for (int i = 0; i < fromStr.length(); i++) { |
797 |
| - int key = fromStr.charAt(i); |
798 |
| - int value = toStr.charAt(i); |
| 800 | + int i, j; |
| 801 | + for (i = 0, j = 0; i < fromStr.length() && j < toStr.length();) { |
| 802 | + int key = PString.codePointAt(fromStr, i); |
| 803 | + int value = PString.codePointAt(toStr, j); |
799 | 804 | storage = lib.setItem(storage, key, value);
|
| 805 | + i += PString.charCount(key); |
| 806 | + j += PString.charCount(value); |
| 807 | + } |
| 808 | + if (i < fromStr.length() || j < toStr.length()) { |
| 809 | + throw raise(PythonBuiltinClassType.ValueError, ErrorMessages.FIRST_TWO_MAKETRANS_ARGS_MUST_HAVE_EQ_LENGTH); |
| 810 | + } |
| 811 | + if (hasZ) { |
| 812 | + for (i = 0; i < zString.length();) { |
| 813 | + int key = PString.codePointAt(zString, i); |
| 814 | + storage = lib.setItem(storage, key, PNone.NONE); |
| 815 | + i += PString.charCount(key); |
| 816 | + } |
800 | 817 | }
|
801 |
| - translation.setDictStorage(storage); |
802 |
| - |
803 |
| - // TODO implement character deletion specified with 'z' |
804 | 818 |
|
805 |
| - return translation; |
| 819 | + return factory().createDict(storage); |
806 | 820 | }
|
807 | 821 |
|
808 |
| - @Specialization(guards = "isNoValue(to)") |
| 822 | + @Specialization(guards = {"isNoValue(to)", "isNoValue(z)"}) |
809 | 823 | @SuppressWarnings("unused")
|
810 |
| - static PDict doDict(PDict from, Object cls, Object to, Object z) { |
811 |
| - // TODO implement dict case; see CPython 'unicodeobject.c' function |
812 |
| - // 'unicode_maketrans_impl' |
813 |
| - CompilerDirectives.transferToInterpreterAndInvalidate(); |
814 |
| - throw new IllegalStateException("not yet implemented"); |
| 824 | + PDict doDict(VirtualFrame frame, Object cls, PDict from, Object to, Object z, |
| 825 | + @Cached HashingCollectionNodes.GetHashingStorageNode getHashingStorageNode, |
| 826 | + @Cached CastToJavaStringCheckedNode cast, |
| 827 | + @CachedLibrary(limit = "3") HashingStorageLibrary hlib) { |
| 828 | + HashingStorage srcStorage = getHashingStorageNode.execute(frame, from); |
| 829 | + HashingStorage destStorage = PDict.createNewStorage(false, hlib.length(srcStorage)); |
| 830 | + for (HashingStorage.DictEntry entry : hlib.entries(srcStorage)) { |
| 831 | + if (PGuards.isInteger(entry.key) || PGuards.isPInt(entry.key)) { |
| 832 | + hlib.setItem(destStorage, entry.key, entry.value); |
| 833 | + } else { |
| 834 | + String strKey = cast.cast(entry.key, ErrorMessages.KEYS_IN_TRANSLATE_TABLE_MUST_BE_STRINGS_OR_INTEGERS); |
| 835 | + if (strKey.isEmpty()) { |
| 836 | + throw raise(ValueError, ErrorMessages.STRING_KEYS_MUST_BE_LENGHT_1); |
| 837 | + } |
| 838 | + int codePoint = PString.codePointAt(strKey, 0); |
| 839 | + if (strKey.length() != PString.charCount(codePoint)) { |
| 840 | + throw raise(ValueError, ErrorMessages.STRING_KEYS_MUST_BE_LENGHT_1); |
| 841 | + } |
| 842 | + hlib.setItem(destStorage, codePoint, entry.value); |
| 843 | + } |
| 844 | + } |
| 845 | + return factory().createDict(destStorage); |
815 | 846 | }
|
816 | 847 |
|
817 | 848 | @Specialization(guards = {"!isDict(from)", "isNoValue(to)"})
|
818 | 849 | @SuppressWarnings("unused")
|
819 |
| - PDict doFail(Object from, Object cls, Object to, Object z) { |
| 850 | + PDict doFail(Object cls, Object from, Object to, Object z) { |
820 | 851 | throw raise(PythonBuiltinClassType.TypeError, ErrorMessages.IF_YOU_GIVE_ONLY_ONE_ARG_TO_DICT);
|
821 | 852 | }
|
822 | 853 | }
|
|
0 commit comments