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.

migrate to a prototype based system

+892 -319
+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.7.26') 77 + version_conf.set('ANT_VERSION', '0.0.7.27') 78 78 version_conf.set('ANT_GIT_HASH', git_hash) 79 79 version_conf.set('ANT_BUILD_DATE', build_date) 80 80
+702 -318
src/ant.c
··· 250 250 251 251 enum { 252 252 T_OBJ, T_PROP, T_STR, T_UNDEF, T_NULL, T_NUM, 253 - T_BOOL, T_FUNC, T_CODEREF, T_CFUNC, T_ERR, T_ARR, T_PROMISE, T_GENERATOR, T_BIGINT 253 + T_BOOL, T_FUNC, T_CODEREF, T_CFUNC, T_ERR, T_ARR, 254 + T_PROMISE, T_GENERATOR, T_BIGINT, T_PROPREF 254 255 }; 255 256 256 257 static const char *typestr(uint8_t t) { ··· 264 265 265 266 static jsval_t tov(double d) { union { double d; jsval_t v; } u = {d}; return u.v; } 266 267 static double tod(jsval_t v) { union { jsval_t v; double d; } u = {v}; return u.d; } 267 - static jsval_t mkval(uint8_t type, uint64_t data) { return ((jsval_t) 0x7fe0U << 48U) | ((jsval_t) (type) << 48) | (data & 0xffffffffffffUL); } 268 268 static bool is_nan(jsval_t v) { return (v >> 52U) == 0x7feU; } 269 269 static uint8_t vtype(jsval_t v) { return is_nan(v) ? ((v >> 48U) & 15U) : (uint8_t) T_NUM; } 270 270 static size_t vdata(jsval_t v) { return (size_t) (v & ~((jsval_t) 0x7fffUL << 48U)); } 271 - static jsval_t mkcoderef(jsval_t off, jsoff_t len) { return mkval(T_CODEREF, (off & 0xffffffU) | ((jsval_t)(len & 0xffffffU) << 24U)); } 272 271 static jsoff_t coderefoff(jsval_t v) { return v & 0xffffffU; } 273 272 static jsoff_t codereflen(jsval_t v) { return (v >> 24U) & 0xffffffU; } 273 + static jsoff_t propref_obj(jsval_t v) { return v & 0xffffffU; } 274 + static jsoff_t propref_key(jsval_t v) { return (v >> 24U) & 0xffffffU; } 275 + 276 + static jsval_t mkval(uint8_t type, uint64_t data) { 277 + return ((jsval_t) 0x7fe0U << 48U) | ((jsval_t) (type) << 48) | (data & 0xffffffffffffUL); 278 + } 279 + 280 + static jsval_t mkcoderef(jsval_t off, jsoff_t len) { 281 + return mkval(T_CODEREF, (off & 0xffffffU) | ((jsval_t)(len & 0xffffffU) << 24U)); 282 + } 283 + 284 + static jsval_t mkpropref(jsoff_t obj_off, jsoff_t key_off) { 285 + return mkval(T_PROPREF, (obj_off & 0xffffffU) | ((jsval_t)(key_off & 0xffffffU) << 24U)); 286 + } 274 287 275 288 static uint8_t unhex(uint8_t c) { return (c >= '0' && c <= '9') ? (uint8_t) (c - '0') : (c >= 'a' && c <= 'f') ? (uint8_t) (c - 'W') : (c >= 'A' && c <= 'F') ? (uint8_t) (c - '7') : 0; } 276 289 static bool is_space(int c) { return c == ' ' || c == '\r' || c == '\n' || c == '\t' || c == '\f' || c == '\v'; } ··· 422 435 static jsval_t call_js_code_with_args(struct js *js, const char *fn, jsoff_t fnlen, jsval_t closure_scope, jsval_t *args, int nargs); 423 436 static jsval_t start_async_in_coroutine(struct js *js, const char *code, size_t code_len, jsval_t closure_scope, jsval_t *args, int nargs); 424 437 438 + static jsval_t get_proto(struct js *js, jsval_t obj); 439 + static void set_proto(struct js *js, jsval_t obj, jsval_t proto); 440 + static jsoff_t lkp_proto(struct js *js, jsval_t obj, const char *key, size_t len); 441 + static jsval_t get_ctor_proto(struct js *js, const char *name, size_t len); 442 + static jsval_t get_prototype_for_type(struct js *js, uint8_t type); 443 + 425 444 static void free_coroutine(coroutine_t *coro); 426 445 static bool has_ready_coroutines(void); 427 446 ··· 448 467 } 449 468 450 469 } 451 - 452 - /* unused for now 453 - static coroutine_t *create_coroutine(struct js *js, jsval_t promise, jsval_t async_func) { 454 - coroutine_t *coro = (coroutine_t *)malloc(sizeof(coroutine_t)); 455 - if (!coro) return NULL; 456 - 457 - coro->js = js; 458 - coro->type = CORO_ASYNC_AWAIT; 459 - coro->scope = js->scope; 460 - coro->this_val = js->this_val; 461 - coro->awaited_promise = promise; 462 - coro->result = js_mkundef(); 463 - coro->async_func = async_func; 464 - coro->args = NULL; 465 - coro->nargs = 0; 466 - coro->is_settled = false; 467 - coro->is_error = false; 468 - coro->is_done = false; 469 - coro->resume_point = 0; 470 - coro->yield_value = js_mkundef(); 471 - coro->next = NULL; 472 - 473 - coro->mco = NULL; 474 - coro->mco_started = false; 475 - coro->is_ready = false; 476 - 477 - return coro; 478 - } 479 - 480 - static coroutine_t *create_generator(struct js *js, jsval_t gen_func, jsval_t *args, int nargs, bool is_async) { 481 - coroutine_t *coro = (coroutine_t *)malloc(sizeof(coroutine_t)); 482 - if (!coro) return NULL; 483 - 484 - coro->js = js; 485 - coro->type = is_async ? CORO_ASYNC_GENERATOR : CORO_GENERATOR; 486 - coro->scope = js->scope; 487 - coro->this_val = js->this_val; 488 - coro->awaited_promise = js_mkundef(); 489 - coro->result = js_mkundef(); 490 - coro->async_func = gen_func; 491 - 492 - if (nargs > 0) { 493 - coro->args = (jsval_t *)malloc(sizeof(jsval_t) * nargs); 494 - if (coro->args) { 495 - memcpy(coro->args, args, sizeof(jsval_t) * nargs); 496 - } 497 - } else { 498 - coro->args = NULL; 499 - } 500 - coro->nargs = nargs; 501 - 502 - coro->is_settled = false; 503 - coro->is_error = false; 504 - coro->is_done = false; 505 - coro->resume_point = 0; 506 - coro->yield_value = js_mkundef(); 507 - coro->next = NULL; 508 - 509 - return coro; 510 - } 511 - */ 512 470 513 471 static void enqueue_coroutine(coroutine_t *coro) { 514 472 if (!coro) return; ··· 947 905 return n; 948 906 } 949 907 908 + static bool is_internal_prop(const char *key, jsoff_t klen) { 909 + if (klen == 6 && memcmp(key, "__code", 6) == 0) return true; 910 + if (klen == 13 && memcmp(key, "__native_func", 13) == 0) return true; 911 + if (klen == 9 && memcmp(key, "prototype", 9) == 0) return true; 912 + if (klen == 9 && memcmp(key, "__proto__", 9) == 0) return true; 913 + return false; 914 + } 915 + 916 + static size_t strfunc_ctor(struct js *js, jsval_t func_obj, char *buf, size_t len) { 917 + if (is_circular(func_obj)) return cpy(buf, len, "[Circular]", 10); 918 + push_stringify(func_obj); 919 + 920 + size_t n = cpy(buf, len, "{", 1); 921 + bool first = true; 922 + 923 + jsoff_t next = loadoff(js, (jsoff_t) vdata(func_obj)) & ~(3U | CONSTMASK); 924 + while (next < js->brk && next != 0) { 925 + jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 926 + jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 927 + 928 + jsoff_t klen = offtolen(loadoff(js, koff)); 929 + const char *kstr = (const char *) &js->mem[koff + sizeof(jsoff_t)]; 930 + 931 + if (!is_internal_prop(kstr, klen)) { 932 + n += cpy(buf + n, len - n, first ? "" : ",", first ? 0 : 1); 933 + first = false; 934 + n += tostr(js, mkval(T_STR, koff), buf + n, len - n); 935 + n += cpy(buf + n, len - n, ":", 1); 936 + n += tostr(js, val, buf + n, len - n); 937 + } 938 + next = loadoff(js, next) & ~(3U | CONSTMASK); 939 + } 940 + 941 + jsoff_t proto_off = lkp(js, func_obj, "prototype", 9); 942 + if (proto_off != 0) { 943 + jsval_t proto_val = resolveprop(js, mkval(T_PROP, proto_off)); 944 + if (vtype(proto_val) == T_OBJ) { 945 + jsoff_t proto_next = loadoff(js, (jsoff_t) vdata(proto_val)) & ~(3U | CONSTMASK); 946 + while (proto_next < js->brk && proto_next != 0) { 947 + jsoff_t pkoff = loadoff(js, proto_next + (jsoff_t) sizeof(proto_next)); 948 + jsval_t pval = loadval(js, proto_next + (jsoff_t) (sizeof(proto_next) + sizeof(pkoff))); 949 + 950 + jsoff_t pklen = offtolen(loadoff(js, pkoff)); 951 + const char *pkstr = (const char *) &js->mem[pkoff + sizeof(jsoff_t)]; 952 + 953 + if (!is_internal_prop(pkstr, pklen)) { 954 + n += cpy(buf + n, len - n, first ? "" : ",", first ? 0 : 1); 955 + first = false; 956 + n += tostr(js, mkval(T_STR, pkoff), buf + n, len - n); 957 + n += cpy(buf + n, len - n, ":", 1); 958 + n += tostr(js, pval, buf + n, len - n); 959 + } 960 + proto_next = loadoff(js, proto_next) & ~(3U | CONSTMASK); 961 + } 962 + } 963 + } 964 + 965 + n += cpy(buf + n, len - n, "}", 1); 966 + pop_stringify(); 967 + return n; 968 + } 969 + 950 970 static size_t strfunc(struct js *js, jsval_t value, char *buf, size_t len) { 951 971 jsval_t func_obj = mkval(T_OBJ, vdata(value)); 952 972 jsoff_t code_off = lkp(js, func_obj, "__code", 6); 953 973 954 - if (code_off == 0) return cpy(buf, len, "function()", 10); 974 + if (code_off == 0) { 975 + jsoff_t native_off = lkp(js, func_obj, "__native_func", 13); 976 + if (native_off != 0) { 977 + jsval_t native_val = resolveprop(js, mkval(T_PROP, native_off)); 978 + if (vtype(native_val) == T_CFUNC) return strfunc_ctor(js, func_obj, buf, len); 979 + } 980 + return cpy(buf, len, "function()", 10); 981 + } 955 982 jsval_t code_val = resolveprop(js, mkval(T_PROP, code_off)); 956 983 957 984 if (vtype(code_val) != T_STR) return cpy(buf, len, "function()", 10); 985 + 958 986 jsoff_t sn, off = vstr(js, code_val, &sn); 959 - size_t n = cpy(buf, len, "function", 8); 987 + if (sn >= 9 && memcmp(&js->mem[off], "__builtin", 9) == 0) { 988 + return strfunc_ctor(js, func_obj, buf, len); 989 + } 960 990 991 + size_t n = cpy(buf, len, "function", 8); 961 992 return n + cpy(buf + n, len - n, (char *) &js->mem[off], sn); 962 993 } 963 994 ··· 1523 1554 } 1524 1555 1525 1556 static jsval_t mkarr(struct js *js) { 1526 - return mkobj(js, 0); 1557 + jsval_t arr = mkobj(js, 0); 1558 + jsval_t array_proto = get_ctor_proto(js, "Array", 5); 1559 + if (vtype(array_proto) == T_OBJ) { 1560 + set_proto(js, arr, array_proto); 1561 + } 1562 + return mkval(T_ARR, vdata(arr)); 1527 1563 } 1528 1564 1529 1565 static jsoff_t arr_length(struct js *js, jsval_t arr) { ··· 2269 2305 return lkp_inline(js, obj, buf, len); 2270 2306 } 2271 2307 2308 + static jsval_t get_proto(struct js *js, jsval_t obj) { 2309 + uint8_t t = vtype(obj); 2310 + 2311 + if (t != T_OBJ && t != T_ARR && t != T_FUNC) return js_mknull(); 2312 + jsval_t as_obj = (t == T_OBJ) ? obj : mkval(T_OBJ, vdata(obj)); 2313 + 2314 + jsoff_t off = lkp(js, as_obj, "__proto__", 9); 2315 + if (off == 0) return js_mknull(); 2316 + 2317 + jsval_t val = resolveprop(js, mkval(T_PROP, off)); 2318 + uint8_t vt = vtype(val); 2319 + 2320 + return (vt == T_OBJ || vt == T_ARR || vt == T_FUNC) ? val : js_mknull(); 2321 + } 2322 + 2323 + static void set_proto(struct js *js, jsval_t obj, jsval_t proto) { 2324 + uint8_t t = vtype(obj); 2325 + if (t != T_OBJ && t != T_ARR && t != T_FUNC) return; 2326 + 2327 + jsval_t as_obj = (t == T_OBJ) ? obj : mkval(T_OBJ, vdata(obj)); 2328 + jsval_t key = js_mkstr(js, "__proto__", 9); 2329 + setprop(js, as_obj, key, proto); 2330 + } 2331 + 2332 + static jsval_t get_ctor_proto(struct js *js, const char *name, size_t len) { 2333 + jsoff_t ctor_off = lkp(js, js->scope, name, len); 2334 + 2335 + if (ctor_off == 0 && global_scope_stack) { 2336 + int stack_len = utarray_len(global_scope_stack); 2337 + for (int i = stack_len - 1; i >= 0 && ctor_off == 0; i--) { 2338 + jsoff_t *scope_off = (jsoff_t *)utarray_eltptr(global_scope_stack, i); 2339 + jsval_t scope = mkval(T_OBJ, *scope_off); 2340 + ctor_off = lkp(js, scope, name, len); 2341 + } 2342 + } else if (ctor_off == 0) { 2343 + for (jsval_t scope = upper(js, js->scope); vdata(scope) != 0 && ctor_off == 0; scope = upper(js, scope)) { 2344 + ctor_off = lkp(js, scope, name, len); 2345 + } 2346 + } 2347 + 2348 + if (ctor_off == 0) return js_mknull(); 2349 + jsval_t ctor = resolveprop(js, mkval(T_PROP, ctor_off)); 2350 + if (vtype(ctor) != T_FUNC) return js_mknull(); 2351 + jsval_t ctor_obj = mkval(T_OBJ, vdata(ctor)); 2352 + jsoff_t proto_off = lkp(js, ctor_obj, "prototype", 9); 2353 + 2354 + if (proto_off == 0) return js_mknull(); 2355 + return resolveprop(js, mkval(T_PROP, proto_off)); 2356 + } 2357 + 2358 + static jsval_t get_prototype_for_type(struct js *js, uint8_t type) { 2359 + switch (type) { 2360 + case T_STR: return get_ctor_proto(js, "String", 6); 2361 + case T_NUM: return get_ctor_proto(js, "Number", 6); 2362 + case T_BOOL: return get_ctor_proto(js, "Boolean", 7); 2363 + case T_ARR: return get_ctor_proto(js, "Array", 5); 2364 + case T_FUNC: return get_ctor_proto(js, "Function", 8); 2365 + case T_PROMISE: return get_ctor_proto(js, "Promise", 7); 2366 + case T_OBJ: return get_ctor_proto(js, "Object", 6); 2367 + default: return js_mknull(); 2368 + } 2369 + } 2370 + 2371 + static jsoff_t lkp_proto(struct js *js, jsval_t obj, const char *key, size_t len) { 2372 + if (streq(key, len, "__proto__", 9)) { 2373 + uint8_t t = vtype(obj); 2374 + if (t == T_OBJ || t == T_ARR || t == T_FUNC) { 2375 + jsval_t as_obj = (t == T_OBJ) ? obj : mkval(T_OBJ, vdata(obj)); 2376 + return lkp(js, as_obj, key, len); 2377 + } 2378 + return 0; 2379 + } 2380 + 2381 + jsval_t cur = obj; 2382 + int depth = 0; 2383 + const int MAX_PROTO_DEPTH = 32; 2384 + 2385 + while (depth < MAX_PROTO_DEPTH) { 2386 + uint8_t t = vtype(cur); 2387 + 2388 + if (t == T_OBJ || t == T_ARR || t == T_FUNC) { 2389 + jsval_t as_obj = (t == T_OBJ) ? cur : mkval(T_OBJ, vdata(cur)); 2390 + jsoff_t off = lkp(js, as_obj, key, len); 2391 + if (off != 0) return off; 2392 + 2393 + cur = get_proto(js, cur); 2394 + if (vtype(cur) == T_NULL || vtype(cur) == T_UNDEF) break; 2395 + depth++; 2396 + } else if (t == T_STR || t == T_NUM || t == T_BOOL) { 2397 + jsval_t proto = get_prototype_for_type(js, t); 2398 + if (vtype(proto) == T_NULL || vtype(proto) == T_UNDEF) break; 2399 + cur = proto; 2400 + depth++; 2401 + } 2402 + else break; 2403 + } 2404 + 2405 + return 0; 2406 + } 2407 + 2272 2408 static jsval_t try_dynamic_getter(struct js *js, jsval_t obj, const char *key, size_t key_len) { 2273 2409 if (streq(key, key_len, "__getter", 8)) return js_mkundef(); 2274 2410 ··· 2318 2454 } 2319 2455 2320 2456 static jsval_t resolveprop(struct js *js, jsval_t v) { 2457 + if (vtype(v) == T_PROPREF) return js_mkundef(); 2321 2458 if (vtype(v) != T_PROP) return v; 2322 2459 return resolveprop(js, loadval(js, (jsoff_t) (vdata(v) + sizeof(jsoff_t) * 2))); 2323 2460 } 2324 2461 2325 2462 static jsval_t assign(struct js *js, jsval_t lhs, jsval_t val) { 2463 + if (vtype(lhs) == T_PROPREF) { 2464 + jsoff_t obj_off = propref_obj(lhs); 2465 + jsoff_t key_off = propref_key(lhs); 2466 + jsval_t obj = mkval(T_OBJ, obj_off); 2467 + jsval_t key = mkval(T_STR, key_off); 2468 + return setprop(js, obj, key, val); 2469 + } 2470 + 2326 2471 jsoff_t propoff = (jsoff_t) vdata(lhs); 2327 2472 if (is_const_prop(js, propoff)) { 2328 2473 return js_mkerr(js, "assignment to constant"); ··· 2495 2640 2496 2641 static jsval_t do_dot_op(struct js *js, jsval_t l, jsval_t r) { 2497 2642 const char *ptr = (char *) &js->code[coderefoff(r)]; 2643 + size_t plen = codereflen(r); 2498 2644 2499 2645 if (vtype(r) != T_CODEREF) return js_mkerr(js, "ident expected"); 2500 - if (vtype(l) == T_STR) { 2501 - if (streq(ptr, codereflen(r), "length", 6)) { 2502 - return tov(offtolen(loadoff(js, (jsoff_t) vdata(l)))); 2503 - } else if (streq(ptr, codereflen(r), "indexOf", 7)) { 2504 - return js_mkfun(builtin_string_indexOf); 2505 - } else if (streq(ptr, codereflen(r), "substring", 9)) { 2506 - return js_mkfun(builtin_string_substring); 2507 - } else if (streq(ptr, codereflen(r), "split", 5)) { 2508 - return js_mkfun(builtin_string_split); 2509 - } else if (streq(ptr, codereflen(r), "slice", 5)) { 2510 - return js_mkfun(builtin_string_slice); 2511 - } else if (streq(ptr, codereflen(r), "includes", 8)) { 2512 - return js_mkfun(builtin_string_includes); 2513 - } else if (streq(ptr, codereflen(r), "startsWith", 10)) { 2514 - return js_mkfun(builtin_string_startsWith); 2515 - } else if (streq(ptr, codereflen(r), "endsWith", 8)) { 2516 - return js_mkfun(builtin_string_endsWith); 2517 - } else if (streq(ptr, codereflen(r), "replace", 7)) { 2518 - return js_mkfun(builtin_string_replace); 2519 - } else if (streq(ptr, codereflen(r), "template", 8)) { 2520 - return js_mkfun(builtin_string_template); 2521 - } else if (streq(ptr, codereflen(r), "charCodeAt", 10)) { 2522 - return js_mkfun(builtin_string_charCodeAt); 2523 - } else if (streq(ptr, codereflen(r), "toLowerCase", 11)) { 2524 - return js_mkfun(builtin_string_toLowerCase); 2525 - } else if (streq(ptr, codereflen(r), "toUpperCase", 11)) { 2526 - return js_mkfun(builtin_string_toUpperCase); 2527 - } else if (streq(ptr, codereflen(r), "trim", 4)) { 2528 - return js_mkfun(builtin_string_trim); 2529 - } else if (streq(ptr, codereflen(r), "repeat", 6)) { 2530 - return js_mkfun(builtin_string_repeat); 2531 - } else if (streq(ptr, codereflen(r), "padStart", 8)) { 2532 - return js_mkfun(builtin_string_padStart); 2533 - } else if (streq(ptr, codereflen(r), "padEnd", 6)) { 2534 - return js_mkfun(builtin_string_padEnd); 2535 - } else if (streq(ptr, codereflen(r), "charAt", 6)) { 2536 - return js_mkfun(builtin_string_charAt); 2537 - } 2538 - } 2646 + uint8_t t = vtype(l); 2539 2647 2540 - if (vtype(l) == T_NUM) { 2541 - if (streq(ptr, codereflen(r), "toString", 8)) { 2542 - return js_mkfun(builtin_number_toString); 2543 - } else if (streq(ptr, codereflen(r), "toFixed", 7)) { 2544 - return js_mkfun(builtin_number_toFixed); 2545 - } else if (streq(ptr, codereflen(r), "toPrecision", 11)) { 2546 - return js_mkfun(builtin_number_toPrecision); 2547 - } else if (streq(ptr, codereflen(r), "toExponential", 13)) { 2548 - return js_mkfun(builtin_number_toExponential); 2549 - } 2648 + if (t == T_STR && streq(ptr, plen, "length", 6)) { 2649 + return tov(offtolen(loadoff(js, (jsoff_t) vdata(l)))); 2550 2650 } 2551 2651 2552 - if (vtype(l) == T_ARR && streq(ptr, codereflen(r), "length", 6)) { 2652 + if (t == T_ARR && streq(ptr, plen, "length", 6)) { 2553 2653 jsoff_t off = lkp(js, l, "length", 6); 2554 2654 if (off == 0) return tov(0); 2555 2655 return resolveprop(js, mkval(T_PROP, off)); 2556 2656 } 2557 2657 2558 - if (vtype(l) == T_ARR) { 2559 - if (streq(ptr, codereflen(r), "push", 4)) { 2560 - return js_mkfun(builtin_array_push); 2561 - } else if (streq(ptr, codereflen(r), "pop", 3)) { 2562 - return js_mkfun(builtin_array_pop); 2563 - } else if (streq(ptr, codereflen(r), "slice", 5)) { 2564 - return js_mkfun(builtin_array_slice); 2565 - } else if (streq(ptr, codereflen(r), "join", 4)) { 2566 - return js_mkfun(builtin_array_join); 2567 - } else if (streq(ptr, codereflen(r), "includes", 8)) { 2568 - return js_mkfun(builtin_array_includes); 2569 - } else if (streq(ptr, codereflen(r), "every", 5)) { 2570 - return js_mkfun(builtin_array_every); 2658 + if (t == T_STR || t == T_NUM || t == T_BOOL) { 2659 + jsoff_t off = lkp_proto(js, l, ptr, plen); 2660 + if (off != 0) { 2661 + return resolveprop(js, mkval(T_PROP, off)); 2571 2662 } 2663 + return js_mkundef(); 2572 2664 } 2573 2665 2574 - if (vtype(l) == T_OBJ) { 2575 - jsoff_t map_off = lkp(js, l, "__map", 5); 2576 - if (map_off != 0) { 2577 - if (streq(ptr, codereflen(r), "set", 3)) { 2578 - return js_mkfun(map_set); 2579 - } else if (streq(ptr, codereflen(r), "get", 3)) { 2580 - return js_mkfun(map_get); 2581 - } else if (streq(ptr, codereflen(r), "has", 3)) { 2582 - return js_mkfun(map_has); 2583 - } else if (streq(ptr, codereflen(r), "delete", 6)) { 2584 - return js_mkfun(map_delete); 2585 - } else if (streq(ptr, codereflen(r), "clear", 5)) { 2586 - return js_mkfun(map_clear); 2587 - } else if (streq(ptr, codereflen(r), "size", 4)) { 2588 - return js_mkfun(map_size); 2589 - } 2666 + if (t == T_PROMISE) { 2667 + jsoff_t off = lkp_proto(js, mkval(T_OBJ, vdata(l)), ptr, plen); 2668 + if (off != 0) { 2669 + return resolveprop(js, mkval(T_PROP, off)); 2590 2670 } 2591 - 2592 - jsoff_t set_off = lkp(js, l, "__set", 5); 2593 - if (set_off != 0) { 2594 - if (streq(ptr, codereflen(r), "add", 3)) { 2595 - return js_mkfun(set_add); 2596 - } else if (streq(ptr, codereflen(r), "has", 3)) { 2597 - return js_mkfun(set_has); 2598 - } else if (streq(ptr, codereflen(r), "delete", 6)) { 2599 - return js_mkfun(set_delete); 2600 - } else if (streq(ptr, codereflen(r), "clear", 5)) { 2601 - return js_mkfun(set_clear); 2602 - } else if (streq(ptr, codereflen(r), "size", 4)) { 2603 - return js_mkfun(set_size); 2671 + jsval_t promise_proto = get_ctor_proto(js, "Promise", 7); 2672 + if (vtype(promise_proto) != T_UNDEF && vtype(promise_proto) != T_NULL) { 2673 + off = lkp_proto(js, promise_proto, ptr, plen); 2674 + if (off != 0) { 2675 + return resolveprop(js, mkval(T_PROP, off)); 2604 2676 } 2605 2677 } 2678 + return js_mkundef(); 2606 2679 } 2607 2680 2608 - if (vtype(l) == T_PROMISE) { 2609 - if (streq(ptr, codereflen(r), "then", 4)) { 2610 - return js_mkfun(builtin_promise_then); 2611 - } else if (streq(ptr, codereflen(r), "catch", 5)) { 2612 - return js_mkfun(builtin_promise_catch); 2613 - } else if (streq(ptr, codereflen(r), "finally", 7)) { 2614 - return js_mkfun(builtin_promise_finally); 2615 - } 2681 + if (t == T_FUNC) { 2682 + jsval_t func_obj = mkval(T_OBJ, vdata(l)); 2683 + jsoff_t off = lkp_proto(js, func_obj, ptr, plen); 2684 + if (off != 0) return mkval(T_PROP, off); 2685 + if (streq(ptr, plen, "name", 4)) return js_mkstr(js, "", 0); 2686 + jsval_t key = js_mkstr(js, ptr, plen); 2687 + jsval_t prop = setprop(js, func_obj, key, js_mkundef()); 2688 + return prop; 2616 2689 } 2617 2690 2618 - if (vtype(l) == T_FUNC) { 2619 - jsval_t func_obj = mkval(T_OBJ, vdata(l)); 2620 - jsoff_t off = lkp(js, func_obj, ptr, codereflen(r)); 2621 - if (off == 0) { 2622 - if (streq(ptr, codereflen(r), "name", 4)) { 2623 - return js_mkstr(js, "", 0); 2624 - } 2625 - jsval_t key = js_mkstr(js, ptr, codereflen(r)); 2626 - jsval_t prop = setprop(js, func_obj, key, js_mkundef()); 2627 - return prop; 2628 - } 2629 - return mkval(T_PROP, off); 2691 + if (t != T_OBJ && t != T_ARR) { 2692 + return js_mkerr(js, "lookup in non-obj"); 2630 2693 } 2631 2694 2632 - if (vtype(l) != T_OBJ && vtype(l) != T_ARR) return js_mkerr(js, "lookup in non-obj"); 2633 - jsoff_t off = lkp(js, l, ptr, codereflen(r)); 2634 - if (off == 0) { 2635 - jsval_t result = try_dynamic_getter(js, l, ptr, codereflen(r)); 2636 - if (vtype(result) != T_UNDEF) { 2637 - off = lkp(js, l, ptr, codereflen(r)); 2638 - if (off != 0) return mkval(T_PROP, off); 2639 - } 2640 - jsval_t key = js_mkstr(js, ptr, codereflen(r)); 2641 - jsval_t prop = setprop(js, l, key, js_mkundef()); 2642 - return prop; 2695 + jsoff_t own_off = lkp(js, l, ptr, plen); 2696 + if (own_off != 0) { 2697 + return mkval(T_PROP, own_off); 2643 2698 } 2644 2699 2645 - return mkval(T_PROP, off); 2700 + jsval_t result = try_dynamic_getter(js, l, ptr, plen); 2701 + if (vtype(result) != T_UNDEF) { 2702 + own_off = lkp(js, l, ptr, plen); 2703 + if (own_off != 0) return mkval(T_PROP, own_off); 2704 + } 2705 + 2706 + jsoff_t proto_off = lkp_proto(js, l, ptr, plen); 2707 + if (proto_off != 0) return resolveprop(js, mkval(T_PROP, proto_off)); 2708 + 2709 + jsval_t key = js_mkstr(js, ptr, plen); 2710 + return mkpropref((jsoff_t)vdata(l), (jsoff_t)vdata(key)); 2646 2711 } 2647 2712 2648 2713 static jsval_t do_optional_chain_op(struct js *js, jsval_t l, jsval_t r) { 2649 - if (vtype(l) == T_NULL || vtype(l) == T_UNDEF) { 2650 - return js_mkundef(); 2651 - } 2714 + if (vtype(l) == T_NULL || vtype(l) == T_UNDEF) return js_mkundef(); 2652 2715 return do_dot_op(js, l, r); 2653 2716 } 2654 2717 ··· 3046 3109 if (vtype(args) != T_CODEREF) return js_mkerr(js, "bad call"); 3047 3110 if (vtype(func) != T_FUNC && vtype(func) != T_CFUNC) 3048 3111 return js_mkerr(js, "calling non-function"); 3112 + 3113 + jsval_t target_this = peek_this(); 3114 + if (vtype(func) == T_FUNC && vtype(target_this) == T_OBJ) { 3115 + jsoff_t proto_check = lkp(js, target_this, "__proto__", 9); 3116 + if (proto_check == 0) { 3117 + jsval_t func_obj = mkval(T_OBJ, vdata(func)); 3118 + jsoff_t proto_off = lkp(js, func_obj, "prototype", 9); 3119 + if (proto_off != 0) { 3120 + jsval_t proto = resolveprop(js, mkval(T_PROP, proto_off)); 3121 + if (vtype(proto) == T_OBJ) set_proto(js, target_this, proto); 3122 + } 3123 + } 3124 + } 3125 + 3049 3126 const char *code = js->code; 3050 3127 jsoff_t clen = js->clen, pos = js->pos; 3051 3128 ··· 3101 3178 } 3102 3179 } 3103 3180 3104 - push_call_frame(js->filename, func_name ? func_name : "<anonymous>", call_line, call_col); 3181 + push_call_frame( 3182 + js->filename, 3183 + func_name ? func_name : "<anonymous>", 3184 + call_line, call_col 3185 + ); 3105 3186 3106 3187 jsval_t saved_func = js->current_func; 3107 3188 js->current_func = func; ··· 3132 3213 if (js->flags & F_NOEXEC) return 0; 3133 3214 jsval_t l = resolveprop(js, lhs), r = resolveprop(js, rhs); 3134 3215 setlwm(js); 3216 + 3135 3217 if (is_err(l)) return l; 3136 3218 if (is_err(r)) return r; 3137 - if (is_assign(op) && vtype(lhs) != T_PROP) return js_mkerr(js, "bad lhs"); 3219 + if (is_assign(op) && vtype(lhs) != T_PROP && vtype(lhs) != T_PROPREF) return js_mkerr(js, "bad lhs"); 3220 + 3138 3221 switch (op) { 3139 3222 case TOK_TYPEOF: return js_mkstr(js, typestr(vtype(r)), strlen(typestr(vtype(r)))); 3140 3223 case TOK_VOID: return js_mkundef(); ··· 3596 3679 uint8_t exe = !(js->flags & F_NOEXEC); 3597 3680 jsval_t obj = exe ? mkobj(js, 0) : js_mkundef(); 3598 3681 if (is_err(obj)) return obj; 3682 + if (exe) { 3683 + jsval_t object_proto = get_ctor_proto(js, "Object", 6); 3684 + if (vtype(object_proto) == T_OBJ) set_proto(js, obj, object_proto); 3685 + } 3599 3686 js->consumed = 1; 3600 3687 3601 3688 while (next(js) != TOK_RBRACE) { ··· 6060 6147 6061 6148 if (exe) { 6062 6149 jsval_t super_constructor = js_mkundef(); 6150 + jsval_t super_proto = js_mknull(); 6063 6151 if (super_len > 0) { 6064 6152 jsval_t super_val = lookup(js, &js->code[super_off], super_len); 6065 6153 if (is_err(super_val)) return super_val; ··· 6067 6155 if (vtype(super_constructor) != T_FUNC && vtype(super_constructor) != T_CFUNC) { 6068 6156 return js_mkerr(js, "super class must be a constructor"); 6069 6157 } 6158 + jsval_t super_obj = mkval(T_OBJ, vdata(super_constructor)); 6159 + jsoff_t super_proto_off = lkp(js, super_obj, "prototype", 9); 6160 + if (super_proto_off != 0) { 6161 + super_proto = resolveprop(js, mkval(T_PROP, super_proto_off)); 6162 + } 6163 + } 6164 + 6165 + jsval_t proto = js_mkobj(js); 6166 + if (is_err(proto)) return proto; 6167 + 6168 + if (vtype(super_proto) == T_OBJ) { 6169 + set_proto(js, proto, super_proto); 6170 + } else { 6171 + jsval_t object_proto = get_ctor_proto(js, "Object", 6); 6172 + if (vtype(object_proto) == T_OBJ) set_proto(js, proto, object_proto); 6173 + } 6174 + 6175 + jsval_t func_scope = mkobj(js, (jsoff_t) vdata(js->scope)); 6176 + if (super_len > 0) { 6177 + jsval_t super_key = js_mkstr(js, "super", 5); 6178 + if (is_err(super_key)) return super_key; 6179 + jsval_t res_super = setprop(js, func_scope, super_key, super_constructor); 6180 + if (is_err(res_super)) return res_super; 6181 + } 6182 + 6183 + for (int i = 0; i < method_count; i++) { 6184 + if (methods[i].is_static) continue; 6185 + if (methods[i].is_field) continue; 6186 + 6187 + jsval_t method_name = js_mkstr(js, &js->code[methods[i].name_off], methods[i].name_len); 6188 + if (is_err(method_name)) return method_name; 6189 + 6190 + jsoff_t mlen = methods[i].fn_end - methods[i].fn_start; 6191 + jsval_t method_code = js_mkstr(js, &js->code[methods[i].fn_start], mlen); 6192 + if (is_err(method_code)) return method_code; 6193 + 6194 + jsval_t method_obj = mkobj(js, 0); 6195 + if (is_err(method_obj)) return method_obj; 6196 + 6197 + jsval_t mcode_key = js_mkstr(js, "__code", 6); 6198 + if (is_err(mcode_key)) return mcode_key; 6199 + 6200 + if (methods[i].is_async) { 6201 + char *async_code = malloc(mlen + 7); 6202 + if (!async_code) return js_mkerr(js, "oom"); 6203 + memcpy(async_code, "async ", 6); 6204 + memcpy(async_code + 6, &js->code[methods[i].fn_start], mlen); 6205 + method_code = js_mkstr(js, async_code, mlen + 6); 6206 + free(async_code); 6207 + if (is_err(method_code)) return method_code; 6208 + } 6209 + 6210 + jsval_t mres = setprop(js, method_obj, mcode_key, method_code); 6211 + if (is_err(mres)) return mres; 6212 + 6213 + jsval_t mscope_key = js_mkstr(js, "__scope", 7); 6214 + if (is_err(mscope_key)) return mscope_key; 6215 + jsval_t mscope_res = setprop(js, method_obj, mscope_key, func_scope); 6216 + if (is_err(mscope_res)) return mscope_res; 6217 + 6218 + jsval_t method_func = mkval(T_FUNC, (unsigned long) vdata(method_obj)); 6219 + jsval_t set_res = setprop(js, proto, method_name, method_func); 6220 + if (is_err(set_res)) return set_res; 6070 6221 } 6071 6222 6072 6223 jsoff_t wrapper_size = 256; ··· 6075 6226 } 6076 6227 6077 6228 for (int i = 0; i < method_count; i++) { 6229 + if (methods[i].is_static) continue; 6230 + if (!methods[i].is_field) continue; 6078 6231 wrapper_size += methods[i].name_len + 20; 6079 - wrapper_size += methods[i].fn_end - methods[i].fn_start; 6232 + wrapper_size += methods[i].field_end - methods[i].field_start; 6080 6233 } 6081 6234 6082 6235 char *wrapper = (char *) malloc(wrapper_size); ··· 6092 6245 wp += 2; 6093 6246 } 6094 6247 wrapper[wp++] = '{'; 6095 - if (constructor_body_start > 0) { 6096 - jsoff_t blen = constructor_body_end - constructor_body_start; 6097 - memcpy(wrapper + wp, &js->code[constructor_body_start], blen); 6098 - wp += blen; 6099 - while (wp > 0 && (wrapper[wp - 1] == ' ' || wrapper[wp - 1] == '\t' || 6100 - wrapper[wp - 1] == '\n' || wrapper[wp - 1] == '\r')) { 6101 - wp--; 6102 - } 6103 - if (wp > 0 && wrapper[wp - 1] != ';' && wrapper[wp - 1] != '}') { 6104 - wrapper[wp++] = ';'; 6105 - } 6106 - } 6248 + 6107 6249 for (int i = 0; i < method_count; i++) { 6108 6250 if (methods[i].is_static) continue; 6109 - if (methods[i].is_field) continue; 6251 + if (!methods[i].is_field) continue; 6252 + 6110 6253 if (wp > 0 && wrapper[wp - 1] != ';' && wrapper[wp - 1] != '{') { 6111 6254 wrapper[wp++] = ';'; 6112 6255 } ··· 6115 6258 memcpy(wrapper + wp, &js->code[methods[i].name_off], methods[i].name_len); 6116 6259 wp += methods[i].name_len; 6117 6260 wrapper[wp++] = '='; 6118 - if (methods[i].is_async) { 6119 - memcpy(wrapper + wp, "async ", 6); 6120 - wp += 6; 6261 + if (methods[i].field_start > 0 && methods[i].field_end > methods[i].field_start) { 6262 + jsoff_t flen = methods[i].field_end - methods[i].field_start; 6263 + memcpy(wrapper + wp, &js->code[methods[i].field_start], flen); 6264 + wp += flen; 6265 + } else { 6266 + memcpy(wrapper + wp, "undefined", 9); 6267 + wp += 9; 6121 6268 } 6122 - memcpy(wrapper + wp, "function", 8); 6123 - wp += 8; 6124 - jsoff_t mlen = methods[i].fn_end - methods[i].fn_start; 6125 - memcpy(wrapper + wp, &js->code[methods[i].fn_start], mlen); 6126 - wp += mlen; 6127 6269 wrapper[wp++] = ';'; 6128 6270 } 6129 6271 6272 + if (constructor_body_start > 0) { 6273 + jsoff_t blen = constructor_body_end - constructor_body_start; 6274 + memcpy(wrapper + wp, &js->code[constructor_body_start], blen); 6275 + wp += blen; 6276 + while (wp > 0 && (wrapper[wp - 1] == ' ' || wrapper[wp - 1] == '\t' || 6277 + wrapper[wp - 1] == '\n' || wrapper[wp - 1] == '\r')) { 6278 + wp--; 6279 + } 6280 + if (wp > 0 && wrapper[wp - 1] != ';' && wrapper[wp - 1] != '}') { 6281 + wrapper[wp++] = ';'; 6282 + } 6283 + } 6284 + 6130 6285 wrapper[wp++] = '}'; 6131 6286 jsval_t code_str = js_mkstr(js, wrapper, wp); 6132 6287 free(wrapper); 6133 6288 if (is_err(code_str)) return code_str; 6289 + 6134 6290 jsval_t func_obj = mkobj(js, 0); 6135 6291 if (is_err(func_obj)) return func_obj; 6136 6292 jsval_t code_key = js_mkstr(js, "__code", 6); 6137 6293 if (is_err(code_key)) return code_key; 6138 6294 jsval_t res2 = setprop(js, func_obj, code_key, code_str); 6139 6295 if (is_err(res2)) return res2; 6140 - jsval_t func_scope = mkobj(js, (jsoff_t) vdata(js->scope)); 6141 - 6142 - if (super_len > 0) { 6143 - jsval_t super_key = js_mkstr(js, "super", 5); 6144 - if (is_err(super_key)) return super_key; 6145 - jsval_t res_super = setprop(js, func_scope, super_key, super_constructor); 6146 - if (is_err(res_super)) return res_super; 6147 - } 6148 6296 6149 6297 jsval_t scope_key = js_mkstr(js, "__scope", 7); 6150 6298 if (is_err(scope_key)) return scope_key; ··· 6157 6305 if (is_err(name_val)) return name_val; 6158 6306 jsval_t res_name = setprop(js, func_obj, name_key, name_val); 6159 6307 if (is_err(res_name)) return res_name; 6308 + 6309 + jsval_t proto_key = js_mkstr(js, "prototype", 9); 6310 + if (is_err(proto_key)) return proto_key; 6311 + jsval_t proto_res = setprop(js, func_obj, proto_key, proto); 6312 + if (is_err(proto_res)) return proto_res; 6160 6313 6161 6314 jsval_t constructor = mkval(T_FUNC, (unsigned long) vdata(func_obj)); 6162 6315 if (lkp(js, js->scope, class_name, class_name_len) > 0) { ··· 6920 7073 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 6921 7074 jsoff_t klen = offtolen(loadoff(js, koff)); 6922 7075 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 6923 - char idxstr[16]; 6924 - snprintf(idxstr, sizeof(idxstr), "%u", (unsigned) idx); 6925 - jsval_t idx_key = js_mkstr(js, idxstr, strlen(idxstr)); 6926 - jsval_t key_val = js_mkstr(js, key, klen); 6927 - setprop(js, arr, idx_key, key_val); 6928 - idx++; 7076 + // Skip internal __proto__ property 7077 + if (!streq(key, klen, "__proto__", 9)) { 7078 + char idxstr[16]; 7079 + snprintf(idxstr, sizeof(idxstr), "%u", (unsigned) idx); 7080 + jsval_t idx_key = js_mkstr(js, idxstr, strlen(idxstr)); 7081 + jsval_t key_val = js_mkstr(js, key, klen); 7082 + setprop(js, arr, idx_key, key_val); 7083 + idx++; 7084 + } 6929 7085 next = loadoff(js, next) & ~(3U | CONSTMASK); 6930 7086 } 6931 7087 ··· 6933 7089 jsval_t len_val = tov((double) idx); 6934 7090 setprop(js, arr, len_key, len_val); 6935 7091 return mkval(T_ARR, vdata(arr)); 7092 + } 7093 + 7094 + static jsval_t builtin_object_getPrototypeOf(struct js *js, jsval_t *args, int nargs) { 7095 + if (nargs == 0) return js_mkerr(js, "Object.getPrototypeOf requires an argument"); 7096 + jsval_t obj = args[0]; 7097 + uint8_t t = vtype(obj); 7098 + 7099 + if (t == T_STR || t == T_NUM || t == T_BOOL) return get_prototype_for_type(js, t); 7100 + if (t == T_OBJ || t == T_ARR || t == T_FUNC) return get_proto(js, obj); 7101 + 7102 + return js_mknull(); 7103 + } 7104 + 7105 + static jsval_t builtin_object_setPrototypeOf(struct js *js, jsval_t *args, int nargs) { 7106 + if (nargs < 2) return js_mkerr(js, "Object.setPrototypeOf requires 2 arguments"); 7107 + 7108 + jsval_t obj = args[0]; 7109 + jsval_t proto = args[1]; 7110 + 7111 + uint8_t t = vtype(obj); 7112 + if (t != T_OBJ && t != T_ARR && t != T_FUNC) { 7113 + return js_mkerr(js, "Object.setPrototypeOf: first argument must be an object"); 7114 + } 7115 + 7116 + uint8_t pt = vtype(proto); 7117 + if (pt != T_OBJ && pt != T_ARR && pt != T_FUNC && pt != T_NULL) { 7118 + return js_mkerr(js, "Object.setPrototypeOf: prototype must be an object or null"); 7119 + } 7120 + 7121 + if (pt != T_NULL) { 7122 + jsval_t cur = proto; 7123 + int depth = 0; 7124 + while (vtype(cur) != T_NULL && depth < 32) { 7125 + if (vdata(cur) == vdata(obj)) return js_mkerr(js, "Cyclic __proto__ value"); 7126 + cur = get_proto(js, cur); 7127 + depth++; 7128 + } 7129 + } 7130 + 7131 + set_proto(js, obj, proto); 7132 + return obj; 7133 + } 7134 + 7135 + static jsval_t builtin_object_create(struct js *js, jsval_t *args, int nargs) { 7136 + if (nargs == 0) return js_mkerr(js, "Object.create requires a prototype argument"); 7137 + 7138 + jsval_t proto = args[0]; 7139 + uint8_t pt = vtype(proto); 7140 + 7141 + if (pt != T_OBJ && pt != T_ARR && pt != T_FUNC && pt != T_NULL) { 7142 + return js_mkerr(js, "Object.create: prototype must be an object or null"); 7143 + } 7144 + 7145 + jsval_t obj = js_mkobj(js); 7146 + if (pt != T_NULL) { 7147 + set_proto(js, obj, proto); 7148 + } 7149 + 7150 + if (nargs >= 2 && vtype(args[1]) == T_OBJ) { 7151 + jsval_t props = args[1]; 7152 + jsoff_t next = loadoff(js, (jsoff_t) vdata(props)) & ~(3U | CONSTMASK); 7153 + 7154 + while (next < js->brk && next != 0) { 7155 + jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 7156 + jsoff_t klen = offtolen(loadoff(js, koff)); 7157 + const char *key = (char *) &js->mem[koff + sizeof(koff)]; 7158 + jsval_t descriptor = resolveprop(js, mkval(T_PROP, next)); 7159 + 7160 + if (vtype(descriptor) == T_OBJ) { 7161 + jsoff_t val_off = lkp(js, descriptor, "value", 5); 7162 + if (val_off != 0) { 7163 + jsval_t val = resolveprop(js, mkval(T_PROP, val_off)); 7164 + jsval_t key_str = js_mkstr(js, key, klen); 7165 + setprop(js, obj, key_str, val); 7166 + } 7167 + } 7168 + 7169 + next = loadoff(js, next) & ~(3U | CONSTMASK); 7170 + } 7171 + } 7172 + 7173 + return obj; 7174 + } 7175 + 7176 + static jsval_t builtin_object_hasOwn(struct js *js, jsval_t *args, int nargs) { 7177 + if (nargs < 2) return mkval(T_BOOL, 0); 7178 + 7179 + jsval_t obj = args[0]; 7180 + jsval_t key = args[1]; 7181 + 7182 + uint8_t t = vtype(obj); 7183 + 7184 + if (t != T_OBJ && t != T_ARR && t != T_FUNC) return mkval(T_BOOL, 0); 7185 + if (vtype(key) != T_STR) return mkval(T_BOOL, 0); 7186 + 7187 + jsval_t as_obj = (t == T_OBJ) ? obj : mkval(T_OBJ, vdata(obj)); 7188 + jsoff_t key_len, key_off = vstr(js, key, &key_len); 7189 + const char *key_str = (char *) &js->mem[key_off]; 7190 + 7191 + jsoff_t off = lkp(js, as_obj, key_str, key_len); 7192 + return mkval(T_BOOL, off != 0 ? 1 : 0); 6936 7193 } 6937 7194 6938 7195 static jsval_t builtin_array_push(struct js *js, jsval_t *args, int nargs) { ··· 8418 8675 8419 8676 static jsval_t do_instanceof(struct js *js, jsval_t l, jsval_t r) { 8420 8677 uint8_t ltype = vtype(l); 8421 - if (vtype(r) == T_FUNC) { 8422 - jsval_t func_obj = mkval(T_OBJ, vdata(r)); 8423 - jsoff_t native_off = lkp(js, func_obj, "__native_func", 13); 8424 - if (native_off != 0) { 8425 - jsval_t native_val = resolveprop(js, mkval(T_PROP, native_off)); 8426 - if (vtype(native_val) == T_CFUNC) { 8427 - jsval_t (*fn)(struct js *, jsval_t *, int) = (jsval_t(*)(struct js *, jsval_t *, int)) vdata(native_val); 8428 - if (fn == builtin_Promise) { 8429 - return mkval(T_BOOL, ltype == T_PROMISE ? 1 : 0); 8430 - } 8431 - } 8432 - } 8433 - jsoff_t code_off = lkp(js, func_obj, "__code", 6); 8434 - if (code_off != 0) { 8435 - jsval_t code_val = resolveprop(js, mkval(T_PROP, code_off)); 8436 - if (vtype(code_val) == T_STR) { 8437 - jsoff_t fnlen, fnoff = vstr(js, code_val, &fnlen); 8438 - const char *code_str = (const char *) (&js->mem[fnoff]); 8439 - if (fnlen == 16 && memcmp(code_str, "__builtin_Object", 16) == 0) { 8440 - return mkval(T_BOOL, ltype == T_OBJ ? 1 : 0); 8441 - } 8678 + 8679 + if (vtype(r) != T_FUNC) { 8680 + // handle legacy T_CFUNC 8681 + if (vtype(r) == T_CFUNC) { 8682 + jsval_t (*fn)(struct js *, jsval_t *, int) = (jsval_t(*)(struct js *, jsval_t *, int)) vdata(r); 8683 + if (fn == builtin_Object) { 8684 + return mkval(T_BOOL, ltype == T_OBJ ? 1 : 0); 8685 + } else if (fn == builtin_Function) { 8686 + return mkval(T_BOOL, (ltype == T_FUNC || ltype == T_CFUNC) ? 1 : 0); 8687 + } else if (fn == builtin_String) { 8688 + return mkval(T_BOOL, ltype == T_STR ? 1 : 0); 8689 + } else if (fn == builtin_Number) { 8690 + return mkval(T_BOOL, ltype == T_NUM ? 1 : 0); 8691 + } else if (fn == builtin_Boolean) { 8692 + return mkval(T_BOOL, ltype == T_BOOL ? 1 : 0); 8693 + } else if (fn == builtin_Array) { 8694 + return mkval(T_BOOL, ltype == T_ARR ? 1 : 0); 8695 + } else if (fn == builtin_Promise) { 8696 + return mkval(T_BOOL, ltype == T_PROMISE ? 1 : 0); 8442 8697 } 8443 8698 } 8699 + return mkval(T_BOOL, 0); 8444 8700 } 8445 - if (vtype(r) == T_CFUNC) { 8446 - jsval_t (*fn)(struct js *, jsval_t *, int) = (jsval_t(*)(struct js *, jsval_t *, int)) vdata(r); 8447 - if (fn == builtin_Object) { 8448 - return mkval(T_BOOL, ltype == T_OBJ ? 1 : 0); 8449 - } else if (fn == builtin_Function) { 8450 - return mkval(T_BOOL, (ltype == T_FUNC || ltype == T_CFUNC) ? 1 : 0); 8451 - } else if (fn == builtin_String) { 8452 - return mkval(T_BOOL, ltype == T_STR ? 1 : 0); 8453 - } else if (fn == builtin_Number) { 8454 - return mkval(T_BOOL, ltype == T_NUM ? 1 : 0); 8455 - } else if (fn == builtin_Boolean) { 8456 - return mkval(T_BOOL, ltype == T_BOOL ? 1 : 0); 8457 - } else if (fn == builtin_Array) { 8458 - return mkval(T_BOOL, ltype == T_ARR ? 1 : 0); 8459 - } else if (fn == builtin_Promise) { 8460 - return mkval(T_BOOL, ltype == T_PROMISE ? 1 : 0); 8461 - } 8701 + 8702 + jsval_t func_obj = mkval(T_OBJ, vdata(r)); 8703 + jsoff_t proto_off = lkp(js, func_obj, "prototype", 9); 8704 + if (proto_off == 0) return mkval(T_BOOL, 0); 8705 + jsval_t ctor_proto = resolveprop(js, mkval(T_PROP, proto_off)); 8706 + 8707 + uint8_t pt = vtype(ctor_proto); 8708 + if (pt != T_OBJ && pt != T_ARR && pt != T_FUNC) return mkval(T_BOOL, 0); 8709 + 8710 + if (ltype == T_STR || ltype == T_NUM || ltype == T_BOOL) { 8711 + jsval_t type_proto = get_prototype_for_type(js, ltype); 8712 + return mkval(T_BOOL, vdata(ctor_proto) == vdata(type_proto) ? 1 : 0); 8462 8713 } 8714 + 8715 + if (ltype != T_OBJ && ltype != T_ARR && ltype != T_FUNC && ltype != T_PROMISE) { 8716 + return mkval(T_BOOL, 0); 8717 + } 8718 + 8719 + jsval_t current = get_proto(js, l); 8720 + int depth = 0; 8721 + const int MAX_DEPTH = 32; 8722 + 8723 + while (vtype(current) != T_NULL && depth < MAX_DEPTH) { 8724 + if (vdata(current) == vdata(ctor_proto)) return mkval(T_BOOL, 1); 8725 + current = get_proto(js, current); 8726 + depth++; 8727 + } 8728 + 8463 8729 return mkval(T_BOOL, 0); 8464 8730 } 8465 8731 ··· 8476 8742 jsoff_t prop_off = vstr(js, l, &prop_len); 8477 8743 const char *prop_name = (char *) &js->mem[prop_off]; 8478 8744 8479 - jsval_t check_obj = r; 8480 - if (vtype(r) == T_FUNC) { 8481 - check_obj = mkval(T_OBJ, vdata(r)); 8482 - } 8483 - 8484 - jsoff_t found = lkp(js, check_obj, prop_name, prop_len); 8745 + jsoff_t found = lkp_proto(js, r, prop_name, prop_len); 8485 8746 return mkval(T_BOOL, found != 0 ? 1 : 0); 8486 8747 } 8487 8748 ··· 9607 9868 js->this_val = js->scope; 9608 9869 9609 9870 jsval_t glob = js->scope; 9871 + jsval_t object_proto = js_mkobj(js); 9872 + 9873 + jsval_t function_proto = js_mkobj(js); 9874 + set_proto(js, function_proto, object_proto); 9875 + 9876 + jsval_t array_proto = js_mkobj(js); 9877 + set_proto(js, array_proto, object_proto); 9878 + setprop(js, array_proto, js_mkstr(js, "push", 4), js_mkfun(builtin_array_push)); 9879 + setprop(js, array_proto, js_mkstr(js, "pop", 3), js_mkfun(builtin_array_pop)); 9880 + setprop(js, array_proto, js_mkstr(js, "slice", 5), js_mkfun(builtin_array_slice)); 9881 + setprop(js, array_proto, js_mkstr(js, "join", 4), js_mkfun(builtin_array_join)); 9882 + setprop(js, array_proto, js_mkstr(js, "includes", 8), js_mkfun(builtin_array_includes)); 9883 + setprop(js, array_proto, js_mkstr(js, "every", 5), js_mkfun(builtin_array_every)); 9884 + 9885 + jsval_t string_proto = js_mkobj(js); 9886 + set_proto(js, string_proto, object_proto); 9887 + setprop(js, string_proto, js_mkstr(js, "indexOf", 7), js_mkfun(builtin_string_indexOf)); 9888 + setprop(js, string_proto, js_mkstr(js, "substring", 9), js_mkfun(builtin_string_substring)); 9889 + setprop(js, string_proto, js_mkstr(js, "split", 5), js_mkfun(builtin_string_split)); 9890 + setprop(js, string_proto, js_mkstr(js, "slice", 5), js_mkfun(builtin_string_slice)); 9891 + setprop(js, string_proto, js_mkstr(js, "includes", 8), js_mkfun(builtin_string_includes)); 9892 + setprop(js, string_proto, js_mkstr(js, "startsWith", 10), js_mkfun(builtin_string_startsWith)); 9893 + setprop(js, string_proto, js_mkstr(js, "endsWith", 8), js_mkfun(builtin_string_endsWith)); 9894 + setprop(js, string_proto, js_mkstr(js, "replace", 7), js_mkfun(builtin_string_replace)); 9895 + setprop(js, string_proto, js_mkstr(js, "template", 8), js_mkfun(builtin_string_template)); 9896 + setprop(js, string_proto, js_mkstr(js, "charCodeAt", 10), js_mkfun(builtin_string_charCodeAt)); 9897 + setprop(js, string_proto, js_mkstr(js, "toLowerCase", 11), js_mkfun(builtin_string_toLowerCase)); 9898 + setprop(js, string_proto, js_mkstr(js, "toUpperCase", 11), js_mkfun(builtin_string_toUpperCase)); 9899 + setprop(js, string_proto, js_mkstr(js, "trim", 4), js_mkfun(builtin_string_trim)); 9900 + setprop(js, string_proto, js_mkstr(js, "repeat", 6), js_mkfun(builtin_string_repeat)); 9901 + setprop(js, string_proto, js_mkstr(js, "padStart", 8), js_mkfun(builtin_string_padStart)); 9902 + setprop(js, string_proto, js_mkstr(js, "padEnd", 6), js_mkfun(builtin_string_padEnd)); 9903 + setprop(js, string_proto, js_mkstr(js, "charAt", 6), js_mkfun(builtin_string_charAt)); 9904 + 9905 + jsval_t number_proto = js_mkobj(js); 9906 + set_proto(js, number_proto, object_proto); 9907 + setprop(js, number_proto, js_mkstr(js, "toString", 8), js_mkfun(builtin_number_toString)); 9908 + setprop(js, number_proto, js_mkstr(js, "toFixed", 7), js_mkfun(builtin_number_toFixed)); 9909 + setprop(js, number_proto, js_mkstr(js, "toPrecision", 11), js_mkfun(builtin_number_toPrecision)); 9910 + setprop(js, number_proto, js_mkstr(js, "toExponential", 13), js_mkfun(builtin_number_toExponential)); 9911 + 9912 + jsval_t boolean_proto = js_mkobj(js); 9913 + set_proto(js, boolean_proto, object_proto); 9914 + 9915 + jsval_t error_proto = js_mkobj(js); 9916 + set_proto(js, error_proto, object_proto); 9917 + setprop(js, error_proto, js_mkstr(js, "name", 4), js_mkstr(js, "Error", 5)); 9918 + setprop(js, error_proto, js_mkstr(js, "message", 7), js_mkstr(js, "", 0)); 9919 + 9920 + jsval_t date_proto = js_mkobj(js); 9921 + set_proto(js, date_proto, object_proto); 9922 + 9923 + jsval_t regexp_proto = js_mkobj(js); 9924 + set_proto(js, regexp_proto, object_proto); 9925 + 9926 + jsval_t map_proto = js_mkobj(js); 9927 + set_proto(js, map_proto, object_proto); 9928 + setprop(js, map_proto, js_mkstr(js, "set", 3), js_mkfun(map_set)); 9929 + setprop(js, map_proto, js_mkstr(js, "get", 3), js_mkfun(map_get)); 9930 + setprop(js, map_proto, js_mkstr(js, "has", 3), js_mkfun(map_has)); 9931 + setprop(js, map_proto, js_mkstr(js, "delete", 6), js_mkfun(map_delete)); 9932 + setprop(js, map_proto, js_mkstr(js, "clear", 5), js_mkfun(map_clear)); 9933 + setprop(js, map_proto, js_mkstr(js, "size", 4), js_mkfun(map_size)); 9934 + 9935 + jsval_t set_proto_obj = js_mkobj(js); 9936 + set_proto(js, set_proto_obj, object_proto); 9937 + setprop(js, set_proto_obj, js_mkstr(js, "add", 3), js_mkfun(set_add)); 9938 + setprop(js, set_proto_obj, js_mkstr(js, "has", 3), js_mkfun(set_has)); 9939 + setprop(js, set_proto_obj, js_mkstr(js, "delete", 6), js_mkfun(set_delete)); 9940 + setprop(js, set_proto_obj, js_mkstr(js, "clear", 5), js_mkfun(set_clear)); 9941 + setprop(js, set_proto_obj, js_mkstr(js, "size", 4), js_mkfun(set_size)); 9942 + 9943 + jsval_t promise_proto = js_mkobj(js); 9944 + set_proto(js, promise_proto, object_proto); 9945 + setprop(js, promise_proto, js_mkstr(js, "then", 4), js_mkfun(builtin_promise_then)); 9946 + setprop(js, promise_proto, js_mkstr(js, "catch", 5), js_mkfun(builtin_promise_catch)); 9947 + setprop(js, promise_proto, js_mkstr(js, "finally", 7), js_mkfun(builtin_promise_finally)); 9948 + 9610 9949 jsval_t obj_func_obj = mkobj(js, 0); 9611 - jsval_t obj_code_key = js_mkstr(js, "__code", 6); 9612 - jsval_t obj_code_val = js_mkstr(js, "__builtin_Object", 16); 9613 - setprop(js, obj_func_obj, obj_code_key, obj_code_val); 9614 - jsval_t obj_keys_key = js_mkstr(js, "keys", 4); 9615 - setprop(js, obj_func_obj, obj_keys_key, js_mkfun(builtin_object_keys)); 9616 - jsval_t obj_func = mkval(T_FUNC, vdata(obj_func_obj)); 9950 + set_proto(js, obj_func_obj, function_proto); 9951 + setprop(js, obj_func_obj, js_mkstr(js, "__code", 6), js_mkstr(js, "__builtin_Object", 16)); 9952 + setprop(js, obj_func_obj, js_mkstr(js, "keys", 4), js_mkfun(builtin_object_keys)); 9953 + setprop(js, obj_func_obj, js_mkstr(js, "getPrototypeOf", 14), js_mkfun(builtin_object_getPrototypeOf)); 9954 + setprop(js, obj_func_obj, js_mkstr(js, "setPrototypeOf", 14), js_mkfun(builtin_object_setPrototypeOf)); 9955 + setprop(js, obj_func_obj, js_mkstr(js, "create", 6), js_mkfun(builtin_object_create)); 9956 + setprop(js, obj_func_obj, js_mkstr(js, "hasOwn", 6), js_mkfun(builtin_object_hasOwn)); 9957 + setprop(js, obj_func_obj, js_mkstr(js, "prototype", 9), object_proto); 9958 + setprop(js, glob, js_mkstr(js, "Object", 6), mkval(T_FUNC, vdata(obj_func_obj))); 9617 9959 9618 - setprop(js, glob, js_mkstr(js, "Object", 6), obj_func); 9619 - setprop(js, glob, js_mkstr(js, "eval", 4), js_mkfun(builtin_eval)); 9620 - setprop(js, glob, js_mkstr(js, "Function", 8), js_mkfun(builtin_Function)); 9621 - setprop(js, glob, js_mkstr(js, "String", 6), js_mkfun(builtin_String)); 9960 + jsval_t func_ctor_obj = mkobj(js, 0); 9961 + set_proto(js, func_ctor_obj, function_proto); 9962 + setprop(js, func_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Function)); 9963 + setprop(js, func_ctor_obj, js_mkstr(js, "prototype", 9), function_proto); 9964 + setprop(js, glob, js_mkstr(js, "Function", 8), mkval(T_FUNC, vdata(func_ctor_obj))); 9965 + 9966 + jsval_t str_ctor_obj = mkobj(js, 0); 9967 + set_proto(js, str_ctor_obj, function_proto); 9968 + setprop(js, str_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_String)); 9969 + setprop(js, str_ctor_obj, js_mkstr(js, "prototype", 9), string_proto); 9970 + setprop(js, glob, js_mkstr(js, "String", 6), mkval(T_FUNC, vdata(str_ctor_obj))); 9622 9971 9623 9972 jsval_t number_ctor_obj = mkobj(js, 0); 9973 + set_proto(js, number_ctor_obj, function_proto); 9624 9974 setprop(js, number_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Number)); 9625 9975 setprop(js, number_ctor_obj, js_mkstr(js, "isNaN", 5), js_mkfun(builtin_Number_isNaN)); 9626 9976 setprop(js, number_ctor_obj, js_mkstr(js, "isFinite", 8), js_mkfun(builtin_Number_isFinite)); 9977 + setprop(js, number_ctor_obj, js_mkstr(js, "prototype", 9), number_proto); 9627 9978 setprop(js, glob, js_mkstr(js, "Number", 6), mkval(T_FUNC, vdata(number_ctor_obj))); 9628 9979 9629 - setprop(js, glob, js_mkstr(js, "Boolean", 7), js_mkfun(builtin_Boolean)); 9630 - setprop(js, glob, js_mkstr(js, "Array", 5), js_mkfun(builtin_Array)); 9631 - setprop(js, glob, js_mkstr(js, "Map", 3), js_mkfun(builtin_Map)); 9632 - setprop(js, glob, js_mkstr(js, "Set", 3), js_mkfun(builtin_Set)); 9633 - setprop(js, glob, js_mkstr(js, "Error", 5), js_mkfun(builtin_Error)); 9634 - setprop(js, glob, js_mkstr(js, "RegExp", 6), js_mkfun(builtin_RegExp)); 9635 - setprop(js, glob, js_mkstr(js, "parseInt", 8), js_mkfun(builtin_parseInt)); 9636 - setprop(js, glob, js_mkstr(js, "parseFloat", 10), js_mkfun(builtin_parseFloat)); 9980 + jsval_t bool_ctor_obj = mkobj(js, 0); 9981 + set_proto(js, bool_ctor_obj, function_proto); 9982 + setprop(js, bool_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Boolean)); 9983 + setprop(js, bool_ctor_obj, js_mkstr(js, "prototype", 9), boolean_proto); 9984 + setprop(js, glob, js_mkstr(js, "Boolean", 7), mkval(T_FUNC, vdata(bool_ctor_obj))); 9985 + 9986 + jsval_t arr_ctor_obj = mkobj(js, 0); 9987 + set_proto(js, arr_ctor_obj, function_proto); 9988 + setprop(js, arr_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Array)); 9989 + setprop(js, arr_ctor_obj, js_mkstr(js, "prototype", 9), array_proto); 9990 + setprop(js, glob, js_mkstr(js, "Array", 5), mkval(T_FUNC, vdata(arr_ctor_obj))); 9991 + 9992 + jsval_t map_ctor_obj = mkobj(js, 0); 9993 + set_proto(js, map_ctor_obj, function_proto); 9994 + setprop(js, map_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Map)); 9995 + setprop(js, map_ctor_obj, js_mkstr(js, "prototype", 9), map_proto); 9996 + setprop(js, glob, js_mkstr(js, "Map", 3), mkval(T_FUNC, vdata(map_ctor_obj))); 9997 + 9998 + jsval_t set_ctor_obj = mkobj(js, 0); 9999 + set_proto(js, set_ctor_obj, function_proto); 10000 + setprop(js, set_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Set)); 10001 + setprop(js, set_ctor_obj, js_mkstr(js, "prototype", 9), set_proto_obj); 10002 + setprop(js, glob, js_mkstr(js, "Set", 3), mkval(T_FUNC, vdata(set_ctor_obj))); 10003 + 10004 + jsval_t err_ctor_obj = mkobj(js, 0); 10005 + set_proto(js, err_ctor_obj, function_proto); 10006 + setprop(js, err_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Error)); 10007 + setprop(js, err_ctor_obj, js_mkstr(js, "prototype", 9), error_proto); 10008 + setprop(js, glob, js_mkstr(js, "Error", 5), mkval(T_FUNC, vdata(err_ctor_obj))); 10009 + 10010 + jsval_t regex_ctor_obj = mkobj(js, 0); 10011 + set_proto(js, regex_ctor_obj, function_proto); 10012 + setprop(js, regex_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_RegExp)); 10013 + setprop(js, regex_ctor_obj, js_mkstr(js, "prototype", 9), regexp_proto); 10014 + setprop(js, glob, js_mkstr(js, "RegExp", 6), mkval(T_FUNC, vdata(regex_ctor_obj))); 10015 + 10016 + jsval_t date_ctor_obj = mkobj(js, 0); 10017 + set_proto(js, date_ctor_obj, function_proto); 10018 + setprop(js, date_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Date)); 10019 + setprop(js, date_ctor_obj, js_mkstr(js, "now", 3), js_mkfun(builtin_Date_now)); 10020 + setprop(js, date_ctor_obj, js_mkstr(js, "prototype", 9), date_proto); 10021 + setprop(js, glob, js_mkstr(js, "Date", 4), mkval(T_FUNC, vdata(date_ctor_obj))); 9637 10022 9638 - setprop(js, glob, js_mkstr(js, "NaN", 3), tov(NAN)); 9639 - setprop(js, glob, js_mkstr(js, "Infinity", 8), tov(INFINITY)); 10023 + jsval_t p_ctor_obj = mkobj(js, 0); 10024 + set_proto(js, p_ctor_obj, function_proto); 10025 + setprop(js, p_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Promise)); 10026 + setprop(js, p_ctor_obj, js_mkstr(js, "resolve", 7), js_mkfun(builtin_Promise_resolve)); 10027 + setprop(js, p_ctor_obj, js_mkstr(js, "reject", 6), js_mkfun(builtin_Promise_reject)); 10028 + setprop(js, p_ctor_obj, js_mkstr(js, "try", 3), js_mkfun(builtin_Promise_try)); 10029 + setprop(js, p_ctor_obj, js_mkstr(js, "all", 3), js_mkfun(builtin_Promise_all)); 10030 + setprop(js, p_ctor_obj, js_mkstr(js, "race", 4), js_mkfun(builtin_Promise_race)); 10031 + setprop(js, p_ctor_obj, js_mkstr(js, "prototype", 9), promise_proto); 10032 + setprop(js, glob, js_mkstr(js, "Promise", 7), mkval(T_FUNC, vdata(p_ctor_obj))); 9640 10033 9641 10034 jsval_t bigint_ctor_obj = mkobj(js, 0); 10035 + set_proto(js, bigint_ctor_obj, function_proto); 9642 10036 setprop(js, bigint_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_BigInt)); 9643 10037 setprop(js, bigint_ctor_obj, js_mkstr(js, "asIntN", 6), js_mkfun(builtin_BigInt_asIntN)); 9644 10038 setprop(js, bigint_ctor_obj, js_mkstr(js, "asUintN", 7), js_mkfun(builtin_BigInt_asUintN)); 9645 10039 setprop(js, glob, js_mkstr(js, "BigInt", 6), mkval(T_FUNC, vdata(bigint_ctor_obj))); 9646 10040 10041 + setprop(js, glob, js_mkstr(js, "eval", 4), js_mkfun(builtin_eval)); 10042 + setprop(js, glob, js_mkstr(js, "parseInt", 8), js_mkfun(builtin_parseInt)); 10043 + setprop(js, glob, js_mkstr(js, "parseFloat", 10), js_mkfun(builtin_parseFloat)); 10044 + setprop(js, glob, js_mkstr(js, "NaN", 3), tov(NAN)); 10045 + setprop(js, glob, js_mkstr(js, "Infinity", 8), tov(INFINITY)); 10046 + 10047 + // Math object 9647 10048 jsval_t math_obj = mkobj(js, 0); 10049 + set_proto(js, math_obj, object_proto); 9648 10050 setprop(js, math_obj, js_mkstr(js, "E", 1), tov(M_E)); 9649 10051 setprop(js, math_obj, js_mkstr(js, "LN10", 4), tov(M_LN10)); 9650 10052 setprop(js, math_obj, js_mkstr(js, "LN2", 3), tov(M_LN2)); ··· 9690 10092 setprop(js, math_obj, js_mkstr(js, "trunc", 5), js_mkfun(builtin_Math_trunc)); 9691 10093 setprop(js, glob, js_mkstr(js, "Math", 4), math_obj); 9692 10094 9693 - jsval_t date_ctor_obj = mkobj(js, 0); 9694 - setprop(js, date_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Date)); 9695 - setprop(js, date_ctor_obj, js_mkstr(js, "now", 3), js_mkfun(builtin_Date_now)); 9696 - setprop(js, glob, js_mkstr(js, "Date", 4), mkval(T_FUNC, vdata(date_ctor_obj))); 9697 - 9698 - jsval_t p_proto = js_mkobj(js); 9699 - setprop(js, p_proto, js_mkstr(js, "then", 4), js_mkfun(builtin_promise_then)); 9700 - setprop(js, p_proto, js_mkstr(js, "catch", 5), js_mkfun(builtin_promise_catch)); 9701 - setprop(js, p_proto, js_mkstr(js, "finally", 7), js_mkfun(builtin_promise_finally)); 9702 - 9703 - jsval_t p_ctor_obj = mkobj(js, 0); 9704 - setprop(js, p_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Promise)); 9705 - setprop(js, p_ctor_obj, js_mkstr(js, "resolve", 7), js_mkfun(builtin_Promise_resolve)); 9706 - setprop(js, p_ctor_obj, js_mkstr(js, "reject", 6), js_mkfun(builtin_Promise_reject)); 9707 - setprop(js, p_ctor_obj, js_mkstr(js, "try", 3), js_mkfun(builtin_Promise_try)); 9708 - setprop(js, p_ctor_obj, js_mkstr(js, "all", 3), js_mkfun(builtin_Promise_all)); 9709 - setprop(js, p_ctor_obj, js_mkstr(js, "race", 4), js_mkfun(builtin_Promise_race)); 9710 - setprop(js, p_ctor_obj, js_mkstr(js, "prototype", 9), p_proto); 10095 + jsval_t import_obj = mkobj(js, 0); 10096 + set_proto(js, import_obj, function_proto); 9711 10097 9712 - setprop(js, glob, js_mkstr(js, "Promise", 7), mkval(T_FUNC, vdata(p_ctor_obj))); 9713 - 9714 - jsval_t import_obj = mkobj(js, 0); 9715 10098 setprop(js, import_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_import)); 9716 10099 setprop(js, glob, js_mkstr(js, "import", 6), mkval(T_FUNC, vdata(import_obj))); 10100 + setprop(js, glob, js_mkstr(js, "__esm_module_scope", 18), js_mkundef()); 9717 10101 9718 - setprop(js, glob, js_mkstr(js, "__esm_module_scope", 18), js_mkundef()); 10102 + set_proto(js, glob, object_proto); 9719 10103 9720 10104 js->owns_mem = false; 9721 10105 js->max_size = 0;
+6
tests/meow.js
··· 1 + String.prototype.meow = function () { 2 + if (!this) return 'meow'; 3 + return `${this}, meow`; 4 + }; 5 + 6 + console.log('hello'.meow());
+183
tests/test_prototypes.cjs
··· 1 + // Test JavaScript Prototype Chain Implementation 2 + 3 + console.log("=== Prototype Chain Tests ===\n"); 4 + 5 + // ============================================ 6 + // Test 1: Basic prototype chain for objects 7 + // ============================================ 8 + console.log("--- Test 1: Object Prototypes ---"); 9 + 10 + let obj = {}; 11 + console.log("{} instanceof Object:", {} instanceof Object); 12 + console.log("Object.getPrototypeOf({}) === Object.prototype:", 13 + Object.getPrototypeOf({}) === Object.prototype); 14 + 15 + // ============================================ 16 + // Test 2: Array prototype chain 17 + // ============================================ 18 + console.log("\n--- Test 2: Array Prototypes ---"); 19 + 20 + let arr = [1, 2, 3]; 21 + console.log("[] instanceof Array:", [] instanceof Array); 22 + console.log("[] instanceof Object:", [] instanceof Object); 23 + console.log("Object.getPrototypeOf([]) === Array.prototype:", 24 + Object.getPrototypeOf([]) === Array.prototype); 25 + 26 + // Array prototype should chain to Object.prototype 27 + let arrProto = Object.getPrototypeOf(arr); 28 + let objProto = Object.getPrototypeOf(arrProto); 29 + console.log("Array.prototype.__proto__ === Object.prototype:", 30 + objProto === Object.prototype); 31 + 32 + // ============================================ 33 + // Test 3: String prototype methods 34 + // ============================================ 35 + console.log("\n--- Test 3: String Prototype Methods ---"); 36 + 37 + console.log("\"hello\".toUpperCase():", "hello".toUpperCase()); 38 + console.log("\"WORLD\".toLowerCase():", "WORLD".toLowerCase()); 39 + console.log("\"hello world\".split(\" \"):", "hello world".split(" ")); 40 + console.log("\"abc\".indexOf(\"b\"):", "abc".indexOf("b")); 41 + console.log("\" trimmed \".trim():", " trimmed ".trim()); 42 + console.log("\"ab\".repeat(3):", "ab".repeat(3)); 43 + console.log("\"5\".padStart(3, \"0\"):", "5".padStart(3, "0")); 44 + 45 + // ============================================ 46 + // Test 4: Number prototype methods 47 + // ============================================ 48 + console.log("\n--- Test 4: Number Prototype Methods ---"); 49 + 50 + console.log("(3.14159).toFixed(2):", (3.14159).toFixed(2)); 51 + console.log("(42).toString():", (42).toString()); 52 + console.log("(123.456).toPrecision(4):", (123.456).toPrecision(4)); 53 + 54 + // ============================================ 55 + // Test 5: Array prototype methods 56 + // ============================================ 57 + console.log("\n--- Test 5: Array Prototype Methods ---"); 58 + 59 + let testArr = [1, 2, 3]; 60 + console.log("Initial array:", testArr); 61 + console.log("[1,2,3].push(4):", testArr.push(4)); 62 + console.log("After push:", testArr); 63 + console.log("[1,2,3,4].pop():", testArr.pop()); 64 + console.log("After pop:", testArr); 65 + console.log("[1,2,3].slice(1):", [1,2,3].slice(1)); 66 + console.log("[1,2,3].join(\"-\"):", [1,2,3].join("-")); 67 + console.log("[1,2,3].includes(2):", [1,2,3].includes(2)); 68 + 69 + // ============================================ 70 + // Test 6: Object.create with prototype 71 + // ============================================ 72 + console.log("\n--- Test 6: Object.create ---"); 73 + 74 + let animal = { 75 + speak: function() { return "animal sound"; }, 76 + type: "animal" 77 + }; 78 + let dog = Object.create(animal); 79 + dog.bark = function() { return "woof"; }; 80 + dog.name = "Rex"; 81 + 82 + console.log("dog.speak() (inherited):", dog.speak()); 83 + console.log("dog.bark() (own):", dog.bark()); 84 + console.log("dog.type (inherited):", dog.type); 85 + console.log("dog.name (own):", dog.name); 86 + console.log("\"speak\" in dog:", "speak" in dog); 87 + console.log("\"bark\" in dog:", "bark" in dog); 88 + console.log("Object.hasOwn(dog, \"speak\"):", Object.hasOwn(dog, "speak")); 89 + console.log("Object.hasOwn(dog, \"bark\"):", Object.hasOwn(dog, "bark")); 90 + 91 + // ============================================ 92 + // Test 7: Object.setPrototypeOf 93 + // ============================================ 94 + console.log("\n--- Test 7: Object.setPrototypeOf ---"); 95 + 96 + let target = { own: "property" }; 97 + let proto = { inherited: "value", method: function() { return "from proto"; } }; 98 + Object.setPrototypeOf(target, proto); 99 + 100 + console.log("target.own:", target.own); 101 + console.log("target.inherited:", target.inherited); 102 + console.log("target.method():", target.method()); 103 + console.log("Object.getPrototypeOf(target) === proto:", Object.getPrototypeOf(target) === proto); 104 + 105 + // ============================================ 106 + // Test 8: instanceof with prototype chain 107 + // ============================================ 108 + console.log("\n--- Test 8: instanceof ---"); 109 + 110 + console.log("{} instanceof Object:", {} instanceof Object); 111 + console.log("[] instanceof Array:", [] instanceof Array); 112 + console.log("[] instanceof Object:", [] instanceof Object); 113 + console.log("\"str\" instanceof String:", "str" instanceof String); 114 + console.log("42 instanceof Number:", 42 instanceof Number); 115 + console.log("true instanceof Boolean:", true instanceof Boolean); 116 + 117 + // Custom prototype chain 118 + let customProto = {}; 119 + let customObj = Object.create(customProto); 120 + console.log("Object.getPrototypeOf(customObj) === customProto:", 121 + Object.getPrototypeOf(customObj) === customProto); 122 + 123 + // ============================================ 124 + // Test 9: 'in' operator with prototype chain 125 + // ============================================ 126 + console.log("\n--- Test 9: 'in' Operator ---"); 127 + 128 + let base = { baseMethod: function() {} }; 129 + let derived = Object.create(base); 130 + derived.derivedMethod = function() {}; 131 + 132 + console.log("\"baseMethod\" in derived:", "baseMethod" in derived); 133 + console.log("\"derivedMethod\" in derived:", "derivedMethod" in derived); 134 + console.log("\"nonexistent\" in derived:", "nonexistent" in derived); 135 + 136 + // Array methods should be found via prototype 137 + console.log("\"push\" in []:", "push" in []); 138 + console.log("\"pop\" in []:", "pop" in []); 139 + console.log("\"slice\" in []:", "slice" in []); 140 + 141 + // ============================================ 142 + // Test 10: Property shadowing with new properties 143 + // ============================================ 144 + console.log("\n--- Test 10: Property Shadowing ---"); 145 + 146 + let parent = { value: "parent", shared: "from parent" }; 147 + let child = Object.create(parent); 148 + // Note: To shadow a prototype property, declare it as a new own property 149 + child.childOnly = "child's own"; 150 + 151 + console.log("parent.value:", parent.value); 152 + console.log("child.value (inherited):", child.value); 153 + console.log("child.shared (inherited):", child.shared); 154 + console.log("child.childOnly (own):", child.childOnly); 155 + console.log("Object.hasOwn(child, \"childOnly\"):", Object.hasOwn(child, "childOnly")); 156 + console.log("Object.hasOwn(child, \"value\"):", Object.hasOwn(child, "value")); 157 + 158 + // ============================================ 159 + // Test 11: Object.keys doesn't include prototype props 160 + // ============================================ 161 + console.log("\n--- Test 11: Object.keys ---"); 162 + 163 + let protoObj = { protoKey: 1 }; 164 + let ownObj = Object.create(protoObj); 165 + ownObj.ownKey = 2; 166 + 167 + let keys = Object.keys(ownObj); 168 + console.log("Object.keys(ownObj):", keys); 169 + console.log("Includes ownKey:", keys.includes("ownKey")); 170 + console.log("Includes protoKey:", keys.includes("protoKey")); 171 + 172 + // ============================================ 173 + // Test 12: Constructor.prototype 174 + // ============================================ 175 + console.log("\n--- Test 12: Constructor.prototype ---"); 176 + 177 + console.log("Array.prototype exists:", Array.prototype !== undefined); 178 + console.log("String.prototype exists:", String.prototype !== undefined); 179 + console.log("Number.prototype exists:", Number.prototype !== undefined); 180 + console.log("Object.prototype exists:", Object.prototype !== undefined); 181 + console.log("Function.prototype exists:", Function.prototype !== undefined); 182 + 183 + console.log("\n=== All Prototype Tests Complete ===");