diff --git a/gen/function_source.c b/gen/function_source.c index 05d432e..0409ecc 100644 Binary files a/gen/function_source.c and b/gen/function_source.c differ diff --git a/gen/hello.c b/gen/hello.c index db73313..b3c7b13 100644 Binary files a/gen/hello.c and b/gen/hello.c differ diff --git a/gen/hello_module.c b/gen/hello_module.c index 101bbbc..55cefb4 100644 Binary files a/gen/hello_module.c and b/gen/hello_module.c differ diff --git a/gen/repl.c b/gen/repl.c index c448eb4..ee8396f 100644 Binary files a/gen/repl.c and b/gen/repl.c differ diff --git a/gen/test_fib.c b/gen/test_fib.c index e8182d2..c53b12d 100644 Binary files a/gen/test_fib.c and b/gen/test_fib.c differ diff --git a/quickjs-atom.h b/quickjs-atom.h index 49c82a5..a009735 100644 --- a/quickjs-atom.h +++ b/quickjs-atom.h @@ -217,6 +217,7 @@ DEF(Set, "Set") /* Map + 1 */ DEF(WeakMap, "WeakMap") /* Map + 2 */ DEF(WeakSet, "WeakSet") /* Map + 3 */ DEF(Iterator, "Iterator") +DEF(IteratorHelper, "Iterator Helper") DEF(Map_Iterator, "Map Iterator") DEF(Set_Iterator, "Set Iterator") DEF(Array_Iterator, "Array Iterator") diff --git a/quickjs.c b/quickjs.c index ca4db69..a612f07 100644 --- a/quickjs.c +++ b/quickjs.c @@ -154,6 +154,7 @@ enum { JS_CLASS_WEAKMAP, /* u.map_state */ JS_CLASS_WEAKSET, /* u.map_state */ JS_CLASS_ITERATOR, + JS_CLASS_ITERATOR_HELPER, /* u.iterator_helper_data */ JS_CLASS_MAP_ITERATOR, /* u.map_iterator_data */ JS_CLASS_SET_ITERATOR, /* u.map_iterator_data */ JS_CLASS_ARRAY_ITERATOR, /* u.array_iterator_data */ @@ -705,6 +706,14 @@ typedef enum JSIteratorKindEnum { JS_ITERATOR_KIND_KEY_AND_VALUE, } JSIteratorKindEnum; +typedef enum JSIteratorHelperKindEnum { + JS_ITERATOR_HELPER_KIND_DROP, + JS_ITERATOR_HELPER_KIND_FILTER, + JS_ITERATOR_HELPER_KIND_FLAT_MAP, + JS_ITERATOR_HELPER_KIND_MAP, + JS_ITERATOR_HELPER_KIND_TAKE, +} JSIteratorHelperKindEnum; + typedef struct JSForInIterator { JSValue obj; BOOL is_array; @@ -944,6 +953,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 JSProxyData *proxy_data; /* JS_CLASS_PROXY */ struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */ struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */ @@ -1120,6 +1130,9 @@ static void js_map_iterator_mark(JSRuntime *rt, JSValue val, static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val); static void js_array_iterator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); +static void js_iterator_helper_finalizer(JSRuntime *rt, JSValue val); +static void js_iterator_helper_mark(JSRuntime *rt, JSValue val, + JS_MarkFunc *mark_func); static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val); static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func); @@ -1722,6 +1735,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_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 */ { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */ @@ -33531,7 +33545,7 @@ typedef enum BCTagEnum { BC_TAG_SYMBOL, } BCTagEnum; -#define BC_VERSION 17 +#define BC_VERSION 18 typedef struct BCWriterState { JSContext *ctx; @@ -40007,10 +40021,46 @@ static JSValue js_iterator_from(JSContext *ctx, JSValue this_val, return iter; } +static JSValue js_create_iterator_helper(JSContext *ctx, JSValue iterator, + JSIteratorHelperKindEnum kind, JSValue func, int64_t limit); + static JSValue js_iterator_proto_drop(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { - return JS_ThrowInternalError(ctx, "TODO implement Iterator.prototype.drop"); + JSValue v; + double dlimit; + int64_t limit; + if (!JS_IsObject(this_val)) + return JS_ThrowTypeError(ctx, "Iterator.prototype.drop 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_DROP, JS_UNDEFINED, limit); } static JSValue js_iterator_proto_every(JSContext *ctx, JSValue this_val, @@ -40396,6 +40446,142 @@ static JSValue js_iterator_proto_set_toStringTag(JSContext *ctx, JSValue this_va return JS_UNDEFINED; } +typedef struct JSIteratorHelperData { + JSIteratorHelperKindEnum kind; + JSValue obj; + JSValue next; + JSValue func; // predicate (filter) or mapper (flatMap, map) + int64_t limit; // (drop, take) + BOOL executing; + BOOL done; +} JSIteratorHelperData; + +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_free_rt(rt, it); + } +} + +static void js_iterator_helper_mark(JSRuntime *rt, JSValue 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); + } +} + +static JSValue js_iterator_helper_next(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, + BOOL *pdone, int magic) +{ + JSIteratorHelperData *it; + JSValue ret; + + 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) + return JS_UNDEFINED; + + it->executing = TRUE; + + switch (it->kind) { + case JS_ITERATOR_HELPER_KIND_DROP: + { + JSValue item, method; + 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; + } + while (it->limit > 0) { + it->limit--; + 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; + default: + abort(); + } + +done: + it->done = magic == GEN_MAGIC_NEXT ? *pdone : TRUE; + it->executing = FALSE; + return ret; +fail: + it->executing = FALSE; + if (it && JS_IsObject(it->obj)) { + /* close the iterator object, preserving pending exception */ + JS_IteratorClose(ctx, it->obj, TRUE); + } + *pdone = FALSE; + return JS_EXCEPTION; +} + +static JSValue js_create_iterator_helper(JSContext *ctx, JSValue iterator, + JSIteratorHelperKindEnum kind, JSValue func, int64_t limit) +{ + JSValue obj, method; + JSIteratorHelperData *it; + + method = JS_GetProperty(ctx, iterator, JS_ATOM_next); + if (JS_IsException(method)) + return JS_EXCEPTION; + obj = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_HELPER); + if (JS_IsException(obj)) { + JS_FreeValue(ctx, method); + return JS_EXCEPTION; + } + it = js_malloc(ctx, sizeof(*it)); + if (!it) { + JS_FreeValue(ctx, obj); + JS_FreeValue(ctx, method); + return JS_EXCEPTION; + } + it->kind = kind; + it->obj = js_dup(iterator); + it->func = js_dup(func); + it->next = method; + it->limit = limit; + it->executing = FALSE; + it->done = FALSE; + JS_SetOpaqueInternal(obj, it); + return obj; +} + static const JSCFunctionListEntry js_iterator_funcs[] = { JS_CFUNC_DEF("from", 1, js_iterator_from ), }; @@ -40416,6 +40602,12 @@ static const JSCFunctionListEntry js_iterator_proto_funcs[] = { 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[] = { JS_CFUNC_DEF("at", 1, js_array_at ), JS_CFUNC_DEF("with", 2, js_array_with ), @@ -50986,6 +51178,11 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_ITERATOR], JS_CLASS_ITERATOR); + ctx->class_proto[JS_CLASS_ITERATOR_HELPER] = JS_NewObjectProto(ctx, ctx->iterator_proto); + JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ITERATOR_HELPER], + js_iterator_helper_proto_funcs, + countof(js_iterator_helper_proto_funcs)); + /* Array */ JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY], js_array_proto_funcs, diff --git a/test262_errors.txt b/test262_errors.txt index dd2c470..845a5de 100644 --- a/test262_errors.txt +++ b/test262_errors.txt @@ -24,60 +24,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/drop/argument-effect-order.js:16: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/argument-effect-order.js:16: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/callable.js:10: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/callable.js:10: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/exhaustion-does-not-call-return.js:38: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/exhaustion-does-not-call-return.js:38: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/get-next-method-only-once.js:38: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/get-next-method-only-once.js:38: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/get-next-method-throws.js:17: Test262Error: Expected a Test262Error but got a InternalError -test262/test/built-ins/Iterator/prototype/drop/get-next-method-throws.js:17: strict mode: Test262Error: Expected a Test262Error but got a InternalError -test262/test/built-ins/Iterator/prototype/drop/get-return-method-throws.js:25: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/get-return-method-throws.js:25: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/limit-equals-total.js:18: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/limit-equals-total.js:18: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/limit-greater-than-total.js:19: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/limit-greater-than-total.js:19: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/limit-less-than-total.js:18: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/limit-less-than-total.js:18: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/limit-rangeerror.js:18: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/limit-rangeerror.js:18: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/limit-tonumber-throws.js:16: Test262Error: Expected a Test262Error but got a InternalError -test262/test/built-ins/Iterator/prototype/drop/limit-tonumber-throws.js:16: strict mode: Test262Error: Expected a Test262Error but got a InternalError -test262/test/built-ins/Iterator/prototype/drop/limit-tonumber.js:22: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/limit-tonumber.js:22: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/next-method-returns-non-object.js:23: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/next-method-returns-non-object.js:23: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-done.js:31: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-done.js:31: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-value-done.js:32: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-value-done.js:32: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-value.js:29: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/next-method-returns-throwing-value.js:29: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/next-method-throws.js:23: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/next-method-throws.js:23: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/result-is-iterator.js:11: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/result-is-iterator.js:11: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/return-is-forwarded.js:31: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/return-is-forwarded.js:31: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/return-is-not-forwarded-after-exhaustion.js:27: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/return-is-not-forwarded-after-exhaustion.js:27: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/this-non-callable-next.js:15: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/this-non-callable-next.js:15: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/this-non-object.js:22: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/drop/this-non-object.js:22: strict mode: Test262Error: Expected a TypeError but got a InternalError -test262/test/built-ins/Iterator/prototype/drop/this-plain-iterator.js:25: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/this-plain-iterator.js:25: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/throws-typeerror-when-generator-is-running.js:33: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/throws-typeerror-when-generator-is-running.js:33: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/underlying-iterator-advanced-in-parallel.js:19: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/underlying-iterator-advanced-in-parallel.js:19: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/underlying-iterator-closed-in-parallel.js:19: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/underlying-iterator-closed-in-parallel.js:19: strict mode: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/underlying-iterator-closed.js:21: InternalError: TODO implement Iterator.prototype.drop -test262/test/built-ins/Iterator/prototype/drop/underlying-iterator-closed.js:21: strict mode: InternalError: TODO implement Iterator.prototype.drop test262/test/built-ins/Iterator/prototype/filter/argument-effect-order.js:16: Test262Error: Expected a TypeError but got a InternalError test262/test/built-ins/Iterator/prototype/filter/argument-effect-order.js:16: strict mode: Test262Error: Expected a TypeError but got a InternalError test262/test/built-ins/Iterator/prototype/filter/callable.js:10: InternalError: TODO implement Iterator.prototype.filter