MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at mir/inline-method 1311 lines 48 kB view raw
1#include <stdlib.h> 2#include <string.h> 3 4#include "ant.h" 5#include "errors.h" 6#include "runtime.h" 7#include "internal.h" 8#include "ptr.h" 9#include "silver/engine.h" 10#include "descriptors.h" 11 12#include "modules/assert.h" 13#include "modules/iterator.h" 14#include "modules/symbol.h" 15 16enum { 17 WRAP_MAP = 0, 18 WRAP_FILTER = 1, 19 WRAP_TAKE = 2, 20 WRAP_DROP = 3, 21 WRAP_FLATMAP = 4, 22 WRAP_PASS = 5, 23 WRAP_FROM_SYNC = 6, 24}; 25 26enum { 27 ASYNC_TERM_EVERY = 0, 28 ASYNC_TERM_SOME = 1, 29 ASYNC_TERM_FIND = 2, 30 ASYNC_TERM_FOREACH = 3, 31 ASYNC_TERM_REDUCE = 4, 32 ASYNC_TERM_TOARRAY = 5, 33}; 34 35static ant_value_t g_wrap_iter_proto = 0; 36static ant_value_t g_async_wrap_iter_proto = 0; 37 38enum { ASYNC_TERMINAL_STATE_TAG = 0x41544954u }; // ATIT 39 40typedef struct { 41 double index; 42 int mode; 43 bool has_acc; 44} async_terminal_state_t; 45 46static inline ant_value_t call_indexed_callback(ant_t *js, ant_value_t fn, ant_value_t value, double index) { 47 ant_value_t call_args[2] = { value, js_mknum(index) }; 48 return sv_vm_call(js->vm, js, fn, js_mkundef(), call_args, 2, NULL, false); 49} 50 51static inline ant_value_t set_iter_result(ant_t *js, ant_value_t result, ant_value_t value, bool done) { 52 js_set(js, result, "done", done ? js_true : js_false); 53 js_set(js, result, "value", value); 54 return result; 55} 56 57static ant_value_t wrap_iter_next(ant_t *js, ant_value_t *args, int nargs) { 58 ant_value_t self = js->this_val; 59 ant_value_t source = js_get_slot(self, SLOT_DATA); 60 ant_value_t state_v = js_get_slot(self, SLOT_ITER_STATE); 61 62 uint32_t state = (vtype(state_v) == T_NUM) ? (uint32_t)js_getnum(state_v) : 0; 63 uint32_t kind = ITER_STATE_KIND(state); 64 uint32_t count = ITER_STATE_INDEX(state); 65 66 ant_value_t result = js_mkobj(js); 67 ant_value_t cb = js_get_slot(self, SLOT_CTOR); 68 ant_value_t next_fn = js_getprop_fallback(js, source, "next"); 69 70 for (;;) { 71 if (kind == WRAP_FLATMAP) { 72 ant_value_t inner = js_get_slot(self, SLOT_ENTRIES); 73 74 if (vtype(inner) != T_UNDEF) { 75 ant_value_t inner_next = js_getprop_fallback(js, inner, "next"); 76 ant_value_t inner_step = sv_vm_call(js->vm, js, inner_next, inner, NULL, 0, NULL, false); 77 if (!is_err(inner_step)) { 78 ant_value_t inner_done = js_getprop_fallback(js, inner_step, "done"); 79 if (!js_truthy(js, inner_done)) return set_iter_result( 80 js, result, js_getprop_fallback(js, inner_step, "value" 81 ), false); 82 } 83 84 js_set_slot(self, SLOT_ENTRIES, js_mkundef()); 85 }} 86 87 ant_value_t step; 88 if (vtype(next_fn) == T_CFUNC) { 89 ant_value_t old_this = js->this_val; 90 js->this_val = source; 91 step = js_as_cfunc(next_fn)(js, NULL, 0); 92 js->this_val = old_this; 93 } else step = sv_vm_call(js->vm, js, next_fn, source, NULL, 0, NULL, false); 94 95 if (is_err(step)) return step; 96 ant_value_t done = js_getprop_fallback(js, step, "done"); 97 98 if (js_truthy(js, done)) { 99 if (kind == WRAP_FLATMAP) { 100 ant_value_t inner = js_get_slot(self, SLOT_ENTRIES); 101 if (vtype(inner) != T_UNDEF) { 102 js_set_slot(self, SLOT_ENTRIES, js_mkundef()); 103 }} 104 105 return set_iter_result(js, result, js_mkundef(), true); 106 } 107 108 ant_value_t value = js_getprop_fallback(js, step, "value"); 109 110 switch (kind) { 111 case WRAP_MAP: { 112 ant_value_t out_val; 113 if (is_callable(cb)) { 114 out_val = call_indexed_callback(js, cb, value, (double)count); 115 if (is_err(out_val)) return out_val; 116 } else out_val = value; 117 118 count++; 119 js_set_slot(self, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, count))); 120 return set_iter_result(js, result, out_val, false); 121 } 122 123 case WRAP_FILTER: { 124 ant_value_t test = call_indexed_callback(js, cb, value, (double)count); 125 if (is_err(test)) return test; 126 count++; 127 js_set_slot(self, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, count))); 128 if (js_truthy(js, test)) { 129 return set_iter_result(js, result, value, false); 130 } 131 continue; 132 } 133 134 case WRAP_TAKE: { 135 uint32_t limit = (vtype(cb) == T_NUM) ? (uint32_t)js_getnum(cb) : 0; 136 if (count >= limit) { 137 return set_iter_result(js, result, js_mkundef(), true); 138 } 139 js_set_slot(self, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, count + 1))); 140 return set_iter_result(js, result, value, false); 141 } 142 143 case WRAP_DROP: { 144 uint32_t limit = (vtype(cb) == T_NUM) ? (uint32_t)js_getnum(cb) : 0; 145 count++; 146 js_set_slot(self, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, count))); 147 if (count <= limit) continue; 148 return set_iter_result(js, result, value, false); 149 } 150 151 case WRAP_FLATMAP: { 152 ant_value_t mapped = call_indexed_callback(js, cb, value, (double)count); 153 if (is_err(mapped)) return mapped; 154 count++; 155 js_set_slot(self, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, count))); 156 157 ant_value_t iter_fn = js_get_sym(js, mapped, get_iterator_sym()); 158 if (!is_callable(iter_fn)) { 159 return set_iter_result(js, result, mapped, false); 160 } 161 162 ant_value_t inner = sv_vm_call(js->vm, js, iter_fn, mapped, NULL, 0, NULL, false); 163 if (is_err(inner)) return inner; 164 165 ant_value_t inner_next = js_getprop_fallback(js, inner, "next"); 166 ant_value_t inner_step = sv_vm_call(js->vm, js, inner_next, inner, NULL, 0, NULL, false); 167 if (is_err(inner_step)) return inner_step; 168 ant_value_t inner_done = js_getprop_fallback(js, inner_step, "done"); 169 if (!js_truthy(js, inner_done)) { 170 js_set_slot_wb(js, self, SLOT_ENTRIES, inner); 171 return set_iter_result(js, result, js_getprop_fallback(js, inner_step, "value"), false); 172 } 173 continue; 174 } 175 176 default: 177 return set_iter_result(js, result, value, false); 178 } 179 } 180} 181 182static ant_value_t make_wrap_iter(ant_t *js, ant_value_t source, int kind, ant_value_t cb) { 183 ant_value_t iter = js_mkobj(js); 184 185 js_set_proto_init(iter, g_wrap_iter_proto); 186 js_set_slot_wb(js, iter, SLOT_DATA, source); 187 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, 0))); 188 js_set_slot_wb(js, iter, SLOT_CTOR, cb); 189 190 return iter; 191} 192 193static ant_value_t get_source_iter(ant_t *js) { 194 ant_value_t self = js->this_val; 195 ant_value_t next = js_getprop_fallback(js, self, "next"); 196 if (is_callable(next)) return self; 197 198 ant_value_t iter_fn = js_get_sym(js, self, get_iterator_sym()); 199 if (!is_callable(iter_fn)) return js_mkerr_typed(js, JS_ERR_TYPE, "object is not iterable"); 200 201 return sv_vm_call(js->vm, js, iter_fn, self, NULL, 0, NULL, false); 202} 203 204static ant_value_t iter_make_helper(ant_t *js, int kind, ant_value_t cb) { 205 ant_value_t source = get_source_iter(js); 206 if (is_err(source)) return source; 207 return make_wrap_iter(js, source, kind, cb); 208} 209 210static ant_value_t iter_make_callable_helper( 211 ant_t *js, 212 ant_value_t *args, 213 int nargs, 214 int kind, 215 const char *method 216) { 217 if (nargs < 1 || !is_callable(args[0])) 218 return js_mkerr_typed(js, JS_ERR_TYPE, "%s requires a callable", method); 219 return iter_make_helper(js, kind, args[0]); 220} 221 222static ant_value_t iter_make_count_helper( 223 ant_t *js, ant_value_t *args, 224 int nargs, int kind, 225 const char *method 226) { 227 double limit = (nargs >= 1 && vtype(args[0]) == T_NUM) ? js_getnum(args[0]) : 0; 228 if (limit < 0) return js_mkerr(js, "%s requires a non-negative number", method); 229 return iter_make_helper(js, kind, js_mknum(limit)); 230} 231 232static ant_value_t iter_map(ant_t *js, ant_value_t *args, int nargs) { 233 return iter_make_callable_helper(js, args, nargs, WRAP_MAP, "Iterator.prototype.map"); 234} 235 236static ant_value_t iter_filter(ant_t *js, ant_value_t *args, int nargs) { 237 return iter_make_callable_helper(js, args, nargs, WRAP_FILTER, "Iterator.prototype.filter"); 238} 239 240static ant_value_t iter_take(ant_t *js, ant_value_t *args, int nargs) { 241 return iter_make_count_helper(js, args, nargs, WRAP_TAKE, "Iterator.prototype.take"); 242} 243 244static ant_value_t iter_drop(ant_t *js, ant_value_t *args, int nargs) { 245 return iter_make_count_helper(js, args, nargs, WRAP_DROP, "Iterator.prototype.drop"); 246} 247 248static ant_value_t iter_flatMap(ant_t *js, ant_value_t *args, int nargs) { 249 return iter_make_callable_helper(js, args, nargs, WRAP_FLATMAP, "Iterator.prototype.flatMap"); 250} 251 252static ant_value_t iter_every(ant_t *js, ant_value_t *args, int nargs) { 253 if (nargs < 1 || !is_callable(args[0])) 254 return js_mkerr_typed(js, JS_ERR_TYPE, "Iterator.prototype.every requires a callable"); 255 ant_value_t fn = args[0]; 256 257 js_iter_t it; 258 if (!js_iter_open(js, js->this_val, &it)) 259 return js_mkerr_typed(js, JS_ERR_TYPE, "object is not iterable"); 260 261 ant_value_t value; 262 uint32_t counter = 0; 263 while (js_iter_next(js, &it, &value)) { 264 ant_value_t test = call_indexed_callback(js, fn, value, (double)counter++); 265 if (is_err(test)) { js_iter_close(js, &it); return test; } 266 if (!js_truthy(js, test)) { js_iter_close(js, &it); return js_false; } 267 } 268 return js_true; 269} 270 271static ant_value_t iter_some(ant_t *js, ant_value_t *args, int nargs) { 272 if (nargs < 1 || !is_callable(args[0])) 273 return js_mkerr_typed(js, JS_ERR_TYPE, "Iterator.prototype.some requires a callable"); 274 ant_value_t fn = args[0]; 275 276 js_iter_t it; 277 if (!js_iter_open(js, js->this_val, &it)) 278 return js_mkerr_typed(js, JS_ERR_TYPE, "object is not iterable"); 279 280 ant_value_t value; 281 uint32_t counter = 0; 282 while (js_iter_next(js, &it, &value)) { 283 ant_value_t test = call_indexed_callback(js, fn, value, (double)counter++); 284 if (is_err(test)) { js_iter_close(js, &it); return test; } 285 if (js_truthy(js, test)) { js_iter_close(js, &it); return js_true; } 286 } 287 return js_false; 288} 289 290static ant_value_t iter_find(ant_t *js, ant_value_t *args, int nargs) { 291 if (nargs < 1 || !is_callable(args[0])) 292 return js_mkerr_typed(js, JS_ERR_TYPE, "Iterator.prototype.find requires a callable"); 293 ant_value_t fn = args[0]; 294 295 js_iter_t it; 296 if (!js_iter_open(js, js->this_val, &it)) 297 return js_mkerr_typed(js, JS_ERR_TYPE, "object is not iterable"); 298 299 ant_value_t value; 300 uint32_t counter = 0; 301 while (js_iter_next(js, &it, &value)) { 302 ant_value_t test = call_indexed_callback(js, fn, value, (double)counter++); 303 if (is_err(test)) { js_iter_close(js, &it); return test; } 304 if (js_truthy(js, test)) { js_iter_close(js, &it); return value; } 305 } 306 return js_mkundef(); 307} 308 309static ant_value_t iter_forEach(ant_t *js, ant_value_t *args, int nargs) { 310 if (nargs < 1 || !is_callable(args[0])) 311 return js_mkerr_typed(js, JS_ERR_TYPE, "Iterator.prototype.forEach requires a callable"); 312 ant_value_t fn = args[0]; 313 314 js_iter_t it; 315 if (!js_iter_open(js, js->this_val, &it)) 316 return js_mkerr_typed(js, JS_ERR_TYPE, "object is not iterable"); 317 318 ant_value_t value; 319 uint32_t counter = 0; 320 while (js_iter_next(js, &it, &value)) { 321 ant_value_t r = call_indexed_callback(js, fn, value, (double)counter++); 322 if (is_err(r)) { js_iter_close(js, &it); return r; } 323 } 324 return js_mkundef(); 325} 326 327static ant_value_t iter_reduce(ant_t *js, ant_value_t *args, int nargs) { 328 if (nargs < 1 || !is_callable(args[0])) 329 return js_mkerr_typed(js, JS_ERR_TYPE, "Iterator.prototype.reduce requires a callable"); 330 ant_value_t fn = args[0]; 331 bool has_init = (nargs >= 2); 332 333 js_iter_t it; 334 if (!js_iter_open(js, js->this_val, &it)) 335 return js_mkerr_typed(js, JS_ERR_TYPE, "object is not iterable"); 336 337 ant_value_t acc = has_init ? args[1] : js_mkundef(); 338 bool first = !has_init; 339 ant_value_t value; 340 uint32_t counter = 0; 341 342 while (js_iter_next(js, &it, &value)) { 343 if (first) { acc = value; first = false; counter++; continue; } 344 ant_value_t call_args[3] = { acc, value, js_mknum((double)counter++) }; 345 acc = sv_vm_call(js->vm, js, fn, js_mkundef(), call_args, 3, NULL, false); 346 if (is_err(acc)) { js_iter_close(js, &it); return acc; } 347 } 348 349 if (first) 350 return js_mkerr_typed(js, JS_ERR_TYPE, "reduce of empty iterator with no initial value"); 351 return acc; 352} 353 354static ant_value_t iter_toArray(ant_t *js, ant_value_t *args, int nargs) { 355 js_iter_t it; 356 if (!js_iter_open(js, js->this_val, &it)) 357 return js_mkerr_typed(js, JS_ERR_TYPE, "object is not iterable"); 358 359 ant_value_t arr = js_mkarr(js); 360 ant_value_t value; 361 while (js_iter_next(js, &it, &value)) 362 js_arr_push(js, arr, value); 363 364 return arr; 365} 366 367static ant_value_t iter_from(ant_t *js, ant_value_t *args, int nargs) { 368 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "Iterator.from requires an argument"); 369 ant_value_t obj = args[0]; 370 371 ant_value_t next = js_getprop_fallback(js, obj, "next"); 372 if (is_callable(next)) { 373 return make_wrap_iter(js, obj, WRAP_MAP, js_mkundef()); 374 } 375 376 ant_value_t iter_fn = js_get_sym(js, obj, get_iterator_sym()); 377 if (!is_callable(iter_fn)) 378 return js_mkerr_typed(js, JS_ERR_TYPE, "object is not iterable"); 379 380 ant_value_t iterator = sv_vm_call(js->vm, js, iter_fn, obj, NULL, 0, NULL, false); 381 if (is_err(iterator)) return iterator; 382 383 return iterator; 384} 385 386static ant_value_t iter_ctor(ant_t *js, ant_value_t *args, int nargs) { 387 if (vtype(js->new_target) == T_UNDEF) 388 return js_mkerr_typed(js, JS_ERR_TYPE, "Iterator is not directly constructable"); 389 390 ant_value_t obj = js_mkobj(js); 391 ant_value_t proto = js_instance_proto_from_new_target(js, js->sym.iterator_proto); 392 if (is_object_type(proto)) js_set_proto_init(obj, proto); 393 394 return obj; 395} 396 397static ant_value_t async_iter_ctor(ant_t *js, ant_value_t *args, int nargs) { 398 if (vtype(js->new_target) == T_UNDEF) 399 return js_mkerr_typed(js, JS_ERR_TYPE, "AsyncIterator constructor requires 'new'"); 400 401 ant_value_t obj = js_mkobj(js); 402 ant_value_t proto = js_instance_proto_from_new_target(js, js->sym.async_iterator_proto); 403 if (is_object_type(proto)) js_set_proto_init(obj, proto); 404 405 return obj; 406} 407 408static inline ant_value_t iter_result(ant_t *js, ant_value_t value, bool done) { 409 ant_value_t result = js_mkobj(js); 410 js_set(js, result, "done", done ? js_true : js_false); 411 js_set(js, result, "value", value); 412 return result; 413} 414 415static inline ant_value_t fulfilled_promise(ant_t *js, ant_value_t value) { 416 ant_value_t promise = js_mkpromise(js); 417 js_resolve_promise(js, promise, value); 418 return promise; 419} 420 421static inline ant_value_t rejected_promise(ant_t *js, ant_value_t reason) { 422 ant_value_t promise = js_mkpromise(js); 423 js_reject_promise(js, promise, reason); 424 return promise; 425} 426 427static inline ant_value_t promise_from_call_result(ant_t *js, ant_value_t result) { 428 if (vtype(result) == T_PROMISE) return result; 429 if (is_err(result)) return rejected_promise(js, result); 430 return fulfilled_promise(js, result); 431} 432 433static ant_value_t async_iter_call_method( 434 ant_t *js, ant_value_t receiver, 435 const char *name, ant_value_t *args, int nargs, bool *missing 436) { 437 ant_value_t fn = js_getprop_fallback(js, receiver, name); 438 if (missing) *missing = !is_callable(fn); 439 if (!is_callable(fn)) return js_mkundef(); 440 return sv_vm_call(js->vm, js, fn, receiver, args, nargs, NULL, false); 441} 442 443static ant_value_t make_async_wrap_iter(ant_t *js, ant_value_t source, int kind, ant_value_t cb) { 444 ant_value_t iter = js_mkobj(js); 445 js_set_proto_init(iter, g_async_wrap_iter_proto); 446 js_set_slot_wb(js, iter, SLOT_DATA, source); 447 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, 0))); 448 js_set_slot_wb(js, iter, SLOT_CTOR, cb); 449 js_set_slot(iter, SLOT_ENTRIES, js_mkundef()); 450 return iter; 451} 452 453static ant_value_t async_wrap_advance( 454 ant_t *js, 455 ant_value_t iter, 456 ant_value_t promise 457); 458 459static ant_value_t async_wrap_handle_step( 460 ant_t *js, 461 ant_value_t iter, 462 ant_value_t promise, 463 ant_value_t step 464); 465 466static ant_value_t async_wrap_handle_callback_result( 467 ant_t *js, 468 ant_value_t iter, 469 ant_value_t promise, 470 uint32_t kind, 471 ant_value_t value, 472 ant_value_t result 473); 474 475static ant_value_t async_wrap_on_step(ant_t *js, ant_value_t *args, int nargs) { 476 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 477 ant_value_t iter = js_get(js, state, "iter"); 478 ant_value_t promise = js_get(js, state, "promise"); 479 ant_value_t step = nargs > 0 ? args[0] : js_mkundef(); 480 return async_wrap_handle_step(js, iter, promise, step); 481} 482 483static ant_value_t async_wrap_on_reject(ant_t *js, ant_value_t *args, int nargs) { 484 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 485 ant_value_t promise = js_get(js, state, "promise"); 486 js_reject_promise(js, promise, nargs > 0 ? args[0] : js_mkundef()); 487 return js_mkundef(); 488} 489 490static ant_value_t async_wrap_on_callback(ant_t *js, ant_value_t *args, int nargs) { 491 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 492 ant_value_t iter = js_get(js, state, "iter"); 493 ant_value_t promise = js_get(js, state, "promise"); 494 uint32_t kind = (uint32_t)js_getnum(js_get(js, state, "kind")); 495 ant_value_t value = js_get(js, state, "value"); 496 ant_value_t result = nargs > 0 ? args[0] : js_mkundef(); 497 return async_wrap_handle_callback_result(js, iter, promise, kind, value, result); 498} 499 500static ant_value_t async_wrap_on_sync_value(ant_t *js, ant_value_t *args, int nargs) { 501 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 502 ant_value_t promise = js_get(js, state, "promise"); 503 bool done = js_truthy(js, js_get(js, state, "done")); 504 ant_value_t value = nargs > 0 ? args[0] : js_mkundef(); 505 js_resolve_promise(js, promise, iter_result(js, value, done)); 506 return js_mkundef(); 507} 508 509static bool async_wrap_chain_step(ant_t *js, ant_value_t iter, ant_value_t promise, ant_value_t next_result) { 510 if (is_err(next_result)) { 511 js_reject_promise(js, promise, next_result); 512 return true; 513 } 514 515 if (vtype(next_result) != T_PROMISE) { 516 async_wrap_handle_step(js, iter, promise, next_result); 517 return true; 518 } 519 520 ant_value_t state = js_mkobj(js); 521 js_set(js, state, "iter", iter); 522 js_set(js, state, "promise", promise); 523 ant_value_t on_resolve = js_heavy_mkfun(js, async_wrap_on_step, state); 524 ant_value_t on_reject = js_heavy_mkfun(js, async_wrap_on_reject, state); 525 ant_value_t then_result = js_promise_then(js, next_result, on_resolve, on_reject); 526 promise_mark_handled(then_result); 527 return true; 528} 529 530static ant_value_t async_wrap_handle_inner_step( 531 ant_t *js, 532 ant_value_t iter, 533 ant_value_t promise, 534 ant_value_t step 535) { 536 if (!is_object_type(step)) { 537 js_reject_promise(js, promise, js_mkerr_typed(js, JS_ERR_TYPE, "iterator result is not an object")); 538 return js_mkundef(); 539 } 540 541 if (!js_truthy(js, js_getprop_fallback(js, step, "done"))) { 542 js_resolve_promise(js, promise, iter_result(js, js_getprop_fallback(js, step, "value"), false)); 543 return js_mkundef(); 544 } 545 546 js_set_slot(iter, SLOT_ENTRIES, js_mkundef()); 547 async_wrap_advance(js, iter, promise); 548 return js_mkundef(); 549} 550 551static ant_value_t async_wrap_on_inner_step(ant_t *js, ant_value_t *args, int nargs) { 552 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 553 ant_value_t iter = js_get(js, state, "iter"); 554 ant_value_t promise = js_get(js, state, "promise"); 555 ant_value_t step = nargs > 0 ? args[0] : js_mkundef(); 556 return async_wrap_handle_inner_step(js, iter, promise, step); 557} 558 559static ant_value_t async_wrap_advance_inner(ant_t *js, ant_value_t iter, ant_value_t promise) { 560 ant_value_t inner = js_get_slot(iter, SLOT_ENTRIES); 561 if (vtype(inner) == T_UNDEF || vtype(inner) == T_NULL) return async_wrap_advance(js, iter, promise); 562 563 bool missing = false; 564 ant_value_t next_result = async_iter_call_method(js, inner, "next", NULL, 0, &missing); 565 if (missing) { 566 js_set_slot(iter, SLOT_ENTRIES, js_mkundef()); 567 return async_wrap_advance(js, iter, promise); 568 } 569 570 if (is_err(next_result)) { 571 js_reject_promise(js, promise, next_result); 572 return js_mkundef(); 573 } 574 575 if (vtype(next_result) == T_PROMISE) { 576 ant_value_t state = js_mkobj(js); 577 js_set(js, state, "iter", iter); 578 js_set(js, state, "promise", promise); 579 ant_value_t on_resolve = js_heavy_mkfun(js, async_wrap_on_inner_step, state); 580 ant_value_t on_reject = js_heavy_mkfun(js, async_wrap_on_reject, state); 581 ant_value_t then_result = js_promise_then(js, next_result, on_resolve, on_reject); 582 promise_mark_handled(then_result); 583 return js_mkundef(); 584 } 585 586 return async_wrap_handle_inner_step(js, iter, promise, next_result); 587} 588 589static ant_value_t async_wrap_handle_step( 590 ant_t *js, 591 ant_value_t iter, 592 ant_value_t promise, 593 ant_value_t step 594) { 595 if (!is_object_type(step)) { 596 js_reject_promise(js, promise, js_mkerr_typed(js, JS_ERR_TYPE, "iterator result is not an object")); 597 return js_mkundef(); 598 } 599 600 bool done = js_truthy(js, js_getprop_fallback(js, step, "done")); 601 ant_value_t state_v = js_get_slot(iter, SLOT_ITER_STATE); 602 603 uint32_t state = (vtype(state_v) == T_NUM) ? (uint32_t)js_getnum(state_v) : 0; 604 uint32_t kind = ITER_STATE_KIND(state); 605 uint32_t count = ITER_STATE_INDEX(state); 606 ant_value_t value = js_getprop_fallback(js, step, "value"); 607 608 if (kind == WRAP_FROM_SYNC && vtype(value) == T_PROMISE) { 609 ant_value_t state_obj = js_mkobj(js); 610 js_set(js, state_obj, "promise", promise); 611 js_set(js, state_obj, "done", done ? js_true : js_false); 612 613 ant_value_t on_resolve = js_heavy_mkfun(js, async_wrap_on_sync_value, state_obj); 614 ant_value_t on_reject = js_heavy_mkfun(js, async_wrap_on_reject, state_obj); 615 ant_value_t then_result = js_promise_then(js, value, on_resolve, on_reject); 616 617 promise_mark_handled(then_result); 618 return js_mkundef(); 619 } 620 621 if (done) { 622 js_resolve_promise( 623 js, promise, 624 iter_result(js, kind == WRAP_FROM_SYNC ? value : js_mkundef(), true) 625 ); 626 return js_mkundef(); 627 } 628 629 ant_value_t cb = js_get_slot(iter, SLOT_CTOR); 630 631 switch (kind) { 632 case WRAP_MAP: { 633 ant_value_t mapped = call_indexed_callback(js, cb, value, (double)count); 634 if (is_err(mapped)) { 635 js_reject_promise(js, promise, mapped); 636 return js_mkundef(); 637 } 638 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, count + 1))); 639 return async_wrap_handle_callback_result(js, iter, promise, kind, value, mapped); 640 } 641 642 case WRAP_FILTER: { 643 ant_value_t test = call_indexed_callback(js, cb, value, (double)count); 644 if (is_err(test)) { 645 js_reject_promise(js, promise, test); 646 return js_mkundef(); 647 } 648 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, count + 1))); 649 return async_wrap_handle_callback_result(js, iter, promise, kind, value, test); 650 } 651 652 case WRAP_TAKE: 653 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, count + 1))); 654 js_resolve_promise(js, promise, iter_result(js, value, false)); 655 return js_mkundef(); 656 657 case WRAP_DROP: { 658 double limit = (vtype(cb) == T_NUM) ? js_getnum(cb) : 0; 659 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, count + 1))); 660 if ((double)(count + 1) <= limit) async_wrap_advance(js, iter, promise); 661 else js_resolve_promise(js, promise, iter_result(js, value, false)); 662 return js_mkundef(); 663 } 664 665 case WRAP_FLATMAP: { 666 ant_value_t mapped = call_indexed_callback(js, cb, value, (double)count); 667 if (is_err(mapped)) { 668 js_reject_promise(js, promise, mapped); 669 return js_mkundef(); 670 } 671 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, count + 1))); 672 return async_wrap_handle_callback_result(js, iter, promise, kind, value, mapped); 673 } 674 675 default: 676 js_resolve_promise(js, promise, iter_result(js, value, false)); 677 return js_mkundef(); 678 } 679} 680 681static ant_value_t async_wrap_handle_callback_result( 682 ant_t *js, 683 ant_value_t iter, 684 ant_value_t promise, 685 uint32_t kind, 686 ant_value_t value, 687 ant_value_t result 688) { 689 if (vtype(result) == T_PROMISE) { 690 ant_value_t state = js_mkobj(js); 691 js_set(js, state, "iter", iter); 692 js_set(js, state, "promise", promise); 693 js_set(js, state, "kind", js_mknum((double)kind)); 694 js_set(js, state, "value", value); 695 ant_value_t on_resolve = js_heavy_mkfun(js, async_wrap_on_callback, state); 696 ant_value_t on_reject = js_heavy_mkfun(js, async_wrap_on_reject, state); 697 ant_value_t then_result = js_promise_then(js, result, on_resolve, on_reject); 698 promise_mark_handled(then_result); 699 return js_mkundef(); 700 } 701 702 if (kind == WRAP_MAP) { 703 js_resolve_promise(js, promise, iter_result(js, result, false)); 704 return js_mkundef(); 705 } 706 707 if (kind == WRAP_FILTER) { 708 if (js_truthy(js, result)) js_resolve_promise(js, promise, iter_result(js, value, false)); 709 else async_wrap_advance(js, iter, promise); 710 return js_mkundef(); 711 } 712 713 if (kind == WRAP_FLATMAP) { 714 ant_value_t iter_fn = js_get_sym(js, result, get_asyncIterator_sym()); 715 if (!is_callable(iter_fn)) iter_fn = js_get_sym(js, result, get_iterator_sym()); 716 if (!is_callable(iter_fn)) { 717 js_resolve_promise(js, promise, iter_result(js, result, false)); 718 return js_mkundef(); 719 } 720 721 ant_value_t inner = sv_vm_call(js->vm, js, iter_fn, result, NULL, 0, NULL, false); 722 if (is_err(inner)) { 723 js_reject_promise(js, promise, inner); 724 return js_mkundef(); 725 } 726 js_set_slot_wb(js, iter, SLOT_ENTRIES, inner); 727 return async_wrap_advance_inner(js, iter, promise); 728 } 729 730 js_resolve_promise(js, promise, iter_result(js, result, false)); 731 return js_mkundef(); 732} 733 734static ant_value_t async_wrap_advance(ant_t *js, ant_value_t iter, ant_value_t promise) { 735 ant_value_t state_v = js_get_slot(iter, SLOT_ITER_STATE); 736 uint32_t state = (vtype(state_v) == T_NUM) ? (uint32_t)js_getnum(state_v) : 0; 737 uint32_t kind = ITER_STATE_KIND(state); 738 ant_value_t cb = js_get_slot(iter, SLOT_CTOR); 739 740 if (kind == WRAP_TAKE) { 741 double limit = (vtype(cb) == T_NUM) ? js_getnum(cb) : 0; 742 if ((double)ITER_STATE_INDEX(state) >= limit) { 743 js_resolve_promise(js, promise, iter_result(js, js_mkundef(), true)); 744 return js_mkundef(); 745 } 746 } 747 748 if (kind == WRAP_FLATMAP && vtype(js_get_slot(iter, SLOT_ENTRIES)) != T_UNDEF) 749 return async_wrap_advance_inner(js, iter, promise); 750 751 ant_value_t source = js_get_slot(iter, SLOT_DATA); 752 bool missing = false; 753 ant_value_t next_result = async_iter_call_method(js, source, "next", NULL, 0, &missing); 754 if (missing) js_reject_promise(js, promise, js_mkerr_typed(js, JS_ERR_TYPE, "object is not async iterable")); 755 else async_wrap_chain_step(js, iter, promise, next_result); 756 return js_mkundef(); 757} 758 759static ant_value_t async_wrap_next(ant_t *js, ant_value_t *args, int nargs) { 760 (void)args; (void)nargs; 761 ant_value_t promise = js_mkpromise(js); 762 async_wrap_advance(js, js->this_val, promise); 763 return promise; 764} 765 766static ant_value_t async_wrap_return(ant_t *js, ant_value_t *args, int nargs) { 767 ant_value_t source = js_get_slot(js->this_val, SLOT_DATA); 768 bool missing = false; 769 ant_value_t result = async_iter_call_method(js, source, "return", args, nargs, &missing); 770 if (missing) return fulfilled_promise(js, iter_result(js, nargs > 0 ? args[0] : js_mkundef(), true)); 771 ant_value_t state_v = js_get_slot(js->this_val, SLOT_ITER_STATE); 772 uint32_t state = (vtype(state_v) == T_NUM) ? (uint32_t)js_getnum(state_v) : 0; 773 if (ITER_STATE_KIND(state) == WRAP_FROM_SYNC) { 774 ant_value_t promise = js_mkpromise(js); 775 async_wrap_chain_step(js, js->this_val, promise, result); 776 return promise; 777 } 778 return promise_from_call_result(js, result); 779} 780 781static ant_value_t async_wrap_throw(ant_t *js, ant_value_t *args, int nargs) { 782 ant_value_t source = js_get_slot(js->this_val, SLOT_DATA); 783 bool missing = false; 784 ant_value_t result = async_iter_call_method(js, source, "throw", args, nargs, &missing); 785 if (missing) return rejected_promise(js, nargs > 0 ? args[0] : js_mkundef()); 786 ant_value_t state_v = js_get_slot(js->this_val, SLOT_ITER_STATE); 787 uint32_t state = (vtype(state_v) == T_NUM) ? (uint32_t)js_getnum(state_v) : 0; 788 if (ITER_STATE_KIND(state) == WRAP_FROM_SYNC) { 789 ant_value_t promise = js_mkpromise(js); 790 async_wrap_chain_step(js, js->this_val, promise, result); 791 return promise; 792 } 793 return promise_from_call_result(js, result); 794} 795 796static ant_value_t async_iter_from(ant_t *js, ant_value_t *args, int nargs) { 797 if (nargs < 1 || vtype(args[0]) == T_UNDEF || vtype(args[0]) == T_NULL) 798 return js_mkerr_typed(js, JS_ERR_TYPE, "AsyncIterator.from requires an object"); 799 800 ant_value_t obj = args[0]; 801 ant_value_t iter_fn = js_get_sym(js, obj, get_asyncIterator_sym()); 802 if (is_callable(iter_fn)) { 803 ant_value_t iterator = sv_vm_call(js->vm, js, iter_fn, obj, NULL, 0, NULL, false); 804 if (is_err(iterator)) return iterator; 805 return make_async_wrap_iter(js, iterator, WRAP_PASS, js_mkundef()); 806 } 807 808 iter_fn = js_get_sym(js, obj, get_iterator_sym()); 809 if (is_callable(iter_fn)) { 810 ant_value_t iterator = sv_vm_call(js->vm, js, iter_fn, obj, NULL, 0, NULL, false); 811 if (is_err(iterator)) return iterator; 812 return make_async_wrap_iter(js, iterator, WRAP_FROM_SYNC, js_mkundef()); 813 } 814 815 ant_value_t next = js_getprop_fallback(js, obj, "next"); 816 if (is_callable(next)) return make_async_wrap_iter(js, obj, WRAP_FROM_SYNC, js_mkundef()); 817 818 return js_mkerr_typed(js, JS_ERR_TYPE, "object is not async iterable"); 819} 820 821static ant_value_t get_async_source_iter(ant_t *js) { 822 ant_value_t self = js->this_val; 823 ant_value_t next = js_getprop_fallback(js, self, "next"); 824 if (is_callable(next)) return self; 825 826 ant_value_t iter_fn = js_get_sym(js, self, get_asyncIterator_sym()); 827 if (!is_callable(iter_fn)) return js_mkerr_typed(js, JS_ERR_TYPE, "object is not async iterable"); 828 829 return sv_vm_call(js->vm, js, iter_fn, self, NULL, 0, NULL, false); 830} 831 832static ant_value_t async_iter_make_helper(ant_t *js, int kind, ant_value_t cb) { 833 ant_value_t source = get_async_source_iter(js); 834 if (is_err(source)) return source; 835 return make_async_wrap_iter(js, source, kind, cb); 836} 837 838static ant_value_t async_iter_make_callable_helper( 839 ant_t *js, 840 ant_value_t *args, 841 int nargs, 842 int kind, 843 const char *method 844) { 845 if (nargs < 1 || !is_callable(args[0])) 846 return js_mkerr_typed(js, JS_ERR_TYPE, "%s requires a callable", method); 847 return async_iter_make_helper(js, kind, args[0]); 848} 849 850static ant_value_t async_iter_make_count_helper( 851 ant_t *js, 852 ant_value_t *args, 853 int nargs, 854 int kind, 855 const char *method 856) { 857 double limit = (nargs >= 1 && vtype(args[0]) == T_NUM) ? js_getnum(args[0]) : 0; 858 if (limit < 0) return js_mkerr_typed(js, JS_ERR_TYPE, "%s requires a non-negative number", method); 859 return async_iter_make_helper(js, kind, js_mknum(limit)); 860} 861 862static ant_value_t async_iter_map(ant_t *js, ant_value_t *args, int nargs) { 863 return async_iter_make_callable_helper(js, args, nargs, WRAP_MAP, "AsyncIterator.prototype.map"); 864} 865 866static ant_value_t async_iter_filter(ant_t *js, ant_value_t *args, int nargs) { 867 return async_iter_make_callable_helper(js, args, nargs, WRAP_FILTER, "AsyncIterator.prototype.filter"); 868} 869 870static ant_value_t async_iter_take(ant_t *js, ant_value_t *args, int nargs) { 871 return async_iter_make_count_helper(js, args, nargs, WRAP_TAKE, "AsyncIterator.prototype.take"); 872} 873 874static ant_value_t async_iter_drop(ant_t *js, ant_value_t *args, int nargs) { 875 return async_iter_make_count_helper(js, args, nargs, WRAP_DROP, "AsyncIterator.prototype.drop"); 876} 877 878static ant_value_t async_iter_flatMap(ant_t *js, ant_value_t *args, int nargs) { 879 return async_iter_make_callable_helper(js, args, nargs, WRAP_FLATMAP, "AsyncIterator.prototype.flatMap"); 880} 881 882static ant_value_t async_terminal_advance(ant_t *js, ant_value_t state); 883static ant_value_t async_terminal_finish_callback(ant_t *js, ant_value_t state, ant_value_t result); 884static void async_terminal_close_and_reject(ant_t *js, ant_value_t state, ant_value_t reason); 885 886static void async_terminal_state_finalize(ant_t *js, ant_object_t *obj) { 887 free(obj->native.ptr); 888 obj->native.ptr = NULL; 889} 890 891static inline async_terminal_state_t *async_terminal_state(ant_value_t state) { 892 if (!js_check_native_tag(state, ASYNC_TERMINAL_STATE_TAG)) return NULL; 893 return (async_terminal_state_t *)js_get_native_ptr(state); 894} 895 896static inline int async_terminal_mode(ant_value_t state) { 897 async_terminal_state_t *st = async_terminal_state(state); 898 return st ? st->mode : ASYNC_TERM_TOARRAY; 899} 900 901static inline double async_terminal_index(ant_value_t state) { 902 async_terminal_state_t *st = async_terminal_state(state); 903 return st ? st->index : 0; 904} 905 906static inline bool async_terminal_has_acc(ant_value_t state) { 907 async_terminal_state_t *st = async_terminal_state(state); 908 return st && st->has_acc; 909} 910 911static ant_value_t async_terminal_on_reject(ant_t *js, ant_value_t *args, int nargs) { 912 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 913 ant_value_t promise = js_get_slot(state, SLOT_CTOR); 914 js_reject_promise(js, promise, nargs > 0 ? args[0] : js_mkundef()); 915 return js_mkundef(); 916} 917 918static ant_value_t async_terminal_on_callback_reject(ant_t *js, ant_value_t *args, int nargs) { 919 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 920 async_terminal_close_and_reject(js, state, nargs > 0 ? args[0] : js_mkundef()); 921 return js_mkundef(); 922} 923 924static ant_value_t async_terminal_on_callback(ant_t *js, ant_value_t *args, int nargs) { 925 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 926 ant_value_t result = nargs > 0 ? args[0] : js_mkundef(); 927 return async_terminal_finish_callback(js, state, result); 928} 929 930static ant_value_t async_terminal_on_close(ant_t *js, ant_value_t *args, int nargs) { 931 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 932 ant_value_t promise = js_get_slot(state, SLOT_CTOR); 933 js_resolve_promise(js, promise, js_get_slot(state, SLOT_AUX)); 934 return js_mkundef(); 935} 936 937static ant_value_t async_terminal_on_close_reject(ant_t *js, ant_value_t *args, int nargs) { 938 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 939 ant_value_t promise = js_get_slot(state, SLOT_CTOR); 940 js_reject_promise(js, promise, js_get_slot(state, SLOT_AUX)); 941 return js_mkundef(); 942} 943 944static void async_terminal_close_and_resolve(ant_t *js, ant_value_t state, ant_value_t value) { 945 ant_value_t promise = js_get_slot(state, SLOT_CTOR); 946 ant_value_t iter = js_get_slot(state, SLOT_DATA); 947 js_set_slot_wb(js, state, SLOT_AUX, value); 948 949 bool missing = false; 950 ant_value_t result = async_iter_call_method(js, iter, "return", NULL, 0, &missing); 951 if (missing) { 952 js_resolve_promise(js, promise, value); 953 return; 954 } 955 956 if (is_err(result)) { 957 js_reject_promise(js, promise, result); 958 return; 959 } 960 961 if (vtype(result) == T_PROMISE) { 962 ant_value_t on_resolve = js_heavy_mkfun(js, async_terminal_on_close, state); 963 ant_value_t on_reject = js_heavy_mkfun(js, async_terminal_on_reject, state); 964 ant_value_t then_result = js_promise_then(js, result, on_resolve, on_reject); 965 promise_mark_handled(then_result); 966 return; 967 } 968 969 js_resolve_promise(js, promise, value); 970} 971 972static void async_terminal_close_and_reject(ant_t *js, ant_value_t state, ant_value_t reason) { 973 ant_value_t promise = js_get_slot(state, SLOT_CTOR); 974 ant_value_t iter = js_get_slot(state, SLOT_DATA); 975 js_set_slot_wb(js, state, SLOT_AUX, reason); 976 977 bool missing = false; 978 ant_value_t result = async_iter_call_method(js, iter, "return", NULL, 0, &missing); 979 if (missing) { 980 js_reject_promise(js, promise, reason); 981 return; 982 } 983 984 if (is_err(result)) { 985 js_reject_promise(js, promise, result); 986 return; 987 } 988 989 if (vtype(result) == T_PROMISE) { 990 ant_value_t on_resolve = js_heavy_mkfun(js, async_terminal_on_close_reject, state); 991 ant_value_t on_reject = js_heavy_mkfun(js, async_terminal_on_reject, state); 992 ant_value_t then_result = js_promise_then(js, result, on_resolve, on_reject); 993 promise_mark_handled(then_result); 994 return; 995 } 996 997 js_reject_promise(js, promise, reason); 998} 999 1000static bool async_terminal_apply_callback_result(ant_t *js, ant_value_t state, ant_value_t result) { 1001 int mode = async_terminal_mode(state); 1002 1003 if (mode == ASYNC_TERM_REDUCE) { 1004 js_set_slot_wb(js, state, SLOT_SET, result); 1005 async_terminal_state_t *st = async_terminal_state(state); 1006 if (st) st->has_acc = true; 1007 return true; 1008 } 1009 1010 switch (mode) { 1011 case ASYNC_TERM_EVERY: 1012 if (!js_truthy(js, result)) { 1013 async_terminal_close_and_resolve(js, state, js_false); 1014 return false; 1015 } 1016 return true; 1017 case ASYNC_TERM_SOME: 1018 if (js_truthy(js, result)) { 1019 async_terminal_close_and_resolve(js, state, js_true); 1020 return false; 1021 } 1022 return true; 1023 case ASYNC_TERM_FIND: 1024 if (js_truthy(js, result)) { 1025 async_terminal_close_and_resolve(js, state, js_get_slot(state, SLOT_AUX)); 1026 return false; 1027 } 1028 return true; 1029 default: 1030 return true; 1031 } 1032} 1033 1034static bool async_terminal_handle_step(ant_t *js, ant_value_t state, ant_value_t step) { 1035 ant_value_t promise = js_get_slot(state, SLOT_CTOR); 1036 1037 if (!is_object_type(step)) { 1038 js_reject_promise(js, promise, js_mkerr_typed(js, JS_ERR_TYPE, "iterator result is not an object")); 1039 return false; 1040 } 1041 1042 int mode = async_terminal_mode(state); 1043 ant_value_t done = js_getprop_fallback(js, step, "done"); 1044 ant_value_t value = js_getprop_fallback(js, step, "value"); 1045 1046 if (js_truthy(js, done)) { 1047 switch (mode) { 1048 case ASYNC_TERM_EVERY: js_resolve_promise(js, promise, js_true); break; 1049 case ASYNC_TERM_SOME: js_resolve_promise(js, promise, js_false); break; 1050 1051 case ASYNC_TERM_FIND: js_resolve_promise(js, promise, js_mkundef()); break; 1052 case ASYNC_TERM_FOREACH: js_resolve_promise(js, promise, js_mkundef()); break; 1053 1054 case ASYNC_TERM_REDUCE: 1055 if (!async_terminal_has_acc(state)) { 1056 js_reject_promise(js, promise, js_mkerr_typed(js, JS_ERR_TYPE, "reduce of empty iterator with no initial value")); 1057 } else js_resolve_promise(js, promise, js_get_slot(state, SLOT_SET)); 1058 break; 1059 1060 default: 1061 js_resolve_promise(js, promise, js_get_slot(state, SLOT_ENTRIES)); 1062 break; 1063 } 1064 1065 return false; 1066 } 1067 1068 double index = async_terminal_index(state); 1069 async_terminal_state_t *st = async_terminal_state(state); 1070 if (st) st->index = index + 1; 1071 1072 if (mode == ASYNC_TERM_TOARRAY) { 1073 js_arr_push(js, js_get_slot(state, SLOT_ENTRIES), value); 1074 return true; 1075 } 1076 1077 ant_value_t fn = js_get_slot(state, SLOT_MAP); 1078 if (!is_callable(fn)) { 1079 js_reject_promise(js, promise, js_mkerr_typed(js, JS_ERR_TYPE, "callback is not callable")); 1080 return false; 1081 } 1082 1083 if (mode == ASYNC_TERM_REDUCE) { 1084 if (!async_terminal_has_acc(state)) { 1085 js_set_slot_wb(js, state, SLOT_SET, value); 1086 if (st) st->has_acc = true; 1087 return true; 1088 } 1089 1090 ant_value_t call_args[3] = { js_get_slot(state, SLOT_SET), value, js_mknum(index) }; 1091 ant_value_t next_acc = sv_vm_call(js->vm, js, fn, js_mkundef(), call_args, 3, NULL, false); 1092 if (is_err(next_acc)) { 1093 async_terminal_close_and_reject(js, state, next_acc); 1094 return false; 1095 } 1096 1097 if (vtype(next_acc) == T_PROMISE) { 1098 ant_value_t on_resolve = js_heavy_mkfun(js, async_terminal_on_callback, state); 1099 ant_value_t on_reject = js_heavy_mkfun(js, async_terminal_on_callback_reject, state); 1100 ant_value_t then_result = js_promise_then(js, next_acc, on_resolve, on_reject); 1101 promise_mark_handled(then_result); 1102 return false; 1103 } 1104 return async_terminal_apply_callback_result(js, state, next_acc); 1105 } 1106 1107 ant_value_t result = call_indexed_callback(js, fn, value, (double)index); 1108 if (is_err(result)) { 1109 async_terminal_close_and_reject(js, state, result); 1110 return false; 1111 } 1112 1113 js_set_slot_wb(js, state, SLOT_AUX, value); 1114 if (vtype(result) == T_PROMISE) { 1115 ant_value_t on_resolve = js_heavy_mkfun(js, async_terminal_on_callback, state); 1116 ant_value_t on_reject = js_heavy_mkfun(js, async_terminal_on_callback_reject, state); 1117 ant_value_t then_result = js_promise_then(js, result, on_resolve, on_reject); 1118 promise_mark_handled(then_result); 1119 return false; 1120 } 1121 1122 return async_terminal_apply_callback_result(js, state, result); 1123} 1124 1125static ant_value_t async_terminal_on_step(ant_t *js, ant_value_t *args, int nargs) { 1126 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 1127 ant_value_t step = nargs > 0 ? args[0] : js_mkundef(); 1128 if (async_terminal_handle_step(js, state, step)) return async_terminal_advance(js, state); 1129 return js_mkundef(); 1130} 1131 1132static ant_value_t async_terminal_finish_callback( 1133 ant_t *js, 1134 ant_value_t state, 1135 ant_value_t result 1136) { 1137 if (vtype(result) == T_PROMISE) { 1138 ant_value_t on_resolve = js_heavy_mkfun(js, async_terminal_on_callback, state); 1139 ant_value_t on_reject = js_heavy_mkfun(js, async_terminal_on_callback_reject, state); 1140 ant_value_t then_result = js_promise_then(js, result, on_resolve, on_reject); 1141 promise_mark_handled(then_result); 1142 return js_mkundef(); 1143 } 1144 1145 if (async_terminal_apply_callback_result(js, state, result)) return async_terminal_advance(js, state); 1146 return js_mkundef(); 1147} 1148 1149static ant_value_t async_terminal_advance(ant_t *js, ant_value_t state) { 1150for (;;) { 1151 ant_value_t iter = js_get_slot(state, SLOT_DATA); 1152 ant_value_t promise = js_get_slot(state, SLOT_CTOR); 1153 bool missing = false; 1154 ant_value_t next_result = async_iter_call_method(js, iter, "next", NULL, 0, &missing); 1155 1156 if (missing) { 1157 js_reject_promise(js, promise, js_mkerr_typed(js, JS_ERR_TYPE, "object is not async iterable")); 1158 return js_mkundef(); 1159 } 1160 1161 if (is_err(next_result)) { 1162 js_reject_promise(js, promise, next_result); 1163 return js_mkundef(); 1164 } 1165 1166 if (vtype(next_result) == T_PROMISE) { 1167 ant_value_t on_resolve = js_heavy_mkfun(js, async_terminal_on_step, state); 1168 ant_value_t on_reject = js_heavy_mkfun(js, async_terminal_on_reject, state); 1169 ant_value_t then_result = js_promise_then(js, next_result, on_resolve, on_reject); 1170 promise_mark_handled(then_result); 1171 return js_mkundef(); 1172 } 1173 1174 if (!async_terminal_handle_step(js, state, next_result)) return js_mkundef(); 1175}} 1176 1177static ant_value_t async_iter_terminal(ant_t *js, ant_value_t *args, int nargs, int mode) { 1178 if (mode != ASYNC_TERM_TOARRAY && (nargs < 1 || !is_callable(args[0]))) 1179 return js_mkerr_typed(js, JS_ERR_TYPE, "AsyncIterator helper requires a callable"); 1180 1181 ant_value_t iter = get_async_source_iter(js); 1182 if (is_err(iter)) return rejected_promise(js, iter); 1183 1184 ant_value_t promise = js_mkpromise(js); 1185 ant_value_t state = js_mkobj(js); 1186 async_terminal_state_t *st = calloc(1, sizeof(*st)); 1187 1188 if (!st) { 1189 js_reject_promise(js, promise, js_mkerr(js, "out of memory")); 1190 return promise; 1191 } 1192 1193 st->mode = mode; 1194 st->index = 0; 1195 st->has_acc = (mode == ASYNC_TERM_REDUCE && nargs > 1); 1196 1197 js_set_native_tag(state, ASYNC_TERMINAL_STATE_TAG); 1198 js_set_native_ptr(state, st); 1199 js_set_finalizer(state, async_terminal_state_finalize); 1200 1201 js_set_slot_wb(js, state, SLOT_DATA, iter); 1202 js_set_slot_wb(js, state, SLOT_CTOR, promise); 1203 js_set_slot_wb(js, state, SLOT_MAP, mode == ASYNC_TERM_TOARRAY ? js_mkundef() : args[0]); 1204 js_set_slot_wb(js, state, SLOT_ENTRIES, js_mkarr(js)); 1205 js_set_slot_wb(js, state, SLOT_SET, (mode == ASYNC_TERM_REDUCE && nargs > 1) ? args[1] : js_mkundef()); 1206 js_set_slot(state, SLOT_AUX, js_mkundef()); 1207 1208 async_terminal_advance(js, state); 1209 return promise; 1210} 1211 1212static ant_value_t async_iter_every(ant_t *js, ant_value_t *args, int nargs) { 1213 return async_iter_terminal(js, args, nargs, ASYNC_TERM_EVERY); 1214} 1215 1216static ant_value_t async_iter_some(ant_t *js, ant_value_t *args, int nargs) { 1217 return async_iter_terminal(js, args, nargs, ASYNC_TERM_SOME); 1218} 1219 1220static ant_value_t async_iter_find(ant_t *js, ant_value_t *args, int nargs) { 1221 return async_iter_terminal(js, args, nargs, ASYNC_TERM_FIND); 1222} 1223 1224static ant_value_t async_iter_forEach(ant_t *js, ant_value_t *args, int nargs) { 1225 return async_iter_terminal(js, args, nargs, ASYNC_TERM_FOREACH); 1226} 1227 1228static ant_value_t async_iter_reduce(ant_t *js, ant_value_t *args, int nargs) { 1229 return async_iter_terminal(js, args, nargs, ASYNC_TERM_REDUCE); 1230} 1231 1232static ant_value_t async_iter_toArray(ant_t *js, ant_value_t *args, int nargs) { 1233 return async_iter_terminal(js, args, nargs, ASYNC_TERM_TOARRAY); 1234} 1235 1236void init_iterator_module(void) { 1237 ant_t *js = rt->js; 1238 ant_value_t g = js_glob(js); 1239 ant_value_t iter_proto = js->sym.iterator_proto; 1240 1241 g_wrap_iter_proto = js_mkobj(js); 1242 js_set_proto_init(g_wrap_iter_proto, iter_proto); 1243 js_set(js, g_wrap_iter_proto, "next", js_mkfun(wrap_iter_next)); 1244 1245 js_set(js, iter_proto, "map", js_mkfun(iter_map)); 1246 js_set(js, iter_proto, "filter", js_mkfun(iter_filter)); 1247 js_set(js, iter_proto, "take", js_mkfun(iter_take)); 1248 js_set(js, iter_proto, "drop", js_mkfun(iter_drop)); 1249 js_set(js, iter_proto, "flatMap", js_mkfun(iter_flatMap)); 1250 js_set(js, iter_proto, "every", js_mkfun(iter_every)); 1251 js_set(js, iter_proto, "some", js_mkfun(iter_some)); 1252 js_set(js, iter_proto, "find", js_mkfun(iter_find)); 1253 js_set(js, iter_proto, "forEach", js_mkfun(iter_forEach)); 1254 js_set(js, iter_proto, "reduce", js_mkfun(iter_reduce)); 1255 js_set(js, iter_proto, "toArray", js_mkfun(iter_toArray)); 1256 js_set_sym(js, iter_proto, get_toStringTag_sym(), js_mkstr(js, "Iterator", 8)); 1257 1258 ant_value_t ctor_obj = js_mkobj(js); 1259 js_set_slot(ctor_obj, SLOT_CFUNC, js_mkfun(iter_ctor)); 1260 js_mkprop_fast(js, ctor_obj, "prototype", 9, iter_proto); 1261 js_mkprop_fast(js, ctor_obj, "name", 4, js_mkstr(js, "Iterator", 8)); 1262 js_set_descriptor(js, ctor_obj, "name", 4, 0); 1263 1264 ant_value_t ctor = js_obj_to_func(ctor_obj); 1265 js_set(js, ctor, "from", js_mkfun(iter_from)); 1266 js_set(js, iter_proto, "constructor", ctor); 1267 js_set(js, g, "Iterator", ctor); 1268 1269 ant_value_t async_iter_proto = js_mkobj(js); 1270 js->sym.async_iterator_proto = async_iter_proto; 1271 js_set_proto_init(async_iter_proto, js->sym.object_proto); 1272 js_set_sym(js, async_iter_proto, get_asyncIterator_sym(), js_mkfun(sym_this_cb)); 1273 js_set_sym(js, async_iter_proto, get_toStringTag_sym(), js_mkstr(js, "AsyncIterator", 13)); 1274 1275 ant_value_t async_ctor_obj = js_mkobj(js); 1276 js_set_slot(async_ctor_obj, SLOT_CFUNC, js_mkfun(async_iter_ctor)); 1277 js_mkprop_fast(js, async_ctor_obj, "prototype", 9, async_iter_proto); 1278 js_mkprop_fast(js, async_ctor_obj, "name", 4, js_mkstr(js, "AsyncIterator", 13)); 1279 js_set_descriptor(js, async_ctor_obj, "name", 4, 0); 1280 1281 ant_value_t async_ctor = js_obj_to_func(async_ctor_obj); 1282 js_set(js, async_iter_proto, "constructor", async_ctor); 1283 js_set(js, g, "AsyncIterator", async_ctor); 1284 1285 g_async_wrap_iter_proto = js_mkobj(js); 1286 js_set_proto_init(g_async_wrap_iter_proto, async_iter_proto); 1287 js_set(js, g_async_wrap_iter_proto, "next", js_mkfun(async_wrap_next)); 1288 js_set(js, g_async_wrap_iter_proto, "return", js_mkfun(async_wrap_return)); 1289 js_set(js, g_async_wrap_iter_proto, "throw", js_mkfun(async_wrap_throw)); 1290} 1291 1292void init_async_iterator_helpers(void) { 1293 ant_t *js = rt->js; 1294 ant_value_t g = js_glob(js); 1295 1296 ant_value_t ctor = js_get(js, g, "AsyncIterator"); 1297 ant_value_t proto = js->sym.async_iterator_proto; 1298 1299 js_set(js, ctor, "from", js_mkfun(async_iter_from)); 1300 js_set(js, proto, "map", js_mkfun(async_iter_map)); 1301 js_set(js, proto, "filter", js_mkfun(async_iter_filter)); 1302 js_set(js, proto, "take", js_mkfun(async_iter_take)); 1303 js_set(js, proto, "drop", js_mkfun(async_iter_drop)); 1304 js_set(js, proto, "flatMap", js_mkfun(async_iter_flatMap)); 1305 js_set(js, proto, "every", js_mkfun(async_iter_every)); 1306 js_set(js, proto, "some", js_mkfun(async_iter_some)); 1307 js_set(js, proto, "find", js_mkfun(async_iter_find)); 1308 js_set(js, proto, "forEach", js_mkfun(async_iter_forEach)); 1309 js_set(js, proto, "reduce", js_mkfun(async_iter_reduce)); 1310 js_set(js, proto, "toArray", js_mkfun(async_iter_toArray)); 1311}