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 |