summaryrefslogtreecommitdiff
path: root/deps/v8/src/string.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/string.js')
-rw-r--r--deps/v8/src/string.js387
1 files changed, 293 insertions, 94 deletions
diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js
index ac5cb7f99e..0f29cd1dc1 100644
--- a/deps/v8/src/string.js
+++ b/deps/v8/src/string.js
@@ -2,11 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// This file relies on the fact that the following declaration has been made
-// in runtime.js:
-// var $String = global.String;
+var $stringCharAt;
+var $stringIndexOf;
+var $stringSubstring;
-// -------------------------------------------------------------------
+(function() {
+
+%CheckIsBootstrapping();
+
+var GlobalArray = global.Array;
+var GlobalRegExp = global.RegExp;
+var GlobalString = global.String;
+
+//-------------------------------------------------------------------
function StringConstructor(x) {
if (%_ArgumentsLength() == 0) x = '';
@@ -14,7 +22,7 @@ function StringConstructor(x) {
%_SetValueOf(this, TO_STRING_INLINE(x));
} else {
return IS_SYMBOL(x) ?
- %_CallFunction(x, SymbolToString) : TO_STRING_INLINE(x);
+ %_CallFunction(x, $symbolToString) : TO_STRING_INLINE(x);
}
}
@@ -38,7 +46,7 @@ function StringValueOf() {
// ECMA-262, section 15.5.4.4
-function StringCharAt(pos) {
+function StringCharAtJS(pos) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.charAt");
var result = %_StringCharAt(this, pos);
@@ -50,7 +58,7 @@ function StringCharAt(pos) {
// ECMA-262 section 15.5.4.5
-function StringCharCodeAt(pos) {
+function StringCharCodeAtJS(pos) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.charCodeAt");
var result = %_StringCharCodeAt(this, pos);
@@ -64,11 +72,10 @@ function StringCharCodeAt(pos) {
// ECMA-262, section 15.5.4.6
function StringConcat(other /* and more */) { // length == 1
CHECK_OBJECT_COERCIBLE(this, "String.prototype.concat");
-
var len = %_ArgumentsLength();
var this_as_string = TO_STRING_INLINE(this);
if (len === 1) {
- return this_as_string + other;
+ return this_as_string + TO_STRING_INLINE(other);
}
var parts = new InternalArray(len + 1);
parts[0] = this_as_string;
@@ -147,16 +154,15 @@ function StringMatchJS(regexp) {
// value is discarded.
var lastIndex = regexp.lastIndex;
TO_INTEGER_FOR_SIDE_EFFECT(lastIndex);
- if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0);
- // lastMatchInfo is defined in regexp.js.
- var result = %StringMatch(subject, regexp, lastMatchInfo);
- if (result !== null) lastMatchInfoOverride = null;
+ if (!regexp.global) return $regexpExecNoTests(regexp, subject, 0);
+ var result = %StringMatch(subject, regexp, $regexpLastMatchInfo);
+ if (result !== null) $regexpLastMatchInfoOverride = null;
regexp.lastIndex = 0;
return result;
}
// Non-regexp argument.
- regexp = new $RegExp(regexp);
- return RegExpExecNoTests(regexp, subject, 0);
+ regexp = new GlobalRegExp(regexp);
+ return $regexpExecNoTests(regexp, subject, 0);
}
@@ -182,9 +188,9 @@ function StringNormalizeJS(form) {
}
-// This has the same size as the lastMatchInfo array, and can be used for
-// functions that expect that structure to be returned. It is used when the
-// needle is a string rather than a regexp. In this case we can't update
+// This has the same size as the $regexpLastMatchInfo array, and can be used
+// for functions that expect that structure to be returned. It is used when
+// the needle is a string rather than a regexp. In this case we can't update
// lastMatchArray without erroneously affecting the properties on the global
// RegExp object.
var reusableMatchInfo = [2, "", "", -1, -1];
@@ -224,7 +230,7 @@ function StringReplace(search, replace) {
if (!search.global) {
// Non-global regexp search, string replace.
- var match = DoRegExpExec(search, subject, 0);
+ var match = $regexpExec(search, subject, 0);
if (match == null) {
search.lastIndex = 0
return subject;
@@ -233,28 +239,28 @@ function StringReplace(search, replace) {
return %_SubString(subject, 0, match[CAPTURE0]) +
%_SubString(subject, match[CAPTURE1], subject.length)
}
- return ExpandReplacement(replace, subject, lastMatchInfo,
+ return ExpandReplacement(replace, subject, $regexpLastMatchInfo,
%_SubString(subject, 0, match[CAPTURE0])) +
%_SubString(subject, match[CAPTURE1], subject.length);
}
// Global regexp search, string replace.
search.lastIndex = 0;
- if (lastMatchInfoOverride == null) {
+ if ($regexpLastMatchInfoOverride == null) {
return %StringReplaceGlobalRegExpWithString(
- subject, search, replace, lastMatchInfo);
+ subject, search, replace, $regexpLastMatchInfo);
} else {
// We use this hack to detect whether StringReplaceRegExpWithString
// found at least one hit. In that case we need to remove any
// override.
- var saved_subject = lastMatchInfo[LAST_SUBJECT_INDEX];
- lastMatchInfo[LAST_SUBJECT_INDEX] = 0;
+ var saved_subject = $regexpLastMatchInfo[LAST_SUBJECT_INDEX];
+ $regexpLastMatchInfo[LAST_SUBJECT_INDEX] = 0;
var answer = %StringReplaceGlobalRegExpWithString(
- subject, search, replace, lastMatchInfo);
- if (%_IsSmi(lastMatchInfo[LAST_SUBJECT_INDEX])) {
- lastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
+ subject, search, replace, $regexpLastMatchInfo);
+ if (%_IsSmi($regexpLastMatchInfo[LAST_SUBJECT_INDEX])) {
+ $regexpLastMatchInfo[LAST_SUBJECT_INDEX] = saved_subject;
} else {
- lastMatchInfoOverride = null;
+ $regexpLastMatchInfoOverride = null;
}
return answer;
}
@@ -418,7 +424,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
}
var res = %RegExpExecMultiple(regexp,
subject,
- lastMatchInfo,
+ $regexpLastMatchInfo,
resultArray);
regexp.lastIndex = 0;
if (IS_NULL(res)) {
@@ -427,7 +433,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
return subject;
}
var len = res.length;
- if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
+ if (NUMBER_OF_CAPTURES($regexpLastMatchInfo) == 2) {
// If the number of captures is two then there are no explicit captures in
// the regexp, just the implicit capture that captures the whole match. In
// this case we can simplify quite a bit and end up with something faster.
@@ -451,7 +457,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
} else {
override[0] = elem;
override[1] = match_start;
- lastMatchInfoOverride = override;
+ $regexpLastMatchInfoOverride = override;
var func_result =
%_CallFunction(receiver, elem, match_start, subject, replace);
// Overwrite the i'th element in the results with the string we got
@@ -467,7 +473,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
if (!%_IsSmi(elem)) {
// elem must be an Array.
// Use the apply argument as backing for global RegExp properties.
- lastMatchInfoOverride = elem;
+ $regexpLastMatchInfoOverride = elem;
var func_result = %Apply(replace, receiver, elem, 0, elem.length);
// Overwrite the i'th element in the results with the string we got
// back from the callback function.
@@ -483,7 +489,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
- var matchInfo = DoRegExpExec(regexp, subject, 0);
+ var matchInfo = $regexpExec(regexp, subject, 0);
if (IS_NULL(matchInfo)) {
regexp.lastIndex = 0;
return subject;
@@ -530,9 +536,9 @@ function StringSearch(re) {
} else if (IS_REGEXP(re)) {
regexp = re;
} else {
- regexp = new $RegExp(re);
+ regexp = new GlobalRegExp(re);
}
- var match = DoRegExpExec(regexp, TO_STRING_INLINE(this), 0);
+ var match = $regexpExec(regexp, TO_STRING_INLINE(this), 0);
if (match) {
return match[CAPTURE0];
}
@@ -618,7 +624,7 @@ function StringSplitJS(separator, limit) {
function StringSplitOnRegExp(subject, separator, limit, length) {
if (length === 0) {
- if (DoRegExpExec(separator, subject, 0, 0) != null) {
+ if ($regexpExec(separator, subject, 0, 0) != null) {
return [];
}
return [subject];
@@ -637,7 +643,7 @@ function StringSplitOnRegExp(subject, separator, limit, length) {
break;
}
- var matchInfo = DoRegExpExec(separator, subject, startIndex);
+ var matchInfo = $regexpExec(separator, subject, startIndex);
if (matchInfo == null || length === (startMatch = matchInfo[CAPTURE0])) {
result[result.length] = %_SubString(subject, currentIndex, length);
break;
@@ -924,62 +930,255 @@ function StringSup() {
return "<sup>" + this + "</sup>";
}
+// ES6 draft 01-20-14, section 21.1.3.13
+function StringRepeat(count) {
+ CHECK_OBJECT_COERCIBLE(this, "String.prototype.repeat");
+
+ var s = TO_STRING_INLINE(this);
+ var n = ToInteger(count);
+ // The maximum string length is stored in a smi, so a longer repeat
+ // must result in a range error.
+ if (n < 0 || n > %_MaxSmi()) {
+ throw MakeRangeError("invalid_count_value", []);
+ }
+
+ var r = "";
+ while (true) {
+ if (n & 1) r += s;
+ n >>= 1;
+ if (n === 0) return r;
+ s += s;
+ }
+}
+
+
+// ES6 draft 04-05-14, section 21.1.3.18
+function StringStartsWith(searchString /* position */) { // length == 1
+ CHECK_OBJECT_COERCIBLE(this, "String.prototype.startsWith");
+
+ var s = TO_STRING_INLINE(this);
+
+ if (IS_REGEXP(searchString)) {
+ throw MakeTypeError("first_argument_not_regexp",
+ ["String.prototype.startsWith"]);
+ }
+
+ var ss = TO_STRING_INLINE(searchString);
+ var pos = 0;
+ if (%_ArgumentsLength() > 1) {
+ pos = %_Arguments(1); // position
+ pos = ToInteger(pos);
+ }
+
+ var s_len = s.length;
+ var start = $min($max(pos, 0), s_len);
+ var ss_len = ss.length;
+ if (ss_len + start > s_len) {
+ return false;
+ }
+
+ return %StringIndexOf(s, ss, start) === start;
+}
+
+
+// ES6 draft 04-05-14, section 21.1.3.7
+function StringEndsWith(searchString /* position */) { // length == 1
+ CHECK_OBJECT_COERCIBLE(this, "String.prototype.endsWith");
+
+ var s = TO_STRING_INLINE(this);
+
+ if (IS_REGEXP(searchString)) {
+ throw MakeTypeError("first_argument_not_regexp",
+ ["String.prototype.endsWith"]);
+ }
+
+ var ss = TO_STRING_INLINE(searchString);
+ var s_len = s.length;
+ var pos = s_len;
+ if (%_ArgumentsLength() > 1) {
+ var arg = %_Arguments(1); // position
+ if (!IS_UNDEFINED(arg)) {
+ pos = ToInteger(arg);
+ }
+ }
+
+ var end = $min($max(pos, 0), s_len);
+ var ss_len = ss.length;
+ var start = end - ss_len;
+ if (start < 0) {
+ return false;
+ }
+
+ return %StringLastIndexOf(s, ss, start) === start;
+}
+
+
+// ES6 draft 04-05-14, section 21.1.3.6
+function StringIncludes(searchString /* position */) { // length == 1
+ CHECK_OBJECT_COERCIBLE(this, "String.prototype.includes");
+
+ var s = TO_STRING_INLINE(this);
+
+ if (IS_REGEXP(searchString)) {
+ throw MakeTypeError("first_argument_not_regexp",
+ ["String.prototype.includes"]);
+ }
+
+ var ss = TO_STRING_INLINE(searchString);
+ var pos = 0;
+ if (%_ArgumentsLength() > 1) {
+ pos = %_Arguments(1); // position
+ pos = ToInteger(pos);
+ }
+
+ var s_len = s.length;
+ var start = $min($max(pos, 0), s_len);
+ var ss_len = ss.length;
+ if (ss_len + start > s_len) {
+ return false;
+ }
+
+ return %StringIndexOf(s, ss, start) !== -1;
+}
+
+
+// ES6 Draft 05-22-2014, section 21.1.3.3
+function StringCodePointAt(pos) {
+ CHECK_OBJECT_COERCIBLE(this, "String.prototype.codePointAt");
+
+ var string = TO_STRING_INLINE(this);
+ var size = string.length;
+ pos = TO_INTEGER(pos);
+ if (pos < 0 || pos >= size) {
+ return UNDEFINED;
+ }
+ var first = %_StringCharCodeAt(string, pos);
+ if (first < 0xD800 || first > 0xDBFF || pos + 1 == size) {
+ return first;
+ }
+ var second = %_StringCharCodeAt(string, pos + 1);
+ if (second < 0xDC00 || second > 0xDFFF) {
+ return first;
+ }
+ return (first - 0xD800) * 0x400 + second + 0x2400;
+}
+
+
+// ES6 Draft 05-22-2014, section 21.1.2.2
+function StringFromCodePoint(_) { // length = 1
+ var code;
+ var length = %_ArgumentsLength();
+ var index;
+ var result = "";
+ for (index = 0; index < length; index++) {
+ code = %_Arguments(index);
+ if (!%_IsSmi(code)) {
+ code = ToNumber(code);
+ }
+ if (code < 0 || code > 0x10FFFF || code !== TO_INTEGER(code)) {
+ throw MakeRangeError("invalid_code_point", [code]);
+ }
+ if (code <= 0xFFFF) {
+ result += %_StringCharFromCode(code);
+ } else {
+ code -= 0x10000;
+ result += %_StringCharFromCode((code >>> 10) & 0x3FF | 0xD800);
+ result += %_StringCharFromCode(code & 0x3FF | 0xDC00);
+ }
+ }
+ return result;
+}
+
+
+// -------------------------------------------------------------------
+// String methods related to templates
+
+// ES6 Draft 03-17-2015, section 21.1.2.4
+function StringRaw(callSite) {
+ // TODO(caitp): Use rest parameters when implemented
+ var numberOfSubstitutions = %_ArgumentsLength();
+ var cooked = ToObject(callSite);
+ var raw = ToObject(cooked.raw);
+ var literalSegments = ToLength(raw.length);
+ if (literalSegments <= 0) return "";
+
+ var result = ToString(raw[0]);
+
+ for (var i = 1; i < literalSegments; ++i) {
+ if (i < numberOfSubstitutions) {
+ result += ToString(%_Arguments(i));
+ }
+ result += ToString(raw[i]);
+ }
+
+ return result;
+}
+
// -------------------------------------------------------------------
-function SetUpString() {
- %CheckIsBootstrapping();
-
- // Set the String function and constructor.
- %SetCode($String, StringConstructor);
- %FunctionSetPrototype($String, new $String());
-
- // Set up the constructor property on the String prototype object.
- %AddNamedProperty($String.prototype, "constructor", $String, DONT_ENUM);
-
- // Set up the non-enumerable functions on the String object.
- InstallFunctions($String, DONT_ENUM, $Array(
- "fromCharCode", StringFromCharCode
- ));
-
- // Set up the non-enumerable functions on the String prototype object.
- InstallFunctions($String.prototype, DONT_ENUM, $Array(
- "valueOf", StringValueOf,
- "toString", StringToString,
- "charAt", StringCharAt,
- "charCodeAt", StringCharCodeAt,
- "concat", StringConcat,
- "indexOf", StringIndexOfJS,
- "lastIndexOf", StringLastIndexOfJS,
- "localeCompare", StringLocaleCompareJS,
- "match", StringMatchJS,
- "normalize", StringNormalizeJS,
- "replace", StringReplace,
- "search", StringSearch,
- "slice", StringSlice,
- "split", StringSplitJS,
- "substring", StringSubstring,
- "substr", StringSubstr,
- "toLowerCase", StringToLowerCaseJS,
- "toLocaleLowerCase", StringToLocaleLowerCase,
- "toUpperCase", StringToUpperCaseJS,
- "toLocaleUpperCase", StringToLocaleUpperCase,
- "trim", StringTrimJS,
- "trimLeft", StringTrimLeft,
- "trimRight", StringTrimRight,
- "link", StringLink,
- "anchor", StringAnchor,
- "fontcolor", StringFontcolor,
- "fontsize", StringFontsize,
- "big", StringBig,
- "blink", StringBlink,
- "bold", StringBold,
- "fixed", StringFixed,
- "italics", StringItalics,
- "small", StringSmall,
- "strike", StringStrike,
- "sub", StringSub,
- "sup", StringSup
- ));
-}
-
-SetUpString();
+// Set the String function and constructor.
+%SetCode(GlobalString, StringConstructor);
+%FunctionSetPrototype(GlobalString, new GlobalString());
+
+// Set up the constructor property on the String prototype object.
+%AddNamedProperty(
+ GlobalString.prototype, "constructor", GlobalString, DONT_ENUM);
+
+// Set up the non-enumerable functions on the String object.
+InstallFunctions(GlobalString, DONT_ENUM, GlobalArray(
+ "fromCharCode", StringFromCharCode,
+ "fromCodePoint", StringFromCodePoint,
+ "raw", StringRaw
+));
+
+// Set up the non-enumerable functions on the String prototype object.
+InstallFunctions(GlobalString.prototype, DONT_ENUM, GlobalArray(
+ "valueOf", StringValueOf,
+ "toString", StringToString,
+ "charAt", StringCharAtJS,
+ "charCodeAt", StringCharCodeAtJS,
+ "codePointAt", StringCodePointAt,
+ "concat", StringConcat,
+ "endsWith", StringEndsWith,
+ "includes", StringIncludes,
+ "indexOf", StringIndexOfJS,
+ "lastIndexOf", StringLastIndexOfJS,
+ "localeCompare", StringLocaleCompareJS,
+ "match", StringMatchJS,
+ "normalize", StringNormalizeJS,
+ "repeat", StringRepeat,
+ "replace", StringReplace,
+ "search", StringSearch,
+ "slice", StringSlice,
+ "split", StringSplitJS,
+ "substring", StringSubstring,
+ "substr", StringSubstr,
+ "startsWith", StringStartsWith,
+ "toLowerCase", StringToLowerCaseJS,
+ "toLocaleLowerCase", StringToLocaleLowerCase,
+ "toUpperCase", StringToUpperCaseJS,
+ "toLocaleUpperCase", StringToLocaleUpperCase,
+ "trim", StringTrimJS,
+ "trimLeft", StringTrimLeft,
+ "trimRight", StringTrimRight,
+
+ "link", StringLink,
+ "anchor", StringAnchor,
+ "fontcolor", StringFontcolor,
+ "fontsize", StringFontsize,
+ "big", StringBig,
+ "blink", StringBlink,
+ "bold", StringBold,
+ "fixed", StringFixed,
+ "italics", StringItalics,
+ "small", StringSmall,
+ "strike", StringStrike,
+ "sub", StringSub,
+ "sup", StringSup
+));
+
+$stringCharAt = StringCharAtJS;
+$stringIndexOf = StringIndexOfJS;
+$stringSubstring = StringSubstring;
+
+})();