diff --git a/gen/function_source.c b/gen/function_source.c index 0409ecc..3c55b87 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 b3c7b13..c1df121 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 55cefb4..70d43a4 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 ee8396f..67f4d65 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 c53b12d..5329383 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 a009735..358fe23 100644 --- a/quickjs-atom.h +++ b/quickjs-atom.h @@ -218,6 +218,7 @@ 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") DEF(Array_Iterator, "Array Iterator") diff --git a/quickjs.c b/quickjs.c index 2a662ae..119e810 100644 --- a/quickjs.c +++ b/quickjs.c @@ -158,6 +158,7 @@ enum { JS_CLASS_WEAKSET, /* u.map_state */ JS_CLASS_ITERATOR, 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 */ JS_CLASS_ARRAY_ITERATOR, /* u.array_iterator_data */ @@ -957,6 +958,7 @@ struct JSObject { 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 */ struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */ @@ -1136,6 +1138,9 @@ static void js_array_iterator_mark(JSRuntime *rt, JSValue val, 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_iterator_wrap_finalizer(JSRuntime *rt, JSValue val); +static void js_iterator_wrap_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); @@ -1739,6 +1744,7 @@ static JSClassShortDef const js_std_class_def[] = { { 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 */ { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */ @@ -33653,7 +33659,7 @@ typedef enum BCTagEnum { BC_TAG_SYMBOL, } BCTagEnum; -#define BC_VERSION 18 +#define BC_VERSION 19 typedef struct BCWriterState { JSContext *ctx; @@ -40060,6 +40066,61 @@ static JSValue js_array_iterator_next(JSContext *ctx, JSValue this_val, } } +typedef struct JSIteratorWrapData { + JSValue wrapped_iter; + JSValue wrapped_next; +} JSIteratorWrapData; + +static void js_iterator_wrap_finalizer(JSRuntime *rt, JSValue val) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JSIteratorWrapData *it = p->u.iterator_wrap_data; + if (it) { + JS_FreeValueRT(rt, it->wrapped_iter); + JS_FreeValueRT(rt, it->wrapped_next); + js_free_rt(rt, it); + } +} + +static void js_iterator_wrap_mark(JSRuntime *rt, JSValue val, + JS_MarkFunc *mark_func) +{ + JSObject *p = JS_VALUE_GET_OBJ(val); + JSIteratorWrapData *it = p->u.iterator_wrap_data; + if (it) { + JS_MarkValue(rt, it->wrapped_iter, mark_func); + JS_MarkValue(rt, it->wrapped_next, mark_func); + } +} + +static JSValue js_iterator_wrap_next(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, + BOOL *pdone, int magic) +{ + JSIteratorWrapData *it; + JSValue method, ret; + it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_WRAP); + if (!it) + return JS_EXCEPTION; + if (magic == GEN_MAGIC_NEXT) + return JS_IteratorNext(ctx, it->wrapped_iter, it->wrapped_next, argc, argv, pdone); + method = JS_GetProperty(ctx, it->wrapped_iter, JS_ATOM_return); + if (JS_IsException(method)) + return JS_EXCEPTION; + if (JS_IsNull(method) || JS_IsUndefined(method)) { + *pdone = TRUE; + return JS_UNDEFINED; + } + ret = JS_IteratorNext2(ctx, it->wrapped_iter, method, argc, argv, pdone); + JS_FreeValue(ctx, method); + return ret; +} + +static const JSCFunctionListEntry js_iterator_wrap_proto_funcs[] = { + JS_ITERATOR_NEXT_DEF("next", 0, js_iterator_wrap_next, GEN_MAGIC_NEXT ), + JS_ITERATOR_NEXT_DEF("return", 0, js_iterator_wrap_next, GEN_MAGIC_RETURN ), +}; + static JSValue js_iterator_constructor(JSContext *ctx, JSValue new_target, int argc, JSValue *argv) { @@ -40077,7 +40138,8 @@ static JSValue js_iterator_constructor(JSContext *ctx, JSValue new_target, static JSValue js_iterator_from(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { - JSValue obj, method, iter, temp; + JSValue obj, method, iter; + JSIteratorWrapData *it; int ret; obj = argv[0]; @@ -40101,22 +40163,15 @@ static JSValue js_iterator_from(JSContext *ctx, JSValue this_val, method = JS_GetProperty(ctx, obj, JS_ATOM_next); if (JS_IsException(method)) return JS_EXCEPTION; - // honestly kind of ghetto but avoids having to - // define a separate JS_CLASS_NON_GHETTO_ITERATOR - temp = method; - method = js_function_bind(ctx, method, 1, &obj); - JS_FreeValue(ctx, temp); - if (JS_IsException(method)) - return JS_EXCEPTION; - iter = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_ITERATOR], JS_CLASS_ITERATOR); - if (JS_IsException(iter)) { - JS_FreeValue(ctx, method); - return JS_EXCEPTION; - } - if (JS_SetProperty(ctx, iter, JS_ATOM_next, method) < 0) { - JS_FreeValue(ctx, iter); - return JS_EXCEPTION; - } + iter = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_WRAP); + if (JS_IsException(iter)) + goto fail; + it = js_malloc(ctx, sizeof(*it)); + if (!it) + goto fail; + it->wrapped_iter = js_dup(obj); + it->wrapped_next = method; + JS_SetOpaqueInternal(iter, it); } else { iter = JS_GetIterator2(ctx, obj, method); JS_FreeValue(ctx, method); @@ -40124,6 +40179,10 @@ static JSValue js_iterator_from(JSContext *ctx, JSValue this_val, return JS_EXCEPTION; } return iter; +fail: + JS_FreeValue(ctx, method); + JS_FreeValue(ctx, iter); + return JS_EXCEPTION; } static JSValue js_create_iterator_helper(JSContext *ctx, JSValue iterator, @@ -51544,6 +51603,11 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) 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, + countof(js_iterator_wrap_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 de4f7dc..7e5528f 100644 --- a/test262_errors.txt +++ b/test262_errors.txt @@ -42,16 +42,6 @@ test262/test/built-ins/Date/prototype/setUTCMonth/date-value-read-before-tonumbe test262/test/built-ins/Date/prototype/setUTCMonth/date-value-read-before-tonumber-when-date-is-invalid.js:26: strict mode: Test262Error: time updated in valueOf Expected SameValue(«NaN», «0») to be true test262/test/built-ins/Date/prototype/setUTCSeconds/date-value-read-before-tonumber-when-date-is-invalid.js:26: Test262Error: time updated in valueOf Expected SameValue(«NaN», «0») to be true test262/test/built-ins/Date/prototype/setUTCSeconds/date-value-read-before-tonumber-when-date-is-invalid.js:26: strict mode: Test262Error: time updated in valueOf Expected SameValue(«NaN», «0») to be true -test262/test/built-ins/Iterator/from/get-return-method-when-call-return.js:24: TypeError: not a function -test262/test/built-ins/Iterator/from/get-return-method-when-call-return.js:24: strict mode: TypeError: not a function -test262/test/built-ins/Iterator/from/result-proto.js:10: unexpected error: Test262Error: Expected SameValue(«[object Object]», «[object Iterator]») to be true -test262/test/built-ins/Iterator/from/result-proto.js:10: strict mode: unexpected error: Test262Error: Expected SameValue(«[object Object]», «[object Iterator]») to be true -test262/test/built-ins/Iterator/from/return-method-calls-base-return-method.js:29: TypeError: not a function -test262/test/built-ins/Iterator/from/return-method-calls-base-return-method.js:29: strict mode: TypeError: not a function -test262/test/built-ins/Iterator/from/return-method-returns-iterator-result.js:18: TypeError: not a function -test262/test/built-ins/Iterator/from/return-method-returns-iterator-result.js:18: strict mode: TypeError: not a function -test262/test/built-ins/Iterator/from/return-method-throws-for-invalid-this.js:16: TypeError: not a function -test262/test/built-ins/Iterator/from/return-method-throws-for-invalid-this.js:16: strict mode: TypeError: not a function test262/test/built-ins/Iterator/prototype/constructor/prop-desc.js:10: Test262Error: Expected SameValue(«"undefined"», «"function"») to be true 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