From 0362c0a4eb59aaa43621bd0c487eed021db30bb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 12 Nov 2024 08:10:19 +0100 Subject: [PATCH] Implement Iterator.prototype.take (#676) --- quickjs.c | 78 +++++++++++++++++++++++++++++++++++++++++----- test262_errors.txt | 52 ------------------------------- 2 files changed, 71 insertions(+), 59 deletions(-) diff --git a/quickjs.c b/quickjs.c index f2fc66b8..2bdf37ef 100644 --- a/quickjs.c +++ b/quickjs.c @@ -40060,9 +40060,10 @@ static JSValue js_iterator_proto_drop(JSContext *ctx, JSValue this_val, if (JS_ToInt64Free(ctx, &limit, v)) return JS_EXCEPTION; } - if (limit < 0) + if (limit < 0) { fail: return JS_ThrowRangeError(ctx, "must be positive"); + } return js_create_iterator_helper(ctx, this_val, JS_ITERATOR_HELPER_KIND_DROP, JS_UNDEFINED, limit); } @@ -40373,7 +40374,41 @@ static JSValue js_iterator_proto_some(JSContext *ctx, JSValue this_val, static JSValue js_iterator_proto_take(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { - return JS_ThrowInternalError(ctx, "TODO implement Iterator.prototype.take"); + JSValue v; + double dlimit; + int64_t limit; + if (!JS_IsObject(this_val)) + return JS_ThrowTypeError(ctx, "Iterator.prototype.take called on non-object"); + v = JS_ToNumber(ctx, argv[0]); + if (JS_IsException(v)) + return JS_EXCEPTION; + // Check for Infinity. + if (JS_ToFloat64(ctx, &dlimit, v)) { + JS_FreeValue(ctx, v); + return JS_EXCEPTION; + } + if (isnan(dlimit)) { + JS_FreeValue(ctx, v); + goto fail; + } + if (!isfinite(dlimit)) { + JS_FreeValue(ctx, v); + if (dlimit < 0) + goto fail; + else + limit = MAX_SAFE_INTEGER; + } else { + v = JS_ToIntegerFree(ctx, v); + if (JS_IsException(v)) + return JS_EXCEPTION; + if (JS_ToInt64Free(ctx, &limit, v)) + return JS_EXCEPTION; + } + if (limit < 0) { + fail: + return JS_ThrowRangeError(ctx, "must be positive"); + } + return js_create_iterator_helper(ctx, this_val, JS_ITERATOR_HELPER_KIND_TAKE, JS_UNDEFINED, limit); } static JSValue js_iterator_proto_toArray(JSContext *ctx, JSValue this_val, @@ -40490,12 +40525,14 @@ static JSValue js_iterator_helper_next(JSContext *ctx, JSValue this_val, JSIteratorHelperData *it; JSValue ret; + *pdone = FALSE; + it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_HELPER); if (!it) goto fail; if (it->executing) return JS_ThrowTypeError(ctx, "cannot invoke a running iterator"); - if (magic == GEN_MAGIC_RETURN && it->done) + if (it->done) return JS_UNDEFINED; it->executing = TRUE; @@ -40536,6 +40573,34 @@ static JSValue js_iterator_helper_next(JSContext *ctx, JSValue this_val, goto done; } break; + case JS_ITERATOR_HELPER_KIND_TAKE: + { + JSValue item, method; + if (it->limit > 0) { + if (magic == GEN_MAGIC_NEXT) { + method = js_dup(it->next); + } else { + method = JS_GetProperty(ctx, it->obj, JS_ATOM_return); + if (JS_IsException(method)) + goto fail; + } + it->limit--; + item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone); + JS_FreeValue(ctx, method); + if (JS_IsException(item)) + goto fail; + ret = item; + goto done; + } + + *pdone = TRUE; + if (JS_IteratorClose(ctx, it->obj, FALSE)) + ret = JS_EXCEPTION; + else + ret = JS_UNDEFINED; + goto done; + } + break; default: abort(); } @@ -40545,13 +40610,12 @@ static JSValue js_iterator_helper_next(JSContext *ctx, JSValue this_val, it->executing = FALSE; return ret; fail: - it->executing = FALSE; - if (it && JS_IsObject(it->obj)) { + if (it) { /* close the iterator object, preserving pending exception */ JS_IteratorClose(ctx, it->obj, TRUE); } - *pdone = FALSE; - return JS_EXCEPTION; + ret = JS_EXCEPTION; + goto done; } static JSValue js_create_iterator_helper(JSContext *ctx, JSValue iterator, diff --git a/test262_errors.txt b/test262_errors.txt index 845a5ded..bb81f323 100644 --- a/test262_errors.txt +++ b/test262_errors.txt @@ -216,58 +216,6 @@ test262/test/built-ins/Iterator/prototype/map/underlying-iterator-closed-in-para test262/test/built-ins/Iterator/prototype/map/underlying-iterator-closed-in-parallel.js:19: strict mode: InternalError: TODO implement Iterator.prototype.map test262/test/built-ins/Iterator/prototype/map/underlying-iterator-closed.js:21: InternalError: TODO implement Iterator.prototype.map test262/test/built-ins/Iterator/prototype/map/underlying-iterator-closed.js:21: strict mode: InternalError: TODO implement Iterator.prototype.map -test262/test/built-ins/Iterator/prototype/take/argument-effect-order.js:24: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/argument-effect-order.js:24: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/callable.js:10: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/callable.js:10: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/exhaustion-calls-return.js:35: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/exhaustion-calls-return.js:35: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/get-next-method-only-once.js:38: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/get-next-method-only-once.js:38: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/get-next-method-throws.js:17: Test262Error: Expected a Test262Error but got a InternalError -test262/test/built-ins/Iterator/prototype/take/get-next-method-throws.js:17: strict mode: Test262Error: Expected a Test262Error but got a InternalError -test262/test/built-ins/Iterator/prototype/take/get-return-method-throws.js:25: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/get-return-method-throws.js:25: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/limit-greater-than-or-equal-to-total.js:23: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/limit-greater-than-or-equal-to-total.js:23: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/limit-less-than-total.js:25: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/limit-less-than-total.js:25: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/limit-rangeerror.js:18: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/limit-rangeerror.js:18: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/limit-tonumber-throws.js:16: Test262Error: Expected a Test262Error but got a InternalError -test262/test/built-ins/Iterator/prototype/take/limit-tonumber-throws.js:16: strict mode: Test262Error: Expected a Test262Error but got a InternalError -test262/test/built-ins/Iterator/prototype/take/limit-tonumber.js:23: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/limit-tonumber.js:23: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/next-method-returns-non-object.js:21: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/next-method-returns-non-object.js:21: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-done.js:32: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-done.js:32: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-value-done.js:30: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-value-done.js:30: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-value.js:32: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/next-method-returns-throwing-value.js:32: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/next-method-throws.js:21: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/next-method-throws.js:21: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/result-is-iterator.js:11: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/result-is-iterator.js:11: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/return-is-forwarded.js:28: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/return-is-forwarded.js:28: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/return-is-not-forwarded-after-exhaustion.js:27: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/return-is-not-forwarded-after-exhaustion.js:27: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/this-non-callable-next.js:15: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/this-non-callable-next.js:15: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/this-non-object.js:22: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/take/this-non-object.js:22: strict mode: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/take/this-plain-iterator.js:25: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/this-plain-iterator.js:25: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/throws-typeerror-when-generator-is-running.js:33: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/throws-typeerror-when-generator-is-running.js:33: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/underlying-iterator-advanced-in-parallel.js:19: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/underlying-iterator-advanced-in-parallel.js:19: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/underlying-iterator-closed-in-parallel.js:19: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/underlying-iterator-closed-in-parallel.js:19: strict mode: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/underlying-iterator-closed.js:21: InternalError: TODO implement Iterator.prototype.take -test262/test/built-ins/Iterator/prototype/take/underlying-iterator-closed.js:21: strict mode: InternalError: TODO implement Iterator.prototype.take test262/test/built-ins/RegExp/property-escapes/generated/Alphabetic.js:16: Test262Error: `\P{Alphabetic}` should match U+000363 (`ͣ`) test262/test/built-ins/RegExp/property-escapes/generated/Alphabetic.js:16: strict mode: Test262Error: `\P{Alphabetic}` should match U+000363 (`ͣ`) test262/test/built-ins/RegExp/property-escapes/generated/Assigned.js:16: Test262Error: `\P{Assigned}` should match U+001B7F (`᭿`)