зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1658308 - Implement the .at() proposal. r=jandem
Differential Revision: https://phabricator.services.mozilla.com/D98743
This commit is contained in:
Родитель
bac48c02e2
Коммит
738aaeb6e6
|
@ -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) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче