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 symbol module and symbol type

+478 -21
+5 -1
include/ant.h
··· 1 1 #pragma once 2 + #define PRIV_SYMBOL 0x80 2 3 3 4 #include <stdbool.h> 4 5 #include <stddef.h> ··· 10 11 11 12 enum { 12 13 JS_UNDEF, JS_NULL, JS_TRUE, JS_FALSE, JS_STR, JS_NUM, 13 - JS_ERR, JS_PRIV, JS_PROMISE, JS_OBJ, JS_FUNC 14 + JS_ERR, JS_PRIV, JS_PROMISE, JS_OBJ, JS_FUNC, JS_SYMBOL 14 15 }; 15 16 16 17 typedef enum { ··· 62 63 jsval_t js_mkarr(struct js *); 63 64 void js_arr_push(struct js *, jsval_t arr, jsval_t val); 64 65 jsval_t js_mkstr(struct js *, const void *, size_t); 66 + jsval_t js_mksym(struct js *, const char *desc); 65 67 jsval_t js_mkerr(struct js *js, const char *fmt, ...); 66 68 jsval_t js_mkerr_typed(struct js *js, js_err_type_t err_type, const char *fmt, ...); 67 69 jsval_t js_mkfun(jsval_t (*fn)(struct js *, jsval_t *, int)); ··· 78 80 jsval_t js_get_ctor_proto(struct js *, const char *name, size_t len); 79 81 80 82 int js_type(jsval_t val); 83 + int js_type_ex(struct js *js, jsval_t val); 84 + 81 85 int js_getbool(jsval_t val); 82 86 uint8_t vtype(jsval_t val); 83 87
+10
include/modules/symbol.h
··· 1 + #ifndef SYMBOL_H 2 + #define SYMBOL_H 3 + 4 + #include "ant.h" 5 + 6 + void init_symbol_module(void); 7 + jsval_t get_iterator_symbol(void); 8 + const char *get_iterator_sym_key(void); 9 + 10 + #endif
+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.15') 77 + version_conf.set('ANT_VERSION', '0.1.1.16') 78 78 version_conf.set('ANT_GIT_HASH', git_hash) 79 79 version_conf.set('ANT_BUILD_DATE', build_date) 80 80
+247 -19
src/ant.c
··· 24 24 #include "modules/fs.h" 25 25 #include "modules/timer.h" 26 26 #include "modules/fetch.h" 27 + #include "modules/symbol.h" 27 28 28 29 #define MINICORO_IMPL 29 30 #include "minicoro.h" ··· 278 279 }; 279 280 280 281 static const char *typestr_raw(uint8_t t) { 282 + if (t == PRIV_SYMBOL) return "symbol"; 283 + 281 284 const char *names[] = { 282 285 "object", "prop", "string", "undefined", "null", "number", 283 286 "boolean", "function", "coderef", "cfunc", "err", "array", ··· 2536 2539 return js_setprop(js, obj, k, v); 2537 2540 } 2538 2541 2542 + static uint64_t g_symbol_counter = 1; 2543 + 2544 + jsval_t js_mksym(struct js *js, const char *desc) { 2545 + jsval_t sym_obj = mkobj(js, 0); 2546 + uint64_t id = g_symbol_counter++; 2547 + setprop(js, sym_obj, js_mkstr(js, "__sym__", 7), mkval(T_BOOL, 1)); 2548 + setprop(js, sym_obj, js_mkstr(js, "__sym_id", 8), tov((double)id)); 2549 + if (desc) { 2550 + setprop(js, sym_obj, js_mkstr(js, "description", 11), js_mkstr(js, desc, strlen(desc))); 2551 + } else { 2552 + setprop(js, sym_obj, js_mkstr(js, "description", 11), mkval(T_UNDEF, 0)); 2553 + } 2554 + return sym_obj; 2555 + } 2556 + 2557 + static bool is_symbol(struct js *js, jsval_t v) { 2558 + if (vtype(v) != T_OBJ) return false; 2559 + jsoff_t off = lkp(js, v, "__sym__", 7); 2560 + return off != 0; 2561 + } 2562 + 2539 2563 static inline jsoff_t esize(jsoff_t w) { 2540 2564 jsoff_t cleaned = w & ~(GCMASK | CONSTMASK); 2541 2565 switch (cleaned & 3U) { ··· 3559 3583 static jsval_t do_bracket_op(struct js *js, jsval_t l, jsval_t r) { 3560 3584 jsval_t obj = resolveprop(js, l); 3561 3585 jsval_t key_val = resolveprop(js, r); 3562 - char keybuf[32]; 3586 + char keybuf[64]; 3563 3587 const char *keystr; 3564 3588 size_t keylen; 3565 3589 if (vtype(key_val) == T_NUM) { ··· 3571 3595 jsoff_t off = vstr(js, key_val, &slen); 3572 3596 keystr = (char *) &js->mem[off]; 3573 3597 keylen = slen; 3598 + } else if (vtype(key_val) == T_OBJ && is_symbol(js, key_val)) { 3599 + jsval_t sym_id = resolveprop(js, mkval(T_PROP, lkp(js, key_val, "__sym_id", 8))); 3600 + snprintf(keybuf, sizeof(keybuf), "__sym_%.0f__", tod(sym_id)); 3601 + keystr = keybuf; 3602 + keylen = strlen(keybuf); 3574 3603 } else { 3575 3604 return js_mkerr(js, "invalid index type"); 3576 3605 } ··· 3580 3609 } 3581 3610 } 3582 3611 if (vtype(obj) == T_STR) { 3583 - if (vtype(key_val) != T_NUM) { 3584 - return js_mkerr(js, "string indices must be numbers"); 3612 + if (vtype(key_val) == T_NUM) { 3613 + double idx_d = tod(key_val); 3614 + if (idx_d < 0 || idx_d != (double)(long)idx_d) { 3615 + return js_mkundef(); 3616 + } 3617 + jsoff_t idx = (jsoff_t) idx_d; 3618 + jsoff_t str_len = offtolen(loadoff(js, (jsoff_t) vdata(obj))); 3619 + if (idx >= str_len) { 3620 + return js_mkundef(); 3621 + } 3622 + jsoff_t str_off = (jsoff_t) vdata(obj) + sizeof(jsoff_t); 3623 + char ch[2] = {js->mem[str_off + idx], 0}; 3624 + return js_mkstr(js, ch, 1); 3585 3625 } 3586 - double idx_d = tod(key_val); 3587 - if (idx_d < 0 || idx_d != (double)(long)idx_d) { 3588 - return js_mkundef(); 3589 - } 3590 - jsoff_t idx = (jsoff_t) idx_d; 3591 - jsoff_t str_len = offtolen(loadoff(js, (jsoff_t) vdata(obj))); 3592 - if (idx >= str_len) { 3593 - return js_mkundef(); 3594 - } 3595 - jsoff_t str_off = (jsoff_t) vdata(obj) + sizeof(jsoff_t); 3596 - char ch[2] = {js->mem[str_off + idx], 0}; 3597 - return js_mkstr(js, ch, 1); 3626 + jsoff_t off = lkp_proto(js, obj, keystr, keylen); 3627 + if (off != 0) return resolveprop(js, mkval(T_PROP, off)); 3628 + return js_mkundef(); 3598 3629 } 3599 3630 if (vtype(obj) != T_OBJ && vtype(obj) != T_ARR) { 3600 3631 return js_mkerr(js, "cannot index non-object"); 3601 3632 } 3602 - jsoff_t off = lkp(js, obj, keystr, keylen); 3633 + jsoff_t off = lkp_proto(js, obj, keystr, keylen); 3603 3634 if (off == 0) { 3604 3635 jsval_t key = js_mkstr(js, keystr, keylen); 3605 3636 jsval_t prop = setprop(js, obj, key, js_mkundef()); ··· 4459 4490 if (is_assign(op) && vtype(lhs) != T_PROP && vtype(lhs) != T_PROPREF) return js_mkerr(js, "bad lhs"); 4460 4491 4461 4492 switch (op) { 4462 - case TOK_TYPEOF: return js_mkstr(js, typestr(vtype(r)), strlen(typestr(vtype(r)))); 4493 + case TOK_TYPEOF: { 4494 + const char *ts = (vtype(r) == T_OBJ && is_symbol(js, r)) ? "symbol" : typestr(vtype(r)); 4495 + return js_mkstr(js, ts, strlen(ts)); 4496 + } 4463 4497 case TOK_VOID: return js_mkundef(); 4464 4498 case TOK_INSTANCEOF: return do_instanceof(js, l, r); 4465 4499 case TOK_IN: return do_in(js, l, r); ··· 5112 5146 jsval_t res = setprop(js, obj, key, resolveprop(js, val)); 5113 5147 if (is_err(res)) return res; 5114 5148 } 5115 - } else if (!is_computed && id_len > 0 && next(js) == TOK_LPAREN) { 5149 + } else if ( 5150 + (!is_computed && id_len > 0 && next(js) == TOK_LPAREN) || 5151 + (is_computed && next(js) == TOK_LPAREN) 5152 + ) { 5116 5153 uint8_t flags = js->flags; 5117 5154 jsoff_t pos = js->pos - 1; 5118 5155 js->consumed = 1; ··· 5505 5542 case TOK_WINDOW: 5506 5543 case TOK_GLOBAL_THIS: return js_glob(js); 5507 5544 5508 - case TOK_OF: 5545 + case TOK_OF: 5546 + case TOK_FOR: 5509 5547 case TOK_WITH: 5510 5548 case TOK_TYPEOF: 5511 5549 case TOK_FROM: ··· 7153 7191 goto done; 7154 7192 } 7155 7193 } 7194 + } else if (itype == T_OBJ) { 7195 + const char *iter_sym_key = get_iterator_sym_key(); 7196 + jsoff_t iter_off = iter_sym_key ? lkp(js, iterable, iter_sym_key, strlen(iter_sym_key)) : 0; 7197 + if (!iter_off) iter_off = lkp_proto(js, iterable, iter_sym_key, strlen(iter_sym_key)); 7198 + 7199 + if (iter_off) { 7200 + jsval_t iter_fn = loadval(js, iter_off + sizeof(jsoff_t) * 2); 7201 + if (vtype(iter_fn) == T_FUNC) { 7202 + push_this(iterable); 7203 + jsval_t iterator = call_js_with_args(js, iter_fn, NULL, 0); 7204 + pop_this(); 7205 + 7206 + if (is_err(iterator)) { 7207 + res = iterator; 7208 + goto done; 7209 + } 7210 + 7211 + while (true) { 7212 + jsoff_t next_off = lkp(js, iterator, "next", 4); 7213 + if (!next_off) { 7214 + res = js_mkerr(js, "iterator has no next method"); 7215 + goto done; 7216 + } 7217 + jsval_t next_fn = loadval(js, next_off + sizeof(jsoff_t) * 2); 7218 + 7219 + push_this(iterator); 7220 + jsval_t result_obj = call_js_with_args(js, next_fn, NULL, 0); 7221 + pop_this(); 7222 + 7223 + if (is_err(result_obj)) { 7224 + res = result_obj; 7225 + goto done; 7226 + } 7227 + 7228 + jsval_t done_val = js_get(js, result_obj, "done"); 7229 + if (js_truthy(js, done_val)) break; 7230 + 7231 + jsval_t value = js_get(js, result_obj, "value"); 7232 + 7233 + const char *var_name = &js->code[var_name_off]; 7234 + jsoff_t existing = lkp(js, js->scope, var_name, var_name_len); 7235 + if (existing > 0) { 7236 + saveval(js, existing + sizeof(jsoff_t) * 2, value); 7237 + } else { 7238 + jsval_t x = mkprop(js, js->scope, js_mkstr(js, var_name, var_name_len), value, is_const_var); 7239 + if (is_err(x)) { 7240 + res = x; 7241 + goto done; 7242 + } 7243 + } 7244 + 7245 + js->pos = body_start; 7246 + js->consumed = 1; 7247 + js->flags = (flags & ~F_NOEXEC) | F_LOOP; 7248 + v = js_block_or_stmt(js); 7249 + if (is_err(v)) { 7250 + res = v; 7251 + goto done; 7252 + } 7253 + 7254 + if (js->flags & F_BREAK) break; 7255 + if (js->flags & F_RETURN) { 7256 + res = v; 7257 + goto done; 7258 + } 7259 + } 7260 + } else { 7261 + res = js_mkerr(js, "for-of requires iterable"); 7262 + goto done; 7263 + } 7264 + } else { 7265 + res = js_mkerr(js, "for-of requires iterable"); 7266 + goto done; 7267 + } 7156 7268 } else { 7157 7269 res = js_mkerr(js, "for-of requires iterable"); 7158 7270 goto done; ··· 15007 15119 } 15008 15120 15009 15121 static jsval_t map_size(struct js *js, jsval_t *args, int nargs) { 15122 + (void)args; (void)nargs; 15010 15123 jsval_t this_val = js->this_val; 15011 15124 map_entry_t **map_ptr = get_map_from_obj(js, this_val); 15012 15125 if (!map_ptr) return tov(0); ··· 15015 15128 return tov((double)count); 15016 15129 } 15017 15130 15131 + static jsval_t map_iter_next(struct js *js, jsval_t *args, int nargs) { 15132 + (void)args; (void)nargs; 15133 + jsval_t this_val = js->this_val; 15134 + jsval_t idx_val = js_get(js, this_val, "__idx"); 15135 + jsval_t keys = js_get(js, this_val, "__keys"); 15136 + jsval_t vals = js_get(js, this_val, "__vals"); 15137 + jsval_t len_val = js_get(js, this_val, "__len"); 15138 + 15139 + int idx = (int)js_getnum(idx_val); 15140 + int len = (int)js_getnum(len_val); 15141 + 15142 + jsval_t result = js_mkobj(js); 15143 + if (idx >= len) { 15144 + js_set(js, result, "done", js_mktrue()); 15145 + js_set(js, result, "value", js_mkundef()); 15146 + } else { 15147 + char idxstr[16]; 15148 + snprintf(idxstr, sizeof(idxstr), "%d", idx); 15149 + jsval_t k = js_get(js, keys, idxstr); 15150 + jsval_t v = js_get(js, vals, idxstr); 15151 + jsval_t entry = js_mkarr(js); 15152 + js_arr_push(js, entry, k); 15153 + js_arr_push(js, entry, v); 15154 + js_set(js, result, "value", entry); 15155 + js_set(js, result, "done", js_mkfalse()); 15156 + js_set(js, this_val, "__idx", js_mknum(idx + 1)); 15157 + } 15158 + return result; 15159 + } 15160 + 15161 + static jsval_t map_entries(struct js *js, jsval_t *args, int nargs) { 15162 + (void)args; (void)nargs; 15163 + jsval_t this_val = js->this_val; 15164 + map_entry_t **map_ptr = get_map_from_obj(js, this_val); 15165 + 15166 + jsval_t keys = js_mkarr(js); 15167 + jsval_t vals = js_mkarr(js); 15168 + int count = 0; 15169 + 15170 + if (map_ptr && *map_ptr) { 15171 + map_entry_t *entry, *tmp; 15172 + HASH_ITER(hh, *map_ptr, entry, tmp) { 15173 + js_arr_push(js, keys, js_mkstr(js, entry->key, strlen(entry->key))); 15174 + js_arr_push(js, vals, entry->value); 15175 + count++; 15176 + } 15177 + } 15178 + 15179 + jsval_t iter = js_mkobj(js); 15180 + js_set(js, iter, "__keys", keys); 15181 + js_set(js, iter, "__vals", vals); 15182 + js_set(js, iter, "__idx", js_mknum(0)); 15183 + js_set(js, iter, "__len", js_mknum(count)); 15184 + js_set(js, iter, "next", js_mkfun(map_iter_next)); 15185 + return iter; 15186 + } 15187 + 15188 + static jsval_t set_iter_next(struct js *js, jsval_t *args, int nargs) { 15189 + (void)args; (void)nargs; 15190 + jsval_t this_val = js->this_val; 15191 + jsval_t idx_val = js_get(js, this_val, "__idx"); 15192 + jsval_t vals = js_get(js, this_val, "__vals"); 15193 + jsval_t len_val = js_get(js, this_val, "__len"); 15194 + 15195 + int idx = (int)js_getnum(idx_val); 15196 + int len = (int)js_getnum(len_val); 15197 + 15198 + jsval_t result = js_mkobj(js); 15199 + if (idx >= len) { 15200 + js_set(js, result, "done", js_mktrue()); 15201 + js_set(js, result, "value", js_mkundef()); 15202 + } else { 15203 + char idxstr[16]; 15204 + snprintf(idxstr, sizeof(idxstr), "%d", idx); 15205 + jsval_t v = js_get(js, vals, idxstr); 15206 + js_set(js, result, "value", v); 15207 + js_set(js, result, "done", js_mkfalse()); 15208 + js_set(js, this_val, "__idx", js_mknum(idx + 1)); 15209 + } 15210 + return result; 15211 + } 15212 + 15213 + static jsval_t set_values(struct js *js, jsval_t *args, int nargs) { 15214 + (void)args; (void)nargs; 15215 + jsval_t this_val = js->this_val; 15216 + set_entry_t **set_ptr = get_set_from_obj(js, this_val); 15217 + 15218 + jsval_t vals = js_mkarr(js); 15219 + int count = 0; 15220 + 15221 + if (set_ptr && *set_ptr) { 15222 + set_entry_t *entry, *tmp; 15223 + HASH_ITER(hh, *set_ptr, entry, tmp) { 15224 + js_arr_push(js, vals, entry->value); 15225 + count++; 15226 + } 15227 + } 15228 + 15229 + jsval_t iter = js_mkobj(js); 15230 + js_set(js, iter, "__vals", vals); 15231 + js_set(js, iter, "__idx", js_mknum(0)); 15232 + js_set(js, iter, "__len", js_mknum(count)); 15233 + js_set(js, iter, "next", js_mkfun(set_iter_next)); 15234 + return iter; 15235 + } 15236 + 15018 15237 static jsval_t set_add(struct js *js, jsval_t *args, int nargs) { 15019 15238 if (nargs < 1) return js_mkerr(js, "Set.add() requires 1 argument"); 15020 15239 ··· 15513 15732 setprop(js, map_proto, js_mkstr(js, "delete", 6), js_mkfun(map_delete)); 15514 15733 setprop(js, map_proto, js_mkstr(js, "clear", 5), js_mkfun(map_clear)); 15515 15734 setprop(js, map_proto, js_mkstr(js, "size", 4), js_mkfun(map_size)); 15735 + setprop(js, map_proto, js_mkstr(js, "entries", 7), js_mkfun(map_entries)); 15516 15736 setprop(js, map_proto, js_mkstr(js, "@@toStringTag", 13), js_mkstr(js, "Map", 3)); 15517 15737 15518 15738 jsval_t set_proto_obj = js_mkobj(js); ··· 15522 15742 setprop(js, set_proto_obj, js_mkstr(js, "delete", 6), js_mkfun(set_delete)); 15523 15743 setprop(js, set_proto_obj, js_mkstr(js, "clear", 5), js_mkfun(set_clear)); 15524 15744 setprop(js, set_proto_obj, js_mkstr(js, "size", 4), js_mkfun(set_size)); 15745 + setprop(js, set_proto_obj, js_mkstr(js, "values", 6), js_mkfun(set_values)); 15525 15746 setprop(js, set_proto_obj, js_mkstr(js, "@@toStringTag", 13), js_mkstr(js, "Set", 3)); 15526 15747 15527 15748 jsval_t weakmap_proto = js_mkobj(js); ··· 15939 16160 case T_NUM: return JS_NUM; 15940 16161 case T_ERR: return JS_ERR; 15941 16162 case T_PROMISE: return JS_PROMISE; 16163 + 15942 16164 case T_OBJ: 15943 16165 case T_ARR: return JS_OBJ; 15944 16166 case T_FUNC: return JS_FUNC; 16167 + 15945 16168 default: return JS_PRIV; 15946 16169 } 16170 + } 16171 + 16172 + int js_type_ex(struct js *js, jsval_t val) { 16173 + if (vtype(val) == T_OBJ && is_symbol(js, val)) return JS_SYMBOL; 16174 + return js_type(val); 15947 16175 } 15948 16176 15949 16177 void js_stats(struct js *js, size_t *total, size_t *lwm, size_t *css) {
+2
src/main.c
··· 33 33 #include "modules/uri.h" 34 34 #include "modules/url.h" 35 35 #include "modules/reflect.h" 36 + #include "modules/symbol.h" 36 37 37 38 int js_result = EXIT_SUCCESS; 38 39 ··· 201 202 init_uri_module(); 202 203 init_url_module(); 203 204 init_reflect_module(); 205 + init_symbol_module(); 204 206 205 207 ant_register_library(shell_library, "ant:shell", NULL); 206 208 ant_register_library(ffi_library, "ant:ffi", NULL);
+213
src/modules/symbol.c
··· 1 + #include <stdlib.h> 2 + #include <string.h> 3 + #include <stdio.h> 4 + 5 + #include "ant.h" 6 + #include "runtime.h" 7 + #include "modules/symbol.h" 8 + 9 + #define MAX_REGISTRY 256 10 + static struct { 11 + char *key; 12 + jsval_t symbol; 13 + } g_symbol_registry[MAX_REGISTRY]; 14 + static int g_registry_count = 0; 15 + 16 + static jsval_t g_iterator_sym = 0; 17 + static jsval_t g_toStringTag_sym = 0; 18 + static jsval_t g_hasInstance_sym = 0; 19 + static char g_iter_sym_key[32] = {0}; 20 + 21 + jsval_t get_iterator_symbol(void) { 22 + return g_iterator_sym; 23 + } 24 + 25 + const char *get_iterator_sym_key(void) { 26 + return g_iter_sym_key; 27 + } 28 + 29 + static jsval_t builtin_Symbol(struct js *js, jsval_t *args, int nargs) { 30 + const char *desc = NULL; 31 + if (nargs > 0 && js_type(args[0]) == JS_STR) { 32 + desc = js_getstr(js, args[0], NULL); 33 + } 34 + return js_mksym(js, desc); 35 + } 36 + 37 + static jsval_t builtin_Symbol_for(struct js *js, jsval_t *args, int nargs) { 38 + if (nargs < 1 || js_type(args[0]) != JS_STR) { 39 + return js_mkerr(js, "Symbol.for requires a string argument"); 40 + } 41 + 42 + char *key = js_getstr(js, args[0], NULL); 43 + if (!key) return js_mkerr(js, "Invalid key"); 44 + 45 + for (int i = 0; i < g_registry_count; i++) { 46 + if (g_symbol_registry[i].key && strcmp(g_symbol_registry[i].key, key) == 0) { 47 + return g_symbol_registry[i].symbol; 48 + } 49 + } 50 + 51 + if (g_registry_count >= MAX_REGISTRY) { 52 + return js_mkerr(js, "Symbol registry full"); 53 + } 54 + 55 + jsval_t sym = js_mksym(js, key); 56 + g_symbol_registry[g_registry_count].key = strdup(key); 57 + g_symbol_registry[g_registry_count].symbol = sym; 58 + 59 + jsval_t sym_obj = js_mkobj(js); 60 + js_set(js, sym_obj, "__sym_id", js_get(js, sym, "__sym_id")); 61 + js_set(js, sym_obj, "description", js_get(js, sym, "description")); 62 + js_set(js, sym_obj, "__registry_key", js_mkstr(js, key, strlen(key))); 63 + 64 + g_symbol_registry[g_registry_count].symbol = sym; 65 + g_registry_count++; 66 + 67 + return sym; 68 + } 69 + 70 + static bool is_symbol_val(struct js *js, jsval_t v) { 71 + if (js_type(v) != JS_OBJ) return false; 72 + jsval_t marker = js_get(js, v, "__sym__"); 73 + return js_type(marker) == JS_TRUE; 74 + } 75 + 76 + static jsval_t builtin_Symbol_keyFor(struct js *js, jsval_t *args, int nargs) { 77 + if (nargs < 1 || !is_symbol_val(js, args[0])) { 78 + return js_mkundef(); 79 + } 80 + 81 + jsval_t sym = args[0]; 82 + jsval_t sym_id = js_get(js, sym, "__sym_id"); 83 + 84 + for (int i = 0; i < g_registry_count; i++) { 85 + jsval_t reg_id = js_get(js, g_symbol_registry[i].symbol, "__sym_id"); 86 + if (js_type(sym_id) == JS_NUM && js_type(reg_id) == JS_NUM && 87 + js_getnum(sym_id) == js_getnum(reg_id)) { 88 + return js_mkstr(js, g_symbol_registry[i].key, strlen(g_symbol_registry[i].key)); 89 + } 90 + } 91 + 92 + return js_mkundef(); 93 + } 94 + 95 + static jsval_t iterator_next(struct js *js, jsval_t *args, int nargs) { 96 + (void)args; (void)nargs; 97 + jsval_t this_val = js_getthis(js); 98 + 99 + jsval_t arr = js_get(js, this_val, "__arr"); 100 + jsval_t idx_val = js_get(js, this_val, "__idx"); 101 + jsval_t len_val = js_get(js, this_val, "__len"); 102 + 103 + int idx = (int)js_getnum(idx_val); 104 + int len = (int)js_getnum(len_val); 105 + 106 + jsval_t result = js_mkobj(js); 107 + 108 + if (idx >= len) { 109 + js_set(js, result, "done", js_mktrue()); 110 + js_set(js, result, "value", js_mkundef()); 111 + } else { 112 + char idxstr[16]; 113 + snprintf(idxstr, sizeof(idxstr), "%d", idx); 114 + jsval_t value = js_get(js, arr, idxstr); 115 + js_set(js, result, "value", value); 116 + js_set(js, result, "done", js_mkfalse()); 117 + js_set(js, this_val, "__idx", js_mknum(idx + 1)); 118 + } 119 + 120 + return result; 121 + } 122 + 123 + static jsval_t array_iterator(struct js *js, jsval_t *args, int nargs) { 124 + (void)args; (void)nargs; 125 + jsval_t arr = js_getthis(js); 126 + 127 + jsval_t len_val = js_get(js, arr, "length"); 128 + int len = js_type(len_val) == JS_NUM ? (int)js_getnum(len_val) : 0; 129 + 130 + jsval_t iter = js_mkobj(js); 131 + js_set(js, iter, "__arr", arr); 132 + js_set(js, iter, "__idx", js_mknum(0)); 133 + js_set(js, iter, "__len", js_mknum(len)); 134 + js_set(js, iter, "next", js_mkfun(iterator_next)); 135 + 136 + return iter; 137 + } 138 + 139 + static jsval_t string_iterator_next(struct js *js, jsval_t *args, int nargs) { 140 + (void)args; (void)nargs; 141 + jsval_t this_val = js_getthis(js); 142 + 143 + jsval_t str = js_get(js, this_val, "__str"); 144 + jsval_t idx_val = js_get(js, this_val, "__idx"); 145 + jsval_t len_val = js_get(js, this_val, "__len"); 146 + 147 + int idx = (int)js_getnum(idx_val); 148 + int len = (int)js_getnum(len_val); 149 + 150 + jsval_t result = js_mkobj(js); 151 + 152 + if (idx >= len) { 153 + js_set(js, result, "done", js_mktrue()); 154 + js_set(js, result, "value", js_mkundef()); 155 + } else { 156 + char *s = js_getstr(js, str, NULL); 157 + char ch[2] = {s[idx], 0}; 158 + js_set(js, result, "value", js_mkstr(js, ch, 1)); 159 + js_set(js, result, "done", js_mkfalse()); 160 + js_set(js, this_val, "__idx", js_mknum(idx + 1)); 161 + } 162 + 163 + return result; 164 + } 165 + 166 + static jsval_t string_iterator(struct js *js, jsval_t *args, int nargs) { 167 + (void)args; (void)nargs; 168 + jsval_t str = js_getthis(js); 169 + 170 + size_t len; 171 + js_getstr(js, str, &len); 172 + 173 + jsval_t iter = js_mkobj(js); 174 + js_set(js, iter, "__str", str); 175 + js_set(js, iter, "__idx", js_mknum(0)); 176 + js_set(js, iter, "__len", js_mknum((double)len)); 177 + js_set(js, iter, "next", js_mkfun(string_iterator_next)); 178 + 179 + return iter; 180 + } 181 + 182 + void init_symbol_module(void) { 183 + struct js *js = rt->js; 184 + 185 + g_iterator_sym = js_mksym(js, "Symbol.iterator"); 186 + g_toStringTag_sym = js_mksym(js, "Symbol.toStringTag"); 187 + g_hasInstance_sym = js_mksym(js, "Symbol.hasInstance"); 188 + 189 + jsval_t sym_id = js_get(js, g_iterator_sym, "__sym_id"); 190 + snprintf(g_iter_sym_key, sizeof(g_iter_sym_key), "__sym_%.0f__", js_getnum(sym_id)); 191 + 192 + jsval_t symbol_ctor = js_mkobj(js); 193 + js_set(js, symbol_ctor, "__native_func", js_mkfun(builtin_Symbol)); 194 + js_setprop(js, symbol_ctor, js_mkstr(js, "for", 3), js_mkfun(builtin_Symbol_for)); 195 + js_set(js, symbol_ctor, "keyFor", js_mkfun(builtin_Symbol_keyFor)); 196 + 197 + js_set(js, symbol_ctor, "iterator", g_iterator_sym); 198 + js_set(js, symbol_ctor, "toStringTag", g_toStringTag_sym); 199 + js_set(js, symbol_ctor, "hasInstance", g_hasInstance_sym); 200 + 201 + jsval_t func_symbol = symbol_ctor; 202 + *(uint64_t*)&func_symbol = (func_symbol & ~((uint64_t)0xF << 48)) | ((uint64_t)0x7 << 48); 203 + 204 + js_set(js, js_glob(js), "Symbol", func_symbol); 205 + 206 + jsval_t array_ctor = js_get(js, js_glob(js), "Array"); 207 + jsval_t array_proto = js_get(js, array_ctor, "prototype"); 208 + js_set(js, array_proto, g_iter_sym_key, js_mkfun(array_iterator)); 209 + 210 + jsval_t string_ctor = js_get(js, js_glob(js), "String"); 211 + jsval_t string_proto = js_get(js, string_ctor, "prototype"); 212 + js_set(js, string_proto, g_iter_sym_key, js_mkfun(string_iterator)); 213 + }