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 special global properties in object stringification

+211 -19
+1
include/modules/symbol.h
··· 8 8 9 9 const char *get_iterator_sym_key(void); 10 10 const char *get_toStringTag_sym_key(void); 11 + const char *get_symbol_description_from_key(const char *sym_key, size_t key_len); 11 12 12 13 #endif
+1 -1
meson.build
··· 75 75 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 76 76 77 77 version_conf = configuration_data() 78 - version_conf.set('ANT_VERSION', '0.2.0.7') 78 + version_conf.set('ANT_VERSION', '0.2.0.8') 79 79 version_conf.set('ANT_GIT_HASH', git_hash) 80 80 version_conf.set('ANT_BUILD_DATE', build_date) 81 81
+184 -18
src/ant.c
··· 1186 1186 static size_t strkey(struct js *js, jsval_t value, char *buf, size_t len) { 1187 1187 jsoff_t slen, off = vstr(js, value, &slen); 1188 1188 const char *str = (const char *) &js->mem[off]; 1189 + 1190 + const char *sym_desc = get_symbol_description_from_key(str, slen); 1191 + if (sym_desc) { 1192 + size_t n = 0; 1193 + n += cpy(buf + n, len - n, "[", 1); 1194 + n += cpy(buf + n, len - n, sym_desc, strlen(sym_desc)); 1195 + n += cpy(buf + n, len - n, "]", 1); 1196 + return n; 1197 + } 1198 + 1189 1199 if (is_valid_identifier(str, slen)) { 1190 1200 return cpy(buf, len, str, slen); 1191 1201 } ··· 1413 1423 jsval_t desc_obj = resolveprop(js, mkval(T_PROP, desc_off)); 1414 1424 if (vtype(desc_obj) != T_OBJ) goto check_done; 1415 1425 1426 + jsoff_t get_off = lkp(js, desc_obj, "get", 3); 1427 + jsoff_t set_off = lkp(js, desc_obj, "set", 3); 1428 + if (get_off != 0 || set_off != 0) { 1429 + jsval_t get_val = get_off ? resolveprop(js, mkval(T_PROP, get_off)) : js_mkundef(); 1430 + jsval_t set_val = set_off ? resolveprop(js, mkval(T_PROP, set_off)) : js_mkundef(); 1431 + if ((vtype(get_val) == T_FUNC || vtype(get_val) == T_CFUNC) || 1432 + (vtype(set_val) == T_FUNC || vtype(set_val) == T_CFUNC)) { 1433 + should_hide = true; 1434 + goto check_done; 1435 + } 1436 + } 1437 + 1416 1438 jsoff_t enumerable_off = lkp(js, desc_obj, "enumerable", 10); 1417 1439 if (enumerable_off == 0) goto check_done; 1418 1440 ··· 1427 1449 if (!first) n += cpy(buf + n, len - n, ",\n", 2); 1428 1450 first = false; 1429 1451 n += add_indent(buf + n, len - n, stringify_indent); 1430 - n += strkey(js, mkval(T_STR, koff), buf + n, len - n); 1431 - n += cpy(buf + n, len - n, ": ", 2); 1432 - n += tostr(js, val, buf + n, len - n); 1452 + 1453 + bool is_special_global = false; 1454 + if (vtype(val) == T_UNDEF && streq(key, klen, "undefined", 9)) { 1455 + is_special_global = true; 1456 + } else if (vtype(val) == T_NUM) { 1457 + double d = tod(val); 1458 + if (isinf(d) && d > 0 && streq(key, klen, "Infinity", 8)) { 1459 + is_special_global = true; 1460 + } else if (isnan(d) && streq(key, klen, "NaN", 3)) { 1461 + is_special_global = true; 1462 + } 1463 + } 1464 + 1465 + if (is_special_global) { 1466 + n += tostr(js, val, buf + n, len - n); 1467 + } else { 1468 + n += strkey(js, mkval(T_STR, koff), buf + n, len - n); 1469 + n += cpy(buf + n, len - n, ": ", 2); 1470 + n += tostr(js, val, buf + n, len - n); 1471 + } 1433 1472 } 1434 1473 next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK); 1435 1474 } 1436 1475 1437 - jsoff_t proto_off = lkp(js, obj, "__proto__", 9); 1438 - if (proto_off != 0) { 1439 - jsval_t proto_val = resolveprop(js, mkval(T_PROP, proto_off)); 1440 - if (vtype(proto_val) == T_OBJ) n += print_prototype(js, proto_val, buf + n, len - n, &first); 1476 + next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | CONSTMASK | ARRMASK); 1477 + while (next < js->brk && next != 0) { 1478 + jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 1479 + jsoff_t klen = offtolen(loadoff(js, koff)); 1480 + const char *key = (char *) &js->mem[koff + sizeof(koff)]; 1481 + 1482 + bool is_desc = (klen > 7 && key[0] == '_' && key[1] == '_' && key[2] == 'd' && key[3] == 'e' && key[4] == 's' && key[5] == 'c' && key[6] == '_'); 1483 + if (is_desc) { 1484 + jsval_t desc_obj = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 1485 + desc_obj = resolveprop(js, desc_obj); 1486 + if (vtype(desc_obj) == T_OBJ) { 1487 + jsoff_t get_off = lkp(js, desc_obj, "get", 3); 1488 + jsoff_t set_off = lkp(js, desc_obj, "set", 3); 1489 + bool has_getter = false, has_setter = false; 1490 + 1491 + if (get_off != 0) { 1492 + jsval_t get_val = resolveprop(js, mkval(T_PROP, get_off)); 1493 + has_getter = (vtype(get_val) == T_FUNC || vtype(get_val) == T_CFUNC); 1494 + } 1495 + if (set_off != 0) { 1496 + jsval_t set_val = resolveprop(js, mkval(T_PROP, set_off)); 1497 + has_setter = (vtype(set_val) == T_FUNC || vtype(set_val) == T_CFUNC); 1498 + } 1499 + 1500 + if (has_getter || has_setter) { 1501 + jsoff_t enumerable_off = lkp(js, desc_obj, "enumerable", 10); 1502 + bool is_enumerable = true; 1503 + if (enumerable_off != 0) { 1504 + jsval_t enumerable_val = resolveprop(js, mkval(T_PROP, enumerable_off)); 1505 + is_enumerable = js_truthy(js, enumerable_val); 1506 + } 1507 + 1508 + if (is_enumerable) { 1509 + const char *prop_name = key + 7; 1510 + size_t prop_len = klen - 7; 1511 + 1512 + if (!first) n += cpy(buf + n, len - n, ",\n", 2); 1513 + first = false; 1514 + n += add_indent(buf + n, len - n, stringify_indent); 1515 + n += cpy(buf + n, len - n, prop_name, prop_len); 1516 + n += cpy(buf + n, len - n, ": ", 2); 1517 + 1518 + if (has_getter && has_setter) { 1519 + n += cpy(buf + n, len - n, "[Getter/Setter]", 15); 1520 + } else if (has_getter) { 1521 + n += cpy(buf + n, len - n, "[Getter]", 8); 1522 + } else { 1523 + n += cpy(buf + n, len - n, "[Setter]", 8); 1524 + } 1525 + } 1526 + } 1527 + } 1528 + } 1529 + next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK); 1441 1530 } 1442 1531 1443 1532 stringify_indent--; ··· 1560 1649 if (klen == 13 && memcmp(key, "__field_count", 13) == 0) return true; 1561 1650 if (klen == 8 && memcmp(key, "__fields", 8) == 0) return true; 1562 1651 if (klen == 8 && memcmp(key, "__source", 8) == 0) return true; 1652 + if (klen >= 9 && memcmp(key, "__sym_", 6) == 0 && key[klen-1] == '_' && key[klen-2] == '_') return true; 1563 1653 return false; 1564 1654 } 1565 1655 ··· 12710 12800 if (desc_off != 0) { 12711 12801 jsval_t desc_obj = resolveprop(js, mkval(T_PROP, desc_off)); 12712 12802 if (vtype(desc_obj) == T_OBJ) { 12803 + jsoff_t get_off = lkp(js, desc_obj, "get", 3); 12804 + jsoff_t set_off = lkp(js, desc_obj, "set", 3); 12805 + if (get_off != 0 || set_off != 0) { 12806 + jsval_t get_val = get_off ? resolveprop(js, mkval(T_PROP, get_off)) : js_mkundef(); 12807 + jsval_t set_val = set_off ? resolveprop(js, mkval(T_PROP, set_off)) : js_mkundef(); 12808 + if ((vtype(get_val) == T_FUNC || vtype(get_val) == T_CFUNC) || 12809 + (vtype(set_val) == T_FUNC || vtype(set_val) == T_CFUNC)) { 12810 + continue; 12811 + } 12812 + } 12713 12813 jsoff_t enum_off = lkp(js, desc_obj, "enumerable", 10); 12714 12814 if (enum_off != 0) { 12715 12815 jsval_t enum_val = resolveprop(js, mkval(T_PROP, enum_off)); ··· 12725 12825 jsval_t key_val = js_mkstr(js, key, klen); 12726 12826 setprop(js, arr, idx_key, key_val); 12727 12827 idx++; 12828 + } 12829 + } 12830 + 12831 + next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | CONSTMASK | ARRMASK); 12832 + while (next < js->brk && next != 0) { 12833 + jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 12834 + jsoff_t klen = offtolen(loadoff(js, koff)); 12835 + const char *key = (char *) &js->mem[koff + sizeof(koff)]; 12836 + 12837 + next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK); 12838 + 12839 + if (klen > 7 && key[0] == '_' && key[1] == '_' && key[2] == 'd' && 12840 + key[3] == 'e' && key[4] == 's' && key[5] == 'c' && key[6] == '_') { 12841 + jsval_t desc_obj = resolveprop(js, mkval(T_PROP, lkp(js, obj, key, klen))); 12842 + if (vtype(desc_obj) == T_OBJ) { 12843 + jsoff_t get_off = lkp(js, desc_obj, "get", 3); 12844 + jsoff_t set_off = lkp(js, desc_obj, "set", 3); 12845 + bool has_accessor = false; 12846 + 12847 + if (get_off != 0) { 12848 + jsval_t get_val = resolveprop(js, mkval(T_PROP, get_off)); 12849 + if (vtype(get_val) == T_FUNC || vtype(get_val) == T_CFUNC) has_accessor = true; 12850 + } 12851 + if (set_off != 0) { 12852 + jsval_t set_val = resolveprop(js, mkval(T_PROP, set_off)); 12853 + if (vtype(set_val) == T_FUNC || vtype(set_val) == T_CFUNC) has_accessor = true; 12854 + } 12855 + 12856 + if (has_accessor) { 12857 + jsoff_t enum_off = lkp(js, desc_obj, "enumerable", 10); 12858 + bool is_enumerable = true; 12859 + if (enum_off != 0) { 12860 + jsval_t enum_val = resolveprop(js, mkval(T_PROP, enum_off)); 12861 + is_enumerable = js_truthy(js, enum_val); 12862 + } 12863 + 12864 + if (is_enumerable) { 12865 + const char *prop_name = key + 7; 12866 + size_t prop_len = klen - 7; 12867 + 12868 + char idxstr[16]; 12869 + snprintf(idxstr, sizeof(idxstr), "%u", (unsigned) idx); 12870 + jsval_t idx_key = js_mkstr(js, idxstr, strlen(idxstr)); 12871 + jsval_t key_val = js_mkstr(js, prop_name, prop_len); 12872 + setprop(js, arr, idx_key, key_val); 12873 + idx++; 12874 + } 12875 + } 12876 + } 12728 12877 } 12729 12878 } 12730 12879 ··· 13443 13592 if (vtype(desc) == T_OBJ) { 13444 13593 jsval_t result = js_mkobj(js); 13445 13594 13446 - jsoff_t prop_off = lkp(js, as_obj, key_str, key_len); 13447 - if (prop_off != 0) { 13448 - jsval_t prop_val = resolveprop(js, mkval(T_PROP, prop_off)); 13449 - setprop(js, result, js_mkstr(js, "value", 5), prop_val); 13595 + jsoff_t get_off = lkp(js, desc, "get", 3); 13596 + jsoff_t set_off = lkp(js, desc, "set", 3); 13597 + bool has_getter = false, has_setter = false; 13598 + 13599 + if (get_off != 0) { 13600 + jsval_t get_val = resolveprop(js, mkval(T_PROP, get_off)); 13601 + if (vtype(get_val) == T_FUNC || vtype(get_val) == T_CFUNC) { 13602 + setprop(js, result, js_mkstr(js, "get", 3), get_val); 13603 + has_getter = true; 13604 + } 13605 + } 13606 + if (set_off != 0) { 13607 + jsval_t set_val = resolveprop(js, mkval(T_PROP, set_off)); 13608 + if (vtype(set_val) == T_FUNC || vtype(set_val) == T_CFUNC) { 13609 + setprop(js, result, js_mkstr(js, "set", 3), set_val); 13610 + has_setter = true; 13611 + } 13450 13612 } 13451 13613 13452 - jsoff_t writable_off = lkp(js, desc, "writable", 8); 13453 - if (writable_off != 0) { 13454 - setprop(js, result, js_mkstr(js, "writable", 8), resolveprop(js, mkval(T_PROP, writable_off))); 13614 + if (!has_getter && !has_setter) { 13615 + jsoff_t prop_off = lkp(js, as_obj, key_str, key_len); 13616 + if (prop_off != 0) { 13617 + jsval_t prop_val = resolveprop(js, mkval(T_PROP, prop_off)); 13618 + setprop(js, result, js_mkstr(js, "value", 5), prop_val); 13619 + } 13620 + 13621 + jsoff_t writable_off = lkp(js, desc, "writable", 8); 13622 + if (writable_off != 0) { 13623 + setprop(js, result, js_mkstr(js, "writable", 8), resolveprop(js, mkval(T_PROP, writable_off))); 13624 + } 13455 13625 } 13456 13626 13457 13627 jsoff_t enumerable_off = lkp(js, desc, "enumerable", 10); ··· 19914 20084 setprop(js, map_proto, js_mkstr(js, "clear", 5), js_mkfun(map_clear)); 19915 20085 setprop(js, map_proto, js_mkstr(js, "size", 4), js_mkfun(map_size)); 19916 20086 setprop(js, map_proto, js_mkstr(js, "entries", 7), js_mkfun(map_entries)); 19917 - const char *map_tag_key = get_toStringTag_sym_key(); 19918 - js_set(js, map_proto, map_tag_key, js_mkstr(js, "Map", 3)); 19919 20087 19920 20088 jsval_t set_proto_obj = js_mkobj(js); 19921 20089 set_proto(js, set_proto_obj, object_proto); ··· 19925 20093 setprop(js, set_proto_obj, js_mkstr(js, "clear", 5), js_mkfun(set_clear)); 19926 20094 setprop(js, set_proto_obj, js_mkstr(js, "size", 4), js_mkfun(set_size)); 19927 20095 setprop(js, set_proto_obj, js_mkstr(js, "values", 6), js_mkfun(set_values)); 19928 - const char *set_tag_key = get_toStringTag_sym_key(); 19929 - js_set(js, set_proto_obj, set_tag_key, js_mkstr(js, "Set", 3)); 19930 20096 19931 20097 jsval_t weakmap_proto = js_mkobj(js); 19932 20098 set_proto(js, weakmap_proto, object_proto);
+25
src/modules/symbol.c
··· 177 177 return iter; 178 178 } 179 179 180 + const char *get_symbol_description_from_key(const char *sym_key, size_t key_len) { 181 + if ( 182 + key_len < 9 || sym_key[0] != '_' || sym_key[1] != '_' || 183 + sym_key[2] != 's' || sym_key[3] != 'y' || sym_key[4] != 'm' || sym_key[5] != '_' 184 + ) return NULL; 185 + 186 + if (g_iter_sym_key[0] && strncmp(sym_key, g_iter_sym_key, key_len) == 0 && g_iter_sym_key[key_len] == '\0') return "Symbol.iterator"; 187 + if (g_toStringTag_sym_key[0] && strncmp(sym_key, g_toStringTag_sym_key, key_len) == 0 && g_toStringTag_sym_key[key_len] == '\0') return "Symbol.toStringTag"; 188 + 189 + return "Symbol()"; 190 + } 191 + 180 192 void init_symbol_module(void) { 181 193 struct js *js = rt->js; 182 194 ··· 211 223 jsval_t string_ctor = js_get(js, js_glob(js), "String"); 212 224 jsval_t string_proto = js_get(js, string_ctor, "prototype"); 213 225 js_set(js, string_proto, g_iter_sym_key, js_mkfun(string_iterator)); 226 + 227 + // set internal types before module ready 228 + jsval_t map_ctor = js_get(js, js_glob(js), "Map"); 229 + jsval_t map_proto = js_get(js, map_ctor, "prototype"); 230 + if (js_type(map_proto) == JS_OBJ) { 231 + js_set(js, map_proto, g_toStringTag_sym_key, js_mkstr(js, "Map", 3)); 232 + } 233 + 234 + jsval_t set_ctor = js_get(js, js_glob(js), "Set"); 235 + jsval_t set_proto = js_get(js, set_ctor, "prototype"); 236 + if (js_type(set_proto) == JS_OBJ) { 237 + js_set(js, set_proto, g_toStringTag_sym_key, js_mkstr(js, "Set", 3)); 238 + } 214 239 }