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.

improve spread operator support for arrays, strings, and dynamic arguments

+109 -56
+100 -53
src/ant.c
··· 6599 6599 } 6600 6600 } 6601 6601 6602 + typedef enum { ITER_CONTINUE, ITER_BREAK, ITER_ERROR } iter_action_t; 6603 + typedef iter_action_t (*iter_callback_t)(struct js *js, jsval_t value, void *ctx, jsval_t *out); 6604 + 6605 + static jsval_t iter_foreach(struct js *js, jsval_t iterable, iter_callback_t cb, void *ctx); 6606 + typedef struct { UT_array *args; } spread_utarray_ctx_t; 6607 + 6608 + static iter_action_t spread_utarray_iter_cb(struct js *js, jsval_t value, void *ctx, jsval_t *out) { 6609 + spread_utarray_ctx_t *sctx = (spread_utarray_ctx_t *)ctx; 6610 + utarray_push_back(sctx->args, &value); 6611 + return ITER_CONTINUE; 6612 + } 6613 + 6614 + static jsval_t append_spread_to_utarray(struct js *js, UT_array *args, jsval_t spread_value) { 6615 + spread_utarray_ctx_t ctx = { .args = args }; 6616 + return iter_foreach(js, spread_value, spread_utarray_iter_cb, &ctx); 6617 + } 6618 + 6619 + typedef struct { 6620 + jsval_t **args; 6621 + int *argc; 6622 + int *args_cap; 6623 + bool *args_on_heap; 6624 + } spread_dynargs_ctx_t; 6625 + 6626 + static void spread_dynargs_push(spread_dynargs_ctx_t *ctx, jsval_t value) { 6627 + if (*ctx->argc >= *ctx->args_cap) { 6628 + int new_cap = *ctx->args_cap * 2; 6629 + jsval_t *new_args = try_oom((size_t)new_cap * sizeof(jsval_t)); 6630 + memcpy(new_args, *ctx->args, (size_t)*ctx->argc * sizeof(jsval_t)); 6631 + if (*ctx->args_on_heap) free(*ctx->args); 6632 + *ctx->args = new_args; 6633 + *ctx->args_cap = new_cap; 6634 + *ctx->args_on_heap = true; 6635 + } 6636 + (*ctx->args)[(*ctx->argc)++] = value; 6637 + } 6638 + 6639 + static iter_action_t spread_dynargs_iter_cb(struct js *js, jsval_t value, void *ctx, jsval_t *out) { 6640 + spread_dynargs_ctx_t *sctx = (spread_dynargs_ctx_t *)ctx; 6641 + spread_dynargs_push(sctx, value); 6642 + return ITER_CONTINUE; 6643 + } 6644 + 6645 + static jsval_t append_spread_to_dynargs(struct js *js, spread_dynargs_ctx_t *ctx, jsval_t spread_value) { 6646 + return iter_foreach(js, spread_value, spread_dynargs_iter_cb, ctx); 6647 + } 6648 + 6602 6649 static int parse_call_args(struct js *js, UT_array *args, jsval_t *err_out) { 6603 6650 while (js->pos < js->clen) { 6604 6651 if (next(js) == TOK_RPAREN) break; ··· 6606 6653 if (is_spread) js->consumed = 1; 6607 6654 jsval_t arg = resolveprop(js, js_expr(js)); 6608 6655 if (is_err(arg)) { *err_out = arg; return -1; } 6609 - if (is_spread && vtype(arg) == T_ARR) { 6610 - jsoff_t len = js_arr_len(js, arg); 6611 - for (jsoff_t i = 0; i < len; i++) { 6612 - jsval_t elem = js_arr_get(js, arg, i); 6613 - utarray_push_back(args, &elem); 6614 - } 6656 + if (is_spread) { 6657 + jsval_t spread_result = append_spread_to_utarray(js, args, arg); 6658 + if (is_err(spread_result)) { *err_out = spread_result; return -1; } 6615 6659 } else utarray_push_back(args, &arg); 6616 6660 if (next(js) == TOK_COMMA) js->consumed = 1; 6617 6661 } ··· 7446 7490 argc = 0; 7447 7491 args_on_heap = false; 7448 7492 int args_cap = 8; 7449 - 7450 - #define ARGS_PUSH(val) do { \ 7451 - if (argc >= args_cap) { \ 7452 - int _new_cap = args_cap * 2; \ 7453 - jsval_t *_new = try_oom(_new_cap * sizeof(jsval_t)); \ 7454 - memcpy(_new, args, argc * sizeof(jsval_t)); \ 7455 - if (args_on_heap) free(args); \ 7456 - args = _new; \ 7457 - args_cap = _new_cap; \ 7458 - args_on_heap = true; \ 7459 - } \ 7460 - args[argc++] = (val); \ 7461 - } while (0) 7493 + spread_dynargs_ctx_t spread_ctx = { 7494 + .args = &args, 7495 + .argc = &argc, 7496 + .args_cap = &args_cap, 7497 + .args_on_heap = &args_on_heap 7498 + }; 7462 7499 7463 - for (int i = 0; i < bound_argc; i++) ARGS_PUSH(bound_args[i]); 7500 + for (int i = 0; i < bound_argc; i++) spread_dynargs_push(&spread_ctx, bound_args[i]); 7464 7501 caller_pos = skiptonext(caller_code, caller_clen, caller_pos, NULL); 7465 7502 7466 7503 while (caller_pos < caller_clen && caller_code[caller_pos] != ')') { ··· 7473 7510 js->consumed = 1; 7474 7511 jsval_t arg = resolveprop(js, js_expr(js)); 7475 7512 caller_pos = js->pos; 7476 - if (is_spread && vtype(arg) == T_ARR) { 7477 - jsoff_t len = js_arr_len(js, arg); 7478 - for (jsoff_t i = 0; i < len; i++) ARGS_PUSH(js_arr_get(js, arg, i)); 7479 - } else ARGS_PUSH(arg); 7513 + if (is_err(arg)) { 7514 + if (args_on_heap) free(args); 7515 + restore_saved_scope(js); 7516 + if (global_scope_stack && utarray_len(global_scope_stack) > 0) utarray_pop_back(global_scope_stack); 7517 + return arg; 7518 + } 7519 + if (is_spread) { 7520 + jsval_t spread_result = append_spread_to_dynargs(js, &spread_ctx, arg); 7521 + if (is_err(spread_result)) { 7522 + if (args_on_heap) free(args); 7523 + restore_saved_scope(js); 7524 + if (global_scope_stack && utarray_len(global_scope_stack) > 0) utarray_pop_back(global_scope_stack); 7525 + return spread_result; 7526 + } 7527 + } else spread_dynargs_push(&spread_ctx, arg); 7480 7528 caller_pos = skiptonext(caller_code, caller_clen, caller_pos, NULL); 7481 7529 if (caller_pos < caller_clen && caller_code[caller_pos] == ',') caller_pos++; 7482 7530 caller_pos = skiptonext(caller_code, caller_clen, caller_pos, NULL); 7483 7531 } 7484 - 7485 - #undef ARGS_PUSH 7532 + 7486 7533 js->pos = caller_pos; 7487 7534 } 7488 7535 ··· 8944 8991 return js_obj_literal(js); 8945 8992 } 8946 8993 8994 + typedef struct { 8995 + jsval_t arr; 8996 + jsoff_t *idx; 8997 + } spread_arr_literal_ctx_t; 8998 + 8999 + static iter_action_t spread_arr_literal_iter_cb(struct js *js, jsval_t value, void *ctx, jsval_t *out) { 9000 + spread_arr_literal_ctx_t *sctx = (spread_arr_literal_ctx_t *)ctx; 9001 + arr_set(js, sctx->arr, *sctx->idx, value); 9002 + (*sctx->idx)++; 9003 + return ITER_CONTINUE; 9004 + } 9005 + 9006 + static jsval_t append_spread_to_array_literal(struct js *js, jsval_t arr, jsoff_t *idx, jsval_t spread_value) { 9007 + spread_arr_literal_ctx_t ctx = { .arr = arr, .idx = idx }; 9008 + return iter_foreach(js, spread_value, spread_arr_literal_iter_cb, &ctx); 9009 + } 9010 + 8947 9011 static jsval_t js_arr_literal(struct js *js) { 8948 9012 bool saved_tail = js->tail_ctx; 8949 9013 js->tail_ctx = false; ··· 8981 9045 arr_set(js, arr, idx, resolved); 8982 9046 idx++; goto next_elem; 8983 9047 } 8984 - 8985 - uint8_t t = vtype(resolved); 8986 - if (t != T_ARR && t != T_STR) goto next_elem; 8987 - 8988 - if (t == T_STR) { 8989 - jsoff_t slen, soff = vstr(js, resolved, &slen); 8990 - for (jsoff_t i = 0; i < slen; i++) { 8991 - jsval_t ch = js_mkstr(js, (char *)&js->mem[soff + i], 1); 8992 - arr_set(js, arr, idx, ch); idx++; 8993 - } 8994 - goto next_elem; 8995 - } 8996 - 8997 - jsoff_t len = js_arr_len(js, resolved); 8998 - for (jsoff_t i = 0; i < len; i++) { 8999 - jsval_t elem = arr_get(js, resolved, i); 9000 - arr_set(js, arr, idx, elem); idx++; 9001 - } 9048 + jsval_t spread_result = append_spread_to_array_literal(js, arr, &idx, resolved); 9049 + if (is_err(spread_result)) return spread_result; 9002 9050 9003 9051 next_elem: 9004 9052 if (next(js) == TOK_RBRACKET) break; ··· 11702 11750 size_t char_bytes; 11703 11751 jsval_t char_str; 11704 11752 11705 - if (c < 0x80) { char_bytes = 1; char_str = js->ascii_char_cache[c]; } else { 11706 - if ((c & 0xE0) == 0xC0) char_bytes = 2; 11707 - else if ((c & 0xF0) == 0xE0) char_bytes = 3; 11708 - else if ((c & 0xF8) == 0xF0) char_bytes = 4; 11709 - else char_bytes = 1; 11753 + if (c < 0x80) { 11754 + char_bytes = 1; 11755 + char_str = js->ascii_char_cache[c]; 11756 + } else { 11757 + int seq_len = utf8_sequence_length(c); 11758 + char_bytes = (size_t)(seq_len > 0 ? seq_len : 1); 11710 11759 if (byte_pos + char_bytes > cur_byte_len) char_bytes = cur_byte_len - byte_pos; 11711 11760 char_str = js_mkstr(js, cur_str + byte_pos, char_bytes); 11712 - } byte_pos += char_bytes; 11761 + } 11762 + byte_pos += char_bytes; 11713 11763 11714 11764 jsval_t err = for_iter_bind_var(js, ctx, char_str); 11715 11765 if (is_err(err)) { js_unroot(js, h_iterable); return err; } ··· 11724 11774 js_unroot(js, h_iterable); 11725 11775 return js_mkundef(); 11726 11776 } 11727 - 11728 - typedef enum { ITER_CONTINUE, ITER_BREAK, ITER_ERROR } iter_action_t; 11729 - typedef iter_action_t (*iter_callback_t)(struct js *js, jsval_t value, void *ctx, jsval_t *out); 11730 11777 11731 11778 static jsval_t iter_call_noargs_with_this(struct js *js, jsval_t this_val, jsval_t method) { 11732 11779 js_parse_state_t saved_state;
+9 -3
src/modules/symbol.c
··· 3 3 #include <stdio.h> 4 4 5 5 #include "ant.h" 6 + #include "utf8.h" 6 7 #include "errors.h" 7 8 #include "runtime.h" 8 9 #include "internal.h" ··· 213 214 js_set(js, result, "value", js_mkundef()); 214 215 } else { 215 216 char *s = js_getstr(js, str, NULL); 216 - char ch[2] = {s[idx], 0}; 217 - js_set(js, result, "value", js_mkstr(js, ch, 1)); 217 + unsigned char c = (unsigned char)s[idx]; 218 + 219 + int char_bytes = utf8_sequence_length(c); 220 + if (char_bytes < 1) char_bytes = 1; 221 + if (idx + char_bytes > len) char_bytes = len - idx; 222 + 223 + js_set(js, result, "value", js_mkstr(js, s + idx, (jsoff_t)char_bytes)); 218 224 js_set(js, result, "done", js_false); 219 - js_set(js, this_val, "__idx", js_mknum(idx + 1)); 225 + js_set(js, this_val, "__idx", js_mknum(idx + char_bytes)); 220 226 } 221 227 222 228 return result;