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 Proxy

+246 -1
+1 -1
meson.build
··· 74 74 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 75 75 76 76 version_conf = configuration_data() 77 - version_conf.set('ANT_VERSION', '0.1.1.18') 77 + version_conf.set('ANT_VERSION', '0.1.1.19') 78 78 version_conf.set('ANT_GIT_HASH', git_hash) 79 79 version_conf.set('ANT_BUILD_DATE', build_date) 80 80
+245
src/ant.c
··· 173 173 UT_hash_handle hh; 174 174 } set_entry_t; 175 175 176 + typedef struct proxy_data { 177 + jsoff_t obj_offset; 178 + jsval_t target; 179 + jsval_t handler; 180 + bool revoked; 181 + UT_hash_handle hh; 182 + } proxy_data_t; 183 + 176 184 static ant_library_t *library_registry = NULL; 177 185 static esm_module_cache_t global_module_cache = {NULL, 0}; 178 186 static obj_prop_cache_t *global_property_cache = NULL; 187 + static proxy_data_t *proxy_registry = NULL; 179 188 180 189 void js_protect_init_memory(struct js *js) { 181 190 protected_brk = js_getbrk(js); ··· 504 513 static jsval_t builtin_Set(struct js *js, jsval_t *args, int nargs); 505 514 static jsval_t builtin_WeakMap(struct js *js, jsval_t *args, int nargs); 506 515 static jsval_t builtin_WeakSet(struct js *js, jsval_t *args, int nargs); 516 + static jsval_t builtin_Proxy(struct js *js, jsval_t *args, int nargs); 517 + static jsval_t builtin_Proxy_revocable(struct js *js, jsval_t *args, int nargs); 518 + static bool is_proxy(struct js *js, jsval_t obj); 519 + static jsval_t proxy_get(struct js *js, jsval_t proxy, const char *key, size_t key_len); 520 + static jsval_t proxy_set(struct js *js, jsval_t proxy, const char *key, size_t key_len, jsval_t value); 521 + static jsval_t proxy_has(struct js *js, jsval_t proxy, const char *key, size_t key_len); 522 + static jsval_t proxy_delete(struct js *js, jsval_t proxy, const char *key, size_t key_len); 507 523 static jsval_t map_set(struct js *js, jsval_t *args, int nargs); 508 524 static jsval_t map_get(struct js *js, jsval_t *args, int nargs); 509 525 static jsval_t map_has(struct js *js, jsval_t *args, int nargs); ··· 2498 2514 if (streq(key, klen, "__proto__", 9)) { 2499 2515 return js_mkerr(js, "cannot assign to __proto__"); 2500 2516 } 2517 + 2518 + if (is_proxy(js, obj)) { 2519 + jsval_t result = proxy_set(js, obj, key, klen, v); 2520 + if (is_err(result)) return result; 2521 + return v; 2522 + } 2523 + 2501 2524 jsoff_t existing = lkp(js, obj, key, klen); 2502 2525 if (existing > 0) { 2503 2526 char desc_key[128]; ··· 3444 3467 jsval_t obj = mkval(T_OBJ, obj_off); 3445 3468 jsval_t key = mkval(T_STR, key_off); 3446 3469 jsoff_t len; 3470 + 3447 3471 const char *key_str = (const char *)&js->mem[vstr(js, key, &len)]; 3472 + if (is_proxy(js, obj)) return proxy_get(js, obj, key_str, len); 3473 + 3448 3474 jsoff_t prop_off = lkp(js, obj, key_str, len); 3449 3475 if (prop_off == 0) return js_mkundef(); 3450 3476 return resolveprop(js, mkval(T_PROP, prop_off)); ··· 5847 5873 jsval_t key = mkval(T_STR, key_off); 5848 5874 jsoff_t len; 5849 5875 const char *key_str = (const char *)&js->mem[vstr(js, key, &len)]; 5876 + 5877 + if (is_proxy(js, obj)) { 5878 + jsval_t result = proxy_delete(js, obj, key_str, len); 5879 + if (is_err(result)) return result; 5880 + return js_truthy(js, result) ? js_mktrue() : js_mkfalse(); 5881 + } 5882 + 5850 5883 jsoff_t prop_off = lkp(js, obj, key_str, len); 5851 5884 if (prop_off == 0) return js_mktrue(); 5852 5885 if (is_const_prop(js, prop_off)) { ··· 14100 14133 jsoff_t prop_off = vstr(js, l, &prop_len); 14101 14134 const char *prop_name = (char *) &js->mem[prop_off]; 14102 14135 14136 + if (is_proxy(js, r)) { 14137 + jsval_t result = proxy_has(js, r, prop_name, prop_len); 14138 + if (is_err(result)) return result; 14139 + return js_truthy(js, result) ? js_mktrue() : js_mkfalse(); 14140 + } 14141 + 14103 14142 jsoff_t found = lkp_proto(js, r, prop_name, prop_len); 14104 14143 return mkval(T_BOOL, found != 0 ? 1 : 0); 14105 14144 } ··· 15441 15480 return ws_obj; 15442 15481 } 15443 15482 15483 + static proxy_data_t *get_proxy_data(jsval_t obj) { 15484 + if (vtype(obj) != T_OBJ) return NULL; 15485 + jsoff_t off = (jsoff_t)vdata(obj); 15486 + proxy_data_t *data = NULL; 15487 + HASH_FIND(hh, proxy_registry, &off, sizeof(jsoff_t), data); 15488 + return data; 15489 + } 15490 + 15491 + static bool is_proxy(struct js *js, jsval_t obj) { 15492 + (void)js; 15493 + return get_proxy_data(obj) != NULL; 15494 + } 15495 + 15496 + static jsval_t throw_proxy_error(struct js *js, const char *message) { 15497 + jsval_t err_obj = mkobj(js, 0); 15498 + setprop(js, err_obj, js_mkstr(js, "message", 7), js_mkstr(js, message, strlen(message))); 15499 + setprop(js, err_obj, js_mkstr(js, "name", 4), js_mkstr(js, "TypeError", 9)); 15500 + return js_throw(js, err_obj); 15501 + } 15502 + 15503 + static jsval_t proxy_get(struct js *js, jsval_t proxy, const char *key, size_t key_len) { 15504 + proxy_data_t *data = get_proxy_data(proxy); 15505 + if (!data) return js_mkundef(); 15506 + if (data->revoked) return throw_proxy_error(js, "Cannot perform 'get' on a proxy that has been revoked"); 15507 + 15508 + jsval_t target = data->target; 15509 + jsval_t handler = data->handler; 15510 + 15511 + jsoff_t get_trap_off = vtype(handler) == T_OBJ ? lkp(js, handler, "get", 3) : 0; 15512 + if (get_trap_off != 0) { 15513 + jsval_t get_trap = resolveprop(js, mkval(T_PROP, get_trap_off)); 15514 + if (vtype(get_trap) == T_FUNC || vtype(get_trap) == T_CFUNC) { 15515 + jsval_t key_val = js_mkstr(js, key, key_len); 15516 + jsval_t args[3] = { target, key_val, proxy }; 15517 + return js_call(js, get_trap, args, 3); 15518 + } 15519 + } 15520 + 15521 + char key_buf[256]; 15522 + size_t len = key_len < sizeof(key_buf) - 1 ? key_len : sizeof(key_buf) - 1; 15523 + memcpy(key_buf, key, len); 15524 + key_buf[len] = '\0'; 15525 + 15526 + jsoff_t off = lkp(js, target, key_buf, len); 15527 + if (off != 0) return resolveprop(js, mkval(T_PROP, off)); 15528 + 15529 + jsoff_t proto_off = lkp_proto(js, target, key_buf, len); 15530 + if (proto_off != 0) return resolveprop(js, mkval(T_PROP, proto_off)); 15531 + 15532 + return js_mkundef(); 15533 + } 15534 + 15535 + static jsval_t proxy_set(struct js *js, jsval_t proxy, const char *key, size_t key_len, jsval_t value) { 15536 + proxy_data_t *data = get_proxy_data(proxy); 15537 + if (!data) return js_mkundef(); 15538 + if (data->revoked) return throw_proxy_error(js, "Cannot perform 'set' on a proxy that has been revoked"); 15539 + 15540 + jsval_t target = data->target; 15541 + jsval_t handler = data->handler; 15542 + 15543 + jsoff_t set_trap_off = vtype(handler) == T_OBJ ? lkp(js, handler, "set", 3) : 0; 15544 + if (set_trap_off != 0) { 15545 + jsval_t set_trap = resolveprop(js, mkval(T_PROP, set_trap_off)); 15546 + if (vtype(set_trap) == T_FUNC || vtype(set_trap) == T_CFUNC) { 15547 + jsval_t key_val = js_mkstr(js, key, key_len); 15548 + jsval_t args[4] = { target, key_val, value, proxy }; 15549 + jsval_t result = js_call(js, set_trap, args, 4); 15550 + if (is_err(result)) return result; 15551 + return js_mktrue(); 15552 + } 15553 + } 15554 + 15555 + jsval_t key_str = js_mkstr(js, key, key_len); 15556 + setprop(js, target, key_str, value); 15557 + return js_mktrue(); 15558 + } 15559 + 15560 + static jsval_t proxy_has(struct js *js, jsval_t proxy, const char *key, size_t key_len) { 15561 + proxy_data_t *data = get_proxy_data(proxy); 15562 + if (!data) return js_mkfalse(); 15563 + if (data->revoked) return throw_proxy_error(js, "Cannot perform 'has' on a proxy that has been revoked"); 15564 + 15565 + jsval_t target = data->target; 15566 + jsval_t handler = data->handler; 15567 + 15568 + jsoff_t has_trap_off = vtype(handler) == T_OBJ ? lkp(js, handler, "has", 3) : 0; 15569 + if (has_trap_off != 0) { 15570 + jsval_t has_trap = resolveprop(js, mkval(T_PROP, has_trap_off)); 15571 + if (vtype(has_trap) == T_FUNC || vtype(has_trap) == T_CFUNC) { 15572 + jsval_t key_val = js_mkstr(js, key, key_len); 15573 + jsval_t args[2] = { target, key_val }; 15574 + return js_call(js, has_trap, args, 2); 15575 + } 15576 + } 15577 + 15578 + char key_buf[256]; 15579 + size_t len = key_len < sizeof(key_buf) - 1 ? key_len : sizeof(key_buf) - 1; 15580 + memcpy(key_buf, key, len); 15581 + key_buf[len] = '\0'; 15582 + 15583 + jsoff_t off = lkp_proto(js, target, key_buf, len); 15584 + return off != 0 ? js_mktrue() : js_mkfalse(); 15585 + } 15586 + 15587 + static jsval_t proxy_delete(struct js *js, jsval_t proxy, const char *key, size_t key_len) { 15588 + proxy_data_t *data = get_proxy_data(proxy); 15589 + if (!data) return js_mktrue(); 15590 + if (data->revoked) return throw_proxy_error(js, "Cannot perform 'deleteProperty' on a proxy that has been revoked"); 15591 + 15592 + jsval_t target = data->target; 15593 + jsval_t handler = data->handler; 15594 + 15595 + jsoff_t delete_trap_off = vtype(handler) == T_OBJ ? lkp(js, handler, "deleteProperty", 14) : 0; 15596 + if (delete_trap_off != 0) { 15597 + jsval_t delete_trap = resolveprop(js, mkval(T_PROP, delete_trap_off)); 15598 + if (vtype(delete_trap) == T_FUNC || vtype(delete_trap) == T_CFUNC) { 15599 + jsval_t key_val = js_mkstr(js, key, key_len); 15600 + jsval_t args[2] = { target, key_val }; 15601 + return js_call(js, delete_trap, args, 2); 15602 + } 15603 + } 15604 + 15605 + jsval_t key_str = js_mkstr(js, key, key_len); 15606 + setprop(js, target, key_str, js_mkundef()); 15607 + return js_mktrue(); 15608 + } 15609 + 15610 + static jsval_t mkproxy(struct js *js, jsval_t target, jsval_t handler) { 15611 + jsval_t proxy_obj = mkobj(js, 0); 15612 + jsoff_t off = (jsoff_t)vdata(proxy_obj); 15613 + 15614 + proxy_data_t *data = (proxy_data_t *)ANT_GC_MALLOC(sizeof(proxy_data_t)); 15615 + if (!data) return js_mkerr(js, "out of memory"); 15616 + 15617 + data->obj_offset = off; 15618 + data->target = target; 15619 + data->handler = handler; 15620 + data->revoked = false; 15621 + 15622 + HASH_ADD(hh, proxy_registry, obj_offset, sizeof(jsoff_t), data); 15623 + return proxy_obj; 15624 + } 15625 + 15626 + static jsval_t builtin_Proxy(struct js *js, jsval_t *args, int nargs) { 15627 + if (nargs < 2) return js_mkerr(js, "Proxy requires two arguments: target and handler"); 15628 + 15629 + jsval_t target = args[0]; 15630 + jsval_t handler = args[1]; 15631 + 15632 + uint8_t target_type = vtype(target); 15633 + if (target_type != T_OBJ && target_type != T_FUNC && target_type != T_ARR) { 15634 + return js_mkerr(js, "Proxy target must be an object"); 15635 + } 15636 + 15637 + uint8_t handler_type = vtype(handler); 15638 + if (handler_type != T_OBJ && handler_type != T_FUNC) { 15639 + return js_mkerr(js, "Proxy handler must be an object"); 15640 + } 15641 + 15642 + return mkproxy(js, target, handler); 15643 + } 15644 + 15645 + static jsval_t proxy_revoke_fn(struct js *js, jsval_t *args, int nargs) { 15646 + (void)args; (void)nargs; 15647 + jsval_t func = js->current_func; 15648 + jsoff_t ref_off = lkp(js, func, "__proxy_ref__", 13); 15649 + 15650 + if (ref_off != 0) { 15651 + jsval_t proxy = resolveprop(js, mkval(T_PROP, ref_off)); 15652 + proxy_data_t *data = get_proxy_data(proxy); 15653 + if (data) data->revoked = true; 15654 + } 15655 + 15656 + return js_mkundef(); 15657 + } 15658 + 15659 + static jsval_t builtin_Proxy_revocable(struct js *js, jsval_t *args, int nargs) { 15660 + jsval_t proxy = builtin_Proxy(js, args, nargs); 15661 + if (is_err(proxy)) return proxy; 15662 + 15663 + jsval_t revoke_obj = mkobj(js, 0); 15664 + setprop(js, revoke_obj, js_mkstr(js, "__native_func", 13), js_mkfun(proxy_revoke_fn)); 15665 + setprop(js, revoke_obj, js_mkstr(js, "__proxy_ref__", 13), proxy); 15666 + 15667 + jsval_t revoke_func = mkval(T_FUNC, vdata(revoke_obj)); 15668 + 15669 + jsval_t result = mkobj(js, 0); 15670 + setprop(js, result, js_mkstr(js, "proxy", 5), proxy); 15671 + setprop(js, result, js_mkstr(js, "revoke", 6), revoke_func); 15672 + 15673 + return result; 15674 + } 15675 + 15444 15676 static weakmap_entry_t** get_weakmap_from_obj(struct js *js, jsval_t obj) { 15445 15677 jsoff_t wm_off = lkp(js, obj, "__weakmap", 9); 15446 15678 if (wm_off == 0) return NULL; ··· 15895 16127 setprop(js, weakset_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_WeakSet)); 15896 16128 setprop(js, weakset_ctor_obj, js_mkstr(js, "prototype", 9), weakset_proto); 15897 16129 setprop(js, glob, js_mkstr(js, "WeakSet", 7), mkval(T_FUNC, vdata(weakset_ctor_obj))); 16130 + 16131 + jsval_t proxy_ctor_obj = mkobj(js, 0); 16132 + set_proto(js, proxy_ctor_obj, function_proto); 16133 + setprop(js, proxy_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Proxy)); 16134 + setprop(js, proxy_ctor_obj, js_mkstr(js, "revocable", 9), js_mkfun(builtin_Proxy_revocable)); 16135 + setprop(js, glob, js_mkstr(js, "Proxy", 5), mkval(T_FUNC, vdata(proxy_ctor_obj))); 15898 16136 15899 16137 jsval_t err_ctor_obj = mkobj(js, 0); 15900 16138 set_proto(js, err_ctor_obj, function_proto); ··· 16389 16627 jsval_t saved_this = js->this_val; 16390 16628 js->this_val = use_bound_this ? bound_this : js_glob(js); 16391 16629 16630 + js_parse_state_t saved_state; 16631 + JS_SAVE_STATE(js, saved_state); 16632 + uint8_t caller_flags = js->flags; 16633 + 16392 16634 js->flags = F_CALL; 16393 16635 jsval_t res = js_eval(js, &fn[fnpos], body_len); 16394 16636 if (!is_err(res) && !(js->flags & F_RETURN)) res = js_mkundef(); 16637 + 16638 + JS_RESTORE_STATE(js, saved_state); 16639 + js->flags = caller_flags; 16395 16640 16396 16641 js->this_val = saved_this; 16397 16642 delscope(js);