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 support for arguments to setTimeout and setInterval

+104 -102
+74 -96
src/ant.c
··· 273 273 int param_count; 274 274 bool has_rest; 275 275 bool is_strict; 276 + bool is_expr; 276 277 jsoff_t rest_param_start; 277 278 jsoff_t rest_param_len; 278 279 UT_array *params; ··· 5749 5750 5750 5751 if (fnpos < fnlen && fn[fnpos] == ')') fnpos++; 5751 5752 fnpos = skiptonext(fn, fnlen, fnpos, NULL); 5752 - if (fnpos < fnlen && fn[fnpos] == '{') fnpos++; 5753 + bool is_block = (fnpos < fnlen && fn[fnpos] == '{'); 5754 + if (is_block) fnpos++; 5753 5755 5754 5756 pf->body_start = fnpos; 5755 - pf->body_len = (fnlen > fnpos + 1) ? (fnlen - fnpos - 1) : 0; 5757 + pf->body_len = (fnlen > fnpos) ? (fnlen - fnpos - (is_block ? 1 : 0)) : 0; 5758 + pf->is_expr = !is_block; 5756 5759 pf->is_strict = is_strict_function_body(&fn[fnpos], pf->body_len); 5757 5760 5758 5761 HASH_ADD(hh, func_parse_cache, code_hash, sizeof(pf->code_hash), pf); ··· 5981 5984 } else js->this_val = target_this; 5982 5985 5983 5986 js->flags = F_CALL | (func_strict ? F_STRICT : 0); 5984 - jsval_t res = js_eval(js, &fn[pf->body_start], pf->body_len); 5987 + jsval_t res; 5988 + if (pf->is_expr) { 5989 + res = js_eval_str(js, &fn[pf->body_start], pf->body_len); 5990 + res = resolveprop(js, res); 5991 + } else { 5992 + res = js_eval(js, &fn[pf->body_start], pf->body_len); 5993 + if (!is_err(res) && !(js->flags & F_RETURN)) res = js_mkundef(); 5994 + } 5985 5995 js->skip_func_hoist = false; 5986 - 5987 - if (!is_err(res) && !(js->flags & F_RETURN)) res = js_mkundef(); 5988 5996 if (global_scope_stack && utarray_len(global_scope_stack) > 0) utarray_pop_back(global_scope_stack); 5989 5997 5990 5998 utarray_free(args_arr); ··· 6209 6217 6210 6218 if (fnpos < fnlen && fn[fnpos] == ')') fnpos++; 6211 6219 fnpos = skiptonext(fn, fnlen, fnpos, NULL); 6220 + 6212 6221 if (fnpos >= fnlen) return js_mkerr(js, "unexpected end of function"); 6213 - if (fn[fnpos] == '{') fnpos++; 6214 - jsoff_t body_len = fnlen - fnpos - 1; 6222 + bool is_block = (fn[fnpos] == '{'); 6223 + 6224 + if (is_block) fnpos++; 6225 + jsoff_t body_len = fnlen - fnpos - (is_block ? 1 : 0); 6215 6226 6216 6227 bool func_strict = is_strict_function_body(&fn[fnpos], body_len); 6217 6228 if (code_uses_arguments(&fn[fnpos], body_len)) { ··· 6229 6240 } 6230 6241 js->flags = F_CALL | (func_strict ? F_STRICT : 0); 6231 6242 6232 - jsval_t res = js_eval(js, &fn[fnpos], body_len); 6233 - if (!is_err(res) && !(js->flags & F_RETURN)) res = js_mkundef(); 6243 + jsval_t res; 6244 + if (!is_block) { 6245 + res = js_eval_str(js, &fn[fnpos], body_len); 6246 + res = resolveprop(js, res); 6247 + } else { 6248 + res = js_eval(js, &fn[fnpos], body_len); 6249 + if (!is_err(res) && !(js->flags & F_RETURN)) res = js_mkundef(); 6250 + } 6234 6251 6235 6252 js->this_val = saved_this; 6236 6253 if (global_scope_stack && utarray_len(global_scope_stack) > 0) utarray_pop_back(global_scope_stack); ··· 7985 8002 } else body_end = js->pos; 7986 8003 } 7987 8004 js->flags = flags; 7988 - size_t fn_size = id_len + (body_end - body_start) + 64; 7989 - char *fn_str = (char *) malloc(fn_size); 8005 + size_t body_len = body_end - body_start; 8006 + size_t param_len = id_len + 2; 8007 + size_t fn_len = param_len + body_len; 8008 + char *fn_str = (char *) malloc(fn_len + 1); 7990 8009 if (!fn_str) return js_mkerr(js, "oom"); 7991 - jsoff_t fn_pos = 0; 7992 - memcpy(fn_str + fn_pos, param_buf, id_len + 2); 7993 - fn_pos += id_len + 2; 7994 - if (is_expr) { 7995 - fn_str[fn_pos++] = '{'; 7996 - memcpy(fn_str + fn_pos, "return ", 7); 7997 - fn_pos += 7; 7998 - size_t body_len = body_end - body_start; 7999 - memcpy(fn_str + fn_pos, &js->code[body_start], body_len); 8000 - fn_pos += body_len; 8001 - fn_str[fn_pos++] = '}'; 8002 - } else { 8003 - size_t body_len = body_end - body_start; 8004 - memcpy(fn_str + fn_pos, &js->code[body_start], body_len); 8005 - fn_pos += body_len; 8006 - } 8010 + memcpy(fn_str, param_buf, param_len); 8011 + memcpy(fn_str + param_len, &js->code[body_start], body_len); 8007 8012 jsval_t func_obj = mkobj(js, 0); 8008 8013 if (is_err(func_obj)) { free(fn_str); return func_obj; } 8009 - set_func_code(js, func_obj, fn_str, fn_pos); 8014 + set_func_code(js, func_obj, fn_str, fn_len); 8010 8015 free(fn_str); 8011 8016 set_slot(js, func_obj, SLOT_ASYNC, js_true); 8012 8017 set_slot(js, func_obj, SLOT_ARROW, js_true); ··· 8130 8135 8131 8136 js->flags = flags; 8132 8137 8133 - size_t fn_size = (params_end - params_start) + (body_end_actual - body_start) + 32; 8134 - char *fn_str = (char *) malloc(fn_size); 8135 - if (!fn_str) return js_mkerr(js, "oom"); 8138 + size_t param_len = params_end - params_start; 8139 + size_t body_len = body_end_actual - body_start; 8140 + size_t fn_len = param_len + body_len; 8136 8141 8137 - jsoff_t fn_pos = 0; 8142 + char *fn_str = (char *) malloc(fn_len + 1); 8143 + if (!fn_str) return js_mkerr(js, "oom"); 8138 8144 8139 - size_t param_len = params_end - params_start; 8140 - memcpy(fn_str + fn_pos, &js->code[params_start], param_len); 8141 - fn_pos += param_len; 8142 - 8143 - if (is_expr) { 8144 - fn_str[fn_pos++] = '{'; 8145 - memcpy(fn_str + fn_pos, "return ", 7); 8146 - fn_pos += 7; 8147 - size_t body_len = body_end_actual - body_start; 8148 - memcpy(fn_str + fn_pos, &js->code[body_start], body_len); 8149 - fn_pos += body_len; 8150 - fn_str[fn_pos++] = '}'; 8151 - } else { 8152 - size_t body_len = body_end_actual - body_start; 8153 - memcpy(fn_str + fn_pos, &js->code[body_start], body_len); 8154 - fn_pos += body_len; 8155 - } 8145 + memcpy(fn_str, &js->code[params_start], param_len); 8146 + memcpy(fn_str + param_len, &js->code[body_start], body_len); 8156 8147 8157 8148 jsval_t func_obj = mkobj(js, 0); 8158 8149 if (is_err(func_obj)) { free(fn_str); return func_obj; } 8159 8150 8160 - set_func_code(js, func_obj, fn_str, fn_pos); 8151 + set_func_code(js, func_obj, fn_str, fn_len); 8161 8152 free(fn_str); 8162 8153 8163 8154 if (is_async) { ··· 8765 8756 jsval_t then_args[] = { mkval(T_FUNC, vdata(resume_obj)), mkval(T_FUNC, vdata(reject_obj)) }; 8766 8757 jsval_t saved_this = js->this_val; 8767 8758 js->this_val = resolved; 8768 - (void)builtin_promise_then(js, then_args, 2); 8759 + 8760 + builtin_promise_then(js, then_args, 2); 8769 8761 js->this_val = saved_this; 8770 8762 8771 8763 js_parse_state_t saved; ··· 9004 8996 body_end = is_body_end_tok(tok) ? js->toff : js->pos; 9005 8997 } else body_end = js->pos; 9006 8998 9007 - size_t fn_size = param_len + (body_end - body_start) + 64; 9008 - char *fn_str = (char *) malloc(fn_size); 8999 + size_t params_len = param_len + 2; 9000 + size_t body_len = body_end - body_start; 9001 + size_t fn_len = params_len + body_len; 9002 + 9003 + char *fn_str = (char *) malloc(fn_len + 1); 9009 9004 if (!fn_str) return js_mkerr(js, "oom"); 9010 - 9011 - jsoff_t fn_pos = 0; 9012 - memcpy(fn_str + fn_pos, param_buf, param_len + 2); 9013 - fn_pos += param_len + 2; 9014 - 9015 - if (is_expr) { 9016 - fn_str[fn_pos++] = '{'; 9017 - memcpy(fn_str + fn_pos, "return ", 7); 9018 - fn_pos += 7; 9019 - size_t body_len = body_end - body_start; 9020 - memcpy(fn_str + fn_pos, &js->code[body_start], body_len); 9021 - fn_pos += body_len; 9022 - fn_str[fn_pos++] = '}'; 9023 - } else { 9024 - size_t body_len = body_end - body_start; 9025 - memcpy(fn_str + fn_pos, &js->code[body_start], body_len); 9026 - fn_pos += body_len; 9027 - } 9005 + 9006 + memcpy(fn_str, param_buf, params_len); 9007 + memcpy(fn_str + params_len, &js->code[body_start], body_len); 9028 9008 9029 9009 jsval_t func_obj = mkobj(js, 0); 9030 9010 if (is_err(func_obj)) { free(fn_str); return func_obj; } 9031 - set_func_code(js, func_obj, fn_str, fn_pos); 9011 + 9012 + set_func_code(js, func_obj, fn_str, fn_len); 9032 9013 free(fn_str); 9033 9014 9034 9015 jsval_t func_proto = get_slot(js, js_glob(js), SLOT_FUNC_PROTO); ··· 9041 9022 set_slot(js, func_obj, SLOT_THIS, js->this_val); 9042 9023 } 9043 9024 9025 + set_slot(js, func_obj, SLOT_ARROW, js_true); 9044 9026 return mkval(T_FUNC, (unsigned long) vdata(func_obj)); 9045 9027 } 9046 9028 ··· 12352 12334 bool is_arrow = (arrow_slot == js_true); 12353 12335 12354 12336 if (is_arrow) { 12355 - const char *brace = memchr(code, '{', code_len); 12356 - if (!brace) goto fallback_arrow; 12337 + const char *paren_end = memchr(code, ')', code_len); 12338 + if (!paren_end) goto fallback_arrow; 12357 12339 12358 - size_t params_len = brace - code; 12359 - const char *body_start = brace + 1; 12360 - size_t body_len = code_len - params_len - 1; 12361 - bool is_expr = (body_len >= 7 && memcmp(body_start, "return ", 7) == 0); 12340 + size_t params_len = paren_end - code + 1; 12341 + const char *body = paren_end + 1; 12342 + size_t body_len = code_len - params_len; 12362 12343 12363 - size_t total = (is_async ? 6 : 0) + params_len + 4 + body_len + 2; 12364 - char *buf = ant_calloc(total + 1); 12344 + size_t len = (is_async ? 6 : 0) + params_len + 4 + body_len + 1; 12345 + char *buf = ant_calloc(len); 12365 12346 size_t n = 0; 12366 12347 12367 - if (is_async) n += cpy(buf + n, total - n, "async ", 6); 12368 - n += cpy(buf + n, total - n, code, params_len); 12369 - n += cpy(buf + n, total - n, " => ", 4); 12370 - 12371 - if (is_expr) { 12372 - const char *expr = body_start + 7; 12373 - size_t expr_len = body_len - 7; 12374 - while (expr_len > 0 && (expr[expr_len-1] == ' ' || expr[expr_len-1] == '}' || expr[expr_len-1] == ')')) expr_len--; 12375 - n += cpy(buf + n, total - n, expr, expr_len); 12376 - } else { 12377 - size_t block_len = code_len - params_len; 12378 - while (block_len > 0 && brace[block_len-1] == ')') block_len--; 12379 - n += cpy(buf + n, total - n, brace, block_len); 12380 - } 12348 + if (is_async) n += cpy(buf + n, REMAIN(n, len), "async ", 6); 12349 + n += cpy(buf + n, REMAIN(n, len), code, params_len); 12350 + n += cpy(buf + n, REMAIN(n, len), " => ", 4); 12351 + n += cpy(buf + n, REMAIN(n, len), body, body_len); 12381 12352 12382 12353 jsval_t result = js_mkstr(js, buf, n); 12383 12354 free(buf); ··· 22725 22696 uint8_t caller_flags = js->flags; 22726 22697 22727 22698 js->flags = F_CALL | (pf->is_strict ? F_STRICT : 0); 22728 - jsval_t res = js_eval(js, &fn[pf->body_start], pf->body_len); 22729 - if (!is_err(res) && !(js->flags & F_RETURN)) res = js_mkundef(); 22699 + jsval_t res; 22700 + 22701 + if (pf->is_expr) { 22702 + res = js_eval_str(js, &fn[pf->body_start], pf->body_len); 22703 + res = resolveprop(js, res); 22704 + } else { 22705 + res = js_eval(js, &fn[pf->body_start], pf->body_len); 22706 + if (!is_err(res) && !(js->flags & F_RETURN)) res = js_mkundef(); 22707 + } 22730 22708 22731 22709 JS_RESTORE_STATE(js, saved_state); 22732 22710 js->flags = caller_flags;
+26 -4
src/modules/timer.c
··· 15 15 typedef struct timer_entry { 16 16 uv_timer_t handle; 17 17 jsval_t callback; 18 + jsval_t *args; 19 + int nargs; 18 20 int timer_id; 19 21 int active; 20 22 int is_interval; ··· 62 64 if (entry->next) entry->next->prev = entry->prev; 63 65 } 64 66 67 + static int timer_copy_args(timer_entry_t *entry, jsval_t *args, int nargs) { 68 + entry->nargs = nargs > 2 ? nargs - 2 : 0; 69 + if (entry->nargs > 0) { 70 + entry->args = ant_calloc(sizeof(jsval_t) * entry->nargs); 71 + if (!entry->args) return -1; 72 + memcpy(entry->args, args + 2, sizeof(jsval_t) * entry->nargs); 73 + } else entry->args = NULL; 74 + return 0; 75 + } 76 + 65 77 static void timer_close_cb(uv_handle_t *h) { 66 78 timer_entry_t *entry = (timer_entry_t *)h->data; 67 79 if (!entry) return; ··· 72 84 entry->prev = NULL; 73 85 h->data = NULL; 74 86 87 + if (entry->args) free(entry->args); 75 88 free(entry); 76 89 } 77 90 ··· 80 93 if (!entry || !entry->active) return; 81 94 82 95 struct js *js = timer_state.js; 83 - jsval_t args[0]; 84 - js_call(js, entry->callback, args, 0); 96 + js_call(js, entry->callback, entry->args, entry->nargs); 85 97 process_microtasks(js); 86 98 87 99 if (!entry->is_interval) { ··· 91 103 } 92 104 } 93 105 94 - // setTimeout(callback, delay) 106 + // setTimeout(callback, delay, ...args) 95 107 static jsval_t js_set_timeout(struct js *js, jsval_t *args, int nargs) { 96 108 if (nargs < 2) { 97 109 return js_mkerr(js, "setTimeout requires 2 arguments (callback, delay)"); ··· 103 115 104 116 timer_entry_t *entry = ant_calloc(sizeof(timer_entry_t)); 105 117 if (entry == NULL) return js_mkerr(js, "failed to allocate timer"); 118 + 119 + if (timer_copy_args(entry, args, nargs) < 0) { 120 + free(entry); 121 + return js_mkerr(js, "failed to allocate timer args"); 122 + } 106 123 107 124 uv_timer_init(uv_default_loop(), &entry->handle); 108 125 entry->handle.data = entry; ··· 118 135 return js_mknum((double)entry->timer_id); 119 136 } 120 137 121 - // setInterval(callback, delay) 138 + // setInterval(callback, delay, ...args) 122 139 static jsval_t js_set_interval(struct js *js, jsval_t *args, int nargs) { 123 140 if (nargs < 2) { 124 141 return js_mkerr(js, "setInterval requires 2 arguments (callback, delay)"); ··· 130 147 131 148 timer_entry_t *entry = ant_calloc(sizeof(timer_entry_t)); 132 149 if (entry == NULL) return js_mkerr(js, "failed to allocate timer"); 150 + 151 + if (timer_copy_args(entry, args, nargs) < 0) { 152 + free(entry); 153 + return js_mkerr(js, "failed to allocate timer args"); 154 + } 133 155 134 156 uv_timer_init(uv_default_loop(), &entry->handle); 135 157 entry->handle.data = entry;
+4 -2
src/types/timers.d.ts
··· 1 - declare function setTimeout(callback: () => void, delay: number): number; 1 + declare function setTimeout<T extends any[]>(callback: (...args: T) => void, delay: number, ...args: T): number; 2 + declare function setInterval<T extends any[]>(callback: (...args: T) => void, delay: number, ...args: T): number; 3 + 2 4 declare function clearTimeout(timerId: number): void; 3 - declare function setInterval(callback: () => void, delay: number): number; 4 5 declare function clearInterval(timerId: number): void; 6 + 5 7 declare function setImmediate(callback: () => void): number; 6 8 declare function clearImmediate(immediateId: number): void; 7 9 declare function queueMicrotask(callback: () => void): void;