| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 return %StringLocaleCompare(this_str, other_str); | 161 return %StringLocaleCompare(this_str, other_str); |
| 162 } | 162 } |
| 163 | 163 |
| 164 | 164 |
| 165 // ECMA-262 section 15.5.4.10 | 165 // ECMA-262 section 15.5.4.10 |
| 166 function StringMatch(regexp) { | 166 function StringMatch(regexp) { |
| 167 if (!IS_REGEXP(regexp)) regexp = new ORIGINAL_REGEXP(regexp); | 167 if (!IS_REGEXP(regexp)) regexp = new ORIGINAL_REGEXP(regexp); |
| 168 var subject = TO_STRING_INLINE(this); | 168 var subject = TO_STRING_INLINE(this); |
| 169 | 169 |
| 170 if (!regexp.global) return regexp.exec(subject); | 170 if (!regexp.global) return regexp.exec(subject); |
| 171 |
| 172 var cache = regExpCache; |
| 173 |
| 174 if (%_ObjectEquals(cache.type, 'match') && |
| 175 %_ObjectEquals(cache.regExp, regexp) && |
| 176 %_ObjectEquals(cache.subject, subject)) { |
| 177 var last = cache.answer; |
| 178 if (last == null) { |
| 179 return last; |
| 180 } else { |
| 181 return CloneRegexpAnswer(last); |
| 182 } |
| 183 } |
| 184 |
| 171 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); | 185 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); |
| 172 // lastMatchInfo is defined in regexp-delay.js. | 186 // lastMatchInfo is defined in regexp-delay.js. |
| 173 return %StringMatch(subject, regexp, lastMatchInfo); | 187 var result = %StringMatch(subject, regexp, lastMatchInfo); |
| 188 cache.type = 'match'; |
| 189 cache.regExp = regexp; |
| 190 cache.subject = subject; |
| 191 cache.answer = result; |
| 192 if (result == null) { |
| 193 return result; |
| 194 } else { |
| 195 return CloneRegexpAnswer(result); |
| 196 } |
| 174 } | 197 } |
| 175 | 198 |
| 176 | 199 |
| 177 // SubString is an internal function that returns the sub string of 'string'. | 200 // SubString is an internal function that returns the sub string of 'string'. |
| 178 // If resulting string is of length 1, we use the one character cache | 201 // If resulting string is of length 1, we use the one character cache |
| 179 // otherwise we call the runtime system. | 202 // otherwise we call the runtime system. |
| 180 function SubString(string, start, end) { | 203 function SubString(string, start, end) { |
| 181 // Use the one character string cache. | 204 // Use the one character string cache. |
| 182 if (start + 1 == end) { | 205 if (start + 1 == end) { |
| 183 var char_code = %_FastCharCodeAt(string, start); | 206 var char_code = %_FastCharCodeAt(string, start); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 199 | 222 |
| 200 | 223 |
| 201 // ECMA-262, section 15.5.4.11 | 224 // ECMA-262, section 15.5.4.11 |
| 202 function StringReplace(search, replace) { | 225 function StringReplace(search, replace) { |
| 203 var subject = TO_STRING_INLINE(this); | 226 var subject = TO_STRING_INLINE(this); |
| 204 | 227 |
| 205 // Delegate to one of the regular expression variants if necessary. | 228 // Delegate to one of the regular expression variants if necessary. |
| 206 if (IS_REGEXP(search)) { | 229 if (IS_REGEXP(search)) { |
| 207 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]); | 230 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]); |
| 208 if (IS_FUNCTION(replace)) { | 231 if (IS_FUNCTION(replace)) { |
| 232 regExpCache.type = 'none'; |
| 209 return StringReplaceRegExpWithFunction(subject, search, replace); | 233 return StringReplaceRegExpWithFunction(subject, search, replace); |
| 210 } else { | 234 } else { |
| 211 return StringReplaceRegExp(subject, search, replace); | 235 return StringReplaceRegExp(subject, search, replace); |
| 212 } | 236 } |
| 213 } | 237 } |
| 214 | 238 |
| 215 // Convert the search argument to a string and search for it. | 239 // Convert the search argument to a string and search for it. |
| 216 search = TO_STRING_INLINE(search); | 240 search = TO_STRING_INLINE(search); |
| 217 var start = %StringIndexOf(subject, search, 0); | 241 var start = %StringIndexOf(subject, search, 0); |
| 218 if (start < 0) return subject; | 242 if (start < 0) return subject; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 232 ExpandReplacement(replace, subject, reusableMatchInfo, builder); | 256 ExpandReplacement(replace, subject, reusableMatchInfo, builder); |
| 233 } | 257 } |
| 234 | 258 |
| 235 // suffix | 259 // suffix |
| 236 builder.addSpecialSlice(end, subject.length); | 260 builder.addSpecialSlice(end, subject.length); |
| 237 | 261 |
| 238 return builder.generate(); | 262 return builder.generate(); |
| 239 } | 263 } |
| 240 | 264 |
| 241 | 265 |
| 242 var cachedReplaceSubject; | |
| 243 var cachedReplaceRegexp; | |
| 244 var cachedReplaceReplacement; | |
| 245 var cachedReplaceAnswer; | |
| 246 | |
| 247 // Helper function for regular expressions in String.prototype.replace. | 266 // Helper function for regular expressions in String.prototype.replace. |
| 248 function StringReplaceRegExp(subject, regexp, replace) { | 267 function StringReplaceRegExp(subject, regexp, replace) { |
| 249 if (%_ObjectEquals(replace, cachedReplaceReplacement) && | 268 var cache = regExpCache; |
| 250 %_ObjectEquals(subject, cachedReplaceSubject) && | 269 if (%_ObjectEquals(cache.regExp, regexp) && |
| 251 %_ObjectEquals(regexp, cachedReplaceRegexp)) { | 270 %_ObjectEquals(cache.type, 'replace') && |
| 252 return cachedReplaceAnswer; | 271 %_ObjectEquals(cache.replaceString, replace) && |
| 272 %_ObjectEquals(cache.subject, subject)) { |
| 273 return cache.answer; |
| 253 } | 274 } |
| 254 replace = TO_STRING_INLINE(replace); | 275 replace = TO_STRING_INLINE(replace); |
| 255 var answer = %StringReplaceRegExpWithString(subject, | 276 var answer = %StringReplaceRegExpWithString(subject, |
| 256 regexp, | 277 regexp, |
| 257 replace, | 278 replace, |
| 258 lastMatchInfo); | 279 lastMatchInfo); |
| 259 cachedReplaceSubject = subject; | 280 cache.subject = subject; |
| 260 cachedReplaceRegexp = regexp; | 281 cache.regExp = regexp; |
| 261 cachedReplaceReplacement = replace; | 282 cache.replaceString = replace; |
| 262 cachedReplaceAnswer = answer; | 283 cache.answer = answer; |
| 284 cache.type = 'replace'; |
| 263 return answer; | 285 return answer; |
| 264 } | 286 } |
| 265 | 287 |
| 266 | 288 |
| 267 // Expand the $-expressions in the string and return a new string with | 289 // Expand the $-expressions in the string and return a new string with |
| 268 // the result. | 290 // the result. |
| 269 function ExpandReplacement(string, subject, matchInfo, builder) { | 291 function ExpandReplacement(string, subject, matchInfo, builder) { |
| 270 var next = %StringIndexOf(string, '$', 0); | 292 var next = %StringIndexOf(string, '$', 0); |
| 271 if (next < 0) { | 293 if (next < 0) { |
| 272 builder.add(string); | 294 builder.add(string); |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 570 var separator_length = separator.length; | 592 var separator_length = separator.length; |
| 571 | 593 |
| 572 // If the separator string is empty then return the elements in the subject. | 594 // If the separator string is empty then return the elements in the subject. |
| 573 if (separator_length === 0) return %StringToArray(subject); | 595 if (separator_length === 0) return %StringToArray(subject); |
| 574 | 596 |
| 575 var result = %StringSplit(subject, separator, limit); | 597 var result = %StringSplit(subject, separator, limit); |
| 576 | 598 |
| 577 return result; | 599 return result; |
| 578 } | 600 } |
| 579 | 601 |
| 602 var cache = regExpCache; |
| 603 |
| 604 if (%_ObjectEquals(cache.type, 'split') && |
| 605 %_ObjectEquals(cache.regExp, separator) && |
| 606 %_ObjectEquals(cache.subject, subject)) { |
| 607 return CloneRegexpAnswer(cache.answer); |
| 608 } |
| 609 |
| 610 cache.type = 'split'; |
| 611 cache.regExp = separator; |
| 612 cache.subject = subject; |
| 613 |
| 580 %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]); | 614 %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]); |
| 581 | 615 |
| 582 if (length === 0) { | 616 if (length === 0) { |
| 583 if (splitMatch(separator, subject, 0, 0) != null) return []; | 617 if (splitMatch(separator, subject, 0, 0) != null) { |
| 618 cache.answer = []; |
| 619 return []; |
| 620 } |
| 621 cache.answer = [subject]; |
| 584 return [subject]; | 622 return [subject]; |
| 585 } | 623 } |
| 586 | 624 |
| 587 var currentIndex = 0; | 625 var currentIndex = 0; |
| 588 var startIndex = 0; | 626 var startIndex = 0; |
| 589 var result = []; | 627 var result = []; |
| 590 | 628 |
| 591 while (true) { | 629 while (true) { |
| 592 | 630 |
| 593 if (startIndex === length) { | 631 if (startIndex === length) { |
| 594 result[result.length] = subject.slice(currentIndex, length); | 632 result[result.length] = subject.slice(currentIndex, length); |
| 595 return result; | 633 cache.answer = result; |
| 634 return CloneRegexpAnswer(result); |
| 596 } | 635 } |
| 597 | 636 |
| 598 var matchInfo = splitMatch(separator, subject, currentIndex, startIndex); | 637 var matchInfo = splitMatch(separator, subject, currentIndex, startIndex); |
| 599 | 638 |
| 600 if (IS_NULL(matchInfo)) { | 639 if (IS_NULL(matchInfo)) { |
| 601 result[result.length] = subject.slice(currentIndex, length); | 640 result[result.length] = subject.slice(currentIndex, length); |
| 602 return result; | 641 cache.answer = result; |
| 642 return CloneRegexpAnswer(result); |
| 603 } | 643 } |
| 604 | 644 |
| 605 var endIndex = matchInfo[CAPTURE1]; | 645 var endIndex = matchInfo[CAPTURE1]; |
| 606 | 646 |
| 607 // We ignore a zero-length match at the currentIndex. | 647 // We ignore a zero-length match at the currentIndex. |
| 608 if (startIndex === endIndex && endIndex === currentIndex) { | 648 if (startIndex === endIndex && endIndex === currentIndex) { |
| 609 startIndex++; | 649 startIndex++; |
| 610 continue; | 650 continue; |
| 611 } | 651 } |
| 612 | 652 |
| 613 result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]
); | 653 result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]
); |
| 614 if (result.length === limit) return result; | 654 if (result.length === limit) { |
| 655 cache.answer = result; |
| 656 return CloneRegexpAnswer(result); |
| 657 } |
| 615 | 658 |
| 616 var num_captures = NUMBER_OF_CAPTURES(matchInfo); | 659 var num_captures = NUMBER_OF_CAPTURES(matchInfo); |
| 617 for (var i = 2; i < num_captures; i += 2) { | 660 for (var i = 2; i < num_captures; i += 2) { |
| 618 var start = matchInfo[CAPTURE(i)]; | 661 var start = matchInfo[CAPTURE(i)]; |
| 619 var end = matchInfo[CAPTURE(i + 1)]; | 662 var end = matchInfo[CAPTURE(i + 1)]; |
| 620 if (start != -1 && end != -1) { | 663 if (start != -1 && end != -1) { |
| 621 result[result.length] = SubString(subject, start, end); | 664 result[result.length] = SubString(subject, start, end); |
| 622 } else { | 665 } else { |
| 623 result[result.length] = void 0; | 666 result[result.length] = void 0; |
| 624 } | 667 } |
| 625 if (result.length === limit) return result; | 668 if (result.length === limit) { |
| 669 cache.answer = result; |
| 670 return CloneRegexpAnswer(result); |
| 671 } |
| 626 } | 672 } |
| 627 | 673 |
| 628 startIndex = currentIndex = endIndex; | 674 startIndex = currentIndex = endIndex; |
| 629 } | 675 } |
| 630 } | 676 } |
| 631 | 677 |
| 632 | 678 |
| 633 // ECMA-262 section 15.5.4.14 | 679 // ECMA-262 section 15.5.4.14 |
| 634 // Helper function used by split. This version returns the matchInfo | 680 // Helper function used by split. This version returns the matchInfo |
| 635 // instead of allocating a new array with basically the same information. | 681 // instead of allocating a new array with basically the same information. |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 939 "small", StringSmall, | 985 "small", StringSmall, |
| 940 "strike", StringStrike, | 986 "strike", StringStrike, |
| 941 "sub", StringSub, | 987 "sub", StringSub, |
| 942 "sup", StringSup, | 988 "sup", StringSup, |
| 943 "toJSON", StringToJSON | 989 "toJSON", StringToJSON |
| 944 )); | 990 )); |
| 945 } | 991 } |
| 946 | 992 |
| 947 | 993 |
| 948 SetupString(); | 994 SetupString(); |
| OLD | NEW |