| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 26 matching lines...) Expand all Loading... |
| 37 var value = %_ArgumentsLength() == 0 ? '' : ToString(x); | 37 var value = %_ArgumentsLength() == 0 ? '' : ToString(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 %AddProperty($String.prototype, "constructor", $String, DONT_ENUM); | 47 // ECMA-262 section 15.5.4.2 |
| 48 function StringToString() { |
| 49 if (!IS_STRING(this) && %ClassOf(this) !== 'String') |
| 50 throw new $TypeError('String.prototype.toString is not generic'); |
| 51 return %_ValueOf(this); |
| 52 } |
| 48 | 53 |
| 49 %AddProperty($String.prototype, "valueOf", function valueOf() { | 54 |
| 55 // ECMA-262 section 15.5.4.3 |
| 56 function StringValueOf() { |
| 50 if (!IS_STRING(this) && %ClassOf(this) !== 'String') | 57 if (!IS_STRING(this) && %ClassOf(this) !== 'String') |
| 51 throw new $TypeError('String.prototype.valueOf is not generic'); | 58 throw new $TypeError('String.prototype.valueOf is not generic'); |
| 52 return %_ValueOf(this); | 59 return %_ValueOf(this); |
| 53 }, DONT_ENUM); | 60 } |
| 54 | 61 |
| 55 %AddProperty($String.prototype, "toString", function toString() { | 62 |
| 56 if (!IS_STRING(this) && %ClassOf(this) !== 'String') | 63 // ECMA-262, section 15.5.4.4 |
| 57 throw new $TypeError('String.prototype.toString is not generic'); | 64 function StringCharAt(pos) { |
| 58 return %_ValueOf(this); | 65 var subject = ToString(this); |
| 59 }, DONT_ENUM); | 66 var index = TO_INTEGER(pos); |
| 67 if (index >= subject.length || index < 0) return ""; |
| 68 return %CharFromCode(%StringCharCodeAt(subject, index)); |
| 69 } |
| 70 |
| 60 | 71 |
| 61 // ECMA-262 section 15.5.4.5 | 72 // ECMA-262 section 15.5.4.5 |
| 62 %AddProperty($String.prototype, "charCodeAt", function charCodeAt(pos) { | 73 function StringCharCodeAt(pos) { |
| 63 var fast_answer = %_FastCharCodeAt(this, pos); | 74 var fast_answer = %_FastCharCodeAt(this, pos); |
| 64 if (%_IsSmi(fast_answer)) { | 75 if (%_IsSmi(fast_answer)) { |
| 65 return fast_answer; | 76 return fast_answer; |
| 66 } | 77 } |
| 67 var subject = ToString(this); | 78 var subject = ToString(this); |
| 68 var index = TO_INTEGER(pos); | 79 var index = TO_INTEGER(pos); |
| 69 return %StringCharCodeAt(subject, index); | 80 return %StringCharCodeAt(subject, index); |
| 70 }, DONT_ENUM); | 81 } |
| 71 | 82 |
| 72 | 83 |
| 73 // ECMA-262, section 15.5.4.6 | 84 // ECMA-262, section 15.5.4.6 |
| 74 %AddProperty($String.prototype, "concat", function concat() { | 85 function StringConcat() { |
| 75 var len = %_ArgumentsLength(); | 86 var len = %_ArgumentsLength(); |
| 76 var parts = new $Array(len + 1); | 87 var parts = new $Array(len + 1); |
| 77 parts[0] = ToString(this); | 88 parts[0] = ToString(this); |
| 78 for (var i = 0; i < len; i++) | 89 for (var i = 0; i < len; i++) |
| 79 parts[i + 1] = ToString(%_Arguments(i)); | 90 parts[i + 1] = ToString(%_Arguments(i)); |
| 80 return parts.join(''); | 91 return parts.join(''); |
| 81 }, DONT_ENUM); | 92 } |
| 82 | 93 |
| 83 // Match ES3 and Safari | 94 // Match ES3 and Safari |
| 84 %FunctionSetLength($String.prototype.concat, 1); | 95 %FunctionSetLength(StringConcat, 1); |
| 96 |
| 97 |
| 98 // ECMA-262 section 15.5.4.7 |
| 99 function StringIndexOf(searchString /* position */) { // length == 1 |
| 100 var subject_str = ToString(this); |
| 101 var pattern_str = ToString(searchString); |
| 102 var subject_str_len = subject_str.length; |
| 103 var pattern_str_len = pattern_str.length; |
| 104 var index = 0; |
| 105 if (%_ArgumentsLength() > 1) { |
| 106 var arg1 = %_Arguments(1); // position |
| 107 index = TO_INTEGER(arg1); |
| 108 } |
| 109 if (index < 0) index = 0; |
| 110 if (index > subject_str_len) index = subject_str_len; |
| 111 if (pattern_str_len + index > subject_str_len) return -1; |
| 112 return %StringIndexOf(subject_str, pattern_str, index); |
| 113 } |
| 114 |
| 115 |
| 116 // ECMA-262 section 15.5.4.8 |
| 117 function StringLastIndexOf(searchString /* position */) { // length == 1 |
| 118 var sub = ToString(this); |
| 119 var pat = ToString(searchString); |
| 120 var index = (%_ArgumentsLength() > 1) |
| 121 ? ToNumber(%_Arguments(1) /* position */) |
| 122 : $NaN; |
| 123 var firstIndex; |
| 124 if ($isNaN(index)) { |
| 125 firstIndex = sub.length - pat.length; |
| 126 } else { |
| 127 firstIndex = TO_INTEGER(index); |
| 128 if (firstIndex + pat.length > sub.length) { |
| 129 firstIndex = sub.length - pat.length; |
| 130 } |
| 131 } |
| 132 return %StringLastIndexOf(sub, pat, firstIndex); |
| 133 } |
| 134 |
| 135 |
| 136 // ECMA-262 section 15.5.4.9 |
| 137 // |
| 138 // This function is implementation specific. For now, we do not |
| 139 // do anything locale specific. |
| 140 function StringLocaleCompare(other) { |
| 141 if (%_ArgumentsLength() === 0) return 0; |
| 142 |
| 143 var this_str = ToString(this); |
| 144 var other_str = ToString(other); |
| 145 return %StringLocaleCompare(this_str, other_str); |
| 146 } |
| 147 |
| 148 |
| 149 // ECMA-262 section 15.5.4.10 |
| 150 function StringMatch(regexp) { |
| 151 if (!IS_REGEXP(regexp)) regexp = new ORIGINAL_REGEXP(regexp); |
| 152 var subject = ToString(this); |
| 153 |
| 154 if (!regexp.global) return regexp.exec(subject); |
| 155 var matches = DoRegExpExecGlobal(regexp, subject); |
| 156 |
| 157 // If the regexp did not match, return null. |
| 158 if (matches.length == 0) return null; |
| 159 |
| 160 // Build the result array. |
| 161 var result = new $Array(match_string); |
| 162 for (var i = 0; i < matches.length; ++i) { |
| 163 var match = matches[i]; |
| 164 var match_string = subject.slice(match[0], match[1]); |
| 165 result[i] = match_string; |
| 166 } |
| 167 |
| 168 return result; |
| 169 } |
| 85 | 170 |
| 86 | 171 |
| 87 // SubString is an internal function that returns the sub string of 'string'. | 172 // SubString is an internal function that returns the sub string of 'string'. |
| 88 // If resulting string is of length 1, we use the one character cache | 173 // If resulting string is of length 1, we use the one character cache |
| 89 // otherwise we call the runtime system. | 174 // otherwise we call the runtime system. |
| 90 function SubString(string, start, end) { | 175 function SubString(string, start, end) { |
| 91 // Use the one character string cache. | 176 // Use the one character string cache. |
| 92 if (start + 1 == end) return %CharFromCode(%StringCharCodeAt(string, start)); | 177 if (start + 1 == end) return %CharFromCode(%StringCharCodeAt(string, start)); |
| 93 return %StringSlice(string, start, end); | 178 return %StringSlice(string, start, end); |
| 94 } | 179 } |
| 95 | 180 |
| 96 | 181 |
| 97 // ECMA-262, section 15.5.4.11 | 182 // ECMA-262, section 15.5.4.11 |
| 98 %AddProperty($String.prototype, "replace", function replace(search, replace) { | 183 function StringReplace(search, replace) { |
| 99 var subject = ToString(this); | 184 var subject = ToString(this); |
| 100 | 185 |
| 101 // Delegate to one of the regular expression variants if necessary. | 186 // Delegate to one of the regular expression variants if necessary. |
| 102 if (IS_REGEXP(search)) { | 187 if (IS_REGEXP(search)) { |
| 103 if (IS_FUNCTION(replace)) { | 188 if (IS_FUNCTION(replace)) { |
| 104 return StringReplaceRegExpWithFunction(subject, search, replace); | 189 return StringReplaceRegExpWithFunction(subject, search, replace); |
| 105 } else { | 190 } else { |
| 106 return StringReplaceRegExp(subject, search, replace); | 191 return StringReplaceRegExp(subject, search, replace); |
| 107 } | 192 } |
| 108 } | 193 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 121 if (IS_FUNCTION(replace)) { | 206 if (IS_FUNCTION(replace)) { |
| 122 builder.add(replace.call(null, search, start, subject)); | 207 builder.add(replace.call(null, search, start, subject)); |
| 123 } else { | 208 } else { |
| 124 ExpandReplacement(ToString(replace), subject, [ start, end ], builder); | 209 ExpandReplacement(ToString(replace), subject, [ start, end ], builder); |
| 125 } | 210 } |
| 126 | 211 |
| 127 // suffix | 212 // suffix |
| 128 builder.add(SubString(subject, end, subject.length)); | 213 builder.add(SubString(subject, end, subject.length)); |
| 129 | 214 |
| 130 return builder.generate(); | 215 return builder.generate(); |
| 131 }, DONT_ENUM); | 216 } |
| 132 | 217 |
| 133 | 218 |
| 134 // Helper function for regular expressions in String.prototype.replace. | 219 // Helper function for regular expressions in String.prototype.replace. |
| 135 function StringReplaceRegExp(subject, regexp, replace) { | 220 function StringReplaceRegExp(subject, regexp, replace) { |
| 136 // Compute an array of matches; each match is really a list of | 221 // Compute an array of matches; each match is really a list of |
| 137 // captures - pairs of (start, end) indexes into the subject string. | 222 // captures - pairs of (start, end) indexes into the subject string. |
| 138 var matches; | 223 var matches; |
| 139 if (regexp.global) { | 224 if (regexp.global) { |
| 140 matches = DoRegExpExecGlobal(regexp, subject); | 225 matches = DoRegExpExecGlobal(regexp, subject); |
| 141 if (matches.length == 0) return subject; | 226 if (matches.length == 0) return subject; |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 var parameters = $Array(m + 2); | 410 var parameters = $Array(m + 2); |
| 326 for (var j = 0; j < m; j++) { | 411 for (var j = 0; j < m; j++) { |
| 327 parameters[j] = CaptureString(subject, captures, j); | 412 parameters[j] = CaptureString(subject, captures, j); |
| 328 } | 413 } |
| 329 parameters[j] = index; | 414 parameters[j] = index; |
| 330 parameters[j + 1] = subject; | 415 parameters[j + 1] = subject; |
| 331 return ToString(replace.apply(null, parameters)); | 416 return ToString(replace.apply(null, parameters)); |
| 332 } | 417 } |
| 333 | 418 |
| 334 | 419 |
| 335 // ECMA-262 section 15.5.4.7 | |
| 336 %AddProperty($String.prototype, "indexOf", function indexOf(searchString /* posi
tion */) { // length == 1 | |
| 337 var subject_str = ToString(this); | |
| 338 var pattern_str = ToString(searchString); | |
| 339 var subject_str_len = subject_str.length; | |
| 340 var pattern_str_len = pattern_str.length; | |
| 341 var index = 0; | |
| 342 if (%_ArgumentsLength() > 1) { | |
| 343 var arg1 = %_Arguments(1); // position | |
| 344 index = TO_INTEGER(arg1); | |
| 345 } | |
| 346 if (index < 0) index = 0; | |
| 347 if (index > subject_str_len) index = subject_str_len; | |
| 348 if (pattern_str_len + index > subject_str_len) return -1; | |
| 349 return %StringIndexOf(subject_str, pattern_str, index); | |
| 350 }, DONT_ENUM); | |
| 351 | |
| 352 | |
| 353 // ECMA-262 section 15.5.4.8 | |
| 354 %AddProperty($String.prototype, "lastIndexOf", function lastIndexOf(searchString
/* position */) { // length == 1 | |
| 355 var sub = ToString(this); | |
| 356 var pat = ToString(searchString); | |
| 357 var index = (%_ArgumentsLength() > 1) | |
| 358 ? ToNumber(%_Arguments(1) /* position */) | |
| 359 : $NaN; | |
| 360 var firstIndex; | |
| 361 if ($isNaN(index)) { | |
| 362 firstIndex = sub.length - pat.length; | |
| 363 } else { | |
| 364 firstIndex = TO_INTEGER(index); | |
| 365 if (firstIndex + pat.length > sub.length) { | |
| 366 firstIndex = sub.length - pat.length; | |
| 367 } | |
| 368 } | |
| 369 return %StringLastIndexOf(sub, pat, firstIndex); | |
| 370 }, DONT_ENUM); | |
| 371 | |
| 372 | |
| 373 // ECMA-262 section 15.5.4.9 | |
| 374 // | |
| 375 // This function is implementation specific. For now, we do not | |
| 376 // do anything locale specific. | |
| 377 %AddProperty($String.prototype, "localeCompare", function localeCompare(other) { | |
| 378 if (%_ArgumentsLength() === 0) return 0; | |
| 379 | |
| 380 var this_str = ToString(this); | |
| 381 var other_str = ToString(other); | |
| 382 return %StringLocaleCompare(this_str, other_str); | |
| 383 }, DONT_ENUM); | |
| 384 | |
| 385 | |
| 386 // ECMA-262 section 15.5.4.10 | |
| 387 %AddProperty($String.prototype, "match", function match(regexp) { | |
| 388 if (!IS_REGEXP(regexp)) regexp = new ORIGINAL_REGEXP(regexp); | |
| 389 var subject = ToString(this); | |
| 390 | |
| 391 if (!regexp.global) return regexp.exec(subject); | |
| 392 var matches = DoRegExpExecGlobal(regexp, subject); | |
| 393 | |
| 394 // If the regexp did not match, return null. | |
| 395 if (matches.length == 0) return null; | |
| 396 | |
| 397 // Build the result array. | |
| 398 var result = new $Array(match_string); | |
| 399 for (var i = 0; i < matches.length; ++i) { | |
| 400 var match = matches[i]; | |
| 401 var match_string = subject.slice(match[0], match[1]); | |
| 402 result[i] = match_string; | |
| 403 } | |
| 404 | |
| 405 return result; | |
| 406 }, DONT_ENUM); | |
| 407 | |
| 408 | |
| 409 // ECMA-262 section 15.5.4.12 | 420 // ECMA-262 section 15.5.4.12 |
| 410 %AddProperty($String.prototype, "search", function search(re) { | 421 function StringSearch(re) { |
| 411 var regexp = new ORIGINAL_REGEXP(re); | 422 var regexp = new ORIGINAL_REGEXP(re); |
| 412 var s = ToString(this); | 423 var s = ToString(this); |
| 413 var last_idx = regexp.lastIndex; // keep old lastIndex | 424 var last_idx = regexp.lastIndex; // keep old lastIndex |
| 414 regexp.lastIndex = 0; // ignore re.global property | 425 regexp.lastIndex = 0; // ignore re.global property |
| 415 var result = regexp.exec(s); | 426 var result = regexp.exec(s); |
| 416 regexp.lastIndex = last_idx; // restore lastIndex | 427 regexp.lastIndex = last_idx; // restore lastIndex |
| 417 if (result == null) | 428 if (result == null) |
| 418 return -1; | 429 return -1; |
| 419 else | 430 else |
| 420 return result.index; | 431 return result.index; |
| 421 }, DONT_ENUM); | 432 } |
| 422 | 433 |
| 423 | 434 |
| 424 // ECMA-262 section 15.5.4.13 | 435 // ECMA-262 section 15.5.4.13 |
| 425 %AddProperty($String.prototype, "slice", function slice(start, end) { | 436 function StringSlice(start, end) { |
| 426 var s = ToString(this); | 437 var s = ToString(this); |
| 427 var s_len = s.length; | 438 var s_len = s.length; |
| 428 var start_i = TO_INTEGER(start); | 439 var start_i = TO_INTEGER(start); |
| 429 var end_i = s_len; | 440 var end_i = s_len; |
| 430 if (end !== void 0) | 441 if (end !== void 0) |
| 431 end_i = TO_INTEGER(end); | 442 end_i = TO_INTEGER(end); |
| 432 | 443 |
| 433 if (start_i < 0) { | 444 if (start_i < 0) { |
| 434 start_i += s_len; | 445 start_i += s_len; |
| 435 if (start_i < 0) | 446 if (start_i < 0) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 446 } else { | 457 } else { |
| 447 if (end_i > s_len) | 458 if (end_i > s_len) |
| 448 end_i = s_len; | 459 end_i = s_len; |
| 449 } | 460 } |
| 450 | 461 |
| 451 var num_c = end_i - start_i; | 462 var num_c = end_i - start_i; |
| 452 if (num_c < 0) | 463 if (num_c < 0) |
| 453 num_c = 0; | 464 num_c = 0; |
| 454 | 465 |
| 455 return SubString(s, start_i, start_i + num_c); | 466 return SubString(s, start_i, start_i + num_c); |
| 456 }, DONT_ENUM); | 467 } |
| 457 | 468 |
| 458 | 469 |
| 459 // ECMA-262 section 15.5.4.14 | 470 // ECMA-262 section 15.5.4.14 |
| 460 %AddProperty($String.prototype, "split", function split(separator, limit) { | 471 function StringSplit(separator, limit) { |
| 461 var subject = ToString(this); | 472 var subject = ToString(this); |
| 462 var result = []; | 473 var result = []; |
| 463 var lim = (limit === void 0) ? 0xffffffff : ToUint32(limit); | 474 var lim = (limit === void 0) ? 0xffffffff : ToUint32(limit); |
| 464 | 475 |
| 465 if (lim === 0) return result; | 476 if (lim === 0) return result; |
| 466 | 477 |
| 467 // ECMA-262 says that if separator is undefined, the result should | 478 // ECMA-262 says that if separator is undefined, the result should |
| 468 // be an array of size 1 containing the entire string. SpiderMonkey | 479 // be an array of size 1 containing the entire string. SpiderMonkey |
| 469 // and KJS have this behaviour only when no separator is given. If | 480 // and KJS have this behaviour only when no separator is given. If |
| 470 // undefined is explicitly given, they convert it to a string and | 481 // undefined is explicitly given, they convert it to a string and |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 result[result.length] = match[1]; | 522 result[result.length] = match[1]; |
| 512 if (result.length === lim) return result; | 523 if (result.length === lim) return result; |
| 513 | 524 |
| 514 for (var i = 2; i < match.length; i++) { | 525 for (var i = 2; i < match.length; i++) { |
| 515 result[result.length] = match[i]; | 526 result[result.length] = match[i]; |
| 516 if (result.length === lim) return result; | 527 if (result.length === lim) return result; |
| 517 } | 528 } |
| 518 | 529 |
| 519 startIndex = currentIndex = endIndex; | 530 startIndex = currentIndex = endIndex; |
| 520 } | 531 } |
| 521 }, DONT_ENUM); | 532 } |
| 522 | 533 |
| 523 | 534 |
| 524 // ECMA-262 section 15.5.4.14 | 535 // ECMA-262 section 15.5.4.14 |
| 525 // Helper function used by split. | 536 // Helper function used by split. |
| 526 function splitMatch(separator, subject, current_index, start_index) { | 537 function splitMatch(separator, subject, current_index, start_index) { |
| 527 if (IS_REGEXP(separator)) { | 538 if (IS_REGEXP(separator)) { |
| 528 var ovector = DoRegExpExec(separator, subject, start_index); | 539 var ovector = DoRegExpExec(separator, subject, start_index); |
| 529 if (ovector == null) return null; | 540 if (ovector == null) return null; |
| 530 var nof_results = ovector.length >> 1; | 541 var nof_results = ovector.length >> 1; |
| 531 var result = new $Array(nof_results + 1); | 542 var result = new $Array(nof_results + 1); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 542 } | 553 } |
| 543 | 554 |
| 544 var separatorIndex = subject.indexOf(separator, start_index); | 555 var separatorIndex = subject.indexOf(separator, start_index); |
| 545 if (separatorIndex === -1) return null; | 556 if (separatorIndex === -1) return null; |
| 546 | 557 |
| 547 return [ separatorIndex + separator.length, subject.slice(current_index, separ
atorIndex) ]; | 558 return [ separatorIndex + separator.length, subject.slice(current_index, separ
atorIndex) ]; |
| 548 }; | 559 }; |
| 549 | 560 |
| 550 | 561 |
| 551 // ECMA-262 section 15.5.4.15 | 562 // ECMA-262 section 15.5.4.15 |
| 552 %AddProperty($String.prototype, "substring", function substring(start, end) { | 563 function StringSubstring(start, end) { |
| 553 var s = ToString(this); | 564 var s = ToString(this); |
| 554 var s_len = s.length; | 565 var s_len = s.length; |
| 555 var start_i = TO_INTEGER(start); | 566 var start_i = TO_INTEGER(start); |
| 556 var end_i = s_len; | 567 var end_i = s_len; |
| 557 if (!IS_UNDEFINED(end)) | 568 if (!IS_UNDEFINED(end)) |
| 558 end_i = TO_INTEGER(end); | 569 end_i = TO_INTEGER(end); |
| 559 | 570 |
| 560 if (start_i < 0) start_i = 0; | 571 if (start_i < 0) start_i = 0; |
| 561 if (start_i > s_len) start_i = s_len; | 572 if (start_i > s_len) start_i = s_len; |
| 562 if (end_i < 0) end_i = 0; | 573 if (end_i < 0) end_i = 0; |
| 563 if (end_i > s_len) end_i = s_len; | 574 if (end_i > s_len) end_i = s_len; |
| 564 | 575 |
| 565 if (start_i > end_i) { | 576 if (start_i > end_i) { |
| 566 var tmp = end_i; | 577 var tmp = end_i; |
| 567 end_i = start_i; | 578 end_i = start_i; |
| 568 start_i = tmp; | 579 start_i = tmp; |
| 569 } | 580 } |
| 570 | 581 |
| 571 return SubString(s, start_i, end_i); | 582 return SubString(s, start_i, end_i); |
| 572 }, DONT_ENUM); | 583 } |
| 573 | 584 |
| 574 | 585 |
| 575 // This is not a part of ECMA-262. | 586 // This is not a part of ECMA-262. |
| 576 %AddProperty($String.prototype, "substr", function substr(start, n) { | 587 function StringSubstr(start, n) { |
| 577 var s = ToString(this); | 588 var s = ToString(this); |
| 578 var len; | 589 var len; |
| 579 | 590 |
| 580 // Correct n: If not given, set to string length; if explicitly | 591 // Correct n: If not given, set to string length; if explicitly |
| 581 // set to undefined, zero, or negative, returns empty string. | 592 // set to undefined, zero, or negative, returns empty string. |
| 582 if (n === void 0) { | 593 if (n === void 0) { |
| 583 len = s.length; | 594 len = s.length; |
| 584 } else { | 595 } else { |
| 585 len = TO_INTEGER(n); | 596 len = TO_INTEGER(n); |
| 586 if (len <= 0) return ''; | 597 if (len <= 0) return ''; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 600 if (start < 0) { | 611 if (start < 0) { |
| 601 start += s.length; | 612 start += s.length; |
| 602 if (start < 0) start = 0; | 613 if (start < 0) start = 0; |
| 603 } | 614 } |
| 604 } | 615 } |
| 605 | 616 |
| 606 var end = start + len; | 617 var end = start + len; |
| 607 if (end > s.length) end = s.length; | 618 if (end > s.length) end = s.length; |
| 608 | 619 |
| 609 return SubString(s, start, end); | 620 return SubString(s, start, end); |
| 610 }, DONT_ENUM); | 621 } |
| 611 | 622 |
| 612 | 623 |
| 613 // ECMA-262, 15.5.4.16 | 624 // ECMA-262, 15.5.4.16 |
| 614 %AddProperty($String.prototype, "toLowerCase", function toLowerCase() { | 625 function StringToLowerCase() { |
| 615 return %StringToLowerCase(ToString(this)); | 626 return %StringToLowerCase(ToString(this)); |
| 616 }, DONT_ENUM); | 627 } |
| 617 | 628 |
| 618 | 629 |
| 619 // ECMA-262, 15.5.4.17 | 630 // ECMA-262, 15.5.4.17 |
| 620 %AddProperty($String.prototype, "toLocaleLowerCase", function toLocaleLowerCase(
) { | 631 function StringToLocaleLowerCase() { |
| 621 return %StringToLowerCase(ToString(this)); | 632 return %StringToLowerCase(ToString(this)); |
| 622 }, DONT_ENUM); | 633 } |
| 623 | 634 |
| 624 | 635 |
| 625 // ECMA-262, 15.5.4.18 | 636 // ECMA-262, 15.5.4.18 |
| 626 %AddProperty($String.prototype, "toUpperCase", function toUpperCase() { | 637 function StringToUpperCase() { |
| 627 return %StringToUpperCase(ToString(this)); | 638 return %StringToUpperCase(ToString(this)); |
| 628 }, DONT_ENUM); | 639 } |
| 629 | 640 |
| 630 | 641 |
| 631 // ECMA-262, 15.5.4.19 | 642 // ECMA-262, 15.5.4.19 |
| 632 %AddProperty($String.prototype, "toLocaleUpperCase", function toLocaleUpperCase(
) { | 643 function StringToLocaleUpperCase() { |
| 633 return %StringToUpperCase(ToString(this)); | 644 return %StringToUpperCase(ToString(this)); |
| 634 }, DONT_ENUM); | 645 } |
| 635 | 646 |
| 636 | 647 |
| 637 // ECMA-262, section 15.5.3.2 | 648 // ECMA-262, section 15.5.3.2 |
| 638 %AddProperty($String, "fromCharCode", function fromCharCode(code) { | 649 function StringFromCharCode(code) { |
| 639 var n = %_ArgumentsLength(); | 650 var n = %_ArgumentsLength(); |
| 640 if (n == 1) return %CharFromCode(ToNumber(code) & 0xffff) | 651 if (n == 1) return %CharFromCode(ToNumber(code) & 0xffff) |
| 641 | 652 |
| 642 // NOTE: This is not super-efficient, but it is necessary because we | 653 // NOTE: This is not super-efficient, but it is necessary because we |
| 643 // want to avoid converting to numbers from within the virtual | 654 // want to avoid converting to numbers from within the virtual |
| 644 // machine. Maybe we can find another way of doing this? | 655 // machine. Maybe we can find another way of doing this? |
| 645 var codes = new $Array(n); | 656 var codes = new $Array(n); |
| 646 for (var i = 0; i < n; i++) codes[i] = ToNumber(%_Arguments(i)); | 657 for (var i = 0; i < n; i++) codes[i] = ToNumber(%_Arguments(i)); |
| 647 return %StringFromCharCodeArray(codes); | 658 return %StringFromCharCodeArray(codes); |
| 648 }, DONT_ENUM); | 659 } |
| 649 | |
| 650 | |
| 651 // ECMA-262, section 15.5.4.4 | |
| 652 function charAt(pos) { | |
| 653 var subject = ToString(this); | |
| 654 var index = TO_INTEGER(pos); | |
| 655 if (index >= subject.length || index < 0) return ""; | |
| 656 return %CharFromCode(%StringCharCodeAt(subject, index)); | |
| 657 }; | |
| 658 | |
| 659 %AddProperty($String.prototype, "charAt", charAt, DONT_ENUM); | |
| 660 | 660 |
| 661 | 661 |
| 662 // Helper function for very basic XSS protection. | 662 // Helper function for very basic XSS protection. |
| 663 function HtmlEscape(str) { | 663 function HtmlEscape(str) { |
| 664 return ToString(str).replace(/</g, "<") | 664 return ToString(str).replace(/</g, "<") |
| 665 .replace(/>/g, ">") | 665 .replace(/>/g, ">") |
| 666 .replace(/"/g, """) | 666 .replace(/"/g, """) |
| 667 .replace(/'/g, "'"); | 667 .replace(/'/g, "'"); |
| 668 }; | 668 }; |
| 669 | 669 |
| 670 | 670 |
| 671 // Compatibility support for KJS. | 671 // Compatibility support for KJS. |
| 672 // Tested by mozilla/js/tests/js1_5/Regress/regress-276103.js. | 672 // Tested by mozilla/js/tests/js1_5/Regress/regress-276103.js. |
| 673 %AddProperty($String.prototype, "link", function link(s) { | 673 function StringLink(s) { |
| 674 return "<a href=\"" + HtmlEscape(s) + "\">" + this + "</a>"; | 674 return "<a href=\"" + HtmlEscape(s) + "\">" + this + "</a>"; |
| 675 }, DONT_ENUM); | 675 } |
| 676 | 676 |
| 677 | 677 |
| 678 %AddProperty($String.prototype, "anchor", function anchor(name) { | 678 function StringAnchor(name) { |
| 679 return "<a name=\"" + HtmlEscape(name) + "\">" + this + "</a>"; | 679 return "<a name=\"" + HtmlEscape(name) + "\">" + this + "</a>"; |
| 680 }, DONT_ENUM); | 680 } |
| 681 | 681 |
| 682 | 682 |
| 683 %AddProperty($String.prototype, "fontcolor", function fontcolor(color) { | 683 function StringFontcolor(color) { |
| 684 return "<font color=\"" + HtmlEscape(color) + "\">" + this + "</font>"; | 684 return "<font color=\"" + HtmlEscape(color) + "\">" + this + "</font>"; |
| 685 }, DONT_ENUM); | 685 } |
| 686 | 686 |
| 687 | 687 |
| 688 %AddProperty($String.prototype, "fontsize", function fontsize(size) { | 688 function StringFontsize(size) { |
| 689 return "<font size=\"" + HtmlEscape(size) + "\">" + this + "</font>"; | 689 return "<font size=\"" + HtmlEscape(size) + "\">" + this + "</font>"; |
| 690 }, DONT_ENUM); | 690 } |
| 691 | 691 |
| 692 | 692 |
| 693 %AddProperty($String.prototype, "big", function big() { | 693 function StringBig() { |
| 694 return "<big>" + this + "</big>"; | 694 return "<big>" + this + "</big>"; |
| 695 }, DONT_ENUM); | 695 } |
| 696 | 696 |
| 697 | 697 |
| 698 %AddProperty($String.prototype, "blink", function blink() { | 698 function StringBlink() { |
| 699 return "<blink>" + this + "</blink>"; | 699 return "<blink>" + this + "</blink>"; |
| 700 }, DONT_ENUM); | 700 } |
| 701 | 701 |
| 702 | 702 |
| 703 %AddProperty($String.prototype, "bold", function bold() { | 703 function StringBold() { |
| 704 return "<b>" + this + "</b>"; | 704 return "<b>" + this + "</b>"; |
| 705 }, DONT_ENUM); | 705 } |
| 706 | 706 |
| 707 | 707 |
| 708 %AddProperty($String.prototype, "fixed", function fixed() { | 708 function StringFixed() { |
| 709 return "<tt>" + this + "</tt>"; | 709 return "<tt>" + this + "</tt>"; |
| 710 }, DONT_ENUM); | 710 } |
| 711 | 711 |
| 712 | 712 |
| 713 %AddProperty($String.prototype, "italics", function italics() { | 713 function StringItalics() { |
| 714 return "<i>" + this + "</i>"; | 714 return "<i>" + this + "</i>"; |
| 715 }, DONT_ENUM); | 715 } |
| 716 | 716 |
| 717 | 717 |
| 718 %AddProperty($String.prototype, "small", function small() { | 718 function StringSmall() { |
| 719 return "<small>" + this + "</small>"; | 719 return "<small>" + this + "</small>"; |
| 720 }, DONT_ENUM); | 720 } |
| 721 | 721 |
| 722 | 722 |
| 723 %AddProperty($String.prototype, "strike", function strike() { | 723 function StringStrike() { |
| 724 return "<strike>" + this + "</strike>"; | 724 return "<strike>" + this + "</strike>"; |
| 725 }, DONT_ENUM); | 725 } |
| 726 | 726 |
| 727 | 727 |
| 728 %AddProperty($String.prototype, "sub", function sub() { | 728 function StringSub() { |
| 729 return "<sub>" + this + "</sub>"; | 729 return "<sub>" + this + "</sub>"; |
| 730 }, DONT_ENUM); | 730 } |
| 731 | 731 |
| 732 | 732 |
| 733 %AddProperty($String.prototype, "sup", function sup() { | 733 function StringSup() { |
| 734 return "<sup>" + this + "</sup>"; | 734 return "<sup>" + this + "</sup>"; |
| 735 }, DONT_ENUM); | 735 } |
| 736 | 736 |
| 737 | 737 |
| 738 // StringBuilder support. | 738 // StringBuilder support. |
| 739 | 739 |
| 740 function StringBuilder() { | 740 function StringBuilder() { |
| 741 this.elements = new $Array(); | 741 this.elements = new $Array(); |
| 742 } | 742 } |
| 743 | 743 |
| 744 | 744 |
| 745 function ReplaceResultBuilder(str) { | 745 function ReplaceResultBuilder(str) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 771 | 771 |
| 772 | 772 |
| 773 StringBuilder.prototype.generate = function() { | 773 StringBuilder.prototype.generate = function() { |
| 774 return %StringBuilderConcat(this.elements, ""); | 774 return %StringBuilderConcat(this.elements, ""); |
| 775 } | 775 } |
| 776 | 776 |
| 777 | 777 |
| 778 ReplaceResultBuilder.prototype.generate = function() { | 778 ReplaceResultBuilder.prototype.generate = function() { |
| 779 return %StringBuilderConcat(this.elements, this.special_string); | 779 return %StringBuilderConcat(this.elements, this.special_string); |
| 780 } | 780 } |
| 781 |
| 782 |
| 783 // ------------------------------------------------------------------- |
| 784 |
| 785 function SetupString() { |
| 786 // Setup the constructor property on the String prototype object. |
| 787 %AddProperty($String.prototype, "constructor", $String, DONT_ENUM); |
| 788 |
| 789 |
| 790 // Setup the non-enumerable functions on the String object. |
| 791 InstallFunctions($String, DONT_ENUM, $Array( |
| 792 "fromCharCode", StringFromCharCode |
| 793 )); |
| 794 |
| 795 |
| 796 // Setup the non-enumerable functions on the String prototype object. |
| 797 InstallFunctions($String.prototype, DONT_ENUM, $Array( |
| 798 "valueOf", StringValueOf, |
| 799 "toString", StringToString, |
| 800 "charAt", StringCharAt, |
| 801 "charCodeAt", StringCharCodeAt, |
| 802 "concat", StringConcat, |
| 803 "indexOf", StringIndexOf, |
| 804 "lastIndexOf", StringLastIndexOf, |
| 805 "localeCompare", StringLocaleCompare, |
| 806 "match", StringMatch, |
| 807 "replace", StringReplace, |
| 808 "search", StringSearch, |
| 809 "slice", StringSlice, |
| 810 "split", StringSplit, |
| 811 "substring", StringSubstring, |
| 812 "substr", StringSubstr, |
| 813 "toLowerCase", StringToLowerCase, |
| 814 "toLocaleLowerCase", StringToLocaleLowerCase, |
| 815 "toUpperCase", StringToUpperCase, |
| 816 "toLocaleUpperCase", StringToLocaleUpperCase, |
| 817 "link", StringLink, |
| 818 "anchor", StringAnchor, |
| 819 "fontcolor", StringFontcolor, |
| 820 "fontsize", StringFontsize, |
| 821 "big", StringBig, |
| 822 "blink", StringBlink, |
| 823 "bold", StringBold, |
| 824 "fixed", StringFixed, |
| 825 "italics", StringItalics, |
| 826 "small", StringSmall, |
| 827 "strike", StringStrike, |
| 828 "sub", StringSub, |
| 829 "sup", StringSup |
| 830 )); |
| 831 } |
| 832 |
| 833 |
| 834 SetupString(); |
| OLD | NEW |