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 %CheckIsBootstrapping(); | 7 %CheckIsBootstrapping(); |
8 | 8 |
9 // ------------------------------------------------------------------- | 9 // ------------------------------------------------------------------- |
10 // Imports | 10 // Imports |
11 | 11 |
12 var ExpandReplacement; | 12 var ExpandReplacement; |
13 var GlobalArray = global.Array; | 13 var GlobalArray = global.Array; |
14 var GlobalObject = global.Object; | 14 var GlobalObject = global.Object; |
15 var GlobalRegExp = global.RegExp; | 15 var GlobalRegExp = global.RegExp; |
16 var InternalArray = utils.InternalArray; | 16 var InternalArray = utils.InternalArray; |
17 var InternalPackedArray = utils.InternalPackedArray; | 17 var InternalPackedArray = utils.InternalPackedArray; |
18 var MaxSimple; | 18 var MaxSimple; |
19 var MinSimple; | 19 var MinSimple; |
20 var lastMatchInfoSymbol = utils.ImportNow("regexp_last_match_info_symbol"); | |
21 var matchSymbol = utils.ImportNow("match_symbol"); | 20 var matchSymbol = utils.ImportNow("match_symbol"); |
22 var replaceSymbol = utils.ImportNow("replace_symbol"); | 21 var replaceSymbol = utils.ImportNow("replace_symbol"); |
23 var searchSymbol = utils.ImportNow("search_symbol"); | 22 var searchSymbol = utils.ImportNow("search_symbol"); |
24 var speciesSymbol = utils.ImportNow("species_symbol"); | 23 var speciesSymbol = utils.ImportNow("species_symbol"); |
25 var splitSymbol = utils.ImportNow("split_symbol"); | 24 var splitSymbol = utils.ImportNow("split_symbol"); |
26 var SpeciesConstructor; | 25 var SpeciesConstructor; |
27 | 26 |
28 utils.Import(function(from) { | 27 utils.Import(function(from) { |
29 ExpandReplacement = from.ExpandReplacement; | 28 ExpandReplacement = from.ExpandReplacement; |
30 MaxSimple = from.MaxSimple; | 29 MaxSimple = from.MaxSimple; |
(...skipping 886 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
917 var previousLastIndex = this.lastIndex; | 916 var previousLastIndex = this.lastIndex; |
918 this.lastIndex = 0; | 917 this.lastIndex = 0; |
919 var result = RegExpSubclassExec(this, string); | 918 var result = RegExpSubclassExec(this, string); |
920 this.lastIndex = previousLastIndex; | 919 this.lastIndex = previousLastIndex; |
921 if (IS_NULL(result)) return -1; | 920 if (IS_NULL(result)) return -1; |
922 return result.index; | 921 return result.index; |
923 } | 922 } |
924 %FunctionRemovePrototype(RegExpSubclassSearch); | 923 %FunctionRemovePrototype(RegExpSubclassSearch); |
925 | 924 |
926 | 925 |
| 926 // Getters for the static properties lastMatch, lastParen, leftContext, and |
| 927 // rightContext of the RegExp constructor. The properties are computed based |
| 928 // on the captures array of the last successful match and the subject string |
| 929 // of the last successful match. |
| 930 function RegExpGetLastMatch() { |
| 931 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo); |
| 932 return %_SubString(regExpSubject, |
| 933 RegExpLastMatchInfo[CAPTURE0], |
| 934 RegExpLastMatchInfo[CAPTURE1]); |
| 935 } |
| 936 |
| 937 |
| 938 function RegExpGetLastParen() { |
| 939 var length = NUMBER_OF_CAPTURES(RegExpLastMatchInfo); |
| 940 if (length <= 2) return ''; // There were no captures. |
| 941 // We match the SpiderMonkey behavior: return the substring defined by the |
| 942 // last pair (after the first pair) of elements of the capture array even if |
| 943 // it is empty. |
| 944 var regExpSubject = LAST_SUBJECT(RegExpLastMatchInfo); |
| 945 var start = RegExpLastMatchInfo[CAPTURE(length - 2)]; |
| 946 var end = RegExpLastMatchInfo[CAPTURE(length - 1)]; |
| 947 if (start != -1 && end != -1) { |
| 948 return %_SubString(regExpSubject, start, end); |
| 949 } |
| 950 return ""; |
| 951 } |
| 952 |
| 953 |
| 954 function RegExpGetLeftContext() { |
| 955 var start_index; |
| 956 var subject; |
| 957 start_index = RegExpLastMatchInfo[CAPTURE0]; |
| 958 subject = LAST_SUBJECT(RegExpLastMatchInfo); |
| 959 return %_SubString(subject, 0, start_index); |
| 960 } |
| 961 |
| 962 |
| 963 function RegExpGetRightContext() { |
| 964 var start_index; |
| 965 var subject; |
| 966 start_index = RegExpLastMatchInfo[CAPTURE1]; |
| 967 subject = LAST_SUBJECT(RegExpLastMatchInfo); |
| 968 return %_SubString(subject, start_index, subject.length); |
| 969 } |
| 970 |
| 971 |
| 972 // The properties $1..$9 are the first nine capturing substrings of the last |
| 973 // successful match, or ''. The function RegExpMakeCaptureGetter will be |
| 974 // called with indices from 1 to 9. |
| 975 function RegExpMakeCaptureGetter(n) { |
| 976 return function foo() { |
| 977 var index = n * 2; |
| 978 if (index >= NUMBER_OF_CAPTURES(RegExpLastMatchInfo)) return ''; |
| 979 var matchStart = RegExpLastMatchInfo[CAPTURE(index)]; |
| 980 var matchEnd = RegExpLastMatchInfo[CAPTURE(index + 1)]; |
| 981 if (matchStart == -1 || matchEnd == -1) return ''; |
| 982 return %_SubString(LAST_SUBJECT(RegExpLastMatchInfo), matchStart, matchEnd); |
| 983 }; |
| 984 } |
| 985 |
| 986 |
| 987 // ES6 21.2.5.3. |
| 988 function RegExpGetFlags() { |
| 989 if (!IS_RECEIVER(this)) { |
| 990 throw %make_type_error( |
| 991 kRegExpNonObject, "RegExp.prototype.flags", TO_STRING(this)); |
| 992 } |
| 993 var result = ''; |
| 994 if (this.global) result += 'g'; |
| 995 if (this.ignoreCase) result += 'i'; |
| 996 if (this.multiline) result += 'm'; |
| 997 if (this.unicode) result += 'u'; |
| 998 if (this.sticky) result += 'y'; |
| 999 return result; |
| 1000 } |
| 1001 |
| 1002 |
| 1003 // ES6 21.2.5.4. |
| 1004 function RegExpGetGlobal() { |
| 1005 if (!IS_REGEXP(this)) { |
| 1006 // TODO(littledan): Remove this RegExp compat workaround |
| 1007 if (this === GlobalRegExp.prototype) { |
| 1008 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); |
| 1009 return UNDEFINED; |
| 1010 } |
| 1011 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.global"); |
| 1012 } |
| 1013 return TO_BOOLEAN(REGEXP_GLOBAL(this)); |
| 1014 } |
| 1015 %SetForceInlineFlag(RegExpGetGlobal); |
| 1016 |
| 1017 |
| 1018 // ES6 21.2.5.5. |
| 1019 function RegExpGetIgnoreCase() { |
| 1020 if (!IS_REGEXP(this)) { |
| 1021 // TODO(littledan): Remove this RegExp compat workaround |
| 1022 if (this === GlobalRegExp.prototype) { |
| 1023 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); |
| 1024 return UNDEFINED; |
| 1025 } |
| 1026 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.ignoreCase"); |
| 1027 } |
| 1028 return TO_BOOLEAN(REGEXP_IGNORE_CASE(this)); |
| 1029 } |
| 1030 |
| 1031 |
| 1032 // ES6 21.2.5.7. |
| 1033 function RegExpGetMultiline() { |
| 1034 if (!IS_REGEXP(this)) { |
| 1035 // TODO(littledan): Remove this RegExp compat workaround |
| 1036 if (this === GlobalRegExp.prototype) { |
| 1037 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); |
| 1038 return UNDEFINED; |
| 1039 } |
| 1040 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.multiline"); |
| 1041 } |
| 1042 return TO_BOOLEAN(REGEXP_MULTILINE(this)); |
| 1043 } |
| 1044 |
| 1045 |
| 1046 // ES6 21.2.5.10. |
| 1047 function RegExpGetSource() { |
| 1048 if (!IS_REGEXP(this)) { |
| 1049 // TODO(littledan): Remove this RegExp compat workaround |
| 1050 if (this === GlobalRegExp.prototype) { |
| 1051 %IncrementUseCounter(kRegExpPrototypeSourceGetter); |
| 1052 return "(?:)"; |
| 1053 } |
| 1054 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.source"); |
| 1055 } |
| 1056 return REGEXP_SOURCE(this); |
| 1057 } |
| 1058 |
| 1059 |
| 1060 // ES6 21.2.5.12. |
| 1061 function RegExpGetSticky() { |
| 1062 if (!IS_REGEXP(this)) { |
| 1063 // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it |
| 1064 // TODO(littledan): Remove this workaround or standardize it |
| 1065 if (this === GlobalRegExp.prototype) { |
| 1066 %IncrementUseCounter(kRegExpPrototypeStickyGetter); |
| 1067 return UNDEFINED; |
| 1068 } |
| 1069 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.sticky"); |
| 1070 } |
| 1071 return TO_BOOLEAN(REGEXP_STICKY(this)); |
| 1072 } |
| 1073 %SetForceInlineFlag(RegExpGetSticky); |
| 1074 |
| 1075 |
| 1076 // ES6 21.2.5.15. |
| 1077 function RegExpGetUnicode() { |
| 1078 if (!IS_REGEXP(this)) { |
| 1079 // TODO(littledan): Remove this RegExp compat workaround |
| 1080 if (this === GlobalRegExp.prototype) { |
| 1081 %IncrementUseCounter(kRegExpPrototypeUnicodeGetter); |
| 1082 return UNDEFINED; |
| 1083 } |
| 1084 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.unicode"); |
| 1085 } |
| 1086 return TO_BOOLEAN(REGEXP_UNICODE(this)); |
| 1087 } |
| 1088 %SetForceInlineFlag(RegExpGetUnicode); |
| 1089 |
| 1090 |
| 1091 function RegExpSpecies() { |
| 1092 return this; |
| 1093 } |
| 1094 |
| 1095 |
927 // ------------------------------------------------------------------- | 1096 // ------------------------------------------------------------------- |
928 | 1097 |
| 1098 utils.InstallGetter(GlobalRegExp, speciesSymbol, RegExpSpecies); |
| 1099 |
929 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [ | 1100 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [ |
930 "exec", RegExpSubclassExecJS, | 1101 "exec", RegExpSubclassExecJS, |
931 "test", RegExpSubclassTest, | 1102 "test", RegExpSubclassTest, |
932 "toString", RegExpToString, | 1103 "toString", RegExpToString, |
933 "compile", RegExpCompileJS, | 1104 "compile", RegExpCompileJS, |
934 matchSymbol, RegExpSubclassMatch, | 1105 matchSymbol, RegExpSubclassMatch, |
935 replaceSymbol, RegExpSubclassReplace, | 1106 replaceSymbol, RegExpSubclassReplace, |
936 searchSymbol, RegExpSubclassSearch, | 1107 searchSymbol, RegExpSubclassSearch, |
937 splitSymbol, RegExpSubclassSplit, | 1108 splitSymbol, RegExpSubclassSplit, |
938 ]); | 1109 ]); |
939 | 1110 |
940 // Temporary until all RegExpLastMatchInfo accesses are ported to C++. | 1111 utils.InstallGetter(GlobalRegExp.prototype, 'flags', RegExpGetFlags); |
941 SET_PRIVATE(GlobalRegExp, lastMatchInfoSymbol, RegExpLastMatchInfo); | 1112 utils.InstallGetter(GlobalRegExp.prototype, 'global', RegExpGetGlobal); |
| 1113 utils.InstallGetter(GlobalRegExp.prototype, 'ignoreCase', RegExpGetIgnoreCase); |
| 1114 utils.InstallGetter(GlobalRegExp.prototype, 'multiline', RegExpGetMultiline); |
| 1115 utils.InstallGetter(GlobalRegExp.prototype, 'source', RegExpGetSource); |
| 1116 utils.InstallGetter(GlobalRegExp.prototype, 'sticky', RegExpGetSticky); |
| 1117 utils.InstallGetter(GlobalRegExp.prototype, 'unicode', RegExpGetUnicode); |
| 1118 |
| 1119 // The properties `input` and `$_` are aliases for each other. When this |
| 1120 // value is set the value it is set to is coerced to a string. |
| 1121 // Getter and setter for the input. |
| 1122 var RegExpGetInput = function() { |
| 1123 var regExpInput = LAST_INPUT(RegExpLastMatchInfo); |
| 1124 return IS_UNDEFINED(regExpInput) ? "" : regExpInput; |
| 1125 }; |
| 1126 var RegExpSetInput = function(string) { |
| 1127 LAST_INPUT(RegExpLastMatchInfo) = TO_STRING(string); |
| 1128 }; |
| 1129 |
| 1130 %OptimizeObjectForAddingMultipleProperties(GlobalRegExp, 22); |
| 1131 utils.InstallGetterSetter(GlobalRegExp, 'input', RegExpGetInput, RegExpSetInput, |
| 1132 DONT_DELETE); |
| 1133 utils.InstallGetterSetter(GlobalRegExp, '$_', RegExpGetInput, RegExpSetInput, |
| 1134 DONT_ENUM | DONT_DELETE); |
| 1135 |
| 1136 |
| 1137 var NoOpSetter = function(ignored) {}; |
| 1138 |
| 1139 |
| 1140 // Static properties set by a successful match. |
| 1141 utils.InstallGetterSetter(GlobalRegExp, 'lastMatch', RegExpGetLastMatch, |
| 1142 NoOpSetter, DONT_DELETE); |
| 1143 utils.InstallGetterSetter(GlobalRegExp, '$&', RegExpGetLastMatch, NoOpSetter, |
| 1144 DONT_ENUM | DONT_DELETE); |
| 1145 utils.InstallGetterSetter(GlobalRegExp, 'lastParen', RegExpGetLastParen, |
| 1146 NoOpSetter, DONT_DELETE); |
| 1147 utils.InstallGetterSetter(GlobalRegExp, '$+', RegExpGetLastParen, NoOpSetter, |
| 1148 DONT_ENUM | DONT_DELETE); |
| 1149 utils.InstallGetterSetter(GlobalRegExp, 'leftContext', RegExpGetLeftContext, |
| 1150 NoOpSetter, DONT_DELETE); |
| 1151 utils.InstallGetterSetter(GlobalRegExp, '$`', RegExpGetLeftContext, NoOpSetter, |
| 1152 DONT_ENUM | DONT_DELETE); |
| 1153 utils.InstallGetterSetter(GlobalRegExp, 'rightContext', RegExpGetRightContext, |
| 1154 NoOpSetter, DONT_DELETE); |
| 1155 utils.InstallGetterSetter(GlobalRegExp, "$'", RegExpGetRightContext, NoOpSetter, |
| 1156 DONT_ENUM | DONT_DELETE); |
| 1157 |
| 1158 for (var i = 1; i < 10; ++i) { |
| 1159 utils.InstallGetterSetter(GlobalRegExp, '$' + i, RegExpMakeCaptureGetter(i), |
| 1160 NoOpSetter, DONT_DELETE); |
| 1161 } |
| 1162 %ToFastProperties(GlobalRegExp); |
942 | 1163 |
943 // ------------------------------------------------------------------- | 1164 // ------------------------------------------------------------------- |
944 // Internal | 1165 // Internal |
945 | 1166 |
946 var InternalRegExpMatchInfo = { | 1167 var InternalRegExpMatchInfo = { |
947 REGEXP_NUMBER_OF_CAPTURES: 2, | 1168 REGEXP_NUMBER_OF_CAPTURES: 2, |
948 REGEXP_LAST_SUBJECT: "", | 1169 REGEXP_LAST_SUBJECT: "", |
949 REGEXP_LAST_INPUT: UNDEFINED, | 1170 REGEXP_LAST_INPUT: UNDEFINED, |
950 CAPTURE0: 0, | 1171 CAPTURE0: 0, |
951 CAPTURE1: 0 | 1172 CAPTURE1: 0 |
(...skipping 19 matching lines...) Expand all Loading... |
971 to.InternalRegExpMatch = InternalRegExpMatch; | 1192 to.InternalRegExpMatch = InternalRegExpMatch; |
972 to.InternalRegExpReplace = InternalRegExpReplace; | 1193 to.InternalRegExpReplace = InternalRegExpReplace; |
973 to.IsRegExp = IsRegExp; | 1194 to.IsRegExp = IsRegExp; |
974 to.RegExpExec = DoRegExpExec; | 1195 to.RegExpExec = DoRegExpExec; |
975 to.RegExpInitialize = RegExpInitialize; | 1196 to.RegExpInitialize = RegExpInitialize; |
976 to.RegExpLastMatchInfo = RegExpLastMatchInfo; | 1197 to.RegExpLastMatchInfo = RegExpLastMatchInfo; |
977 to.RegExpTest = RegExpTest; | 1198 to.RegExpTest = RegExpTest; |
978 }); | 1199 }); |
979 | 1200 |
980 }) | 1201 }) |
OLD | NEW |