diff options
Diffstat (limited to 'deps/v8/src/string.js')
-rw-r--r-- | deps/v8/src/string.js | 387 |
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; + +})(); |