| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 (function(global, utils) { | 5 (function(global, utils) { |
| 6 | 6 |
| 7 'use strict'; | 7 'use strict'; |
| 8 | 8 |
| 9 %CheckIsBootstrapping(); | 9 %CheckIsBootstrapping(); |
| 10 | 10 |
| (...skipping 759 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 770 if (previousLastIndex != 0) this.lastIndex = 0; | 770 if (previousLastIndex != 0) this.lastIndex = 0; |
| 771 var result = RegExpSubclassExec(this, string); | 771 var result = RegExpSubclassExec(this, string); |
| 772 var currentLastIndex = this.lastIndex; | 772 var currentLastIndex = this.lastIndex; |
| 773 if (currentLastIndex != previousLastIndex) this.lastIndex = previousLastIndex; | 773 if (currentLastIndex != previousLastIndex) this.lastIndex = previousLastIndex; |
| 774 if (IS_NULL(result)) return -1; | 774 if (IS_NULL(result)) return -1; |
| 775 return result.index; | 775 return result.index; |
| 776 } | 776 } |
| 777 %FunctionRemovePrototype(RegExpSubclassSearch); | 777 %FunctionRemovePrototype(RegExpSubclassSearch); |
| 778 | 778 |
| 779 | 779 |
| 780 // Getters for the static properties lastMatch, lastParen, leftContext, and | |
| 781 // rightContext of the RegExp constructor. The properties are computed based | |
| 782 // on the captures array of the last successful match and the subject string | |
| 783 // of the last successful match. | |
| 784 function RegExpGetLastMatch() { | |
| 785 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo); | |
| 786 return %_SubString(regExpSubject, | |
| 787 RegExpLastMatchInfo[CAPTURE0], | |
| 788 RegExpLastMatchInfo[CAPTURE1]); | |
| 789 } | |
| 790 | |
| 791 | |
| 792 function RegExpGetLastParen() { | |
| 793 var length = NUMBER_OF_CAPTURES(RegExpLastMatchInfo); | |
| 794 if (length <= 2) return ''; // There were no captures. | |
| 795 // We match the SpiderMonkey behavior: return the substring defined by the | |
| 796 // last pair (after the first pair) of elements of the capture array even if | |
| 797 // it is empty. | |
| 798 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo); | |
| 799 var start = RegExpLastMatchInfo[CAPTURE(length - 2)]; | |
| 800 var end = RegExpLastMatchInfo[CAPTURE(length - 1)]; | |
| 801 if (start != -1 && end != -1) { | |
| 802 return %_SubString(regExpSubject, start, end); | |
| 803 } | |
| 804 return ""; | |
| 805 } | |
| 806 | |
| 807 | |
| 808 function RegExpGetLeftContext() { | |
| 809 var start_index; | |
| 810 var subject; | |
| 811 start_index = RegExpLastMatchInfo[CAPTURE0]; | |
| 812 subject = LAST_SUBJECT(RegExpLastMatchInfo); | |
| 813 return %_SubString(subject, 0, start_index); | |
| 814 } | |
| 815 | |
| 816 | |
| 817 function RegExpGetRightContext() { | |
| 818 var start_index; | |
| 819 var subject; | |
| 820 start_index = RegExpLastMatchInfo[CAPTURE1]; | |
| 821 subject = LAST_SUBJECT(RegExpLastMatchInfo); | |
| 822 return %_SubString(subject, start_index, subject.length); | |
| 823 } | |
| 824 | |
| 825 | |
| 826 // The properties $1..$9 are the first nine capturing substrings of the last | |
| 827 // successful match, or ''. The function RegExpMakeCaptureGetter will be | |
| 828 // called with indices from 1 to 9. | |
| 829 function RegExpMakeCaptureGetter(n) { | |
| 830 return function foo() { | |
| 831 var index = n * 2; | |
| 832 if (index >= NUMBER_OF_CAPTURES(RegExpLastMatchInfo)) return ''; | |
| 833 var matchStart = RegExpLastMatchInfo[CAPTURE(index)]; | |
| 834 var matchEnd = RegExpLastMatchInfo[CAPTURE(index + 1)]; | |
| 835 if (matchStart == -1 || matchEnd == -1) return ''; | |
| 836 return %_SubString(LAST_SUBJECT(RegExpLastMatchInfo), matchStart, matchEnd); | |
| 837 }; | |
| 838 } | |
| 839 | |
| 840 | |
| 841 // ES6 21.2.5.3. | |
| 842 function RegExpGetFlags() { | |
| 843 if (!IS_RECEIVER(this)) { | |
| 844 throw %make_type_error( | |
| 845 kRegExpNonObject, "RegExp.prototype.flags", TO_STRING(this)); | |
| 846 } | |
| 847 var result = ''; | |
| 848 if (this.global) result += 'g'; | |
| 849 if (this.ignoreCase) result += 'i'; | |
| 850 if (this.multiline) result += 'm'; | |
| 851 if (this.unicode) result += 'u'; | |
| 852 if (this.sticky) result += 'y'; | |
| 853 return result; | |
| 854 } | |
| 855 | |
| 856 | |
| 857 // ES6 21.2.5.4. | |
| 858 function RegExpGetGlobal() { | |
| 859 if (!IS_REGEXP(this)) { | |
| 860 if (this === GlobalRegExpPrototype) { | |
| 861 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); | |
| 862 return UNDEFINED; | |
| 863 } | |
| 864 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.global"); | |
| 865 } | |
| 866 return TO_BOOLEAN(REGEXP_GLOBAL(this)); | |
| 867 } | |
| 868 %SetForceInlineFlag(RegExpGetGlobal); | |
| 869 | |
| 870 | |
| 871 // ES6 21.2.5.5. | |
| 872 function RegExpGetIgnoreCase() { | |
| 873 if (!IS_REGEXP(this)) { | |
| 874 if (this === GlobalRegExpPrototype) { | |
| 875 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); | |
| 876 return UNDEFINED; | |
| 877 } | |
| 878 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.ignoreCase"); | |
| 879 } | |
| 880 return TO_BOOLEAN(REGEXP_IGNORE_CASE(this)); | |
| 881 } | |
| 882 | |
| 883 | |
| 884 // ES6 21.2.5.7. | |
| 885 function RegExpGetMultiline() { | |
| 886 if (!IS_REGEXP(this)) { | |
| 887 if (this === GlobalRegExpPrototype) { | |
| 888 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); | |
| 889 return UNDEFINED; | |
| 890 } | |
| 891 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.multiline"); | |
| 892 } | |
| 893 return TO_BOOLEAN(REGEXP_MULTILINE(this)); | |
| 894 } | |
| 895 | |
| 896 | |
| 897 // ES6 21.2.5.10. | |
| 898 function RegExpGetSource() { | |
| 899 if (!IS_REGEXP(this)) { | |
| 900 if (this === GlobalRegExpPrototype) { | |
| 901 %IncrementUseCounter(kRegExpPrototypeSourceGetter); | |
| 902 return "(?:)"; | |
| 903 } | |
| 904 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.source"); | |
| 905 } | |
| 906 return REGEXP_SOURCE(this); | |
| 907 } | |
| 908 | |
| 909 | |
| 910 // ES6 21.2.5.12. | |
| 911 function RegExpGetSticky() { | |
| 912 if (!IS_REGEXP(this)) { | |
| 913 if (this === GlobalRegExpPrototype) { | |
| 914 %IncrementUseCounter(kRegExpPrototypeStickyGetter); | |
| 915 return UNDEFINED; | |
| 916 } | |
| 917 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.sticky"); | |
| 918 } | |
| 919 return TO_BOOLEAN(REGEXP_STICKY(this)); | |
| 920 } | |
| 921 %SetForceInlineFlag(RegExpGetSticky); | |
| 922 | |
| 923 | |
| 924 // ES6 21.2.5.15. | |
| 925 function RegExpGetUnicode() { | |
| 926 if (!IS_REGEXP(this)) { | |
| 927 if (this === GlobalRegExpPrototype) { | |
| 928 %IncrementUseCounter(kRegExpPrototypeUnicodeGetter); | |
| 929 return UNDEFINED; | |
| 930 } | |
| 931 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.unicode"); | |
| 932 } | |
| 933 return TO_BOOLEAN(REGEXP_UNICODE(this)); | |
| 934 } | |
| 935 %SetForceInlineFlag(RegExpGetUnicode); | |
| 936 | |
| 937 | |
| 938 function RegExpSpecies() { | |
| 939 return this; | |
| 940 } | |
| 941 | |
| 942 | |
| 943 // ------------------------------------------------------------------- | 780 // ------------------------------------------------------------------- |
| 944 | 781 |
| 945 utils.InstallGetter(GlobalRegExp, speciesSymbol, RegExpSpecies); | |
| 946 | |
| 947 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [ | 782 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [ |
| 948 "test", RegExpSubclassTest, | 783 "test", RegExpSubclassTest, |
| 949 "toString", RegExpToString, | 784 "toString", RegExpToString, |
| 950 "compile", RegExpCompileJS, | 785 "compile", RegExpCompileJS, |
| 951 matchSymbol, RegExpSubclassMatch, | 786 matchSymbol, RegExpSubclassMatch, |
| 952 replaceSymbol, RegExpSubclassReplace, | 787 replaceSymbol, RegExpSubclassReplace, |
| 953 searchSymbol, RegExpSubclassSearch, | 788 searchSymbol, RegExpSubclassSearch, |
| 954 splitSymbol, RegExpSubclassSplit, | 789 splitSymbol, RegExpSubclassSplit, |
| 955 ]); | 790 ]); |
| 956 | 791 |
| 957 utils.InstallGetter(GlobalRegExp.prototype, 'flags', RegExpGetFlags); | |
| 958 utils.InstallGetter(GlobalRegExp.prototype, 'global', RegExpGetGlobal); | |
| 959 utils.InstallGetter(GlobalRegExp.prototype, 'ignoreCase', RegExpGetIgnoreCase); | |
| 960 utils.InstallGetter(GlobalRegExp.prototype, 'multiline', RegExpGetMultiline); | |
| 961 utils.InstallGetter(GlobalRegExp.prototype, 'source', RegExpGetSource); | |
| 962 utils.InstallGetter(GlobalRegExp.prototype, 'sticky', RegExpGetSticky); | |
| 963 utils.InstallGetter(GlobalRegExp.prototype, 'unicode', RegExpGetUnicode); | |
| 964 | |
| 965 // The properties `input` and `$_` are aliases for each other. When this | |
| 966 // value is set the value it is set to is coerced to a string. | |
| 967 // Getter and setter for the input. | |
| 968 var RegExpGetInput = function() { | |
| 969 var regExpInput = LAST_INPUT(RegExpLastMatchInfo); | |
| 970 return IS_UNDEFINED(regExpInput) ? "" : regExpInput; | |
| 971 }; | |
| 972 var RegExpSetInput = function(string) { | |
| 973 LAST_INPUT(RegExpLastMatchInfo) = TO_STRING(string); | |
| 974 }; | |
| 975 | |
| 976 // TODO(jgruber): All of these getters and setters were intended to be installed | |
| 977 // with various attributes (e.g. DONT_ENUM | DONT_DELETE), but | |
| 978 // InstallGetterSetter had a bug which ignored the passed attributes and | |
| 979 // simply installed as DONT_ENUM instead. We might want to change back | |
| 980 // to the intended attributes at some point. | |
| 981 // On the other hand, installing attributes as DONT_ENUM matches the draft | |
| 982 // specification at | |
| 983 // https://github.com/claudepache/es-regexp-legacy-static-properties | |
| 984 | |
| 985 %OptimizeObjectForAddingMultipleProperties(GlobalRegExp, 22); | |
| 986 utils.InstallGetterSetter(GlobalRegExp, 'input', RegExpGetInput, RegExpSetInput, | |
| 987 DONT_ENUM); | |
| 988 utils.InstallGetterSetter(GlobalRegExp, '$_', RegExpGetInput, RegExpSetInput, | |
| 989 DONT_ENUM); | |
| 990 | |
| 991 | |
| 992 var NoOpSetter = function(ignored) {}; | |
| 993 | |
| 994 | |
| 995 // Static properties set by a successful match. | |
| 996 utils.InstallGetterSetter(GlobalRegExp, 'lastMatch', RegExpGetLastMatch, | |
| 997 NoOpSetter, DONT_ENUM); | |
| 998 utils.InstallGetterSetter(GlobalRegExp, '$&', RegExpGetLastMatch, NoOpSetter, | |
| 999 DONT_ENUM); | |
| 1000 utils.InstallGetterSetter(GlobalRegExp, 'lastParen', RegExpGetLastParen, | |
| 1001 NoOpSetter, DONT_ENUM); | |
| 1002 utils.InstallGetterSetter(GlobalRegExp, '$+', RegExpGetLastParen, NoOpSetter, | |
| 1003 DONT_ENUM); | |
| 1004 utils.InstallGetterSetter(GlobalRegExp, 'leftContext', RegExpGetLeftContext, | |
| 1005 NoOpSetter, DONT_ENUM); | |
| 1006 utils.InstallGetterSetter(GlobalRegExp, '$`', RegExpGetLeftContext, NoOpSetter, | |
| 1007 DONT_ENUM); | |
| 1008 utils.InstallGetterSetter(GlobalRegExp, 'rightContext', RegExpGetRightContext, | |
| 1009 NoOpSetter, DONT_ENUM); | |
| 1010 utils.InstallGetterSetter(GlobalRegExp, "$'", RegExpGetRightContext, NoOpSetter, | |
| 1011 DONT_ENUM); | |
| 1012 | |
| 1013 for (var i = 1; i < 10; ++i) { | |
| 1014 utils.InstallGetterSetter(GlobalRegExp, '$' + i, RegExpMakeCaptureGetter(i), | |
| 1015 NoOpSetter, DONT_ENUM); | |
| 1016 } | |
| 1017 %ToFastProperties(GlobalRegExp); | |
| 1018 | |
| 1019 %InstallToContext(["regexp_last_match_info", RegExpLastMatchInfo]); | 792 %InstallToContext(["regexp_last_match_info", RegExpLastMatchInfo]); |
| 1020 | 793 |
| 1021 // ------------------------------------------------------------------- | 794 // ------------------------------------------------------------------- |
| 1022 // Internal | 795 // Internal |
| 1023 | 796 |
| 1024 var InternalRegExpMatchInfo = { | 797 var InternalRegExpMatchInfo = { |
| 1025 REGEXP_NUMBER_OF_CAPTURES: 2, | 798 REGEXP_NUMBER_OF_CAPTURES: 2, |
| 1026 REGEXP_LAST_SUBJECT: "", | 799 REGEXP_LAST_SUBJECT: "", |
| 1027 REGEXP_LAST_INPUT: UNDEFINED, | 800 REGEXP_LAST_INPUT: UNDEFINED, |
| 1028 CAPTURE0: 0, | 801 CAPTURE0: 0, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1049 to.GetSubstitution = GetSubstitution; | 822 to.GetSubstitution = GetSubstitution; |
| 1050 to.InternalRegExpMatch = InternalRegExpMatch; | 823 to.InternalRegExpMatch = InternalRegExpMatch; |
| 1051 to.InternalRegExpReplace = InternalRegExpReplace; | 824 to.InternalRegExpReplace = InternalRegExpReplace; |
| 1052 to.IsRegExp = IsRegExp; | 825 to.IsRegExp = IsRegExp; |
| 1053 to.RegExpExec = DoRegExpExec; | 826 to.RegExpExec = DoRegExpExec; |
| 1054 to.RegExpInitialize = RegExpInitialize; | 827 to.RegExpInitialize = RegExpInitialize; |
| 1055 to.RegExpLastMatchInfo = RegExpLastMatchInfo; | 828 to.RegExpLastMatchInfo = RegExpLastMatchInfo; |
| 1056 }); | 829 }); |
| 1057 | 830 |
| 1058 }) | 831 }) |
| OLD | NEW |