blob: a70eeade83b9d68b51937611b621b628fa6be286 [file] [log] [blame]
Steve Blockd0582a62009-12-15 09:54:21 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28
29// This file relies on the fact that the following declaration has been made
30// in runtime.js:
31// const $String = global.String;
32// const $NaN = 0/0;
33
34
35// Set the String function and constructor.
36%SetCode($String, function(x) {
Andrei Popescu402d9372010-02-26 13:31:12 +000037 var value = %_ArgumentsLength() == 0 ? '' : TO_STRING_INLINE(x);
Steve Blocka7e24c12009-10-30 11:49:00 +000038 if (%_IsConstructCall()) {
39 %_SetValueOf(this, value);
40 } else {
41 return value;
42 }
43});
44
45%FunctionSetPrototype($String, new $String());
46
47// ECMA-262 section 15.5.4.2
48function StringToString() {
49 if (!IS_STRING(this) && !IS_STRING_WRAPPER(this))
50 throw new $TypeError('String.prototype.toString is not generic');
51 return %_ValueOf(this);
52}
53
54
55// ECMA-262 section 15.5.4.3
56function StringValueOf() {
57 if (!IS_STRING(this) && !IS_STRING_WRAPPER(this))
58 throw new $TypeError('String.prototype.valueOf is not generic');
59 return %_ValueOf(this);
60}
61
62
63// ECMA-262, section 15.5.4.4
64function StringCharAt(pos) {
Ben Murdoch257744e2011-11-30 15:57:28 +000065 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
66 throw MakeTypeError("called_on_null_or_undefined",
67 ["String.prototype.charAt"]);
68 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010069 var result = %_StringCharAt(this, pos);
70 if (%_IsSmi(result)) {
71 result = %_StringCharAt(TO_STRING_INLINE(this), TO_INTEGER(pos));
Steve Blocka7e24c12009-10-30 11:49:00 +000072 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010073 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000074}
75
76
77// ECMA-262 section 15.5.4.5
78function StringCharCodeAt(pos) {
Ben Murdoch257744e2011-11-30 15:57:28 +000079 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
80 throw MakeTypeError("called_on_null_or_undefined",
81 ["String.prototype.charCodeAt"]);
82 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010083 var result = %_StringCharCodeAt(this, pos);
84 if (!%_IsSmi(result)) {
85 result = %_StringCharCodeAt(TO_STRING_INLINE(this), TO_INTEGER(pos));
Steve Blocka7e24c12009-10-30 11:49:00 +000086 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010087 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000088}
89
90
91// ECMA-262, section 15.5.4.6
92function StringConcat() {
Ben Murdoch257744e2011-11-30 15:57:28 +000093 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
94 throw MakeTypeError("called_on_null_or_undefined", ["String.prototype.concat"]);
95 }
Andrei Popescu402d9372010-02-26 13:31:12 +000096 var len = %_ArgumentsLength();
97 var this_as_string = TO_STRING_INLINE(this);
98 if (len === 1) {
99 return this_as_string + %_Arguments(0);
Leon Clarkee46be812010-01-19 14:06:41 +0000100 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100101 var parts = new InternalArray(len + 1);
Andrei Popescu402d9372010-02-26 13:31:12 +0000102 parts[0] = this_as_string;
103 for (var i = 0; i < len; i++) {
104 var part = %_Arguments(i);
105 parts[i + 1] = TO_STRING_INLINE(part);
106 }
107 return %StringBuilderConcat(parts, len + 1, "");
Steve Blocka7e24c12009-10-30 11:49:00 +0000108}
109
110// Match ES3 and Safari
111%FunctionSetLength(StringConcat, 1);
112
113
114// ECMA-262 section 15.5.4.7
Ben Murdochb0fe1622011-05-05 13:52:32 +0100115function StringIndexOf(pattern /* position */) { // length == 1
Ben Murdoch257744e2011-11-30 15:57:28 +0000116 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
117 throw MakeTypeError("called_on_null_or_undefined",
118 ["String.prototype.indexOf"]);
119 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100120 var subject = TO_STRING_INLINE(this);
Steve Block1e0659c2011-05-24 12:43:12 +0100121 pattern = TO_STRING_INLINE(pattern);
Steve Blocka7e24c12009-10-30 11:49:00 +0000122 var index = 0;
123 if (%_ArgumentsLength() > 1) {
Steve Block1e0659c2011-05-24 12:43:12 +0100124 index = %_Arguments(1); // position
125 index = TO_INTEGER(index);
126 if (index < 0) index = 0;
127 if (index > subject.length) index = subject.length;
Steve Blocka7e24c12009-10-30 11:49:00 +0000128 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100129 return %StringIndexOf(subject, pattern, index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000130}
131
132
133// ECMA-262 section 15.5.4.8
Ben Murdochb0fe1622011-05-05 13:52:32 +0100134function StringLastIndexOf(pat /* position */) { // length == 1
Ben Murdoch257744e2011-11-30 15:57:28 +0000135 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
136 throw MakeTypeError("called_on_null_or_undefined",
137 ["String.prototype.lastIndexOf"]);
138 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000139 var sub = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000140 var subLength = sub.length;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100141 var pat = TO_STRING_INLINE(pat);
Steve Blocka7e24c12009-10-30 11:49:00 +0000142 var patLength = pat.length;
143 var index = subLength - patLength;
144 if (%_ArgumentsLength() > 1) {
145 var position = ToNumber(%_Arguments(1));
Steve Block9fac8402011-05-12 15:51:54 +0100146 if (!NUMBER_IS_NAN(position)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000147 position = TO_INTEGER(position);
148 if (position < 0) {
149 position = 0;
150 }
151 if (position + patLength < subLength) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000152 index = position;
Steve Blocka7e24c12009-10-30 11:49:00 +0000153 }
154 }
155 }
156 if (index < 0) {
157 return -1;
158 }
159 return %StringLastIndexOf(sub, pat, index);
160}
161
162
163// ECMA-262 section 15.5.4.9
164//
165// This function is implementation specific. For now, we do not
166// do anything locale specific.
167function StringLocaleCompare(other) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000168 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
169 throw MakeTypeError("called_on_null_or_undefined",
170 ["String.prototype.localeCompare"]);
171 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000172 if (%_ArgumentsLength() === 0) return 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000173 return %StringLocaleCompare(TO_STRING_INLINE(this),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100174 TO_STRING_INLINE(other));
Steve Blocka7e24c12009-10-30 11:49:00 +0000175}
176
177
178// ECMA-262 section 15.5.4.10
179function StringMatch(regexp) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000180 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
181 throw MakeTypeError("called_on_null_or_undefined",
182 ["String.prototype.match"]);
183 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000184 var subject = TO_STRING_INLINE(this);
Steve Block6ded16b2010-05-10 14:33:55 +0100185 if (IS_REGEXP(regexp)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100186 if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0);
Steve Block6ded16b2010-05-10 14:33:55 +0100187 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
188 // lastMatchInfo is defined in regexp.js.
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800189 return %StringMatch(subject, regexp, lastMatchInfo);
Steve Block6ded16b2010-05-10 14:33:55 +0100190 }
191 // Non-regexp argument.
192 regexp = new $RegExp(regexp);
Steve Block6ded16b2010-05-10 14:33:55 +0100193 return RegExpExecNoTests(regexp, subject, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000194}
195
196
197// SubString is an internal function that returns the sub string of 'string'.
198// If resulting string is of length 1, we use the one character cache
199// otherwise we call the runtime system.
200function SubString(string, start, end) {
201 // Use the one character string cache.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100202 if (start + 1 == end) return %_StringCharAt(string, start);
Leon Clarkee46be812010-01-19 14:06:41 +0000203 return %_SubString(string, start, end);
Steve Blocka7e24c12009-10-30 11:49:00 +0000204}
205
206
207// This has the same size as the lastMatchInfo array, and can be used for
208// functions that expect that structure to be returned. It is used when the
209// needle is a string rather than a regexp. In this case we can't update
210// lastMatchArray without erroneously affecting the properties on the global
211// RegExp object.
212var reusableMatchInfo = [2, "", "", -1, -1];
213
214
215// ECMA-262, section 15.5.4.11
216function StringReplace(search, replace) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000217 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
218 throw MakeTypeError("called_on_null_or_undefined",
219 ["String.prototype.replace"]);
220 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000221 var subject = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000222
223 // Delegate to one of the regular expression variants if necessary.
224 if (IS_REGEXP(search)) {
225 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
226 if (IS_FUNCTION(replace)) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100227 if (search.global) {
228 return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
229 } else {
230 return StringReplaceNonGlobalRegExpWithFunction(subject,
231 search,
232 replace);
233 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000234 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100235 return %StringReplaceRegExpWithString(subject,
236 search,
237 TO_STRING_INLINE(replace),
238 lastMatchInfo);
Steve Blocka7e24c12009-10-30 11:49:00 +0000239 }
240 }
241
242 // Convert the search argument to a string and search for it.
Andrei Popescu402d9372010-02-26 13:31:12 +0000243 search = TO_STRING_INLINE(search);
Steve Blocka7e24c12009-10-30 11:49:00 +0000244 var start = %StringIndexOf(subject, search, 0);
245 if (start < 0) return subject;
246 var end = start + search.length;
247
248 var builder = new ReplaceResultBuilder(subject);
249 // prefix
250 builder.addSpecialSlice(0, start);
251
252 // Compute the string to replace with.
253 if (IS_FUNCTION(replace)) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000254 var receiver = %GetDefaultReceiver(replace);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000255 builder.add(%_CallFunction(receiver,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100256 search,
257 start,
258 subject,
259 replace));
Steve Blocka7e24c12009-10-30 11:49:00 +0000260 } else {
261 reusableMatchInfo[CAPTURE0] = start;
262 reusableMatchInfo[CAPTURE1] = end;
Andrei Popescu402d9372010-02-26 13:31:12 +0000263 replace = TO_STRING_INLINE(replace);
Leon Clarkee46be812010-01-19 14:06:41 +0000264 ExpandReplacement(replace, subject, reusableMatchInfo, builder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000265 }
266
267 // suffix
268 builder.addSpecialSlice(end, subject.length);
269
270 return builder.generate();
271}
272
273
Steve Blocka7e24c12009-10-30 11:49:00 +0000274// Expand the $-expressions in the string and return a new string with
275// the result.
276function ExpandReplacement(string, subject, matchInfo, builder) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100277 var length = string.length;
Ben Murdoch257744e2011-11-30 15:57:28 +0000278 var builder_elements = builder.elements;
Steve Blocka7e24c12009-10-30 11:49:00 +0000279 var next = %StringIndexOf(string, '$', 0);
280 if (next < 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100281 if (length > 0) builder_elements.push(string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000282 return;
283 }
284
285 // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102.
286 var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; // Includes the match.
287
Ben Murdochb0fe1622011-05-05 13:52:32 +0100288 if (next > 0) builder_elements.push(SubString(string, 0, next));
Steve Blocka7e24c12009-10-30 11:49:00 +0000289
290 while (true) {
291 var expansion = '$';
292 var position = next + 1;
293 if (position < length) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100294 var peek = %_StringCharCodeAt(string, position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000295 if (peek == 36) { // $$
296 ++position;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100297 builder_elements.push('$');
Steve Blocka7e24c12009-10-30 11:49:00 +0000298 } else if (peek == 38) { // $& - match
299 ++position;
300 builder.addSpecialSlice(matchInfo[CAPTURE0],
301 matchInfo[CAPTURE1]);
302 } else if (peek == 96) { // $` - prefix
303 ++position;
304 builder.addSpecialSlice(0, matchInfo[CAPTURE0]);
305 } else if (peek == 39) { // $' - suffix
306 ++position;
307 builder.addSpecialSlice(matchInfo[CAPTURE1], subject.length);
308 } else if (peek >= 48 && peek <= 57) { // $n, 0 <= n <= 9
309 ++position;
310 var n = peek - 48;
311 if (position < length) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100312 peek = %_StringCharCodeAt(string, position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000313 // $nn, 01 <= nn <= 99
314 if (n != 0 && peek == 48 || peek >= 49 && peek <= 57) {
315 var nn = n * 10 + (peek - 48);
316 if (nn < m) {
317 // If the two digit capture reference is within range of
318 // the captures, we use it instead of the single digit
319 // one. Otherwise, we fall back to using the single
320 // digit reference. This matches the behavior of
321 // SpiderMonkey.
322 ++position;
323 n = nn;
324 }
325 }
326 }
327 if (0 < n && n < m) {
328 addCaptureString(builder, matchInfo, n);
329 } else {
330 // Because of the captures range check in the parsing of two
331 // digit capture references, we can only enter here when a
332 // single digit capture reference is outside the range of
333 // captures.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100334 builder_elements.push('$');
Steve Blocka7e24c12009-10-30 11:49:00 +0000335 --position;
336 }
337 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100338 builder_elements.push('$');
Steve Blocka7e24c12009-10-30 11:49:00 +0000339 }
340 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100341 builder_elements.push('$');
Steve Blocka7e24c12009-10-30 11:49:00 +0000342 }
343
344 // Go the the next $ in the string.
345 next = %StringIndexOf(string, '$', position);
346
347 // Return if there are no more $ characters in the string. If we
348 // haven't reached the end, we need to append the suffix.
349 if (next < 0) {
350 if (position < length) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100351 builder_elements.push(SubString(string, position, length));
Steve Blocka7e24c12009-10-30 11:49:00 +0000352 }
353 return;
354 }
355
356 // Append substring between the previous and the next $ character.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100357 if (next > position) {
358 builder_elements.push(SubString(string, position, next));
359 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000360 }
361};
362
363
364// Compute the string of a given regular expression capture.
365function CaptureString(string, lastCaptureInfo, index) {
366 // Scale the index.
367 var scaled = index << 1;
368 // Compute start and end.
369 var start = lastCaptureInfo[CAPTURE(scaled)];
Kristian Monsen25f61362010-05-21 11:50:48 +0100370 // If start isn't valid, return undefined.
371 if (start < 0) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000372 var end = lastCaptureInfo[CAPTURE(scaled + 1)];
Steve Blocka7e24c12009-10-30 11:49:00 +0000373 return SubString(string, start, end);
374};
375
376
377// Add the string of a given regular expression capture to the
378// ReplaceResultBuilder
379function addCaptureString(builder, matchInfo, index) {
380 // Scale the index.
381 var scaled = index << 1;
382 // Compute start and end.
383 var start = matchInfo[CAPTURE(scaled)];
Kristian Monsen25f61362010-05-21 11:50:48 +0100384 if (start < 0) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000385 var end = matchInfo[CAPTURE(scaled + 1)];
Steve Blocka7e24c12009-10-30 11:49:00 +0000386 builder.addSpecialSlice(start, end);
387};
388
Steve Block6ded16b2010-05-10 14:33:55 +0100389// TODO(lrn): This array will survive indefinitely if replace is never
390// called again. However, it will be empty, since the contents are cleared
391// in the finally block.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100392var reusableReplaceArray = new InternalArray(16);
Steve Blocka7e24c12009-10-30 11:49:00 +0000393
394// Helper function for replacing regular expressions with the result of a
Steve Block6ded16b2010-05-10 14:33:55 +0100395// function application in String.prototype.replace.
Kristian Monsen25f61362010-05-21 11:50:48 +0100396function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
397 var resultArray = reusableReplaceArray;
398 if (resultArray) {
399 reusableReplaceArray = null;
400 } else {
401 // Inside a nested replace (replace called from the replacement function
402 // of another replace) or we have failed to set the reusable array
403 // back due to an exception in a replacement function. Create a new
404 // array to use in the future, or until the original is written back.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100405 resultArray = new InternalArray(16);
Steve Blocka7e24c12009-10-30 11:49:00 +0000406 }
Kristian Monsen25f61362010-05-21 11:50:48 +0100407 var res = %RegExpExecMultiple(regexp,
408 subject,
409 lastMatchInfo,
410 resultArray);
411 regexp.lastIndex = 0;
412 if (IS_NULL(res)) {
413 // No matches at all.
414 reusableReplaceArray = resultArray;
415 return subject;
416 }
417 var len = res.length;
418 var i = 0;
419 if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
420 var match_start = 0;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100421 var override = new InternalArray(null, 0, subject);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000422 var receiver = %GetDefaultReceiver(replace);
Kristian Monsen25f61362010-05-21 11:50:48 +0100423 while (i < len) {
424 var elem = res[i];
425 if (%_IsSmi(elem)) {
426 if (elem > 0) {
427 match_start = (elem >> 11) + (elem & 0x7ff);
428 } else {
429 match_start = res[++i] - elem;
430 }
431 } else {
432 override[0] = elem;
433 override[1] = match_start;
434 lastMatchInfoOverride = override;
435 var func_result =
436 %_CallFunction(receiver, elem, match_start, subject, replace);
Steve Block1e0659c2011-05-24 12:43:12 +0100437 res[i] = TO_STRING_INLINE(func_result);
Kristian Monsen25f61362010-05-21 11:50:48 +0100438 match_start += elem.length;
439 }
440 i++;
441 }
442 } else {
443 while (i < len) {
444 var elem = res[i];
445 if (!%_IsSmi(elem)) {
446 // elem must be an Array.
447 // Use the apply argument as backing for global RegExp properties.
448 lastMatchInfoOverride = elem;
449 var func_result = replace.apply(null, elem);
Steve Block1e0659c2011-05-24 12:43:12 +0100450 res[i] = TO_STRING_INLINE(func_result);
Kristian Monsen25f61362010-05-21 11:50:48 +0100451 }
452 i++;
453 }
454 }
455 var resultBuilder = new ReplaceResultBuilder(subject, res);
456 var result = resultBuilder.generate();
457 resultArray.length = 0;
458 reusableReplaceArray = resultArray;
459 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000460}
461
462
Kristian Monsen25f61362010-05-21 11:50:48 +0100463function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
464 var matchInfo = DoRegExpExec(regexp, subject, 0);
465 if (IS_NULL(matchInfo)) return subject;
466 var result = new ReplaceResultBuilder(subject);
467 var index = matchInfo[CAPTURE0];
468 result.addSpecialSlice(0, index);
469 var endOfMatch = matchInfo[CAPTURE1];
Steve Blocka7e24c12009-10-30 11:49:00 +0000470 // Compute the parameter list consisting of the match, captures, index,
471 // and subject for the replace function invocation.
Steve Blocka7e24c12009-10-30 11:49:00 +0000472 // The number of captures plus one for the match.
473 var m = NUMBER_OF_CAPTURES(matchInfo) >> 1;
Kristian Monsen25f61362010-05-21 11:50:48 +0100474 var replacement;
Steve Blocka7e24c12009-10-30 11:49:00 +0000475 if (m == 1) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100476 // No captures, only the match, which is always valid.
477 var s = SubString(subject, index, endOfMatch);
Steve Blocka7e24c12009-10-30 11:49:00 +0000478 // Don't call directly to avoid exposing the built-in global object.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000479 var receiver = %GetDefaultReceiver(replace);
Kristian Monsen25f61362010-05-21 11:50:48 +0100480 replacement =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000481 %_CallFunction(receiver, s, index, subject, replace);
Kristian Monsen25f61362010-05-21 11:50:48 +0100482 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100483 var parameters = new InternalArray(m + 2);
Kristian Monsen25f61362010-05-21 11:50:48 +0100484 for (var j = 0; j < m; j++) {
485 parameters[j] = CaptureString(subject, matchInfo, j);
486 }
487 parameters[j] = index;
488 parameters[j + 1] = subject;
489
490 replacement = replace.apply(null, parameters);
Steve Blocka7e24c12009-10-30 11:49:00 +0000491 }
Kristian Monsen25f61362010-05-21 11:50:48 +0100492
493 result.add(replacement); // The add method converts to string if necessary.
494 // Can't use matchInfo any more from here, since the function could
495 // overwrite it.
496 result.addSpecialSlice(endOfMatch, subject.length);
497 return result.generate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000498}
499
Kristian Monsen25f61362010-05-21 11:50:48 +0100500
Steve Blocka7e24c12009-10-30 11:49:00 +0000501// ECMA-262 section 15.5.4.12
502function StringSearch(re) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000503 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
504 throw MakeTypeError("called_on_null_or_undefined",
505 ["String.prototype.search"]);
506 }
Steve Block6ded16b2010-05-10 14:33:55 +0100507 var regexp;
508 if (IS_STRING(re)) {
509 regexp = %_GetFromCache(STRING_TO_REGEXP_CACHE_ID, re);
510 } else if (IS_REGEXP(re)) {
511 regexp = re;
512 } else {
513 regexp = new $RegExp(re);
514 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100515 var match = DoRegExpExec(regexp, TO_STRING_INLINE(this), 0);
Steve Block6ded16b2010-05-10 14:33:55 +0100516 if (match) {
517 return match[CAPTURE0];
518 }
519 return -1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000520}
521
522
523// ECMA-262 section 15.5.4.13
524function StringSlice(start, end) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000525 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
526 throw MakeTypeError("called_on_null_or_undefined",
527 ["String.prototype.slice"]);
528 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000529 var s = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000530 var s_len = s.length;
531 var start_i = TO_INTEGER(start);
532 var end_i = s_len;
533 if (end !== void 0)
534 end_i = TO_INTEGER(end);
535
536 if (start_i < 0) {
537 start_i += s_len;
538 if (start_i < 0)
539 start_i = 0;
540 } else {
541 if (start_i > s_len)
542 start_i = s_len;
543 }
544
545 if (end_i < 0) {
546 end_i += s_len;
547 if (end_i < 0)
548 end_i = 0;
549 } else {
550 if (end_i > s_len)
551 end_i = s_len;
552 }
553
554 var num_c = end_i - start_i;
555 if (num_c < 0)
556 num_c = 0;
557
558 return SubString(s, start_i, start_i + num_c);
559}
560
561
562// ECMA-262 section 15.5.4.14
563function StringSplit(separator, limit) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000564 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
565 throw MakeTypeError("called_on_null_or_undefined",
566 ["String.prototype.split"]);
567 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000568 var subject = TO_STRING_INLINE(this);
Leon Clarkee46be812010-01-19 14:06:41 +0000569 limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit);
Steve Blocka7e24c12009-10-30 11:49:00 +0000570 if (limit === 0) return [];
571
572 // ECMA-262 says that if separator is undefined, the result should
573 // be an array of size 1 containing the entire string. SpiderMonkey
Steve Block6ded16b2010-05-10 14:33:55 +0100574 // and KJS have this behavior only when no separator is given. If
Steve Blocka7e24c12009-10-30 11:49:00 +0000575 // undefined is explicitly given, they convert it to a string and
576 // use that. We do as SpiderMonkey and KJS.
577 if (%_ArgumentsLength() === 0) {
578 return [subject];
579 }
580
581 var length = subject.length;
Andrei Popescu402d9372010-02-26 13:31:12 +0000582 if (!IS_REGEXP(separator)) {
583 separator = TO_STRING_INLINE(separator);
584 var separator_length = separator.length;
585
Steve Blocka7e24c12009-10-30 11:49:00 +0000586 // If the separator string is empty then return the elements in the subject.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800587 if (separator_length === 0) return %StringToArray(subject, limit);
Andrei Popescu402d9372010-02-26 13:31:12 +0000588
Steve Block6ded16b2010-05-10 14:33:55 +0100589 var result = %StringSplit(subject, separator, limit);
Andrei Popescu402d9372010-02-26 13:31:12 +0000590
591 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000592 }
593
Andrei Popescu402d9372010-02-26 13:31:12 +0000594 %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
595
Steve Blocka7e24c12009-10-30 11:49:00 +0000596 if (length === 0) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800597 if (DoRegExpExec(separator, subject, 0, 0) != null) {
Steve Block6ded16b2010-05-10 14:33:55 +0100598 return [];
599 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000600 return [subject];
601 }
602
603 var currentIndex = 0;
604 var startIndex = 0;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100605 var startMatch = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000606 var result = [];
607
Steve Block6ded16b2010-05-10 14:33:55 +0100608 outer_loop:
Steve Blocka7e24c12009-10-30 11:49:00 +0000609 while (true) {
610
611 if (startIndex === length) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100612 result.push(SubString(subject, currentIndex, length));
Steve Block6ded16b2010-05-10 14:33:55 +0100613 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000614 }
615
Ben Murdochb0fe1622011-05-05 13:52:32 +0100616 var matchInfo = DoRegExpExec(separator, subject, startIndex);
617 if (matchInfo == null || length === (startMatch = matchInfo[CAPTURE0])) {
618 result.push(SubString(subject, currentIndex, length));
Steve Block6ded16b2010-05-10 14:33:55 +0100619 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000620 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000621 var endIndex = matchInfo[CAPTURE1];
622
623 // We ignore a zero-length match at the currentIndex.
624 if (startIndex === endIndex && endIndex === currentIndex) {
625 startIndex++;
626 continue;
627 }
628
Ben Murdochb0fe1622011-05-05 13:52:32 +0100629 if (currentIndex + 1 == startMatch) {
630 result.push(%_StringCharAt(subject, currentIndex));
631 } else {
632 result.push(%_SubString(subject, currentIndex, startMatch));
633 }
634
Steve Block6ded16b2010-05-10 14:33:55 +0100635 if (result.length === limit) break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000636
Ben Murdochb0fe1622011-05-05 13:52:32 +0100637 var matchinfo_len = NUMBER_OF_CAPTURES(matchInfo) + REGEXP_FIRST_CAPTURE;
638 for (var i = REGEXP_FIRST_CAPTURE + 2; i < matchinfo_len; ) {
639 var start = matchInfo[i++];
640 var end = matchInfo[i++];
641 if (end != -1) {
642 if (start + 1 == end) {
643 result.push(%_StringCharAt(subject, start));
644 } else {
645 result.push(%_SubString(subject, start, end));
646 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000647 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100648 result.push(void 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000649 }
Steve Block6ded16b2010-05-10 14:33:55 +0100650 if (result.length === limit) break outer_loop;
Steve Blocka7e24c12009-10-30 11:49:00 +0000651 }
652
653 startIndex = currentIndex = endIndex;
654 }
Steve Block6ded16b2010-05-10 14:33:55 +0100655 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000656}
657
658
Steve Blocka7e24c12009-10-30 11:49:00 +0000659// ECMA-262 section 15.5.4.15
660function StringSubstring(start, end) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000661 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
662 throw MakeTypeError("called_on_null_or_undefined",
663 ["String.prototype.subString"]);
664 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000665 var s = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000666 var s_len = s.length;
Leon Clarkee46be812010-01-19 14:06:41 +0000667
Steve Blocka7e24c12009-10-30 11:49:00 +0000668 var start_i = TO_INTEGER(start);
Leon Clarkee46be812010-01-19 14:06:41 +0000669 if (start_i < 0) {
670 start_i = 0;
671 } else if (start_i > s_len) {
672 start_i = s_len;
673 }
674
Steve Blocka7e24c12009-10-30 11:49:00 +0000675 var end_i = s_len;
Leon Clarkee46be812010-01-19 14:06:41 +0000676 if (!IS_UNDEFINED(end)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000677 end_i = TO_INTEGER(end);
Leon Clarkee46be812010-01-19 14:06:41 +0000678 if (end_i > s_len) {
679 end_i = s_len;
680 } else {
681 if (end_i < 0) end_i = 0;
682 if (start_i > end_i) {
683 var tmp = end_i;
684 end_i = start_i;
685 start_i = tmp;
686 }
687 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000688 }
689
Ben Murdochb0fe1622011-05-05 13:52:32 +0100690 return (start_i + 1 == end_i
691 ? %_StringCharAt(s, start_i)
692 : %_SubString(s, start_i, end_i));
Steve Blocka7e24c12009-10-30 11:49:00 +0000693}
694
695
696// This is not a part of ECMA-262.
697function StringSubstr(start, n) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000698 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
699 throw MakeTypeError("called_on_null_or_undefined",
700 ["String.prototype.substr"]);
701 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000702 var s = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000703 var len;
704
705 // Correct n: If not given, set to string length; if explicitly
706 // set to undefined, zero, or negative, returns empty string.
707 if (n === void 0) {
708 len = s.length;
709 } else {
710 len = TO_INTEGER(n);
711 if (len <= 0) return '';
712 }
713
714 // Correct start: If not given (or undefined), set to zero; otherwise
715 // convert to integer and handle negative case.
716 if (start === void 0) {
717 start = 0;
718 } else {
719 start = TO_INTEGER(start);
720 // If positive, and greater than or equal to the string length,
721 // return empty string.
722 if (start >= s.length) return '';
723 // If negative and absolute value is larger than the string length,
724 // use zero.
725 if (start < 0) {
726 start += s.length;
727 if (start < 0) start = 0;
728 }
729 }
730
731 var end = start + len;
732 if (end > s.length) end = s.length;
733
Ben Murdochb0fe1622011-05-05 13:52:32 +0100734 return (start + 1 == end
735 ? %_StringCharAt(s, start)
736 : %_SubString(s, start, end));
Steve Blocka7e24c12009-10-30 11:49:00 +0000737}
738
739
740// ECMA-262, 15.5.4.16
741function StringToLowerCase() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000742 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
743 throw MakeTypeError("called_on_null_or_undefined",
744 ["String.prototype.toLowerCase"]);
745 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000746 return %StringToLowerCase(TO_STRING_INLINE(this));
Steve Blocka7e24c12009-10-30 11:49:00 +0000747}
748
749
750// ECMA-262, 15.5.4.17
751function StringToLocaleLowerCase() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000752 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
753 throw MakeTypeError("called_on_null_or_undefined",
754 ["String.prototype.toLocaleLowerCase"]);
755 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000756 return %StringToLowerCase(TO_STRING_INLINE(this));
Steve Blocka7e24c12009-10-30 11:49:00 +0000757}
758
759
760// ECMA-262, 15.5.4.18
761function StringToUpperCase() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000762 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
763 throw MakeTypeError("called_on_null_or_undefined",
764 ["String.prototype.toUpperCase"]);
765 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000766 return %StringToUpperCase(TO_STRING_INLINE(this));
Steve Blocka7e24c12009-10-30 11:49:00 +0000767}
768
769
770// ECMA-262, 15.5.4.19
771function StringToLocaleUpperCase() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000772 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
773 throw MakeTypeError("called_on_null_or_undefined",
774 ["String.prototype.toLocaleUpperCase"]);
775 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000776 return %StringToUpperCase(TO_STRING_INLINE(this));
Steve Blocka7e24c12009-10-30 11:49:00 +0000777}
778
Steve Block3ce2e202009-11-05 08:53:23 +0000779// ES5, 15.5.4.20
780function StringTrim() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000781 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
782 throw MakeTypeError("called_on_null_or_undefined",
783 ["String.prototype.trim"]);
784 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000785 return %StringTrim(TO_STRING_INLINE(this), true, true);
Steve Block3ce2e202009-11-05 08:53:23 +0000786}
787
788function StringTrimLeft() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000789 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
790 throw MakeTypeError("called_on_null_or_undefined",
791 ["String.prototype.trimLeft"]);
792 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000793 return %StringTrim(TO_STRING_INLINE(this), true, false);
Steve Block3ce2e202009-11-05 08:53:23 +0000794}
795
796function StringTrimRight() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000797 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
798 throw MakeTypeError("called_on_null_or_undefined",
799 ["String.prototype.trimRight"]);
800 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000801 return %StringTrim(TO_STRING_INLINE(this), false, true);
Steve Block3ce2e202009-11-05 08:53:23 +0000802}
Steve Blocka7e24c12009-10-30 11:49:00 +0000803
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100804var static_charcode_array = new InternalArray(4);
Steve Block6ded16b2010-05-10 14:33:55 +0100805
Steve Blocka7e24c12009-10-30 11:49:00 +0000806// ECMA-262, section 15.5.3.2
807function StringFromCharCode(code) {
808 var n = %_ArgumentsLength();
Steve Block6ded16b2010-05-10 14:33:55 +0100809 if (n == 1) {
810 if (!%_IsSmi(code)) code = ToNumber(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100811 return %_StringCharFromCode(code & 0xffff);
Steve Block6ded16b2010-05-10 14:33:55 +0100812 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000813
814 // NOTE: This is not super-efficient, but it is necessary because we
815 // want to avoid converting to numbers from within the virtual
816 // machine. Maybe we can find another way of doing this?
Steve Block6ded16b2010-05-10 14:33:55 +0100817 var codes = static_charcode_array;
818 for (var i = 0; i < n; i++) {
819 var code = %_Arguments(i);
820 if (!%_IsSmi(code)) code = ToNumber(code);
821 codes[i] = code;
822 }
823 codes.length = n;
Steve Blocka7e24c12009-10-30 11:49:00 +0000824 return %StringFromCharCodeArray(codes);
825}
826
827
828// Helper function for very basic XSS protection.
829function HtmlEscape(str) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000830 return TO_STRING_INLINE(str).replace(/</g, "&lt;")
831 .replace(/>/g, "&gt;")
832 .replace(/"/g, "&quot;")
833 .replace(/'/g, "&#039;");
Steve Blocka7e24c12009-10-30 11:49:00 +0000834};
835
836
837// Compatibility support for KJS.
838// Tested by mozilla/js/tests/js1_5/Regress/regress-276103.js.
839function StringLink(s) {
840 return "<a href=\"" + HtmlEscape(s) + "\">" + this + "</a>";
841}
842
843
844function StringAnchor(name) {
845 return "<a name=\"" + HtmlEscape(name) + "\">" + this + "</a>";
846}
847
848
849function StringFontcolor(color) {
850 return "<font color=\"" + HtmlEscape(color) + "\">" + this + "</font>";
851}
852
853
854function StringFontsize(size) {
855 return "<font size=\"" + HtmlEscape(size) + "\">" + this + "</font>";
856}
857
858
859function StringBig() {
860 return "<big>" + this + "</big>";
861}
862
863
864function StringBlink() {
865 return "<blink>" + this + "</blink>";
866}
867
868
869function StringBold() {
870 return "<b>" + this + "</b>";
871}
872
873
874function StringFixed() {
875 return "<tt>" + this + "</tt>";
876}
877
878
879function StringItalics() {
880 return "<i>" + this + "</i>";
881}
882
883
884function StringSmall() {
885 return "<small>" + this + "</small>";
886}
887
888
889function StringStrike() {
890 return "<strike>" + this + "</strike>";
891}
892
893
894function StringSub() {
895 return "<sub>" + this + "</sub>";
896}
897
898
899function StringSup() {
900 return "<sup>" + this + "</sup>";
901}
902
903
Leon Clarkee46be812010-01-19 14:06:41 +0000904// ReplaceResultBuilder support.
Steve Blocka7e24c12009-10-30 11:49:00 +0000905function ReplaceResultBuilder(str) {
Steve Block6ded16b2010-05-10 14:33:55 +0100906 if (%_ArgumentsLength() > 1) {
907 this.elements = %_Arguments(1);
908 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100909 this.elements = new InternalArray();
Steve Block6ded16b2010-05-10 14:33:55 +0100910 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000911 this.special_string = str;
912}
913
Ben Murdoch257744e2011-11-30 15:57:28 +0000914ReplaceResultBuilder.prototype.__proto__ = null;
915
Steve Blocka7e24c12009-10-30 11:49:00 +0000916
Leon Clarkee46be812010-01-19 14:06:41 +0000917ReplaceResultBuilder.prototype.add = function(str) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000918 str = TO_STRING_INLINE(str);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100919 if (str.length > 0) this.elements.push(str);
Steve Blocka7e24c12009-10-30 11:49:00 +0000920}
921
922
923ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) {
924 var len = end - start;
Steve Block6ded16b2010-05-10 14:33:55 +0100925 if (start < 0 || len <= 0) return;
Steve Blockd0582a62009-12-15 09:54:21 +0000926 if (start < 0x80000 && len < 0x800) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100927 this.elements.push((start << 11) | len);
Steve Blocka7e24c12009-10-30 11:49:00 +0000928 } else {
Steve Blockd0582a62009-12-15 09:54:21 +0000929 // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
930 // so -len is a smi.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100931 var elements = this.elements;
932 elements.push(-len);
933 elements.push(start);
Steve Blocka7e24c12009-10-30 11:49:00 +0000934 }
935}
936
937
Steve Blocka7e24c12009-10-30 11:49:00 +0000938ReplaceResultBuilder.prototype.generate = function() {
Leon Clarkee46be812010-01-19 14:06:41 +0000939 var elements = this.elements;
940 return %StringBuilderConcat(elements, elements.length, this.special_string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000941}
942
943
Steve Blocka7e24c12009-10-30 11:49:00 +0000944// -------------------------------------------------------------------
945
946function SetupString() {
947 // Setup the constructor property on the String prototype object.
948 %SetProperty($String.prototype, "constructor", $String, DONT_ENUM);
949
950
951 // Setup the non-enumerable functions on the String object.
952 InstallFunctions($String, DONT_ENUM, $Array(
953 "fromCharCode", StringFromCharCode
954 ));
955
956
957 // Setup the non-enumerable functions on the String prototype object.
958 InstallFunctionsOnHiddenPrototype($String.prototype, DONT_ENUM, $Array(
959 "valueOf", StringValueOf,
960 "toString", StringToString,
961 "charAt", StringCharAt,
962 "charCodeAt", StringCharCodeAt,
963 "concat", StringConcat,
964 "indexOf", StringIndexOf,
965 "lastIndexOf", StringLastIndexOf,
966 "localeCompare", StringLocaleCompare,
967 "match", StringMatch,
968 "replace", StringReplace,
969 "search", StringSearch,
970 "slice", StringSlice,
971 "split", StringSplit,
972 "substring", StringSubstring,
973 "substr", StringSubstr,
974 "toLowerCase", StringToLowerCase,
975 "toLocaleLowerCase", StringToLocaleLowerCase,
976 "toUpperCase", StringToUpperCase,
977 "toLocaleUpperCase", StringToLocaleUpperCase,
Steve Block3ce2e202009-11-05 08:53:23 +0000978 "trim", StringTrim,
979 "trimLeft", StringTrimLeft,
980 "trimRight", StringTrimRight,
Steve Blocka7e24c12009-10-30 11:49:00 +0000981 "link", StringLink,
982 "anchor", StringAnchor,
983 "fontcolor", StringFontcolor,
984 "fontsize", StringFontsize,
985 "big", StringBig,
986 "blink", StringBlink,
987 "bold", StringBold,
988 "fixed", StringFixed,
989 "italics", StringItalics,
990 "small", StringSmall,
991 "strike", StringStrike,
992 "sub", StringSub,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100993 "sup", StringSup
Steve Blocka7e24c12009-10-30 11:49:00 +0000994 ));
995}
996
997
998SetupString();