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.

weakmap, weakset

+398 -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.0.8.5') 77 + version_conf.set('ANT_VERSION', '0.0.8.6') 78 78 version_conf.set('ANT_GIT_HASH', git_hash) 79 79 version_conf.set('ANT_BUILD_DATE', build_date) 80 80
+240
src/ant.c
··· 380 380 static jsval_t builtin_Date_now(struct js *js, jsval_t *args, int nargs); 381 381 static jsval_t builtin_Map(struct js *js, jsval_t *args, int nargs); 382 382 static jsval_t builtin_Set(struct js *js, jsval_t *args, int nargs); 383 + static jsval_t builtin_WeakMap(struct js *js, jsval_t *args, int nargs); 384 + static jsval_t builtin_WeakSet(struct js *js, jsval_t *args, int nargs); 383 385 static jsval_t map_set(struct js *js, jsval_t *args, int nargs); 384 386 static jsval_t map_get(struct js *js, jsval_t *args, int nargs); 385 387 static jsval_t map_has(struct js *js, jsval_t *args, int nargs); ··· 397 399 static jsval_t set_size(struct js *js, jsval_t *args, int nargs); 398 400 static jsval_t set_values(struct js *js, jsval_t *args, int nargs); 399 401 static jsval_t set_forEach(struct js *js, jsval_t *args, int nargs); 402 + static jsval_t weakmap_set(struct js *js, jsval_t *args, int nargs); 403 + static jsval_t weakmap_get(struct js *js, jsval_t *args, int nargs); 404 + static jsval_t weakmap_has(struct js *js, jsval_t *args, int nargs); 405 + static jsval_t weakmap_delete(struct js *js, jsval_t *args, int nargs); 406 + static jsval_t weakset_add(struct js *js, jsval_t *args, int nargs); 407 + static jsval_t weakset_has(struct js *js, jsval_t *args, int nargs); 408 + static jsval_t weakset_delete(struct js *js, jsval_t *args, int nargs); 400 409 static jsval_t builtin_function_call(struct js *js, jsval_t *args, int nargs); 401 410 static jsval_t builtin_function_apply(struct js *js, jsval_t *args, int nargs); 402 411 static jsval_t builtin_function_bind(struct js *js, jsval_t *args, int nargs); ··· 10354 10363 UT_hash_handle hh; 10355 10364 } set_entry_t; 10356 10365 10366 + typedef struct weakmap_entry { 10367 + jsval_t key_obj; 10368 + jsval_t value; 10369 + UT_hash_handle hh; 10370 + } weakmap_entry_t; 10371 + 10372 + typedef struct weakset_entry { 10373 + jsval_t value_obj; 10374 + UT_hash_handle hh; 10375 + } weakset_entry_t; 10376 + 10357 10377 static const char* jsval_to_key(struct js *js, jsval_t val) { 10358 10378 if (vtype(val) == T_STR) { 10359 10379 jsoff_t len; ··· 10616 10636 return tov((double)count); 10617 10637 } 10618 10638 10639 + static jsval_t builtin_WeakMap(struct js *js, jsval_t *args, int nargs) { 10640 + jsval_t wm_obj = mkobj(js, 0); 10641 + 10642 + jsval_t wm_proto = get_ctor_proto(js, "WeakMap", 7); 10643 + if (vtype(wm_proto) == T_OBJ) { 10644 + set_proto(js, wm_obj, wm_proto); 10645 + } 10646 + 10647 + weakmap_entry_t **wm_head = (weakmap_entry_t **)ANT_GC_MALLOC(sizeof(weakmap_entry_t *)); 10648 + if (!wm_head) return js_mkerr(js, "out of memory"); 10649 + *wm_head = NULL; 10650 + 10651 + jsval_t wm_ptr = mkval(T_NUM, (size_t)wm_head); 10652 + jsval_t wm_key = js_mkstr(js, "__weakmap", 9); 10653 + setprop(js, wm_obj, wm_key, wm_ptr); 10654 + 10655 + return wm_obj; 10656 + } 10657 + 10658 + static jsval_t builtin_WeakSet(struct js *js, jsval_t *args, int nargs) { 10659 + jsval_t ws_obj = mkobj(js, 0); 10660 + 10661 + jsval_t ws_proto = get_ctor_proto(js, "WeakSet", 7); 10662 + if (vtype(ws_proto) == T_OBJ) { 10663 + set_proto(js, ws_obj, ws_proto); 10664 + } 10665 + 10666 + weakset_entry_t **ws_head = (weakset_entry_t **)ANT_GC_MALLOC(sizeof(weakset_entry_t *)); 10667 + if (!ws_head) return js_mkerr(js, "out of memory"); 10668 + *ws_head = NULL; 10669 + 10670 + jsval_t ws_ptr = mkval(T_NUM, (size_t)ws_head); 10671 + jsval_t ws_key = js_mkstr(js, "__weakset", 9); 10672 + setprop(js, ws_obj, ws_key, ws_ptr); 10673 + 10674 + return ws_obj; 10675 + } 10676 + 10677 + static weakmap_entry_t** get_weakmap_from_obj(struct js *js, jsval_t obj) { 10678 + jsoff_t wm_off = lkp(js, obj, "__weakmap", 9); 10679 + if (wm_off == 0) return NULL; 10680 + jsval_t wm_val = resolveprop(js, mkval(T_PROP, wm_off)); 10681 + if (vtype(wm_val) != T_NUM) return NULL; 10682 + return (weakmap_entry_t**)(size_t)vdata(wm_val); 10683 + } 10684 + 10685 + static weakset_entry_t** get_weakset_from_obj(struct js *js, jsval_t obj) { 10686 + jsoff_t ws_off = lkp(js, obj, "__weakset", 9); 10687 + if (ws_off == 0) return NULL; 10688 + jsval_t ws_val = resolveprop(js, mkval(T_PROP, ws_off)); 10689 + if (vtype(ws_val) != T_NUM) return NULL; 10690 + return (weakset_entry_t**)(size_t)vdata(ws_val); 10691 + } 10692 + 10693 + static jsval_t weakmap_set(struct js *js, jsval_t *args, int nargs) { 10694 + if (nargs < 2) return js_mkerr(js, "WeakMap.set() requires 2 arguments"); 10695 + 10696 + jsval_t this_val = js->this_val; 10697 + weakmap_entry_t **wm_ptr = get_weakmap_from_obj(js, this_val); 10698 + if (!wm_ptr) return js_mkerr(js, "Invalid WeakMap object"); 10699 + 10700 + if (vtype(args[0]) != T_OBJ) { 10701 + return js_mkerr(js, "WeakMap key must be an object"); 10702 + } 10703 + 10704 + jsval_t key_obj = args[0]; 10705 + 10706 + weakmap_entry_t *entry; 10707 + HASH_FIND(hh, *wm_ptr, &key_obj, sizeof(jsval_t), entry); 10708 + if (entry) { 10709 + entry->value = args[1]; 10710 + } else { 10711 + entry = (weakmap_entry_t *)ANT_GC_MALLOC(sizeof(weakmap_entry_t)); 10712 + if (!entry) return js_mkerr(js, "out of memory"); 10713 + entry->key_obj = key_obj; 10714 + entry->value = args[1]; 10715 + HASH_ADD(hh, *wm_ptr, key_obj, sizeof(jsval_t), entry); 10716 + } 10717 + 10718 + return this_val; 10719 + } 10720 + 10721 + static jsval_t weakmap_get(struct js *js, jsval_t *args, int nargs) { 10722 + if (nargs < 1) return js_mkerr(js, "WeakMap.get() requires 1 argument"); 10723 + 10724 + jsval_t this_val = js->this_val; 10725 + weakmap_entry_t **wm_ptr = get_weakmap_from_obj(js, this_val); 10726 + if (!wm_ptr) return js_mkundef(); 10727 + 10728 + if (vtype(args[0]) != T_OBJ) return js_mkundef(); 10729 + 10730 + jsval_t key_obj = args[0]; 10731 + weakmap_entry_t *entry; 10732 + HASH_FIND(hh, *wm_ptr, &key_obj, sizeof(jsval_t), entry); 10733 + return entry ? entry->value : js_mkundef(); 10734 + } 10735 + 10736 + static jsval_t weakmap_has(struct js *js, jsval_t *args, int nargs) { 10737 + if (nargs < 1) return js_mkerr(js, "WeakMap.has() requires 1 argument"); 10738 + 10739 + jsval_t this_val = js->this_val; 10740 + weakmap_entry_t **wm_ptr = get_weakmap_from_obj(js, this_val); 10741 + if (!wm_ptr) return mkval(T_BOOL, 0); 10742 + 10743 + if (vtype(args[0]) != T_OBJ) return mkval(T_BOOL, 0); 10744 + 10745 + jsval_t key_obj = args[0]; 10746 + weakmap_entry_t *entry; 10747 + HASH_FIND(hh, *wm_ptr, &key_obj, sizeof(jsval_t), entry); 10748 + return mkval(T_BOOL, entry ? 1 : 0); 10749 + } 10750 + 10751 + static jsval_t weakmap_delete(struct js *js, jsval_t *args, int nargs) { 10752 + if (nargs < 1) return js_mkerr(js, "WeakMap.delete() requires 1 argument"); 10753 + 10754 + jsval_t this_val = js->this_val; 10755 + weakmap_entry_t **wm_ptr = get_weakmap_from_obj(js, this_val); 10756 + if (!wm_ptr) return mkval(T_BOOL, 0); 10757 + 10758 + if (vtype(args[0]) != T_OBJ) return mkval(T_BOOL, 0); 10759 + 10760 + jsval_t key_obj = args[0]; 10761 + weakmap_entry_t *entry; 10762 + HASH_FIND(hh, *wm_ptr, &key_obj, sizeof(jsval_t), entry); 10763 + if (entry) { 10764 + HASH_DEL(*wm_ptr, entry); 10765 + ANT_GC_FREE(entry); 10766 + return mkval(T_BOOL, 1); 10767 + } 10768 + return mkval(T_BOOL, 0); 10769 + } 10770 + 10771 + static jsval_t weakset_add(struct js *js, jsval_t *args, int nargs) { 10772 + if (nargs < 1) return js_mkerr(js, "WeakSet.add() requires 1 argument"); 10773 + 10774 + jsval_t this_val = js->this_val; 10775 + weakset_entry_t **ws_ptr = get_weakset_from_obj(js, this_val); 10776 + if (!ws_ptr) return js_mkerr(js, "Invalid WeakSet object"); 10777 + 10778 + if (vtype(args[0]) != T_OBJ) { 10779 + return js_mkerr(js, "WeakSet value must be an object"); 10780 + } 10781 + 10782 + jsval_t value_obj = args[0]; 10783 + 10784 + weakset_entry_t *entry; 10785 + HASH_FIND(hh, *ws_ptr, &value_obj, sizeof(jsval_t), entry); 10786 + 10787 + if (!entry) { 10788 + entry = (weakset_entry_t *)ANT_GC_MALLOC(sizeof(weakset_entry_t)); 10789 + if (!entry) return js_mkerr(js, "out of memory"); 10790 + entry->value_obj = value_obj; 10791 + HASH_ADD(hh, *ws_ptr, value_obj, sizeof(jsval_t), entry); 10792 + } 10793 + 10794 + return this_val; 10795 + } 10796 + 10797 + static jsval_t weakset_has(struct js *js, jsval_t *args, int nargs) { 10798 + if (nargs < 1) return js_mkerr(js, "WeakSet.has() requires 1 argument"); 10799 + 10800 + jsval_t this_val = js->this_val; 10801 + weakset_entry_t **ws_ptr = get_weakset_from_obj(js, this_val); 10802 + if (!ws_ptr) return mkval(T_BOOL, 0); 10803 + 10804 + if (vtype(args[0]) != T_OBJ) return mkval(T_BOOL, 0); 10805 + 10806 + jsval_t value_obj = args[0]; 10807 + weakset_entry_t *entry; 10808 + HASH_FIND(hh, *ws_ptr, &value_obj, sizeof(jsval_t), entry); 10809 + 10810 + return mkval(T_BOOL, entry ? 1 : 0); 10811 + } 10812 + 10813 + static jsval_t weakset_delete(struct js *js, jsval_t *args, int nargs) { 10814 + if (nargs < 1) return js_mkerr(js, "WeakSet.delete() requires 1 argument"); 10815 + 10816 + jsval_t this_val = js->this_val; 10817 + weakset_entry_t **ws_ptr = get_weakset_from_obj(js, this_val); 10818 + if (!ws_ptr) return mkval(T_BOOL, 0); 10819 + 10820 + if (vtype(args[0]) != T_OBJ) return mkval(T_BOOL, 0); 10821 + 10822 + jsval_t value_obj = args[0]; 10823 + weakset_entry_t *entry; 10824 + HASH_FIND(hh, *ws_ptr, &value_obj, sizeof(jsval_t), entry); 10825 + 10826 + if (entry) { 10827 + HASH_DEL(*ws_ptr, entry); 10828 + ANT_GC_FREE(entry); 10829 + return mkval(T_BOOL, 1); 10830 + } 10831 + return mkval(T_BOOL, 0); 10832 + } 10833 + 10619 10834 struct js *js_create(void *buf, size_t len) { 10620 10835 ANT_GC_INIT(); 10621 10836 init_free_list(); ··· 10710 10925 setprop(js, set_proto_obj, js_mkstr(js, "clear", 5), js_mkfun(set_clear)); 10711 10926 setprop(js, set_proto_obj, js_mkstr(js, "size", 4), js_mkfun(set_size)); 10712 10927 10928 + jsval_t weakmap_proto = js_mkobj(js); 10929 + set_proto(js, weakmap_proto, object_proto); 10930 + setprop(js, weakmap_proto, js_mkstr(js, "set", 3), js_mkfun(weakmap_set)); 10931 + setprop(js, weakmap_proto, js_mkstr(js, "get", 3), js_mkfun(weakmap_get)); 10932 + setprop(js, weakmap_proto, js_mkstr(js, "has", 3), js_mkfun(weakmap_has)); 10933 + setprop(js, weakmap_proto, js_mkstr(js, "delete", 6), js_mkfun(weakmap_delete)); 10934 + 10935 + jsval_t weakset_proto = js_mkobj(js); 10936 + set_proto(js, weakset_proto, object_proto); 10937 + setprop(js, weakset_proto, js_mkstr(js, "add", 3), js_mkfun(weakset_add)); 10938 + setprop(js, weakset_proto, js_mkstr(js, "has", 3), js_mkfun(weakset_has)); 10939 + setprop(js, weakset_proto, js_mkstr(js, "delete", 6), js_mkfun(weakset_delete)); 10940 + 10713 10941 jsval_t promise_proto = js_mkobj(js); 10714 10942 set_proto(js, promise_proto, object_proto); 10715 10943 setprop(js, promise_proto, js_mkstr(js, "then", 4), js_mkfun(builtin_promise_then)); ··· 10771 10999 setprop(js, set_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Set)); 10772 11000 setprop(js, set_ctor_obj, js_mkstr(js, "prototype", 9), set_proto_obj); 10773 11001 setprop(js, glob, js_mkstr(js, "Set", 3), mkval(T_FUNC, vdata(set_ctor_obj))); 11002 + 11003 + jsval_t weakmap_ctor_obj = mkobj(js, 0); 11004 + set_proto(js, weakmap_ctor_obj, function_proto); 11005 + setprop(js, weakmap_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_WeakMap)); 11006 + setprop(js, weakmap_ctor_obj, js_mkstr(js, "prototype", 9), weakmap_proto); 11007 + setprop(js, glob, js_mkstr(js, "WeakMap", 7), mkval(T_FUNC, vdata(weakmap_ctor_obj))); 11008 + 11009 + jsval_t weakset_ctor_obj = mkobj(js, 0); 11010 + set_proto(js, weakset_ctor_obj, function_proto); 11011 + setprop(js, weakset_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_WeakSet)); 11012 + setprop(js, weakset_ctor_obj, js_mkstr(js, "prototype", 9), weakset_proto); 11013 + setprop(js, glob, js_mkstr(js, "WeakSet", 7), mkval(T_FUNC, vdata(weakset_ctor_obj))); 10774 11014 10775 11015 jsval_t err_ctor_obj = mkobj(js, 0); 10776 11016 set_proto(js, err_ctor_obj, function_proto);
+72
tests/test_weakmap.js
··· 1 + // Test WeakMap functionality 2 + console.log('=== WeakMap Tests ==='); 3 + 4 + const wm = new WeakMap(); 5 + 6 + // Test with object keys 7 + const key1 = { id: 1 }; 8 + const key2 = { id: 2 }; 9 + const key3 = { id: 3 }; 10 + 11 + // Test set and get 12 + wm.set(key1, 'value1'); 13 + wm.set(key2, { data: 42 }); 14 + wm.set(key3, true); 15 + 16 + console.log('Get key1:', wm.get(key1)); // Should be 'value1' 17 + console.log('Get key2:', wm.get(key2)); // Should be { data: 42 } 18 + console.log('Get key3:', wm.get(key3)); // Should be true 19 + 20 + // Test has() 21 + console.log('Has key1:', wm.has(key1)); // Should be true 22 + console.log('Has key2:', wm.has(key2)); // Should be true 23 + const key4 = { id: 4 }; 24 + console.log('Has key4 (not added):', wm.has(key4)); // Should be false 25 + 26 + // Test delete() 27 + console.log('Delete key2:', wm.delete(key2)); // Should be true 28 + console.log('Has key2 after delete:', wm.has(key2)); // Should be false 29 + console.log('Get key2 after delete:', wm.get(key2)); // Should be undefined 30 + 31 + // Test that key1 and key3 are still there 32 + console.log('Has key1 after delete key2:', wm.has(key1)); // Should be true 33 + console.log('Has key3 after delete key2:', wm.has(key3)); // Should be true 34 + 35 + // Test overwrite 36 + wm.set(key1, 'newvalue1'); 37 + console.log('Get key1 after overwrite:', wm.get(key1)); // Should be 'newvalue1' 38 + 39 + // Test that primitive keys throw errors 40 + try { 41 + wm.set('string', 'value'); 42 + console.log('ERROR: Should have thrown for string key'); 43 + } catch (e) { 44 + console.log('Correctly threw error for string key:', e.message); 45 + } 46 + 47 + try { 48 + wm.set(123, 'value'); 49 + console.log('ERROR: Should have thrown for number key'); 50 + } catch (e) { 51 + console.log('Correctly threw error for number key:', e.message); 52 + } 53 + 54 + try { 55 + wm.set(null, 'value'); 56 + console.log('ERROR: Should have thrown for null key'); 57 + } catch (e) { 58 + console.log('Correctly threw error for null key:', e.message); 59 + } 60 + 61 + // Test get/has/delete with non-object keys (should return undefined/false) 62 + console.log('Get with string key:', wm.get('string')); // Should be undefined 63 + console.log('Has with number key:', wm.has(123)); // Should be false 64 + console.log('Delete with boolean key:', wm.delete(true)); // Should be false 65 + 66 + // Test multiple WeakMaps 67 + const wm2 = new WeakMap(); 68 + wm2.set(key1, 'different value'); 69 + console.log('Get key1 from wm:', wm.get(key1)); // Should be 'newvalue1' 70 + console.log('Get key1 from wm2:', wm2.get(key1)); // Should be 'different value' 71 + 72 + console.log('WeakMap tests completed!');
+85
tests/test_weakset.js
··· 1 + // Test WeakSet functionality 2 + console.log('=== WeakSet Tests ==='); 3 + 4 + const ws = new WeakSet(); 5 + 6 + // Test with object values 7 + const obj1 = { id: 1 }; 8 + const obj2 = { id: 2 }; 9 + const obj3 = { id: 3 }; 10 + 11 + // Test add and has 12 + ws.add(obj1); 13 + ws.add(obj2); 14 + ws.add(obj3); 15 + 16 + console.log('Has obj1:', ws.has(obj1)); // Should be true 17 + console.log('Has obj2:', ws.has(obj2)); // Should be true 18 + console.log('Has obj3:', ws.has(obj3)); // Should be true 19 + 20 + const obj4 = { id: 4 }; 21 + console.log('Has obj4 (not added):', ws.has(obj4)); // Should be false 22 + 23 + // Test delete() 24 + console.log('Delete obj2:', ws.delete(obj2)); // Should be true 25 + console.log('Has obj2 after delete:', ws.has(obj2)); // Should be false 26 + 27 + // Test that obj1 and obj3 are still there 28 + console.log('Has obj1 after delete obj2:', ws.has(obj1)); // Should be true 29 + console.log('Has obj3 after delete obj2:', ws.has(obj3)); // Should be true 30 + 31 + // Test adding the same object twice (should not throw) 32 + ws.add(obj1); 33 + console.log('Has obj1 after re-adding:', ws.has(obj1)); // Should still be true 34 + 35 + // Test that primitive values throw errors 36 + try { 37 + ws.add('string'); 38 + console.log('ERROR: Should have thrown for string value'); 39 + } catch (e) { 40 + console.log('Correctly threw error for string value:', e.message); 41 + } 42 + 43 + try { 44 + ws.add(123); 45 + console.log('ERROR: Should have thrown for number value'); 46 + } catch (e) { 47 + console.log('Correctly threw error for number value:', e.message); 48 + } 49 + 50 + try { 51 + ws.add(null); 52 + console.log('ERROR: Should have thrown for null value'); 53 + } catch (e) { 54 + console.log('Correctly threw error for null value:', e.message); 55 + } 56 + 57 + try { 58 + ws.add(undefined); 59 + console.log('ERROR: Should have thrown for undefined value'); 60 + } catch (e) { 61 + console.log('Correctly threw error for undefined value:', e.message); 62 + } 63 + 64 + // Test has/delete with non-object values (should return false) 65 + console.log('Has with string:', ws.has('string')); // Should be false 66 + console.log('Has with number:', ws.has(123)); // Should be false 67 + console.log('Delete with boolean:', ws.delete(true)); // Should be false 68 + 69 + // Test multiple WeakSets with the same object 70 + const ws2 = new WeakSet(); 71 + ws2.add(obj1); 72 + console.log('Has obj1 in ws:', ws.has(obj1)); // Should be true 73 + console.log('Has obj1 in ws2:', ws2.has(obj1)); // Should be true 74 + 75 + // Delete from ws should not affect ws2 76 + ws.delete(obj1); 77 + console.log('Has obj1 in ws after delete:', ws.has(obj1)); // Should be false 78 + console.log('Has obj1 in ws2 after delete from ws:', ws2.has(obj1)); // Should be true 79 + 80 + // Test chaining 81 + ws.add(obj1).add(obj2); 82 + console.log('Has obj1 after chaining:', ws.has(obj1)); // Should be true 83 + console.log('Has obj2 after chaining:', ws.has(obj2)); // Should be true 84 + 85 + console.log('WeakSet tests completed!');