diff --git a/quickjs.c b/quickjs.c index 9e157925..1e776c5f 100644 --- a/quickjs.c +++ b/quickjs.c @@ -40284,7 +40284,13 @@ static JSValue js_iterator_proto_find(JSContext *ctx, JSValue this_val, static JSValue js_iterator_proto_flatMap(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { - return JS_ThrowInternalError(ctx, "TODO implement Iterator.prototype.flatMap"); + JSValue func; + if (!JS_IsObject(this_val)) + return JS_ThrowTypeError(ctx, "Iterator.prototype.flatMap called on non-object"); + func = argv[0]; + if (check_function(ctx, func)) + return JS_EXCEPTION; + return js_create_iterator_helper(ctx, this_val, JS_ITERATOR_HELPER_KIND_FLAT_MAP, func, 0); } static JSValue js_iterator_proto_forEach(JSContext *ctx, JSValue this_val, @@ -40576,6 +40582,7 @@ typedef struct JSIteratorHelperData { JSValue obj; JSValue next; JSValue func; // predicate (filter) or mapper (flatMap, map) + JSValue inner; // innerValue (flatMap) int64_t count; // limit (drop, take) or counter (filter, map, flatMap) BOOL executing; BOOL done; @@ -40589,6 +40596,7 @@ static void js_iterator_helper_finalizer(JSRuntime *rt, JSValue val) JS_FreeValueRT(rt, it->obj); JS_FreeValueRT(rt, it->func); JS_FreeValueRT(rt, it->next); + JS_FreeValueRT(rt, it->inner); js_free_rt(rt, it); } } @@ -40602,6 +40610,7 @@ static void js_iterator_helper_mark(JSRuntime *rt, JSValue val, JS_MarkValue(rt, it->obj, mark_func); JS_MarkValue(rt, it->func, mark_func); JS_MarkValue(rt, it->next, mark_func); + JS_MarkValue(rt, it->inner, mark_func); } } @@ -40700,6 +40709,89 @@ static JSValue js_iterator_helper_next(JSContext *ctx, JSValue this_val, goto filter_again; } break; + case JS_ITERATOR_HELPER_KIND_FLAT_MAP: + { + JSValue item, method, index_val, args[2], iter; + flat_map_again: + if (JS_IsUndefined(it->inner)) { + 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; + } + item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone); + JS_FreeValue(ctx, method); + if (JS_IsException(item)) + goto fail; + if (*pdone || magic == GEN_MAGIC_RETURN) { + ret = item; + goto done; + } + index_val = js_int64(it->count++); + args[0] = item; + args[1] = index_val; + ret = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, item); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) + goto fail; + if (!JS_IsObject(ret)) { + JS_FreeValue(ctx, ret); + JS_ThrowTypeError(ctx, "not an object"); + goto fail; + } + method = JS_GetProperty(ctx, ret, JS_ATOM_Symbol_iterator); + if (JS_IsException(method)) { + JS_FreeValue(ctx, ret); + goto fail; + } + if (JS_IsNull(method) || JS_IsUndefined(method)) { + JS_FreeValue(ctx, method); + iter = ret; + } else { + iter = JS_GetIterator2(ctx, ret, method); + JS_FreeValue(ctx, method); + JS_FreeValue(ctx, ret); + if (JS_IsException(iter)) + goto fail; + } + + it->inner = iter; + } + + if (magic == GEN_MAGIC_NEXT) + method = JS_GetProperty(ctx, it->inner, JS_ATOM_next); + else + method = JS_GetProperty(ctx, it->inner, JS_ATOM_return); + if (JS_IsException(method)) { + inner_fail: + JS_IteratorClose(ctx, it->inner, FALSE); + JS_FreeValue(ctx, it->inner); + it->inner = JS_UNDEFINED; + goto fail; + } + if (magic == GEN_MAGIC_RETURN && (JS_IsUndefined(method) || JS_IsNull(method))) { + goto inner_end; + } else { + item = JS_IteratorNext(ctx, it->inner, method, 0, NULL, pdone); + JS_FreeValue(ctx, method); + if (JS_IsException(item)) + goto inner_fail; + } + if (*pdone) { + inner_end: + *pdone = FALSE; // The outer iterator must continue. + JS_IteratorClose(ctx, it->inner, FALSE); + JS_FreeValue(ctx, it->inner); + it->inner = JS_UNDEFINED; + goto flat_map_again; + } + ret = item; + goto done; + } + break; case JS_ITERATOR_HELPER_KIND_MAP: { JSValue item, method, index_val, args[2]; @@ -40797,6 +40889,7 @@ static JSValue js_create_iterator_helper(JSContext *ctx, JSValue iterator, it->obj = js_dup(iterator); it->func = js_dup(func); it->next = method; + it->inner = JS_UNDEFINED; it->count = count; it->executing = FALSE; it->done = FALSE; diff --git a/test262_errors.txt b/test262_errors.txt index 17a8c86d..3ae43279 100644 --- a/test262_errors.txt +++ b/test262_errors.txt @@ -56,80 +56,6 @@ test262/test/built-ins/Iterator/prototype/constructor/prop-desc.js:10: Test262Er test262/test/built-ins/Iterator/prototype/constructor/prop-desc.js:10: strict mode: Test262Error: Expected SameValue(«"undefined"», «"function"») to be true test262/test/built-ins/Iterator/prototype/constructor/weird-setter.js:23: TypeError: cannot read property 'call' of undefined test262/test/built-ins/Iterator/prototype/constructor/weird-setter.js:23: strict mode: TypeError: cannot read property 'call' of undefined -test262/test/built-ins/Iterator/prototype/flatMap/argument-effect-order.js:21: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/flatMap/argument-effect-order.js:21: strict mode: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/flatMap/callable.js:10: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/callable.js:10: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/exhaustion-does-not-call-return.js:31: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/exhaustion-does-not-call-return.js:31: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/flattens-iterable.js:22: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/flattens-iterable.js:22: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/flattens-iterator.js:24: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/flattens-iterator.js:24: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/flattens-only-depth-1.js:32: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/flattens-only-depth-1.js:32: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/get-next-method-only-once.js:38: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/get-next-method-only-once.js:38: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/get-next-method-throws.js:17: Test262Error: Expected a Test262Error but got a InternalError -test262/test/built-ins/Iterator/prototype/flatMap/get-next-method-throws.js:17: strict mode: Test262Error: Expected a Test262Error but got a InternalError -test262/test/built-ins/Iterator/prototype/flatMap/get-return-method-throws.js:25: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/get-return-method-throws.js:25: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/iterable-primitives-are-not-flattened.js:32: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/flatMap/iterable-primitives-are-not-flattened.js:32: strict mode: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/flatMap/iterable-to-iterator-fallback.js:27: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/iterable-to-iterator-fallback.js:27: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/iterator-already-exhausted.js:19: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/iterator-already-exhausted.js:19: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/iterator-return-method-throws.js:25: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/iterator-return-method-throws.js:25: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/mapper-args.js:24: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/mapper-args.js:24: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/mapper-returns-closed-iterator.js:26: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/mapper-returns-closed-iterator.js:26: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/mapper-returns-non-object.js:23: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/mapper-returns-non-object.js:23: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/mapper-this.js:26: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/mapper-this.js:26: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/mapper-throws-then-closing-iterator-also-throws.js:30: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/mapper-throws-then-closing-iterator-also-throws.js:30: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/mapper-throws.js:31: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/mapper-throws.js:31: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/next-method-returns-non-object.js:19: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/next-method-returns-non-object.js:19: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-done.js:27: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-done.js:27: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-value-done.js:27: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-value-done.js:27: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-value.js:27: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-value.js:27: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/next-method-throws.js:19: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/next-method-throws.js:19: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/non-callable-mapper.js:18: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/flatMap/non-callable-mapper.js:18: strict mode: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/flatMap/result-is-iterator.js:12: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/result-is-iterator.js:12: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/return-is-forwarded-to-mapper-result.js:19: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/return-is-forwarded-to-mapper-result.js:19: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/return-is-forwarded-to-underlying-iterator.js:28: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/return-is-forwarded-to-underlying-iterator.js:28: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/return-is-not-forwarded-after-exhaustion.js:27: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/return-is-not-forwarded-after-exhaustion.js:27: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/strings-are-not-flattened.js:21: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/flatMap/strings-are-not-flattened.js:21: strict mode: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/flatMap/this-non-callable-next.js:13: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/this-non-callable-next.js:13: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/this-non-object.js:21: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/flatMap/this-non-object.js:21: strict mode: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/flatMap/this-plain-iterator.js:24: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/this-plain-iterator.js:24: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/throws-typeerror-when-generator-is-running.js:39: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/throws-typeerror-when-generator-is-running.js:39: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-advanced-in-parallel.js:19: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-advanced-in-parallel.js:19: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-closed-in-parallel.js:19: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-closed-in-parallel.js:19: strict mode: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-closed.js:21: InternalError: TODO implement Iterator.prototype.flatMap -test262/test/built-ins/Iterator/prototype/flatMap/underlying-iterator-closed.js:21: strict mode: InternalError: TODO implement Iterator.prototype.flatMap test262/test/built-ins/Object/defineProperties/typedarray-backed-by-resizable-buffer.js:20: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all test262/test/built-ins/Object/defineProperties/typedarray-backed-by-resizable-buffer.js:20: strict mode: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all test262/test/built-ins/Object/defineProperty/coerced-P-grow.js:45: TypeError: out-of-bound index in typed array