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.

at mir/inline-method 396 lines 14 kB view raw
1#include <stdlib.h> 2#include <string.h> 3#include <stdio.h> 4 5#include "ant.h" 6#include "utf8.h" 7#include "errors.h" 8#include "runtime.h" 9#include "internal.h" 10#include "silver/engine.h" 11#include "modules/symbol.h" 12#include "descriptors.h" 13#include "gc/roots.h" 14#include "gc/modules.h" 15 16#define DECL_SYM(name, _desc) static ant_value_t g_##name = {0}; 17WELLKNOWN_SYMBOLS(DECL_SYM) 18#undef DECL_SYM 19 20#define DEF_GET_SYM(name, _desc) ant_value_t get_##name##_sym(void) { return g_##name; } 21WELLKNOWN_SYMBOLS(DEF_GET_SYM) 22#undef DEF_GET_SYM 23 24static ant_value_t builtin_Symbol(ant_t *js, ant_value_t *args, int nargs) { 25 if (vtype(js->new_target) != T_UNDEF) 26 return js_mkerr_typed(js, JS_ERR_TYPE, "Symbol is not a constructor"); 27 28 const char *desc = NULL; 29 if (nargs > 0 && vtype(args[0]) == T_STR) { 30 desc = js_getstr(js, args[0], NULL); 31 } 32 return js_mksym(js, desc); 33} 34 35static ant_value_t builtin_Symbol_for(ant_t *js, ant_value_t *args, int nargs) { 36 if (nargs < 1 || vtype(args[0]) != T_STR) { 37 return js_mkerr(js, "Symbol.for requires a string argument"); 38 } 39 40 char *key = js_getstr(js, args[0], NULL); 41 if (!key) return js_mkerr(js, "Invalid key"); 42 43 return js_mksym_for(js, key); 44} 45 46static ant_value_t builtin_Symbol_keyFor(ant_t *js, ant_value_t *args, int nargs) { 47 if (nargs < 1 || vtype(args[0]) != T_SYMBOL) { 48 return js_mkundef(); 49 } 50 51 const char *key = js_sym_key(args[0]); 52 if (!key) return js_mkundef(); 53 54 return js_mkstr(js, key, strlen(key)); 55} 56 57static ant_value_t builtin_Symbol_toString(ant_t *js, ant_value_t *args, int nargs) { 58 ant_value_t this_val = js_getthis(js); 59 60 if (vtype(this_val) != T_SYMBOL) { 61 return js_mkerr(js, "Symbol.prototype.toString requires a symbol"); 62 } 63 64 return js_symbol_to_string(js, this_val); 65} 66 67static ant_value_t builtin_Symbol_description(ant_t *js, ant_value_t *args, int nargs) { 68 ant_value_t this_val = js_getthis(js); 69 ant_value_t sym = this_val; 70 71 if (vtype(sym) != T_SYMBOL && is_object_type(sym)) { 72 ant_value_t prim = js_get_slot(sym, SLOT_PRIMITIVE); 73 if (vtype(prim) == T_SYMBOL) sym = prim; 74 } 75 76 if (vtype(sym) != T_SYMBOL) 77 return js_mkerr_typed(js, JS_ERR_TYPE, "Symbol.prototype.description requires a symbol"); 78 79 const char *desc = js_sym_desc(sym); 80 if (!desc) return js_mkundef(); 81 82 return js_mkstr(js, desc, strlen(desc)); 83} 84 85static ant_value_t get_iterator_prototype(ant_t *js) { 86 if (vtype(js->sym.iterator_proto) == T_OBJ) return js->sym.iterator_proto; 87 88 js->sym.iterator_proto = js_mkobj(js); 89 js_set_proto_init(js->sym.iterator_proto, js->sym.object_proto); 90 js_set_sym(js, js->sym.iterator_proto, g_iterator, js_mkfun(sym_this_cb)); 91 92 return js->sym.iterator_proto; 93} 94 95static inline ant_value_t iter_get_element(ant_t *js, ant_value_t obj, uint32_t idx) { 96 if (vtype(obj) == T_ARR) return js_arr_get(js, obj, (ant_offset_t)idx); 97 char buf[16]; snprintf(buf, sizeof(buf), "%u", idx); 98 return js_get(js, obj, buf); 99} 100 101static inline ant_offset_t iter_get_length(ant_t *js, ant_value_t obj) { 102 if (vtype(obj) == T_ARR) return js_arr_len(js, obj); 103 ant_value_t v = js_get(js, obj, "length"); 104 return (vtype(v) == T_NUM) ? (ant_offset_t)js_getnum(v) : 0; 105} 106 107static bool advance_array(ant_t *js, js_iter_t *it, ant_value_t *out) { 108 ant_value_t iter = it->iterator; 109 ant_value_t array = js_get_slot(iter, SLOT_DATA); 110 ant_value_t state_v = js_get_slot(iter, SLOT_ITER_STATE); 111 112 uint32_t state = (vtype(state_v) == T_NUM) ? (uint32_t)js_getnum(state_v) : 0; 113 uint32_t kind = ITER_STATE_KIND(state); 114 uint32_t idx = ITER_STATE_INDEX(state); 115 ant_offset_t len = iter_get_length(js, array); 116 if (idx >= (uint32_t)len) return false; 117 118 switch (kind) { 119 case ARR_ITER_KEYS: 120 *out = js_mknum((double)idx); 121 break; 122 case ARR_ITER_ENTRIES: { 123 ant_value_t pair = js_mkarr(js); 124 js_arr_push(js, pair, js_mknum((double)idx)); 125 js_arr_push(js, pair, iter_get_element(js, array, idx)); 126 *out = pair; 127 break; 128 } 129 default: 130 *out = iter_get_element(js, array, idx); 131 break; 132 } 133 134 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, idx + 1))); 135 return true; 136} 137 138static bool advance_string(ant_t *js, js_iter_t *it, ant_value_t *out) { 139 ant_value_t iter = it->iterator; 140 ant_value_t str = js_get_slot(iter, SLOT_DATA); 141 ant_value_t idx_v = js_get_slot(iter, SLOT_ITER_STATE); 142 int idx = (vtype(idx_v) == T_NUM) ? (int)js_getnum(idx_v) : 0; 143 144 size_t slen; 145 char *s = js_getstr(js, str, &slen); 146 if (idx >= (int)slen) return false; 147 148 unsigned char c = (unsigned char)s[idx]; 149 int char_bytes = utf8_sequence_length(c); 150 if (char_bytes < 1) char_bytes = 1; 151 if (idx + char_bytes > (int)slen) char_bytes = (int)slen - idx; 152 153 *out = js_mkstr(js, s + idx, (ant_offset_t)char_bytes); 154 js_set_slot(iter, SLOT_ITER_STATE, js_mknum(idx + char_bytes)); 155 return true; 156} 157 158static ant_value_t arr_iter_next(ant_t *js, ant_value_t *args, int nargs) { 159 js_iter_t it = { .iterator = js->this_val }; 160 ant_value_t value; 161 return js_iter_result(js, advance_array(js, &it, &value), value); 162} 163 164static ant_value_t get_array_iterator_prototype(ant_t *js) { 165 if (vtype(js->sym.array_iterator_proto) == T_OBJ) return js->sym.array_iterator_proto; 166 167 ant_value_t iterator_proto = get_iterator_prototype(js); 168 js->sym.array_iterator_proto = js_mkobj(js); 169 js_set(js, js->sym.array_iterator_proto, "next", js_mkfun(arr_iter_next)); 170 js_set_proto_init(js->sym.array_iterator_proto, iterator_proto); 171 172 return js->sym.array_iterator_proto; 173} 174 175ant_value_t make_array_iterator(ant_t *js, ant_value_t array, int kind) { 176 ant_value_t iter = js_mkobj(js); 177 js_set_slot_wb(js, iter, SLOT_DATA, array); 178 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, 0))); 179 js_set_proto_init(iter, get_array_iterator_prototype(js)); 180 return iter; 181} 182 183static ant_value_t str_iter_next(ant_t *js, ant_value_t *args, int nargs) { 184 js_iter_t it = { .iterator = js->this_val }; 185 ant_value_t value; 186 return js_iter_result(js, advance_string(js, &it, &value), value); 187} 188 189static ant_value_t get_string_iterator_prototype(ant_t *js) { 190 if (vtype(js->sym.string_iterator_proto) == T_OBJ) return js->sym.string_iterator_proto; 191 192 ant_value_t iterator_proto = get_iterator_prototype(js); 193 js->sym.string_iterator_proto = js_mkobj(js); 194 js_set(js, js->sym.string_iterator_proto, "next", js_mkfun(str_iter_next)); 195 js_set_proto_init(js->sym.string_iterator_proto, iterator_proto); 196 197 return js->sym.string_iterator_proto; 198} 199 200static ant_value_t string_iterator(ant_t *js, ant_value_t *args, int nargs) { 201 ant_value_t iter = js_mkobj(js); 202 203 js_set_slot_wb(js, iter, SLOT_DATA, js->this_val); 204 js_set_slot(iter, SLOT_ITER_STATE, js_mknum(0)); 205 js_set_proto_init(iter, get_string_iterator_prototype(js)); 206 207 return iter; 208} 209 210static struct { 211 ant_value_t proto; 212 js_iter_advance_fn fn; 213} g_advance_table[8]; 214 215static int g_advance_count = 0; 216 217void js_iter_register_advance(ant_value_t proto, js_iter_advance_fn fn) { 218 if (g_advance_count < 8) 219 g_advance_table[g_advance_count++] = (typeof(g_advance_table[0])){ proto, fn }; 220} 221 222bool js_iter_open(ant_t *js, ant_value_t iterable, js_iter_t *it) { 223 memset(it, 0, sizeof(*it)); 224 225 ant_value_t iter_fn = js_get_sym(js, iterable, get_iterator_sym()); 226 if (!is_callable(iter_fn)) return false; 227 228 ant_value_t iterator = sv_vm_call(js->vm, js, iter_fn, iterable, NULL, 0, NULL, false); 229 if (is_err(iterator)) return false; 230 231 it->iterator = iterator; 232 it->next_fn = js_getprop_fallback(js, iterator, "next"); 233 it->advance = NULL; 234 235 ant_value_t proto = (vtype(iterator) == T_OBJ) ? js_get_proto(js, iterator) : js_mkundef(); 236 for (int i = 0; i < g_advance_count; i++) 237 if (proto == g_advance_table[i].proto) { it->advance = g_advance_table[i].fn; break; } 238 239 return true; 240} 241 242bool js_iter_next(ant_t *js, js_iter_t *it, ant_value_t *out) { 243 if (it->advance) return it->advance(js, it, out); 244 245 ant_value_t next_fn = it->next_fn; 246 ant_value_t result; 247 248 if (vtype(next_fn) == T_CFUNC) { 249 ant_value_t old_this = js->this_val; 250 js->this_val = it->iterator; 251 result = js_as_cfunc(next_fn)(js, NULL, 0); 252 js->this_val = old_this; 253 } 254 255 else if (is_callable(next_fn)) result = sv_vm_call(js->vm, js, next_fn, it->iterator, NULL, 0, NULL, false); 256 else return false; 257 258 if (is_err(result)) return false; 259 ant_value_t done = js_getprop_fallback(js, result, "done"); 260 261 if (js_truthy(js, done)) return false; 262 *out = js_getprop_fallback(js, result, "value"); 263 264 return true; 265} 266 267void js_iter_close(ant_t *js, js_iter_t *it) { 268 if (it->advance) return; 269 ant_value_t return_fn = js_getprop_fallback(js, it->iterator, "return"); 270 if (is_callable(return_fn)) sv_vm_call(js->vm, js, return_fn, it->iterator, NULL, 0, NULL, false); 271} 272 273ant_value_t maybe_call_symbol_method( 274 ant_t *js, ant_value_t target, 275 ant_value_t sym, 276 ant_value_t this_arg, ant_value_t *args, 277 int nargs, bool *called 278) { 279 *called = false; 280 if (vtype(sym) != T_SYMBOL || !is_object_type(target)) return js_mkundef(); 281 282 ant_value_t method = js_get_sym(js, target, sym); 283 if (is_err(method)) return method; 284 285 uint8_t mt = vtype(method); 286 if (mt == T_UNDEF || mt == T_NULL) return js_mkundef(); 287 if (!is_callable(method)) { 288 return js_mkerr_typed(js, JS_ERR_TYPE, "Symbol method is not callable"); 289 } 290 291 *called = true; 292 return sv_vm_call(js->vm, js, method, this_arg, args, nargs, NULL, false); 293} 294 295void js_define_species_getter(ant_t *js, ant_value_t ctor) { 296 if (!is_object_type(ctor) || vtype(g_species) != T_SYMBOL) return; 297 ctor = js_as_obj(ctor); 298 js_set_sym_getter_desc(js, ctor, g_species, js_mkfun(sym_this_cb), JS_DESC_C); 299} 300 301void init_symbol_module(void) { 302 ant_t *js = rt->js; 303 304 js->sym.iterator_proto = js_mkundef(); 305 js->sym.array_iterator_proto = js_mkundef(); 306 js->sym.string_iterator_proto = js_mkundef(); 307 js->sym.generator_proto = js_mkundef(); 308 js->sym.async_generator_proto = js_mkundef(); 309 js->sym.async_iterator_proto = js_mkundef(); 310 311 gc_register_root(&js->sym.iterator_proto); 312 gc_register_root(&js->sym.array_iterator_proto); 313 gc_register_root(&js->sym.string_iterator_proto); 314 gc_register_root(&js->sym.generator_proto); 315 gc_register_root(&js->sym.async_generator_proto); 316 gc_register_root(&js->sym.async_iterator_proto); 317 318 #define INIT_SYM(name, desc) g_##name = js_mksym_well_known(js, desc); 319 WELLKNOWN_SYMBOLS(INIT_SYM) 320 #undef INIT_SYM 321 322 ant_value_t symbol_proto = js_mkobj(js); 323 ant_value_t object_proto = js->sym.object_proto; 324 325 if (is_object_type(object_proto)) js_set_proto_init(symbol_proto, object_proto); 326 js_set(js, symbol_proto, "toString", js_mkfun(builtin_Symbol_toString)); 327 js_set_getter_desc(js, symbol_proto, "description", 11, js_mkfun(builtin_Symbol_description), JS_DESC_C); 328 329 ant_value_t symbol_ctor = js_mkobj(js); 330 js_set_slot(symbol_ctor, SLOT_CFUNC, js_mkfun(builtin_Symbol)); 331 js_setprop(js, symbol_ctor, js_mkstr(js, "for", 3), js_mkfun(builtin_Symbol_for)); 332 js_set(js, symbol_ctor, "keyFor", js_mkfun(builtin_Symbol_keyFor)); 333 js_set(js, symbol_ctor, "prototype", symbol_proto); 334 335 #define SET_CTOR_SYM(name, _desc) js_set(js, symbol_ctor, #name, g_##name); 336 WELLKNOWN_SYMBOLS(SET_CTOR_SYM) 337 #undef SET_CTOR_SYM 338 339 ant_value_t func_symbol = js_obj_to_func(symbol_ctor); 340 js_set(js, js_glob(js), "Symbol", func_symbol); 341 342 // set internal types before ant module snapshot 343 ant_value_t array_ctor = js_get(js, js_glob(js), "Array"); 344 ant_value_t array_proto = js_get(js, array_ctor, "prototype"); 345 346 (void)get_array_iterator_prototype(js); 347 (void)get_string_iterator_prototype(js); 348 349 js_iter_register_advance(js->sym.array_iterator_proto, advance_array); 350 js_iter_register_advance(js->sym.string_iterator_proto, advance_string); 351 352 js_set_sym(js, rt->ant_obj, g_toStringTag, js_mkstr(js, "Ant", 3)); 353 js_set_sym(js, array_proto, g_iterator, js_get(js, array_proto, "values")); 354 355 ant_value_t array_unscopables = js_mkobj(js); 356 js_set(js, array_unscopables, "find", js_true); 357 js_set(js, array_unscopables, "findIndex", js_true); 358 js_set(js, array_unscopables, "fill", js_true); 359 js_set(js, array_unscopables, "copyWithin", js_true); 360 js_set(js, array_unscopables, "entries", js_true); 361 js_set(js, array_unscopables, "keys", js_true); 362 js_set(js, array_unscopables, "values", js_true); 363 js_set(js, array_unscopables, "flat", js_true); 364 js_set(js, array_unscopables, "flatMap", js_true); 365 js_set_sym(js, array_proto, g_unscopables, array_unscopables); 366 367 ant_value_t string_ctor = js_get(js, js_glob(js), "String"); 368 ant_value_t string_proto = js_get(js, string_ctor, "prototype"); 369 js_set_sym(js, string_proto, g_iterator, js_mkfun(string_iterator)); 370 371 ant_value_t promise_ctor = js_get(js, js_glob(js), "Promise"); 372 ant_value_t promise_proto = js_get(js, promise_ctor, "prototype"); 373 js_set_sym(js, promise_proto, g_toStringTag, js_mkstr(js, "Promise", 7)); 374 375 ant_value_t async_func_proto = js_get_slot(js_glob(js), SLOT_ASYNC_PROTO); 376 js_set_sym(js, async_func_proto, g_toStringTag, js_mkstr(js, "AsyncFunction", 13)); 377 378 ant_value_t async_generator_func_proto = js_get_slot(js_glob(js), SLOT_ASYNC_GENERATOR_PROTO); 379 js_set_sym(js, async_generator_func_proto, g_toStringTag, js_mkstr(js, "AsyncGeneratorFunction", 22)); 380 381 js_define_species_getter(js, promise_ctor); 382 js_define_species_getter(js, array_ctor); 383} 384 385void gc_mark_symbols(ant_t *js, gc_mark_fn mark) { 386 mark(js, js->sym.iterator_proto); 387 mark(js, js->sym.array_iterator_proto); 388 mark(js, js->sym.string_iterator_proto); 389 mark(js, js->sym.generator_proto); 390 mark(js, js->sym.async_generator_proto); 391 mark(js, js->sym.async_iterator_proto); 392 393 #define GC_SYM(name, _desc) mark(js, g_##name); 394 WELLKNOWN_SYMBOLS(GC_SYM) 395 #undef GC_SYM 396}