mirror of
https://github.com/bendtherules/completion-viz.git
synced 2026-08-18 13:42:51 +00:00
251 lines
7.6 KiB
JavaScript
251 lines
7.6 KiB
JavaScript
import { surroundingAgent } from '../engine.mjs';
|
|
import {
|
|
Descriptor,
|
|
Type,
|
|
Value,
|
|
wellKnownSymbols,
|
|
} from '../value.mjs';
|
|
import { Q, X } from '../completion.mjs';
|
|
import {
|
|
AbstractRelationalComparison,
|
|
Assert,
|
|
Call,
|
|
Construct,
|
|
Get,
|
|
GetFunctionRealm,
|
|
IsDataDescriptor,
|
|
IsArray,
|
|
IsConstructor,
|
|
OrdinaryDefineOwnProperty,
|
|
OrdinaryGetOwnProperty,
|
|
OrdinaryObjectCreate,
|
|
MakeBasicObject,
|
|
SameValue,
|
|
ToBoolean,
|
|
ToNumber,
|
|
ToString,
|
|
ToUint32,
|
|
IsPropertyKey,
|
|
IsNonNegativeInteger,
|
|
isArrayIndex,
|
|
} from './all.mjs';
|
|
|
|
// #sec-array-exotic-objects-defineownproperty-p-desc
|
|
function ArrayDefineOwnProperty(P, Desc) {
|
|
const A = this;
|
|
|
|
Assert(IsPropertyKey(P));
|
|
if (Type(P) === 'String' && P.stringValue() === 'length') {
|
|
return Q(ArraySetLength(A, Desc));
|
|
} else if (isArrayIndex(P)) {
|
|
const oldLenDesc = OrdinaryGetOwnProperty(A, new Value('length'));
|
|
Assert(X(IsDataDescriptor(oldLenDesc)));
|
|
Assert(oldLenDesc.Configurable === Value.false);
|
|
const oldLen = oldLenDesc.Value;
|
|
const index = X(ToUint32(P));
|
|
if (index.numberValue() >= oldLen.numberValue() && oldLenDesc.Writable === Value.false) {
|
|
return Value.false;
|
|
}
|
|
const succeeded = X(OrdinaryDefineOwnProperty(A, P, Desc));
|
|
if (succeeded === Value.false) {
|
|
return Value.false;
|
|
}
|
|
if (index.numberValue() >= oldLen.numberValue()) {
|
|
oldLenDesc.Value = new Value(index.numberValue() + 1);
|
|
const succeeded = OrdinaryDefineOwnProperty(A, new Value('length'), oldLenDesc); // eslint-disable-line no-shadow
|
|
Assert(succeeded === Value.true);
|
|
}
|
|
return Value.true;
|
|
}
|
|
return OrdinaryDefineOwnProperty(A, P, Desc);
|
|
}
|
|
|
|
export function isArrayExoticObject(O) {
|
|
return O.DefineOwnProperty === ArrayDefineOwnProperty;
|
|
}
|
|
|
|
// 9.4.2.2 #sec-arraycreate
|
|
export function ArrayCreate(length, proto) {
|
|
Assert(X(IsNonNegativeInteger(length)) === Value.true);
|
|
if (Object.is(length.numberValue(), -0)) {
|
|
length = new Value(0);
|
|
}
|
|
if (length.numberValue() > (2 ** 32) - 1) {
|
|
return surroundingAgent.Throw('RangeError', 'InvalidArrayLength', length);
|
|
}
|
|
if (proto === undefined) {
|
|
proto = surroundingAgent.intrinsic('%Array.prototype%');
|
|
}
|
|
const A = X(MakeBasicObject(['Prototype', 'Extensible']));
|
|
A.Prototype = proto;
|
|
A.DefineOwnProperty = ArrayDefineOwnProperty;
|
|
|
|
X(OrdinaryDefineOwnProperty(A, new Value('length'), Descriptor({
|
|
Value: length,
|
|
Writable: Value.true,
|
|
Enumerable: Value.false,
|
|
Configurable: Value.false,
|
|
})));
|
|
|
|
return A;
|
|
}
|
|
|
|
// 9.4.2.3 #sec-arrayspeciescreate
|
|
export function ArraySpeciesCreate(originalArray, length) {
|
|
Assert(Type(length) === 'Number' && Number.isInteger(length.numberValue()) && length.numberValue() >= 0);
|
|
if (Object.is(length.numberValue(), -0)) {
|
|
length = new Value(+0);
|
|
}
|
|
const isArray = Q(IsArray(originalArray));
|
|
if (isArray === Value.false) {
|
|
return Q(ArrayCreate(length));
|
|
}
|
|
let C = Q(Get(originalArray, new Value('constructor')));
|
|
if (IsConstructor(C) === Value.true) {
|
|
const thisRealm = surroundingAgent.currentRealmRecord;
|
|
const realmC = Q(GetFunctionRealm(C));
|
|
if (thisRealm !== realmC) {
|
|
if (SameValue(C, realmC.Intrinsics['%Array%']) === Value.true) {
|
|
C = Value.undefined;
|
|
}
|
|
}
|
|
}
|
|
if (Type(C) === 'Object') {
|
|
C = Q(Get(C, wellKnownSymbols.species));
|
|
if (C === Value.null) {
|
|
C = Value.undefined;
|
|
}
|
|
}
|
|
if (C === Value.undefined) {
|
|
return Q(ArrayCreate(length));
|
|
}
|
|
if (IsConstructor(C) === Value.false) {
|
|
return surroundingAgent.Throw('TypeError', 'NotAConstructor', C);
|
|
}
|
|
return Q(Construct(C, [length]));
|
|
}
|
|
|
|
// 9.4.2.4 #sec-arraysetlength
|
|
export function ArraySetLength(A, Desc) {
|
|
if (Desc.Value === undefined) {
|
|
return OrdinaryDefineOwnProperty(A, new Value('length'), Desc);
|
|
}
|
|
const newLenDesc = Descriptor({ ...Desc });
|
|
const newLen = Q(ToUint32(Desc.Value)).numberValue();
|
|
const numberLen = Q(ToNumber(Desc.Value)).numberValue();
|
|
if (newLen !== numberLen) {
|
|
return surroundingAgent.Throw('RangeError', 'InvalidArrayLength', Desc.Value);
|
|
}
|
|
newLenDesc.Value = new Value(newLen);
|
|
const oldLenDesc = OrdinaryGetOwnProperty(A, new Value('length'));
|
|
Assert(X(IsDataDescriptor(oldLenDesc)));
|
|
Assert(oldLenDesc.Configurable === Value.false);
|
|
const oldLen = oldLenDesc.Value.numberValue();
|
|
if (newLen >= oldLen) {
|
|
return OrdinaryDefineOwnProperty(A, new Value('length'), newLenDesc);
|
|
}
|
|
if (oldLenDesc.Writable === Value.false) {
|
|
return Value.false;
|
|
}
|
|
let newWritable;
|
|
if (newLenDesc.Writable === undefined || newLenDesc.Writable === Value.true) {
|
|
newWritable = true;
|
|
} else {
|
|
newWritable = false;
|
|
newLenDesc.Writable = Value.true;
|
|
}
|
|
const succeeded = X(OrdinaryDefineOwnProperty(A, new Value('length'), newLenDesc));
|
|
if (succeeded === Value.false) {
|
|
return Value.false;
|
|
}
|
|
const keys = [];
|
|
A.properties.forEach((value, key) => {
|
|
if (isArrayIndex(key) && Number(key.stringValue()) >= newLen) {
|
|
keys.push(key);
|
|
}
|
|
});
|
|
keys.sort((a, b) => Number(b.stringValue()) - Number(a.stringValue()));
|
|
for (const P of keys) {
|
|
const deleteSucceeded = X(A.Delete(P));
|
|
if (deleteSucceeded === Value.false) {
|
|
newLenDesc.Value = new Value(X(ToUint32(P)).numberValue() + 1);
|
|
if (newWritable === false) {
|
|
newLenDesc.Writable = Value.false;
|
|
}
|
|
X(OrdinaryDefineOwnProperty(A, new Value('length'), newLenDesc));
|
|
return Value.false;
|
|
}
|
|
}
|
|
if (newWritable === false) {
|
|
const s = OrdinaryDefineOwnProperty(A, new Value('length'), Descriptor({ Writable: Value.false }));
|
|
Assert(s === Value.true);
|
|
}
|
|
return Value.true;
|
|
}
|
|
|
|
// 22.1.3.1.1 #sec-isconcatspreadable
|
|
export function IsConcatSpreadable(O) {
|
|
if (Type(O) !== 'Object') {
|
|
return Value.false;
|
|
}
|
|
const spreadable = Q(Get(O, wellKnownSymbols.isConcatSpreadable));
|
|
if (spreadable !== Value.undefined) {
|
|
return ToBoolean(spreadable);
|
|
}
|
|
return Q(IsArray(O));
|
|
}
|
|
|
|
// 22.1.3.27.1 #sec-sortcompare
|
|
export function SortCompare(x, y, comparefn) {
|
|
if (x === Value.undefined && y === Value.undefined) {
|
|
return new Value(+0);
|
|
}
|
|
if (x === Value.undefined) {
|
|
return new Value(1);
|
|
}
|
|
if (y === Value.undefined) {
|
|
return new Value(-1);
|
|
}
|
|
if (comparefn !== Value.undefined) {
|
|
const callRes = Q(Call(comparefn, Value.undefined, [x, y]));
|
|
const v = Q(ToNumber(callRes));
|
|
if (v.isNaN()) {
|
|
return new Value(+0);
|
|
}
|
|
return v;
|
|
}
|
|
const xString = Q(ToString(x));
|
|
const yString = Q(ToString(y));
|
|
const xSmaller = AbstractRelationalComparison(xString, yString);
|
|
if (xSmaller === Value.true) {
|
|
return new Value(-1);
|
|
}
|
|
const ySmaller = AbstractRelationalComparison(yString, xString);
|
|
if (ySmaller === Value.true) {
|
|
return new Value(1);
|
|
}
|
|
return new Value(+0);
|
|
}
|
|
|
|
// 22.1.5.1 #sec-createarrayiterator
|
|
export function CreateArrayIterator(array, kind) {
|
|
// 1. Assert: Type(array) is Object.
|
|
Assert(Type(array) === 'Object');
|
|
// 2. Assert: kind is key+value, key, or value.
|
|
Assert(kind === 'key+value' || kind === 'key' || kind === 'value');
|
|
// 3. Let iterator be ObjectCreate(%ArrayIteratorPrototype%, « [[IteratedArrayLike]], [[ArrayLikeNextIndex]], [[ArrayLikeIterationKind]] »).
|
|
const iterator = OrdinaryObjectCreate(surroundingAgent.intrinsic('%ArrayIterator.prototype%'), [
|
|
'IteratedArrayLike',
|
|
'ArrayLikeNextIndex',
|
|
'ArrayLikeIterationKind',
|
|
]);
|
|
// 4. Set iterator.[[IteratedArrayLike]] to array.
|
|
iterator.IteratedArrayLike = array;
|
|
// 5. Set iterator.[[ArrayLikeNextIndex]] to 0.
|
|
iterator.ArrayLikeNextIndex = 0;
|
|
// 6. Set iterator.[[ArrayLikeIterationKind]] to kind.
|
|
iterator.ArrayLikeIterationKind = kind;
|
|
// 7. Return iterator.
|
|
return iterator;
|
|
}
|