blob: ac5cb7f99ef006378056828d1c97341ea1372d9d [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
5// This file relies on the fact that the following declaration has been made
6// in runtime.js:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007// var $String = global.String;
Steve Blocka7e24c12009-10-30 11:49:00 +00008
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009// -------------------------------------------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +000010
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011function StringConstructor(x) {
12 if (%_ArgumentsLength() == 0) x = '';
Steve Blocka7e24c12009-10-30 11:49:00 +000013 if (%_IsConstructCall()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014 %_SetValueOf(this, TO_STRING_INLINE(x));
Steve Blocka7e24c12009-10-30 11:49:00 +000015 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016 return IS_SYMBOL(x) ?
17 %_CallFunction(x, SymbolToString) : TO_STRING_INLINE(x);
Steve Blocka7e24c12009-10-30 11:49:00 +000018 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000019}
Steve Blocka7e24c12009-10-30 11:49:00 +000020
Steve Blocka7e24c12009-10-30 11:49:00 +000021
22// ECMA-262 section 15.5.4.2
23function StringToString() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010024 if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000025 throw new $TypeError('String.prototype.toString is not generic');
Ben Murdoch3ef787d2012-04-12 10:51:47 +010026 }
Steve Blocka7e24c12009-10-30 11:49:00 +000027 return %_ValueOf(this);
28}
29
30
31// ECMA-262 section 15.5.4.3
32function StringValueOf() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010033 if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000034 throw new $TypeError('String.prototype.valueOf is not generic');
Ben Murdoch3ef787d2012-04-12 10:51:47 +010035 }
Steve Blocka7e24c12009-10-30 11:49:00 +000036 return %_ValueOf(this);
37}
38
39
40// ECMA-262, section 15.5.4.4
41function StringCharAt(pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000042 CHECK_OBJECT_COERCIBLE(this, "String.prototype.charAt");
43
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010044 var result = %_StringCharAt(this, pos);
45 if (%_IsSmi(result)) {
46 result = %_StringCharAt(TO_STRING_INLINE(this), TO_INTEGER(pos));
Steve Blocka7e24c12009-10-30 11:49:00 +000047 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010048 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000049}
50
51
52// ECMA-262 section 15.5.4.5
53function StringCharCodeAt(pos) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054 CHECK_OBJECT_COERCIBLE(this, "String.prototype.charCodeAt");
55
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010056 var result = %_StringCharCodeAt(this, pos);
57 if (!%_IsSmi(result)) {
58 result = %_StringCharCodeAt(TO_STRING_INLINE(this), TO_INTEGER(pos));
Steve Blocka7e24c12009-10-30 11:49:00 +000059 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010060 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000061}
62
63
64// ECMA-262, section 15.5.4.6
Ben Murdochb8a8cc12014-11-26 15:28:44 +000065function StringConcat(other /* and more */) { // length == 1
66 CHECK_OBJECT_COERCIBLE(this, "String.prototype.concat");
67
Andrei Popescu402d9372010-02-26 13:31:12 +000068 var len = %_ArgumentsLength();
69 var this_as_string = TO_STRING_INLINE(this);
70 if (len === 1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000071 return this_as_string + other;
Leon Clarkee46be812010-01-19 14:06:41 +000072 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +010073 var parts = new InternalArray(len + 1);
Andrei Popescu402d9372010-02-26 13:31:12 +000074 parts[0] = this_as_string;
75 for (var i = 0; i < len; i++) {
76 var part = %_Arguments(i);
77 parts[i + 1] = TO_STRING_INLINE(part);
78 }
79 return %StringBuilderConcat(parts, len + 1, "");
Steve Blocka7e24c12009-10-30 11:49:00 +000080}
81
Steve Blocka7e24c12009-10-30 11:49:00 +000082
83// ECMA-262 section 15.5.4.7
Ben Murdochb8a8cc12014-11-26 15:28:44 +000084function StringIndexOfJS(pattern /* position */) { // length == 1
85 CHECK_OBJECT_COERCIBLE(this, "String.prototype.indexOf");
86
Ben Murdochb0fe1622011-05-05 13:52:32 +010087 var subject = TO_STRING_INLINE(this);
Steve Block1e0659c2011-05-24 12:43:12 +010088 pattern = TO_STRING_INLINE(pattern);
Steve Blocka7e24c12009-10-30 11:49:00 +000089 var index = 0;
90 if (%_ArgumentsLength() > 1) {
Steve Block1e0659c2011-05-24 12:43:12 +010091 index = %_Arguments(1); // position
92 index = TO_INTEGER(index);
93 if (index < 0) index = 0;
94 if (index > subject.length) index = subject.length;
Steve Blocka7e24c12009-10-30 11:49:00 +000095 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010096 return %StringIndexOf(subject, pattern, index);
Steve Blocka7e24c12009-10-30 11:49:00 +000097}
98
99
100// ECMA-262 section 15.5.4.8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000101function StringLastIndexOfJS(pat /* position */) { // length == 1
102 CHECK_OBJECT_COERCIBLE(this, "String.prototype.lastIndexOf");
103
Andrei Popescu402d9372010-02-26 13:31:12 +0000104 var sub = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000105 var subLength = sub.length;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100106 var pat = TO_STRING_INLINE(pat);
Steve Blocka7e24c12009-10-30 11:49:00 +0000107 var patLength = pat.length;
108 var index = subLength - patLength;
109 if (%_ArgumentsLength() > 1) {
110 var position = ToNumber(%_Arguments(1));
Steve Block9fac8402011-05-12 15:51:54 +0100111 if (!NUMBER_IS_NAN(position)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000112 position = TO_INTEGER(position);
113 if (position < 0) {
114 position = 0;
115 }
116 if (position + patLength < subLength) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000117 index = position;
Steve Blocka7e24c12009-10-30 11:49:00 +0000118 }
119 }
120 }
121 if (index < 0) {
122 return -1;
123 }
124 return %StringLastIndexOf(sub, pat, index);
125}
126
127
128// ECMA-262 section 15.5.4.9
129//
130// This function is implementation specific. For now, we do not
131// do anything locale specific.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132function StringLocaleCompareJS(other) {
133 CHECK_OBJECT_COERCIBLE(this, "String.prototype.localeCompare");
134
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000135 return %StringLocaleCompare(TO_STRING_INLINE(this),
Ben Murdochb0fe1622011-05-05 13:52:32 +0100136 TO_STRING_INLINE(other));
Steve Blocka7e24c12009-10-30 11:49:00 +0000137}
138
139
140// ECMA-262 section 15.5.4.10
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141function StringMatchJS(regexp) {
142 CHECK_OBJECT_COERCIBLE(this, "String.prototype.match");
143
Andrei Popescu402d9372010-02-26 13:31:12 +0000144 var subject = TO_STRING_INLINE(this);
Steve Block6ded16b2010-05-10 14:33:55 +0100145 if (IS_REGEXP(regexp)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000146 // Emulate RegExp.prototype.exec's side effect in step 5, even though
147 // value is discarded.
148 var lastIndex = regexp.lastIndex;
149 TO_INTEGER_FOR_SIDE_EFFECT(lastIndex);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100150 if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0);
Steve Block6ded16b2010-05-10 14:33:55 +0100151 // lastMatchInfo is defined in regexp.js.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152 var result = %StringMatch(subject, regexp, lastMatchInfo);
153 if (result !== null) lastMatchInfoOverride = null;
154 regexp.lastIndex = 0;
155 return result;
Steve Block6ded16b2010-05-10 14:33:55 +0100156 }
157 // Non-regexp argument.
158 regexp = new $RegExp(regexp);
Steve Block6ded16b2010-05-10 14:33:55 +0100159 return RegExpExecNoTests(regexp, subject, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000160}
161
162
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000163var NORMALIZATION_FORMS = ['NFC', 'NFD', 'NFKC', 'NFKD'];
164
165
166// ECMA-262 v6, section 21.1.3.12
167//
168// For now we do nothing, as proper normalization requires big tables.
169// If Intl is enabled, then i18n.js will override it and provide the the
170// proper functionality.
171function StringNormalizeJS(form) {
172 CHECK_OBJECT_COERCIBLE(this, "String.prototype.normalize");
173
174 var form = form ? TO_STRING_INLINE(form) : 'NFC';
175 var normalizationForm = NORMALIZATION_FORMS.indexOf(form);
176 if (normalizationForm === -1) {
177 throw new $RangeError('The normalization form should be one of '
178 + NORMALIZATION_FORMS.join(', ') + '.');
179 }
180
181 return %_ValueOf(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000182}
183
184
185// This has the same size as the lastMatchInfo array, and can be used for
186// functions that expect that structure to be returned. It is used when the
187// needle is a string rather than a regexp. In this case we can't update
188// lastMatchArray without erroneously affecting the properties on the global
189// RegExp object.
190var reusableMatchInfo = [2, "", "", -1, -1];
191
192
193// ECMA-262, section 15.5.4.11
194function StringReplace(search, replace) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000195 CHECK_OBJECT_COERCIBLE(this, "String.prototype.replace");
196
Andrei Popescu402d9372010-02-26 13:31:12 +0000197 var subject = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000198
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000199 // Decision tree for dispatch
200 // .. regexp search
201 // .... string replace
202 // ...... non-global search
203 // ........ empty string replace
204 // ........ non-empty string replace (with $-expansion)
205 // ...... global search
206 // ........ no need to circumvent last match info override
207 // ........ need to circument last match info override
208 // .... function replace
209 // ...... global search
210 // ...... non-global search
211 // .. string search
212 // .... special case that replaces with one single character
213 // ...... function replace
214 // ...... string replace (with $-expansion)
215
Steve Blocka7e24c12009-10-30 11:49:00 +0000216 if (IS_REGEXP(search)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217 // Emulate RegExp.prototype.exec's side effect in step 5, even if
218 // value is discarded.
219 var lastIndex = search.lastIndex;
220 TO_INTEGER_FOR_SIDE_EFFECT(lastIndex);
221
222 if (!IS_SPEC_FUNCTION(replace)) {
223 replace = TO_STRING_INLINE(replace);
224
225 if (!search.global) {
226 // Non-global regexp search, string replace.
227 var match = DoRegExpExec(search, subject, 0);
228 if (match == null) {
229 search.lastIndex = 0
230 return subject;
231 }
232 if (replace.length == 0) {
233 return %_SubString(subject, 0, match[CAPTURE0]) +
234 %_SubString(subject, match[CAPTURE1], subject.length)
235 }
236 return ExpandReplacement(replace, subject, lastMatchInfo,
237 %_SubString(subject, 0, match[CAPTURE0])) +
238 %_SubString(subject, match[CAPTURE1], subject.length);
Kristian Monsen25f61362010-05-21 11:50:48 +0100239 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000240
241 // Global regexp search, string replace.
242 search.lastIndex = 0;
243 if (lastMatchInfoOverride == null) {
244 return %StringReplaceGlobalRegExpWithString(
245 subject, search, replace, lastMatchInfo);
246 } else {
247 // We use this hack to detect whether StringReplaceRegExpWithString
248 // found at least one hit. In that case we need to remove any
249 // override.
250 var saved_subject = lastMatchInfo[LAST_SUBJECT_INDEX];
251 lastMatchInfo[LAST_SUBJECT_INDEX] = 0;
252 var answer = %StringReplaceGlobalRegExpWithString(
253 subject, search, replace, lastMatchInfo);
254 if (%_IsSmi(lastMatchInfo[LAST_SUBJECT_INDEX])) {
255 lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
256 } else {
257 lastMatchInfoOverride = null;
258 }
259 return answer;
260 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000261 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000262
263 if (search.global) {
264 // Global regexp search, function replace.
265 return StringReplaceGlobalRegExpWithFunction(subject, search, replace);
266 }
267 // Non-global regexp search, function replace.
268 return StringReplaceNonGlobalRegExpWithFunction(subject, search, replace);
Steve Blocka7e24c12009-10-30 11:49:00 +0000269 }
270
Andrei Popescu402d9372010-02-26 13:31:12 +0000271 search = TO_STRING_INLINE(search);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000272
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100273 if (search.length == 1 &&
274 subject.length > 0xFF &&
275 IS_STRING(replace) &&
276 %StringIndexOf(replace, '$', 0) < 0) {
277 // Searching by traversing a cons string tree and replace with cons of
278 // slices works only when the replaced string is a single character, being
279 // replaced by a simple string and only pays off for long strings.
280 return %StringReplaceOneCharWithString(subject, search, replace);
281 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000282 var start = %StringIndexOf(subject, search, 0);
283 if (start < 0) return subject;
284 var end = start + search.length;
285
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286 var result = %_SubString(subject, 0, start);
Steve Blocka7e24c12009-10-30 11:49:00 +0000287
288 // Compute the string to replace with.
Ben Murdoch589d6972011-11-30 16:04:58 +0000289 if (IS_SPEC_FUNCTION(replace)) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000290 var receiver = %GetDefaultReceiver(replace);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000291 result += %_CallFunction(receiver, search, start, subject, replace);
Steve Blocka7e24c12009-10-30 11:49:00 +0000292 } else {
293 reusableMatchInfo[CAPTURE0] = start;
294 reusableMatchInfo[CAPTURE1] = end;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000295 result = ExpandReplacement(TO_STRING_INLINE(replace),
296 subject,
297 reusableMatchInfo,
298 result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000299 }
300
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 return result + %_SubString(subject, end, subject.length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000302}
303
304
Steve Blocka7e24c12009-10-30 11:49:00 +0000305// Expand the $-expressions in the string and return a new string with
306// the result.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000307function ExpandReplacement(string, subject, matchInfo, result) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100308 var length = string.length;
Steve Blocka7e24c12009-10-30 11:49:00 +0000309 var next = %StringIndexOf(string, '$', 0);
310 if (next < 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000311 if (length > 0) result += string;
312 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000313 }
314
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 if (next > 0) result += %_SubString(string, 0, next);
Steve Blocka7e24c12009-10-30 11:49:00 +0000316
317 while (true) {
318 var expansion = '$';
319 var position = next + 1;
320 if (position < length) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100321 var peek = %_StringCharCodeAt(string, position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000322 if (peek == 36) { // $$
323 ++position;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000324 result += '$';
Steve Blocka7e24c12009-10-30 11:49:00 +0000325 } else if (peek == 38) { // $& - match
326 ++position;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000327 result +=
328 %_SubString(subject, matchInfo[CAPTURE0], matchInfo[CAPTURE1]);
Steve Blocka7e24c12009-10-30 11:49:00 +0000329 } else if (peek == 96) { // $` - prefix
330 ++position;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000331 result += %_SubString(subject, 0, matchInfo[CAPTURE0]);
Steve Blocka7e24c12009-10-30 11:49:00 +0000332 } else if (peek == 39) { // $' - suffix
333 ++position;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000334 result += %_SubString(subject, matchInfo[CAPTURE1], subject.length);
335 } else if (peek >= 48 && peek <= 57) {
336 // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
337 var scaled_index = (peek - 48) << 1;
338 var advance = 1;
339 var number_of_captures = NUMBER_OF_CAPTURES(matchInfo);
340 if (position + 1 < string.length) {
341 var next = %_StringCharCodeAt(string, position + 1);
342 if (next >= 48 && next <= 57) {
343 var new_scaled_index = scaled_index * 10 + ((next - 48) << 1);
344 if (new_scaled_index < number_of_captures) {
345 scaled_index = new_scaled_index;
346 advance = 2;
Steve Blocka7e24c12009-10-30 11:49:00 +0000347 }
348 }
349 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000350 if (scaled_index != 0 && scaled_index < number_of_captures) {
351 var start = matchInfo[CAPTURE(scaled_index)];
352 if (start >= 0) {
353 result +=
354 %_SubString(subject, start, matchInfo[CAPTURE(scaled_index + 1)]);
355 }
356 position += advance;
Steve Blocka7e24c12009-10-30 11:49:00 +0000357 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000358 result += '$';
Steve Blocka7e24c12009-10-30 11:49:00 +0000359 }
360 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000361 result += '$';
Steve Blocka7e24c12009-10-30 11:49:00 +0000362 }
363 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000364 result += '$';
Steve Blocka7e24c12009-10-30 11:49:00 +0000365 }
366
367 // Go the the next $ in the string.
368 next = %StringIndexOf(string, '$', position);
369
370 // Return if there are no more $ characters in the string. If we
371 // haven't reached the end, we need to append the suffix.
372 if (next < 0) {
373 if (position < length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000374 result += %_SubString(string, position, length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000375 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000376 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000377 }
378
379 // Append substring between the previous and the next $ character.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100380 if (next > position) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000381 result += %_SubString(string, position, next);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100382 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000383 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000384 return result;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100385}
Steve Blocka7e24c12009-10-30 11:49:00 +0000386
387
388// Compute the string of a given regular expression capture.
389function CaptureString(string, lastCaptureInfo, index) {
390 // Scale the index.
391 var scaled = index << 1;
392 // Compute start and end.
393 var start = lastCaptureInfo[CAPTURE(scaled)];
Kristian Monsen25f61362010-05-21 11:50:48 +0100394 // If start isn't valid, return undefined.
395 if (start < 0) return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000396 var end = lastCaptureInfo[CAPTURE(scaled + 1)];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000397 return %_SubString(string, start, end);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100398}
Steve Blocka7e24c12009-10-30 11:49:00 +0000399
400
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;
Kristian Monsen25f61362010-05-21 11:50:48 +0100430 if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000431 // If the number of captures is two then there are no explicit captures in
432 // the regexp, just the implicit capture that captures the whole match. In
433 // this case we can simplify quite a bit and end up with something faster.
434 // The builder will consist of some integers that indicate slices of the
435 // input string and some replacements that were returned from the replace
436 // function.
Kristian Monsen25f61362010-05-21 11:50:48 +0100437 var match_start = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000438 var override = new InternalPackedArray(null, 0, subject);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000439 var receiver = %GetDefaultReceiver(replace);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000440 for (var i = 0; i < len; i++) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100441 var elem = res[i];
442 if (%_IsSmi(elem)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000443 // Integers represent slices of the original string. Use these to
444 // get the offsets we need for the override array (so things like
445 // RegExp.leftContext work during the callback function.
Kristian Monsen25f61362010-05-21 11:50:48 +0100446 if (elem > 0) {
447 match_start = (elem >> 11) + (elem & 0x7ff);
448 } else {
449 match_start = res[++i] - elem;
450 }
451 } else {
452 override[0] = elem;
453 override[1] = match_start;
454 lastMatchInfoOverride = override;
455 var func_result =
456 %_CallFunction(receiver, elem, match_start, subject, replace);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000457 // Overwrite the i'th element in the results with the string we got
458 // back from the callback function.
Steve Block1e0659c2011-05-24 12:43:12 +0100459 res[i] = TO_STRING_INLINE(func_result);
Kristian Monsen25f61362010-05-21 11:50:48 +0100460 match_start += elem.length;
461 }
Kristian Monsen25f61362010-05-21 11:50:48 +0100462 }
463 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +0000464 var receiver = %GetDefaultReceiver(replace);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 for (var i = 0; i < len; i++) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100466 var elem = res[i];
467 if (!%_IsSmi(elem)) {
468 // elem must be an Array.
469 // Use the apply argument as backing for global RegExp properties.
470 lastMatchInfoOverride = elem;
Ben Murdoch589d6972011-11-30 16:04:58 +0000471 var func_result = %Apply(replace, receiver, elem, 0, elem.length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000472 // Overwrite the i'th element in the results with the string we got
473 // back from the callback function.
Steve Block1e0659c2011-05-24 12:43:12 +0100474 res[i] = TO_STRING_INLINE(func_result);
Kristian Monsen25f61362010-05-21 11:50:48 +0100475 }
Kristian Monsen25f61362010-05-21 11:50:48 +0100476 }
477 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000478 var result = %StringBuilderConcat(res, res.length, subject);
Kristian Monsen25f61362010-05-21 11:50:48 +0100479 resultArray.length = 0;
480 reusableReplaceArray = resultArray;
481 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000482}
483
484
Kristian Monsen25f61362010-05-21 11:50:48 +0100485function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
486 var matchInfo = DoRegExpExec(regexp, subject, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000487 if (IS_NULL(matchInfo)) {
488 regexp.lastIndex = 0;
489 return subject;
490 }
Kristian Monsen25f61362010-05-21 11:50:48 +0100491 var index = matchInfo[CAPTURE0];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000492 var result = %_SubString(subject, 0, index);
Kristian Monsen25f61362010-05-21 11:50:48 +0100493 var endOfMatch = matchInfo[CAPTURE1];
Steve Blocka7e24c12009-10-30 11:49:00 +0000494 // Compute the parameter list consisting of the match, captures, index,
495 // and subject for the replace function invocation.
Steve Blocka7e24c12009-10-30 11:49:00 +0000496 // The number of captures plus one for the match.
497 var m = NUMBER_OF_CAPTURES(matchInfo) >> 1;
Kristian Monsen25f61362010-05-21 11:50:48 +0100498 var replacement;
Ben Murdoch589d6972011-11-30 16:04:58 +0000499 var receiver = %GetDefaultReceiver(replace);
Steve Blocka7e24c12009-10-30 11:49:00 +0000500 if (m == 1) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100501 // No captures, only the match, which is always valid.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000502 var s = %_SubString(subject, index, endOfMatch);
Steve Blocka7e24c12009-10-30 11:49:00 +0000503 // Don't call directly to avoid exposing the built-in global object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000504 replacement = %_CallFunction(receiver, s, index, subject, replace);
Kristian Monsen25f61362010-05-21 11:50:48 +0100505 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100506 var parameters = new InternalArray(m + 2);
Kristian Monsen25f61362010-05-21 11:50:48 +0100507 for (var j = 0; j < m; j++) {
508 parameters[j] = CaptureString(subject, matchInfo, j);
509 }
510 parameters[j] = index;
511 parameters[j + 1] = subject;
512
Ben Murdoch589d6972011-11-30 16:04:58 +0000513 replacement = %Apply(replace, receiver, parameters, 0, j + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000514 }
Kristian Monsen25f61362010-05-21 11:50:48 +0100515
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000516 result += replacement; // The add method converts to string if necessary.
Kristian Monsen25f61362010-05-21 11:50:48 +0100517 // Can't use matchInfo any more from here, since the function could
518 // overwrite it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000519 return result + %_SubString(subject, endOfMatch, subject.length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000520}
521
Kristian Monsen25f61362010-05-21 11:50:48 +0100522
Steve Blocka7e24c12009-10-30 11:49:00 +0000523// ECMA-262 section 15.5.4.12
524function StringSearch(re) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000525 CHECK_OBJECT_COERCIBLE(this, "String.prototype.search");
526
Steve Block6ded16b2010-05-10 14:33:55 +0100527 var regexp;
528 if (IS_STRING(re)) {
529 regexp = %_GetFromCache(STRING_TO_REGEXP_CACHE_ID, re);
530 } else if (IS_REGEXP(re)) {
531 regexp = re;
532 } else {
533 regexp = new $RegExp(re);
534 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100535 var match = DoRegExpExec(regexp, TO_STRING_INLINE(this), 0);
Steve Block6ded16b2010-05-10 14:33:55 +0100536 if (match) {
537 return match[CAPTURE0];
538 }
539 return -1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000540}
541
542
543// ECMA-262 section 15.5.4.13
544function StringSlice(start, end) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000545 CHECK_OBJECT_COERCIBLE(this, "String.prototype.slice");
546
Andrei Popescu402d9372010-02-26 13:31:12 +0000547 var s = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000548 var s_len = s.length;
549 var start_i = TO_INTEGER(start);
550 var end_i = s_len;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000551 if (!IS_UNDEFINED(end)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000552 end_i = TO_INTEGER(end);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100553 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000554
555 if (start_i < 0) {
556 start_i += s_len;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100557 if (start_i < 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000558 start_i = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100559 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000560 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100561 if (start_i > s_len) {
562 return '';
563 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000564 }
565
566 if (end_i < 0) {
567 end_i += s_len;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100568 if (end_i < 0) {
569 return '';
570 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000571 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100572 if (end_i > s_len) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000573 end_i = s_len;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100574 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000575 }
576
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100577 if (end_i <= start_i) {
578 return '';
579 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000580
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000581 return %_SubString(s, start_i, end_i);
Steve Blocka7e24c12009-10-30 11:49:00 +0000582}
583
584
585// ECMA-262 section 15.5.4.14
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000586function StringSplitJS(separator, limit) {
587 CHECK_OBJECT_COERCIBLE(this, "String.prototype.split");
588
Andrei Popescu402d9372010-02-26 13:31:12 +0000589 var subject = TO_STRING_INLINE(this);
Leon Clarkee46be812010-01-19 14:06:41 +0000590 limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit);
Steve Blocka7e24c12009-10-30 11:49:00 +0000591
Steve Blocka7e24c12009-10-30 11:49:00 +0000592 var length = subject.length;
Andrei Popescu402d9372010-02-26 13:31:12 +0000593 if (!IS_REGEXP(separator)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000594 var separator_string = TO_STRING_INLINE(separator);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100595
596 if (limit === 0) return [];
597
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000598 // ECMA-262 says that if separator is undefined, the result should
599 // be an array of size 1 containing the entire string.
600 if (IS_UNDEFINED(separator)) return [subject];
601
602 var separator_length = separator_string.length;
Andrei Popescu402d9372010-02-26 13:31:12 +0000603
Steve Blocka7e24c12009-10-30 11:49:00 +0000604 // If the separator string is empty then return the elements in the subject.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800605 if (separator_length === 0) return %StringToArray(subject, limit);
Andrei Popescu402d9372010-02-26 13:31:12 +0000606
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000607 var result = %StringSplit(subject, separator_string, limit);
Andrei Popescu402d9372010-02-26 13:31:12 +0000608
609 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000610 }
611
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100612 if (limit === 0) return [];
613
614 // Separator is a regular expression.
615 return StringSplitOnRegExp(subject, separator, limit, length);
616}
617
618
619function StringSplitOnRegExp(subject, separator, limit, length) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000620 if (length === 0) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800621 if (DoRegExpExec(separator, subject, 0, 0) != null) {
Steve Block6ded16b2010-05-10 14:33:55 +0100622 return [];
623 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000624 return [subject];
625 }
626
627 var currentIndex = 0;
628 var startIndex = 0;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100629 var startMatch = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000630 var result = new InternalArray();
Steve Blocka7e24c12009-10-30 11:49:00 +0000631
Steve Block6ded16b2010-05-10 14:33:55 +0100632 outer_loop:
Steve Blocka7e24c12009-10-30 11:49:00 +0000633 while (true) {
634
635 if (startIndex === length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000636 result[result.length] = %_SubString(subject, currentIndex, length);
Steve Block6ded16b2010-05-10 14:33:55 +0100637 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000638 }
639
Ben Murdochb0fe1622011-05-05 13:52:32 +0100640 var matchInfo = DoRegExpExec(separator, subject, startIndex);
641 if (matchInfo == null || length === (startMatch = matchInfo[CAPTURE0])) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000642 result[result.length] = %_SubString(subject, currentIndex, length);
Steve Block6ded16b2010-05-10 14:33:55 +0100643 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000644 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000645 var endIndex = matchInfo[CAPTURE1];
646
647 // We ignore a zero-length match at the currentIndex.
648 if (startIndex === endIndex && endIndex === currentIndex) {
649 startIndex++;
650 continue;
651 }
652
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000653 result[result.length] = %_SubString(subject, currentIndex, startMatch);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100654
Steve Block6ded16b2010-05-10 14:33:55 +0100655 if (result.length === limit) break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000656
Ben Murdochb0fe1622011-05-05 13:52:32 +0100657 var matchinfo_len = NUMBER_OF_CAPTURES(matchInfo) + REGEXP_FIRST_CAPTURE;
658 for (var i = REGEXP_FIRST_CAPTURE + 2; i < matchinfo_len; ) {
659 var start = matchInfo[i++];
660 var end = matchInfo[i++];
661 if (end != -1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000662 result[result.length] = %_SubString(subject, start, end);
Steve Blocka7e24c12009-10-30 11:49:00 +0000663 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000664 result[result.length] = UNDEFINED;
Steve Blocka7e24c12009-10-30 11:49:00 +0000665 }
Steve Block6ded16b2010-05-10 14:33:55 +0100666 if (result.length === limit) break outer_loop;
Steve Blocka7e24c12009-10-30 11:49:00 +0000667 }
668
669 startIndex = currentIndex = endIndex;
670 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000671 var array_result = [];
672 %MoveArrayContents(result, array_result);
673 return array_result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000674}
675
676
Steve Blocka7e24c12009-10-30 11:49:00 +0000677// ECMA-262 section 15.5.4.15
678function StringSubstring(start, end) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000679 CHECK_OBJECT_COERCIBLE(this, "String.prototype.subString");
680
Andrei Popescu402d9372010-02-26 13:31:12 +0000681 var s = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000682 var s_len = s.length;
Leon Clarkee46be812010-01-19 14:06:41 +0000683
Steve Blocka7e24c12009-10-30 11:49:00 +0000684 var start_i = TO_INTEGER(start);
Leon Clarkee46be812010-01-19 14:06:41 +0000685 if (start_i < 0) {
686 start_i = 0;
687 } else if (start_i > s_len) {
688 start_i = s_len;
689 }
690
Steve Blocka7e24c12009-10-30 11:49:00 +0000691 var end_i = s_len;
Leon Clarkee46be812010-01-19 14:06:41 +0000692 if (!IS_UNDEFINED(end)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000693 end_i = TO_INTEGER(end);
Leon Clarkee46be812010-01-19 14:06:41 +0000694 if (end_i > s_len) {
695 end_i = s_len;
696 } else {
697 if (end_i < 0) end_i = 0;
698 if (start_i > end_i) {
699 var tmp = end_i;
700 end_i = start_i;
701 start_i = tmp;
702 }
703 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000704 }
705
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000706 return %_SubString(s, start_i, end_i);
Steve Blocka7e24c12009-10-30 11:49:00 +0000707}
708
709
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000710// ES6 draft, revision 26 (2014-07-18), section B.2.3.1
Steve Blocka7e24c12009-10-30 11:49:00 +0000711function StringSubstr(start, n) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000712 CHECK_OBJECT_COERCIBLE(this, "String.prototype.substr");
713
Andrei Popescu402d9372010-02-26 13:31:12 +0000714 var s = TO_STRING_INLINE(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000715 var len;
716
717 // Correct n: If not given, set to string length; if explicitly
718 // set to undefined, zero, or negative, returns empty string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000719 if (IS_UNDEFINED(n)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000720 len = s.length;
721 } else {
722 len = TO_INTEGER(n);
723 if (len <= 0) return '';
724 }
725
726 // Correct start: If not given (or undefined), set to zero; otherwise
727 // convert to integer and handle negative case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000728 if (IS_UNDEFINED(start)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000729 start = 0;
730 } else {
731 start = TO_INTEGER(start);
732 // If positive, and greater than or equal to the string length,
733 // return empty string.
734 if (start >= s.length) return '';
735 // If negative and absolute value is larger than the string length,
736 // use zero.
737 if (start < 0) {
738 start += s.length;
739 if (start < 0) start = 0;
740 }
741 }
742
743 var end = start + len;
744 if (end > s.length) end = s.length;
745
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000746 return %_SubString(s, start, end);
Steve Blocka7e24c12009-10-30 11:49:00 +0000747}
748
749
750// ECMA-262, 15.5.4.16
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000751function StringToLowerCaseJS() {
752 CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLowerCase");
753
Andrei Popescu402d9372010-02-26 13:31:12 +0000754 return %StringToLowerCase(TO_STRING_INLINE(this));
Steve Blocka7e24c12009-10-30 11:49:00 +0000755}
756
757
758// ECMA-262, 15.5.4.17
759function StringToLocaleLowerCase() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000760 CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleLowerCase");
761
Andrei Popescu402d9372010-02-26 13:31:12 +0000762 return %StringToLowerCase(TO_STRING_INLINE(this));
Steve Blocka7e24c12009-10-30 11:49:00 +0000763}
764
765
766// ECMA-262, 15.5.4.18
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000767function StringToUpperCaseJS() {
768 CHECK_OBJECT_COERCIBLE(this, "String.prototype.toUpperCase");
769
Andrei Popescu402d9372010-02-26 13:31:12 +0000770 return %StringToUpperCase(TO_STRING_INLINE(this));
Steve Blocka7e24c12009-10-30 11:49:00 +0000771}
772
773
774// ECMA-262, 15.5.4.19
775function StringToLocaleUpperCase() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000776 CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleUpperCase");
777
Andrei Popescu402d9372010-02-26 13:31:12 +0000778 return %StringToUpperCase(TO_STRING_INLINE(this));
Steve Blocka7e24c12009-10-30 11:49:00 +0000779}
780
Steve Block3ce2e202009-11-05 08:53:23 +0000781// ES5, 15.5.4.20
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000782function StringTrimJS() {
783 CHECK_OBJECT_COERCIBLE(this, "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 Murdochb8a8cc12014-11-26 15:28:44 +0000789 CHECK_OBJECT_COERCIBLE(this, "String.prototype.trimLeft");
790
Andrei Popescu402d9372010-02-26 13:31:12 +0000791 return %StringTrim(TO_STRING_INLINE(this), true, false);
Steve Block3ce2e202009-11-05 08:53:23 +0000792}
793
794function StringTrimRight() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000795 CHECK_OBJECT_COERCIBLE(this, "String.prototype.trimRight");
796
Andrei Popescu402d9372010-02-26 13:31:12 +0000797 return %StringTrim(TO_STRING_INLINE(this), false, true);
Steve Block3ce2e202009-11-05 08:53:23 +0000798}
Steve Blocka7e24c12009-10-30 11:49:00 +0000799
Steve Block6ded16b2010-05-10 14:33:55 +0100800
Steve Blocka7e24c12009-10-30 11:49:00 +0000801// ECMA-262, section 15.5.3.2
802function StringFromCharCode(code) {
803 var n = %_ArgumentsLength();
Steve Block6ded16b2010-05-10 14:33:55 +0100804 if (n == 1) {
805 if (!%_IsSmi(code)) code = ToNumber(code);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100806 return %_StringCharFromCode(code & 0xffff);
Steve Block6ded16b2010-05-10 14:33:55 +0100807 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000808
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000809 var one_byte = %NewString(n, NEW_ONE_BYTE_STRING);
810 var i;
811 for (i = 0; i < n; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +0100812 var code = %_Arguments(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000813 if (!%_IsSmi(code)) code = ToNumber(code) & 0xffff;
814 if (code < 0) code = code & 0xffff;
815 if (code > 0xff) break;
816 %_OneByteSeqStringSetChar(i, code, one_byte);
Steve Block6ded16b2010-05-10 14:33:55 +0100817 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000818 if (i == n) return one_byte;
819 one_byte = %TruncateString(one_byte, i);
820
821 var two_byte = %NewString(n - i, NEW_TWO_BYTE_STRING);
822 for (var j = 0; i < n; i++, j++) {
823 var code = %_Arguments(i);
824 if (!%_IsSmi(code)) code = ToNumber(code) & 0xffff;
825 %_TwoByteSeqStringSetChar(j, code, two_byte);
826 }
827 return one_byte + two_byte;
Steve Blocka7e24c12009-10-30 11:49:00 +0000828}
829
830
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000831// ES6 draft, revision 26 (2014-07-18), section B.2.3.2.1
Steve Blocka7e24c12009-10-30 11:49:00 +0000832function HtmlEscape(str) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000833 return TO_STRING_INLINE(str).replace(/"/g, "&quot;");
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100834}
Steve Blocka7e24c12009-10-30 11:49:00 +0000835
836
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000837// ES6 draft, revision 26 (2014-07-18), section B.2.3.2
Steve Blocka7e24c12009-10-30 11:49:00 +0000838function StringAnchor(name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000839 CHECK_OBJECT_COERCIBLE(this, "String.prototype.anchor");
Steve Blocka7e24c12009-10-30 11:49:00 +0000840 return "<a name=\"" + HtmlEscape(name) + "\">" + this + "</a>";
841}
842
843
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000844// ES6 draft, revision 26 (2014-07-18), section B.2.3.3
Steve Blocka7e24c12009-10-30 11:49:00 +0000845function StringBig() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000846 CHECK_OBJECT_COERCIBLE(this, "String.prototype.big");
Steve Blocka7e24c12009-10-30 11:49:00 +0000847 return "<big>" + this + "</big>";
848}
849
850
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000851// ES6 draft, revision 26 (2014-07-18), section B.2.3.4
Steve Blocka7e24c12009-10-30 11:49:00 +0000852function StringBlink() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000853 CHECK_OBJECT_COERCIBLE(this, "String.prototype.blink");
Steve Blocka7e24c12009-10-30 11:49:00 +0000854 return "<blink>" + this + "</blink>";
855}
856
857
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000858// ES6 draft, revision 26 (2014-07-18), section B.2.3.5
Steve Blocka7e24c12009-10-30 11:49:00 +0000859function StringBold() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000860 CHECK_OBJECT_COERCIBLE(this, "String.prototype.bold");
Steve Blocka7e24c12009-10-30 11:49:00 +0000861 return "<b>" + this + "</b>";
862}
863
864
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000865// ES6 draft, revision 26 (2014-07-18), section B.2.3.6
Steve Blocka7e24c12009-10-30 11:49:00 +0000866function StringFixed() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000867 CHECK_OBJECT_COERCIBLE(this, "String.prototype.fixed");
Steve Blocka7e24c12009-10-30 11:49:00 +0000868 return "<tt>" + this + "</tt>";
869}
870
871
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000872// ES6 draft, revision 26 (2014-07-18), section B.2.3.7
873function StringFontcolor(color) {
874 CHECK_OBJECT_COERCIBLE(this, "String.prototype.fontcolor");
875 return "<font color=\"" + HtmlEscape(color) + "\">" + this + "</font>";
876}
877
878
879// ES6 draft, revision 26 (2014-07-18), section B.2.3.8
880function StringFontsize(size) {
881 CHECK_OBJECT_COERCIBLE(this, "String.prototype.fontsize");
882 return "<font size=\"" + HtmlEscape(size) + "\">" + this + "</font>";
883}
884
885
886// ES6 draft, revision 26 (2014-07-18), section B.2.3.9
Steve Blocka7e24c12009-10-30 11:49:00 +0000887function StringItalics() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000888 CHECK_OBJECT_COERCIBLE(this, "String.prototype.italics");
Steve Blocka7e24c12009-10-30 11:49:00 +0000889 return "<i>" + this + "</i>";
890}
891
892
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000893// ES6 draft, revision 26 (2014-07-18), section B.2.3.10
894function StringLink(s) {
895 CHECK_OBJECT_COERCIBLE(this, "String.prototype.link");
896 return "<a href=\"" + HtmlEscape(s) + "\">" + this + "</a>";
897}
898
899
900// ES6 draft, revision 26 (2014-07-18), section B.2.3.11
Steve Blocka7e24c12009-10-30 11:49:00 +0000901function StringSmall() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000902 CHECK_OBJECT_COERCIBLE(this, "String.prototype.small");
Steve Blocka7e24c12009-10-30 11:49:00 +0000903 return "<small>" + this + "</small>";
904}
905
906
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000907// ES6 draft, revision 26 (2014-07-18), section B.2.3.12
Steve Blocka7e24c12009-10-30 11:49:00 +0000908function StringStrike() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000909 CHECK_OBJECT_COERCIBLE(this, "String.prototype.strike");
Steve Blocka7e24c12009-10-30 11:49:00 +0000910 return "<strike>" + this + "</strike>";
911}
912
913
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000914// ES6 draft, revision 26 (2014-07-18), section B.2.3.13
Steve Blocka7e24c12009-10-30 11:49:00 +0000915function StringSub() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000916 CHECK_OBJECT_COERCIBLE(this, "String.prototype.sub");
Steve Blocka7e24c12009-10-30 11:49:00 +0000917 return "<sub>" + this + "</sub>";
918}
919
920
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000921// ES6 draft, revision 26 (2014-07-18), section B.2.3.14
Steve Blocka7e24c12009-10-30 11:49:00 +0000922function StringSup() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000923 CHECK_OBJECT_COERCIBLE(this, "String.prototype.sup");
Steve Blocka7e24c12009-10-30 11:49:00 +0000924 return "<sup>" + this + "</sup>";
925}
926
Steve Blocka7e24c12009-10-30 11:49:00 +0000927// -------------------------------------------------------------------
928
Ben Murdoch589d6972011-11-30 16:04:58 +0000929function SetUpString() {
930 %CheckIsBootstrapping();
Steve Blocka7e24c12009-10-30 11:49:00 +0000931
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000932 // Set the String function and constructor.
933 %SetCode($String, StringConstructor);
934 %FunctionSetPrototype($String, new $String());
935
936 // Set up the constructor property on the String prototype object.
937 %AddNamedProperty($String.prototype, "constructor", $String, DONT_ENUM);
Steve Blocka7e24c12009-10-30 11:49:00 +0000938
Ben Murdoch589d6972011-11-30 16:04:58 +0000939 // Set up the non-enumerable functions on the String object.
Steve Blocka7e24c12009-10-30 11:49:00 +0000940 InstallFunctions($String, DONT_ENUM, $Array(
941 "fromCharCode", StringFromCharCode
942 ));
943
Ben Murdoch589d6972011-11-30 16:04:58 +0000944 // Set up the non-enumerable functions on the String prototype object.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100945 InstallFunctions($String.prototype, DONT_ENUM, $Array(
Steve Blocka7e24c12009-10-30 11:49:00 +0000946 "valueOf", StringValueOf,
947 "toString", StringToString,
948 "charAt", StringCharAt,
949 "charCodeAt", StringCharCodeAt,
950 "concat", StringConcat,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000951 "indexOf", StringIndexOfJS,
952 "lastIndexOf", StringLastIndexOfJS,
953 "localeCompare", StringLocaleCompareJS,
954 "match", StringMatchJS,
955 "normalize", StringNormalizeJS,
Steve Blocka7e24c12009-10-30 11:49:00 +0000956 "replace", StringReplace,
957 "search", StringSearch,
958 "slice", StringSlice,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000959 "split", StringSplitJS,
Steve Blocka7e24c12009-10-30 11:49:00 +0000960 "substring", StringSubstring,
961 "substr", StringSubstr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000962 "toLowerCase", StringToLowerCaseJS,
Steve Blocka7e24c12009-10-30 11:49:00 +0000963 "toLocaleLowerCase", StringToLocaleLowerCase,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000964 "toUpperCase", StringToUpperCaseJS,
Steve Blocka7e24c12009-10-30 11:49:00 +0000965 "toLocaleUpperCase", StringToLocaleUpperCase,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000966 "trim", StringTrimJS,
Steve Block3ce2e202009-11-05 08:53:23 +0000967 "trimLeft", StringTrimLeft,
968 "trimRight", StringTrimRight,
Steve Blocka7e24c12009-10-30 11:49:00 +0000969 "link", StringLink,
970 "anchor", StringAnchor,
971 "fontcolor", StringFontcolor,
972 "fontsize", StringFontsize,
973 "big", StringBig,
974 "blink", StringBlink,
975 "bold", StringBold,
976 "fixed", StringFixed,
977 "italics", StringItalics,
978 "small", StringSmall,
979 "strike", StringStrike,
980 "sub", StringSub,
Ben Murdochb0fe1622011-05-05 13:52:32 +0100981 "sup", StringSup
Steve Blocka7e24c12009-10-30 11:49:00 +0000982 ));
983}
984
Ben Murdoch589d6972011-11-30 16:04:58 +0000985SetUpString();