| 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 249 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   260  |   260  | 
|   261   // Successful match. |   261   // Successful match. | 
|   262   if (updateLastIndex) { |   262   if (updateLastIndex) { | 
|   263     this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; |   263     this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; | 
|   264   } |   264   } | 
|   265   RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string); |   265   RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string); | 
|   266 } |   266 } | 
|   267  |   267  | 
|   268  |   268  | 
|   269 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |   269 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | 
|   270 function RegExpSubclassExec(regexp, string) { |   270 // Also takes an optional exec method in case our caller | 
|   271   var exec = regexp.exec; |   271 // has already fetched exec. | 
 |   272 function RegExpSubclassExec(regexp, string, exec) { | 
 |   273   if (IS_UNDEFINED(exec)) { | 
 |   274     exec = regexp.exec; | 
 |   275   } | 
|   272   if (IS_CALLABLE(exec)) { |   276   if (IS_CALLABLE(exec)) { | 
|   273     var result = %_Call(exec, regexp, string); |   277     var result = %_Call(exec, regexp, string); | 
|   274     if (!IS_RECEIVER(result) && !IS_NULL(result)) { |   278     if (!IS_RECEIVER(result) && !IS_NULL(result)) { | 
|   275       throw MakeTypeError(kInvalidRegExpExecResult); |   279       throw MakeTypeError(kInvalidRegExpExecResult); | 
|   276     } |   280     } | 
|   277     return result; |   281     return result; | 
|   278   } |   282   } | 
|   279   return %_Call(RegExpExecJS, regexp, string); |   283   return %_Call(RegExpExecJS, regexp, string); | 
|   280 } |   284 } | 
 |   285 %SetForceInlineFlag(RegExpSubclassExec); | 
|   281  |   286  | 
|   282  |   287  | 
|   283 // One-element cache for the simplified test regexp. |   288 // One-element cache for the simplified test regexp. | 
|   284 var regexp_key; |   289 var regexp_key; | 
|   285 var regexp_val; |   290 var regexp_val; | 
|   286  |   291  | 
|   287 // Legacy implementation of RegExp.prototype.test |   292 // Legacy implementation of RegExp.prototype.test | 
|   288 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be |   293 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be | 
|   289 // that test is defined in terms of String.prototype.exec. However, it probably |   294 // that test is defined in terms of String.prototype.exec. However, it probably | 
|   290 // means the original value of String.prototype.exec, which is what everybody |   295 // means the original value of String.prototype.exec, which is what everybody | 
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   476 // ES#sec-regexp.prototype-@@split |   481 // ES#sec-regexp.prototype-@@split | 
|   477 // RegExp.prototype [ @@split ] ( string, limit ) |   482 // RegExp.prototype [ @@split ] ( string, limit ) | 
|   478 function RegExpSubclassSplit(string, limit) { |   483 function RegExpSubclassSplit(string, limit) { | 
|   479   if (!IS_RECEIVER(this)) { |   484   if (!IS_RECEIVER(this)) { | 
|   480     throw MakeTypeError(kIncompatibleMethodReceiver, |   485     throw MakeTypeError(kIncompatibleMethodReceiver, | 
|   481                         "RegExp.prototype.@@split", this); |   486                         "RegExp.prototype.@@split", this); | 
|   482   } |   487   } | 
|   483   string = TO_STRING(string); |   488   string = TO_STRING(string); | 
|   484   var constructor = SpeciesConstructor(this, GlobalRegExp); |   489   var constructor = SpeciesConstructor(this, GlobalRegExp); | 
|   485   var flags = TO_STRING(this.flags); |   490   var flags = TO_STRING(this.flags); | 
 |   491  | 
 |   492   // TODO(adamk): this fast path is wrong with respect to this.global | 
 |   493   // and this.sticky, but hopefully the spec will remove those gets | 
 |   494   // and thus make the assumption of 'exec' having no side-effects | 
 |   495   // more correct. Also, we doesn't ensure that 'exec' is actually | 
 |   496   // a data property on RegExp.prototype. | 
 |   497   var exec; | 
 |   498   if (IS_REGEXP(this) && constructor === GlobalRegExp) { | 
 |   499     exec = this.exec; | 
 |   500     if (exec === RegExpSubclassExecJS) { | 
 |   501       return %_Call(RegExpSplit, this, string, limit); | 
 |   502     } | 
 |   503   } | 
 |   504  | 
|   486   var unicode = %StringIndexOf(flags, 'u', 0) >= 0; |   505   var unicode = %StringIndexOf(flags, 'u', 0) >= 0; | 
|   487   var sticky = %StringIndexOf(flags, 'y', 0) >= 0; |   506   var sticky = %StringIndexOf(flags, 'y', 0) >= 0; | 
|   488   var newFlags = sticky ? flags : flags + "y"; |   507   var newFlags = sticky ? flags : flags + "y"; | 
|   489   var splitter = new constructor(this, newFlags); |   508   var splitter = new constructor(this, newFlags); | 
|   490   var array = new GlobalArray(); |   509   var array = new GlobalArray(); | 
|   491   var arrayIndex = 0; |   510   var arrayIndex = 0; | 
|   492   var lim = (IS_UNDEFINED(limit)) ? kMaxUint32 : TO_UINT32(limit); |   511   var lim = (IS_UNDEFINED(limit)) ? kMaxUint32 : TO_UINT32(limit); | 
|   493   var size = string.length; |   512   var size = string.length; | 
|   494   var prevStringIndex = 0; |   513   var prevStringIndex = 0; | 
|   495   if (lim === 0) return array; |   514   if (lim === 0) return array; | 
|   496   var result; |   515   var result; | 
|   497   if (size === 0) { |   516   if (size === 0) { | 
|   498     result = RegExpSubclassExec(splitter, string); |   517     result = RegExpSubclassExec(splitter, string); | 
|   499     if (IS_NULL(result)) AddIndexedProperty(array, 0, string); |   518     if (IS_NULL(result)) AddIndexedProperty(array, 0, string); | 
|   500     return array; |   519     return array; | 
|   501   } |   520   } | 
|   502   var stringIndex = prevStringIndex; |   521   var stringIndex = prevStringIndex; | 
|   503   while (stringIndex < size) { |   522   while (stringIndex < size) { | 
|   504     splitter.lastIndex = stringIndex; |   523     splitter.lastIndex = stringIndex; | 
|   505     result = RegExpSubclassExec(splitter, string); |   524     result = RegExpSubclassExec(splitter, string, exec); | 
 |   525     // Ensure exec will be read again on the next loop through. | 
 |   526     exec = UNDEFINED; | 
|   506     if (IS_NULL(result)) { |   527     if (IS_NULL(result)) { | 
|   507       stringIndex += AdvanceStringIndex(string, stringIndex, unicode); |   528       stringIndex += AdvanceStringIndex(string, stringIndex, unicode); | 
|   508     } else { |   529     } else { | 
|   509       var end = MinSimple(TO_LENGTH(splitter.lastIndex), size); |   530       var end = MinSimple(TO_LENGTH(splitter.lastIndex), size); | 
|   510       if (end === stringIndex) { |   531       if (end === stringIndex) { | 
|   511         stringIndex += AdvanceStringIndex(string, stringIndex, unicode); |   532         stringIndex += AdvanceStringIndex(string, stringIndex, unicode); | 
|   512       } else { |   533       } else { | 
|   513         AddIndexedProperty( |   534         AddIndexedProperty( | 
|   514             array, arrayIndex, |   535             array, arrayIndex, | 
|   515             %_SubString(string, prevStringIndex, stringIndex)); |   536             %_SubString(string, prevStringIndex, stringIndex)); | 
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   554 function RegExpSubclassMatch(string) { |   575 function RegExpSubclassMatch(string) { | 
|   555   if (!IS_RECEIVER(this)) { |   576   if (!IS_RECEIVER(this)) { | 
|   556     throw MakeTypeError(kIncompatibleMethodReceiver, |   577     throw MakeTypeError(kIncompatibleMethodReceiver, | 
|   557                         "RegExp.prototype.@@match", this); |   578                         "RegExp.prototype.@@match", this); | 
|   558   } |   579   } | 
|   559   string = TO_STRING(string); |   580   string = TO_STRING(string); | 
|   560   var global = this.global; |   581   var global = this.global; | 
|   561   if (!global) return RegExpSubclassExec(this, string); |   582   if (!global) return RegExpSubclassExec(this, string); | 
|   562   var unicode = this.unicode; |   583   var unicode = this.unicode; | 
|   563   this.lastIndex = 0; |   584   this.lastIndex = 0; | 
|   564   var array = []; |   585   var array = new InternalArray(); | 
|   565   var n = 0; |   586   var n = 0; | 
|   566   var result; |   587   var result; | 
|   567   while (true) { |   588   while (true) { | 
|   568     result = RegExpSubclassExec(this, string); |   589     result = RegExpSubclassExec(this, string); | 
|   569     if (IS_NULL(result)) { |   590     if (IS_NULL(result)) { | 
|   570       if (n === 0) return null; |   591       if (n === 0) return null; | 
|   571       return array; |   592       break; | 
|   572     } |   593     } | 
|   573     var matchStr = TO_STRING(result[0]); |   594     var matchStr = TO_STRING(result[0]); | 
|   574     %AddElement(array, n, matchStr); |   595     array[n] = matchStr; | 
|   575     if (matchStr === "") SetAdvancedStringIndex(this, string, unicode); |   596     if (matchStr === "") SetAdvancedStringIndex(this, string, unicode); | 
|   576     n++; |   597     n++; | 
|   577   } |   598   } | 
 |   599   var resultArray = []; | 
 |   600   %MoveArrayContents(array, resultArray); | 
 |   601   return resultArray; | 
|   578 } |   602 } | 
|   579 %FunctionRemovePrototype(RegExpSubclassMatch); |   603 %FunctionRemovePrototype(RegExpSubclassMatch); | 
|   580  |   604  | 
|   581  |   605  | 
|   582 // Legacy implementation of RegExp.prototype[Symbol.replace] which |   606 // Legacy implementation of RegExp.prototype[Symbol.replace] which | 
|   583 // doesn't properly call the underlying exec method. |   607 // doesn't properly call the underlying exec method. | 
|   584  |   608  | 
|   585 // TODO(lrn): This array will survive indefinitely if replace is never |   609 // TODO(lrn): This array will survive indefinitely if replace is never | 
|   586 // called again. However, it will be empty, since the contents are cleared |   610 // called again. However, it will be empty, since the contents are cleared | 
|   587 // in the finally block. |   611 // in the finally block. | 
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   864 // RegExp.prototype [ @@replace ] ( string, replaceValue ) |   888 // RegExp.prototype [ @@replace ] ( string, replaceValue ) | 
|   865 function RegExpSubclassReplace(string, replace) { |   889 function RegExpSubclassReplace(string, replace) { | 
|   866   if (!IS_RECEIVER(this)) { |   890   if (!IS_RECEIVER(this)) { | 
|   867     throw MakeTypeError(kIncompatibleMethodReceiver, |   891     throw MakeTypeError(kIncompatibleMethodReceiver, | 
|   868                         "RegExp.prototype.@@replace", this); |   892                         "RegExp.prototype.@@replace", this); | 
|   869   } |   893   } | 
|   870   string = TO_STRING(string); |   894   string = TO_STRING(string); | 
|   871   var length = string.length; |   895   var length = string.length; | 
|   872   var functionalReplace = IS_CALLABLE(replace); |   896   var functionalReplace = IS_CALLABLE(replace); | 
|   873   if (!functionalReplace) replace = TO_STRING(replace); |   897   if (!functionalReplace) replace = TO_STRING(replace); | 
|   874   var global = this.global; |   898   var global = TO_BOOLEAN(this.global); | 
|   875   if (global) { |   899   if (global) { | 
|   876     var unicode = this.unicode; |   900     var unicode = TO_BOOLEAN(this.unicode); | 
|   877     this.lastIndex = 0; |   901     this.lastIndex = 0; | 
|   878   } |   902   } | 
 |   903  | 
 |   904   // TODO(adamk): this fast path is wrong with respect to this.global | 
 |   905   // and this.sticky, but hopefully the spec will remove those gets | 
 |   906   // and thus make the assumption of 'exec' having no side-effects | 
 |   907   // more correct. Also, we doesn't ensure that 'exec' is actually | 
 |   908   // a data property on RegExp.prototype, nor does the fast path | 
 |   909   // correctly handle lastIndex setting. | 
 |   910   var exec; | 
 |   911   if (IS_REGEXP(this)) { | 
 |   912     exec = this.exec; | 
 |   913     if (exec === RegExpSubclassExecJS) { | 
 |   914       return %_Call(RegExpReplace, this, string, replace); | 
 |   915     } | 
 |   916   } | 
 |   917  | 
|   879   var results = new InternalArray(); |   918   var results = new InternalArray(); | 
|   880   var result, replacement; |   919   var result, replacement; | 
|   881   while (true) { |   920   while (true) { | 
|   882     result = RegExpSubclassExec(this, string); |   921     result = RegExpSubclassExec(this, string, exec); | 
 |   922     // Ensure exec will be read again on the next loop through. | 
 |   923     exec = UNDEFINED; | 
|   883     if (IS_NULL(result)) { |   924     if (IS_NULL(result)) { | 
|   884       break; |   925       break; | 
|   885     } else { |   926     } else { | 
|   886       results.push(result); |   927       results.push(result); | 
|   887       if (!global) break; |   928       if (!global) break; | 
|   888       var matchStr = TO_STRING(result[0]); |   929       var matchStr = TO_STRING(result[0]); | 
|   889       if (matchStr === "") SetAdvancedStringIndex(this, string, unicode); |   930       if (matchStr === "") SetAdvancedStringIndex(this, string, unicode); | 
|   890     } |   931     } | 
|   891   } |   932   } | 
|   892   var accumulatedResult = ""; |   933   var accumulatedResult = ""; | 
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1039 // ES6 21.2.5.4. |  1080 // ES6 21.2.5.4. | 
|  1040 function RegExpGetGlobal() { |  1081 function RegExpGetGlobal() { | 
|  1041   if (!IS_REGEXP(this)) { |  1082   if (!IS_REGEXP(this)) { | 
|  1042     // TODO(littledan): Remove this RegExp compat workaround |  1083     // TODO(littledan): Remove this RegExp compat workaround | 
|  1043     if (this === GlobalRegExpPrototype) { |  1084     if (this === GlobalRegExpPrototype) { | 
|  1044       %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); |  1085       %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); | 
|  1045       return UNDEFINED; |  1086       return UNDEFINED; | 
|  1046     } |  1087     } | 
|  1047     throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.global"); |  1088     throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.global"); | 
|  1048   } |  1089   } | 
|  1049   return !!REGEXP_GLOBAL(this); |  1090   return TO_BOOLEAN(REGEXP_GLOBAL(this)); | 
|  1050 } |  1091 } | 
 |  1092 %SetForceInlineFlag(RegExpGetGlobal); | 
|  1051  |  1093  | 
|  1052  |  1094  | 
|  1053 // ES6 21.2.5.5. |  1095 // ES6 21.2.5.5. | 
|  1054 function RegExpGetIgnoreCase() { |  1096 function RegExpGetIgnoreCase() { | 
|  1055   if (!IS_REGEXP(this)) { |  1097   if (!IS_REGEXP(this)) { | 
|  1056     // TODO(littledan): Remove this RegExp compat workaround |  1098     // TODO(littledan): Remove this RegExp compat workaround | 
|  1057     if (this === GlobalRegExpPrototype) { |  1099     if (this === GlobalRegExpPrototype) { | 
|  1058       %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); |  1100       %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); | 
|  1059       return UNDEFINED; |  1101       return UNDEFINED; | 
|  1060     } |  1102     } | 
|  1061     throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.ignoreCase"); |  1103     throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.ignoreCase"); | 
|  1062   } |  1104   } | 
|  1063   return !!REGEXP_IGNORE_CASE(this); |  1105   return TO_BOOLEAN(REGEXP_IGNORE_CASE(this)); | 
|  1064 } |  1106 } | 
|  1065  |  1107  | 
|  1066  |  1108  | 
|  1067 // ES6 21.2.5.7. |  1109 // ES6 21.2.5.7. | 
|  1068 function RegExpGetMultiline() { |  1110 function RegExpGetMultiline() { | 
|  1069   if (!IS_REGEXP(this)) { |  1111   if (!IS_REGEXP(this)) { | 
|  1070     // TODO(littledan): Remove this RegExp compat workaround |  1112     // TODO(littledan): Remove this RegExp compat workaround | 
|  1071     if (this === GlobalRegExpPrototype) { |  1113     if (this === GlobalRegExpPrototype) { | 
|  1072       %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); |  1114       %IncrementUseCounter(kRegExpPrototypeOldFlagGetter); | 
|  1073       return UNDEFINED; |  1115       return UNDEFINED; | 
|  1074     } |  1116     } | 
|  1075     throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.multiline"); |  1117     throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.multiline"); | 
|  1076   } |  1118   } | 
|  1077   return !!REGEXP_MULTILINE(this); |  1119   return TO_BOOLEAN(REGEXP_MULTILINE(this)); | 
|  1078 } |  1120 } | 
|  1079  |  1121  | 
|  1080  |  1122  | 
|  1081 // ES6 21.2.5.10. |  1123 // ES6 21.2.5.10. | 
|  1082 function RegExpGetSource() { |  1124 function RegExpGetSource() { | 
|  1083   if (!IS_REGEXP(this)) { |  1125   if (!IS_REGEXP(this)) { | 
|  1084     // TODO(littledan): Remove this RegExp compat workaround |  1126     // TODO(littledan): Remove this RegExp compat workaround | 
|  1085     if (this === GlobalRegExpPrototype) { |  1127     if (this === GlobalRegExpPrototype) { | 
|  1086       %IncrementUseCounter(kRegExpPrototypeSourceGetter); |  1128       %IncrementUseCounter(kRegExpPrototypeSourceGetter); | 
|  1087       return UNDEFINED; |  1129       return UNDEFINED; | 
|  1088     } |  1130     } | 
|  1089     throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.source"); |  1131     throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.source"); | 
|  1090   } |  1132   } | 
|  1091   return REGEXP_SOURCE(this); |  1133   return REGEXP_SOURCE(this); | 
|  1092 } |  1134 } | 
|  1093  |  1135  | 
|  1094  |  1136  | 
|  1095 // ES6 21.2.5.12. |  1137 // ES6 21.2.5.12. | 
|  1096 function RegExpGetSticky() { |  1138 function RegExpGetSticky() { | 
|  1097   if (!IS_REGEXP(this)) { |  1139   if (!IS_REGEXP(this)) { | 
|  1098     // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it |  1140     // Compat fix: RegExp.prototype.sticky == undefined; UseCounter tracks it | 
|  1099     // TODO(littledan): Remove this workaround or standardize it |  1141     // TODO(littledan): Remove this workaround or standardize it | 
|  1100     if (this === GlobalRegExpPrototype) { |  1142     if (this === GlobalRegExpPrototype) { | 
|  1101       %IncrementUseCounter(kRegExpPrototypeStickyGetter); |  1143       %IncrementUseCounter(kRegExpPrototypeStickyGetter); | 
|  1102       return UNDEFINED; |  1144       return UNDEFINED; | 
|  1103     } |  1145     } | 
|  1104     throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.sticky"); |  1146     throw MakeTypeError(kRegExpNonRegExp, "RegExp.prototype.sticky"); | 
|  1105   } |  1147   } | 
|  1106   return !!REGEXP_STICKY(this); |  1148   return TO_BOOLEAN(REGEXP_STICKY(this)); | 
|  1107 } |  1149 } | 
 |  1150 %SetForceInlineFlag(RegExpGetSticky); | 
|  1108  |  1151  | 
|  1109 // ------------------------------------------------------------------- |  1152 // ------------------------------------------------------------------- | 
|  1110  |  1153  | 
|  1111 %FunctionSetInstanceClassName(GlobalRegExp, 'RegExp'); |  1154 %FunctionSetInstanceClassName(GlobalRegExp, 'RegExp'); | 
|  1112 GlobalRegExpPrototype = new GlobalObject(); |  1155 GlobalRegExpPrototype = new GlobalObject(); | 
|  1113 %FunctionSetPrototype(GlobalRegExp, GlobalRegExpPrototype); |  1156 %FunctionSetPrototype(GlobalRegExp, GlobalRegExpPrototype); | 
|  1114 %AddNamedProperty( |  1157 %AddNamedProperty( | 
|  1115     GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM); |  1158     GlobalRegExp.prototype, 'constructor', GlobalRegExp, DONT_ENUM); | 
|  1116 %SetCode(GlobalRegExp, RegExpConstructor); |  1159 %SetCode(GlobalRegExp, RegExpConstructor); | 
|  1117  |  1160  | 
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1188   to.RegExpSubclassMatch = RegExpSubclassMatch; |  1231   to.RegExpSubclassMatch = RegExpSubclassMatch; | 
|  1189   to.RegExpSubclassReplace = RegExpSubclassReplace; |  1232   to.RegExpSubclassReplace = RegExpSubclassReplace; | 
|  1190   to.RegExpSubclassSearch = RegExpSubclassSearch; |  1233   to.RegExpSubclassSearch = RegExpSubclassSearch; | 
|  1191   to.RegExpSubclassSplit = RegExpSubclassSplit; |  1234   to.RegExpSubclassSplit = RegExpSubclassSplit; | 
|  1192   to.RegExpSubclassTest = RegExpSubclassTest; |  1235   to.RegExpSubclassTest = RegExpSubclassTest; | 
|  1193   to.RegExpTest = RegExpTest; |  1236   to.RegExpTest = RegExpTest; | 
|  1194   to.IsRegExp = IsRegExp; |  1237   to.IsRegExp = IsRegExp; | 
|  1195 }); |  1238 }); | 
|  1196  |  1239  | 
|  1197 }) |  1240 }) | 
| OLD | NEW |