Commit 1eacdd55 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Implement String.prototype.codePointAt and String.fromCodePoint.

Contributed by Mathias Bynens <mathiasb@opera.com>.

TBR=mathiasb@opera.com, rossberg@chromium.org
BUG=v8:2840
LOG=Y

Review URL: https://codereview.chromium.org/406863003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22493 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 219e7631
......@@ -120,17 +120,73 @@ function StringContains(searchString /* position */) { // length == 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 += StringFromCharCode(
code >>> 10 & 0x3FF | 0xD800,
0xDC00 | code & 0x3FF
);
}
}
return result;
}
// -------------------------------------------------------------------
function ExtendStringPrototype() {
%CheckIsBootstrapping();
// Set up the non-enumerable functions on the String object.
InstallFunctions($String, DONT_ENUM, $Array(
"fromCodePoint", StringFromCodePoint
));
// Set up the non-enumerable functions on the String prototype object.
InstallFunctions($String.prototype, DONT_ENUM, $Array(
"repeat", StringRepeat,
"startsWith", StringStartsWith,
"codePointAt", StringCodePointAt,
"contains", StringContains,
"endsWith", StringEndsWith,
"contains", StringContains
"repeat", StringRepeat,
"startsWith", StringStartsWith
));
}
......
......@@ -113,6 +113,7 @@ var kMessages = {
stack_overflow: ["Maximum call stack size exceeded"],
invalid_time_value: ["Invalid time value"],
invalid_count_value: ["Invalid count value"],
invalid_code_point: ["Invalid code point ", "%0"],
// ReferenceError
invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"],
invalid_lhs_in_for: ["Invalid left-hand side in for-loop"],
......
// Copyright 2014 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.
// Flags: --harmony-strings
// Tests taken from:
// https://github.com/mathiasbynens/String.prototype.codePointAt
assertEquals(String.prototype.codePointAt.length, 1);
assertEquals(String.prototype.propertyIsEnumerable("codePointAt"), false);
// String that starts with a BMP symbol
assertEquals("abc\uD834\uDF06def".codePointAt(""), 0x61);
assertEquals("abc\uD834\uDF06def".codePointAt("_"), 0x61);
assertEquals("abc\uD834\uDF06def".codePointAt(), 0x61);
assertEquals("abc\uD834\uDF06def".codePointAt(-Infinity), undefined);
assertEquals("abc\uD834\uDF06def".codePointAt(-1), undefined);
assertEquals("abc\uD834\uDF06def".codePointAt(-0), 0x61);
assertEquals("abc\uD834\uDF06def".codePointAt(0), 0x61);
assertEquals("abc\uD834\uDF06def".codePointAt(3), 0x1D306);
assertEquals("abc\uD834\uDF06def".codePointAt(4), 0xDF06);
assertEquals("abc\uD834\uDF06def".codePointAt(5), 0x64);
assertEquals("abc\uD834\uDF06def".codePointAt(42), undefined);
assertEquals("abc\uD834\uDF06def".codePointAt(Infinity), undefined);
assertEquals("abc\uD834\uDF06def".codePointAt(Infinity), undefined);
assertEquals("abc\uD834\uDF06def".codePointAt(NaN), 0x61);
assertEquals("abc\uD834\uDF06def".codePointAt(false), 0x61);
assertEquals("abc\uD834\uDF06def".codePointAt(null), 0x61);
assertEquals("abc\uD834\uDF06def".codePointAt(undefined), 0x61);
// String that starts with an astral symbol
assertEquals("\uD834\uDF06def".codePointAt(""), 0x1D306);
assertEquals("\uD834\uDF06def".codePointAt("1"), 0xDF06);
assertEquals("\uD834\uDF06def".codePointAt("_"), 0x1D306);
assertEquals("\uD834\uDF06def".codePointAt(), 0x1D306);
assertEquals("\uD834\uDF06def".codePointAt(-1), undefined);
assertEquals("\uD834\uDF06def".codePointAt(-0), 0x1D306);
assertEquals("\uD834\uDF06def".codePointAt(0), 0x1D306);
assertEquals("\uD834\uDF06def".codePointAt(1), 0xDF06);
assertEquals("\uD834\uDF06def".codePointAt(42), undefined);
assertEquals("\uD834\uDF06def".codePointAt(false), 0x1D306);
assertEquals("\uD834\uDF06def".codePointAt(null), 0x1D306);
assertEquals("\uD834\uDF06def".codePointAt(undefined), 0x1D306);
// Lone high surrogates
assertEquals("\uD834abc".codePointAt(""), 0xD834);
assertEquals("\uD834abc".codePointAt("_"), 0xD834);
assertEquals("\uD834abc".codePointAt(), 0xD834);
assertEquals("\uD834abc".codePointAt(-1), undefined);
assertEquals("\uD834abc".codePointAt(-0), 0xD834);
assertEquals("\uD834abc".codePointAt(0), 0xD834);
assertEquals("\uD834abc".codePointAt(false), 0xD834);
assertEquals("\uD834abc".codePointAt(NaN), 0xD834);
assertEquals("\uD834abc".codePointAt(null), 0xD834);
assertEquals("\uD834abc".codePointAt(undefined), 0xD834);
// Lone low surrogates
assertEquals("\uDF06abc".codePointAt(""), 0xDF06);
assertEquals("\uDF06abc".codePointAt("_"), 0xDF06);
assertEquals("\uDF06abc".codePointAt(), 0xDF06);
assertEquals("\uDF06abc".codePointAt(-1), undefined);
assertEquals("\uDF06abc".codePointAt(-0), 0xDF06);
assertEquals("\uDF06abc".codePointAt(0), 0xDF06);
assertEquals("\uDF06abc".codePointAt(false), 0xDF06);
assertEquals("\uDF06abc".codePointAt(NaN), 0xDF06);
assertEquals("\uDF06abc".codePointAt(null), 0xDF06);
assertEquals("\uDF06abc".codePointAt(undefined), 0xDF06);
assertThrows(function() {
String.prototype.codePointAt.call(undefined);
}, TypeError);
assertThrows(function() {
String.prototype.codePointAt.call(undefined, 4);
}, TypeError);
assertThrows(function() {
String.prototype.codePointAt.call(null);
}, TypeError);
assertThrows(function() {
String.prototype.codePointAt.call(null, 4);
}, TypeError);
assertEquals(String.prototype.codePointAt.call(42, 0), 0x34);
assertEquals(String.prototype.codePointAt.call(42, 1), 0x32);
assertEquals(String.prototype.codePointAt.call({
toString: function() { return "abc"; }
}, 2), 0x63);
var tmp = 0;
assertEquals(String.prototype.codePointAt.call({
toString: function() { ++tmp; return String(tmp); }
}, 0), 0x31);
assertEquals(tmp, 1);
// Copyright 2014 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.
// Flags: --harmony-strings
// Tests taken from:
// https://github.com/mathiasbynens/String.fromCodePoint
assertEquals(String.fromCodePoint.length, 1);
assertEquals(String.propertyIsEnumerable("fromCodePoint"), false);
assertEquals(String.fromCodePoint(""), "\0");
assertEquals(String.fromCodePoint(), "");
assertEquals(String.fromCodePoint(-0), "\0");
assertEquals(String.fromCodePoint(0), "\0");
assertEquals(String.fromCodePoint(0x1D306), "\uD834\uDF06");
assertEquals(
String.fromCodePoint(0x1D306, 0x61, 0x1D307),
"\uD834\uDF06a\uD834\uDF07");
assertEquals(String.fromCodePoint(0x61, 0x62, 0x1D307), "ab\uD834\uDF07");
assertEquals(String.fromCodePoint(false), "\0");
assertEquals(String.fromCodePoint(null), "\0");
assertThrows(function() { String.fromCodePoint("_"); }, RangeError);
assertThrows(function() { String.fromCodePoint("+Infinity"); }, RangeError);
assertThrows(function() { String.fromCodePoint("-Infinity"); }, RangeError);
assertThrows(function() { String.fromCodePoint(-1); }, RangeError);
assertThrows(function() { String.fromCodePoint(0x10FFFF + 1); }, RangeError);
assertThrows(function() { String.fromCodePoint(3.14); }, RangeError);
assertThrows(function() { String.fromCodePoint(3e-2); }, RangeError);
assertThrows(function() { String.fromCodePoint(-Infinity); }, RangeError);
assertThrows(function() { String.fromCodePoint(+Infinity); }, RangeError);
assertThrows(function() { String.fromCodePoint(NaN); }, RangeError);
assertThrows(function() { String.fromCodePoint(undefined); }, RangeError);
assertThrows(function() { String.fromCodePoint({}); }, RangeError);
assertThrows(function() { String.fromCodePoint(/./); }, RangeError);
assertThrows(function() { String.fromCodePoint({
valueOf: function() { throw Error(); } });
}, Error);
assertThrows(function() { String.fromCodePoint({
valueOf: function() { throw Error(); } });
}, Error);
var tmp = 0x60;
assertEquals(String.fromCodePoint({
valueOf: function() { ++tmp; return tmp; }
}), "a");
assertEquals(tmp, 0x61);
var counter = Math.pow(2, 15) * 3 / 2;
var result = [];
while (--counter >= 0) {
result.push(0); // one code unit per symbol
}
String.fromCodePoint.apply(null, result); // must not throw
var counter = Math.pow(2, 15) * 3 / 2;
var result = [];
while (--counter >= 0) {
result.push(0xFFFF + 1); // two code units per symbol
}
String.fromCodePoint.apply(null, result); // must not throw
......@@ -51,7 +51,7 @@ EXPECTED_FUNCTION_COUNT = 418
EXPECTED_FUZZABLE_COUNT = 333
EXPECTED_CCTEST_COUNT = 8
EXPECTED_UNKNOWN_COUNT = 4
EXPECTED_BUILTINS_COUNT = 810
EXPECTED_BUILTINS_COUNT = 812
# Don't call these at all.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment