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 enhanced destructuring pattern support for arrays and objects

+264 -36
+264 -36
src/ant.c
··· 6699 6699 return pos; 6700 6700 } 6701 6701 6702 + static jsoff_t destruct_source_len(struct js *js, jsval_t val) { 6703 + if (vtype(val) == T_STR) { 6704 + size_t slen = 0; 6705 + (void)js_getstr(js, val, &slen); 6706 + return (jsoff_t)slen; 6707 + } 6708 + return js_arr_len(js, val); 6709 + } 6710 + 6711 + static jsval_t destruct_source_get(struct js *js, jsval_t val, jsoff_t idx) { 6712 + if (vtype(val) == T_STR) { 6713 + size_t slen = 0; 6714 + char *s = js_getstr(js, val, &slen); 6715 + if ((size_t)idx >= slen) return js_mkundef(); 6716 + return js_mkstr(js, &s[idx], 1); 6717 + } 6718 + return js_arr_get(js, val, idx); 6719 + } 6720 + 6721 + static jsval_t destruct_get_by_key(struct js *js, jsval_t obj, jsval_t key) { 6722 + if (!is_object_type(obj)) return js_mkerr(js, "invalid assignment target"); 6723 + if (vtype(key) == T_SYMBOL) { 6724 + char sym_buf[32]; 6725 + int klen = sym_to_prop_key(key, sym_buf, sizeof(sym_buf)); 6726 + if (klen < 0) return js_mkerr(js, "invalid symbol key"); 6727 + return getprop_any(js, obj, sym_buf, (size_t)klen); 6728 + } 6729 + jsval_t key_str = coerce_to_str(js, key); 6730 + if (is_err(key_str)) return key_str; 6731 + jsoff_t klen = 0, koff = vstr(js, key_str, &klen); 6732 + return getprop_any(js, obj, (const char *)&js->mem[koff], (size_t)klen); 6733 + } 6734 + 6735 + static jsval_t destruct_set_by_key(struct js *js, jsval_t obj, jsval_t key, jsval_t value) { 6736 + if (!is_object_type(obj)) return js_mkerr(js, "invalid assignment target"); 6737 + if (vtype(key) == T_SYMBOL) { 6738 + char sym_buf[32]; 6739 + int klen = sym_to_prop_key(key, sym_buf, sizeof(sym_buf)); 6740 + if (klen < 0) return js_mkerr(js, "invalid symbol key"); 6741 + return js_setprop(js, obj, js_mkstr(js, sym_buf, (size_t)klen), value); 6742 + } 6743 + jsval_t key_str = coerce_to_str(js, key); 6744 + if (is_err(key_str)) return key_str; 6745 + return js_setprop(js, obj, key_str, value); 6746 + } 6747 + 6748 + static bool scan_balanced_with_strings(const char *p, jsoff_t len, jsoff_t *pos, char open, char close) { 6749 + if (*pos >= len || p[*pos] != open) return false; 6750 + 6751 + int depth = 1; 6752 + bool in_string = false; 6753 + char string_char = '\0'; 6754 + (*pos)++; 6755 + 6756 + while (*pos < len && depth > 0) { 6757 + char ch = p[*pos]; 6758 + if (in_string) { 6759 + if (ch == '\\' && *pos + 1 < len) { 6760 + *pos += 2; 6761 + continue; 6762 + } 6763 + if (ch == string_char) { 6764 + in_string = false; 6765 + string_char = '\0'; 6766 + } 6767 + (*pos)++; 6768 + continue; 6769 + } 6770 + if (ch == '"' || ch == '\'' || ch == '`') { 6771 + in_string = true; 6772 + string_char = ch; 6773 + (*pos)++; 6774 + continue; 6775 + } 6776 + if (ch == open) depth++; 6777 + else if (ch == close) depth--; 6778 + (*pos)++; 6779 + } 6780 + return depth == 0; 6781 + } 6782 + 6783 + static jsval_t parse_nested_pattern_span( 6784 + struct js *js, const char *p, jsoff_t len, jsoff_t *pos, 6785 + jsoff_t *out_start, jsoff_t *out_len 6786 + ) { 6787 + char open = p[*pos]; 6788 + char close = (open == '[') ? ']' : '}'; 6789 + 6790 + *out_start = *pos; 6791 + if (!scan_balanced_with_strings(p, len, pos, open, close)) { 6792 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "unclosed nested destructuring pattern"); 6793 + } 6794 + *out_len = *pos - *out_start; 6795 + return js_mkundef(); 6796 + } 6797 + 6798 + static jsval_t eval_computed_key_expr( 6799 + struct js *js, const char *p, jsoff_t len, jsoff_t *pos, const char *unclosed_msg 6800 + ) { 6801 + jsoff_t expr_start = *pos + 1; 6802 + if (!scan_balanced_with_strings(p, len, pos, '[', ']')) { 6803 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "%s", unclosed_msg); 6804 + } 6805 + 6806 + jsoff_t expr_end = *pos - 1; 6807 + jsval_t key = js_eval_str(js, &p[expr_start], expr_end - expr_start); 6808 + if (is_err(key)) return key; 6809 + return resolveprop(js, key); 6810 + } 6811 + 6812 + static jsval_t extend_destruct_target_span( 6813 + struct js *js, const char *p, jsoff_t len, jsoff_t target_pos, 6814 + jsoff_t *target_len, jsoff_t *out_pos 6815 + ) { 6816 + jsoff_t pos = skiptonext(p, len, target_pos + *target_len, NULL); 6817 + 6818 + while (pos < len && (p[pos] == '.' || p[pos] == '[')) { 6819 + if (p[pos] == '.') { 6820 + pos = skiptonext(p, len, pos + 1, NULL); 6821 + jsoff_t ident_len = 0; 6822 + if (parseident(&p[pos], len - pos, &ident_len) != TOK_IDENTIFIER) { 6823 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected after '.'"); 6824 + } 6825 + pos += ident_len; 6826 + pos = skiptonext(p, len, pos, NULL); 6827 + *target_len = pos - target_pos; 6828 + continue; 6829 + } 6830 + 6831 + if (!scan_balanced_with_strings(p, len, &pos, '[', ']')) { 6832 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "']' expected"); 6833 + } 6834 + pos = skiptonext(p, len, pos, NULL); 6835 + *target_len = pos - target_pos; 6836 + } 6837 + 6838 + *out_pos = pos; 6839 + return js_mkundef(); 6840 + } 6841 + 6842 + static jsval_t make_destruct_rest_array(struct js *js, jsval_t val, jsoff_t start_idx) { 6843 + jsval_t rest = js_mkarr(js); 6844 + if (is_err(rest)) return rest; 6845 + 6846 + jsoff_t alen = destruct_source_len(js, val); 6847 + for (jsoff_t i = start_idx; i < alen; i++) { 6848 + js_arr_push(js, rest, destruct_source_get(js, val, i)); 6849 + } 6850 + return rest; 6851 + } 6852 + 6853 + static jsval_t assign_destruct_target(struct js *js, const char *p, jsoff_t len, jsval_t value, jsval_t scope) { 6854 + jsoff_t pos = skiptonext(p, len, 0, NULL); 6855 + jsoff_t base_len = 0; 6856 + if (parseident(&p[pos], len - pos, &base_len) != TOK_IDENTIFIER) { 6857 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "invalid assignment target in destructuring"); 6858 + } 6859 + 6860 + jsoff_t base_pos = pos; 6861 + pos += base_len; 6862 + pos = skiptonext(p, len, pos, NULL); 6863 + if (pos >= len) { 6864 + jsval_t vname = js_mkstr(js, &p[base_pos], base_len); 6865 + return js_setprop(js, scope, vname, value); 6866 + } 6867 + 6868 + jsval_t cur = getprop_any(js, scope, &p[base_pos], (size_t)base_len); 6869 + if (is_err(cur)) return cur; 6870 + 6871 + while (pos < len) { 6872 + if (p[pos] == '.') { 6873 + pos = skiptonext(p, len, pos + 1, NULL); 6874 + jsoff_t nlen = 0; 6875 + if (parseident(&p[pos], len - pos, &nlen) != TOK_IDENTIFIER) { 6876 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected after '.'"); 6877 + } 6878 + jsval_t key = js_mkstr(js, &p[pos], nlen); 6879 + pos += nlen; 6880 + pos = skiptonext(p, len, pos, NULL); 6881 + if (pos >= len) return destruct_set_by_key(js, cur, key, value); 6882 + cur = destruct_get_by_key(js, cur, key); 6883 + if (is_err(cur)) return cur; 6884 + continue; 6885 + } 6886 + 6887 + if (p[pos] == '[') { 6888 + jsval_t key = eval_computed_key_expr(js, p, len, &pos, "']' expected"); 6889 + if (is_err(key)) return key; 6890 + pos = skiptonext(p, len, pos, NULL); 6891 + if (pos >= len) return destruct_set_by_key(js, cur, key, value); 6892 + cur = destruct_get_by_key(js, cur, key); 6893 + if (is_err(cur)) return cur; 6894 + continue; 6895 + } 6896 + 6897 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "invalid assignment target in destructuring"); 6898 + } 6899 + return js_mkundef(); 6900 + } 6901 + 6702 6902 static jsval_t bind_destruct_pattern(struct js *js, const char *p, jsoff_t len, jsval_t val, jsval_t scope) { 6703 6903 jsoff_t pos = skiptonext(p, len, 0, NULL); 6704 6904 if (pos >= len) return js_mkundef(); ··· 6716 6916 if (p[pos] == ',') { pos++; idx++; continue; } 6717 6917 6718 6918 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); 6919 + jsoff_t nested_start = 0, nested_len = 0; 6920 + jsval_t nested_res = parse_nested_pattern_span(js, p, len, &pos, &nested_start, &nested_len); 6921 + if (is_err(nested_res)) return nested_res; 6922 + 6923 + jsval_t elem_val = destruct_source_get(js, val, idx); 6730 6924 jsval_t r = bind_destruct_pattern(js, &p[nested_start], nested_len, elem_val, scope); 6731 6925 if (is_err(r)) return r; 6732 6926 idx++; ··· 6737 6931 6738 6932 bool is_rest = (pos + 2 < len && p[pos] == '.' && p[pos+1] == '.' && p[pos+2] == '.'); 6739 6933 if (is_rest) { pos += 3; pos = skiptonext(p, len, pos, NULL); } 6934 + 6935 + if (is_arr && is_rest && pos < len && (p[pos] == '[' || p[pos] == '{')) { 6936 + jsoff_t nested_start = 0, nested_len = 0; 6937 + jsval_t nested_res = parse_nested_pattern_span(js, p, len, &pos, &nested_start, &nested_len); 6938 + if (is_err(nested_res)) return nested_res; 6939 + 6940 + jsval_t rest = make_destruct_rest_array(js, val, idx); 6941 + if (is_err(rest)) return rest; 6942 + 6943 + jsval_t r = bind_destruct_pattern(js, &p[nested_start], nested_len, rest, scope); 6944 + if (is_err(r)) return r; 6945 + 6946 + idx = (int)destruct_source_len(js, val); 6947 + pos = skiptonext(p, len, pos, NULL); 6948 + if (pos < len && p[pos] == ',') pos++; 6949 + continue; 6950 + } 6740 6951 6952 + bool has_computed_key = false; 6953 + jsval_t computed_key = js_mkundef(); 6741 6954 jsoff_t name_len = 0; 6742 - if (parseident(&p[pos], len - pos, &name_len) != TOK_IDENTIFIER) break; 6743 - 6744 - jsoff_t var_pos = pos, var_len = name_len; 6745 - jsoff_t src_pos = pos, src_len = name_len; 6746 - 6747 - pos += name_len; 6955 + jsoff_t var_pos = 0, var_len = 0; 6956 + jsoff_t src_pos = 0, src_len = 0; 6957 + jsoff_t target_pos = 0, target_len = 0; 6958 + 6959 + if (!is_arr && p[pos] == '[') { 6960 + has_computed_key = true; 6961 + computed_key = eval_computed_key_expr(js, p, len, &pos, "unclosed computed property name"); 6962 + if (is_err(computed_key)) return computed_key; 6963 + } else { 6964 + if (parseident(&p[pos], len - pos, &name_len) != TOK_IDENTIFIER) break; 6965 + var_pos = pos; 6966 + var_len = name_len; 6967 + src_pos = pos; 6968 + src_len = name_len; 6969 + target_pos = pos; 6970 + target_len = name_len; 6971 + pos += name_len; 6972 + } 6748 6973 pos = skiptonext(p, len, pos, NULL); 6749 6974 6750 6975 bool is_nested = false; ··· 6755 6980 6756 6981 if (pos < len && (p[pos] == '{' || p[pos] == '[')) { 6757 6982 is_nested = true; 6758 - nested_start = pos; 6759 - char open = p[pos], close = (open == '{') ? '}' : ']'; 6760 - int depth = 1; 6761 - pos++; 6762 - while (pos < len && depth > 0) { 6763 - if (p[pos] == open) depth++; 6764 - else if (p[pos] == close) depth--; 6765 - pos++; 6766 - } 6767 - nested_len = pos - nested_start; 6983 + jsval_t nested_res = parse_nested_pattern_span(js, p, len, &pos, &nested_start, &nested_len); 6984 + if (is_err(nested_res)) return nested_res; 6768 6985 pos = skiptonext(p, len, pos, NULL); 6769 6986 } else { 6770 6987 jsoff_t rlen = 0; 6771 6988 if (parseident(&p[pos], len - pos, &rlen) == TOK_IDENTIFIER) { 6772 6989 var_pos = pos; var_len = rlen; 6990 + target_pos = pos; target_len = rlen; 6773 6991 pos += rlen; 6774 6992 pos = skiptonext(p, len, pos, NULL); 6775 6993 } 6776 6994 } 6995 + } else if (!is_arr && has_computed_key) { 6996 + return js_mkerr(js, "':' expected after computed property name"); 6997 + } 6998 + 6999 + if (target_len > 0) { 7000 + jsval_t span_res = extend_destruct_target_span(js, p, len, target_pos, &target_len, &pos); 7001 + if (is_err(span_res)) return span_res; 6777 7002 } 6778 7003 6779 7004 jsval_t prop_val; 6780 7005 if (is_rest && is_arr) { 6781 - jsval_t rest = js_mkarr(js); 6782 - if (is_err(rest)) return rest; 6783 - jsoff_t alen = js_arr_len(js, val); 6784 - for (jsoff_t i = idx; i < alen; i++) js_arr_push(js, rest, js_arr_get(js, val, i)); 6785 - prop_val = rest; 7006 + prop_val = make_destruct_rest_array(js, val, idx); 7007 + if (is_err(prop_val)) return prop_val; 6786 7008 } else if (is_rest) prop_val = mkobj(js, 0); 6787 - else if (is_arr) prop_val = js_arr_get(js, val, idx); 7009 + else if (is_arr) prop_val = destruct_source_get(js, val, idx); 7010 + else if (has_computed_key) prop_val = destruct_get_by_key(js, val, computed_key); 6788 7011 else prop_val = getprop_any(js, val, &p[src_pos], src_len); 7012 + if (is_err(prop_val)) return prop_val; 6789 7013 6790 7014 if (is_nested) { 6791 7015 jsval_t r = bind_destruct_pattern(js, &p[nested_start], nested_len, prop_val, scope); ··· 6808 7032 prop_val = resolveprop(js, prop_val); 6809 7033 6810 7034 bind:; 6811 - jsval_t vname = js_mkstr(js, &p[var_pos], var_len); 6812 - if (is_err(vname)) return vname; 6813 - jsval_t r = js_setprop(js, scope, vname, prop_val); 7035 + jsval_t r; 7036 + if (target_len > 0) r = assign_destruct_target(js, &p[target_pos], target_len, prop_val, scope); 7037 + else { 7038 + jsval_t vname = js_mkstr(js, &p[var_pos], var_len); 7039 + if (is_err(vname)) return vname; 7040 + r = js_setprop(js, scope, vname, prop_val); 7041 + } 6814 7042 if (is_err(r)) return r; 6815 7043 6816 7044 idx++;