| 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 |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 if (updateLastIndex) { | 197 if (updateLastIndex) { |
| 198 if (i > string.length) { | 198 if (i > string.length) { |
| 199 this.lastIndex = 0; | 199 this.lastIndex = 0; |
| 200 return null; | 200 return null; |
| 201 } | 201 } |
| 202 } else { | 202 } else { |
| 203 i = 0; | 203 i = 0; |
| 204 } | 204 } |
| 205 | 205 |
| 206 // matchIndices is either null or the RegExpLastMatchInfo array. | 206 // matchIndices is either null or the RegExpLastMatchInfo array. |
| 207 // TODO(littledan): Whether a RegExp is sticky is compiled into the RegExp | |
| 208 // itself, but ES2015 allows monkey-patching this property to differ from | |
| 209 // the internal flags. If it differs, recompile a different RegExp? | |
| 210 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo); | 207 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo); |
| 211 | 208 |
| 212 if (IS_NULL(matchIndices)) { | 209 if (IS_NULL(matchIndices)) { |
| 213 this.lastIndex = 0; | 210 this.lastIndex = 0; |
| 214 return null; | 211 return null; |
| 215 } | 212 } |
| 216 | 213 |
| 217 // Successful match. | 214 // Successful match. |
| 218 if (updateLastIndex) { | 215 if (updateLastIndex) { |
| 219 this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; | 216 this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 380 | 377 |
| 381 function AtSurrogatePair(subject, index) { | 378 function AtSurrogatePair(subject, index) { |
| 382 if (index + 1 >= subject.length) return false; | 379 if (index + 1 >= subject.length) return false; |
| 383 var first = %_StringCharCodeAt(subject, index); | 380 var first = %_StringCharCodeAt(subject, index); |
| 384 if (first < 0xD800 || first > 0xDBFF) return false; | 381 if (first < 0xD800 || first > 0xDBFF) return false; |
| 385 var second = %_StringCharCodeAt(subject, index + 1); | 382 var second = %_StringCharCodeAt(subject, index + 1); |
| 386 return second >= 0xDC00 || second <= 0xDFFF; | 383 return second >= 0xDC00 || second <= 0xDFFF; |
| 387 } | 384 } |
| 388 | 385 |
| 389 | 386 |
| 390 // Legacy implementation of RegExp.prototype[Symbol.split] which | 387 // Fast path implementation of RegExp.prototype[Symbol.split] which |
| 391 // doesn't properly call the underlying exec, @@species methods | 388 // doesn't properly call the underlying exec, @@species methods |
| 392 function RegExpSplit(string, limit) { | 389 function RegExpSplit(string, limit) { |
| 393 // TODO(yangguo): allow non-regexp receivers. | |
| 394 if (!IS_REGEXP(this)) { | 390 if (!IS_REGEXP(this)) { |
| 395 throw %make_type_error(kIncompatibleMethodReceiver, | 391 throw %make_type_error(kIncompatibleMethodReceiver, |
| 396 "RegExp.prototype.@@split", this); | 392 "RegExp.prototype.@@split", this); |
| 397 } | 393 } |
| 398 var separator = this; | 394 var separator = this; |
| 399 var subject = TO_STRING(string); | 395 var subject = TO_STRING(string); |
| 400 | 396 |
| 401 limit = (IS_UNDEFINED(limit)) ? kMaxUint32 : TO_UINT32(limit); | 397 limit = (IS_UNDEFINED(limit)) ? kMaxUint32 : TO_UINT32(limit); |
| 402 var length = subject.length; | 398 var length = subject.length; |
| 403 | 399 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 466 // RegExp.prototype [ @@split ] ( string, limit ) | 462 // RegExp.prototype [ @@split ] ( string, limit ) |
| 467 function RegExpSubclassSplit(string, limit) { | 463 function RegExpSubclassSplit(string, limit) { |
| 468 if (!IS_RECEIVER(this)) { | 464 if (!IS_RECEIVER(this)) { |
| 469 throw %make_type_error(kIncompatibleMethodReceiver, | 465 throw %make_type_error(kIncompatibleMethodReceiver, |
| 470 "RegExp.prototype.@@split", this); | 466 "RegExp.prototype.@@split", this); |
| 471 } | 467 } |
| 472 string = TO_STRING(string); | 468 string = TO_STRING(string); |
| 473 var constructor = SpeciesConstructor(this, GlobalRegExp); | 469 var constructor = SpeciesConstructor(this, GlobalRegExp); |
| 474 var flags = TO_STRING(this.flags); | 470 var flags = TO_STRING(this.flags); |
| 475 | 471 |
| 476 // TODO(adamk): this fast path is wrong with respect to this.global | 472 // TODO(adamk): this fast path is wrong as we doesn't ensure that 'exec' |
| 477 // and this.sticky, but hopefully the spec will remove those gets | 473 // is actually a data property on RegExp.prototype. |
| 478 // and thus make the assumption of 'exec' having no side-effects | |
| 479 // more correct. Also, we doesn't ensure that 'exec' is actually | |
| 480 // a data property on RegExp.prototype. | |
| 481 var exec; | 474 var exec; |
| 482 if (IS_REGEXP(this) && constructor === GlobalRegExp) { | 475 if (IS_REGEXP(this) && constructor === GlobalRegExp) { |
| 483 exec = this.exec; | 476 exec = this.exec; |
| 484 if (exec === RegExpSubclassExecJS) { | 477 if (exec === RegExpSubclassExecJS) { |
| 485 return %_Call(RegExpSplit, this, string, limit); | 478 return %_Call(RegExpSplit, this, string, limit); |
| 486 } | 479 } |
| 487 } | 480 } |
| 488 | 481 |
| 489 var unicode = %StringIndexOf(flags, 'u', 0) >= 0; | 482 var unicode = %StringIndexOf(flags, 'u', 0) >= 0; |
| 490 var sticky = %StringIndexOf(flags, 'y', 0) >= 0; | 483 var sticky = %StringIndexOf(flags, 'y', 0) >= 0; |
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 862 string = TO_STRING(string); | 855 string = TO_STRING(string); |
| 863 var length = string.length; | 856 var length = string.length; |
| 864 var functionalReplace = IS_CALLABLE(replace); | 857 var functionalReplace = IS_CALLABLE(replace); |
| 865 if (!functionalReplace) replace = TO_STRING(replace); | 858 if (!functionalReplace) replace = TO_STRING(replace); |
| 866 var global = TO_BOOLEAN(this.global); | 859 var global = TO_BOOLEAN(this.global); |
| 867 if (global) { | 860 if (global) { |
| 868 var unicode = TO_BOOLEAN(this.unicode); | 861 var unicode = TO_BOOLEAN(this.unicode); |
| 869 this.lastIndex = 0; | 862 this.lastIndex = 0; |
| 870 } | 863 } |
| 871 | 864 |
| 872 // TODO(adamk): this fast path is wrong with respect to this.global | 865 // TODO(adamk): this fast path is wrong as we doesn't ensure that 'exec' |
| 873 // and this.sticky, but hopefully the spec will remove those gets | 866 // is actually a data property on RegExp.prototype. |
| 874 // and thus make the assumption of 'exec' having no side-effects | |
| 875 // more correct. Also, we doesn't ensure that 'exec' is actually | |
| 876 // a data property on RegExp.prototype, nor does the fast path | |
| 877 // correctly handle lastIndex setting. | |
| 878 var exec; | 867 var exec; |
| 879 if (IS_REGEXP(this)) { | 868 if (IS_REGEXP(this)) { |
| 880 exec = this.exec; | 869 exec = this.exec; |
| 881 if (exec === RegExpSubclassExecJS) { | 870 if (exec === RegExpSubclassExecJS) { |
| 882 return %_Call(RegExpReplace, this, string, replace); | 871 return %_Call(RegExpReplace, this, string, replace); |
| 883 } | 872 } |
| 884 } | 873 } |
| 885 | 874 |
| 886 var results = new InternalArray(); | 875 var results = new InternalArray(); |
| 887 var result, replacement; | 876 var result, replacement; |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1028 if (this.multiline) result += 'm'; | 1017 if (this.multiline) result += 'm'; |
| 1029 if (this.unicode) result += 'u'; | 1018 if (this.unicode) result += 'u'; |
| 1030 if (this.sticky) result += 'y'; | 1019 if (this.sticky) result += 'y'; |
| 1031 return result; | 1020 return result; |
| 1032 } | 1021 } |
| 1033 | 1022 |
| 1034 | 1023 |
| 1035 // ES6 21.2.5.4. | 1024 // ES6 21.2.5.4. |
| 1036 function RegExpGetGlobal() { | 1025 function RegExpGetGlobal() { |
| 1037 if (!IS_REGEXP(this)) { | 1026 if (!IS_REGEXP(this)) { |
| 1038 // TODO(littledan): Remove this RegExp compat workaround | |
| 1039 if (this === GlobalRegExpPrototype) { | 1027 if (this === GlobalRegExpPrototype) { |
| 1040 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); | 1028 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); |
| 1041 return UNDEFINED; | 1029 return UNDEFINED; |
| 1042 } | 1030 } |
| 1043 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.global"); | 1031 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.global"); |
| 1044 } | 1032 } |
| 1045 return TO_BOOLEAN(REGEXP_GLOBAL(this)); | 1033 return TO_BOOLEAN(REGEXP_GLOBAL(this)); |
| 1046 } | 1034 } |
| 1047 %SetForceInlineFlag(RegExpGetGlobal); | 1035 %SetForceInlineFlag(RegExpGetGlobal); |
| 1048 | 1036 |
| 1049 | 1037 |
| 1050 // ES6 21.2.5.5. | 1038 // ES6 21.2.5.5. |
| 1051 function RegExpGetIgnoreCase() { | 1039 function RegExpGetIgnoreCase() { |
| 1052 if (!IS_REGEXP(this)) { | 1040 if (!IS_REGEXP(this)) { |
| 1053 // TODO(littledan): Remove this RegExp compat workaround | |
| 1054 if (this === GlobalRegExpPrototype) { | 1041 if (this === GlobalRegExpPrototype) { |
| 1055 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); | 1042 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); |
| 1056 return UNDEFINED; | 1043 return UNDEFINED; |
| 1057 } | 1044 } |
| 1058 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.ignoreCase"); | 1045 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.ignoreCase"); |
| 1059 } | 1046 } |
| 1060 return TO_BOOLEAN(REGEXP_IGNORE_CASE(this)); | 1047 return TO_BOOLEAN(REGEXP_IGNORE_CASE(this)); |
| 1061 } | 1048 } |
| 1062 | 1049 |
| 1063 | 1050 |
| 1064 // ES6 21.2.5.7. | 1051 // ES6 21.2.5.7. |
| 1065 function RegExpGetMultiline() { | 1052 function RegExpGetMultiline() { |
| 1066 if (!IS_REGEXP(this)) { | 1053 if (!IS_REGEXP(this)) { |
| 1067 // TODO(littledan): Remove this RegExp compat workaround | |
| 1068 if (this === GlobalRegExpPrototype) { | 1054 if (this === GlobalRegExpPrototype) { |
| 1069 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); | 1055 %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); |
| 1070 return UNDEFINED; | 1056 return UNDEFINED; |
| 1071 } | 1057 } |
| 1072 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.multiline"); | 1058 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.multiline"); |
| 1073 } | 1059 } |
| 1074 return TO_BOOLEAN(REGEXP_MULTILINE(this)); | 1060 return TO_BOOLEAN(REGEXP_MULTILINE(this)); |
| 1075 } | 1061 } |
| 1076 | 1062 |
| 1077 | 1063 |
| 1078 // ES6 21.2.5.10. | 1064 // ES6 21.2.5.10. |
| 1079 function RegExpGetSource() { | 1065 function RegExpGetSource() { |
| 1080 if (!IS_REGEXP(this)) { | 1066 if (!IS_REGEXP(this)) { |
| 1081 // TODO(littledan): Remove this RegExp compat workaround | |
| 1082 if (this === GlobalRegExpPrototype) { | 1067 if (this === GlobalRegExpPrototype) { |
| 1083 %IncrementUseCounter(kRegExpPrototypeSourceGetter); | 1068 %IncrementUseCounter(kRegExpPrototypeSourceGetter); |
| 1084 return "(?:)"; | 1069 return "(?:)"; |
| 1085 } | 1070 } |
| 1086 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.source"); | 1071 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.source"); |
| 1087 } | 1072 } |
| 1088 return REGEXP_SOURCE(this); | 1073 return REGEXP_SOURCE(this); |
| 1089 } | 1074 } |
| 1090 | 1075 |
| 1091 | 1076 |
| 1092 // ES6 21.2.5.12. | 1077 // ES6 21.2.5.12. |
| 1093 function RegExpGetSticky() { | 1078 function RegExpGetSticky() { |
| 1094 if (!IS_REGEXP(this)) { | 1079 if (!IS_REGEXP(this)) { |
| 1095 // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it | |
| 1096 // TODO(littledan): Remove this workaround or standardize it | |
| 1097 if (this === GlobalRegExpPrototype) { | 1080 if (this === GlobalRegExpPrototype) { |
| 1098 %IncrementUseCounter(kRegExpPrototypeStickyGetter); | 1081 %IncrementUseCounter(kRegExpPrototypeStickyGetter); |
| 1099 return UNDEFINED; | 1082 return UNDEFINED; |
| 1100 } | 1083 } |
| 1101 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.sticky"); | 1084 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.sticky"); |
| 1102 } | 1085 } |
| 1103 return TO_BOOLEAN(REGEXP_STICKY(this)); | 1086 return TO_BOOLEAN(REGEXP_STICKY(this)); |
| 1104 } | 1087 } |
| 1105 %SetForceInlineFlag(RegExpGetSticky); | 1088 %SetForceInlineFlag(RegExpGetSticky); |
| 1106 | 1089 |
| 1107 | 1090 |
| 1108 // ES6 21.2.5.15. | 1091 // ES6 21.2.5.15. |
| 1109 function RegExpGetUnicode() { | 1092 function RegExpGetUnicode() { |
| 1110 if (!IS_REGEXP(this)) { | 1093 if (!IS_REGEXP(this)) { |
| 1111 // TODO(littledan): Remove this RegExp compat workaround | |
| 1112 if (this === GlobalRegExpPrototype) { | 1094 if (this === GlobalRegExpPrototype) { |
| 1113 %IncrementUseCounter(kRegExpPrototypeUnicodeGetter); | 1095 %IncrementUseCounter(kRegExpPrototypeUnicodeGetter); |
| 1114 return UNDEFINED; | 1096 return UNDEFINED; |
| 1115 } | 1097 } |
| 1116 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.unicode"); | 1098 throw %make_type_error(kRegExpNonRegExp, "RegExp.prototype.unicode"); |
| 1117 } | 1099 } |
| 1118 return TO_BOOLEAN(REGEXP_UNICODE(this)); | 1100 return TO_BOOLEAN(REGEXP_UNICODE(this)); |
| 1119 } | 1101 } |
| 1120 %SetForceInlineFlag(RegExpGetUnicode); | 1102 %SetForceInlineFlag(RegExpGetUnicode); |
| 1121 | 1103 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1164 }; | 1146 }; |
| 1165 var RegExpSetInput = function(string) { | 1147 var RegExpSetInput = function(string) { |
| 1166 LAST_INPUT(RegExpLastMatchInfo) = TO_STRING(string); | 1148 LAST_INPUT(RegExpLastMatchInfo) = TO_STRING(string); |
| 1167 }; | 1149 }; |
| 1168 | 1150 |
| 1169 // TODO(jgruber): All of these getters and setters were intended to be installed | 1151 // TODO(jgruber): All of these getters and setters were intended to be installed |
| 1170 // with various attributes (e.g. DONT_ENUM | DONT_DELETE), but | 1152 // with various attributes (e.g. DONT_ENUM | DONT_DELETE), but |
| 1171 // InstallGetterSetter had a bug which ignored the passed attributes and | 1153 // InstallGetterSetter had a bug which ignored the passed attributes and |
| 1172 // simply installed as DONT_ENUM instead. We might want to change back | 1154 // simply installed as DONT_ENUM instead. We might want to change back |
| 1173 // to the intended attributes at some point. | 1155 // to the intended attributes at some point. |
| 1156 // On the other hand, installing attributes as DONT_ENUM matches the draft |
| 1157 // specification at |
| 1158 // https://github.com/claudepache/es-regexp-legacy-static-properties |
| 1174 | 1159 |
| 1175 %OptimizeObjectForAddingMultipleProperties(GlobalRegExp, 22); | 1160 %OptimizeObjectForAddingMultipleProperties(GlobalRegExp, 22); |
| 1176 utils.InstallGetterSetter(GlobalRegExp, 'input', RegExpGetInput, RegExpSetInput, | 1161 utils.InstallGetterSetter(GlobalRegExp, 'input', RegExpGetInput, RegExpSetInput, |
| 1177 DONT_ENUM); | 1162 DONT_ENUM); |
| 1178 utils.InstallGetterSetter(GlobalRegExp, '$_', RegExpGetInput, RegExpSetInput, | 1163 utils.InstallGetterSetter(GlobalRegExp, '$_', RegExpGetInput, RegExpSetInput, |
| 1179 DONT_ENUM); | 1164 DONT_ENUM); |
| 1180 | 1165 |
| 1181 | 1166 |
| 1182 var NoOpSetter = function(ignored) {}; | 1167 var NoOpSetter = function(ignored) {}; |
| 1183 | 1168 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1237 to.InternalRegExpMatch = InternalRegExpMatch; | 1222 to.InternalRegExpMatch = InternalRegExpMatch; |
| 1238 to.InternalRegExpReplace = InternalRegExpReplace; | 1223 to.InternalRegExpReplace = InternalRegExpReplace; |
| 1239 to.IsRegExp = IsRegExp; | 1224 to.IsRegExp = IsRegExp; |
| 1240 to.RegExpExec = DoRegExpExec; | 1225 to.RegExpExec = DoRegExpExec; |
| 1241 to.RegExpInitialize = RegExpInitialize; | 1226 to.RegExpInitialize = RegExpInitialize; |
| 1242 to.RegExpLastMatchInfo = RegExpLastMatchInfo; | 1227 to.RegExpLastMatchInfo = RegExpLastMatchInfo; |
| 1243 to.RegExpTest = RegExpTest; | 1228 to.RegExpTest = RegExpTest; |
| 1244 }); | 1229 }); |
| 1245 | 1230 |
| 1246 }) | 1231 }) |
| OLD | NEW |