string.js revision a7e24c173cf37484693b9abb38e494fa7bd7baeb
1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2006-2008 the V8 project authors. All rights reserved. 2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without 3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are 4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met: 5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions of source code must retain the above copyright 7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// notice, this list of conditions and the following disclaimer. 8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Redistributions in binary form must reproduce the above 9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// copyright notice, this list of conditions and the following 10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// disclaimer in the documentation and/or other materials provided 11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// with the distribution. 12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// * Neither the name of Google Inc. nor the names of its 13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// contributors may be used to endorse or promote products derived 14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// from this software without specific prior written permission. 15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// This file relies on the fact that the following declaration has been made 30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// in runtime.js: 31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// const $String = global.String; 32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// const $NaN = 0/0; 33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Set the String function and constructor. 36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block%SetCode($String, function(x) { 37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var value = %_ArgumentsLength() == 0 ? '' : ToString(x); 38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (%_IsConstructCall()) { 39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block %_SetValueOf(this, value); 40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return value; 42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}); 44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block%FunctionSetPrototype($String, new $String()); 46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262 section 15.5.4.2 48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringToString() { 49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) 50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block throw new $TypeError('String.prototype.toString is not generic'); 51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %_ValueOf(this); 52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262 section 15.5.4.3 56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringValueOf() { 57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) 58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block throw new $TypeError('String.prototype.valueOf is not generic'); 59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %_ValueOf(this); 60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262, section 15.5.4.4 64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringCharAt(pos) { 65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var char_code = %_FastCharCodeAt(this, pos); 66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!%_IsSmi(char_code)) { 67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var subject = ToString(this); 68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var index = TO_INTEGER(pos); 69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (index >= subject.length || index < 0) return ""; 70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char_code = %StringCharCodeAt(subject, index); 71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %CharFromCode(char_code); 73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262 section 15.5.4.5 77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringCharCodeAt(pos) { 78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var fast_answer = %_FastCharCodeAt(this, pos); 79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (%_IsSmi(fast_answer)) { 80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return fast_answer; 81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var subject = ToString(this); 83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var index = TO_INTEGER(pos); 84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringCharCodeAt(subject, index); 85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262, section 15.5.4.6 89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringConcat() { 90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var len = %_ArgumentsLength(); 91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var parts = new $Array(len + 1); 92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block parts[0] = ToString(this); 93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (var i = 0; i < len; i++) 94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block parts[i + 1] = ToString(%_Arguments(i)); 95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return parts.join(''); 96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Match ES3 and Safari 99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block%FunctionSetLength(StringConcat, 1); 100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262 section 15.5.4.7 103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringIndexOf(searchString /* position */) { // length == 1 104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var subject_str = ToString(this); 105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var pattern_str = ToString(searchString); 106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var subject_str_len = subject_str.length; 107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var pattern_str_len = pattern_str.length; 108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var index = 0; 109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (%_ArgumentsLength() > 1) { 110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var arg1 = %_Arguments(1); // position 111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index = TO_INTEGER(arg1); 112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (index < 0) index = 0; 114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (index > subject_str_len) index = subject_str_len; 115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (pattern_str_len + index > subject_str_len) return -1; 116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringIndexOf(subject_str, pattern_str, index); 117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262 section 15.5.4.8 121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringLastIndexOf(searchString /* position */) { // length == 1 122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var sub = ToString(this); 123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var subLength = sub.length; 124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var pat = ToString(searchString); 125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var patLength = pat.length; 126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var index = subLength - patLength; 127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (%_ArgumentsLength() > 1) { 128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var position = ToNumber(%_Arguments(1)); 129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!$isNaN(position)) { 130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block position = TO_INTEGER(position); 131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (position < 0) { 132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block position = 0; 133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (position + patLength < subLength) { 135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block index = position 136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (index < 0) { 140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return -1; 141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringLastIndexOf(sub, pat, index); 143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262 section 15.5.4.9 147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// This function is implementation specific. For now, we do not 149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// do anything locale specific. 150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringLocaleCompare(other) { 151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (%_ArgumentsLength() === 0) return 0; 152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var this_str = ToString(this); 154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var other_str = ToString(other); 155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringLocaleCompare(this_str, other_str); 156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262 section 15.5.4.10 160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringMatch(regexp) { 161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!IS_REGEXP(regexp)) regexp = new ORIGINAL_REGEXP(regexp); 162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var subject = ToString(this); 163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!regexp.global) return regexp.exec(subject); 165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]); 166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // lastMatchInfo is defined in regexp-delay.js. 167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringMatch(subject, regexp, lastMatchInfo); 168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SubString is an internal function that returns the sub string of 'string'. 172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// If resulting string is of length 1, we use the one character cache 173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// otherwise we call the runtime system. 174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction SubString(string, start, end) { 175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Use the one character string cache. 176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start + 1 == end) { 177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var char_code = %_FastCharCodeAt(string, start); 178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!%_IsSmi(char_code)) { 179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block char_code = %StringCharCodeAt(string, start); 180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %CharFromCode(char_code); 182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringSlice(string, start, end); 184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// This has the same size as the lastMatchInfo array, and can be used for 188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// functions that expect that structure to be returned. It is used when the 189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// needle is a string rather than a regexp. In this case we can't update 190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// lastMatchArray without erroneously affecting the properties on the global 191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// RegExp object. 192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvar reusableMatchInfo = [2, "", "", -1, -1]; 193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262, section 15.5.4.11 196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringReplace(search, replace) { 197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var subject = ToString(this); 198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Delegate to one of the regular expression variants if necessary. 200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (IS_REGEXP(search)) { 201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]); 202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (IS_FUNCTION(replace)) { 203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return StringReplaceRegExpWithFunction(subject, search, replace); 204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return StringReplaceRegExp(subject, search, replace); 206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Convert the search argument to a string and search for it. 210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block search = ToString(search); 211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var start = %StringIndexOf(subject, search, 0); 212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start < 0) return subject; 213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var end = start + search.length; 214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var builder = new ReplaceResultBuilder(subject); 216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // prefix 217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.addSpecialSlice(0, start); 218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compute the string to replace with. 220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (IS_FUNCTION(replace)) { 221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.add(replace.call(null, search, start, subject)); 222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block reusableMatchInfo[CAPTURE0] = start; 224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block reusableMatchInfo[CAPTURE1] = end; 225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ExpandReplacement(ToString(replace), subject, reusableMatchInfo, builder); 226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // suffix 229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.addSpecialSlice(end, subject.length); 230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return builder.generate(); 232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Helper function for regular expressions in String.prototype.replace. 236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringReplaceRegExp(subject, regexp, replace) { 237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block replace = ToString(replace); 238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringReplaceRegExpWithString(subject, 239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block regexp, 240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block replace, 241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block lastMatchInfo); 242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Expand the $-expressions in the string and return a new string with 246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// the result. 247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction ExpandReplacement(string, subject, matchInfo, builder) { 248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var next = %StringIndexOf(string, '$', 0); 249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (next < 0) { 250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.add(string); 251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102. 255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; // Includes the match. 256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (next > 0) builder.add(SubString(string, 0, next)); 258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var length = string.length; 259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (true) { 261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var expansion = '$'; 262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var position = next + 1; 263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (position < length) { 264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var peek = %_FastCharCodeAt(string, position); 265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!%_IsSmi(peek)) { 266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block peek = %StringCharCodeAt(string, position); 267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (peek == 36) { // $$ 269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ++position; 270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.add('$'); 271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (peek == 38) { // $& - match 272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ++position; 273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.addSpecialSlice(matchInfo[CAPTURE0], 274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block matchInfo[CAPTURE1]); 275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (peek == 96) { // $` - prefix 276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ++position; 277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.addSpecialSlice(0, matchInfo[CAPTURE0]); 278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (peek == 39) { // $' - suffix 279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ++position; 280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.addSpecialSlice(matchInfo[CAPTURE1], subject.length); 281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else if (peek >= 48 && peek <= 57) { // $n, 0 <= n <= 9 282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ++position; 283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var n = peek - 48; 284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (position < length) { 285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block peek = %_FastCharCodeAt(string, position); 286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!%_IsSmi(peek)) { 287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block peek = %StringCharCodeAt(string, position); 288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // $nn, 01 <= nn <= 99 290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (n != 0 && peek == 48 || peek >= 49 && peek <= 57) { 291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var nn = n * 10 + (peek - 48); 292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (nn < m) { 293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the two digit capture reference is within range of 294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // the captures, we use it instead of the single digit 295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // one. Otherwise, we fall back to using the single 296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // digit reference. This matches the behavior of 297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // SpiderMonkey. 298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ++position; 299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block n = nn; 300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (0 < n && n < m) { 304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block addCaptureString(builder, matchInfo, n); 305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Because of the captures range check in the parsing of two 307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // digit capture references, we can only enter here when a 308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // single digit capture reference is outside the range of 309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // captures. 310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.add('$'); 311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block --position; 312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.add('$'); 315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.add('$'); 318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Go the the next $ in the string. 321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block next = %StringIndexOf(string, '$', position); 322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Return if there are no more $ characters in the string. If we 324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // haven't reached the end, we need to append the suffix. 325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (next < 0) { 326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (position < length) { 327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.add(SubString(string, position, length)); 328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return; 330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Append substring between the previous and the next $ character. 333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.add(SubString(string, position, next)); 334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Compute the string of a given regular expression capture. 339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction CaptureString(string, lastCaptureInfo, index) { 340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Scale the index. 341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var scaled = index << 1; 342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compute start and end. 343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var start = lastCaptureInfo[CAPTURE(scaled)]; 344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var end = lastCaptureInfo[CAPTURE(scaled + 1)]; 345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If either start or end is missing return undefined. 346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start < 0 || end < 0) return; 347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return SubString(string, start, end); 348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Add the string of a given regular expression capture to the 352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ReplaceResultBuilder 353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction addCaptureString(builder, matchInfo, index) { 354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Scale the index. 355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var scaled = index << 1; 356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compute start and end. 357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var start = matchInfo[CAPTURE(scaled)]; 358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var end = matchInfo[CAPTURE(scaled + 1)]; 359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If either start or end is missing return. 360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start < 0 || end <= start) return; 361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block builder.addSpecialSlice(start, end); 362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Helper function for replacing regular expressions with the result of a 366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// function application in String.prototype.replace. The function application 367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// must be interleaved with the regexp matching (contrary to ECMA-262 368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 15.5.4.11) to mimic SpiderMonkey and KJS behavior when the function uses 369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// the static properties of the RegExp constructor. Example: 370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 'abcd'.replace(/(.)/g, function() { return RegExp.$1; } 371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// should be 'abcd' and not 'dddd' (or anything else). 372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringReplaceRegExpWithFunction(subject, regexp, replace) { 373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var matchInfo = DoRegExpExec(regexp, subject, 0); 374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (IS_NULL(matchInfo)) return subject; 375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var result = new ReplaceResultBuilder(subject); 377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // There's at least one match. If the regexp is global, we have to loop 378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // over all matches. The loop is not in C++ code here like the one in 379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // RegExp.prototype.exec, because of the interleaved function application. 380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Unfortunately, that means this code is nearly duplicated, here and in 381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // jsregexp.cc. 382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (regexp.global) { 383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var previous = 0; 384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block do { 385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result.addSpecialSlice(previous, matchInfo[CAPTURE0]); 386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var startOfMatch = matchInfo[CAPTURE0]; 387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block previous = matchInfo[CAPTURE1]; 388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result.add(ApplyReplacementFunction(replace, matchInfo, subject)); 389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Can't use matchInfo any more from here, since the function could 390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // overwrite it. 391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Continue with the next match. 392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Increment previous if we matched an empty string, as per ECMA-262 393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // 15.5.4.10. 394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (previous == startOfMatch) { 395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Add the skipped character to the output, if any. 396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (previous < subject.length) { 397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result.addSpecialSlice(previous, previous + 1); 398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block previous++; 400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Per ECMA-262 15.10.6.2, if the previous index is greater than the 403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // string length, there is no match 404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block matchInfo = (previous > subject.length) 405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block ? null 406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block : DoRegExpExec(regexp, subject, previous); 407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } while (!IS_NULL(matchInfo)); 408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Tack on the final right substring after the last match, if necessary. 410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (previous < subject.length) { 411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result.addSpecialSlice(previous, subject.length); 412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { // Not a global regexp, no need to loop. 414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result.addSpecialSlice(0, matchInfo[CAPTURE0]); 415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var endOfMatch = matchInfo[CAPTURE1]; 416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result.add(ApplyReplacementFunction(replace, matchInfo, subject)); 417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Can't use matchInfo any more from here, since the function could 418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // overwrite it. 419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result.addSpecialSlice(endOfMatch, subject.length); 420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return result.generate(); 423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Helper function to apply a string replacement function once. 427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction ApplyReplacementFunction(replace, matchInfo, subject) { 428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compute the parameter list consisting of the match, captures, index, 429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // and subject for the replace function invocation. 430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var index = matchInfo[CAPTURE0]; 431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // The number of captures plus one for the match. 432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; 433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (m == 1) { 434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var s = CaptureString(subject, matchInfo, 0); 435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Don't call directly to avoid exposing the built-in global object. 436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return replace.call(null, s, index, subject); 437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var parameters = $Array(m + 2); 439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (var j = 0; j < m; j++) { 440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block parameters[j] = CaptureString(subject, matchInfo, j); 441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block parameters[j] = index; 443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block parameters[j + 1] = subject; 444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return replace.apply(null, parameters); 445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262 section 15.5.4.12 449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringSearch(re) { 450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var regexp = new ORIGINAL_REGEXP(re); 451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var s = ToString(this); 452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var last_idx = regexp.lastIndex; // keep old lastIndex 453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block regexp.lastIndex = 0; // ignore re.global property 454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var result = regexp.exec(s); 455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block regexp.lastIndex = last_idx; // restore lastIndex 456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (result == null) 457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return -1; 458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block else 459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return result.index; 460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262 section 15.5.4.13 464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringSlice(start, end) { 465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var s = ToString(this); 466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var s_len = s.length; 467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var start_i = TO_INTEGER(start); 468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var end_i = s_len; 469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (end !== void 0) 470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block end_i = TO_INTEGER(end); 471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start_i < 0) { 473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block start_i += s_len; 474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start_i < 0) 475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block start_i = 0; 476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start_i > s_len) 478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block start_i = s_len; 479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (end_i < 0) { 482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block end_i += s_len; 483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (end_i < 0) 484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block end_i = 0; 485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (end_i > s_len) 487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block end_i = s_len; 488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var num_c = end_i - start_i; 491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (num_c < 0) 492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block num_c = 0; 493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return SubString(s, start_i, start_i + num_c); 495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262 section 15.5.4.14 499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringSplit(separator, limit) { 500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var subject = ToString(this); 501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block limit = (limit === void 0) ? 0xffffffff : ToUint32(limit); 502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (limit === 0) return []; 503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // ECMA-262 says that if separator is undefined, the result should 505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // be an array of size 1 containing the entire string. SpiderMonkey 506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // and KJS have this behaviour only when no separator is given. If 507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // undefined is explicitly given, they convert it to a string and 508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // use that. We do as SpiderMonkey and KJS. 509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (%_ArgumentsLength() === 0) { 510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return [subject]; 511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var length = subject.length; 514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (IS_REGEXP(separator)) { 515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]); 516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block separator = ToString(separator); 518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If the separator string is empty then return the elements in the subject. 519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (separator.length == 0) { 520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var result = $Array(length); 521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (var i = 0; i < length; i++) result[i] = subject[i]; 522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return result; 523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (length === 0) { 527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (splitMatch(separator, subject, 0, 0) != null) return []; 528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return [subject]; 529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var currentIndex = 0; 532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var startIndex = 0; 533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var result = []; 534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block while (true) { 536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (startIndex === length) { 538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result[result.length] = subject.slice(currentIndex, length); 539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return result; 540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var matchInfo = splitMatch(separator, subject, currentIndex, startIndex); 543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (IS_NULL(matchInfo)) { 545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result[result.length] = subject.slice(currentIndex, length); 546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return result; 547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var endIndex = matchInfo[CAPTURE1]; 550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // We ignore a zero-length match at the currentIndex. 552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (startIndex === endIndex && endIndex === currentIndex) { 553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block startIndex++; 554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block continue; 555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]); 558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (result.length === limit) return result; 559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (var i = 2; i < NUMBER_OF_CAPTURES(matchInfo); i += 2) { 561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var start = matchInfo[CAPTURE(i)]; 562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var end = matchInfo[CAPTURE(i + 1)]; 563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start != -1 && end != -1) { 564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result[result.length] = SubString(subject, start, end); 565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result[result.length] = void 0; 567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (result.length === limit) return result; 569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block startIndex = currentIndex = endIndex; 572a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 573a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 574a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 575a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262 section 15.5.4.14 577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Helper function used by split. This version returns the matchInfo 578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// instead of allocating a new array with basically the same information. 579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction splitMatch(separator, subject, current_index, start_index) { 580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (IS_REGEXP(separator)) { 581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var matchInfo = DoRegExpExec(separator, subject, start_index); 582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (matchInfo == null) return null; 583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Section 15.5.4.14 paragraph two says that we do not allow zero length 584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // matches at the end of the string. 585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (matchInfo[CAPTURE0] === subject.length) return null; 586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return matchInfo; 587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var separatorIndex = subject.indexOf(separator, start_index); 590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (separatorIndex === -1) return null; 591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block reusableMatchInfo[CAPTURE0] = separatorIndex; 593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block reusableMatchInfo[CAPTURE1] = separatorIndex + separator.length; 594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return reusableMatchInfo; 595a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262 section 15.5.4.15 599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringSubstring(start, end) { 600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var s = ToString(this); 601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var s_len = s.length; 602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var start_i = TO_INTEGER(start); 603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var end_i = s_len; 604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!IS_UNDEFINED(end)) 605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block end_i = TO_INTEGER(end); 606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start_i < 0) start_i = 0; 608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start_i > s_len) start_i = s_len; 609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (end_i < 0) end_i = 0; 610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (end_i > s_len) end_i = s_len; 611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start_i > end_i) { 613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var tmp = end_i; 614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block end_i = start_i; 615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block start_i = tmp; 616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return SubString(s, start_i, end_i); 619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// This is not a part of ECMA-262. 623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringSubstr(start, n) { 624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var s = ToString(this); 625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var len; 626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Correct n: If not given, set to string length; if explicitly 628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // set to undefined, zero, or negative, returns empty string. 629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (n === void 0) { 630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block len = s.length; 631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block len = TO_INTEGER(n); 633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (len <= 0) return ''; 634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Correct start: If not given (or undefined), set to zero; otherwise 637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // convert to integer and handle negative case. 638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start === void 0) { 639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block start = 0; 640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block start = TO_INTEGER(start); 642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If positive, and greater than or equal to the string length, 643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // return empty string. 644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start >= s.length) return ''; 645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // If negative and absolute value is larger than the string length, 646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // use zero. 647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start < 0) { 648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block start += s.length; 649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start < 0) start = 0; 650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var end = start + len; 654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (end > s.length) end = s.length; 655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return SubString(s, start, end); 657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262, 15.5.4.16 661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringToLowerCase() { 662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringToLowerCase(ToString(this)); 663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262, 15.5.4.17 667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringToLocaleLowerCase() { 668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringToLowerCase(ToString(this)); 669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262, 15.5.4.18 673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringToUpperCase() { 674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringToUpperCase(ToString(this)); 675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262, 15.5.4.19 679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringToLocaleUpperCase() { 680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringToUpperCase(ToString(this)); 681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ECMA-262, section 15.5.3.2 685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringFromCharCode(code) { 686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var n = %_ArgumentsLength(); 687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (n == 1) return %CharFromCode(ToNumber(code) & 0xffff) 688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // NOTE: This is not super-efficient, but it is necessary because we 690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // want to avoid converting to numbers from within the virtual 691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // machine. Maybe we can find another way of doing this? 692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var codes = new $Array(n); 693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (var i = 0; i < n; i++) codes[i] = ToNumber(%_Arguments(i)); 694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringFromCharCodeArray(codes); 695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Helper function for very basic XSS protection. 699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction HtmlEscape(str) { 700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ToString(str).replace(/</g, "<") 701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block .replace(/>/g, ">") 702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block .replace(/"/g, """) 703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block .replace(/'/g, "'"); 704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}; 705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Compatibility support for KJS. 708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Tested by mozilla/js/tests/js1_5/Regress/regress-276103.js. 709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringLink(s) { 710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "<a href=\"" + HtmlEscape(s) + "\">" + this + "</a>"; 711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringAnchor(name) { 715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "<a name=\"" + HtmlEscape(name) + "\">" + this + "</a>"; 716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringFontcolor(color) { 720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "<font color=\"" + HtmlEscape(color) + "\">" + this + "</font>"; 721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringFontsize(size) { 725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "<font size=\"" + HtmlEscape(size) + "\">" + this + "</font>"; 726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringBig() { 730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "<big>" + this + "</big>"; 731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringBlink() { 735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "<blink>" + this + "</blink>"; 736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringBold() { 740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "<b>" + this + "</b>"; 741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringFixed() { 745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "<tt>" + this + "</tt>"; 746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringItalics() { 750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "<i>" + this + "</i>"; 751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringSmall() { 755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "<small>" + this + "</small>"; 756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringStrike() { 760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "<strike>" + this + "</strike>"; 761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringSub() { 765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "<sub>" + this + "</sub>"; 766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringSup() { 770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return "<sup>" + this + "</sup>"; 771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// StringBuilder support. 775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringBuilder() { 777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.elements = new $Array(); 778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction ReplaceResultBuilder(str) { 782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.elements = new $Array(); 783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block this.special_string = str; 784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockReplaceResultBuilder.prototype.add = 788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockStringBuilder.prototype.add = function(str) { 789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (!IS_STRING(str)) str = ToString(str); 790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (str.length > 0) { 791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var elements = this.elements; 792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block elements[elements.length] = str; 793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) { 798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var len = end - start; 799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (len == 0) return; 800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block var elements = this.elements; 801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (start >= 0 && len >= 0 && start < 0x80000 && len < 0x800) { 802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block elements[elements.length] = (start << 11) + len; 803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block elements[elements.length] = SubString(this.special_string, start, end); 805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockStringBuilder.prototype.generate = function() { 810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringBuilderConcat(this.elements, ""); 811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockReplaceResultBuilder.prototype.generate = function() { 815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return %StringBuilderConcat(this.elements, this.special_string); 816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction StringToJSON(key) { 820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return CheckJSONPrimitive(this.valueOf()); 821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ------------------------------------------------------------------- 825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfunction SetupString() { 827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Setup the constructor property on the String prototype object. 828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block %SetProperty($String.prototype, "constructor", $String, DONT_ENUM); 829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Setup the non-enumerable functions on the String object. 832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block InstallFunctions($String, DONT_ENUM, $Array( 833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "fromCharCode", StringFromCharCode 834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block )); 835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Setup the non-enumerable functions on the String prototype object. 838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block InstallFunctionsOnHiddenPrototype($String.prototype, DONT_ENUM, $Array( 839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "valueOf", StringValueOf, 840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "toString", StringToString, 841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "charAt", StringCharAt, 842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "charCodeAt", StringCharCodeAt, 843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "concat", StringConcat, 844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "indexOf", StringIndexOf, 845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "lastIndexOf", StringLastIndexOf, 846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "localeCompare", StringLocaleCompare, 847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "match", StringMatch, 848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "replace", StringReplace, 849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "search", StringSearch, 850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "slice", StringSlice, 851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "split", StringSplit, 852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "substring", StringSubstring, 853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "substr", StringSubstr, 854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "toLowerCase", StringToLowerCase, 855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "toLocaleLowerCase", StringToLocaleLowerCase, 856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "toUpperCase", StringToUpperCase, 857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "toLocaleUpperCase", StringToLocaleUpperCase, 858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "link", StringLink, 859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "anchor", StringAnchor, 860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "fontcolor", StringFontcolor, 861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "fontsize", StringFontsize, 862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "big", StringBig, 863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "blink", StringBlink, 864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "bold", StringBold, 865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "fixed", StringFixed, 866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "italics", StringItalics, 867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "small", StringSmall, 868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "strike", StringStrike, 869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "sub", StringSub, 870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "sup", StringSup, 871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "toJSON", StringToJSON 872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block )); 873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSetupString(); 877