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 |