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, "&lt;")
701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                      .replace(/>/g, "&gt;")
702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                      .replace(/"/g, "&quot;")
703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                      .replace(/'/g, "&#039;");
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