Bug 1658308 - Implement the .at() proposal. r=jandem

Differential Revision: https://phabricator.services.mozilla.com/D98743
This commit is contained in:
Tom Schuster 2020-12-04 14:46:00 +00:00
Родитель bac48c02e2
Коммит 738aaeb6e6
10 изменённых файлов: 249 добавлений и 0 удалений

Просмотреть файл

@ -3701,6 +3701,11 @@ static const JSFunctionSpec array_methods[] = {
JS_SELF_HOSTED_FN("flatMap", "ArrayFlatMap", 1, 0),
JS_SELF_HOSTED_FN("flat", "ArrayFlat", 0, 0),
/* Proposal */
#ifdef NIGHTLY_BUILD
JS_SELF_HOSTED_FN("at", "ArrayAt", 1, 0),
#endif
JS_FS_END};
static const JSFunctionSpec array_static_methods[] = {

Просмотреть файл

@ -1140,3 +1140,32 @@ function FlattenIntoArray(target, source, sourceLen, start, depth, mapperFunctio
// Step 4.
return targetIndex;
}
// https://github.com/tc39/proposal-relative-indexing-method
// Array.prototype.at ( index )
function ArrayAt(index) {
// Step 1.
var O = ToObject(this);
// Step 2.
var len = ToLength(O.length);
// Step 3.
var relativeIndex = ToInteger(index);
// Steps 4-5.
var k;
if (relativeIndex >= 0) {
k = relativeIndex;
} else {
k = len + relativeIndex;
}
// Step 6.
if (k < 0 || k >= len) {
return undefined;
}
// Step 7.
return O[k];
}

Просмотреть файл

@ -3599,6 +3599,10 @@ static const JSFunctionSpec string_methods[] = {
JS_SELF_HOSTED_FN("concat", "String_concat", 1, 0),
JS_SELF_HOSTED_FN("slice", "String_slice", 2, 0),
#ifdef NIGHTLY_BUILD
JS_SELF_HOSTED_FN("at", "String_at", 1, 0),
#endif
/* HTML string methods. */
JS_SELF_HOSTED_FN("bold", "String_bold", 0, 0),
JS_SELF_HOSTED_FN("italics", "String_italics", 0, 0),

Просмотреть файл

@ -937,6 +937,39 @@ function String_static_raw(callSite/*, ...substitutions*/) {
return resultString;
}
// https://github.com/tc39/proposal-relative-indexing-method
// String.prototype.at ( index )
function String_at(index) {
// Step 1.
if (this === undefined || this === null)
ThrowIncompatibleMethod("at", this);
// Step 2.
var string = ToString(this);
// Step 3.
var len = string.length;
// Step 4.
var relativeIndex = ToInteger(index);
// Steps 5-6.
var k;
if (relativeIndex >= 0) {
k = relativeIndex;
} else {
k = len + relativeIndex;
}
// Step 7.
if (k < 0 || k >= len) {
return undefined;
}
// Step 8.
return string[k];
}
// ES6 draft 2014-04-27 B.2.3.3
function String_big() {
if (this === undefined || this === null)

Просмотреть файл

@ -1337,6 +1337,45 @@ function TypedArraySubarray(begin, end) {
return TypedArraySpeciesCreateWithBuffer(obj, buffer, beginByteOffset, newLength);
}
// https://tc39.es/proposal-relative-indexing-method
// %TypedArray%.prototype.at ( index )
function TypedArrayAt(index) {
// Step 1.
var obj = this;
// Step 2.
// This function is not generic.
if (!IsObject(obj) || !IsTypedArray(obj)) {
return callFunction(CallTypedArrayMethodIfWrapped, obj, index,
"TypedArrayAt");
}
GetAttachedArrayBuffer(obj);
// If we got here, `this` is either a typed array or a wrapper for one.
// Step 3.
var len = TypedArrayLength(obj);
// Step 4.
var relativeIndex = ToInteger(index);
// Steps 5-6.
var k;
if (relativeIndex >= 0) {
k = relativeIndex;
} else {
k = len + relativeIndex;
}
// Step 7.
if (k < 0 || k >= len) {
return undefined;
}
// Step 8.
return obj[k];
}
// ES6 draft rev30 (2014/12/24) 22.2.3.30 %TypedArray%.prototype.values()
//
// Uncloned functions with `$` prefix are allocated as extended function

Просмотреть файл

@ -0,0 +1,41 @@
// |reftest| skip-if(!Array.prototype.at)
function basic() {
assertEq([0].at(0), 0);
assertEq([0].at(-1), 0);
assertEq([].at(0), undefined);
assertEq([].at(-1), undefined);
assertEq([].at(1), undefined);
assertEq([0, 1].at(0), 0);
assertEq([0, 1].at(1), 1);
assertEq([0, 1].at(-2), 0);
assertEq([0, 1].at(-1), 1);
assertEq([0, 1].at(2), undefined);
assertEq([0, 1].at(-3), undefined);
assertEq([0, 1].at(-4), undefined);
assertEq([0, 1].at(Infinity), undefined);
assertEq([0, 1].at(-Infinity), undefined);
assertEq([0, 1].at(NaN), 0); // ToInteger(NaN) = 0
}
function obj() {
var o = {length: 0, [0]: "a", at: Array.prototype.at};
assertEq(o.at(0), undefined);
assertEq(o.at(-1), undefined);
o.length = 1;
assertEq(o.at(0), "a");
assertEq(o.at(-1), "a");
assertEq(o.at(1), undefined);
assertEq(o.at(-2), undefined);
}
basic();
obj();
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,40 @@
// |reftest| skip-if(!String.prototype.at)
function basic() {
assertEq("a".at(0), "a");
assertEq("a".at(-1), "a");
assertEq("".at(0), undefined);
assertEq("".at(-1), undefined);
assertEq("".at(1), undefined);
assertEq("ab".at(0), "a");
assertEq("ab".at(1), "b");
assertEq("ab".at(-2), "a");
assertEq("ab".at(-1), "b");
assertEq("ab".at(2), undefined);
assertEq("ab".at(-3), undefined);
assertEq("ab".at(-4), undefined);
assertEq("ab".at(Infinity), undefined);
assertEq("ab".at(-Infinity), undefined);
assertEq("ab".at(NaN), "a"); // ToInteger(NaN) = 0
assertEq("\u{1f921}".at(0), "\u{d83e}");
assertEq("\u{1f921}".at(1), "\u{dd21}");
}
function other() {
var n = 146;
assertEq(String.prototype.at.call(n, 0), "1");
var obj = {};
assertEq(String.prototype.at.call(obj, -1), "]");
var b = true;
assertEq(String.prototype.at.call(b, 0), "t");
}
basic();
other();
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -0,0 +1,49 @@
// |reftest| skip-if(!Int32Array.prototype.at)
for (var constructor of anyTypedArrayConstructors) {
assertEq(constructor.prototype.at.length, 1);
assertEq(new constructor([0]).at(0), 0);
assertEq(new constructor([0]).at(-1), 0);
assertEq(new constructor([]).at(0), undefined);
assertEq(new constructor([]).at(-1), undefined);
assertEq(new constructor([]).at(1), undefined);
assertEq(new constructor([0, 1]).at(0), 0);
assertEq(new constructor([0, 1]).at(1), 1);
assertEq(new constructor([0, 1]).at(-2), 0);
assertEq(new constructor([0, 1]).at(-1), 1);
assertEq(new constructor([0, 1]).at(2), undefined);
assertEq(new constructor([0, 1]).at(-3), undefined);
assertEq(new constructor([0, 1]).at(-4), undefined);
assertEq(new constructor([0, 1]).at(Infinity), undefined);
assertEq(new constructor([0, 1]).at(-Infinity), undefined);
assertEq(new constructor([0, 1]).at(NaN), 0); // ToInteger(NaN) = 0
// Called from other globals.
if (typeof newGlobal === "function") {
var at = newGlobal()[constructor.name].prototype.at;
assertEq(at.call(new constructor([1, 2, 3]), 2), 3);
}
// Throws if `this` isn't a TypedArray.
var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./,
new Proxy(new constructor(), {})];
invalidReceivers.forEach(invalidReceiver => {
assertThrowsInstanceOf(() => {
constructor.prototype.at.call(invalidReceiver);
}, TypeError, "Assert that 'at' fails if this value is not a TypedArray");
});
// Test that the length getter is never called.
assertEq(Object.defineProperty(new constructor([1, 2, 3]), "length", {
get() {
throw new Error("length accessor called");
}
}).at(1), 2);
}
if (typeof reportCompare === "function")
reportCompare(true, true);

Просмотреть файл

@ -1887,6 +1887,9 @@ bool TypedArrayObject::set(JSContext* cx, unsigned argc, Value* vp) {
JS_SELF_HOSTED_FN("includes", "TypedArrayIncludes", 2, 0),
JS_SELF_HOSTED_FN("toString", "ArrayToString", 0, 0),
JS_SELF_HOSTED_FN("toLocaleString", "TypedArrayToLocaleString", 2, 0),
#ifdef NIGHTLY_BUILD
JS_SELF_HOSTED_FN("at", "TypedArrayAt", 1, 0),
#endif
JS_FS_END};
/* static */ const JSFunctionSpec TypedArrayObject::staticFunctions[] = {

Просмотреть файл

@ -235,6 +235,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
"includes", "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "find",
"findIndex", "copyWithin", "fill", Symbol.iterator, Symbol.unscopables, "entries", "keys",
"values", "constructor", "flat", "flatMap"];
if (isNightlyBuild) {
gPrototypeProperties['Array'].push("at");
}
gConstructorProperties['Array'] =
constructorProps(["isArray", "from", "of", Symbol.species]);
for (var c of typedArrayClasses) {
@ -246,6 +249,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
"set", "copyWithin", "find", "findIndex", "forEach","indexOf", "lastIndexOf", "includes",
"reverse", "join", "every", "some", "reduce", "reduceRight", "entries", "keys", "values",
"slice", "map", "filter"];
if (isNightlyBuild) {
gPrototypeProperties['TypedArray'].push("at");
}
// There is no TypedArray constructor, looks like.
is(window.TypedArray, undefined, "If this ever changes, add to this test!");
for (var c of errorObjectClasses) {