| 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 lastMatchInfoSymbol = utils.ImportNow("regexp_last_match_info_symbol"); |
| 21 var matchSymbol = utils.ImportNow("match_symbol"); | 21 var matchSymbol = utils.ImportNow("match_symbol"); |
| 22 var replaceSymbol = utils.ImportNow("replace_symbol"); | 22 var replaceSymbol = utils.ImportNow("replace_symbol"); |
| 23 var searchSymbol = utils.ImportNow("search_symbol"); | 23 var searchSymbol = utils.ImportNow("search_symbol"); |
| 24 var speciesSymbol = utils.ImportNow("species_symbol"); | 24 var speciesSymbol = utils.ImportNow("species_symbol"); |
| 25 var splitSymbol = utils.ImportNow("split_symbol"); | 25 var splitSymbol = utils.ImportNow("split_symbol"); |
| 26 var SpeciesConstructor; | 26 var SpeciesConstructor; |
| 27 var RegExpSubclassExecJS; |
| 27 | 28 |
| 28 utils.Import(function(from) { | 29 utils.Import(function(from) { |
| 29 ExpandReplacement = from.ExpandReplacement; | 30 ExpandReplacement = from.ExpandReplacement; |
| 30 MaxSimple = from.MaxSimple; | 31 MaxSimple = from.MaxSimple; |
| 31 MinSimple = from.MinSimple; | 32 MinSimple = from.MinSimple; |
| 32 SpeciesConstructor = from.SpeciesConstructor; | 33 SpeciesConstructor = from.SpeciesConstructor; |
| 33 }); | 34 }); |
| 34 | 35 |
| 35 // ------------------------------------------------------------------- | 36 // ------------------------------------------------------------------- |
| 36 | 37 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 if (start != -1) { | 96 if (start != -1) { |
| 96 end = MATCHINFO[j]; | 97 end = MATCHINFO[j]; |
| 97 result[i] = %_SubString(STRING, start, end); | 98 result[i] = %_SubString(STRING, start, end); |
| 98 } | 99 } |
| 99 j++; | 100 j++; |
| 100 } | 101 } |
| 101 return result; | 102 return result; |
| 102 endmacro | 103 endmacro |
| 103 | 104 |
| 104 | 105 |
| 105 function RegExpExecNoTests(regexp, string, start) { | |
| 106 // Must be called with RegExp, string and positive integer as arguments. | |
| 107 var matchInfo = %_RegExpExec(regexp, string, start, RegExpLastMatchInfo); | |
| 108 if (matchInfo !== null) { | |
| 109 // ES6 21.2.5.2.2 step 18. | |
| 110 if (REGEXP_STICKY(regexp)) regexp.lastIndex = matchInfo[CAPTURE1]; | |
| 111 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchInfo, string); | |
| 112 } | |
| 113 regexp.lastIndex = 0; | |
| 114 return null; | |
| 115 } | |
| 116 | |
| 117 | |
| 118 // ES#sec-regexp.prototype.exec | |
| 119 // RegExp.prototype.exec ( string ) | |
| 120 function RegExpSubclassExecJS(string) { | |
| 121 if (!IS_REGEXP(this)) { | |
| 122 throw %make_type_error(kIncompatibleMethodReceiver, | |
| 123 'RegExp.prototype.exec', this); | |
| 124 } | |
| 125 | |
| 126 string = TO_STRING(string); | |
| 127 var lastIndex = this.lastIndex; | |
| 128 | |
| 129 // Conversion is required by the ES2015 specification (RegExpBuiltinExec | |
| 130 // algorithm, step 4) even if the value is discarded for non-global RegExps. | |
| 131 var i = TO_LENGTH(lastIndex); | |
| 132 | |
| 133 var global = TO_BOOLEAN(REGEXP_GLOBAL(this)); | |
| 134 var sticky = TO_BOOLEAN(REGEXP_STICKY(this)); | |
| 135 var updateLastIndex = global || sticky; | |
| 136 if (updateLastIndex) { | |
| 137 if (i > string.length) { | |
| 138 this.lastIndex = 0; | |
| 139 return null; | |
| 140 } | |
| 141 } else { | |
| 142 i = 0; | |
| 143 } | |
| 144 | |
| 145 // matchIndices is either null or the RegExpLastMatchInfo array. | |
| 146 // TODO(littledan): Whether a RegExp is sticky is compiled into the RegExp | |
| 147 // itself, but ES2015 allows monkey-patching this property to differ from | |
| 148 // the internal flags. If it differs, recompile a different RegExp? | |
| 149 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo); | |
| 150 | |
| 151 if (IS_NULL(matchIndices)) { | |
| 152 this.lastIndex = 0; | |
| 153 return null; | |
| 154 } | |
| 155 | |
| 156 // Successful match. | |
| 157 if (updateLastIndex) { | |
| 158 this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; | |
| 159 } | |
| 160 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string); | |
| 161 } | |
| 162 %FunctionRemovePrototype(RegExpSubclassExecJS); | |
| 163 | |
| 164 | |
| 165 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | 106 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
| 166 // Also takes an optional exec method in case our caller | 107 // Also takes an optional exec method in case our caller |
| 167 // has already fetched exec. | 108 // has already fetched exec. |
| 168 function RegExpSubclassExec(regexp, string, exec) { | 109 function RegExpSubclassExec(regexp, string, exec) { |
| 169 if (IS_UNDEFINED(exec)) { | 110 if (IS_UNDEFINED(exec)) { |
| 170 exec = regexp.exec; | 111 exec = regexp.exec; |
| 171 } | 112 } |
| 172 if (IS_CALLABLE(exec)) { | 113 if (IS_CALLABLE(exec)) { |
| 173 var result = %_Call(exec, regexp, string); | 114 var result = %_Call(exec, regexp, string); |
| 174 if (!IS_RECEIVER(result) && !IS_NULL(result)) { | 115 if (!IS_RECEIVER(result) && !IS_NULL(result)) { |
| 175 throw %make_type_error(kInvalidRegExpExecResult); | 116 throw %make_type_error(kInvalidRegExpExecResult); |
| 176 } | 117 } |
| 177 return result; | 118 return result; |
| 178 } | 119 } |
| 179 return %_Call(RegExpSubclassExecJS, regexp, string); | 120 return %_Call(RegExpSubclassExecJS, regexp, string); |
| 180 } | 121 } |
| 181 %SetForceInlineFlag(RegExpSubclassExec); | 122 %SetForceInlineFlag(RegExpSubclassExec); |
| 182 | 123 |
| 183 | 124 |
| 184 // ES#sec-regexp.prototype.test RegExp.prototype.test ( S ) | |
| 185 function RegExpSubclassTest(string) { | |
| 186 if (!IS_RECEIVER(this)) { | |
| 187 throw %make_type_error(kIncompatibleMethodReceiver, | |
| 188 'RegExp.prototype.test', this); | |
| 189 } | |
| 190 string = TO_STRING(string); | |
| 191 var match = RegExpSubclassExec(this, string); | |
| 192 return !IS_NULL(match); | |
| 193 } | |
| 194 %FunctionRemovePrototype(RegExpSubclassTest); | |
| 195 | |
| 196 | |
| 197 function AtSurrogatePair(subject, index) { | 125 function AtSurrogatePair(subject, index) { |
| 198 if (index + 1 >= subject.length) return false; | 126 if (index + 1 >= subject.length) return false; |
| 199 var first = %_StringCharCodeAt(subject, index); | 127 var first = %_StringCharCodeAt(subject, index); |
| 200 if (first < 0xD800 || first > 0xDBFF) return false; | 128 if (first < 0xD800 || first > 0xDBFF) return false; |
| 201 var second = %_StringCharCodeAt(subject, index + 1); | 129 var second = %_StringCharCodeAt(subject, index + 1); |
| 202 return second >= 0xDC00 || second <= 0xDFFF; | 130 return second >= 0xDC00 || second <= 0xDFFF; |
| 203 } | 131 } |
| 204 | 132 |
| 205 | 133 |
| 206 // Legacy implementation of RegExp.prototype[Symbol.split] which | 134 // Legacy implementation of RegExp.prototype[Symbol.split] which |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 347 } | 275 } |
| 348 } | 276 } |
| 349 } | 277 } |
| 350 %AddElement(array, arrayIndex, | 278 %AddElement(array, arrayIndex, |
| 351 %_SubString(string, prevStringIndex, size)); | 279 %_SubString(string, prevStringIndex, size)); |
| 352 return array; | 280 return array; |
| 353 } | 281 } |
| 354 %FunctionRemovePrototype(RegExpSubclassSplit); | 282 %FunctionRemovePrototype(RegExpSubclassSplit); |
| 355 | 283 |
| 356 | 284 |
| 357 // ES#sec-regexp.prototype-@@match | |
| 358 // RegExp.prototype [ @@match ] ( string ) | |
| 359 function RegExpSubclassMatch(string) { | |
| 360 if (!IS_RECEIVER(this)) { | |
| 361 throw %make_type_error(kIncompatibleMethodReceiver, | |
| 362 "RegExp.prototype.@@match", this); | |
| 363 } | |
| 364 string = TO_STRING(string); | |
| 365 var global = this.global; | |
| 366 if (!global) return RegExpSubclassExec(this, string); | |
| 367 var unicode = this.unicode; | |
| 368 this.lastIndex = 0; | |
| 369 var array = new InternalArray(); | |
| 370 var n = 0; | |
| 371 var result; | |
| 372 while (true) { | |
| 373 result = RegExpSubclassExec(this, string); | |
| 374 if (IS_NULL(result)) { | |
| 375 if (n === 0) return null; | |
| 376 break; | |
| 377 } | |
| 378 var matchStr = TO_STRING(result[0]); | |
| 379 array[n] = matchStr; | |
| 380 if (matchStr === "") SetAdvancedStringIndex(this, string, unicode); | |
| 381 n++; | |
| 382 } | |
| 383 var resultArray = []; | |
| 384 %MoveArrayContents(array, resultArray); | |
| 385 return resultArray; | |
| 386 } | |
| 387 %FunctionRemovePrototype(RegExpSubclassMatch); | |
| 388 | |
| 389 | |
| 390 // Legacy implementation of RegExp.prototype[Symbol.replace] which | 285 // Legacy implementation of RegExp.prototype[Symbol.replace] which |
| 391 // doesn't properly call the underlying exec method. | 286 // doesn't properly call the underlying exec method. |
| 392 | 287 |
| 393 // TODO(lrn): This array will survive indefinitely if replace is never | 288 // TODO(lrn): This array will survive indefinitely if replace is never |
| 394 // called again. However, it will be empty, since the contents are cleared | 289 // called again. However, it will be empty, since the contents are cleared |
| 395 // in the finally block. | 290 // in the finally block. |
| 396 var reusableReplaceArray = new InternalArray(4); | 291 var reusableReplaceArray = new InternalArray(4); |
| 397 | 292 |
| 398 // Helper function for replacing regular expressions with the result of a | 293 // Helper function for replacing regular expressions with the result of a |
| 399 // function application in String.prototype.replace. | 294 // function application in String.prototype.replace. |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 746 %_SubString(string, nextSourcePosition, position) + replacement; | 641 %_SubString(string, nextSourcePosition, position) + replacement; |
| 747 nextSourcePosition = position + matchedLength; | 642 nextSourcePosition = position + matchedLength; |
| 748 } | 643 } |
| 749 } | 644 } |
| 750 if (nextSourcePosition >= length) return accumulatedResult; | 645 if (nextSourcePosition >= length) return accumulatedResult; |
| 751 return accumulatedResult + %_SubString(string, nextSourcePosition, length); | 646 return accumulatedResult + %_SubString(string, nextSourcePosition, length); |
| 752 } | 647 } |
| 753 %FunctionRemovePrototype(RegExpSubclassReplace); | 648 %FunctionRemovePrototype(RegExpSubclassReplace); |
| 754 | 649 |
| 755 | 650 |
| 756 // ES#sec-regexp.prototype-@@search | |
| 757 // RegExp.prototype [ @@search ] ( string ) | |
| 758 function RegExpSubclassSearch(string) { | |
| 759 if (!IS_RECEIVER(this)) { | |
| 760 throw %make_type_error(kIncompatibleMethodReceiver, | |
| 761 "RegExp.prototype.@@search", this); | |
| 762 } | |
| 763 string = TO_STRING(string); | |
| 764 var previousLastIndex = this.lastIndex; | |
| 765 this.lastIndex = 0; | |
| 766 var result = RegExpSubclassExec(this, string); | |
| 767 this.lastIndex = previousLastIndex; | |
| 768 if (IS_NULL(result)) return -1; | |
| 769 return result.index; | |
| 770 } | |
| 771 %FunctionRemovePrototype(RegExpSubclassSearch); | |
| 772 | |
| 773 | |
| 774 // ------------------------------------------------------------------- | 651 // ------------------------------------------------------------------- |
| 775 | 652 |
| 776 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [ | 653 utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [ |
| 777 "exec", RegExpSubclassExecJS, | |
| 778 "test", RegExpSubclassTest, | |
| 779 matchSymbol, RegExpSubclassMatch, | |
| 780 replaceSymbol, RegExpSubclassReplace, | 654 replaceSymbol, RegExpSubclassReplace, |
| 781 searchSymbol, RegExpSubclassSearch, | |
| 782 splitSymbol, RegExpSubclassSplit, | 655 splitSymbol, RegExpSubclassSplit, |
| 783 ]); | 656 ]); |
| 784 | 657 |
| 785 // Temporary until all RegExpLastMatchInfo accesses are ported to C++. | 658 // Temporary until all RegExpLastMatchInfo accesses are ported to C++. |
| 786 SET_PRIVATE(GlobalRegExp, lastMatchInfoSymbol, RegExpLastMatchInfo); | 659 SET_PRIVATE(GlobalRegExp, lastMatchInfoSymbol, RegExpLastMatchInfo); |
| 787 | 660 |
| 661 var RegExpSubclassExecJS = GlobalRegExp.prototype.exec; |
| 662 |
| 788 // ------------------------------------------------------------------- | 663 // ------------------------------------------------------------------- |
| 789 // Internal | 664 // Internal |
| 790 | 665 |
| 791 var InternalRegExpMatchInfo = { | 666 var InternalRegExpMatchInfo = { |
| 792 REGEXP_NUMBER_OF_CAPTURES: 2, | 667 REGEXP_NUMBER_OF_CAPTURES: 2, |
| 793 REGEXP_LAST_SUBJECT: "", | 668 REGEXP_LAST_SUBJECT: "", |
| 794 REGEXP_LAST_INPUT: UNDEFINED, | 669 REGEXP_LAST_INPUT: UNDEFINED, |
| 795 CAPTURE0: 0, | 670 CAPTURE0: 0, |
| 796 CAPTURE1: 0 | 671 CAPTURE1: 0 |
| 797 }; | 672 }; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 813 // Exports | 688 // Exports |
| 814 | 689 |
| 815 utils.Export(function(to) { | 690 utils.Export(function(to) { |
| 816 to.InternalRegExpMatch = InternalRegExpMatch; | 691 to.InternalRegExpMatch = InternalRegExpMatch; |
| 817 to.InternalRegExpReplace = InternalRegExpReplace; | 692 to.InternalRegExpReplace = InternalRegExpReplace; |
| 818 to.IsRegExp = IsRegExp; | 693 to.IsRegExp = IsRegExp; |
| 819 to.RegExpInitialize = RegExpInitialize; | 694 to.RegExpInitialize = RegExpInitialize; |
| 820 }); | 695 }); |
| 821 | 696 |
| 822 }) | 697 }) |
| OLD | NEW |