diff --git a/quickjs.c b/quickjs.c index e3c2337..bf52f1a 100644 --- a/quickjs.c +++ b/quickjs.c @@ -36817,8 +36817,7 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, if (argc == 0) { item_count = 0; del_count = 0; - } else - if (argc == 1) { + } else if (argc == 1) { item_count = 0; del_count = len - start; } else { @@ -36903,6 +36902,101 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } +static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, obj, ret, *arrp, *pval, *last; + JSObject *p; + int64_t i, j, len, newlen, start, add, del; + uint32_t count32; + + pval = NULL; + last = NULL; + ret = JS_EXCEPTION; + arr = JS_UNDEFINED; + + obj = JS_ToObject(ctx, this_val); + if (js_get_length64(ctx, &len, obj)) + goto exception; + + start = 0; + if (argc > 0) + if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len)) + goto exception; + + del = 0; + if (argc > 0) + del = len - start; + if (argc > 1) + if (JS_ToInt64Clamp(ctx, &del, argv[1], 0, del, 0)) + goto exception; + + add = 0; + if (argc > 2) + add = argc - 2; + + newlen = len + add - del; + if (newlen > UINT32_MAX) { + // Per spec: TypeError if newlen >= 2**53, RangeError below + if (newlen > MAX_SAFE_INTEGER) { + JS_ThrowTypeError(ctx, "invalid array length"); + } else { + JS_ThrowRangeError(ctx, "invalid array length"); + } + goto exception; + } + + arr = JS_NewArray(ctx); + if (JS_IsException(arr)) + goto exception; + + if (newlen <= 0) + goto done; + + p = JS_VALUE_GET_OBJ(arr); + if (expand_fast_array(ctx, p, newlen) < 0) + goto exception; + + p->u.array.count = newlen; + pval = &p->u.array.u.values[0]; + last = &p->u.array.u.values[newlen]; + + if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { + for (i = 0; i < start; i++, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + for (j = 0; j < add; j++, pval++) + *pval = JS_DupValue(ctx, argv[2 + j]); + for (i += del; i < len; i++, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + } else { + for (i = 0; i < start; i++, pval++) + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) + goto exception; + for (j = 0; j < add; j++, pval++) + *pval = JS_DupValue(ctx, argv[2 + j]); + for (i += del; i < len; i++, pval++) + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) + goto exception; + } + + assert(pval == last); + + if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, newlen)) < 0) + goto exception; + +done: + ret = arr; + arr = JS_UNDEFINED; + +exception: + while (pval != last) + *pval++ = JS_UNDEFINED; + + JS_FreeValue(ctx, arr); + JS_FreeValue(ctx, obj); + return ret; +} + static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -37458,6 +37552,7 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = { JS_CFUNC_DEF("toSorted", 1, js_array_toSorted ), JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ), JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ), + JS_CFUNC_DEF("toSpliced", 2, js_array_toSpliced ), JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ), JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ), JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ), diff --git a/test262_errors.txt b/test262_errors.txt index 0f3491a..8d51dfa 100644 --- a/test262_errors.txt +++ b/test262_errors.txt @@ -1,64 +1,6 @@ test262/test/annexB/language/eval-code/direct/script-decl-lex-collision-in-sloppy-mode.js:13: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all test262/test/built-ins/Array/prototype/Symbol.unscopables/change-array-by-copy.js:19: Test262Error: obj should have an own property toReversed test262/test/built-ins/Array/prototype/Symbol.unscopables/change-array-by-copy.js:19: strict mode: Test262Error: obj should have an own property toReversed -test262/test/built-ins/Array/prototype/toSpliced/deleteCount-clamped-between-zero-and-remaining-count.js:20: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/deleteCount-clamped-between-zero-and-remaining-count.js:20: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/deleteCount-missing.js:18: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/deleteCount-missing.js:18: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/deleteCount-undefined.js:27: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/deleteCount-undefined.js:27: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/discarded-element-not-read.js:51: TypeError: cannot read property 'call' of undefined -test262/test/built-ins/Array/prototype/toSpliced/discarded-element-not-read.js:51: strict mode: TypeError: cannot read property 'call' of undefined -test262/test/built-ins/Array/prototype/toSpliced/elements-read-in-order.js:45: TypeError: cannot read property 'call' of undefined -test262/test/built-ins/Array/prototype/toSpliced/elements-read-in-order.js:45: strict mode: TypeError: cannot read property 'call' of undefined -test262/test/built-ins/Array/prototype/toSpliced/frozen-this-value.js:13: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/frozen-this-value.js:13: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/holes-not-preserved.js:33: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/holes-not-preserved.js:33: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/ignores-species.js:21: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/ignores-species.js:21: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/immutable.js:13: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/immutable.js:13: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/length-casted-to-zero.js:19: TypeError: cannot read property 'call' of undefined -test262/test/built-ins/Array/prototype/toSpliced/length-casted-to-zero.js:19: strict mode: TypeError: cannot read property 'call' of undefined -test262/test/built-ins/Array/prototype/toSpliced/length-clamped-to-2pow53minus1.js:31: TypeError: cannot read property 'call' of undefined -test262/test/built-ins/Array/prototype/toSpliced/length-clamped-to-2pow53minus1.js:31: strict mode: TypeError: cannot read property 'call' of undefined -test262/test/built-ins/Array/prototype/toSpliced/length-decreased-while-iterating.js:44: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/length-decreased-while-iterating.js:44: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/length-exceeding-array-length-limit.js:28: Test262Error: Expected a RangeError but got a TypeError -test262/test/built-ins/Array/prototype/toSpliced/length-exceeding-array-length-limit.js:28: strict mode: Test262Error: Expected a RangeError but got a TypeError -test262/test/built-ins/Array/prototype/toSpliced/length-increased-while-iterating.js:37: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/length-increased-while-iterating.js:37: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/length-tolength.js:18: TypeError: cannot read property 'call' of undefined -test262/test/built-ins/Array/prototype/toSpliced/length-tolength.js:18: strict mode: TypeError: cannot read property 'call' of undefined -test262/test/built-ins/Array/prototype/toSpliced/metadata/length.js:30: TypeError: cannot convert to object -test262/test/built-ins/Array/prototype/toSpliced/metadata/length.js:30: strict mode: TypeError: cannot convert to object -test262/test/built-ins/Array/prototype/toSpliced/metadata/name.js:28: TypeError: cannot convert to object -test262/test/built-ins/Array/prototype/toSpliced/metadata/name.js:28: strict mode: TypeError: cannot convert to object -test262/test/built-ins/Array/prototype/toSpliced/metadata/property-descriptor.js:18: Test262Error: typeof Expected SameValue(«undefined», «function») to be true -test262/test/built-ins/Array/prototype/toSpliced/metadata/property-descriptor.js:18: strict mode: Test262Error: typeof Expected SameValue(«undefined», «function») to be true -test262/test/built-ins/Array/prototype/toSpliced/mutate-while-iterating.js:50: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/mutate-while-iterating.js:50: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/not-a-constructor.js:30: Test262Error: isConstructor invoked with a non-function value -test262/test/built-ins/Array/prototype/toSpliced/not-a-constructor.js:30: strict mode: Test262Error: isConstructor invoked with a non-function value -test262/test/built-ins/Array/prototype/toSpliced/start-and-deleteCount-missing.js:23: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/start-and-deleteCount-missing.js:23: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/start-and-deleteCount-undefineds.js:25: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/start-and-deleteCount-undefineds.js:25: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/start-bigger-than-length.js:22: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/start-bigger-than-length.js:22: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/start-neg-infinity-is-zero.js:21: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/start-neg-infinity-is-zero.js:21: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/start-neg-less-than-minus-length-is-zero.js:21: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/start-neg-less-than-minus-length-is-zero.js:21: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/start-neg-subtracted-from-length.js:21: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/start-neg-subtracted-from-length.js:21: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/start-undefined-and-deleteCount-missing.js:24: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/start-undefined-and-deleteCount-missing.js:24: strict mode: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/this-value-boolean.js:18: TypeError: cannot read property 'call' of undefined -test262/test/built-ins/Array/prototype/toSpliced/this-value-boolean.js:18: strict mode: TypeError: cannot read property 'call' of undefined -test262/test/built-ins/Array/prototype/toSpliced/unmodified.js:13: TypeError: not a function -test262/test/built-ins/Array/prototype/toSpliced/unmodified.js:13: strict mode: TypeError: not a function test262/test/built-ins/AsyncGeneratorPrototype/return/return-state-completed-broken-promise.js:53: TypeError: $DONE() not called test262/test/built-ins/AsyncGeneratorPrototype/return/return-state-completed-broken-promise.js:53: strict mode: TypeError: $DONE() not called test262/test/built-ins/AsyncGeneratorPrototype/return/return-suspendedStart-broken-promise.js:34: TypeError: $DONE() not called