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.

implement Symbol.species support for Promise, Array, and RegExp

+156 -126
+4
include/modules/symbol.h
··· 5 5 #include <stdbool.h> 6 6 #include "types.h" 7 7 8 + 8 9 void init_symbol_module(void); 10 + void js_define_species_getter(ant_t *js, jsval_t ctor); 11 + 9 12 bool is_symbol_key(const char *key, size_t key_len); 10 13 int sym_to_prop_key(jsval_t sym, char *buf, size_t bufsz); 11 14 ··· 15 18 const char *get_observable_sym_key(void); 16 19 const char *get_toPrimitive_sym_key(void); 17 20 const char *get_hasInstance_sym_key(void); 21 + const char *get_species_sym_key(void); 18 22 19 23 jsval_t get_wellknown_sym_by_key(const char *key, size_t key_len); 20 24 const char *get_symbol_description_from_key(const char *sym_key, size_t key_len);
+109 -120
src/ant.c
··· 6714 6714 if (pos >= len) break; 6715 6715 if ((is_arr && p[pos] == ']') || (!is_arr && p[pos] == '}')) break; 6716 6716 if (p[pos] == ',') { pos++; idx++; continue; } 6717 + 6718 + if (is_arr && (p[pos] == '[' || p[pos] == '{')) { 6719 + jsoff_t nested_start = pos; 6720 + char open = p[pos], close = (open == '[') ? ']' : '}'; 6721 + int depth = 1; 6722 + pos++; 6723 + while (pos < len && depth > 0) { 6724 + if (p[pos] == open) depth++; 6725 + else if (p[pos] == close) depth--; 6726 + pos++; 6727 + } 6728 + jsoff_t nested_len = pos - nested_start; 6729 + jsval_t elem_val = js_arr_get(js, val, idx); 6730 + jsval_t r = bind_destruct_pattern(js, &p[nested_start], nested_len, elem_val, scope); 6731 + if (is_err(r)) return r; 6732 + idx++; 6733 + pos = skiptonext(p, len, pos, NULL); 6734 + if (pos < len && p[pos] == ',') pos++; 6735 + continue; 6736 + } 6717 6737 6718 6738 bool is_rest = (pos + 2 < len && p[pos] == '.' && p[pos+1] == '.' && p[pos+2] == '.'); 6719 6739 if (is_rest) { pos += 3; pos = skiptonext(p, len, pos, NULL); } ··· 8569 8589 return js_mkbigint(js, start, len, neg); 8570 8590 } 8571 8591 8572 - static jsval_t js_arr_destruct_assign(struct js *js) { 8592 + static jsval_t js_destruct_assign_pattern( 8593 + struct js *js, uint8_t open_tok, uint8_t close_tok, 8594 + const char *missing_assign_msg, bool object_required 8595 + ) { 8573 8596 uint8_t exe = !(js->flags & F_NOEXEC); 8597 + jsoff_t pattern_start = js->toff; 8574 8598 js->consumed = 1; 8575 8599 8576 - js_parse_state_t pattern_state; 8577 - JS_SAVE_STATE(js, pattern_state); 8578 - 8579 8600 int depth = 1; 8580 8601 while (depth > 0 && next(js) != TOK_EOF) { 8581 - if (js->tok == TOK_LBRACKET) depth++; 8582 - else if (js->tok == TOK_RBRACKET) depth--; 8602 + if (js->tok == open_tok) depth++; 8603 + else if (js->tok == close_tok) depth--; 8583 8604 if (depth > 0) js->consumed = 1; 8584 8605 } 8585 8606 js->consumed = 1; 8607 + jsoff_t pattern_len = js->pos - pattern_start; 8586 8608 8587 8609 if (next(js) != TOK_ASSIGN) { 8588 - return js_mkerr_typed(js, JS_ERR_SYNTAX, "array destructuring requires assignment"); 8610 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "%s", missing_assign_msg); 8589 8611 } 8590 8612 js->consumed = 1; 8591 8613 8592 - jsval_t v = js_expr(js); 8593 - if (is_err(v)) return v; 8614 + jsval_t rhs = js_expr(js); 8615 + if (is_err(rhs)) return rhs; 8594 8616 8595 - jsval_t arr = js_mkundef(); 8596 8617 if (exe) { 8597 - arr = resolveprop(js, v); 8598 - if (vtype(arr) != T_ARR && vtype(arr) != T_STR) { 8599 - return js_mkerr(js, "cannot array destructure non-iterable"); 8600 - } 8601 - } 8602 - 8603 - js_parse_state_t end_state; 8604 - JS_SAVE_STATE(js, end_state); 8605 - JS_RESTORE_STATE(js, pattern_state); 8606 - 8607 - int index = 0; 8608 - while (next(js) != TOK_RBRACKET && next(js) != TOK_EOF) { 8609 - if (next(js) == TOK_COMMA) { 8610 - js->consumed = 1; 8611 - index++; 8612 - continue; 8613 - } 8614 - 8615 - bool is_rest = false; 8616 - if (next(js) == TOK_REST) { 8617 - is_rest = true; 8618 - js->consumed = 1; 8619 - } 8620 - 8621 - if (next(js) != TOK_IDENTIFIER) { 8622 - return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected in array destructuring"); 8623 - } 8624 - jsoff_t var_off = js->toff, var_len = js->tlen; 8625 - js->consumed = 1; 8626 - 8627 - jsoff_t default_off = 0, default_len = 0; 8628 - if (!is_rest && next(js) == TOK_ASSIGN) { 8629 - js->consumed = 1; 8630 - default_off = js->pos; 8631 - uint8_t sf = js->flags; 8632 - js->flags |= F_NOEXEC; 8633 - jsval_t r = js_expr(js); 8634 - js->flags = sf; 8635 - if (is_err(r)) return r; 8636 - default_len = js->pos - default_off; 8637 - } 8618 + jsval_t val = resolveprop(js, rhs); 8619 + uint8_t vt = vtype(val); 8638 8620 8639 - if (exe) { 8640 - const char *var_name = &js->code[var_off]; 8641 - 8642 - jsval_t prop_val; 8643 - if (is_rest) { 8644 - jsval_t rest_arr = js_mkarr(js); 8645 - if (is_err(rest_arr)) return rest_arr; 8646 - jsoff_t total_len = vtype(arr) == T_STR ? 0 : js_arr_len(js, arr); 8647 - if (vtype(arr) == T_STR) { 8648 - jsoff_t slen; 8649 - vstr(js, arr, &slen); 8650 - total_len = slen; 8651 - } 8652 - for (jsoff_t i = index; i < total_len; i++) { 8653 - jsval_t elem; 8654 - if (vtype(arr) == T_STR) { 8655 - jsoff_t slen, soff = vstr(js, arr, &slen); 8656 - elem = js_mkstr(js, (char *)&js->mem[soff + i], 1); 8657 - } else { 8658 - elem = js_arr_get(js, arr, i); 8659 - } 8660 - js_arr_push(js, rest_arr, elem); 8661 - } 8662 - prop_val = rest_arr; 8663 - } else { 8664 - if (vtype(arr) == T_STR) { 8665 - jsoff_t slen, soff = vstr(js, arr, &slen); 8666 - if ((jsoff_t)index < slen) { 8667 - prop_val = js_mkstr(js, (char *)&js->mem[soff + index], 1); 8668 - } else { 8669 - prop_val = js_mkundef(); 8670 - } 8671 - } else { 8672 - prop_val = js_arr_get(js, arr, index); 8673 - } 8674 - 8675 - if (vtype(prop_val) == T_UNDEF && default_len > 0) { 8676 - prop_val = js_eval_slice(js, default_off, default_len); 8677 - if (is_err(prop_val)) return prop_val; 8678 - prop_val = resolveprop(js, prop_val); 8679 - } 8621 + if (object_required) { 8622 + if (vt == T_NULL || vt == T_UNDEF) { 8623 + return js_mkerr(js, "cannot destructure null or undefined"); 8680 8624 } 8681 - 8682 - jsoff_t existing = lkp_scope(js, js->scope, var_name, var_len); 8683 - if (existing != 0) { 8684 - jsval_t res = js_setprop(js, js->scope, js_mkstr(js, var_name, var_len), prop_val); 8685 - if (is_err(res)) return res; 8686 - } else { 8687 - jsval_t global_scope = js->scope; 8688 - while (vdata(upper(js, global_scope)) != 0) { 8689 - global_scope = upper(js, global_scope); 8690 - } 8691 - jsval_t res = js_setprop(js, global_scope, js_mkstr(js, var_name, var_len), prop_val); 8692 - if (is_err(res)) return res; 8693 - } 8625 + } else if (vt != T_ARR && vt != T_STR) { 8626 + return js_mkerr(js, "cannot array destructure non-iterable"); 8694 8627 } 8695 8628 8696 - index++; 8697 - if (next(js) == TOK_RBRACKET) break; 8698 - EXPECT(TOK_COMMA); 8629 + jsval_t bind = bind_destruct_pattern(js, &js->code[pattern_start], pattern_len, val, js->scope); 8630 + if (is_err(bind)) return bind; 8699 8631 } 8700 8632 8701 - JS_RESTORE_STATE(js, end_state); 8702 - return v; 8633 + return rhs; 8634 + } 8635 + 8636 + static jsval_t js_arr_destruct_assign(struct js *js) { 8637 + return js_destruct_assign_pattern( 8638 + js, TOK_LBRACKET, TOK_RBRACKET, 8639 + "array destructuring requires assignment", false 8640 + ); 8641 + } 8642 + 8643 + static jsval_t js_obj_destruct_assign(struct js *js) { 8644 + return js_destruct_assign_pattern( 8645 + js, TOK_LBRACE, TOK_RBRACE, 8646 + "destructuring requires assignment", true 8647 + ); 8703 8648 } 8704 8649 8705 8650 static jsval_t js_arr_literal(struct js *js); 8651 + static jsval_t js_obj_literal(struct js *js); 8706 8652 8707 8653 static jsval_t js_arr_or_destruct(struct js *js) { 8708 8654 jsoff_t saved_pos = js->pos; 8709 8655 uint8_t saved_tok = js->tok; 8710 8656 uint8_t saved_consumed = js->consumed; 8711 8657 uint8_t saved_flags = js->flags; 8658 + 8659 + jsoff_t saved_toff = js->toff; 8660 + jsoff_t saved_tlen = js->tlen; 8712 8661 int saved_stream_pos = js->token_stream_pos; 8713 8662 8714 8663 js->flags |= F_NOEXEC; ··· 8726 8675 js->tok = saved_tok; 8727 8676 js->consumed = saved_consumed; 8728 8677 js->flags = saved_flags; 8678 + js->toff = saved_toff; 8679 + js->tlen = saved_tlen; 8729 8680 js->token_stream_pos = saved_stream_pos; 8730 8681 8731 - if (is_destruct) { 8732 - return js_arr_destruct_assign(js); 8682 + if (is_destruct) return js_arr_destruct_assign(js); 8683 + return js_arr_literal(js); 8684 + } 8685 + 8686 + static jsval_t js_obj_or_destruct(struct js *js) { 8687 + jsoff_t saved_pos = js->pos; 8688 + uint8_t saved_tok = js->tok; 8689 + uint8_t saved_consumed = js->consumed; 8690 + uint8_t saved_flags = js->flags; 8691 + 8692 + jsoff_t saved_toff = js->toff; 8693 + jsoff_t saved_tlen = js->tlen; 8694 + int saved_stream_pos = js->token_stream_pos; 8695 + 8696 + js->flags |= F_NOEXEC; 8697 + js->consumed = 1; 8698 + int depth = 1; 8699 + while (depth > 0 && next(js) != TOK_EOF) { 8700 + if (js->tok == TOK_LBRACE) depth++; 8701 + else if (js->tok == TOK_RBRACE) depth--; 8702 + if (depth > 0) js->consumed = 1; 8733 8703 } 8734 - return js_arr_literal(js); 8704 + js->consumed = 1; 8705 + bool is_destruct = (next(js) == TOK_ASSIGN); 8706 + 8707 + js->pos = saved_pos; 8708 + js->tok = saved_tok; 8709 + js->consumed = saved_consumed; 8710 + js->flags = saved_flags; 8711 + js->toff = saved_toff; 8712 + js->tlen = saved_tlen; 8713 + js->token_stream_pos = saved_stream_pos; 8714 + 8715 + if (is_destruct) return js_obj_destruct_assign(js); 8716 + return js_obj_literal(js); 8735 8717 } 8736 8718 8737 8719 static jsval_t js_arr_literal(struct js *js) { ··· 9364 9346 case TOK_BIGINT: return js_bigint_literal(js); 9365 9347 case TOK_STRING: return js_str_literal(js); 9366 9348 case TOK_TEMPLATE: return js_template_literal(js); 9367 - case TOK_LBRACE: return js_obj_literal(js); 9349 + case TOK_LBRACE: return js_obj_or_destruct(js); 9368 9350 case TOK_LBRACKET: return js_arr_or_destruct(js); 9369 9351 case TOK_DIV: return js_regex_literal(js); 9370 9352 case TOK_CLASS: return js_class_expr(js, true); ··· 22429 22411 return proxy_obj; 22430 22412 } 22431 22413 22432 - static jsval_t builtin_Proxy(struct js *js, jsval_t *args, int nargs) { 22414 + static jsval_t create_proxy_checked(struct js *js, jsval_t *args, int nargs, bool require_new) { 22415 + if (require_new && vtype(js->new_target) == T_UNDEF) { 22416 + return js_mkerr_typed(js, JS_ERR_TYPE, "Proxy constructor requires 'new'"); 22417 + } 22433 22418 if (nargs < 2) return js_mkerr(js, "Proxy requires two arguments: target and handler"); 22434 - 22419 + 22435 22420 jsval_t target = args[0]; 22436 22421 jsval_t handler = args[1]; 22437 - 22422 + 22438 22423 uint8_t target_type = vtype(target); 22439 22424 if (target_type != T_OBJ && target_type != T_FUNC && target_type != T_ARR) { 22440 22425 return js_mkerr(js, "Proxy target must be an object"); 22441 22426 } 22442 - 22427 + 22443 22428 uint8_t handler_type = vtype(handler); 22444 22429 if (handler_type != T_OBJ && handler_type != T_FUNC) { 22445 22430 return js_mkerr(js, "Proxy handler must be an object"); 22446 22431 } 22447 - 22432 + 22448 22433 return mkproxy(js, target, handler); 22434 + } 22435 + 22436 + static jsval_t builtin_Proxy(struct js *js, jsval_t *args, int nargs) { 22437 + return create_proxy_checked(js, args, nargs, true); 22449 22438 } 22450 22439 22451 22440 static jsval_t proxy_revoke_fn(struct js *js, jsval_t *args, int nargs) { ··· 22463 22452 } 22464 22453 22465 22454 static jsval_t builtin_Proxy_revocable(struct js *js, jsval_t *args, int nargs) { 22466 - jsval_t proxy = builtin_Proxy(js, args, nargs); 22455 + jsval_t proxy = create_proxy_checked(js, args, nargs, false); 22467 22456 if (is_err(proxy)) return proxy; 22468 22457 22469 22458 jsval_t revoke_obj = mkobj(js, 0);
+14
src/modules/buffer.c
··· 166 166 167 167 // ArrayBuffer constructor 168 168 static jsval_t js_arraybuffer_constructor(struct js *js, jsval_t *args, int nargs) { 169 + if (vtype(js->new_target) == T_UNDEF) { 170 + return js_mkerr_typed(js, JS_ERR_TYPE, "ArrayBuffer constructor requires 'new'"); 171 + } 169 172 size_t length = 0; 170 173 if (nargs > 0 && vtype(args[0]) == T_NUM) { 171 174 length = (size_t)js_getnum(args[0]); ··· 807 810 808 811 #define DEFINE_TYPEDARRAY_CONSTRUCTOR(name, type) \ 809 812 static jsval_t js_##name##_constructor(struct js *js, jsval_t *args, int nargs) { \ 813 + if (vtype(js->new_target) == T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, #name " constructor requires 'new'"); \ 810 814 return js_typedarray_constructor(js, args, nargs, type, #name); \ 811 815 } 812 816 ··· 823 827 DEFINE_TYPEDARRAY_CONSTRUCTOR(BigUint64Array, TYPED_ARRAY_BIGUINT64) 824 828 825 829 static jsval_t js_dataview_constructor(struct js *js, jsval_t *args, int nargs) { 830 + if (vtype(js->new_target) == T_UNDEF) { 831 + return js_mkerr_typed(js, JS_ERR_TYPE, "DataView constructor requires 'new'"); 832 + } 826 833 if (nargs < 1) { 827 834 return js_mkerr(js, "DataView requires an ArrayBuffer"); 828 835 } ··· 1589 1596 } 1590 1597 1591 1598 static jsval_t js_sharedarraybuffer_constructor(struct js *js, jsval_t *args, int nargs) { 1599 + if (vtype(js->new_target) == T_UNDEF) { 1600 + return js_mkerr_typed(js, JS_ERR_TYPE, "SharedArrayBuffer constructor requires 'new'"); 1601 + } 1592 1602 size_t length = 0; 1593 1603 if (nargs > 0 && vtype(args[0]) == T_NUM) { 1594 1604 length = (size_t)js_getnum(args[0]); ··· 1629 1639 js_mkprop_fast(js, arraybuffer_ctor_obj, "prototype", 9, arraybuffer_proto); 1630 1640 js_mkprop_fast(js, arraybuffer_ctor_obj, "name", 4, ANT_STRING("ArrayBuffer")); 1631 1641 js_set_descriptor(js, arraybuffer_ctor_obj, "name", 4, 0); 1642 + js_define_species_getter(js, arraybuffer_ctor_obj); 1632 1643 js_set(js, glob, "ArrayBuffer", js_obj_to_func(arraybuffer_ctor_obj)); 1633 1644 1634 1645 jsval_t typedarray_proto = js_mkobj(js); ··· 1649 1660 js_set_proto(js, name##_proto, typedarray_proto); \ 1650 1661 js_set_slot(js, name##_ctor_obj, SLOT_CFUNC, js_mkfun(js_##name##_constructor)); \ 1651 1662 js_setprop(js, name##_ctor_obj, js_mkstr(js, "prototype", 9), name##_proto); \ 1663 + js_mkprop_fast(js, name##_ctor_obj, "name", 4, ANT_STRING(#name)); \ 1664 + js_set_descriptor(js, name##_ctor_obj, "name", 4, 0); \ 1665 + js_define_species_getter(js, name##_ctor_obj); \ 1652 1666 js_set(js, glob, #name, js_obj_to_func(name##_ctor_obj)); \ 1653 1667 } while(0) 1654 1668
+17 -1
src/modules/collections.c
··· 720 720 } 721 721 722 722 static jsval_t builtin_Map(ant_t *js, jsval_t *args, int nargs) { 723 + if (vtype(js->new_target) == T_UNDEF) { 724 + return js_mkerr_typed(js, JS_ERR_TYPE, "Map constructor requires 'new'"); 725 + } 726 + 723 727 jsval_t map_obj = js_mkobj(js); 724 728 jsoff_t obj_offset = (jsoff_t)vdata(map_obj); 725 729 ··· 767 771 } 768 772 769 773 static jsval_t builtin_Set(ant_t *js, jsval_t *args, int nargs) { 774 + if (vtype(js->new_target) == T_UNDEF) { 775 + return js_mkerr_typed(js, JS_ERR_TYPE, "Set constructor requires 'new'"); 776 + } 777 + 770 778 jsval_t set_obj = js_mkobj(js); 771 779 jsoff_t obj_offset = (jsoff_t)vdata(set_obj); 772 780 ··· 804 812 } 805 813 806 814 static jsval_t builtin_WeakMap(ant_t *js, jsval_t *args, int nargs) { 815 + if (vtype(js->new_target) == T_UNDEF) { 816 + return js_mkerr_typed(js, JS_ERR_TYPE, "WeakMap constructor requires 'new'"); 817 + } 807 818 jsval_t wm_obj = js_mkobj(js); 808 819 809 820 jsval_t wm_proto = js_get_ctor_proto(js, "WeakMap", 7); ··· 850 861 } 851 862 852 863 static jsval_t builtin_WeakSet(ant_t *js, jsval_t *args, int nargs) { 853 - jsval_t ws_obj = js_mkobj(js); 864 + if (vtype(js->new_target) == T_UNDEF) { 865 + return js_mkerr_typed(js, JS_ERR_TYPE, "WeakSet constructor requires 'new'"); 866 + } 854 867 868 + jsval_t ws_obj = js_mkobj(js); 855 869 jsval_t ws_proto = js_get_ctor_proto(js, "WeakSet", 7); 856 870 if (is_special_object(ws_proto)) js_set_proto(js, ws_obj, ws_proto); 857 871 ··· 913 927 js_mkprop_fast(js, map_ctor, "prototype", 9, map_proto); 914 928 js_mkprop_fast(js, map_ctor, "name", 4, ANT_STRING("Map")); 915 929 js_set_descriptor(js, map_ctor, "name", 4, 0); 930 + js_define_species_getter(js, map_ctor); 916 931 js_set(js, glob, "Map", js_obj_to_func(map_ctor)); 917 932 918 933 jsval_t set_proto = js_mkobj(js); ··· 934 949 js_mkprop_fast(js, set_ctor, "prototype", 9, set_proto); 935 950 js_mkprop_fast(js, set_ctor, "name", 4, ANT_STRING("Set")); 936 951 js_set_descriptor(js, set_ctor, "name", 4, 0); 952 + js_define_species_getter(js, set_ctor); 937 953 js_set(js, glob, "Set", js_obj_to_func(set_ctor)); 938 954 939 955 jsval_t weakmap_proto = js_mkobj(js);
+1 -1
src/modules/reflect.c
··· 166 166 jsval_t this_arg = args[1]; 167 167 jsval_t args_arr = args[2]; 168 168 169 - if (vtype(target) != T_FUNC) { 169 + if (vtype(target) != T_FUNC && vtype(target) != T_CFUNC) { 170 170 return js_mkerr(js, "Reflect.apply: first argument must be a function"); 171 171 } 172 172
+11 -4
src/modules/symbol.c
··· 27 27 const char *get_observable_sym_key(void) { return g_observable.key; } 28 28 const char *get_toPrimitive_sym_key(void) { return g_toPrimitive.key; } 29 29 const char *get_hasInstance_sym_key(void) { return g_hasInstance.key; } 30 + const char *get_species_sym_key(void) { return g_species.key; } 30 31 31 32 static const struct { jsval_t *sym; const char *name; } sym_table[] = { 32 33 { &g_iterator.sym, "Symbol.iterator" }, ··· 210 211 return js_getthis(js); 211 212 } 212 213 214 + void js_define_species_getter(struct js *js, jsval_t ctor) { 215 + if (vtype(ctor) == T_FUNC) ctor = mkval(T_OBJ, vdata(ctor)); 216 + if (vtype(ctor) != T_OBJ || g_species.key[0] == '\0') return; 217 + js_set_getter_desc(js, ctor, g_species.key, strlen(g_species.key), js_mkfun(species_getter), JS_DESC_C); 218 + } 219 + 213 220 static jsval_t date_toPrimitive(struct js *js, jsval_t *args, int nargs) { 214 221 jsval_t this_val = js_getthis(js); 215 222 ··· 284 291 jsval_t promise_ctor = js_get(js, js_glob(js), "Promise"); 285 292 jsval_t promise_proto = js_get(js, promise_ctor, "prototype"); 286 293 js_set(js, promise_proto, g_toStringTag.key, js_mkstr(js, "Promise", 7)); 287 - 288 - jsval_t species_fn = js_mkfun(species_getter); 289 - js_set_getter_desc(js, promise_ctor, g_species.key, strlen(g_species.key), species_fn, JS_DESC_C); 290 - js_set_getter_desc(js, array_ctor, g_species.key, strlen(g_species.key), species_fn, JS_DESC_C); 294 + 295 + js_define_species_getter(js, promise_ctor); 296 + js_define_species_getter(js, array_ctor); 297 + js_define_species_getter(js, js_get(js, js_glob(js), "RegExp")); 291 298 }