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.

Object.defineProperty

+375 -4
+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.0') 77 + version_conf.set('ANT_VERSION', '0.0.8.1') 78 78 version_conf.set('ANT_GIT_HASH', git_hash) 79 79 version_conf.set('ANT_BUILD_DATE', build_date) 80 80
+184 -3
src/ant.c
··· 1733 1733 } 1734 1734 jsoff_t existing = lkp(js, obj, key, klen); 1735 1735 if (existing > 0) { 1736 - if (is_const_prop(js, existing)) { 1736 + char desc_key[128]; 1737 + snprintf(desc_key, sizeof(desc_key), "__desc_%.*s", (int)klen, key); 1738 + jsoff_t desc_off = lkp(js, obj, desc_key, strlen(desc_key)); 1739 + 1740 + if (desc_off != 0) { 1741 + jsval_t desc_obj = resolveprop(js, mkval(T_PROP, desc_off)); 1742 + if (vtype(desc_obj) == T_OBJ) { 1743 + jsoff_t writable_off = lkp(js, desc_obj, "writable", 8); 1744 + if (writable_off != 0) { 1745 + jsval_t writable_val = resolveprop(js, mkval(T_PROP, writable_off)); 1746 + if (!js_truthy(js, writable_val)) { 1747 + if (js->flags & F_STRICT) return js_mkerr(js, "assignment to read-only property"); 1748 + return mkval(T_PROP, existing); 1749 + } 1750 + } 1751 + 1752 + jsoff_t configurable_off = lkp(js, desc_obj, "configurable", 12); 1753 + if (configurable_off != 0) { 1754 + jsval_t configurable_val = resolveprop(js, mkval(T_PROP, configurable_off)); 1755 + if (!js_truthy(js, configurable_val)) { 1756 + if (js->flags & F_STRICT) return js_mkerr(js, "assignment to non-configurable property"); 1757 + return mkval(T_PROP, existing); 1758 + } 1759 + } 1760 + } 1761 + } else if (is_const_prop(js, existing)) { 1737 1762 return js_mkerr(js, "assignment to constant"); 1738 1763 } 1764 + 1739 1765 saveval(js, existing + sizeof(jsoff_t) * 2, v); 1740 1766 return mkval(T_PROP, existing); 1741 1767 } ··· 7443 7469 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 7444 7470 jsoff_t klen = offtolen(loadoff(js, koff)); 7445 7471 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 7446 - if (!streq(key, klen, "__proto__", 9)) { 7472 + 7473 + next = loadoff(js, next) & ~(3U | CONSTMASK); 7474 + 7475 + if (streq(key, klen, "__proto__", 9)) continue; 7476 + if (klen > 7 && memcmp(key, "__desc_", 7) == 0) continue; 7477 + 7478 + bool should_include = true; 7479 + char desc_key[128]; 7480 + snprintf(desc_key, sizeof(desc_key), "__desc_%.*s", (int)klen, key); 7481 + jsoff_t desc_off = lkp(js, obj, desc_key, strlen(desc_key)); 7482 + 7483 + if (desc_off != 0) { 7484 + jsval_t desc_obj = resolveprop(js, mkval(T_PROP, desc_off)); 7485 + if (vtype(desc_obj) == T_OBJ) { 7486 + jsoff_t enum_off = lkp(js, desc_obj, "enumerable", 10); 7487 + if (enum_off != 0) { 7488 + jsval_t enum_val = resolveprop(js, mkval(T_PROP, enum_off)); 7489 + should_include = js_truthy(js, enum_val); 7490 + } 7491 + } 7492 + } 7493 + 7494 + if (should_include) { 7447 7495 char idxstr[16]; 7448 7496 snprintf(idxstr, sizeof(idxstr), "%u", (unsigned) idx); 7449 7497 jsval_t idx_key = js_mkstr(js, idxstr, strlen(idxstr)); ··· 7451 7499 setprop(js, arr, idx_key, key_val); 7452 7500 idx++; 7453 7501 } 7454 - next = loadoff(js, next) & ~(3U | CONSTMASK); 7455 7502 } 7456 7503 7457 7504 jsval_t len_key = js_mkstr(js, "length", 6); ··· 7559 7606 7560 7607 jsoff_t off = lkp(js, as_obj, key_str, key_len); 7561 7608 return mkval(T_BOOL, off != 0 ? 1 : 0); 7609 + } 7610 + 7611 + static jsval_t builtin_object_defineProperty(struct js *js, jsval_t *args, int nargs) { 7612 + if (nargs < 3) return js_mkerr(js, "Object.defineProperty requires 3 arguments"); 7613 + 7614 + jsval_t obj = args[0]; 7615 + jsval_t prop = args[1]; 7616 + jsval_t descriptor = args[2]; 7617 + 7618 + uint8_t t = vtype(obj); 7619 + if (t != T_OBJ && t != T_ARR && t != T_FUNC) { 7620 + return js_mkerr(js, "Object.defineProperty called on non-object"); 7621 + } 7622 + 7623 + if (vtype(prop) != T_STR) { 7624 + return js_mkerr(js, "Property key must be a string"); 7625 + } 7626 + 7627 + if (vtype(descriptor) != T_OBJ) { 7628 + return js_mkerr(js, "Property descriptor must be an object"); 7629 + } 7630 + 7631 + jsval_t as_obj = (t == T_OBJ) ? obj : mkval(T_OBJ, vdata(obj)); 7632 + 7633 + jsoff_t prop_len, prop_off = vstr(js, prop, &prop_len); 7634 + const char *prop_str = (char *) &js->mem[prop_off]; 7635 + 7636 + if (streq(prop_str, prop_len, "__proto__", 9)) { 7637 + return js_mkerr(js, "Cannot define __proto__ property"); 7638 + } 7639 + 7640 + bool has_value = false, has_get = false, has_set = false, has_writable = false; 7641 + jsval_t value = js_mkundef(); 7642 + bool writable = true, enumerable = false, configurable = false; 7643 + 7644 + jsoff_t value_off = lkp(js, descriptor, "value", 5); 7645 + if (value_off != 0) { 7646 + has_value = true; 7647 + value = resolveprop(js, mkval(T_PROP, value_off)); 7648 + } 7649 + 7650 + jsoff_t get_off = lkp(js, descriptor, "get", 3); 7651 + if (get_off != 0) { 7652 + has_get = true; 7653 + jsval_t getter = resolveprop(js, mkval(T_PROP, get_off)); 7654 + if (vtype(getter) != T_FUNC && vtype(getter) != T_UNDEF) { 7655 + return js_mkerr(js, "Getter must be a function"); 7656 + } 7657 + } 7658 + 7659 + jsoff_t set_off = lkp(js, descriptor, "set", 3); 7660 + if (set_off != 0) { 7661 + has_set = true; 7662 + jsval_t setter = resolveprop(js, mkval(T_PROP, set_off)); 7663 + if (vtype(setter) != T_FUNC && vtype(setter) != T_UNDEF) { 7664 + return js_mkerr(js, "Setter must be a function"); 7665 + } 7666 + } 7667 + 7668 + if ((has_value || has_writable) && (has_get || has_set)) { 7669 + return js_mkerr(js, "Invalid property descriptor. Cannot both specify accessors and a value or writable attribute"); 7670 + } 7671 + 7672 + jsoff_t writable_off = lkp(js, descriptor, "writable", 8); 7673 + if (writable_off != 0) { 7674 + has_writable = true; 7675 + jsval_t w_val = resolveprop(js, mkval(T_PROP, writable_off)); 7676 + writable = js_truthy(js, w_val); 7677 + } 7678 + 7679 + jsoff_t enumerable_off = lkp(js, descriptor, "enumerable", 10); 7680 + if (enumerable_off != 0) { 7681 + jsval_t e_val = resolveprop(js, mkval(T_PROP, enumerable_off)); 7682 + enumerable = js_truthy(js, e_val); 7683 + } 7684 + 7685 + jsoff_t configurable_off = lkp(js, descriptor, "configurable", 12); 7686 + if (configurable_off != 0) { 7687 + jsval_t c_val = resolveprop(js, mkval(T_PROP, configurable_off)); 7688 + configurable = js_truthy(js, c_val); 7689 + } 7690 + 7691 + jsoff_t existing_off = lkp(js, as_obj, prop_str, prop_len); 7692 + 7693 + if (existing_off > 0) { 7694 + if (is_const_prop(js, existing_off)) { 7695 + return js_mkerr(js, "Cannot redefine non-configurable property"); 7696 + } 7697 + 7698 + if (has_value) { 7699 + saveval(js, existing_off + sizeof(jsoff_t) * 2, value); 7700 + } 7701 + 7702 + char desc_key[128]; 7703 + snprintf(desc_key, sizeof(desc_key), "__desc_%.*s", (int)prop_len, prop_str); 7704 + jsval_t desc_key_str = js_mkstr(js, desc_key, strlen(desc_key)); 7705 + jsval_t desc_obj = js_mkobj(js); 7706 + setprop(js, desc_obj, js_mkstr(js, "writable", 8), mkval(T_BOOL, writable ? 1 : 0)); 7707 + setprop(js, desc_obj, js_mkstr(js, "enumerable", 10), mkval(T_BOOL, enumerable ? 1 : 0)); 7708 + setprop(js, desc_obj, js_mkstr(js, "configurable", 12), mkval(T_BOOL, configurable ? 1 : 0)); 7709 + setprop(js, as_obj, desc_key_str, desc_obj); 7710 + 7711 + if (!configurable) { 7712 + jsoff_t head = (jsoff_t) vdata(as_obj); 7713 + jsoff_t firstprop = loadoff(js, head); 7714 + if ((firstprop & ~(3U | CONSTMASK)) == existing_off) { 7715 + saveoff(js, head, firstprop | CONSTMASK); 7716 + } 7717 + } 7718 + } else { 7719 + if (has_get || has_set) { 7720 + return js_mkerr(js, "Accessor properties not fully supported"); 7721 + } 7722 + 7723 + if (!has_value) { 7724 + value = js_mkundef(); 7725 + } 7726 + 7727 + jsval_t prop_key = js_mkstr(js, prop_str, prop_len); 7728 + bool mark_const = (!writable || !configurable); 7729 + mkprop(js, as_obj, prop_key, value, mark_const); 7730 + 7731 + char desc_key[128]; 7732 + snprintf(desc_key, sizeof(desc_key), "__desc_%.*s", (int)prop_len, prop_str); 7733 + jsval_t desc_key_str = js_mkstr(js, desc_key, strlen(desc_key)); 7734 + jsval_t desc_obj = js_mkobj(js); 7735 + setprop(js, desc_obj, js_mkstr(js, "writable", 8), mkval(T_BOOL, writable ? 1 : 0)); 7736 + setprop(js, desc_obj, js_mkstr(js, "enumerable", 10), mkval(T_BOOL, enumerable ? 1 : 0)); 7737 + setprop(js, desc_obj, js_mkstr(js, "configurable", 12), mkval(T_BOOL, configurable ? 1 : 0)); 7738 + setprop(js, as_obj, desc_key_str, desc_obj); 7739 + } 7740 + 7741 + return obj; 7562 7742 } 7563 7743 7564 7744 static jsval_t builtin_array_push(struct js *js, jsval_t *args, int nargs) { ··· 10444 10624 setprop(js, obj_func_obj, js_mkstr(js, "setPrototypeOf", 14), js_mkfun(builtin_object_setPrototypeOf)); 10445 10625 setprop(js, obj_func_obj, js_mkstr(js, "create", 6), js_mkfun(builtin_object_create)); 10446 10626 setprop(js, obj_func_obj, js_mkstr(js, "hasOwn", 6), js_mkfun(builtin_object_hasOwn)); 10627 + setprop(js, obj_func_obj, js_mkstr(js, "defineProperty", 14), js_mkfun(builtin_object_defineProperty)); 10447 10628 setprop(js, obj_func_obj, js_mkstr(js, "prototype", 9), object_proto); 10448 10629 setprop(js, glob, js_mkstr(js, "Object", 6), mkval(T_FUNC, vdata(obj_func_obj))); 10449 10630
+43
test_define_property.js
··· 1 + // Test Object.defineProperty() 2 + 3 + const object = {}; 4 + 5 + Object.defineProperty(object, "foo", { 6 + value: 42, 7 + writable: false, 8 + }); 9 + 10 + console.log("object.foo =", object.foo); 11 + 12 + // Try to modify (should be prevented by configurable: false default) 13 + try { 14 + object.foo = 77; 15 + console.log("After trying to modify, object.foo =", object.foo); 16 + } catch (e) { 17 + console.log("Cannot modify foo (expected):", e); 18 + } 19 + 20 + // Test with enumerable 21 + const obj2 = {}; 22 + Object.defineProperty(obj2, "bar", { 23 + value: "hello", 24 + enumerable: true, 25 + configurable: true 26 + }); 27 + 28 + console.log("obj2.bar =", obj2.bar); 29 + console.log("Object.keys(obj2) =", Object.keys(obj2)); 30 + 31 + // Test with non-enumerable property 32 + const obj3 = {}; 33 + Object.defineProperty(obj3, "hidden", { 34 + value: "secret", 35 + enumerable: false 36 + }); 37 + obj3.visible = "public"; 38 + 39 + console.log("obj3.hidden =", obj3.hidden); 40 + console.log("obj3.visible =", obj3.visible); 41 + console.log("Object.keys(obj3) =", Object.keys(obj3)); 42 + 43 + console.log("All tests passed!");
+61
test_define_property_edge_cases.js
··· 1 + // Test edge cases for Object.defineProperty() 2 + 3 + console.log("Test 1: Error when called with < 3 arguments"); 4 + try { 5 + Object.defineProperty({}, "foo"); 6 + console.log("FAIL: Should have thrown error"); 7 + } catch (e) { 8 + console.log("PASS: Correctly throws error"); 9 + } 10 + 11 + console.log("\nTest 2: Error when first argument is not an object"); 12 + try { 13 + Object.defineProperty(42, "foo", { value: 1 }); 14 + console.log("FAIL: Should have thrown error"); 15 + } catch (e) { 16 + console.log("PASS: Correctly throws error for non-object"); 17 + } 18 + 19 + console.log("\nTest 3: Error when descriptor is not an object"); 20 + try { 21 + Object.defineProperty({}, "foo", "not an object"); 22 + console.log("FAIL: Should have thrown error"); 23 + } catch (e) { 24 + console.log("PASS: Correctly throws error for non-object descriptor"); 25 + } 26 + 27 + console.log("\nTest 4: Error when mixing data and accessor descriptors"); 28 + try { 29 + Object.defineProperty({}, "foo", { 30 + value: 42, 31 + get: function() { return 0; } 32 + }); 33 + console.log("FAIL: Should have thrown error"); 34 + } catch (e) { 35 + console.log("PASS: Correctly throws error for mixed descriptors"); 36 + } 37 + 38 + console.log("\nTest 5: Can define property with just value"); 39 + const obj5 = {}; 40 + Object.defineProperty(obj5, "test", { value: 100 }); 41 + console.log("PASS: Property defined with just value:", obj5.test); 42 + 43 + console.log("\nTest 6: Cannot define __proto__ property"); 44 + try { 45 + Object.defineProperty({}, "__proto__", { value: {} }); 46 + console.log("FAIL: Should have thrown error"); 47 + } catch (e) { 48 + console.log("PASS: Correctly prevents __proto__ definition"); 49 + } 50 + 51 + console.log("\nTest 7: Works with arrays"); 52 + const arr = [1, 2, 3]; 53 + Object.defineProperty(arr, "myProp", { value: "test" }); 54 + console.log("PASS: Works with arrays:", arr.myProp); 55 + 56 + console.log("\nTest 8: Works with functions"); 57 + function myFunc() {} 58 + Object.defineProperty(myFunc, "customProp", { value: 42 }); 59 + console.log("PASS: Works with functions:", myFunc.customProp); 60 + 61 + console.log("\nAll edge case tests completed!");
+33
test_define_property_simple.js
··· 1 + // Simple test matching MDN example 2 + const object = {}; 3 + 4 + Object.defineProperty(object, "foo", { 5 + value: 42, 6 + writable: false, 7 + }); 8 + 9 + console.log("object.foo:", object.foo); 10 + // Expected output: 42 11 + 12 + // Test modifying existing property 13 + const obj2 = { bar: 10 }; 14 + console.log("Before defineProperty, obj2.bar:", obj2.bar); 15 + 16 + Object.defineProperty(obj2, "bar", { 17 + value: 20 18 + }); 19 + 20 + console.log("After defineProperty, obj2.bar:", obj2.bar); 21 + // Expected output: 20 22 + 23 + // Test return value 24 + const obj3 = {}; 25 + const result = Object.defineProperty(obj3, "test", { 26 + value: 123 27 + }); 28 + 29 + console.log("Returned object is same as input:", result === obj3); 30 + // Expected output: true 31 + 32 + console.log("obj3.test:", obj3.test); 33 + // Expected output: 123
+53
test_define_property_strict.js
··· 1 + "use strict"; 2 + 3 + // Test Object.defineProperty() in strict mode 4 + 5 + const object = {}; 6 + 7 + Object.defineProperty(object, "foo", { 8 + value: 42, 9 + writable: false, 10 + }); 11 + 12 + console.log("object.foo =", object.foo); 13 + 14 + // Try to modify in strict mode (should throw) 15 + try { 16 + object.foo = 77; 17 + console.log("FAIL: Should have thrown an error"); 18 + } catch (e) { 19 + console.log("PASS: Correctly throws in strict mode"); 20 + console.log("object.foo still =", object.foo); 21 + } 22 + 23 + // Test non-configurable property 24 + const obj2 = {}; 25 + Object.defineProperty(obj2, "bar", { 26 + value: "hello", 27 + configurable: false 28 + }); 29 + 30 + try { 31 + obj2.bar = "world"; 32 + console.log("FAIL: Should have thrown an error for non-configurable"); 33 + } catch (e) { 34 + console.log("PASS: Correctly throws for non-configurable in strict mode"); 35 + console.log("obj2.bar still =", obj2.bar); 36 + } 37 + 38 + // Test enumerable 39 + const obj3 = {}; 40 + Object.defineProperty(obj3, "hidden", { 41 + value: "secret", 42 + enumerable: false 43 + }); 44 + 45 + Object.defineProperty(obj3, "visible", { 46 + value: "public", 47 + enumerable: true 48 + }); 49 + 50 + console.log("\nKeys of obj3:", Object.keys(obj3)); 51 + console.log("Expected: only 'visible' should be in keys"); 52 + 53 + console.log("\nAll strict mode tests passed!");