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 SLOT_PRIMITIVE to internal_slots, migrate to js_call for String

+68 -34
+1
include/config.h
··· 48 48 SLOT_NAME, 49 49 SLOT_MAP, 50 50 SLOT_SET, 51 + SLOT_PRIMITIVE, 51 52 SLOT_MAX = 255 52 53 } internal_slot_t; 53 54
+1
include/config.h.in
··· 40 40 SLOT_NAME, 41 41 SLOT_MAP, 42 42 SLOT_SET, 43 + SLOT_PRIMITIVE, 43 44 SLOT_MAX = 255 44 45 } internal_slot_t; 45 46
+1 -1
meson.build
··· 96 96 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 97 97 98 98 version_conf = configuration_data() 99 - version_conf.set('ANT_VERSION', '0.3.2.9') 99 + version_conf.set('ANT_VERSION', '0.3.2.10') 100 100 version_conf.set('ANT_GIT_HASH', git_hash) 101 101 version_conf.set('ANT_BUILD_DATE', build_date) 102 102
+18 -33
src/ant.c
··· 814 814 815 815 static jsval_t unwrap_primitive(struct js *js, jsval_t val) { 816 816 if (vtype(val) != T_OBJ) return val; 817 - jsoff_t prim_off = lkp(js, val, "__primitive_value__", 19); 818 - if (prim_off == 0) return val; 819 - return resolveprop(js, mkval(T_PROP, prim_off)); 817 + jsval_t prim = get_slot(js, val, SLOT_PRIMITIVE); 818 + if (vtype(prim) == T_UNDEF) return val; 819 + return prim; 820 820 } 821 821 822 822 static jsval_t to_string_val(struct js *js, jsval_t val) { 823 823 uint8_t t = vtype(val); 824 824 if (t == T_STR) return val; 825 825 if (t == T_OBJ) { 826 - jsoff_t prim_off = lkp(js, val, "__primitive_value__", 19); 827 - if (prim_off != 0) { 828 - jsval_t prim = resolveprop(js, mkval(T_PROP, prim_off)); 829 - if (vtype(prim) == T_STR) return prim; 830 - } 831 - jsoff_t ts_off = lkp_proto(js, val, "toString", 8); 832 - if (ts_off != 0) { 833 - jsval_t ts_fn = resolveprop(js, mkval(T_PROP, ts_off)); 834 - if (vtype(ts_fn) == T_FUNC || vtype(ts_fn) == T_CFUNC) { 835 - jsval_t saved_this = js->this_val; 836 - js->this_val = val; 837 - jsval_t result = call_js_with_args(js, ts_fn, NULL, 0); 838 - js->this_val = saved_this; 839 - if (vtype(result) == T_STR) return result; 840 - } 841 - } 826 + jsval_t prim = get_slot(js, val, SLOT_PRIMITIVE); 827 + if (vtype(prim) == T_STR) return prim; 842 828 } 843 - 844 - const char *s = js_str(js, val); 845 - return js_mkstr(js, s, strlen(s)); 829 + return js_call_toString(js, val); 846 830 } 847 831 848 832 static void free_coroutine(coroutine_t *coro); ··· 6067 6051 } 6068 6052 6069 6053 L_TOK_PLUS: { 6070 - if (vtype(l) == T_BIGINT && vtype(r) == T_BIGINT) return bigint_add(js, l, r); 6071 - if (vtype(l) == T_BIGINT || vtype(r) == T_BIGINT) 6072 - return js_mkerr(js, "Cannot mix BigInt value and other types"); 6073 - if (is_non_numeric(l) || is_non_numeric(r) || (vtype(l) == T_STR && vtype(r) == T_STR)) { 6054 + jsval_t lu = unwrap_primitive(js, l); 6055 + jsval_t ru = unwrap_primitive(js, r); 6056 + if (vtype(lu) == T_BIGINT && vtype(ru) == T_BIGINT) return bigint_add(js, lu, ru); 6057 + if (vtype(lu) == T_BIGINT || vtype(ru) == T_BIGINT) return js_mkerr(js, "Cannot mix BigInt value and other types"); 6058 + if (is_non_numeric(lu) || is_non_numeric(ru) || (vtype(lu) == T_STR && vtype(ru) == T_STR)) { 6074 6059 jsval_t l_str = coerce_to_str(js, l); 6075 6060 if (is_err(l_str)) return l_str; 6076 6061 jsval_t r_str = coerce_to_str(js, r); ··· 11046 11031 sval = js_mkstr(js, str, strlen(str)); 11047 11032 } 11048 11033 } 11049 - if (vtype(js->this_val) == T_OBJ && lkp(js, js->this_val, "__primitive_value__", 19) == 0) { 11050 - setprop(js, js->this_val, js_mkstr(js, "__primitive_value__", 19), sval); 11034 + if (vtype(js->this_val) == T_OBJ && vtype(get_slot(js, js->this_val, SLOT_PRIMITIVE)) == T_UNDEF) { 11035 + set_slot(js, js->this_val, SLOT_PRIMITIVE, sval); 11051 11036 jsval_t proto = get_ctor_proto(js, "String", 6); 11052 11037 if (vtype(proto) == T_OBJ) set_proto(js, js->this_val, proto); 11053 11038 jsoff_t slen; ··· 11146 11131 nval = tov(0.0); 11147 11132 } 11148 11133 } 11149 - if (vtype(js->this_val) == T_OBJ && lkp(js, js->this_val, "__primitive_value__", 19) == 0) { 11150 - setprop(js, js->this_val, js_mkstr(js, "__primitive_value__", 19), nval); 11134 + if (vtype(js->this_val) == T_OBJ && vtype(get_slot(js, js->this_val, SLOT_PRIMITIVE)) == T_UNDEF) { 11135 + set_slot(js, js->this_val, SLOT_PRIMITIVE, nval); 11151 11136 jsval_t proto = get_ctor_proto(js, "Number", 6); 11152 11137 if (vtype(proto) == T_OBJ) set_proto(js, js->this_val, proto); 11153 11138 } ··· 11156 11141 11157 11142 static jsval_t builtin_Boolean(struct js *js, jsval_t *args, int nargs) { 11158 11143 jsval_t bval = mkval(T_BOOL, nargs > 0 && js_truthy(js, args[0]) ? 1 : 0); 11159 - if (vtype(js->this_val) == T_OBJ && lkp(js, js->this_val, "__primitive_value__", 19) == 0) { 11160 - setprop(js, js->this_val, js_mkstr(js, "__primitive_value__", 19), bval); 11144 + if (vtype(js->this_val) == T_OBJ && vtype(get_slot(js, js->this_val, SLOT_PRIMITIVE)) == T_UNDEF) { 11145 + set_slot(js, js->this_val, SLOT_PRIMITIVE, bval); 11161 11146 jsval_t proto = get_ctor_proto(js, "Boolean", 7); 11162 11147 if (vtype(proto) == T_OBJ) set_proto(js, js->this_val, proto); 11163 11148 } ··· 11184 11169 if (t == T_STR || t == T_NUM || t == T_BOOL || t == T_BIGINT) { 11185 11170 jsval_t wrapper = js_mkobj(js); 11186 11171 if (is_err(wrapper)) return wrapper; 11187 - setprop(js, wrapper, js_mkstr(js, "__primitive_value__", 19), arg); 11172 + set_slot(js, wrapper, SLOT_PRIMITIVE, arg); 11188 11173 jsval_t proto = get_prototype_for_type(js, t); 11189 11174 if (vtype(proto) == T_OBJ) set_proto(js, wrapper, proto); 11190 11175 return wrapper;
+47
tests/test_primitive_wrappers.js
··· 1 + // Test primitive wrapper objects with SLOT_PRIMITIVE 2 + 3 + let passed = 0; 4 + let failed = 0; 5 + 6 + function test(name, condition) { 7 + if (condition) { 8 + console.log("โœ“", name); 9 + passed++; 10 + } else { 11 + console.log("โœ—", name); 12 + failed++; 13 + } 14 + } 15 + 16 + // String wrapper 17 + let s = new String("hello"); 18 + test("String wrapper typeof", typeof s === "object"); 19 + test("String wrapper + concat", s + " world" === "hello world"); 20 + test("String wrapper length", s.length === 5); 21 + test("String wrapper valueOf", s.valueOf() === "hello"); 22 + 23 + // Number wrapper 24 + let n = new Number(42); 25 + test("Number wrapper typeof", typeof n === "object"); 26 + test("Number wrapper + arithmetic", n + 8 === 50); 27 + test("Number wrapper valueOf", n.valueOf() === 42); 28 + 29 + // Boolean wrapper 30 + let b = new Boolean(true); 31 + test("Boolean wrapper typeof", typeof b === "object"); 32 + test("Boolean wrapper is truthy", !!b === true); 33 + test("Boolean wrapper valueOf", b.valueOf() === true); 34 + 35 + // Slot should be hidden from enumeration 36 + let sKeys = Object.keys(s); 37 + test("String keys excludes internal slot", !sKeys.includes("__primitive_value__")); 38 + 39 + let nKeys = Object.keys(n); 40 + test("Number keys excludes internal slot", !nKeys.includes("__primitive_value__")); 41 + 42 + // Object() wrapping primitives 43 + let wrapped = Object("test"); 44 + test("Object(string) is object", typeof wrapped === "object"); 45 + test("Object(string) valueOf", wrapped.valueOf() === "test"); 46 + 47 + console.log("\nResults:", passed, "passed,", failed, "failed");