| 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 |