Skip to content

Commit 2bc339f

Browse files
committed
Make Iterator.from spec compliant
Create a proper wrapper around the inner iterator and proxy the calls to next / return.
1 parent 6d7448e commit 2bc339f

File tree

2 files changed

+101
-22
lines changed

2 files changed

+101
-22
lines changed

quickjs.c

Lines changed: 101 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ enum {
156156
JS_CLASS_SET, /* u.map_state */
157157
JS_CLASS_WEAKMAP, /* u.map_state */
158158
JS_CLASS_WEAKSET, /* u.map_state */
159-
JS_CLASS_ITERATOR,
159+
JS_CLASS_ITERATOR, /* u.iterator_data */
160160
JS_CLASS_ITERATOR_HELPER, /* u.iterator_helper_data */
161161
JS_CLASS_MAP_ITERATOR, /* u.map_iterator_data */
162162
JS_CLASS_SET_ITERATOR, /* u.map_iterator_data */
@@ -956,6 +956,7 @@ struct JSObject {
956956
struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */
957957
struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */
958958
struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */
959+
struct JSIteratorData *iterator_data; /* JS_CLASS_ITERATOR */
959960
struct JSIteratorHelperData *iterator_helper_data; /* JS_CLASS_ITERATOR_HELPER */
960961
struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */
961962
struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */
@@ -1133,6 +1134,9 @@ static void js_map_iterator_mark(JSRuntime *rt, JSValue val,
11331134
static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val);
11341135
static void js_array_iterator_mark(JSRuntime *rt, JSValue val,
11351136
JS_MarkFunc *mark_func);
1137+
static void js_iterator_finalizer(JSRuntime *rt, JSValue val);
1138+
static void js_iterator_mark(JSRuntime *rt, JSValue val,
1139+
JS_MarkFunc *mark_func);
11361140
static void js_iterator_helper_finalizer(JSRuntime *rt, JSValue val);
11371141
static void js_iterator_helper_mark(JSRuntime *rt, JSValue val,
11381142
JS_MarkFunc *mark_func);
@@ -1737,7 +1741,7 @@ static JSClassShortDef const js_std_class_def[] = {
17371741
{ JS_ATOM_Set, js_map_finalizer, js_map_mark }, /* JS_CLASS_SET */
17381742
{ JS_ATOM_WeakMap, js_map_finalizer, js_map_mark }, /* JS_CLASS_WEAKMAP */
17391743
{ JS_ATOM_WeakSet, js_map_finalizer, js_map_mark }, /* JS_CLASS_WEAKSET */
1740-
{ JS_ATOM_Iterator, NULL, NULL }, /* JS_CLASS_ITERATOR */
1744+
{ JS_ATOM_Iterator, js_iterator_finalizer, js_iterator_mark }, /* JS_CLASS_ITERATOR */
17411745
{ JS_ATOM_IteratorHelper, js_iterator_helper_finalizer, js_iterator_helper_mark }, /* JS_CLASS_ITERATOR_HELPER */
17421746
{ JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */
17431747
{ JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */
@@ -40053,24 +40057,95 @@ static JSValue js_array_iterator_next(JSContext *ctx, JSValue this_val,
4005340057
}
4005440058
}
4005540059

40060+
typedef struct JSIteratorData {
40061+
JSValue wrapped_iter;
40062+
JSValue wrapped_next;
40063+
} JSIteratorData;
40064+
40065+
static void js_iterator_finalizer(JSRuntime *rt, JSValue val)
40066+
{
40067+
JSObject *p = JS_VALUE_GET_OBJ(val);
40068+
JSIteratorData *it = p->u.iterator_data;
40069+
if (it) {
40070+
JS_FreeValueRT(rt, it->wrapped_iter);
40071+
JS_FreeValueRT(rt, it->wrapped_next);
40072+
js_free_rt(rt, it);
40073+
}
40074+
}
40075+
40076+
static void js_iterator_mark(JSRuntime *rt, JSValue val,
40077+
JS_MarkFunc *mark_func)
40078+
{
40079+
JSObject *p = JS_VALUE_GET_OBJ(val);
40080+
JSIteratorData *it = p->u.iterator_data;
40081+
if (it) {
40082+
JS_MarkValue(rt, it->wrapped_iter, mark_func);
40083+
JS_MarkValue(rt, it->wrapped_next, mark_func);
40084+
}
40085+
}
40086+
4005640087
static JSValue js_iterator_constructor(JSContext *ctx, JSValue new_target,
4005740088
int argc, JSValue *argv)
4005840089
{
40090+
JSValue obj;
4005940091
JSObject *p;
40092+
JSIteratorData *it;
4006040093

4006140094
if (JS_TAG_OBJECT != JS_VALUE_GET_TAG(new_target))
4006240095
return JS_ThrowTypeError(ctx, "constructor requires 'new'");
4006340096
p = JS_VALUE_GET_OBJ(new_target);
4006440097
if (p->class_id == JS_CLASS_C_FUNCTION)
4006540098
if (p->u.cfunc.c_function.generic == js_iterator_constructor)
4006640099
return JS_ThrowTypeError(ctx, "abstract class not constructable");
40067-
return js_create_from_ctor(ctx, new_target, JS_CLASS_ITERATOR);
40100+
obj = js_create_from_ctor(ctx, new_target, JS_CLASS_ITERATOR);
40101+
if (JS_IsException(obj))
40102+
return JS_EXCEPTION;
40103+
it = js_malloc(ctx, sizeof(*it));
40104+
if (!it) {
40105+
JS_FreeValue(ctx, obj);
40106+
return JS_EXCEPTION;
40107+
}
40108+
it->wrapped_iter = JS_UNDEFINED;
40109+
it->wrapped_next = JS_UNDEFINED;
40110+
JS_SetOpaqueInternal(obj, it);
40111+
return obj;
40112+
}
40113+
40114+
static JSValue js_iterator_wrapper_next(JSContext *ctx, JSValue this_val,
40115+
int argc, JSValue *argv)
40116+
{
40117+
JSIteratorData *it;
40118+
BOOL done;
40119+
it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR);
40120+
if (!it)
40121+
return JS_EXCEPTION;
40122+
return JS_IteratorNext2(ctx, it->wrapped_iter, it->wrapped_next, argc, argv, &done);
40123+
}
40124+
40125+
static JSValue js_iterator_wrapper_return(JSContext *ctx, JSValue this_val,
40126+
int argc, JSValue *argv)
40127+
{
40128+
JSIteratorData *it;
40129+
BOOL done;
40130+
JSValue method, ret;
40131+
it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR);
40132+
if (!it)
40133+
return JS_EXCEPTION;
40134+
method = JS_GetProperty(ctx, it->wrapped_iter, JS_ATOM_return);
40135+
if (JS_IsException(method))
40136+
return JS_EXCEPTION;
40137+
if (JS_IsNull(method) || JS_IsUndefined(method))
40138+
return js_create_iterator_result(ctx, JS_UNDEFINED, TRUE);
40139+
ret = JS_IteratorNext2(ctx, it->wrapped_iter, method, argc, argv, &done);
40140+
JS_FreeValue(ctx, method);
40141+
return ret;
4006840142
}
4006940143

4007040144
static JSValue js_iterator_from(JSContext *ctx, JSValue this_val,
4007140145
int argc, JSValue *argv)
4007240146
{
40073-
JSValue obj, method, iter, temp;
40147+
JSValue obj, method, iter;
40148+
JSIteratorData *it;
4007440149
int ret;
4007540150

4007640151
obj = argv[0];
@@ -40092,31 +40167,43 @@ static JSValue js_iterator_from(JSContext *ctx, JSValue this_val,
4009240167
return JS_EXCEPTION;
4009340168
if (JS_IsNull(method) || JS_IsUndefined(method)) {
4009440169
method = JS_GetProperty(ctx, obj, JS_ATOM_next);
40095-
if (JS_IsException(method))
40096-
return JS_EXCEPTION;
40097-
// honestly kind of ghetto but avoids having to
40098-
// define a separate JS_CLASS_NON_GHETTO_ITERATOR
40099-
temp = method;
40100-
method = js_function_bind(ctx, method, 1, &obj);
40101-
JS_FreeValue(ctx, temp);
4010240170
if (JS_IsException(method))
4010340171
return JS_EXCEPTION;
4010440172
iter = JS_NewObjectProtoClass(ctx, ctx->iterator_proto, JS_CLASS_ITERATOR);
4010540173
if (JS_IsException(iter)) {
4010640174
JS_FreeValue(ctx, method);
4010740175
return JS_EXCEPTION;
4010840176
}
40109-
if (JS_SetProperty(ctx, iter, JS_ATOM_next, method) < 0) {
40110-
JS_FreeValue(ctx, iter);
40111-
return JS_EXCEPTION;
40177+
it = js_malloc(ctx, sizeof(*it));
40178+
if (!it) {
40179+
JS_FreeValue(ctx, method);
40180+
goto fail;
4011240181
}
40182+
it->wrapped_iter = js_dup(obj);
40183+
it->wrapped_next = method;
40184+
JS_SetOpaqueInternal(iter, it);
40185+
// next() method.
40186+
method = JS_NewCFunction(ctx, js_iterator_wrapper_next, "next", 0);
40187+
if (JS_IsException(method))
40188+
goto fail;
40189+
if (JS_SetProperty(ctx, iter, JS_ATOM_next, method) < 0)
40190+
goto fail;
40191+
// return() method.
40192+
method = JS_NewCFunction(ctx, js_iterator_wrapper_return, "return", 0);
40193+
if (JS_IsException(method))
40194+
goto fail;
40195+
if (JS_SetProperty(ctx, iter, JS_ATOM_return, method) < 0)
40196+
goto fail;
4011340197
} else {
4011440198
iter = JS_GetIterator2(ctx, obj, method);
4011540199
JS_FreeValue(ctx, method);
4011640200
if (JS_IsException(iter))
4011740201
return JS_EXCEPTION;
4011840202
}
4011940203
return iter;
40204+
fail:
40205+
JS_FreeValue(ctx, iter);
40206+
return JS_EXCEPTION;
4012040207
}
4012140208

4012240209
static JSValue js_create_iterator_helper(JSContext *ctx, JSValue iterator,

test262_errors.txt

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,6 @@ test262/test/built-ins/Date/prototype/setUTCMonth/date-value-read-before-tonumbe
4242
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
4343
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
4444
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
45-
test262/test/built-ins/Iterator/from/get-return-method-when-call-return.js:24: TypeError: not a function
46-
test262/test/built-ins/Iterator/from/get-return-method-when-call-return.js:24: strict mode: TypeError: not a function
47-
test262/test/built-ins/Iterator/from/return-method-calls-base-return-method.js:29: TypeError: not a function
48-
test262/test/built-ins/Iterator/from/return-method-calls-base-return-method.js:29: strict mode: TypeError: not a function
49-
test262/test/built-ins/Iterator/from/return-method-returns-iterator-result.js:18: TypeError: not a function
50-
test262/test/built-ins/Iterator/from/return-method-returns-iterator-result.js:18: strict mode: TypeError: not a function
51-
test262/test/built-ins/Iterator/from/return-method-throws-for-invalid-this.js:16: TypeError: not a function
52-
test262/test/built-ins/Iterator/from/return-method-throws-for-invalid-this.js:16: strict mode: TypeError: not a function
5345
test262/test/built-ins/Iterator/prototype/Symbol.iterator/prop-desc.js:15: Test262Error: obj should have an own property Symbol(Symbol.iterator)
5446
test262/test/built-ins/Iterator/prototype/Symbol.iterator/prop-desc.js:15: strict mode: Test262Error: obj should have an own property Symbol(Symbol.iterator)
5547
test262/test/built-ins/Iterator/prototype/constructor/prop-desc.js:10: Test262Error: Expected SameValue(«"undefined"», «"function"») to be true

0 commit comments

Comments
 (0)