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"); |
20 var matchSymbol = utils.ImportNow("match_symbol"); | 21 var matchSymbol = utils.ImportNow("match_symbol"); |
21 var replaceSymbol = utils.ImportNow("replace_symbol"); | 22 var replaceSymbol = utils.ImportNow("replace_symbol"); |
22 var searchSymbol = utils.ImportNow("search_symbol"); | 23 var searchSymbol = utils.ImportNow("search_symbol"); |
23 var speciesSymbol = utils.ImportNow("species_symbol"); | 24 var speciesSymbol = utils.ImportNow("species_symbol"); |
24 var splitSymbol = utils.ImportNow("split_symbol"); | 25 var splitSymbol = utils.ImportNow("split_symbol"); |
25 var SpeciesConstructor; | 26 var SpeciesConstructor; |
26 | 27 |
27 utils.Import(function(from) { | 28 utils.Import(function(from) { |
28 ExpandReplacement = from.ExpandReplacement; | 29 ExpandReplacement = from.ExpandReplacement; |
29 MaxSimple = from.MaxSimple; | 30 MaxSimple = from.MaxSimple; |
(...skipping 886 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
916 var previousLastIndex = this.lastIndex; | 917 var previousLastIndex = this.lastIndex; |
917 this.lastIndex = 0; | 918 this.lastIndex = 0; |
918 var result = RegExpSubclassExec(this, string); | 919 var result = RegExpSubclassExec(this, string); |
919 this.lastIndex = previousLastIndex; | 920 this.lastIndex = previousLastIndex; |
920 if (IS_NULL(result)) return -1; | 921 if (IS_NULL(result)) return -1; |
921 return result.index; | 922 return result.index; |
922 } | 923 } |
923 %FunctionRemovePrototype(RegExpSubclassSearch); | 924 %FunctionRemovePrototype(RegExpSubclassSearch); |
924 | 925 |
925 | 926 |
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 | |
1096 // ------------------------------------------------------------------- | 927 // ------------------------------------------------------------------- |
1097 | 928 |
1098 utils.InstallGetter(GlobalRegExp, speciesSymbol, RegExpSpecies); | |
1099 | |
1100 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [ | 929 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [ |
1101 "exec", RegExpSubclassExecJS, | 930 "exec", RegExpSubclassExecJS, |
1102 "test", RegExpSubclassTest, | 931 "test", RegExpSubclassTest, |
1103 "toString", RegExpToString, | 932 "toString", RegExpToString, |
1104 "compile", RegExpCompileJS, | 933 "compile", RegExpCompileJS, |
1105 matchSymbol, RegExpSubclassMatch, | 934 matchSymbol, RegExpSubclassMatch, |
1106 replaceSymbol, RegExpSubclassReplace, | 935 replaceSymbol, RegExpSubclassReplace, |
1107 searchSymbol, RegExpSubclassSearch, | 936 searchSymbol, RegExpSubclassSearch, |
1108 splitSymbol, RegExpSubclassSplit, | 937 splitSymbol, RegExpSubclassSplit, |
1109 ]); | 938 ]); |
1110 | 939 |
1111 utils.InstallGetter(GlobalRegExp.prototype, 'flags', RegExpGetFlags); | 940 // Temporary until all RegExpLastMatchInfo accesses are ported to C++. |
1112 utils.InstallGetter(GlobalRegExp.prototype, 'global', RegExpGetGlobal); | 941 SET_PRIVATE(GlobalRegExp, lastMatchInfoSymbol, RegExpLastMatchInfo); |
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); | |
1163 | 942 |
1164 // ------------------------------------------------------------------- | 943 // ------------------------------------------------------------------- |
1165 // Internal | 944 // Internal |
1166 | 945 |
1167 var InternalRegExpMatchInfo = { | 946 var InternalRegExpMatchInfo = { |
1168 REGEXP_NUMBER_OF_CAPTURES: 2, | 947 REGEXP_NUMBER_OF_CAPTURES: 2, |
1169 REGEXP_LAST_SUBJECT: "", | 948 REGEXP_LAST_SUBJECT: "", |
1170 REGEXP_LAST_INPUT: UNDEFINED, | 949 REGEXP_LAST_INPUT: UNDEFINED, |
1171 CAPTURE0: 0, | 950 CAPTURE0: 0, |
1172 CAPTURE1: 0 | 951 CAPTURE1: 0 |
(...skipping 19 matching lines...) Expand all Loading... |
1192 to.InternalRegExpMatch = InternalRegExpMatch; | 971 to.InternalRegExpMatch = InternalRegExpMatch; |
1193 to.InternalRegExpReplace = InternalRegExpReplace; | 972 to.InternalRegExpReplace = InternalRegExpReplace; |
1194 to.IsRegExp = IsRegExp; | 973 to.IsRegExp = IsRegExp; |
1195 to.RegExpExec = DoRegExpExec; | 974 to.RegExpExec = DoRegExpExec; |
1196 to.RegExpInitialize = RegExpInitialize; | 975 to.RegExpInitialize = RegExpInitialize; |
1197 to.RegExpLastMatchInfo = RegExpLastMatchInfo; | 976 to.RegExpLastMatchInfo = RegExpLastMatchInfo; |
1198 to.RegExpTest = RegExpTest; | 977 to.RegExpTest = RegExpTest; |
1199 }); | 978 }); |
1200 | 979 |
1201 }) | 980 }) |
OLD | NEW |