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 |