blob: 84dde3dc27f5ce040787c5962d7676865c165d7f [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 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:
Ben Murdoch3ef787d2012-04-12 10:51:47 +010031// var $String = global.String;
32// var $NaN = 0/0;
Steve Blocka7e24c12009-10-30 11:49:00 +000033
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() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010049 if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000050 throw new $TypeError('String.prototype.toString is not generic');
Ben Murdoch3ef787d2012-04-12 10:51:47 +010051 }
Steve Blocka7e24c12009-10-30 11:49:00 +000052 return %_ValueOf(this);
53}
54
55
56// ECMA-262 section 15.5.4.3
57function StringValueOf() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010058 if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000059 throw new $TypeError('String.prototype.valueOf is not generic');
Ben Murdoch3ef787d2012-04-12 10:51:47 +010060 }
Steve Blocka7e24c12009-10-30 11:49:00 +000061 return %_ValueOf(this);
62}
63
64
65// ECMA-262, section 15.5.4.4
66function StringCharAt(pos) {
Ben Murdoch257744e2011-11-30 15:57:28 +000067 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
68 throw MakeTypeError("called_on_null_or_undefined",
69 ["String.prototype.charAt"]);
70 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010071 var result = %_StringCharAt(this, pos);
72 if (%_IsSmi(result)) {
73 result = %_StringCharAt(TO_STRING_INLINE(this), TO_INTEGER(pos));
Steve Blocka7e24c12009-10-30 11:49:00 +000074 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010075 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000076}
77
78
79// ECMA-262 section 15.5.4.5
80function StringCharCodeAt(pos) {
Ben Murdoch257744e2011-11-30 15:57:28 +000081 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
82 throw MakeTypeError("called_on_null_or_undefined",
83 ["String.prototype.charCodeAt"]);
84 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010085 var result = %_StringCharCodeAt(this, pos);
86 if (!%_IsSmi(result)) {
87 result = %_StringCharCodeAt(TO_STRING_INLINE(this), TO_INTEGER(pos));
Steve Blocka7e24c12009-10-30 11:49:00 +000088 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010089 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000090}
91
92
93// ECMA-262, section 15.5.4.6
94function StringConcat() {
Ben Murdoch257744e2011-11-30 15:57:28 +000095 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010096 throw MakeTypeError("called_on_null_or_undefined",
97 ["String.prototype.concat"]);
Ben Murdoch257744e2011-11-30 15:57:28 +000098 }
Andrei Popescu402d9372010-02-26 13:31:12 +000099 var len = %_ArgumentsLength();
100 var this_as_string = TO_STRING_INLINE(this);
101 if (len === 1) {
102 return this_as_string + %_Arguments(0);
Leon Clarkee46be812010-01-19 14:06:41 +0000103 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100104 var parts = new InternalArray(len + 1);
Andrei Popescu402d9372010-02-26 13:31:12 +0000105 parts[0] = this_as_string;
106 for (var i = 0; i < len; i++) {
107 var part = %_Arguments(i);
108 parts[i + 1] = TO_STRING_INLINE(part);
109 }
110 return %StringBuilderConcat(parts, len + 1, "");
Steve Blocka7e24c12009-10-30 11:49:00 +0000111}
112
113// Match ES3 and Safari
114%FunctionSetLength(StringConcat, 1);
115
116
117// ECMA-262 section 15.5.4.7
Ben Murdochb0fe1622011-05-05 13:52:32 +0100118function StringIndexOf(pattern /* position */) { // length == 1
Ben Murdoch257744e2011-11-30 15:57:28 +0000119 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
120 throw MakeTypeError("called_on_null_or_undefined",
121 ["String.prototype.indexOf"]);
122 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100123 var subject = TO_STRING_INLINE(this);
Steve Block1e0659c2011-05-24 12:43:12 +0100124 pattern = TO_STRING_INLINE(pattern);
Steve Blocka7e24c12009-10-30 11:49:00 +0000125 var index = 0;
126 if (%_ArgumentsLength() > 1) {
Steve Block1e0659c2011-05-24 12:43:12 +0100127 index = %_Arguments(1); // position
128 index = TO_INTEGER(index);
129 if (index < 0) index = 0;
130 if (index > subject.length) index = subject.length;
Steve Blocka7e24c12009-10-30 11:49:00 +0000131 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100132 return %StringIndexOf(subject, pattern, index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000133}
134
135
136// ECMA-262 section 15.5.4.8
Ben Murdochb0fe1622011-05-05 13:52:32 +0100137function StringLastIndexOf(pat /* position */) { // length == 1
Ben Murdoch257744e2011-11-30 15:57:28 +0000138 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
139 throw MakeTypeError("called_on_null_or_undefined",
140 ["String.prototype.lastIndexOf"]);
141 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000142 var sub = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000143 var subLength = sub.length;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100144 var pat = TO_STRING_INLINE(pat);
Steve Blocka7e24c12009-10-30 11:49:00 +0000145 var patLength = pat.length;
146 var index = subLength - patLength;
147 if (%_ArgumentsLength() > 1) {
148 var position = ToNumber(%_Arguments(1));
Steve Block9fac8402011-05-12 15:51:54 +0100149 if (!NUMBER_IS_NAN(position)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000150 position = TO_INTEGER(position);
151 if (position < 0) {
152 position = 0;
153 }
154 if (position + patLength < subLength) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000155 index = position;
Steve Blocka7e24c12009-10-30 11:49:00 +0000156 }
157 }
158 }
159 if (index < 0) {
160 return -1;
161 }
162 return %StringLastIndexOf(sub, pat, index);
163}
164
165
166// ECMA-262 section 15.5.4.9
167//
168// This function is implementation specific. For now, we do not
169// do anything locale specific.
170function StringLocaleCompare(other) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000171 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
172 throw MakeTypeError("called_on_null_or_undefined",
173 ["String.prototype.localeCompare"]);
174 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000175 if (%_ArgumentsLength() === 0) return 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000176 return %StringLocaleCompare(TO_STRING_INLINE(this),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100177 TO_STRING_INLINE(other));
Steve Blocka7e24c12009-10-30 11:49:00 +0000178}
179
180
181// ECMA-262 section 15.5.4.10
182function StringMatch(regexp) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000183 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
184 throw MakeTypeError("called_on_null_or_undefined",
185 ["String.prototype.match"]);
186 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000187 var subject = TO_STRING_INLINE(this);
Steve Block6ded16b2010-05-10 14:33:55 +0100188 if (IS_REGEXP(regexp)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100189 if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0);
Steve Block6ded16b2010-05-10 14:33:55 +0100190 %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
191 // lastMatchInfo is defined in regexp.js.
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800192 return %StringMatch(subject, regexp, lastMatchInfo);
Steve Block6ded16b2010-05-10 14:33:55 +0100193 }
194 // Non-regexp argument.
195 regexp = new $RegExp(regexp);
Steve Block6ded16b2010-05-10 14:33:55 +0100196 return RegExpExecNoTests(regexp, subject, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000197}
198
199
200// SubString is an internal function that returns the sub string of 'string'.
201// If resulting string is of length 1, we use the one character cache
202// otherwise we call the runtime system.
203function SubString(string, start, end) {
204 // Use the one character string cache.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100205 if (start + 1 == end) return %_StringCharAt(string, start);
Leon Clarkee46be812010-01-19 14:06:41 +0000206 return %_SubString(string, start, end);
Steve Blocka7e24c12009-10-30 11:49:00 +0000207}
208
209
210// This has the same size as the lastMatchInfo array, and can be used for
211// functions that expect that structure to be returned. It is used when the
212// needle is a string rather than a regexp. In this case we can't update
213// lastMatchArray without erroneously affecting the properties on the global
214// RegExp object.
215var reusableMatchInfo = [2, "", "", -1, -1];
216
217
218// ECMA-262, section 15.5.4.11
219function StringReplace(search, replace) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000220 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
221 throw MakeTypeError("called_on_null_or_undefined",
222 ["String.prototype.replace"]);
223 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000224 var subject = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000225
226 // Delegate to one of the regular expression variants if necessary.
227 if (IS_REGEXP(search)) {
228 %_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
Ben Murdoch589d6972011-11-30 16:04:58 +0000229 if (IS_SPEC_FUNCTION(replace)) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100230 if (search.global) {
231 return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
232 } else {
233 return StringReplaceNonGlobalRegExpWithFunction(subject,
234 search,
235 replace);
236 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000237 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100238 return %StringReplaceRegExpWithString(subject,
239 search,
240 TO_STRING_INLINE(replace),
241 lastMatchInfo);
Steve Blocka7e24c12009-10-30 11:49:00 +0000242 }
243 }
244
245 // Convert the search argument to a string and search for it.
Andrei Popescu402d9372010-02-26 13:31:12 +0000246 search = TO_STRING_INLINE(search);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100247 if (search.length == 1 &&
248 subject.length > 0xFF &&
249 IS_STRING(replace) &&
250 %StringIndexOf(replace, '$', 0) < 0) {
251 // Searching by traversing a cons string tree and replace with cons of
252 // slices works only when the replaced string is a single character, being
253 // replaced by a simple string and only pays off for long strings.
254 return %StringReplaceOneCharWithString(subject, search, replace);
255 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000256 var start = %StringIndexOf(subject, search, 0);
257 if (start < 0) return subject;
258 var end = start + search.length;
259
260 var builder = new ReplaceResultBuilder(subject);
261 // prefix
262 builder.addSpecialSlice(0, start);
263
264 // Compute the string to replace with.
Ben Murdoch589d6972011-11-30 16:04:58 +0000265 if (IS_SPEC_FUNCTION(replace)) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000266 var receiver = %GetDefaultReceiver(replace);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000267 builder.add(%_CallFunction(receiver,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100268 search,
269 start,
270 subject,
271 replace));
Steve Blocka7e24c12009-10-30 11:49:00 +0000272 } else {
273 reusableMatchInfo[CAPTURE0] = start;
274 reusableMatchInfo[CAPTURE1] = end;
Andrei Popescu402d9372010-02-26 13:31:12 +0000275 replace = TO_STRING_INLINE(replace);
Leon Clarkee46be812010-01-19 14:06:41 +0000276 ExpandReplacement(replace, subject, reusableMatchInfo, builder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000277 }
278
279 // suffix
280 builder.addSpecialSlice(end, subject.length);
281
282 return builder.generate();
283}
284
285
Steve Blocka7e24c12009-10-30 11:49:00 +0000286// Expand the $-expressions in the string and return a new string with
287// the result.
288function ExpandReplacement(string, subject, matchInfo, builder) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100289 var length = string.length;
Ben Murdoch257744e2011-11-30 15:57:28 +0000290 var builder_elements = builder.elements;
Steve Blocka7e24c12009-10-30 11:49:00 +0000291 var next = %StringIndexOf(string, '$', 0);
292 if (next < 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100293 if (length > 0) builder_elements.push(string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000294 return;
295 }
296
297 // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102.
298 var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; // Includes the match.
299
Ben Murdochb0fe1622011-05-05 13:52:32 +0100300 if (next > 0) builder_elements.push(SubString(string, 0, next));
Steve Blocka7e24c12009-10-30 11:49:00 +0000301
302 while (true) {
303 var expansion = '$';
304 var position = next + 1;
305 if (position < length) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100306 var peek = %_StringCharCodeAt(string, position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000307 if (peek == 36) { // $$
308 ++position;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100309 builder_elements.push('$');
Steve Blocka7e24c12009-10-30 11:49:00 +0000310 } else if (peek == 38) { // $& - match
311 ++position;
312 builder.addSpecialSlice(matchInfo[CAPTURE0],
313 matchInfo[CAPTURE1]);
314 } else if (peek == 96) { // $` - prefix
315 ++position;
316 builder.addSpecialSlice(0, matchInfo[CAPTURE0]);
317 } else if (peek == 39) { // $' - suffix
318 ++position;
319 builder.addSpecialSlice(matchInfo[CAPTURE1], subject.length);
320 } else if (peek >= 48 && peek <= 57) { // $n, 0 <= n <= 9
321 ++position;
322 var n = peek - 48;
323 if (position < length) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100324 peek = %_StringCharCodeAt(string, position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000325 // $nn, 01 <= nn <= 99
326 if (n != 0 && peek == 48 || peek >= 49 && peek <= 57) {
327 var nn = n * 10 + (peek - 48);
328 if (nn < m) {
329 // If the two digit capture reference is within range of
330 // the captures, we use it instead of the single digit
331 // one. Otherwise, we fall back to using the single
332 // digit reference. This matches the behavior of
333 // SpiderMonkey.
334 ++position;
335 n = nn;
336 }
337 }
338 }
339 if (0 < n && n < m) {
340 addCaptureString(builder, matchInfo, n);
341 } else {
342 // Because of the captures range check in the parsing of two
343 // digit capture references, we can only enter here when a
344 // single digit capture reference is outside the range of
345 // captures.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100346 builder_elements.push('$');
Steve Blocka7e24c12009-10-30 11:49:00 +0000347 --position;
348 }
349 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100350 builder_elements.push('$');
Steve Blocka7e24c12009-10-30 11:49:00 +0000351 }
352 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100353 builder_elements.push('$');
Steve Blocka7e24c12009-10-30 11:49:00 +0000354 }
355
356 // Go the the next $ in the string.
357 next = %StringIndexOf(string, '$', position);
358
359 // Return if there are no more $ characters in the string. If we
360 // haven't reached the end, we need to append the suffix.
361 if (next < 0) {
362 if (position < length) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100363 builder_elements.push(SubString(string, position, length));
Steve Blocka7e24c12009-10-30 11:49:00 +0000364 }
365 return;
366 }
367
368 // Append substring between the previous and the next $ character.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100369 if (next > position) {
370 builder_elements.push(SubString(string, position, next));
371 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000372 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100373}
Steve Blocka7e24c12009-10-30 11:49:00 +0000374
375
376// Compute the string of a given regular expression capture.
377function CaptureString(string, lastCaptureInfo, index) {
378 // Scale the index.
379 var scaled = index << 1;
380 // Compute start and end.
381 var start = lastCaptureInfo[CAPTURE(scaled)];
Kristian Monsen25f61362010-05-21 11:50:48 +0100382 // If start isn't valid, return undefined.
383 if (start < 0) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000384 var end = lastCaptureInfo[CAPTURE(scaled + 1)];
Steve Blocka7e24c12009-10-30 11:49:00 +0000385 return SubString(string, start, end);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100386}
Steve Blocka7e24c12009-10-30 11:49:00 +0000387
388
389// Add the string of a given regular expression capture to the
390// ReplaceResultBuilder
391function addCaptureString(builder, matchInfo, index) {
392 // Scale the index.
393 var scaled = index << 1;
394 // Compute start and end.
395 var start = matchInfo[CAPTURE(scaled)];
Kristian Monsen25f61362010-05-21 11:50:48 +0100396 if (start < 0) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000397 var end = matchInfo[CAPTURE(scaled + 1)];
Steve Blocka7e24c12009-10-30 11:49:00 +0000398 builder.addSpecialSlice(start, end);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100399}
Steve Blocka7e24c12009-10-30 11:49:00 +0000400
Steve Block6ded16b2010-05-10 14:33:55 +0100401// TODO(lrn): This array will survive indefinitely if replace is never
402// called again. However, it will be empty, since the contents are cleared
403// in the finally block.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100404var reusableReplaceArray = new InternalArray(16);
Steve Blocka7e24c12009-10-30 11:49:00 +0000405
406// Helper function for replacing regular expressions with the result of a
Steve Block6ded16b2010-05-10 14:33:55 +0100407// function application in String.prototype.replace.
Kristian Monsen25f61362010-05-21 11:50:48 +0100408function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
409 var resultArray = reusableReplaceArray;
410 if (resultArray) {
411 reusableReplaceArray = null;
412 } else {
413 // Inside a nested replace (replace called from the replacement function
414 // of another replace) or we have failed to set the reusable array
415 // back due to an exception in a replacement function. Create a new
416 // array to use in the future, or until the original is written back.
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100417 resultArray = new InternalArray(16);
Steve Blocka7e24c12009-10-30 11:49:00 +0000418 }
Kristian Monsen25f61362010-05-21 11:50:48 +0100419 var res = %RegExpExecMultiple(regexp,
420 subject,
421 lastMatchInfo,
422 resultArray);
423 regexp.lastIndex = 0;
424 if (IS_NULL(res)) {
425 // No matches at all.
426 reusableReplaceArray = resultArray;
427 return subject;
428 }
429 var len = res.length;
430 var i = 0;
431 if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
432 var match_start = 0;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100433 var override = new InternalArray(null, 0, subject);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000434 var receiver = %GetDefaultReceiver(replace);
Kristian Monsen25f61362010-05-21 11:50:48 +0100435 while (i < len) {
436 var elem = res[i];
437 if (%_IsSmi(elem)) {
438 if (elem > 0) {
439 match_start = (elem >> 11) + (elem & 0x7ff);
440 } else {
441 match_start = res[++i] - elem;
442 }
443 } else {
444 override[0] = elem;
445 override[1] = match_start;
446 lastMatchInfoOverride = override;
447 var func_result =
448 %_CallFunction(receiver, elem, match_start, subject, replace);
Steve Block1e0659c2011-05-24 12:43:12 +0100449 res[i] = TO_STRING_INLINE(func_result);
Kristian Monsen25f61362010-05-21 11:50:48 +0100450 match_start += elem.length;
451 }
452 i++;
453 }
454 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +0000455 var receiver = %GetDefaultReceiver(replace);
Kristian Monsen25f61362010-05-21 11:50:48 +0100456 while (i < len) {
457 var elem = res[i];
458 if (!%_IsSmi(elem)) {
459 // elem must be an Array.
460 // Use the apply argument as backing for global RegExp properties.
461 lastMatchInfoOverride = elem;
Ben Murdoch589d6972011-11-30 16:04:58 +0000462 var func_result = %Apply(replace, receiver, elem, 0, elem.length);
Steve Block1e0659c2011-05-24 12:43:12 +0100463 res[i] = TO_STRING_INLINE(func_result);
Kristian Monsen25f61362010-05-21 11:50:48 +0100464 }
465 i++;
466 }
467 }
468 var resultBuilder = new ReplaceResultBuilder(subject, res);
469 var result = resultBuilder.generate();
470 resultArray.length = 0;
471 reusableReplaceArray = resultArray;
472 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000473}
474
475
Kristian Monsen25f61362010-05-21 11:50:48 +0100476function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
477 var matchInfo = DoRegExpExec(regexp, subject, 0);
478 if (IS_NULL(matchInfo)) return subject;
479 var result = new ReplaceResultBuilder(subject);
480 var index = matchInfo[CAPTURE0];
481 result.addSpecialSlice(0, index);
482 var endOfMatch = matchInfo[CAPTURE1];
Steve Blocka7e24c12009-10-30 11:49:00 +0000483 // Compute the parameter list consisting of the match, captures, index,
484 // and subject for the replace function invocation.
Steve Blocka7e24c12009-10-30 11:49:00 +0000485 // The number of captures plus one for the match.
486 var m = NUMBER_OF_CAPTURES(matchInfo) >> 1;
Kristian Monsen25f61362010-05-21 11:50:48 +0100487 var replacement;
Ben Murdoch589d6972011-11-30 16:04:58 +0000488 var receiver = %GetDefaultReceiver(replace);
Steve Blocka7e24c12009-10-30 11:49:00 +0000489 if (m == 1) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100490 // No captures, only the match, which is always valid.
491 var s = SubString(subject, index, endOfMatch);
Steve Blocka7e24c12009-10-30 11:49:00 +0000492 // Don't call directly to avoid exposing the built-in global object.
Kristian Monsen25f61362010-05-21 11:50:48 +0100493 replacement =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000494 %_CallFunction(receiver, s, index, subject, replace);
Kristian Monsen25f61362010-05-21 11:50:48 +0100495 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100496 var parameters = new InternalArray(m + 2);
Kristian Monsen25f61362010-05-21 11:50:48 +0100497 for (var j = 0; j < m; j++) {
498 parameters[j] = CaptureString(subject, matchInfo, j);
499 }
500 parameters[j] = index;
501 parameters[j + 1] = subject;
502
Ben Murdoch589d6972011-11-30 16:04:58 +0000503 replacement = %Apply(replace, receiver, parameters, 0, j + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000504 }
Kristian Monsen25f61362010-05-21 11:50:48 +0100505
506 result.add(replacement); // The add method converts to string if necessary.
507 // Can't use matchInfo any more from here, since the function could
508 // overwrite it.
509 result.addSpecialSlice(endOfMatch, subject.length);
510 return result.generate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000511}
512
Kristian Monsen25f61362010-05-21 11:50:48 +0100513
Steve Blocka7e24c12009-10-30 11:49:00 +0000514// ECMA-262 section 15.5.4.12
515function StringSearch(re) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000516 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
517 throw MakeTypeError("called_on_null_or_undefined",
518 ["String.prototype.search"]);
519 }
Steve Block6ded16b2010-05-10 14:33:55 +0100520 var regexp;
521 if (IS_STRING(re)) {
522 regexp = %_GetFromCache(STRING_TO_REGEXP_CACHE_ID, re);
523 } else if (IS_REGEXP(re)) {
524 regexp = re;
525 } else {
526 regexp = new $RegExp(re);
527 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100528 var match = DoRegExpExec(regexp, TO_STRING_INLINE(this), 0);
Steve Block6ded16b2010-05-10 14:33:55 +0100529 if (match) {
530 return match[CAPTURE0];
531 }
532 return -1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000533}
534
535
536// ECMA-262 section 15.5.4.13
537function StringSlice(start, end) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000538 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
539 throw MakeTypeError("called_on_null_or_undefined",
540 ["String.prototype.slice"]);
541 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000542 var s = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000543 var s_len = s.length;
544 var start_i = TO_INTEGER(start);
545 var end_i = s_len;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100546 if (end !== void 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000547 end_i = TO_INTEGER(end);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100548 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000549
550 if (start_i < 0) {
551 start_i += s_len;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100552 if (start_i < 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000553 start_i = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100554 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000555 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100556 if (start_i > s_len) {
557 return '';
558 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000559 }
560
561 if (end_i < 0) {
562 end_i += s_len;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100563 if (end_i < 0) {
564 return '';
565 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000566 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100567 if (end_i > s_len) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000568 end_i = s_len;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100569 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000570 }
571
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100572 if (end_i <= start_i) {
573 return '';
574 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000575
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100576 return SubString(s, start_i, end_i);
Steve Blocka7e24c12009-10-30 11:49:00 +0000577}
578
579
580// ECMA-262 section 15.5.4.14
581function StringSplit(separator, limit) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000582 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
583 throw MakeTypeError("called_on_null_or_undefined",
584 ["String.prototype.split"]);
585 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000586 var subject = TO_STRING_INLINE(this);
Leon Clarkee46be812010-01-19 14:06:41 +0000587 limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit);
Steve Blocka7e24c12009-10-30 11:49:00 +0000588
589 // ECMA-262 says that if separator is undefined, the result should
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100590 // be an array of size 1 containing the entire string.
591 if (IS_UNDEFINED(separator)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000592 return [subject];
593 }
594
595 var length = subject.length;
Andrei Popescu402d9372010-02-26 13:31:12 +0000596 if (!IS_REGEXP(separator)) {
597 separator = TO_STRING_INLINE(separator);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100598
599 if (limit === 0) return [];
600
Andrei Popescu402d9372010-02-26 13:31:12 +0000601 var separator_length = separator.length;
602
Steve Blocka7e24c12009-10-30 11:49:00 +0000603 // If the separator string is empty then return the elements in the subject.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800604 if (separator_length === 0) return %StringToArray(subject, limit);
Andrei Popescu402d9372010-02-26 13:31:12 +0000605
Steve Block6ded16b2010-05-10 14:33:55 +0100606 var result = %StringSplit(subject, separator, limit);
Andrei Popescu402d9372010-02-26 13:31:12 +0000607
608 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000609 }
610
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100611 if (limit === 0) return [];
612
613 // Separator is a regular expression.
614 return StringSplitOnRegExp(subject, separator, limit, length);
615}
616
617
618function StringSplitOnRegExp(subject, separator, limit, length) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000619 %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
620
Steve Blocka7e24c12009-10-30 11:49:00 +0000621 if (length === 0) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800622 if (DoRegExpExec(separator, subject, 0, 0) != null) {
Steve Block6ded16b2010-05-10 14:33:55 +0100623 return [];
624 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000625 return [subject];
626 }
627
628 var currentIndex = 0;
629 var startIndex = 0;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100630 var startMatch = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000631 var result = [];
632
Steve Block6ded16b2010-05-10 14:33:55 +0100633 outer_loop:
Steve Blocka7e24c12009-10-30 11:49:00 +0000634 while (true) {
635
636 if (startIndex === length) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100637 result.push(SubString(subject, currentIndex, length));
Steve Block6ded16b2010-05-10 14:33:55 +0100638 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000639 }
640
Ben Murdochb0fe1622011-05-05 13:52:32 +0100641 var matchInfo = DoRegExpExec(separator, subject, startIndex);
642 if (matchInfo == null || length === (startMatch = matchInfo[CAPTURE0])) {
643 result.push(SubString(subject, currentIndex, length));
Steve Block6ded16b2010-05-10 14:33:55 +0100644 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000645 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000646 var endIndex = matchInfo[CAPTURE1];
647
648 // We ignore a zero-length match at the currentIndex.
649 if (startIndex === endIndex && endIndex === currentIndex) {
650 startIndex++;
651 continue;
652 }
653
Ben Murdochb0fe1622011-05-05 13:52:32 +0100654 if (currentIndex + 1 == startMatch) {
655 result.push(%_StringCharAt(subject, currentIndex));
656 } else {
657 result.push(%_SubString(subject, currentIndex, startMatch));
658 }
659
Steve Block6ded16b2010-05-10 14:33:55 +0100660 if (result.length === limit) break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000661
Ben Murdochb0fe1622011-05-05 13:52:32 +0100662 var matchinfo_len = NUMBER_OF_CAPTURES(matchInfo) + REGEXP_FIRST_CAPTURE;
663 for (var i = REGEXP_FIRST_CAPTURE + 2; i < matchinfo_len; ) {
664 var start = matchInfo[i++];
665 var end = matchInfo[i++];
666 if (end != -1) {
667 if (start + 1 == end) {
668 result.push(%_StringCharAt(subject, start));
669 } else {
670 result.push(%_SubString(subject, start, end));
671 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000672 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100673 result.push(void 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000674 }
Steve Block6ded16b2010-05-10 14:33:55 +0100675 if (result.length === limit) break outer_loop;
Steve Blocka7e24c12009-10-30 11:49:00 +0000676 }
677
678 startIndex = currentIndex = endIndex;
679 }
Steve Block6ded16b2010-05-10 14:33:55 +0100680 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000681}
682
683
Steve Blocka7e24c12009-10-30 11:49:00 +0000684// ECMA-262 section 15.5.4.15
685function StringSubstring(start, end) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000686 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
687 throw MakeTypeError("called_on_null_or_undefined",
688 ["String.prototype.subString"]);
689 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000690 var s = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000691 var s_len = s.length;
Leon Clarkee46be812010-01-19 14:06:41 +0000692
Steve Blocka7e24c12009-10-30 11:49:00 +0000693 var start_i = TO_INTEGER(start);
Leon Clarkee46be812010-01-19 14:06:41 +0000694 if (start_i < 0) {
695 start_i = 0;
696 } else if (start_i > s_len) {
697 start_i = s_len;
698 }
699
Steve Blocka7e24c12009-10-30 11:49:00 +0000700 var end_i = s_len;
Leon Clarkee46be812010-01-19 14:06:41 +0000701 if (!IS_UNDEFINED(end)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000702 end_i = TO_INTEGER(end);
Leon Clarkee46be812010-01-19 14:06:41 +0000703 if (end_i > s_len) {
704 end_i = s_len;
705 } else {
706 if (end_i < 0) end_i = 0;
707 if (start_i > end_i) {
708 var tmp = end_i;
709 end_i = start_i;
710 start_i = tmp;
711 }
712 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000713 }
714
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100715 return ((start_i + 1 == end_i)
Ben Murdochb0fe1622011-05-05 13:52:32 +0100716 ? %_StringCharAt(s, start_i)
717 : %_SubString(s, start_i, end_i));
Steve Blocka7e24c12009-10-30 11:49:00 +0000718}
719
720
721// This is not a part of ECMA-262.
722function StringSubstr(start, n) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000723 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
724 throw MakeTypeError("called_on_null_or_undefined",
725 ["String.prototype.substr"]);
726 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000727 var s = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000728 var len;
729
730 // Correct n: If not given, set to string length; if explicitly
731 // set to undefined, zero, or negative, returns empty string.
732 if (n === void 0) {
733 len = s.length;
734 } else {
735 len = TO_INTEGER(n);
736 if (len <= 0) return '';
737 }
738
739 // Correct start: If not given (or undefined), set to zero; otherwise
740 // convert to integer and handle negative case.
741 if (start === void 0) {
742 start = 0;
743 } else {
744 start = TO_INTEGER(start);
745 // If positive, and greater than or equal to the string length,
746 // return empty string.
747 if (start >= s.length) return '';
748 // If negative and absolute value is larger than the string length,
749 // use zero.
750 if (start < 0) {
751 start += s.length;
752 if (start < 0) start = 0;
753 }
754 }
755
756 var end = start + len;
757 if (end > s.length) end = s.length;
758
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100759 return ((start + 1 == end)
Ben Murdochb0fe1622011-05-05 13:52:32 +0100760 ? %_StringCharAt(s, start)
761 : %_SubString(s, start, end));
Steve Blocka7e24c12009-10-30 11:49:00 +0000762}
763
764
765// ECMA-262, 15.5.4.16
766function StringToLowerCase() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000767 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
768 throw MakeTypeError("called_on_null_or_undefined",
769 ["String.prototype.toLowerCase"]);
770 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000771 return %StringToLowerCase(TO_STRING_INLINE(this));
Steve Blocka7e24c12009-10-30 11:49:00 +0000772}
773
774
775// ECMA-262, 15.5.4.17
776function StringToLocaleLowerCase() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000777 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
778 throw MakeTypeError("called_on_null_or_undefined",
779 ["String.prototype.toLocaleLowerCase"]);
780 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000781 return %StringToLowerCase(TO_STRING_INLINE(this));
Steve Blocka7e24c12009-10-30 11:49:00 +0000782}
783
784
785// ECMA-262, 15.5.4.18
786function StringToUpperCase() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000787 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
788 throw MakeTypeError("called_on_null_or_undefined",
789 ["String.prototype.toUpperCase"]);
790 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000791 return %StringToUpperCase(TO_STRING_INLINE(this));
Steve Blocka7e24c12009-10-30 11:49:00 +0000792}
793
794
795// ECMA-262, 15.5.4.19
796function StringToLocaleUpperCase() {
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.toLocaleUpperCase"]);
800 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000801 return %StringToUpperCase(TO_STRING_INLINE(this));
Steve Blocka7e24c12009-10-30 11:49:00 +0000802}
803
Steve Block3ce2e202009-11-05 08:53:23 +0000804// ES5, 15.5.4.20
805function StringTrim() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000806 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
807 throw MakeTypeError("called_on_null_or_undefined",
808 ["String.prototype.trim"]);
809 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000810 return %StringTrim(TO_STRING_INLINE(this), true, true);
Steve Block3ce2e202009-11-05 08:53:23 +0000811}
812
813function StringTrimLeft() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000814 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
815 throw MakeTypeError("called_on_null_or_undefined",
816 ["String.prototype.trimLeft"]);
817 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000818 return %StringTrim(TO_STRING_INLINE(this), true, false);
Steve Block3ce2e202009-11-05 08:53:23 +0000819}
820
821function StringTrimRight() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000822 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
823 throw MakeTypeError("called_on_null_or_undefined",
824 ["String.prototype.trimRight"]);
825 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000826 return %StringTrim(TO_STRING_INLINE(this), false, true);
Steve Block3ce2e202009-11-05 08:53:23 +0000827}
Steve Blocka7e24c12009-10-30 11:49:00 +0000828
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100829var static_charcode_array = new InternalArray(4);
Steve Block6ded16b2010-05-10 14:33:55 +0100830
Steve Blocka7e24c12009-10-30 11:49:00 +0000831// ECMA-262, section 15.5.3.2
832function StringFromCharCode(code) {
833 var n = %_ArgumentsLength();
Steve Block6ded16b2010-05-10 14:33:55 +0100834 if (n == 1) {
835 if (!%_IsSmi(code)) code = ToNumber(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100836 return %_StringCharFromCode(code & 0xffff);
Steve Block6ded16b2010-05-10 14:33:55 +0100837 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000838
839 // NOTE: This is not super-efficient, but it is necessary because we
840 // want to avoid converting to numbers from within the virtual
841 // machine. Maybe we can find another way of doing this?
Steve Block6ded16b2010-05-10 14:33:55 +0100842 var codes = static_charcode_array;
843 for (var i = 0; i < n; i++) {
844 var code = %_Arguments(i);
845 if (!%_IsSmi(code)) code = ToNumber(code);
846 codes[i] = code;
847 }
848 codes.length = n;
Steve Blocka7e24c12009-10-30 11:49:00 +0000849 return %StringFromCharCodeArray(codes);
850}
851
852
853// Helper function for very basic XSS protection.
854function HtmlEscape(str) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000855 return TO_STRING_INLINE(str).replace(/</g, "&lt;")
856 .replace(/>/g, "&gt;")
857 .replace(/"/g, "&quot;")
858 .replace(/'/g, "&#039;");
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100859}
Steve Blocka7e24c12009-10-30 11:49:00 +0000860
861
862// Compatibility support for KJS.
863// Tested by mozilla/js/tests/js1_5/Regress/regress-276103.js.
864function StringLink(s) {
865 return "<a href=\"" + HtmlEscape(s) + "\">" + this + "</a>";
866}
867
868
869function StringAnchor(name) {
870 return "<a name=\"" + HtmlEscape(name) + "\">" + this + "</a>";
871}
872
873
874function StringFontcolor(color) {
875 return "<font color=\"" + HtmlEscape(color) + "\">" + this + "</font>";
876}
877
878
879function StringFontsize(size) {
880 return "<font size=\"" + HtmlEscape(size) + "\">" + this + "</font>";
881}
882
883
884function StringBig() {
885 return "<big>" + this + "</big>";
886}
887
888
889function StringBlink() {
890 return "<blink>" + this + "</blink>";
891}
892
893
894function StringBold() {
895 return "<b>" + this + "</b>";
896}
897
898
899function StringFixed() {
900 return "<tt>" + this + "</tt>";
901}
902
903
904function StringItalics() {
905 return "<i>" + this + "</i>";
906}
907
908
909function StringSmall() {
910 return "<small>" + this + "</small>";
911}
912
913
914function StringStrike() {
915 return "<strike>" + this + "</strike>";
916}
917
918
919function StringSub() {
920 return "<sub>" + this + "</sub>";
921}
922
923
924function StringSup() {
925 return "<sup>" + this + "</sup>";
926}
927
928
Leon Clarkee46be812010-01-19 14:06:41 +0000929// ReplaceResultBuilder support.
Steve Blocka7e24c12009-10-30 11:49:00 +0000930function ReplaceResultBuilder(str) {
Steve Block6ded16b2010-05-10 14:33:55 +0100931 if (%_ArgumentsLength() > 1) {
932 this.elements = %_Arguments(1);
933 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100934 this.elements = new InternalArray();
Steve Block6ded16b2010-05-10 14:33:55 +0100935 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000936 this.special_string = str;
937}
938
Ben Murdoch589d6972011-11-30 16:04:58 +0000939SetUpLockedPrototype(ReplaceResultBuilder,
940 $Array("elements", "special_string"), $Array(
941 "add", function(str) {
942 str = TO_STRING_INLINE(str);
943 if (str.length > 0) this.elements.push(str);
944 },
945 "addSpecialSlice", function(start, end) {
946 var len = end - start;
947 if (start < 0 || len <= 0) return;
948 if (start < 0x80000 && len < 0x800) {
949 this.elements.push((start << 11) | len);
950 } else {
951 // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
952 // so -len is a smi.
953 var elements = this.elements;
954 elements.push(-len);
955 elements.push(start);
956 }
957 },
958 "generate", function() {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100959 var elements = this.elements;
Ben Murdoch589d6972011-11-30 16:04:58 +0000960 return %StringBuilderConcat(elements, elements.length, this.special_string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000961 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000962));
Steve Blocka7e24c12009-10-30 11:49:00 +0000963
964
Steve Blocka7e24c12009-10-30 11:49:00 +0000965// -------------------------------------------------------------------
966
Ben Murdoch589d6972011-11-30 16:04:58 +0000967function SetUpString() {
968 %CheckIsBootstrapping();
969 // Set up the constructor property on the String prototype object.
Steve Blocka7e24c12009-10-30 11:49:00 +0000970 %SetProperty($String.prototype, "constructor", $String, DONT_ENUM);
971
972
Ben Murdoch589d6972011-11-30 16:04:58 +0000973 // Set up the non-enumerable functions on the String object.
Steve Blocka7e24c12009-10-30 11:49:00 +0000974 InstallFunctions($String, DONT_ENUM, $Array(
975 "fromCharCode", StringFromCharCode
976 ));
977
978
Ben Murdoch589d6972011-11-30 16:04:58 +0000979 // Set up the non-enumerable functions on the String prototype object.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100980 InstallFunctions($String.prototype, DONT_ENUM, $Array(
Steve Blocka7e24c12009-10-30 11:49:00 +0000981 "valueOf", StringValueOf,
982 "toString", StringToString,
983 "charAt", StringCharAt,
984 "charCodeAt", StringCharCodeAt,
985 "concat", StringConcat,
986 "indexOf", StringIndexOf,
987 "lastIndexOf", StringLastIndexOf,
988 "localeCompare", StringLocaleCompare,
989 "match", StringMatch,
990 "replace", StringReplace,
991 "search", StringSearch,
992 "slice", StringSlice,
993 "split", StringSplit,
994 "substring", StringSubstring,
995 "substr", StringSubstr,
996 "toLowerCase", StringToLowerCase,
997 "toLocaleLowerCase", StringToLocaleLowerCase,
998 "toUpperCase", StringToUpperCase,
999 "toLocaleUpperCase", StringToLocaleUpperCase,
Steve Block3ce2e202009-11-05 08:53:23 +00001000 "trim", StringTrim,
1001 "trimLeft", StringTrimLeft,
1002 "trimRight", StringTrimRight,
Steve Blocka7e24c12009-10-30 11:49:00 +00001003 "link", StringLink,
1004 "anchor", StringAnchor,
1005 "fontcolor", StringFontcolor,
1006 "fontsize", StringFontsize,
1007 "big", StringBig,
1008 "blink", StringBlink,
1009 "bold", StringBold,
1010 "fixed", StringFixed,
1011 "italics", StringItalics,
1012 "small", StringSmall,
1013 "strike", StringStrike,
1014 "sub", StringSub,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001015 "sup", StringSup
Steve Blocka7e24c12009-10-30 11:49:00 +00001016 ));
1017}
1018
Ben Murdoch589d6972011-11-30 16:04:58 +00001019SetUpString();