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 lexical `new.target`

+122 -10
+1
include/common.h
··· 14 14 SLOT_WITH, 15 15 SLOT_SCOPE, 16 16 SLOT_THIS, 17 + SLOT_NEW_TARGET, 17 18 SLOT_BOUND_THIS, 18 19 SLOT_BOUND_ARGS, 19 20 SLOT_FIELD_COUNT,
+1 -1
include/internal.h
··· 110 110 enum { 111 111 T_OBJ, T_PROP, T_STR, T_UNDEF, T_NULL, T_NUM, T_BOOL, T_FUNC, 112 112 T_CODEREF, T_CFUNC, T_ERR, T_ARR, T_PROMISE, T_TYPEDARRAY, 113 - T_BIGINT, T_PROPREF, T_SYMBOL, T_GENERATOR, T_FFI 113 + T_BIGINT, T_PROPREF, T_SYMBOL, T_GENERATOR, T_FFI, T_NTARG 114 114 }; 115 115 116 116 #define JS_HASH_SIZE 512
+101 -2
src/ant.c
··· 364 364 const char *names[] = { 365 365 "object", "prop", "string", "undefined", "null", "number", 366 366 "boolean", "function", "coderef", "cfunc", "err", "array", 367 - "promise", "typedarray", "bigint", "propref", "symbol", "generator", "ffi" 367 + "promise", "typedarray", "bigint", "propref", "symbol", "generator", "ffi", "ntarg" 368 368 }; 369 369 370 370 return (t < sizeof(names) / sizeof(names[0])) ? names[t] : "??"; ··· 510 510 511 511 static jsval_t mkcoderef(jsval_t off, jsoff_t len) { 512 512 return mkval(T_CODEREF, (off & PROPREF_OFF_MASK) | ((jsval_t)(len & PROPREF_OFF_MASK) << PROPREF_KEY_SHIFT)); 513 + } 514 + 515 + typedef enum { 516 + NTARG_INVALID = 0, 517 + NTARG_NEW_TARGET = 1 518 + } ntarg_kind_t; 519 + 520 + static inline jsval_t mkntarg(ntarg_kind_t tag) { 521 + return mkval(T_NTARG, (uint64_t)tag); 522 + } 523 + 524 + static inline bool is_new_target_ref(jsval_t v) { 525 + return vtype(v) == T_NTARG && vdata(v) == (uint64_t)NTARG_NEW_TARGET; 513 526 } 514 527 515 528 static jsval_t mkpropref(jsoff_t obj_off, jsoff_t key_off) { ··· 4925 4938 } 4926 4939 4927 4940 return next_raw(js); 4941 + } 4942 + 4943 + static jsval_t validate_dynamic_function_source(struct js *js, const char *params_body, size_t params_body_len, bool is_async) { 4944 + #define DYN_FN_PREFIX_SYNC "(function" 4945 + #define DYN_FN_PREFIX_ASYNC "(async function" 4946 + 4947 + const char *prefix = is_async 4948 + ? DYN_FN_PREFIX_ASYNC 4949 + : DYN_FN_PREFIX_SYNC; 4950 + 4951 + size_t prefix_len = strlen(prefix); 4952 + size_t wrapped_len = prefix_len + params_body_len + 2; 4953 + 4954 + char *wrapped = (char *) malloc(wrapped_len + 1); 4955 + if (!wrapped) return js_mkerr(js, "oom"); 4956 + 4957 + memcpy(wrapped, prefix, prefix_len); 4958 + memcpy(wrapped + prefix_len, params_body, params_body_len); 4959 + wrapped[prefix_len + params_body_len] = ')'; 4960 + 4961 + wrapped[prefix_len + params_body_len + 1] = ';'; 4962 + wrapped[wrapped_len] = '\0'; 4963 + 4964 + js_parse_state_t saved; 4965 + JS_SAVE_STATE(js, saved); 4966 + bool saved_had_newline = js->had_newline; 4967 + uint8_t saved_flags = js->flags; 4968 + 4969 + js->flags = saved_flags | F_NOEXEC; 4970 + jsval_t parsed = js_eval(js, wrapped, wrapped_len); 4971 + 4972 + JS_RESTORE_STATE(js, saved); 4973 + js->had_newline = saved_had_newline; 4974 + js->flags = saved_flags; 4975 + 4976 + free(wrapped); 4977 + return parsed; 4928 4978 } 4929 4979 4930 4980 static inline uint8_t lookahead(struct js *js) { ··· 5786 5836 return js_mkundef(); 5787 5837 } 5788 5838 5839 + static inline jsval_t current_lexical_new_target(struct js *js) { 5840 + if (vtype(js->current_func) != T_FUNC) return js->new_target; 5841 + 5842 + jsval_t func_obj = mkval(T_OBJ, vdata(js->current_func)); 5843 + if (get_slot(js, func_obj, SLOT_ARROW) != js_true) return js->new_target; 5844 + 5845 + jsval_t captured = get_slot(js, func_obj, SLOT_NEW_TARGET); 5846 + if (captured == T_EMPTY) return js_mkundef(); 5847 + if (vtype(captured) == T_UNDEF) return js_mkundef(); 5848 + 5849 + return captured; 5850 + } 5851 + 5852 + static inline void capture_arrow_new_target(struct js *js, jsval_t func_obj) { 5853 + jsval_t captured = current_lexical_new_target(js); 5854 + if (vtype(captured) == T_UNDEF) captured = T_EMPTY; 5855 + set_slot(js, func_obj, SLOT_NEW_TARGET, captured); 5856 + } 5857 + 5789 5858 static inline jsval_t resolve_object_prop(struct js *js, jsval_t obj, const char *key_str, jsoff_t len) { 5790 5859 if (is_proxy(js, obj)) return proxy_get(js, obj, key_str, len); 5791 5860 ··· 5813 5882 } 5814 5883 5815 5884 jsval_t resolveprop(struct js *js, jsval_t v) { 5885 + if (is_new_target_ref(v)) return current_lexical_new_target(js); 5886 + 5816 5887 if (vtype(v) == T_PROPREF) { 5817 5888 if (is_prim_propref(v)) return resolve_prim_propref(js, v); 5818 5889 ··· 9352 9423 if (is_err(closure_scope)) return closure_scope; 9353 9424 set_slot(js, func_obj, SLOT_SCOPE, closure_scope); 9354 9425 set_slot(js, func_obj, SLOT_THIS, js->this_val); 9426 + capture_arrow_new_target(js, func_obj); 9355 9427 } 9356 9428 return mkval(T_FUNC, (unsigned long) vdata(func_obj)); 9357 9429 } ··· 9495 9567 if (is_err(closure_scope)) return closure_scope; 9496 9568 set_slot(js, func_obj, SLOT_SCOPE, closure_scope); 9497 9569 set_slot(js, func_obj, SLOT_THIS, js->this_val); 9570 + capture_arrow_new_target(js, func_obj); 9498 9571 } 9499 9572 9500 9573 set_slot(js, func_obj, SLOT_ARROW, js_true); ··· 9857 9930 9858 9931 do_new: { 9859 9932 js->consumed = 1; 9933 + if (next(js) == TOK_DOT) { 9934 + js->consumed = 1; 9935 + if (next(js) != TOK_IDENTIFIER || !streq(&js->code[js->toff], js->tlen, "target", 6)) { 9936 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected"); 9937 + } 9938 + js->consumed = 1; 9939 + return mkntarg(NTARG_NEW_TARGET); 9940 + } 9941 + 9860 9942 jsval_t obj = mkobj(js, 0); 9861 9943 jsval_t saved_this = js->this_val; 9862 9944 jsval_t saved_new_target = js->new_target; ··· 9888 9970 ctor = resolve_coderef(js, ctor); 9889 9971 if (is_err(ctor)) { return ctor; } 9890 9972 if (vtype(ctor) == T_PROP || vtype(ctor) == T_PROPREF) ctor = resolveprop(js, ctor); 9891 - 9973 + if (vtype(obj) == T_OBJ && (vtype(ctor) == T_FUNC || vtype(ctor) == T_CFUNC)) set_slot(js, obj, SLOT_CTOR, ctor); 9892 9974 js->new_target = ctor; 9893 9975 9894 9976 jsval_t result; ··· 10313 10395 10314 10396 static jsval_t js_assignment(struct js *js) { 10315 10397 jsval_t res = js_ternary(js); 10398 + bool lhs_is_new_target = is_new_target_ref(res); 10316 10399 10317 10400 if (!is_err(res) && vtype(res) == T_CODEREF && next(js) == TOK_ARROW) { 10318 10401 jsoff_t param_start = coderefoff(res); ··· 10387 10470 if (is_err(closure_scope)) return closure_scope; 10388 10471 set_slot(js, func_obj, SLOT_SCOPE, closure_scope); 10389 10472 set_slot(js, func_obj, SLOT_THIS, js->this_val); 10473 + capture_arrow_new_target(js, func_obj); 10390 10474 } 10391 10475 10392 10476 set_slot(js, func_obj, SLOT_ARROW, js_true); ··· 10403 10487 js->tok == TOK_LOR_ASSIGN || js->tok == TOK_LAND_ASSIGN || 10404 10488 js->tok == TOK_NULLISH_ASSIGN) 10405 10489 ) { 10490 + if (lhs_is_new_target) { 10491 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid left-hand side in assignment"); 10492 + } 10406 10493 uint8_t op = js->tok; 10407 10494 js->consumed = 1; 10408 10495 ··· 13851 13938 params_done:; 13852 13939 } 13853 13940 13941 + jsval_t validate_res = validate_dynamic_function_source(js, code_buf, pos, false); 13942 + if (is_err(validate_res)) { 13943 + free(code_buf); 13944 + return validate_res; 13945 + } 13946 + 13854 13947 jsval_t func_obj = mkobj(js, 0); 13855 13948 if (is_err(func_obj)) { free(code_buf); return func_obj; } 13856 13949 ··· 13928 14021 pos += body_len; 13929 14022 code_buf[pos++] = '}'; 13930 14023 code_buf[pos] = '\0'; 14024 + 14025 + jsval_t validate_res = validate_dynamic_function_source(js, code_buf, pos, true); 14026 + if (is_err(validate_res)) { 14027 + free(code_buf); 14028 + return validate_res; 14029 + } 13931 14030 13932 14031 jsval_t func_obj = mkobj(js, 0); 13933 14032 if (is_err(func_obj)) { free(code_buf); return func_obj; }
+2 -1
src/core/ant.ts
··· 26 26 T_PROPREF: 'propref', 27 27 T_SYMBOL: 'symbol', 28 28 T_GENERATOR: 'generator', 29 - T_FFI: 'ffi' 29 + T_FFI: 'ffi', 30 + T_NTARG: 'ntarg' 30 31 } as const; 31 32 32 33 const names = Object.values(types);
+1
src/modules/io.c
··· 411 411 [SLOT_WITH] = "WITH", 412 412 [SLOT_SCOPE] = "SCOPE", 413 413 [SLOT_THIS] = "THIS", 414 + [SLOT_NEW_TARGET] = "NEW_TARGET", 414 415 [SLOT_BOUND_THIS] = "BOUND_THIS", 415 416 [SLOT_BOUND_ARGS] = "BOUND_ARGS", 416 417 [SLOT_FIELD_COUNT] = "FIELD_COUNT",
+14 -5
src/modules/reflect.c
··· 113 113 114 114 jsval_t target = args[0]; 115 115 jsval_t args_arr = args[1]; 116 + jsval_t new_target = (nargs >= 3) ? args[2] : target; 116 117 117 - if (vtype(target) != T_FUNC) { 118 + if (vtype(target) != T_FUNC && vtype(target) != T_CFUNC) { 118 119 return js_mkerr(js, "Reflect.construct: first argument must be a constructor"); 120 + } 121 + 122 + if (vtype(new_target) != T_FUNC && vtype(new_target) != T_CFUNC) { 123 + return js_mkerr(js, "Reflect.construct: third argument must be a constructor"); 119 124 } 120 125 121 126 jsval_t length_val = js_get(js, args_arr, "length"); ··· 137 142 } 138 143 139 144 jsval_t new_obj = js_mkobj(js); 140 - jsval_t result = js_call_with_this(js, target, new_obj, call_args, arg_count); 145 + jsval_t proto = js_get(js, new_target, "prototype"); 146 + if (vtype(proto) == T_OBJ) js_set_proto(js, new_obj, proto); 147 + 148 + jsval_t saved_new_target = js->new_target; 149 + js->new_target = new_target; 141 150 151 + jsval_t result = js_call_with_this(js, target, new_obj, call_args, arg_count); 152 + js->new_target = saved_new_target; 142 153 if (call_args) free(call_args); 143 154 144 155 int result_type = vtype(result); 145 - if (result_type == T_FUNC || is_special_object(result)) { 146 - return result; 147 - } 156 + if (result_type == T_FUNC || is_special_object(result)) return result; 148 157 return new_obj; 149 158 } 150 159
+2 -1
src/types/ant.d.ts
··· 17 17 | 'propref' 18 18 | 'symbol' 19 19 | 'generator' 20 - | 'ffi'; 20 + | 'ffi' 21 + | 'ntarg'; 21 22 22 23 type AntHost = 23 24 | 'cygwin'