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 16 matching lines...) Expand all Loading... |
27 | 27 |
28 | 28 |
29 // This file relies on the fact that the following declaration has been made | 29 // This file relies on the fact that the following declaration has been made |
30 // in runtime.js: | 30 // in runtime.js: |
31 // const $String = global.String; | 31 // const $String = global.String; |
32 // const $NaN = 0/0; | 32 // const $NaN = 0/0; |
33 | 33 |
34 | 34 |
35 // Set the String function and constructor. | 35 // Set the String function and constructor. |
36 %SetCode($String, function(x) { | 36 %SetCode($String, function(x) { |
37 var value = %_ArgumentsLength() == 0 ? '' : ToString(x); | 37 var value = %_ArgumentsLength() == 0 ? '' : TO_STRING_INLINE(x); |
38 if (%_IsConstructCall()) { | 38 if (%_IsConstructCall()) { |
39 %_SetValueOf(this, value); | 39 %_SetValueOf(this, value); |
40 } else { | 40 } else { |
41 return value; | 41 return value; |
42 } | 42 } |
43 }); | 43 }); |
44 | 44 |
45 %FunctionSetPrototype($String, new $String()); | 45 %FunctionSetPrototype($String, new $String()); |
46 | 46 |
47 // ECMA-262 section 15.5.4.2 | 47 // ECMA-262 section 15.5.4.2 |
48 function StringToString() { | 48 function StringToString() { |
49 if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) | 49 if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) |
50 throw new $TypeError('String.prototype.toString is not generic'); | 50 throw new $TypeError('String.prototype.toString is not generic'); |
51 return %_ValueOf(this); | 51 return %_ValueOf(this); |
52 } | 52 } |
53 | 53 |
54 | 54 |
55 // ECMA-262 section 15.5.4.3 | 55 // ECMA-262 section 15.5.4.3 |
56 function StringValueOf() { | 56 function StringValueOf() { |
57 if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) | 57 if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) |
58 throw new $TypeError('String.prototype.valueOf is not generic'); | 58 throw new $TypeError('String.prototype.valueOf is not generic'); |
59 return %_ValueOf(this); | 59 return %_ValueOf(this); |
60 } | 60 } |
61 | 61 |
62 | 62 |
63 // ECMA-262, section 15.5.4.4 | 63 // ECMA-262, section 15.5.4.4 |
64 function StringCharAt(pos) { | 64 function StringCharAt(pos) { |
65 var char_code = %_FastCharCodeAt(this, pos); | 65 var char_code = %_FastCharCodeAt(this, pos); |
66 if (!%_IsSmi(char_code)) { | 66 if (!%_IsSmi(char_code)) { |
67 var subject = ToString(this); | 67 var subject = TO_STRING_INLINE(this); |
68 var index = TO_INTEGER(pos); | 68 var index = TO_INTEGER(pos); |
69 if (index >= subject.length || index < 0) return ""; | 69 if (index >= subject.length || index < 0) return ""; |
70 char_code = %StringCharCodeAt(subject, index); | 70 char_code = %StringCharCodeAt(subject, index); |
71 } | 71 } |
72 return %CharFromCode(char_code); | 72 return %CharFromCode(char_code); |
73 } | 73 } |
74 | 74 |
75 | 75 |
76 // ECMA-262 section 15.5.4.5 | 76 // ECMA-262 section 15.5.4.5 |
77 function StringCharCodeAt(pos) { | 77 function StringCharCodeAt(pos) { |
78 var fast_answer = %_FastCharCodeAt(this, pos); | 78 var fast_answer = %_FastCharCodeAt(this, pos); |
79 if (%_IsSmi(fast_answer)) { | 79 if (%_IsSmi(fast_answer)) { |
80 return fast_answer; | 80 return fast_answer; |
81 } | 81 } |
82 var subject = ToString(this); | 82 var subject = TO_STRING_INLINE(this); |
83 var index = TO_INTEGER(pos); | 83 var index = TO_INTEGER(pos); |
84 return %StringCharCodeAt(subject, index); | 84 return %StringCharCodeAt(subject, index); |
85 } | 85 } |
86 | 86 |
87 | 87 |
88 // ECMA-262, section 15.5.4.6 | 88 // ECMA-262, section 15.5.4.6 |
89 function StringConcat() { | 89 function StringConcat() { |
90 var len = %_ArgumentsLength(); | 90 var len = %_ArgumentsLength(); |
91 var this_as_string = IS_STRING(this) ? this : ToString(this); | 91 var this_as_string = TO_STRING_INLINE(this); |
92 if (len === 1) { | 92 if (len === 1) { |
93 return this_as_string + %_Arguments(0); | 93 return this_as_string + %_Arguments(0); |
94 } | 94 } |
95 var parts = new $Array(len + 1); | 95 var parts = new $Array(len + 1); |
96 parts[0] = this_as_string; | 96 parts[0] = this_as_string; |
97 for (var i = 0; i < len; i++) { | 97 for (var i = 0; i < len; i++) { |
98 var part = %_Arguments(i); | 98 var part = %_Arguments(i); |
99 parts[i + 1] = IS_STRING(part) ? part : ToString(part); | 99 parts[i + 1] = TO_STRING_INLINE(part); |
100 } | 100 } |
101 return %StringBuilderConcat(parts, len + 1, ""); | 101 return %StringBuilderConcat(parts, len + 1, ""); |
102 } | 102 } |
103 | 103 |
104 // Match ES3 and Safari | 104 // Match ES3 and Safari |
105 %FunctionSetLength(StringConcat, 1); | 105 %FunctionSetLength(StringConcat, 1); |
106 | 106 |
107 | 107 |
108 // ECMA-262 section 15.5.4.7 | 108 // ECMA-262 section 15.5.4.7 |
109 function StringIndexOf(searchString /* position */) { // length == 1 | 109 function StringIndexOf(searchString /* position */) { // length == 1 |
110 var subject_str = ToString(this); | 110 var subject_str = TO_STRING_INLINE(this); |
111 var pattern_str = ToString(searchString); | 111 var pattern_str = TO_STRING_INLINE(searchString); |
112 var subject_str_len = subject_str.length; | 112 var subject_str_len = subject_str.length; |
113 var pattern_str_len = pattern_str.length; | 113 var pattern_str_len = pattern_str.length; |
114 var index = 0; | 114 var index = 0; |
115 if (%_ArgumentsLength() > 1) { | 115 if (%_ArgumentsLength() > 1) { |
116 var arg1 = %_Arguments(1); // position | 116 var arg1 = %_Arguments(1); // position |
117 index = TO_INTEGER(arg1); | 117 index = TO_INTEGER(arg1); |
118 } | 118 } |
119 if (index < 0) index = 0; | 119 if (index < 0) index = 0; |
120 if (index > subject_str_len) index = subject_str_len; | 120 if (index > subject_str_len) index = subject_str_len; |
121 if (pattern_str_len + index > subject_str_len) return -1; | 121 if (pattern_str_len + index > subject_str_len) return -1; |
122 return %StringIndexOf(subject_str, pattern_str, index); | 122 return %StringIndexOf(subject_str, pattern_str, index); |
123 } | 123 } |
124 | 124 |
125 | 125 |
126 // ECMA-262 section 15.5.4.8 | 126 // ECMA-262 section 15.5.4.8 |
127 function StringLastIndexOf(searchString /* position */) { // length == 1 | 127 function StringLastIndexOf(searchString /* position */) { // length == 1 |
128 var sub = ToString(this); | 128 var sub = TO_STRING_INLINE(this); |
129 var subLength = sub.length; | 129 var subLength = sub.length; |
130 var pat = ToString(searchString); | 130 var pat = TO_STRING_INLINE(searchString); |
131 var patLength = pat.length; | 131 var patLength = pat.length; |
132 var index = subLength - patLength; | 132 var index = subLength - patLength; |
133 if (%_ArgumentsLength() > 1) { | 133 if (%_ArgumentsLength() > 1) { |
134 var position = ToNumber(%_Arguments(1)); | 134 var position = ToNumber(%_Arguments(1)); |
135 if (!$isNaN(position)) { | 135 if (!$isNaN(position)) { |
136 position = TO_INTEGER(position); | 136 position = TO_INTEGER(position); |
137 if (position < 0) { | 137 if (position < 0) { |
138 position = 0; | 138 position = 0; |
139 } | 139 } |
140 if (position + patLength < subLength) { | 140 if (position + patLength < subLength) { |
141 index = position | 141 index = position |
142 } | 142 } |
143 } | 143 } |
144 } | 144 } |
145 if (index < 0) { | 145 if (index < 0) { |
146 return -1; | 146 return -1; |
147 } | 147 } |
148 return %StringLastIndexOf(sub, pat, index); | 148 return %StringLastIndexOf(sub, pat, index); |
149 } | 149 } |
150 | 150 |
151 | 151 |
152 // ECMA-262 section 15.5.4.9 | 152 // ECMA-262 section 15.5.4.9 |
153 // | 153 // |
154 // This function is implementation specific. For now, we do not | 154 // This function is implementation specific. For now, we do not |
155 // do anything locale specific. | 155 // do anything locale specific. |
156 function StringLocaleCompare(other) { | 156 function StringLocaleCompare(other) { |
157 if (%_ArgumentsLength() === 0) return 0; | 157 if (%_ArgumentsLength() === 0) return 0; |
158 | 158 |
159 var this_str = ToString(this); | 159 var this_str = TO_STRING_INLINE(this); |
160 var other_str = ToString(other); | 160 var other_str = TO_STRING_INLINE(other); |
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 = ToString(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 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); | 171 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); |
172 // lastMatchInfo is defined in regexp-delay.js. | 172 // lastMatchInfo is defined in regexp-delay.js. |
173 return %StringMatch(subject, regexp, lastMatchInfo); | 173 return %StringMatch(subject, regexp, lastMatchInfo); |
174 } | 174 } |
175 | 175 |
176 | 176 |
177 // SubString is an internal function that returns the sub string of 'string'. | 177 // 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 | 178 // If resulting string is of length 1, we use the one character cache |
(...skipping 14 matching lines...) Expand all Loading... |
193 // This has the same size as the lastMatchInfo array, and can be used for | 193 // This has the same size as the lastMatchInfo array, and can be used for |
194 // functions that expect that structure to be returned. It is used when the | 194 // functions that expect that structure to be returned. It is used when the |
195 // needle is a string rather than a regexp. In this case we can't update | 195 // needle is a string rather than a regexp. In this case we can't update |
196 // lastMatchArray without erroneously affecting the properties on the global | 196 // lastMatchArray without erroneously affecting the properties on the global |
197 // RegExp object. | 197 // RegExp object. |
198 var reusableMatchInfo = [2, "", "", -1, -1]; | 198 var reusableMatchInfo = [2, "", "", -1, -1]; |
199 | 199 |
200 | 200 |
201 // ECMA-262, section 15.5.4.11 | 201 // ECMA-262, section 15.5.4.11 |
202 function StringReplace(search, replace) { | 202 function StringReplace(search, replace) { |
203 var subject = IS_STRING(this) ? this : ToString(this); | 203 var subject = TO_STRING_INLINE(this); |
204 | 204 |
205 // Delegate to one of the regular expression variants if necessary. | 205 // Delegate to one of the regular expression variants if necessary. |
206 if (IS_REGEXP(search)) { | 206 if (IS_REGEXP(search)) { |
207 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]); | 207 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]); |
208 if (IS_FUNCTION(replace)) { | 208 if (IS_FUNCTION(replace)) { |
209 return StringReplaceRegExpWithFunction(subject, search, replace); | 209 return StringReplaceRegExpWithFunction(subject, search, replace); |
210 } else { | 210 } else { |
211 return StringReplaceRegExp(subject, search, replace); | 211 return StringReplaceRegExp(subject, search, replace); |
212 } | 212 } |
213 } | 213 } |
214 | 214 |
215 // Convert the search argument to a string and search for it. | 215 // Convert the search argument to a string and search for it. |
216 search = IS_STRING(search) ? search : ToString(search); | 216 search = TO_STRING_INLINE(search); |
217 var start = %StringIndexOf(subject, search, 0); | 217 var start = %StringIndexOf(subject, search, 0); |
218 if (start < 0) return subject; | 218 if (start < 0) return subject; |
219 var end = start + search.length; | 219 var end = start + search.length; |
220 | 220 |
221 var builder = new ReplaceResultBuilder(subject); | 221 var builder = new ReplaceResultBuilder(subject); |
222 // prefix | 222 // prefix |
223 builder.addSpecialSlice(0, start); | 223 builder.addSpecialSlice(0, start); |
224 | 224 |
225 // Compute the string to replace with. | 225 // Compute the string to replace with. |
226 if (IS_FUNCTION(replace)) { | 226 if (IS_FUNCTION(replace)) { |
227 builder.add(replace.call(null, search, start, subject)); | 227 builder.add(replace.call(null, search, start, subject)); |
228 } else { | 228 } else { |
229 reusableMatchInfo[CAPTURE0] = start; | 229 reusableMatchInfo[CAPTURE0] = start; |
230 reusableMatchInfo[CAPTURE1] = end; | 230 reusableMatchInfo[CAPTURE1] = end; |
231 if (!IS_STRING(replace)) replace = ToString(replace); | 231 replace = TO_STRING_INLINE(replace); |
232 ExpandReplacement(replace, subject, reusableMatchInfo, builder); | 232 ExpandReplacement(replace, subject, reusableMatchInfo, builder); |
233 } | 233 } |
234 | 234 |
235 // suffix | 235 // suffix |
236 builder.addSpecialSlice(end, subject.length); | 236 builder.addSpecialSlice(end, subject.length); |
237 | 237 |
238 return builder.generate(); | 238 return builder.generate(); |
239 } | 239 } |
240 | 240 |
241 | 241 |
242 // Helper function for regular expressions in String.prototype.replace. | 242 // Helper function for regular expressions in String.prototype.replace. |
243 function StringReplaceRegExp(subject, regexp, replace) { | 243 function StringReplaceRegExp(subject, regexp, replace) { |
244 replace = ToString(replace); | 244 replace = TO_STRING_INLINE(replace); |
245 return %StringReplaceRegExpWithString(subject, | 245 return %StringReplaceRegExpWithString(subject, |
246 regexp, | 246 regexp, |
247 replace, | 247 replace, |
248 lastMatchInfo); | 248 lastMatchInfo); |
249 }; | 249 }; |
250 | 250 |
251 | 251 |
252 // Expand the $-expressions in the string and return a new string with | 252 // Expand the $-expressions in the string and return a new string with |
253 // the result. | 253 // the result. |
254 function ExpandReplacement(string, subject, matchInfo, builder) { | 254 function ExpandReplacement(string, subject, matchInfo, builder) { |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 } | 455 } |
456 parameters[j] = index; | 456 parameters[j] = index; |
457 parameters[j + 1] = subject; | 457 parameters[j + 1] = subject; |
458 return replace.apply(null, parameters); | 458 return replace.apply(null, parameters); |
459 } | 459 } |
460 | 460 |
461 | 461 |
462 // ECMA-262 section 15.5.4.12 | 462 // ECMA-262 section 15.5.4.12 |
463 function StringSearch(re) { | 463 function StringSearch(re) { |
464 var regexp = new ORIGINAL_REGEXP(re); | 464 var regexp = new ORIGINAL_REGEXP(re); |
465 var s = ToString(this); | 465 var s = TO_STRING_INLINE(this); |
466 var last_idx = regexp.lastIndex; // keep old lastIndex | 466 var last_idx = regexp.lastIndex; // keep old lastIndex |
467 regexp.lastIndex = 0; // ignore re.global property | 467 regexp.lastIndex = 0; // ignore re.global property |
468 var result = regexp.exec(s); | 468 var result = regexp.exec(s); |
469 regexp.lastIndex = last_idx; // restore lastIndex | 469 regexp.lastIndex = last_idx; // restore lastIndex |
470 if (result == null) | 470 if (result == null) |
471 return -1; | 471 return -1; |
472 else | 472 else |
473 return result.index; | 473 return result.index; |
474 } | 474 } |
475 | 475 |
476 | 476 |
477 // ECMA-262 section 15.5.4.13 | 477 // ECMA-262 section 15.5.4.13 |
478 function StringSlice(start, end) { | 478 function StringSlice(start, end) { |
479 var s = ToString(this); | 479 var s = TO_STRING_INLINE(this); |
480 var s_len = s.length; | 480 var s_len = s.length; |
481 var start_i = TO_INTEGER(start); | 481 var start_i = TO_INTEGER(start); |
482 var end_i = s_len; | 482 var end_i = s_len; |
483 if (end !== void 0) | 483 if (end !== void 0) |
484 end_i = TO_INTEGER(end); | 484 end_i = TO_INTEGER(end); |
485 | 485 |
486 if (start_i < 0) { | 486 if (start_i < 0) { |
487 start_i += s_len; | 487 start_i += s_len; |
488 if (start_i < 0) | 488 if (start_i < 0) |
489 start_i = 0; | 489 start_i = 0; |
(...skipping 14 matching lines...) Expand all Loading... |
504 var num_c = end_i - start_i; | 504 var num_c = end_i - start_i; |
505 if (num_c < 0) | 505 if (num_c < 0) |
506 num_c = 0; | 506 num_c = 0; |
507 | 507 |
508 return SubString(s, start_i, start_i + num_c); | 508 return SubString(s, start_i, start_i + num_c); |
509 } | 509 } |
510 | 510 |
511 | 511 |
512 // ECMA-262 section 15.5.4.14 | 512 // ECMA-262 section 15.5.4.14 |
513 function StringSplit(separator, limit) { | 513 function StringSplit(separator, limit) { |
514 var subject = ToString(this); | 514 var subject = TO_STRING_INLINE(this); |
515 limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit); | 515 limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit); |
516 if (limit === 0) return []; | 516 if (limit === 0) return []; |
517 | 517 |
518 // ECMA-262 says that if separator is undefined, the result should | 518 // ECMA-262 says that if separator is undefined, the result should |
519 // be an array of size 1 containing the entire string. SpiderMonkey | 519 // be an array of size 1 containing the entire string. SpiderMonkey |
520 // and KJS have this behaviour only when no separator is given. If | 520 // and KJS have this behaviour only when no separator is given. If |
521 // undefined is explicitly given, they convert it to a string and | 521 // undefined is explicitly given, they convert it to a string and |
522 // use that. We do as SpiderMonkey and KJS. | 522 // use that. We do as SpiderMonkey and KJS. |
523 if (%_ArgumentsLength() === 0) { | 523 if (%_ArgumentsLength() === 0) { |
524 return [subject]; | 524 return [subject]; |
525 } | 525 } |
526 | 526 |
527 var length = subject.length; | 527 var length = subject.length; |
528 if (IS_REGEXP(separator)) { | 528 if (!IS_REGEXP(separator)) { |
529 %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]); | 529 separator = TO_STRING_INLINE(separator); |
530 } else { | 530 var separator_length = separator.length; |
531 separator = ToString(separator); | 531 |
532 // If the separator string is empty then return the elements in the subject. | 532 // If the separator string is empty then return the elements in the subject. |
533 if (separator.length == 0) { | 533 if (separator_length === 0) { |
534 var result = $Array(length); | 534 var result = $Array(length); |
535 for (var i = 0; i < length; i++) result[i] = subject[i]; | 535 for (var i = 0; i < length; i++) result[i] = subject[i]; |
536 return result; | 536 return result; |
537 } | 537 } |
| 538 |
| 539 var result = []; |
| 540 var start_index = 0; |
| 541 var index; |
| 542 while (true) { |
| 543 if (start_index + separator_length > length || |
| 544 (index = %StringIndexOf(subject, separator, start_index)) === -1) { |
| 545 result.push(SubString(subject, start_index, length)); |
| 546 break; |
| 547 } |
| 548 if (result.push(SubString(subject, start_index, index)) === limit) break; |
| 549 start_index = index + separator_length; |
| 550 } |
| 551 |
| 552 return result; |
538 } | 553 } |
539 | 554 |
| 555 %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]); |
| 556 |
540 if (length === 0) { | 557 if (length === 0) { |
541 if (splitMatch(separator, subject, 0, 0) != null) return []; | 558 if (splitMatch(separator, subject, 0, 0) != null) return []; |
542 return [subject]; | 559 return [subject]; |
543 } | 560 } |
544 | 561 |
545 var currentIndex = 0; | 562 var currentIndex = 0; |
546 var startIndex = 0; | 563 var startIndex = 0; |
547 var result = []; | 564 var result = []; |
548 | 565 |
549 while (true) { | 566 while (true) { |
(...skipping 14 matching lines...) Expand all Loading... |
564 | 581 |
565 // We ignore a zero-length match at the currentIndex. | 582 // We ignore a zero-length match at the currentIndex. |
566 if (startIndex === endIndex && endIndex === currentIndex) { | 583 if (startIndex === endIndex && endIndex === currentIndex) { |
567 startIndex++; | 584 startIndex++; |
568 continue; | 585 continue; |
569 } | 586 } |
570 | 587 |
571 result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]
); | 588 result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]
); |
572 if (result.length === limit) return result; | 589 if (result.length === limit) return result; |
573 | 590 |
574 for (var i = 2; i < NUMBER_OF_CAPTURES(matchInfo); i += 2) { | 591 var num_captures = NUMBER_OF_CAPTURES(matchInfo); |
| 592 for (var i = 2; i < num_captures; i += 2) { |
575 var start = matchInfo[CAPTURE(i)]; | 593 var start = matchInfo[CAPTURE(i)]; |
576 var end = matchInfo[CAPTURE(i + 1)]; | 594 var end = matchInfo[CAPTURE(i + 1)]; |
577 if (start != -1 && end != -1) { | 595 if (start != -1 && end != -1) { |
578 result[result.length] = SubString(subject, start, end); | 596 result[result.length] = SubString(subject, start, end); |
579 } else { | 597 } else { |
580 result[result.length] = void 0; | 598 result[result.length] = void 0; |
581 } | 599 } |
582 if (result.length === limit) return result; | 600 if (result.length === limit) return result; |
583 } | 601 } |
584 | 602 |
585 startIndex = currentIndex = endIndex; | 603 startIndex = currentIndex = endIndex; |
586 } | 604 } |
587 } | 605 } |
588 | 606 |
589 | 607 |
590 // ECMA-262 section 15.5.4.14 | 608 // ECMA-262 section 15.5.4.14 |
591 // Helper function used by split. This version returns the matchInfo | 609 // Helper function used by split. This version returns the matchInfo |
592 // instead of allocating a new array with basically the same information. | 610 // instead of allocating a new array with basically the same information. |
593 function splitMatch(separator, subject, current_index, start_index) { | 611 function splitMatch(separator, subject, current_index, start_index) { |
594 if (IS_REGEXP(separator)) { | 612 var matchInfo = DoRegExpExec(separator, subject, start_index); |
595 var matchInfo = DoRegExpExec(separator, subject, start_index); | 613 if (matchInfo == null) return null; |
596 if (matchInfo == null) return null; | 614 // Section 15.5.4.14 paragraph two says that we do not allow zero length |
597 // Section 15.5.4.14 paragraph two says that we do not allow zero length | 615 // matches at the end of the string. |
598 // matches at the end of the string. | 616 if (matchInfo[CAPTURE0] === subject.length) return null; |
599 if (matchInfo[CAPTURE0] === subject.length) return null; | 617 return matchInfo; |
600 return matchInfo; | 618 } |
601 } | |
602 | |
603 var separatorIndex = subject.indexOf(separator, start_index); | |
604 if (separatorIndex === -1) return null; | |
605 | |
606 reusableMatchInfo[CAPTURE0] = separatorIndex; | |
607 reusableMatchInfo[CAPTURE1] = separatorIndex + separator.length; | |
608 return reusableMatchInfo; | |
609 }; | |
610 | 619 |
611 | 620 |
612 // ECMA-262 section 15.5.4.15 | 621 // ECMA-262 section 15.5.4.15 |
613 function StringSubstring(start, end) { | 622 function StringSubstring(start, end) { |
614 var s = this; | 623 var s = TO_STRING_INLINE(this); |
615 if (!IS_STRING(s)) s = ToString(s); | |
616 var s_len = s.length; | 624 var s_len = s.length; |
617 | 625 |
618 var start_i = TO_INTEGER(start); | 626 var start_i = TO_INTEGER(start); |
619 if (start_i < 0) { | 627 if (start_i < 0) { |
620 start_i = 0; | 628 start_i = 0; |
621 } else if (start_i > s_len) { | 629 } else if (start_i > s_len) { |
622 start_i = s_len; | 630 start_i = s_len; |
623 } | 631 } |
624 | 632 |
625 var end_i = s_len; | 633 var end_i = s_len; |
(...skipping 10 matching lines...) Expand all Loading... |
636 } | 644 } |
637 } | 645 } |
638 } | 646 } |
639 | 647 |
640 return SubString(s, start_i, end_i); | 648 return SubString(s, start_i, end_i); |
641 } | 649 } |
642 | 650 |
643 | 651 |
644 // This is not a part of ECMA-262. | 652 // This is not a part of ECMA-262. |
645 function StringSubstr(start, n) { | 653 function StringSubstr(start, n) { |
646 var s = ToString(this); | 654 var s = TO_STRING_INLINE(this); |
647 var len; | 655 var len; |
648 | 656 |
649 // Correct n: If not given, set to string length; if explicitly | 657 // Correct n: If not given, set to string length; if explicitly |
650 // set to undefined, zero, or negative, returns empty string. | 658 // set to undefined, zero, or negative, returns empty string. |
651 if (n === void 0) { | 659 if (n === void 0) { |
652 len = s.length; | 660 len = s.length; |
653 } else { | 661 } else { |
654 len = TO_INTEGER(n); | 662 len = TO_INTEGER(n); |
655 if (len <= 0) return ''; | 663 if (len <= 0) return ''; |
656 } | 664 } |
(...skipping 17 matching lines...) Expand all Loading... |
674 | 682 |
675 var end = start + len; | 683 var end = start + len; |
676 if (end > s.length) end = s.length; | 684 if (end > s.length) end = s.length; |
677 | 685 |
678 return SubString(s, start, end); | 686 return SubString(s, start, end); |
679 } | 687 } |
680 | 688 |
681 | 689 |
682 // ECMA-262, 15.5.4.16 | 690 // ECMA-262, 15.5.4.16 |
683 function StringToLowerCase() { | 691 function StringToLowerCase() { |
684 return %StringToLowerCase(ToString(this)); | 692 return %StringToLowerCase(TO_STRING_INLINE(this)); |
685 } | 693 } |
686 | 694 |
687 | 695 |
688 // ECMA-262, 15.5.4.17 | 696 // ECMA-262, 15.5.4.17 |
689 function StringToLocaleLowerCase() { | 697 function StringToLocaleLowerCase() { |
690 return %StringToLowerCase(ToString(this)); | 698 return %StringToLowerCase(TO_STRING_INLINE(this)); |
691 } | 699 } |
692 | 700 |
693 | 701 |
694 // ECMA-262, 15.5.4.18 | 702 // ECMA-262, 15.5.4.18 |
695 function StringToUpperCase() { | 703 function StringToUpperCase() { |
696 return %StringToUpperCase(ToString(this)); | 704 return %StringToUpperCase(TO_STRING_INLINE(this)); |
697 } | 705 } |
698 | 706 |
699 | 707 |
700 // ECMA-262, 15.5.4.19 | 708 // ECMA-262, 15.5.4.19 |
701 function StringToLocaleUpperCase() { | 709 function StringToLocaleUpperCase() { |
702 return %StringToUpperCase(ToString(this)); | 710 return %StringToUpperCase(TO_STRING_INLINE(this)); |
703 } | 711 } |
704 | 712 |
705 // ES5, 15.5.4.20 | 713 // ES5, 15.5.4.20 |
706 function StringTrim() { | 714 function StringTrim() { |
707 return %StringTrim(ToString(this), true, true); | 715 return %StringTrim(TO_STRING_INLINE(this), true, true); |
708 } | 716 } |
709 | 717 |
710 function StringTrimLeft() { | 718 function StringTrimLeft() { |
711 return %StringTrim(ToString(this), true, false); | 719 return %StringTrim(TO_STRING_INLINE(this), true, false); |
712 } | 720 } |
713 | 721 |
714 function StringTrimRight() { | 722 function StringTrimRight() { |
715 return %StringTrim(ToString(this), false, true); | 723 return %StringTrim(TO_STRING_INLINE(this), false, true); |
716 } | 724 } |
717 | 725 |
718 // ECMA-262, section 15.5.3.2 | 726 // ECMA-262, section 15.5.3.2 |
719 function StringFromCharCode(code) { | 727 function StringFromCharCode(code) { |
720 var n = %_ArgumentsLength(); | 728 var n = %_ArgumentsLength(); |
721 if (n == 1) return %CharFromCode(ToNumber(code) & 0xffff) | 729 if (n == 1) return %CharFromCode(ToNumber(code) & 0xffff) |
722 | 730 |
723 // NOTE: This is not super-efficient, but it is necessary because we | 731 // NOTE: This is not super-efficient, but it is necessary because we |
724 // want to avoid converting to numbers from within the virtual | 732 // want to avoid converting to numbers from within the virtual |
725 // machine. Maybe we can find another way of doing this? | 733 // machine. Maybe we can find another way of doing this? |
726 var codes = new $Array(n); | 734 var codes = new $Array(n); |
727 for (var i = 0; i < n; i++) codes[i] = ToNumber(%_Arguments(i)); | 735 for (var i = 0; i < n; i++) codes[i] = ToNumber(%_Arguments(i)); |
728 return %StringFromCharCodeArray(codes); | 736 return %StringFromCharCodeArray(codes); |
729 } | 737 } |
730 | 738 |
731 | 739 |
732 // Helper function for very basic XSS protection. | 740 // Helper function for very basic XSS protection. |
733 function HtmlEscape(str) { | 741 function HtmlEscape(str) { |
734 return ToString(str).replace(/</g, "<") | 742 return TO_STRING_INLINE(str).replace(/</g, "<") |
735 .replace(/>/g, ">") | 743 .replace(/>/g, ">") |
736 .replace(/"/g, """) | 744 .replace(/"/g, """) |
737 .replace(/'/g, "'"); | 745 .replace(/'/g, "'"); |
738 }; | 746 }; |
739 | 747 |
740 | 748 |
741 // Compatibility support for KJS. | 749 // Compatibility support for KJS. |
742 // Tested by mozilla/js/tests/js1_5/Regress/regress-276103.js. | 750 // Tested by mozilla/js/tests/js1_5/Regress/regress-276103.js. |
743 function StringLink(s) { | 751 function StringLink(s) { |
744 return "<a href=\"" + HtmlEscape(s) + "\">" + this + "</a>"; | 752 return "<a href=\"" + HtmlEscape(s) + "\">" + this + "</a>"; |
745 } | 753 } |
746 | 754 |
747 | 755 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
806 | 814 |
807 | 815 |
808 // ReplaceResultBuilder support. | 816 // ReplaceResultBuilder support. |
809 function ReplaceResultBuilder(str) { | 817 function ReplaceResultBuilder(str) { |
810 this.elements = new $Array(); | 818 this.elements = new $Array(); |
811 this.special_string = str; | 819 this.special_string = str; |
812 } | 820 } |
813 | 821 |
814 | 822 |
815 ReplaceResultBuilder.prototype.add = function(str) { | 823 ReplaceResultBuilder.prototype.add = function(str) { |
816 if (!IS_STRING(str)) str = ToString(str); | 824 str = TO_STRING_INLINE(str); |
817 if (str.length > 0) { | 825 if (str.length > 0) { |
818 var elements = this.elements; | 826 var elements = this.elements; |
819 elements[elements.length] = str; | 827 elements[elements.length] = str; |
820 } | 828 } |
821 } | 829 } |
822 | 830 |
823 | 831 |
824 ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) { | 832 ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) { |
825 var len = end - start; | 833 var len = end - start; |
826 if (len == 0) return; | 834 if (len == 0) return; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
896 "small", StringSmall, | 904 "small", StringSmall, |
897 "strike", StringStrike, | 905 "strike", StringStrike, |
898 "sub", StringSub, | 906 "sub", StringSub, |
899 "sup", StringSup, | 907 "sup", StringSup, |
900 "toJSON", StringToJSON | 908 "toJSON", StringToJSON |
901 )); | 909 )); |
902 } | 910 } |
903 | 911 |
904 | 912 |
905 SetupString(); | 913 SetupString(); |
OLD | NEW |