From b2ed2e91f5b9a7839c8290e29157ea2c3fba5c19 Mon Sep 17 00:00:00 2001 From: Fabrice Bellard Date: Sat, 20 Sep 2025 16:47:43 +0200 Subject: [PATCH] added Iterator.prototype.[drop,filter,flatMap,map,take,every,find,forEach,some,reduce,[Symbol.toStringTag]] (saghul) --- quickjs-atom.h | 1 + quickjs.c | 668 ++++++++++++++++++++++++++++++++++++++++++++++++- test262.conf | 2 +- 3 files changed, 669 insertions(+), 2 deletions(-) diff --git a/quickjs-atom.h b/quickjs-atom.h index 14cbf27..002e81d 100644 --- a/quickjs-atom.h +++ b/quickjs-atom.h @@ -231,6 +231,7 @@ DEF(Set, "Set") /* Map + 1 */ DEF(WeakMap, "WeakMap") /* Map + 2 */ DEF(WeakSet, "WeakSet") /* Map + 3 */ DEF(Iterator, "Iterator") +DEF(IteratorHelper, "Iterator Helper") DEF(IteratorWrap, "Iterator Wrap") DEF(Map_Iterator, "Map Iterator") DEF(Set_Iterator, "Set Iterator") diff --git a/quickjs.c b/quickjs.c index 8706352..7a04085 100644 --- a/quickjs.c +++ b/quickjs.c @@ -158,6 +158,7 @@ enum { JS_CLASS_WEAKMAP, /* u.map_state */ JS_CLASS_WEAKSET, /* u.map_state */ JS_CLASS_ITERATOR, /* u.map_iterator_data */ + JS_CLASS_ITERATOR_HELPER, /* u.iterator_helper_data */ JS_CLASS_ITERATOR_WRAP, /* u.iterator_wrap_data */ JS_CLASS_MAP_ITERATOR, /* u.map_iterator_data */ JS_CLASS_SET_ITERATOR, /* u.map_iterator_data */ @@ -951,6 +952,7 @@ struct JSObject { struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */ struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */ struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */ + struct JSIteratorHelperData *iterator_helper_data; /* JS_CLASS_ITERATOR_HELPER */ struct JSIteratorWrapData *iterator_wrap_data; /* JS_CLASS_ITERATOR_WRAP */ struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */ struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */ @@ -1136,6 +1138,9 @@ static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val, static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val); static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); +static void js_iterator_helper_finalizer(JSRuntime *rt, JSValue val); +static void js_iterator_helper_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func); static void js_iterator_wrap_finalizer(JSRuntime *rt, JSValue val); static void js_iterator_wrap_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); @@ -1547,6 +1552,7 @@ static JSClassShortDef const js_std_class_def[] = { { JS_ATOM_WeakMap, js_map_finalizer, js_map_mark }, /* JS_CLASS_WEAKMAP */ { JS_ATOM_WeakSet, js_map_finalizer, js_map_mark }, /* JS_CLASS_WEAKSET */ { JS_ATOM_Iterator, NULL, NULL }, /* JS_CLASS_ITERATOR */ + { JS_ATOM_IteratorHelper, js_iterator_helper_finalizer, js_iterator_helper_mark }, /* JS_CLASS_ITERATOR_HELPER */ { JS_ATOM_IteratorWrap, js_iterator_wrap_finalizer, js_iterator_wrap_mark }, /* JS_CLASS_ITERATOR_WRAP */ { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */ { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */ @@ -42288,6 +42294,338 @@ fail: return JS_EXCEPTION; } +typedef enum JSIteratorHelperKindEnum { + JS_ITERATOR_HELPER_KIND_DROP, + JS_ITERATOR_HELPER_KIND_EVERY, + JS_ITERATOR_HELPER_KIND_FILTER, + JS_ITERATOR_HELPER_KIND_FIND, + JS_ITERATOR_HELPER_KIND_FLAT_MAP, + JS_ITERATOR_HELPER_KIND_FOR_EACH, + JS_ITERATOR_HELPER_KIND_MAP, + JS_ITERATOR_HELPER_KIND_SOME, + JS_ITERATOR_HELPER_KIND_TAKE, +} JSIteratorHelperKindEnum; + +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) + JSIteratorHelperKindEnum kind : 8; + uint8_t executing : 1; + uint8_t done : 1; +} JSIteratorHelperData; + +static JSValue js_create_iterator_helper(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic) +{ + JSValueConst func; + JSValue obj, method; + int64_t count; + JSIteratorHelperData *it; + + if (!JS_IsObject(this_val)) + return JS_ThrowTypeErrorNotAnObject(ctx); + func = JS_UNDEFINED; + count = 0; + + switch(magic) { + case JS_ITERATOR_HELPER_KIND_DROP: + case JS_ITERATOR_HELPER_KIND_TAKE: + { + JSValue v; + double dlimit; + v = JS_ToNumber(ctx, argv[0]); + if (JS_IsException(v)) + goto fail; + // Check for Infinity. + if (JS_ToFloat64(ctx, &dlimit, v)) { + JS_FreeValue(ctx, v); + goto fail; + } + if (isnan(dlimit)) { + JS_FreeValue(ctx, v); + goto range_error; + } + if (!isfinite(dlimit)) { + JS_FreeValue(ctx, v); + if (dlimit < 0) + goto range_error; + else + count = MAX_SAFE_INTEGER; + } else { + v = JS_ToIntegerFree(ctx, v); + if (JS_IsException(v)) + goto fail; + if (JS_ToInt64Free(ctx, &count, v)) + goto fail; + } + if (count < 0) + goto range_error; + } + break; + case JS_ITERATOR_HELPER_KIND_FILTER: + case JS_ITERATOR_HELPER_KIND_FLAT_MAP: + case JS_ITERATOR_HELPER_KIND_MAP: + { + func = argv[0]; + if (check_function(ctx, func)) + goto fail; + } + break; + default: + abort(); + break; + } + + method = JS_GetProperty(ctx, this_val, JS_ATOM_next); + if (JS_IsException(method)) + goto fail; + obj = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_HELPER); + if (JS_IsException(obj)) { + JS_FreeValue(ctx, method); + goto fail; + } + it = js_malloc(ctx, sizeof(*it)); + if (!it) { + JS_FreeValue(ctx, obj); + JS_FreeValue(ctx, method); + goto fail; + } + it->kind = magic; + it->obj = JS_DupValue(ctx, this_val); + it->func = JS_DupValue(ctx, func); + it->next = method; + it->inner = JS_UNDEFINED; + it->count = count; + it->executing = 0; + it->done = 0; + JS_SetOpaque(obj, it); + return obj; +range_error: + JS_ThrowRangeError(ctx, "must be positive"); +fail: + JS_IteratorClose(ctx, this_val, TRUE); + return JS_EXCEPTION; +} + +static JSValue js_iterator_proto_func(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic) +{ + JSValue item, method, ret, func, index_val, r; + JSValueConst args[2]; + int64_t idx; + int done; + + if (!JS_IsObject(this_val)) + return JS_ThrowTypeErrorNotAnObject(ctx); + func = JS_UNDEFINED; + method = JS_UNDEFINED; + if (check_function(ctx, argv[0])) + goto fail; + func = JS_DupValue(ctx, argv[0]); + method = JS_GetProperty(ctx, this_val, JS_ATOM_next); + if (JS_IsException(method)) + goto fail; + + r = JS_UNDEFINED; + + switch(magic) { + case JS_ITERATOR_HELPER_KIND_EVERY: + { + r = JS_TRUE; + for (idx = 0; /*empty*/; idx++) { + item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done); + if (JS_IsException(item)) + goto fail; + if (done) + break; + index_val = JS_NewInt64(ctx, idx); + args[0] = item; + args[1] = index_val; + ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, item); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) + goto fail; + if (!JS_ToBoolFree(ctx, ret)) { + if (JS_IteratorClose(ctx, this_val, FALSE) < 0) + r = JS_EXCEPTION; + else + r = JS_FALSE; + break; + } + index_val = JS_UNDEFINED; + ret = JS_UNDEFINED; + item = JS_UNDEFINED; + } + } + break; + case JS_ITERATOR_HELPER_KIND_FIND: + { + for (idx = 0; /*empty*/; idx++) { + item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done); + if (JS_IsException(item)) + goto fail; + if (done) + break; + index_val = JS_NewInt64(ctx, idx); + args[0] = item; + args[1] = index_val; + ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) { + JS_FreeValue(ctx, item); + goto fail; + } + if (JS_ToBoolFree(ctx, ret)) { + if (JS_IteratorClose(ctx, this_val, FALSE) < 0) { + JS_FreeValue(ctx, item); + r = JS_EXCEPTION; + } else { + r = item; + } + break; + } + index_val = JS_UNDEFINED; + ret = JS_UNDEFINED; + item = JS_UNDEFINED; + } + } + break; + case JS_ITERATOR_HELPER_KIND_FOR_EACH: + { + for (idx = 0; /*empty*/; idx++) { + item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done); + if (JS_IsException(item)) + goto fail; + if (done) + break; + index_val = JS_NewInt64(ctx, idx); + args[0] = item; + args[1] = index_val; + ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, item); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) + goto fail; + JS_FreeValue(ctx, ret); + index_val = JS_UNDEFINED; + ret = JS_UNDEFINED; + item = JS_UNDEFINED; + } + } + break; + case JS_ITERATOR_HELPER_KIND_SOME: + { + r = JS_FALSE; + for (idx = 0; /*empty*/; idx++) { + item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done); + if (JS_IsException(item)) + goto fail; + if (done) + break; + index_val = JS_NewInt64(ctx, idx); + args[0] = item; + args[1] = index_val; + ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, item); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) + goto fail; + if (JS_ToBoolFree(ctx, ret)) { + if (JS_IteratorClose(ctx, this_val, FALSE) < 0) + r = JS_EXCEPTION; + else + r = JS_TRUE; + break; + } + index_val = JS_UNDEFINED; + ret = JS_UNDEFINED; + item = JS_UNDEFINED; + } + } + break; + default: + abort(); + break; + } + + JS_FreeValue(ctx, func); + JS_FreeValue(ctx, method); + return r; +fail: + JS_IteratorClose(ctx, this_val, TRUE); + JS_FreeValue(ctx, func); + JS_FreeValue(ctx, method); + return JS_EXCEPTION; +} + +static JSValue js_iterator_proto_reduce(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue item, method, ret, func, index_val, acc; + JSValueConst args[3]; + int64_t idx; + int done; + + if (!JS_IsObject(this_val)) + return JS_ThrowTypeErrorNotAnObject(ctx); + acc = JS_UNDEFINED; + func = JS_UNDEFINED; + method = JS_UNDEFINED; + if (check_function(ctx, argv[0])) + goto exception; + func = JS_DupValue(ctx, argv[0]); + method = JS_GetProperty(ctx, this_val, JS_ATOM_next); + if (JS_IsException(method)) + goto exception; + if (argc > 1) { + acc = JS_DupValue(ctx, argv[1]); + idx = 0; + } else { + acc = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done); + if (JS_IsException(acc)) + goto exception; + if (done) { + JS_ThrowTypeError(ctx, "empty iterator"); + goto exception; + } + idx = 1; + } + for (/* empty */; /*empty*/; idx++) { + item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done); + if (JS_IsException(item)) + goto exception; + if (done) + break; + index_val = JS_NewInt64(ctx, idx); + args[0] = acc; + args[1] = item; + args[2] = index_val; + ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, item); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) + goto exception; + JS_FreeValue(ctx, acc); + acc = ret; + index_val = JS_UNDEFINED; + ret = JS_UNDEFINED; + item = JS_UNDEFINED; + } + JS_FreeValue(ctx, func); + JS_FreeValue(ctx, method); + return acc; +exception: + JS_IteratorClose(ctx, this_val, TRUE); + JS_FreeValue(ctx, acc); + JS_FreeValue(ctx, func); + JS_FreeValue(ctx, method); + return JS_EXCEPTION; +} + static JSValue js_iterator_proto_toArray(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -42329,14 +42667,337 @@ static JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val, { return JS_DupValue(ctx, this_val); } - + +static JSValue js_iterator_proto_get_toStringTag(JSContext *ctx, JSValueConst this_val) +{ + return JS_AtomToString(ctx, JS_ATOM_Iterator); +} + +static JSValue js_iterator_proto_set_toStringTag(JSContext *ctx, JSValueConst this_val, JSValueConst val) +{ + int res; + + if (!JS_IsObject(this_val)) + return JS_ThrowTypeErrorNotAnObject(ctx); + if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_ITERATOR])) + return JS_ThrowTypeError(ctx, "Cannot assign to read only property"); + res = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_Symbol_toStringTag); + if (res < 0) + return JS_EXCEPTION; + if (res) { + if (JS_SetProperty(ctx, this_val, JS_ATOM_Symbol_toStringTag, JS_DupValue(ctx, val)) < 0) + return JS_EXCEPTION; + } else { + if (JS_DefinePropertyValue(ctx, this_val, JS_ATOM_Symbol_toStringTag, JS_DupValue(ctx, val), JS_PROP_C_W_E) < 0) + return JS_EXCEPTION; + } + return JS_UNDEFINED; +} + +/* Iterator Helper */ + +static void js_iterator_helper_finalizer(JSRuntime *rt, JSValue val) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JSIteratorHelperData *it = p->u.iterator_helper_data; + if (it) { + 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); + } +} + +static void js_iterator_helper_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JSIteratorHelperData *it = p->u.iterator_helper_data; + if (it) { + 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); + } +} + +static JSValue js_iterator_helper_next(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, + int *pdone, int magic) +{ + JSIteratorHelperData *it; + JSValue ret; + + *pdone = FALSE; + + it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_HELPER); + if (!it) + return JS_EXCEPTION; + if (it->executing) + return JS_ThrowTypeError(ctx, "cannot invoke a running iterator"); + if (it->done) { + *pdone = TRUE; + return JS_UNDEFINED; + } + + it->executing = 1; + + switch (it->kind) { + case JS_ITERATOR_HELPER_KIND_DROP: + { + JSValue item, method; + if (magic == GEN_MAGIC_NEXT) { + method = JS_DupValue(ctx, it->next); + } else { + method = JS_GetProperty(ctx, it->obj, JS_ATOM_return); + if (JS_IsException(method)) + goto fail; + } + while (it->count > 0) { + it->count--; + item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone); + if (JS_IsException(item)) { + JS_FreeValue(ctx, method); + goto fail; + } + JS_FreeValue(ctx, item); + if (magic == GEN_MAGIC_RETURN) + *pdone = TRUE; + if (*pdone) { + JS_FreeValue(ctx, method); + ret = JS_UNDEFINED; + goto done; + } + } + + item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone); + JS_FreeValue(ctx, method); + if (JS_IsException(item)) + goto fail; + ret = item; + goto done; + } + break; + case JS_ITERATOR_HELPER_KIND_FILTER: + { + JSValue item, method, selected, index_val; + JSValueConst args[2]; + if (magic == GEN_MAGIC_NEXT) { + method = JS_DupValue(ctx, it->next); + } else { + method = JS_GetProperty(ctx, it->obj, JS_ATOM_return); + if (JS_IsException(method)) + goto fail; + } + filter_again: + item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone); + if (JS_IsException(item)) { + JS_FreeValue(ctx, method); + goto fail; + } + if (*pdone || magic == GEN_MAGIC_RETURN) { + JS_FreeValue(ctx, method); + ret = item; + goto done; + } + index_val = JS_NewInt64(ctx, it->count++); + args[0] = item; + args[1] = index_val; + selected = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, index_val); + if (JS_IsException(selected)) { + JS_FreeValue(ctx, method); + goto fail; + } + if (JS_ToBoolFree(ctx, selected)) { + JS_FreeValue(ctx, method); + ret = item; + goto done; + } + goto filter_again; + } + break; + case JS_ITERATOR_HELPER_KIND_FLAT_MAP: + { + JSValue item, method, index_val, iter; + JSValueConst args[2]; + flat_map_again: + if (JS_IsUndefined(it->inner)) { + if (magic == GEN_MAGIC_NEXT) { + method = JS_DupValue(ctx, 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_NewInt64(ctx, 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; + JSValueConst args[2]; + if (magic == GEN_MAGIC_NEXT) { + method = JS_DupValue(ctx, 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_NewInt64(ctx, it->count++); + args[0] = item; + args[1] = index_val; + ret = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, index_val); + if (JS_IsException(ret)) + goto fail; + goto done; + } + break; + case JS_ITERATOR_HELPER_KIND_TAKE: + { + JSValue item, method; + if (it->count > 0) { + if (magic == GEN_MAGIC_NEXT) { + method = JS_DupValue(ctx, it->next); + } else { + method = JS_GetProperty(ctx, it->obj, JS_ATOM_return); + if (JS_IsException(method)) + goto fail; + } + it->count--; + 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(); + } + +done: + it->done = magic == GEN_MAGIC_NEXT ? *pdone : 1; + it->executing = 0; + return ret; +fail: + /* close the iterator object, preserving pending exception */ + JS_IteratorClose(ctx, it->obj, TRUE); + ret = JS_EXCEPTION; + goto done; +} + static const JSCFunctionListEntry js_iterator_funcs[] = { JS_CFUNC_DEF("from", 1, js_iterator_from ), }; static const JSCFunctionListEntry js_iterator_proto_funcs[] = { + JS_CFUNC_MAGIC_DEF("drop", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_DROP ), + JS_CFUNC_MAGIC_DEF("filter", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_FILTER ), + JS_CFUNC_MAGIC_DEF("flatMap", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_FLAT_MAP ), + JS_CFUNC_MAGIC_DEF("map", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_MAP ), + JS_CFUNC_MAGIC_DEF("take", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_TAKE ), + JS_CFUNC_MAGIC_DEF("every", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_EVERY ), + JS_CFUNC_MAGIC_DEF("find", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_FIND), + JS_CFUNC_MAGIC_DEF("forEach", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_FOR_EACH ), + JS_CFUNC_MAGIC_DEF("some", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_SOME ), + JS_CFUNC_DEF("reduce", 1, js_iterator_proto_reduce ), JS_CFUNC_DEF("toArray", 0, js_iterator_proto_toArray ), JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator ), + JS_CGETSET_DEF("[Symbol.toStringTag]", js_iterator_proto_get_toStringTag, js_iterator_proto_set_toStringTag), +}; + +static const JSCFunctionListEntry js_iterator_helper_proto_funcs[] = { + JS_ITERATOR_NEXT_DEF("next", 0, js_iterator_helper_next, GEN_MAGIC_NEXT ), + JS_ITERATOR_NEXT_DEF("return", 0, js_iterator_helper_next, GEN_MAGIC_RETURN ), + JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Iterator Helper", JS_PROP_CONFIGURABLE ), }; static const JSCFunctionListEntry js_array_proto_funcs[] = { @@ -53273,6 +53934,11 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) js_iterator_funcs, countof(js_iterator_funcs)); + ctx->class_proto[JS_CLASS_ITERATOR_HELPER] = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]); + JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ITERATOR_HELPER], + js_iterator_helper_proto_funcs, + countof(js_iterator_helper_proto_funcs)); + ctx->class_proto[JS_CLASS_ITERATOR_WRAP] = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ITERATOR]); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ITERATOR_WRAP], js_iterator_wrap_proto_funcs, diff --git a/test262.conf b/test262.conf index 1722ba7..f955c6c 100644 --- a/test262.conf +++ b/test262.conf @@ -140,7 +140,7 @@ Intl.NumberFormat-v3=skip Intl.RelativeTimeFormat=skip Intl.Segmenter=skip IsHTMLDDA -iterator-helpers=skip +iterator-helpers iterator-sequencing=skip json-modules json-parse-with-source=skip