MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add support for getter and setter methods in class expressions

+197 -58
+1 -1
meson.build
··· 75 75 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 76 76 77 77 version_conf = configuration_data() 78 - version_conf.set('ANT_VERSION', '0.2.0.2') 78 + version_conf.set('ANT_VERSION', '0.2.0.3') 79 79 version_conf.set('ANT_GIT_HASH', git_hash) 80 80 version_conf.set('ANT_BUILD_DATE', build_date) 81 81
+196 -57
src/ant.c
··· 2765 2765 } 2766 2766 2767 2767 jsoff_t existing = lkp(js, obj, key, klen); 2768 - if (existing <= 0) goto create_new; 2769 2768 2770 2769 char desc_key[128]; 2771 2770 snprintf(desc_key, sizeof(desc_key), "__desc_%.*s", (int)klen, key); 2772 2771 jsoff_t desc_off = lkp(js, obj, desc_key, strlen(desc_key)); 2773 2772 2774 2773 if (desc_off == 0) { 2774 + desc_off = lkp_proto(js, obj, desc_key, strlen(desc_key)); 2775 + } 2776 + 2777 + jsval_t desc_obj = js_mkundef(); 2778 + if (desc_off != 0) { 2779 + desc_obj = resolveprop(js, mkval(T_PROP, desc_off)); 2780 + if (vtype(desc_obj) == T_OBJ) { 2781 + jsoff_t set_off = lkp(js, desc_obj, "set", 3); 2782 + if (set_off != 0) { 2783 + jsval_t setter = resolveprop(js, mkval(T_PROP, set_off)); 2784 + if (vtype(setter) == T_FUNC || vtype(setter) == T_CFUNC) { 2785 + js_parse_state_t saved; 2786 + JS_SAVE_STATE(js, saved); 2787 + uint8_t saved_flags = js->flags; 2788 + jsoff_t saved_toff = js->toff; 2789 + jsoff_t saved_tlen = js->tlen; 2790 + 2791 + jsval_t saved_this = js->this_val; 2792 + js->this_val = obj; 2793 + push_this(obj); 2794 + jsval_t result = call_js_with_args(js, setter, &v, 1); 2795 + pop_this(); 2796 + js->this_val = saved_this; 2797 + 2798 + JS_RESTORE_STATE(js, saved); 2799 + js->flags = saved_flags; 2800 + js->toff = saved_toff; 2801 + js->tlen = saved_tlen; 2802 + 2803 + if (is_err(result)) return result; 2804 + return v; 2805 + } 2806 + } 2807 + 2808 + jsoff_t get_off = lkp(js, desc_obj, "get", 3); 2809 + if (get_off != 0 && set_off == 0) { 2810 + if (js->flags & F_STRICT) { 2811 + return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot set property which has only a getter"); 2812 + } 2813 + return v; 2814 + } 2815 + } 2816 + } 2817 + 2818 + if (existing <= 0) goto create_new; 2819 + 2820 + if (desc_off == 0) { 2775 2821 if (is_const_prop(js, existing)) { 2776 2822 if (js->flags & F_STRICT) return js_mkerr(js, "assignment to constant"); 2777 2823 return mkval(T_PROP, existing); ··· 2779 2825 goto do_update; 2780 2826 } 2781 2827 2782 - jsval_t desc_obj = resolveprop(js, mkval(T_PROP, desc_off)); 2783 2828 if (vtype(desc_obj) != T_OBJ) goto do_update; 2784 2829 2785 - jsoff_t get_off = lkp(js, desc_obj, "get", 3); 2786 - jsoff_t set_off = lkp(js, desc_obj, "set", 3); 2787 - 2788 - if (get_off != 0 && set_off == 0) { 2789 - if (js->flags & F_STRICT) { 2790 - return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot set property which has only a getter"); 2791 - } 2792 - return mkval(T_PROP, existing); 2793 - } 2794 - 2795 - if (set_off != 0) { 2796 - jsval_t setter = resolveprop(js, mkval(T_PROP, set_off)); 2797 - if (vtype(setter) == T_FUNC || vtype(setter) == T_CFUNC) { 2798 - js_parse_state_t saved; 2799 - JS_SAVE_STATE(js, saved); 2800 - uint8_t saved_flags = js->flags; 2801 - jsoff_t saved_toff = js->toff; 2802 - jsoff_t saved_tlen = js->tlen; 2803 - 2804 - jsval_t saved_this = js->this_val; 2805 - js->this_val = obj; 2806 - push_this(obj); 2807 - jsval_t result = call_js_with_args(js, setter, &v, 1); 2808 - pop_this(); 2809 - js->this_val = saved_this; 2810 - 2811 - JS_RESTORE_STATE(js, saved); 2812 - js->flags = saved_flags; 2813 - js->toff = saved_toff; 2814 - js->tlen = saved_tlen; 2815 - 2816 - if (is_err(result)) return result; 2817 - return v; 2818 - } 2819 - } 2820 - 2821 2830 jsoff_t writable_off = lkp(js, desc_obj, "writable", 8); 2822 2831 if (writable_off != 0) { 2823 2832 jsval_t writable_val = resolveprop(js, mkval(T_PROP, writable_off)); ··· 4007 4016 static bool try_accessor_getter(struct js *js, jsval_t obj, const char *key, size_t key_len, jsval_t *out) { 4008 4017 char desc_key[128]; 4009 4018 snprintf(desc_key, sizeof(desc_key), "__desc_%.*s", (int)key_len, key); 4019 + jsoff_t desc_off = lkp(js, obj, desc_key, strlen(desc_key)); 4010 4020 4011 - jsoff_t desc_off = lkp(js, obj, desc_key, strlen(desc_key)); 4021 + if (desc_off == 0) { 4022 + desc_off = lkp_proto(js, obj, desc_key, strlen(desc_key)); 4023 + } 4024 + 4012 4025 if (desc_off == 0) return false; 4013 4026 4014 4027 jsval_t desc_obj = loadval(js, desc_off + sizeof(jsoff_t) * 2); ··· 4139 4152 static bool try_accessor_setter(struct js *js, jsval_t obj, const char *key, size_t key_len, jsval_t val, jsval_t *out) { 4140 4153 char desc_key[128]; 4141 4154 snprintf(desc_key, sizeof(desc_key), "__desc_%.*s", (int)key_len, key); 4155 + jsoff_t desc_off = lkp(js, obj, desc_key, strlen(desc_key)); 4156 + 4157 + if (desc_off == 0) { 4158 + desc_off = lkp_proto(js, obj, desc_key, strlen(desc_key)); 4159 + } 4142 4160 4143 - jsoff_t desc_off = lkp(js, obj, desc_key, strlen(desc_key)); 4144 4161 if (desc_off == 0) return false; 4145 4162 4146 4163 jsval_t desc_obj = loadval(js, desc_off + sizeof(jsoff_t) * 2); ··· 4511 4528 return mkval(T_PROP, own_off); 4512 4529 } 4513 4530 4514 - jsval_t accessor_result; 4515 - if (try_accessor_getter(js, l, ptr, plen, &accessor_result)) { 4516 - return accessor_result; 4531 + char desc_key[128]; 4532 + snprintf(desc_key, sizeof(desc_key), "__desc_%.*s", (int)plen, ptr); 4533 + jsoff_t proto_desc_off = lkp_proto(js, l, desc_key, strlen(desc_key)); 4534 + if (proto_desc_off != 0) { 4535 + jsval_t desc_obj = loadval(js, proto_desc_off + sizeof(jsoff_t) * 2); 4536 + if (vtype(desc_obj) == T_OBJ) { 4537 + jsoff_t get_off = lkp(js, desc_obj, "get", 3); 4538 + jsoff_t set_off = lkp(js, desc_obj, "set", 3); 4539 + if (get_off != 0 || set_off != 0) { 4540 + jsval_t key = js_mkstr(js, ptr, plen); 4541 + return mkpropref((jsoff_t)vdata(l), (jsoff_t)vdata(key)); 4542 + } 4543 + } 4517 4544 } 4518 4545 4519 4546 jsval_t result = try_dynamic_getter(js, l, ptr, plen); ··· 4789 4816 static jsval_t call_js_internal_nfe(struct js *js, const char *fn, jsoff_t fnlen, jsval_t closure_scope, jsval_t *bound_args, int bound_argc, jsval_t func_name, jsval_t func_val) { 4790 4817 jsoff_t fnpos = 1; 4791 4818 jsval_t saved_scope = js->scope; 4819 + jsval_t saved_this_val = js->this_val; 4792 4820 jsval_t target_this = peek_this(); 4793 4821 jsoff_t parent_scope_offset; 4794 4822 ··· 4835 4863 caller_pos = skiptonext(caller_code, caller_clen, caller_pos, NULL); 4836 4864 } 4837 4865 js->pos = caller_pos; 4866 + 4867 + js->scope = function_scope; 4838 4868 4839 4869 int argi = 0; 4840 4870 bool has_rest = false; ··· 4974 5004 if (global_scope_stack && utarray_len(global_scope_stack) > 0) utarray_pop_back(global_scope_stack); 4975 5005 4976 5006 js->scope = saved_scope; 5007 + js->this_val = saved_this_val; 4977 5008 return res; 4978 5009 } 4979 5010 ··· 6689 6720 6690 6721 jsval_t desc_key_str = js_mkstr(js, desc_key, strlen(desc_key)); 6691 6722 setprop(js, obj, desc_key_str, desc_obj); 6692 - 6693 - jsoff_t prop_off = lkp(js, obj, key_str, key_len); 6694 - if (prop_off == 0) { 6695 - setprop(js, obj, key, js_mkundef()); 6696 - } 6697 6723 } else { 6698 6724 jsval_t res = setprop(js, obj, key, val); 6699 6725 if (is_err(res)) return res; ··· 8032 8058 if (is_err(scope_key)) return scope_key; 8033 8059 jsval_t res3 = setprop(js, func_obj, scope_key, js->scope); 8034 8060 if (is_err(res3)) return res3; 8061 + 8062 + jsval_t this_key = js_mkstr(js, "__this", 6); 8063 + if (is_err(this_key)) return this_key; 8064 + jsval_t res4 = setprop(js, func_obj, this_key, js->this_val); 8065 + if (is_err(res4)) return res4; 8035 8066 } 8036 8067 8037 8068 return mkval(T_FUNC, (unsigned long) vdata(func_obj)); ··· 8325 8356 jsval_t arr = js_mkundef(); 8326 8357 if (exe) { 8327 8358 arr = resolveprop(js, v); 8328 - if (vtype(arr) != T_ARR) { 8329 - return js_mkerr(js, "cannot array destructure non-array"); 8359 + if (vtype(arr) != T_ARR && vtype(arr) != T_STR) { 8360 + return js_mkerr(js, "cannot array destructure non-iterable"); 8330 8361 } 8331 8362 } 8332 8363 ··· 8376 8407 if (is_rest) { 8377 8408 jsval_t rest_arr = js_mkarr(js); 8378 8409 if (is_err(rest_arr)) return rest_arr; 8379 - jsoff_t total_len = arr_length(js, arr); 8410 + jsoff_t total_len = vtype(arr) == T_STR ? 0 : arr_length(js, arr); 8411 + if (vtype(arr) == T_STR) { 8412 + jsoff_t slen; 8413 + vstr(js, arr, &slen); 8414 + total_len = slen; 8415 + } 8380 8416 for (jsoff_t i = index; i < total_len; i++) { 8381 - jsval_t elem = arr_get(js, arr, i); 8417 + jsval_t elem; 8418 + if (vtype(arr) == T_STR) { 8419 + jsoff_t slen, soff = vstr(js, arr, &slen); 8420 + elem = js_mkstr(js, (char *)&js->mem[soff + i], 1); 8421 + } else { 8422 + elem = arr_get(js, arr, i); 8423 + } 8382 8424 js_arr_push(js, rest_arr, elem); 8383 8425 } 8384 8426 prop_val = rest_arr; 8385 8427 } else { 8386 - prop_val = arr_get(js, arr, index); 8428 + if (vtype(arr) == T_STR) { 8429 + jsoff_t slen, soff = vstr(js, arr, &slen); 8430 + if ((jsoff_t)index < slen) { 8431 + prop_val = js_mkstr(js, (char *)&js->mem[soff + index], 1); 8432 + } else { 8433 + prop_val = js_mkundef(); 8434 + } 8435 + } else { 8436 + prop_val = arr_get(js, arr, index); 8437 + } 8387 8438 8388 8439 if (vtype(prop_val) == T_UNDEF && default_len > 0) { 8389 8440 prop_val = js_eval_slice(js, default_off, default_len); ··· 8684 8735 jsoff_t var_name_len; 8685 8736 bool is_const_var; 8686 8737 uint8_t flags; 8738 + bool has_destructure; 8739 + jsoff_t destructure_off; 8740 + jsoff_t destructure_len; 8687 8741 } for_iter_ctx_t; 8688 8742 8689 8743 static jsval_t for_iter_bind_var(struct js *js, for_iter_ctx_t *ctx, jsval_t value) { 8744 + if (ctx->has_destructure) { 8745 + return bind_destruct_pattern(js, &js->code[ctx->destructure_off], ctx->destructure_len, value, js->scope); 8746 + } 8690 8747 const char *var_name = &js->code[ctx->var_name_off]; 8691 8748 jsoff_t existing = lkp(js, js->scope, var_name, ctx->var_name_len); 8692 8749 if (existing > 0) { ··· 8901 8958 bool is_var_decl = false; 8902 8959 bool is_let_loop = false; 8903 8960 jsoff_t let_var_off = 0, let_var_len = 0; 8961 + bool has_destructure = false; 8962 + jsoff_t destructure_off = 0, destructure_len = 0; 8904 8963 8905 8964 if (next(js) == TOK_LET || next(js) == TOK_CONST || next(js) == TOK_VAR) { 8906 8965 if (js->tok == TOK_VAR) { ··· 8914 8973 } 8915 8974 is_const_var = (js->tok == TOK_CONST); 8916 8975 js->consumed = 1; 8917 - if (next(js) == TOK_IDENTIFIER) { 8976 + 8977 + if (next(js) == TOK_LBRACKET || next(js) == TOK_LBRACE) { 8978 + has_destructure = true; 8979 + destructure_off = js->toff; 8980 + uint8_t open_tok = js->tok; 8981 + uint8_t close_tok = (open_tok == TOK_LBRACKET) ? TOK_RBRACKET : TOK_RBRACE; 8982 + int depth = 1; 8983 + js->consumed = 1; 8984 + while (depth > 0 && next(js) != TOK_EOF) { 8985 + if (js->tok == open_tok) depth++; 8986 + else if (js->tok == close_tok) depth--; 8987 + js->consumed = 1; 8988 + } 8989 + destructure_len = js->pos - destructure_off; 8990 + if (next(js) == TOK_IN) { 8991 + is_for_in = true; 8992 + js->consumed = 1; 8993 + } else if (next(js) == TOK_OF) { 8994 + is_for_of = true; 8995 + js->consumed = 1; 8996 + } else { 8997 + res = js_mkerr_typed(js, JS_ERR_SYNTAX, "expected 'in' or 'of' after destructuring pattern"); 8998 + goto done; 8999 + } 9000 + } else if (next(js) == TOK_IDENTIFIER) { 8918 9001 var_name_off = js->toff; 8919 9002 var_name_len = js->tlen; 8920 9003 if (is_let_loop) { ··· 9084 9167 if (exe) { 9085 9168 jsval_t iterable = resolveprop(js, iter_expr); 9086 9169 uint8_t itype = vtype(iterable); 9087 - for_iter_ctx_t ctx = { body_start, body_end, var_name_off, var_name_len, is_const_var, flags }; 9170 + for_iter_ctx_t ctx = { body_start, body_end, var_name_off, var_name_len, is_const_var, flags, has_destructure, destructure_off, destructure_len }; 9088 9171 9089 9172 if (itype == T_ARR) res = for_of_iter_array(js, &ctx, iterable); 9090 9173 else if (itype == T_STR) res = for_of_iter_string(js, &ctx, iterable); ··· 10079 10162 bool is_async; 10080 10163 bool is_static; 10081 10164 bool is_field; 10165 + bool is_getter; 10166 + bool is_setter; 10082 10167 jsoff_t field_start, field_end; 10083 10168 } MethodInfo; 10084 10169 ··· 10089 10174 while ((class_tok = next(js)) != TOK_RBRACE && class_tok != TOK_EOF && method_count < 32) { 10090 10175 bool is_async_method = false; 10091 10176 bool is_static_member = false; 10177 + bool is_getter_method = false; 10178 + bool is_setter_method = false; 10092 10179 10093 10180 if (next(js) == TOK_STATIC) { 10094 10181 is_static_member = true; ··· 10098 10185 is_async_method = true; 10099 10186 js->consumed = 1; 10100 10187 } 10188 + 10189 + if (next(js) == TOK_IDENTIFIER) { 10190 + bool is_get = (js->tlen == 3 && memcmp(&js->code[js->toff], "get", 3) == 0); 10191 + bool is_set = (js->tlen == 3 && memcmp(&js->code[js->toff], "set", 3) == 0); 10192 + if (is_get || is_set) { 10193 + jsoff_t saved_pos = js->pos; 10194 + jsoff_t saved_toff = js->toff; 10195 + jsoff_t saved_tlen = js->tlen; 10196 + uint8_t saved_tok = js->tok; 10197 + js->consumed = 1; 10198 + if (next(js) == TOK_IDENTIFIER) { 10199 + is_getter_method = is_get; 10200 + is_setter_method = is_set; 10201 + } else { 10202 + js->pos = saved_pos; 10203 + js->toff = saved_toff; 10204 + js->tlen = saved_tlen; 10205 + js->tok = saved_tok; 10206 + js->consumed = 0; 10207 + } 10208 + } 10209 + } 10210 + 10101 10211 if (next(js) != TOK_IDENTIFIER && (next(js) < TOK_ASYNC || next(js) > TOK_STATIC)) { 10102 10212 js->flags = save_flags; 10103 10213 return js_mkerr_typed(js, JS_ERR_SYNTAX, "method name expected"); ··· 10191 10301 methods[method_count].is_async = is_async_method; 10192 10302 methods[method_count].is_static = is_static_member; 10193 10303 methods[method_count].is_field = false; 10304 + methods[method_count].is_getter = is_getter_method; 10305 + methods[method_count].is_setter = is_setter_method; 10194 10306 methods[method_count].field_start = 0; 10195 10307 methods[method_count].field_end = 0; 10196 10308 method_count++; ··· 10269 10381 if (is_err(mscope_res)) return mscope_res; 10270 10382 10271 10383 jsval_t method_func = mkval(T_FUNC, (unsigned long) vdata(method_obj)); 10272 - jsval_t set_res = setprop(js, proto, method_name, method_func); 10273 - if (is_err(set_res)) return set_res; 10384 + 10385 + if (methods[i].is_getter || methods[i].is_setter) { 10386 + char desc_key[128]; 10387 + jsoff_t name_len; 10388 + const char *name_str = (const char *)&js->mem[vstr(js, method_name, &name_len)]; 10389 + snprintf(desc_key, sizeof(desc_key), "__desc_%.*s", (int)name_len, name_str); 10390 + 10391 + jsoff_t desc_off = lkp(js, proto, desc_key, strlen(desc_key)); 10392 + jsval_t desc_obj; 10393 + 10394 + if (desc_off != 0) { 10395 + desc_obj = resolveprop(js, mkval(T_PROP, desc_off)); 10396 + } else { 10397 + desc_obj = mkobj(js, 0); 10398 + if (is_err(desc_obj)) return desc_obj; 10399 + setprop(js, desc_obj, js_mkstr(js, "enumerable", 10), js_mkfalse()); 10400 + setprop(js, desc_obj, js_mkstr(js, "configurable", 12), js_mktrue()); 10401 + setprop(js, proto, js_mkstr(js, desc_key, strlen(desc_key)), desc_obj); 10402 + } 10403 + 10404 + if (methods[i].is_getter) { 10405 + setprop(js, desc_obj, js_mkstr(js, "get", 3), method_func); 10406 + } else { 10407 + setprop(js, desc_obj, js_mkstr(js, "set", 3), method_func); 10408 + } 10409 + } else { 10410 + jsval_t set_res = setprop(js, proto, method_name, method_func); 10411 + if (is_err(set_res)) return set_res; 10412 + } 10274 10413 } 10275 10414 10276 10415 jsval_t func_obj = mkobj(js, 0);