blob: 521afc2c422dce994391bd022a5619d3e3811deb [file] [log] [blame]
// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(function(global, utils) {
"use strict";
%CheckIsBootstrapping();
// -------------------------------------------------------------------
// Imports
var GlobalString = global.String;
var matchSymbol = utils.ImportNow("match_symbol");
var searchSymbol = utils.ImportNow("search_symbol");
//-------------------------------------------------------------------
// ES#sec-createhtml
function HtmlEscape(str) {
return %RegExpInternalReplace(/"/g, TO_STRING(str), """);
}
// Set up the non-enumerable functions on the String prototype object.
DEFINE_METHODS(
GlobalString.prototype,
{
/* ES#sec-string.prototype.match */
match(pattern) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.match");
if (!IS_NULL_OR_UNDEFINED(pattern)) {
var matcher = pattern[matchSymbol];
if (!IS_UNDEFINED(matcher)) {
return %_Call(matcher, pattern, this);
}
}
var subject = TO_STRING(this);
// Equivalent to RegExpCreate (ES#sec-regexpcreate)
var regexp = %RegExpCreate(pattern);
return regexp[matchSymbol](subject);
}
/* ES#sec-string.prototype.search */
search(pattern) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.search");
if (!IS_NULL_OR_UNDEFINED(pattern)) {
var searcher = pattern[searchSymbol];
if (!IS_UNDEFINED(searcher)) {
return %_Call(searcher, pattern, this);
}
}
var subject = TO_STRING(this);
// Equivalent to RegExpCreate (ES#sec-regexpcreate)
var regexp = %RegExpCreate(pattern);
return %_Call(regexp[searchSymbol], regexp, subject);
}
/* ES#sec-string.prototype.anchor */
anchor(name) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.anchor");
return "<a name=\"" + HtmlEscape(name) + "\">" + TO_STRING(this) +
"</a>";
}
/* ES#sec-string.prototype.big */
big() {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.big");
return "<big>" + TO_STRING(this) + "</big>";
}
/* ES#sec-string.prototype.blink */
blink() {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.blink");
return "<blink>" + TO_STRING(this) + "</blink>";
}
/* ES#sec-string.prototype.bold */
bold() {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.bold");
return "<b>" + TO_STRING(this) + "</b>";
}
/* ES#sec-string.prototype.fixed */
fixed() {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.fixed");
return "<tt>" + TO_STRING(this) + "</tt>";
}
/* ES#sec-string.prototype.fontcolor */
fontcolor(color) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.fontcolor");
return "<font color=\"" + HtmlEscape(color) + "\">" + TO_STRING(this) +
"</font>";
}
/* ES#sec-string.prototype.fontsize */
fontsize(size) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.fontsize");
return "<font size=\"" + HtmlEscape(size) + "\">" + TO_STRING(this) +
"</font>";
}
/* ES#sec-string.prototype.italics */
italics() {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.italics");
return "<i>" + TO_STRING(this) + "</i>";
}
/* ES#sec-string.prototype.link */
link(s) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.link");
return "<a href=\"" + HtmlEscape(s) + "\">" + TO_STRING(this) + "</a>";
}
/* ES#sec-string.prototype.small */
small() {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.small");
return "<small>" + TO_STRING(this) + "</small>";
}
/* ES#sec-string.prototype.strike */
strike() {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.strike");
return "<strike>" + TO_STRING(this) + "</strike>";
}
/* ES#sec-string.prototype.sub */
sub() {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.sub");
return "<sub>" + TO_STRING(this) + "</sub>";
}
/* ES#sec-string.prototype.sup */
sup() {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.sup");
return "<sup>" + TO_STRING(this) + "</sup>";
}
/* ES#sec-string.prototype.repeat */
repeat(count) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.repeat");
var s = TO_STRING(this);
var n = TO_INTEGER(count);
if (n < 0 || n === INFINITY) throw %make_range_error(kInvalidCountValue);
// Early return to allow an arbitrarily-large repeat of the empty string.
if (s.length === 0) return "";
// The maximum string length is stored in a smi, so a longer repeat
// must result in a range error.
if (n > %_MaxSmi()) throw %make_range_error(kInvalidStringLength);
var r = "";
while (true) {
if (n & 1) r += s;
n >>= 1;
if (n === 0) return r;
s += s;
}
}
/* ES#sec-string.prototype.codepointat */
codePointAt(pos) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.codePointAt");
var string = TO_STRING(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;
}
}
);
function StringPad(thisString, maxLength, fillString) {
maxLength = TO_LENGTH(maxLength);
var stringLength = thisString.length;
if (maxLength <= stringLength) return "";
if (IS_UNDEFINED(fillString)) {
fillString = " ";
} else {
fillString = TO_STRING(fillString);
if (fillString === "") {
// If filler is the empty String, return S.
return "";
}
}
var fillLength = maxLength - stringLength;
var repetitions = (fillLength / fillString.length) | 0;
var remainingChars = (fillLength - fillString.length * repetitions) | 0;
var filler = "";
while (true) {
if (repetitions & 1) filler += fillString;
repetitions >>= 1;
if (repetitions === 0) break;
fillString += fillString;
}
if (remainingChars) {
filler += %_SubString(fillString, 0, remainingChars);
}
return filler;
}
DEFINE_METHODS_LEN(
GlobalString.prototype,
{
/* ES#sec-string.prototype.padstart */
/* String.prototype.padStart(maxLength [, fillString]) */
padStart(maxLength, fillString) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.padStart");
var thisString = TO_STRING(this);
return StringPad(thisString, maxLength, fillString) + thisString;
}
/* ES#sec-string.prototype.padend */
/* String.prototype.padEnd(maxLength [, fillString]) */
padEnd(maxLength, fillString) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.padEnd");
var thisString = TO_STRING(this);
return thisString + StringPad(thisString, maxLength, fillString);
}
},
1 /* Set functions length */
);
// -------------------------------------------------------------------
// String methods related to templates
// Set up the non-enumerable functions on the String object.
DEFINE_METHOD(
GlobalString,
/* ES#sec-string.raw */
raw(callSite) {
var numberOfSubstitutions = arguments.length;
var cooked = TO_OBJECT(callSite);
var raw = TO_OBJECT(cooked.raw);
var literalSegments = TO_LENGTH(raw.length);
if (literalSegments <= 0) return "";
var result = TO_STRING(raw[0]);
for (var i = 1; i < literalSegments; ++i) {
if (i < numberOfSubstitutions) {
result += TO_STRING(arguments[i]);
}
result += TO_STRING(raw[i]);
}
return result;
}
);
// -------------------------------------------------------------------
})