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.

add iterable support to typed array constructor

+140 -22
+27
examples/demo/pi.js
··· 1 + const iterations = 1_000_000; 2 + 3 + function calculatePiLeibniz() { 4 + let pi = 0; 5 + let denom = 1; 6 + 7 + const limit = iterations - (iterations % 4); 8 + for (let i = 0; i < limit; i += 4) { 9 + pi += 1 / denom - 1 / (denom + 2) + 1 / (denom + 4) - 1 / (denom + 6); 10 + denom += 8; 11 + } 12 + 13 + let sign = 1; 14 + for (let i = limit; i < iterations; i++) { 15 + pi += sign / denom; 16 + sign = -sign; 17 + denom += 2; 18 + } 19 + return pi * 4; 20 + } 21 + 22 + const start = performance.now(); 23 + const result = calculatePiLeibniz(); 24 + const end = performance.now(); 25 + 26 + console.log(`Pi (${iterations}) โ‰ˆ ${result}`); 27 + console.log(`Time: ${(end - start).toFixed(2)} ms`);
+1
include/ant.h
··· 77 77 78 78 jsval_t js_getcurrentfunc(struct js *); 79 79 jsval_t js_get(struct js *, jsval_t, const char *); 80 + bool js_iter(struct js *js, jsval_t iterable, bool (*callback)(struct js *js, jsval_t value, void *udata), void *udata); 80 81 81 82 uint64_t js_sym_id(jsval_t sym); 82 83 const char *js_sym_desc(struct js *js, jsval_t sym);
+69 -16
src/ant.c
··· 886 886 [T_OBJ] = &&l_true, 887 887 [T_FUNC] = &&l_true, 888 888 [T_ARR] = &&l_true, 889 + [T_SYMBOL] = &&l_true, 889 890 [T_BOOL] = &&l_bool, 890 891 [T_STR] = &&l_str, 891 892 [T_BIGINT] = &&l_bigint, ··· 2561 2562 2562 2563 case T_CFUNC: return ANT_COPY(buf, len, "[native code]"); 2563 2564 case T_FFI: return ANT_COPY(buf, len, "[native code (ffi)]"); 2565 + 2566 + case T_SYMBOL: { 2567 + const char *desc = js_sym_desc(js, value); 2568 + if (desc) return (size_t) snprintf(buf, len, "Symbol(%s)", desc); 2569 + return ANT_COPY(buf, len, "Symbol()"); 2570 + } 2564 2571 2565 2572 case T_PROP: return (size_t) snprintf(buf, len, "PROP@%lu", (unsigned long) vdata(value)); 2566 2573 default: return (size_t) snprintf(buf, len, "VTYPE%d", vtype(value)); ··· 6995 7002 6996 7003 L_TOK_POSTINC: 6997 7004 L_TOK_POSTDEC: { 6998 - if (vtype(lhs) != T_PROP) 7005 + uint8_t lhs_type = vtype(lhs); 7006 + if (lhs_type != T_PROP && lhs_type != T_PROPREF) 6999 7007 return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid left-hand side expression in postfix operation"); 7000 7008 do_assign_op(js, op == TOK_POSTINC ? TOK_PLUS_ASSIGN : TOK_MINUS_ASSIGN, lhs, tov(1)); 7001 7009 return l; ··· 10201 10209 return js_mkundef(); 10202 10210 } 10203 10211 10204 - static jsval_t for_of_iter_object(struct js *js, for_iter_ctx_t *ctx, jsval_t iterable) { 10212 + typedef enum { ITER_CONTINUE, ITER_BREAK, ITER_ERROR } iter_action_t; 10213 + typedef iter_action_t (*iter_callback_t)(struct js *js, jsval_t value, void *ctx, jsval_t *out); 10214 + 10215 + static jsval_t iter_foreach(struct js *js, jsval_t iterable, iter_callback_t cb, void *ctx) { 10205 10216 const char *iter_key = get_iterator_sym_key(); 10206 10217 jsoff_t iter_prop = iter_key ? lkp_proto(js, iterable, iter_key, strlen(iter_key)) : 0; 10207 - if (iter_prop == 0) return js_mkerr(js, "for-of requires iterable"); 10218 + if (iter_prop == 0) return js_mkerr(js, "not iterable"); 10208 10219 10209 10220 js_parse_state_t saved_state; 10210 10221 JS_SAVE_STATE(js, saved_state); ··· 10219 10230 10220 10231 if (is_err(iterator)) return iterator; 10221 10232 10233 + jsval_t out = js_mkundef(); 10222 10234 while (true) { 10223 10235 jsoff_t next_off = lkp_proto(js, iterator, "next", 4); 10224 10236 if (next_off == 0) return js_mkerr(js, "iterator.next is not a function"); ··· 10242 10254 jsoff_t value_off = lkp(js, result, "value", 5); 10243 10255 jsval_t value = value_off ? loadval(js, value_off + sizeof(jsoff_t) * 2) : js_mkundef(); 10244 10256 10245 - jsval_t err = for_iter_bind_var(js, ctx, value); 10246 - if (is_err(err)) return err; 10247 - 10248 - jsval_t v = for_iter_exec_body(js, ctx); 10249 - if (is_err(v)) return v; 10250 - if (for_iter_handle_continue(js, ctx)) break; 10251 - if (js->flags & F_BREAK) break; 10252 - if (js->flags & F_RETURN) return v; 10257 + iter_action_t action = cb(js, value, ctx, &out); 10258 + if (action == ITER_BREAK) break; 10259 + if (action == ITER_ERROR) return out; 10253 10260 } 10254 10261 10255 - return js_mkundef(); 10262 + return out; 10263 + } 10264 + 10265 + static iter_action_t for_of_iter_cb(struct js *js, jsval_t value, void *ctx, jsval_t *out) { 10266 + for_iter_ctx_t *fctx = (for_iter_ctx_t *)ctx; 10267 + 10268 + jsval_t err = for_iter_bind_var(js, fctx, value); 10269 + if (is_err(err)) { *out = err; return ITER_ERROR; } 10270 + 10271 + jsval_t v = for_iter_exec_body(js, fctx); 10272 + if (is_err(v)) { *out = v; return ITER_ERROR; } 10273 + if (for_iter_handle_continue(js, fctx)) return ITER_BREAK; 10274 + if (js->flags & F_BREAK) return ITER_BREAK; 10275 + if (js->flags & F_RETURN) { *out = v; return ITER_BREAK; } 10276 + 10277 + return ITER_CONTINUE; 10278 + } 10279 + 10280 + static jsval_t for_of_iter_object(struct js *js, for_iter_ctx_t *ctx, jsval_t iterable) { 10281 + jsval_t result = iter_foreach(js, iterable, for_of_iter_cb, ctx); 10282 + if (is_err(result) && strcmp(js->errmsg, "not iterable") == 0) { 10283 + return js_mkerr(js, "for-of requires iterable"); 10284 + } 10285 + return result; 10256 10286 } 10257 10287 10258 10288 static jsval_t js_for(struct js *js) { ··· 10274 10304 10275 10305 bool is_for_in = false; 10276 10306 bool is_for_of = false; 10277 - jsoff_t var_name_off = 0, var_name_len = 0; 10278 - bool is_const_var = false; 10307 + 10279 10308 bool is_var_decl = false; 10309 + bool is_const_var = false; 10280 10310 bool is_let_loop = false; 10281 - jsoff_t let_var_off = 0, let_var_len = 0; 10311 + 10312 + jsoff_t var_name_off = 0; 10313 + jsoff_t var_name_len = 0; 10314 + jsoff_t let_var_off = 0; 10315 + jsoff_t let_var_len = 0; 10316 + 10282 10317 bool has_destructure = false; 10283 - jsoff_t destructure_off = 0, destructure_len = 0; 10318 + jsoff_t destructure_off = 0; 10319 + jsoff_t destructure_len = 0; 10284 10320 10285 10321 if (next(js) == TOK_LET || next(js) == TOK_CONST || next(js) == TOK_VAR) { 10286 10322 if (js->tok == TOK_VAR) { ··· 21694 21730 } 21695 21731 21696 21732 return off == 0 ? js_mkundef() : resolveprop(js, mkval(T_PROP, off)); 21733 + } 21734 + 21735 + typedef struct { 21736 + bool (*callback)(struct js *js, jsval_t value, void *udata); 21737 + void *udata; 21738 + } js_iter_ctx_t; 21739 + 21740 + static iter_action_t js_iter_cb(struct js *js, jsval_t value, void *ctx, jsval_t *out) { 21741 + (void)out; 21742 + js_iter_ctx_t *ictx = (js_iter_ctx_t *)ctx; 21743 + return ictx->callback(js, value, ictx->udata) ? ITER_CONTINUE : ITER_BREAK; 21744 + } 21745 + 21746 + bool js_iter(struct js *js, jsval_t iterable, bool (*callback)(struct js *js, jsval_t value, void *udata), void *udata) { 21747 + js_iter_ctx_t ctx = { .callback = callback, .udata = udata }; 21748 + jsval_t result = iter_foreach(js, iterable, js_iter_cb, &ctx); 21749 + return !is_err(result); 21697 21750 } 21698 21751 21699 21752 char *js_getstr(struct js *js, jsval_t value, size_t *len) {
+43 -6
src/modules/buffer.c
··· 359 359 return create_typed_array_with_buffer(js, type, buffer, byte_offset, length, type_name, ab_obj); 360 360 } 361 361 362 + typedef struct { 363 + jsval_t *values; 364 + size_t length; 365 + size_t capacity; 366 + } iter_collect_ctx_t; 367 + 368 + static bool iter_collect_callback(struct js *js, jsval_t value, void *udata) { 369 + (void)js; 370 + iter_collect_ctx_t *ctx = (iter_collect_ctx_t *)udata; 371 + if (ctx->length >= ctx->capacity) { 372 + ctx->capacity *= 2; 373 + jsval_t *new_values = realloc(ctx->values, ctx->capacity * sizeof(jsval_t)); 374 + if (!new_values) return false; 375 + ctx->values = new_values; 376 + } 377 + ctx->values[ctx->length++] = value; 378 + return true; 379 + } 380 + 362 381 static jsval_t js_typedarray_constructor(struct js *js, jsval_t *args, int nargs, TypedArrayType type, const char *type_name) { 363 382 if (nargs == 0) { 364 383 ArrayBufferData *buffer = create_array_buffer_data(0); ··· 396 415 int arg_type = js_type(args[0]); 397 416 if (arg_type == JS_OBJ) { 398 417 jsval_t len_val = js_get(js, args[0], "length"); 399 - if (js_type(len_val) == JS_NUM) { 400 - size_t length = (size_t)js_getnum(len_val); 418 + size_t length = 0; jsval_t *values = NULL; 419 + bool is_iterable = false; 420 + 421 + if (js_type(len_val) == JS_NUM) length = (size_t)js_getnum(len_val); else { 422 + iter_collect_ctx_t ctx = { .values = NULL, .length = 0, .capacity = 16 }; 423 + ctx.values = malloc(ctx.capacity * sizeof(jsval_t)); 424 + if (!ctx.values) return js_mkerr(js, "Failed to allocate memory"); 425 + is_iterable = js_iter(js, args[0], iter_collect_callback, &ctx); 426 + 427 + if (is_iterable) { 428 + values = ctx.values; 429 + length = ctx.length; 430 + } else free(ctx.values); 431 + } 432 + 433 + if (length > 0 || is_iterable || js_type(len_val) == JS_NUM) { 401 434 size_t element_size = get_element_size(type); 402 435 ArrayBufferData *buffer = create_array_buffer_data(length * element_size); 403 - if (!buffer) return js_mkerr(js, "Failed to allocate buffer"); 436 + if (!buffer) { if (values) free(values); return js_mkerr(js, "Failed to allocate buffer"); } 404 437 405 438 jsval_t result = create_typed_array(js, type, buffer, 0, length, type_name); 406 439 uint8_t *data = buffer->data; ··· 411 444 }; 412 445 413 446 for (size_t i = 0; i < length; i++) { 414 - char idx_str[16]; 415 - snprintf(idx_str, sizeof(idx_str), "%zu", i); 416 - jsval_t elem = js_get(js, args[0], idx_str); 447 + jsval_t elem; 448 + if (values) elem = values[i]; else { 449 + char idx_str[16]; 450 + snprintf(idx_str, sizeof(idx_str), "%zu", i); 451 + elem = js_get(js, args[0], idx_str); 452 + } 417 453 double val = js_type(elem) == JS_NUM ? js_getnum(elem) : 0; 418 454 419 455 if (type > TYPED_ARRAY_BIGUINT64) goto W_DONE; ··· 430 466 W_NEXT:; 431 467 } 432 468 W_DONE: 469 + if (values) free(values); 433 470 return result; 434 471 } 435 472 }