| Index: src/string.js
|
| ===================================================================
|
| --- src/string.js (revision 6904)
|
| +++ src/string.js (working copy)
|
| @@ -101,28 +101,28 @@
|
|
|
|
|
| // ECMA-262 section 15.5.4.7
|
| -function StringIndexOf(searchString /* position */) { // length == 1
|
| - var subject_str = TO_STRING_INLINE(this);
|
| - var pattern_str = TO_STRING_INLINE(searchString);
|
| - var subject_str_len = subject_str.length;
|
| - var pattern_str_len = pattern_str.length;
|
| +function StringIndexOf(pattern /* position */) { // length == 1
|
| + var subject = TO_STRING_INLINE(this);
|
| + var pattern = TO_STRING_INLINE(pattern);
|
| + var subject_len = subject.length;
|
| + var pattern_len = pattern.length;
|
| var index = 0;
|
| if (%_ArgumentsLength() > 1) {
|
| var arg1 = %_Arguments(1); // position
|
| index = TO_INTEGER(arg1);
|
| }
|
| if (index < 0) index = 0;
|
| - if (index > subject_str_len) index = subject_str_len;
|
| - if (pattern_str_len + index > subject_str_len) return -1;
|
| - return %StringIndexOf(subject_str, pattern_str, index);
|
| + if (index > subject_len) index = subject_len;
|
| + if (pattern_len + index > subject_len) return -1;
|
| + return %StringIndexOf(subject, pattern, index);
|
| }
|
|
|
|
|
| // ECMA-262 section 15.5.4.8
|
| -function StringLastIndexOf(searchString /* position */) { // length == 1
|
| +function StringLastIndexOf(pat /* position */) { // length == 1
|
| var sub = TO_STRING_INLINE(this);
|
| var subLength = sub.length;
|
| - var pat = TO_STRING_INLINE(searchString);
|
| + var pat = TO_STRING_INLINE(pat);
|
| var patLength = pat.length;
|
| var index = subLength - patLength;
|
| if (%_ArgumentsLength() > 1) {
|
| @@ -150,10 +150,8 @@
|
| // do anything locale specific.
|
| function StringLocaleCompare(other) {
|
| if (%_ArgumentsLength() === 0) return 0;
|
| -
|
| - var this_str = TO_STRING_INLINE(this);
|
| - var other_str = TO_STRING_INLINE(other);
|
| - return %StringLocaleCompare(this_str, other_str);
|
| + return %StringLocaleCompare(TO_STRING_INLINE(this),
|
| + TO_STRING_INLINE(other));
|
| }
|
|
|
|
|
| @@ -161,7 +159,7 @@
|
| function StringMatch(regexp) {
|
| var subject = TO_STRING_INLINE(this);
|
| if (IS_REGEXP(regexp)) {
|
| - if (!regexp.global) return regexp.exec(subject);
|
| + if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0);
|
| %_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
|
| // lastMatchInfo is defined in regexp.js.
|
| return %StringMatch(subject, regexp, lastMatchInfo);
|
| @@ -177,9 +175,7 @@
|
| // otherwise we call the runtime system.
|
| function SubString(string, start, end) {
|
| // Use the one character string cache.
|
| - if (start + 1 == end) {
|
| - return %_StringCharAt(string, start);
|
| - }
|
| + if (start + 1 == end) return %_StringCharAt(string, start);
|
| return %_SubString(string, start, end);
|
| }
|
|
|
| @@ -208,7 +204,10 @@
|
| replace);
|
| }
|
| } else {
|
| - return StringReplaceRegExp(subject, search, replace);
|
| + return %StringReplaceRegExpWithString(subject,
|
| + search,
|
| + TO_STRING_INLINE(replace),
|
| + lastMatchInfo);
|
| }
|
| }
|
|
|
| @@ -224,7 +223,11 @@
|
|
|
| // Compute the string to replace with.
|
| if (IS_FUNCTION(replace)) {
|
| - builder.add(replace.call(null, search, start, subject));
|
| + builder.add(%_CallFunction(%GetGlobalReceiver(),
|
| + search,
|
| + start,
|
| + subject,
|
| + replace));
|
| } else {
|
| reusableMatchInfo[CAPTURE0] = start;
|
| reusableMatchInfo[CAPTURE1] = end;
|
| @@ -239,29 +242,21 @@
|
| }
|
|
|
|
|
| -// Helper function for regular expressions in String.prototype.replace.
|
| -function StringReplaceRegExp(subject, regexp, replace) {
|
| - return %StringReplaceRegExpWithString(subject,
|
| - regexp,
|
| - TO_STRING_INLINE(replace),
|
| - lastMatchInfo);
|
| -}
|
| -
|
| -
|
| // Expand the $-expressions in the string and return a new string with
|
| // the result.
|
| function ExpandReplacement(string, subject, matchInfo, builder) {
|
| + var length = string.length;
|
| + var builder_elements = builder.elements;
|
| var next = %StringIndexOf(string, '$', 0);
|
| if (next < 0) {
|
| - builder.add(string);
|
| + if (length > 0) builder_elements.push(string);
|
| return;
|
| }
|
|
|
| // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102.
|
| var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; // Includes the match.
|
|
|
| - if (next > 0) builder.add(SubString(string, 0, next));
|
| - var length = string.length;
|
| + if (next > 0) builder_elements.push(SubString(string, 0, next));
|
|
|
| while (true) {
|
| var expansion = '$';
|
| @@ -270,7 +265,7 @@
|
| var peek = %_StringCharCodeAt(string, position);
|
| if (peek == 36) { // $$
|
| ++position;
|
| - builder.add('$');
|
| + builder_elements.push('$');
|
| } else if (peek == 38) { // $& - match
|
| ++position;
|
| builder.addSpecialSlice(matchInfo[CAPTURE0],
|
| @@ -307,14 +302,14 @@
|
| // digit capture references, we can only enter here when a
|
| // single digit capture reference is outside the range of
|
| // captures.
|
| - builder.add('$');
|
| + builder_elements.push('$');
|
| --position;
|
| }
|
| } else {
|
| - builder.add('$');
|
| + builder_elements.push('$');
|
| }
|
| } else {
|
| - builder.add('$');
|
| + builder_elements.push('$');
|
| }
|
|
|
| // Go the the next $ in the string.
|
| @@ -324,13 +319,15 @@
|
| // haven't reached the end, we need to append the suffix.
|
| if (next < 0) {
|
| if (position < length) {
|
| - builder.add(SubString(string, position, length));
|
| + builder_elements.push(SubString(string, position, length));
|
| }
|
| return;
|
| }
|
|
|
| // Append substring between the previous and the next $ character.
|
| - builder.add(SubString(string, position, next));
|
| + if (next > position) {
|
| + builder_elements.push(SubString(string, position, next));
|
| + }
|
| }
|
| };
|
|
|
| @@ -408,9 +405,7 @@
|
| lastMatchInfoOverride = override;
|
| var func_result =
|
| %_CallFunction(receiver, elem, match_start, subject, replace);
|
| - if (!IS_STRING(func_result)) {
|
| - func_result = NonStringToString(func_result);
|
| - }
|
| + func_result = TO_STRING_INLINE(func_result);
|
| res[i] = func_result;
|
| match_start += elem.length;
|
| }
|
| @@ -424,9 +419,7 @@
|
| // Use the apply argument as backing for global RegExp properties.
|
| lastMatchInfoOverride = elem;
|
| var func_result = replace.apply(null, elem);
|
| - if (!IS_STRING(func_result)) {
|
| - func_result = NonStringToString(func_result);
|
| - }
|
| + func_result = TO_STRING_INLINE(func_result);
|
| res[i] = func_result;
|
| }
|
| i++;
|
| @@ -487,8 +480,7 @@
|
| } else {
|
| regexp = new $RegExp(re);
|
| }
|
| - var s = TO_STRING_INLINE(this);
|
| - var match = DoRegExpExec(regexp, s, 0);
|
| + var match = DoRegExpExec(regexp, TO_STRING_INLINE(this), 0);
|
| if (match) {
|
| return match[CAPTURE0];
|
| }
|
| @@ -570,23 +562,22 @@
|
|
|
| var currentIndex = 0;
|
| var startIndex = 0;
|
| + var startMatch = 0;
|
| var result = [];
|
|
|
| outer_loop:
|
| while (true) {
|
|
|
| if (startIndex === length) {
|
| - result[result.length] = subject.slice(currentIndex, length);
|
| + result.push(SubString(subject, currentIndex, length));
|
| break;
|
| }
|
|
|
| - var matchInfo = splitMatch(separator, subject, currentIndex, startIndex);
|
| -
|
| - if (IS_NULL(matchInfo)) {
|
| - result[result.length] = subject.slice(currentIndex, length);
|
| + var matchInfo = DoRegExpExec(separator, subject, startIndex);
|
| + if (matchInfo == null || length === (startMatch = matchInfo[CAPTURE0])) {
|
| + result.push(SubString(subject, currentIndex, length));
|
| break;
|
| }
|
| -
|
| var endIndex = matchInfo[CAPTURE1];
|
|
|
| // We ignore a zero-length match at the currentIndex.
|
| @@ -595,17 +586,26 @@
|
| continue;
|
| }
|
|
|
| - result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]);
|
| + if (currentIndex + 1 == startMatch) {
|
| + result.push(%_StringCharAt(subject, currentIndex));
|
| + } else {
|
| + result.push(%_SubString(subject, currentIndex, startMatch));
|
| + }
|
| +
|
| if (result.length === limit) break;
|
|
|
| - var num_captures = NUMBER_OF_CAPTURES(matchInfo);
|
| - for (var i = 2; i < num_captures; i += 2) {
|
| - var start = matchInfo[CAPTURE(i)];
|
| - var end = matchInfo[CAPTURE(i + 1)];
|
| - if (start != -1 && end != -1) {
|
| - result[result.length] = SubString(subject, start, end);
|
| + var matchinfo_len = NUMBER_OF_CAPTURES(matchInfo) + REGEXP_FIRST_CAPTURE;
|
| + for (var i = REGEXP_FIRST_CAPTURE + 2; i < matchinfo_len; ) {
|
| + var start = matchInfo[i++];
|
| + var end = matchInfo[i++];
|
| + if (end != -1) {
|
| + if (start + 1 == end) {
|
| + result.push(%_StringCharAt(subject, start));
|
| + } else {
|
| + result.push(%_SubString(subject, start, end));
|
| + }
|
| } else {
|
| - result[result.length] = void 0;
|
| + result.push(void 0);
|
| }
|
| if (result.length === limit) break outer_loop;
|
| }
|
| @@ -616,19 +616,6 @@
|
| }
|
|
|
|
|
| -// ECMA-262 section 15.5.4.14
|
| -// Helper function used by split. This version returns the matchInfo
|
| -// instead of allocating a new array with basically the same information.
|
| -function splitMatch(separator, subject, current_index, start_index) {
|
| - var matchInfo = DoRegExpExec(separator, subject, start_index);
|
| - if (matchInfo == null) return null;
|
| - // Section 15.5.4.14 paragraph two says that we do not allow zero length
|
| - // matches at the end of the string.
|
| - if (matchInfo[CAPTURE0] === subject.length) return null;
|
| - return matchInfo;
|
| -}
|
| -
|
| -
|
| // ECMA-262 section 15.5.4.15
|
| function StringSubstring(start, end) {
|
| var s = TO_STRING_INLINE(this);
|
| @@ -656,7 +643,9 @@
|
| }
|
| }
|
|
|
| - return SubString(s, start_i, end_i);
|
| + return (start_i + 1 == end_i
|
| + ? %_StringCharAt(s, start_i)
|
| + : %_SubString(s, start_i, end_i));
|
| }
|
|
|
|
|
| @@ -694,7 +683,9 @@
|
| var end = start + len;
|
| if (end > s.length) end = s.length;
|
|
|
| - return SubString(s, start, end);
|
| + return (start + 1 == end
|
| + ? %_StringCharAt(s, start)
|
| + : %_SubString(s, start, end));
|
| }
|
|
|
|
|
| @@ -847,24 +838,21 @@
|
|
|
| ReplaceResultBuilder.prototype.add = function(str) {
|
| str = TO_STRING_INLINE(str);
|
| - if (str.length > 0) {
|
| - var elements = this.elements;
|
| - elements[elements.length] = str;
|
| - }
|
| + if (str.length > 0) this.elements.push(str);
|
| }
|
|
|
|
|
| ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) {
|
| var len = end - start;
|
| if (start < 0 || len <= 0) return;
|
| - var elements = this.elements;
|
| if (start < 0x80000 && len < 0x800) {
|
| - elements[elements.length] = (start << 11) | len;
|
| + this.elements.push((start << 11) | len);
|
| } else {
|
| // 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
|
| // so -len is a smi.
|
| - elements[elements.length] = -len;
|
| - elements[elements.length] = start;
|
| + var elements = this.elements;
|
| + elements.push(-len);
|
| + elements.push(start);
|
| }
|
| }
|
|
|
| @@ -875,11 +863,6 @@
|
| }
|
|
|
|
|
| -function StringToJSON(key) {
|
| - return CheckJSONPrimitive(this.valueOf());
|
| -}
|
| -
|
| -
|
| // -------------------------------------------------------------------
|
|
|
| function SetupString() {
|
| @@ -929,8 +912,7 @@
|
| "small", StringSmall,
|
| "strike", StringStrike,
|
| "sub", StringSub,
|
| - "sup", StringSup,
|
| - "toJSON", StringToJSON
|
| + "sup", StringSup
|
| ));
|
| }
|
|
|
|
|