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.

destructuring fixes

+418 -16
+1 -1
examples/spec/path.js
··· 1 1 import { test, summary } from './helpers.js'; 2 - import path from 'path'; 2 + import path from 'ant:path'; 3 3 4 4 console.log('Path Tests\n'); 5 5
+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.1.0.37') 77 + version_conf.set('ANT_VERSION', '0.1.0.38') 78 78 version_conf.set('ANT_GIT_HASH', git_hash) 79 79 version_conf.set('ANT_BUILD_DATE', build_date) 80 80
+416 -14
src/ant.c
··· 3806 3806 return skiptonext(fn, fnlen, default_start + default_len, NULL); 3807 3807 } 3808 3808 3809 + static jsoff_t skip_default_expr(const char *p, jsoff_t len, jsoff_t pos) { 3810 + int depth = 0; 3811 + while (pos < len) { 3812 + char c = p[pos]; 3813 + if (c == '(' || c == '[' || c == '{') depth++; 3814 + else if (c == ')' || c == ']' || c == '}') { if (depth == 0) break; depth--; } 3815 + else if (c == ',' && depth == 0) break; 3816 + pos++; 3817 + } 3818 + return pos; 3819 + } 3820 + 3821 + static jsval_t bind_destruct_pattern(struct js *js, const char *p, jsoff_t len, jsval_t val, jsval_t scope) { 3822 + jsoff_t pos = skiptonext(p, len, 0, NULL); 3823 + if (pos >= len) return js_mkundef(); 3824 + 3825 + bool is_arr = (p[pos] == '['); 3826 + if (!is_arr && p[pos] != '{') return js_mkerr(js, "invalid destructuring pattern"); 3827 + 3828 + pos++; 3829 + int idx = 0; 3830 + 3831 + while (pos < len) { 3832 + pos = skiptonext(p, len, pos, NULL); 3833 + if (pos >= len) break; 3834 + if ((is_arr && p[pos] == ']') || (!is_arr && p[pos] == '}')) break; 3835 + if (p[pos] == ',') { pos++; idx++; continue; } 3836 + 3837 + bool is_rest = (pos + 2 < len && p[pos] == '.' && p[pos+1] == '.' && p[pos+2] == '.'); 3838 + if (is_rest) { pos += 3; pos = skiptonext(p, len, pos, NULL); } 3839 + 3840 + jsoff_t name_len = 0; 3841 + if (parseident(&p[pos], len - pos, &name_len) != TOK_IDENTIFIER) break; 3842 + 3843 + jsoff_t var_pos = pos, var_len = name_len; 3844 + jsoff_t src_pos = pos, src_len = name_len; 3845 + pos += name_len; 3846 + pos = skiptonext(p, len, pos, NULL); 3847 + 3848 + if (!is_arr && !is_rest && pos < len && p[pos] == ':') { 3849 + pos = skiptonext(p, len, pos + 1, NULL); 3850 + jsoff_t rlen = 0; 3851 + if (parseident(&p[pos], len - pos, &rlen) == TOK_IDENTIFIER) { 3852 + var_pos = pos; var_len = rlen; 3853 + pos += rlen; 3854 + pos = skiptonext(p, len, pos, NULL); 3855 + } 3856 + } 3857 + 3858 + jsval_t prop_val; 3859 + if (is_rest && is_arr) { 3860 + jsval_t rest = js_mkarr(js); 3861 + if (is_err(rest)) return rest; 3862 + jsoff_t alen = arr_length(js, val); 3863 + for (jsoff_t i = idx; i < alen; i++) js_arr_push(js, rest, arr_get(js, val, i)); 3864 + prop_val = rest; 3865 + } else if (is_rest) { 3866 + prop_val = mkobj(js, 0); 3867 + } else if (is_arr) { 3868 + prop_val = arr_get(js, val, idx); 3869 + } else { 3870 + jsoff_t off = lkp(js, val, &p[src_pos], src_len); 3871 + prop_val = off > 0 ? resolveprop(js, mkval(T_PROP, off)) : js_mkundef(); 3872 + } 3873 + 3874 + if (is_rest) goto bind; 3875 + if (pos >= len || p[pos] != '=') goto bind; 3876 + 3877 + pos++; 3878 + jsoff_t def_start = pos; 3879 + pos = skip_default_expr(p, len, pos); 3880 + if (vtype(prop_val) != T_UNDEF) goto bind; 3881 + 3882 + prop_val = js_eval_str(js, &p[def_start], pos - def_start); 3883 + if (is_err(prop_val)) return prop_val; 3884 + prop_val = resolveprop(js, prop_val); 3885 + 3886 + bind:; 3887 + jsval_t vname = js_mkstr(js, &p[var_pos], var_len); 3888 + if (is_err(vname)) return vname; 3889 + jsval_t r = setprop(js, scope, vname, prop_val); 3890 + if (is_err(r)) return r; 3891 + 3892 + idx++; 3893 + pos = skiptonext(p, len, pos, NULL); 3894 + if (pos < len && p[pos] == ',') pos++; 3895 + } 3896 + 3897 + return js_mkundef(); 3898 + } 3899 + 3809 3900 static jsval_t call_js(struct js *js, const char *fn, jsoff_t fnlen, jsval_t closure_scope) { 3810 3901 jsoff_t fnpos = 1; 3811 3902 jsval_t saved_scope = js->scope; ··· 3869 3960 3870 3961 jsoff_t identlen = 0; 3871 3962 uint8_t tok = parseident(&fn[fnpos], fnlen - fnpos, &identlen); 3963 + 3964 + if (tok != TOK_IDENTIFIER && (fn[fnpos] == '{' || fn[fnpos] == '[')) { 3965 + char bracket_open = fn[fnpos]; 3966 + char bracket_close = (bracket_open == '{') ? '}' : ']'; 3967 + jsoff_t pattern_start = fnpos; 3968 + int depth = 1; 3969 + fnpos++; 3970 + while (fnpos < fnlen && depth > 0) { 3971 + if (fn[fnpos] == bracket_open) depth++; 3972 + else if (fn[fnpos] == bracket_close) depth--; 3973 + fnpos++; 3974 + } 3975 + jsoff_t pattern_len = fnpos - pattern_start; 3976 + 3977 + jsval_t arg_val = (argi < argc) ? args[argi++] : js_mkundef(); 3978 + jsval_t r = bind_destruct_pattern(js, &fn[pattern_start], pattern_len, arg_val, function_scope); 3979 + if (is_err(r)) { 3980 + js->scope = saved_scope; 3981 + if (global_scope_stack && utarray_len(global_scope_stack) > 0) utarray_pop_back(global_scope_stack); 3982 + return r; 3983 + } 3984 + 3985 + fnpos = skiptonext(fn, fnlen, fnpos, NULL); 3986 + if (fnpos < fnlen && fn[fnpos] == ',') fnpos++; 3987 + continue; 3988 + } 3989 + 3872 3990 if (tok != TOK_IDENTIFIER) break; 3873 3991 3874 3992 if (is_rest) { ··· 4022 4140 4023 4141 jsoff_t identlen = 0; 4024 4142 uint8_t tok = parseident(&fn[fnpos], fnlen - fnpos, &identlen); 4143 + 4144 + fnpos = skiptonext(fn, fnlen, fnpos, NULL); 4145 + if (tok != TOK_IDENTIFIER && fnpos < fnlen && (fn[fnpos] == '{' || fn[fnpos] == '[')) { 4146 + char bracket_open = fn[fnpos]; 4147 + char bracket_close = (bracket_open == '{') ? '}' : ']'; 4148 + jsoff_t pattern_start = fnpos; 4149 + int depth = 1; 4150 + fnpos++; 4151 + while (fnpos < fnlen && depth > 0) { 4152 + if (fn[fnpos] == bracket_open) depth++; 4153 + else if (fn[fnpos] == bracket_close) depth--; 4154 + fnpos++; 4155 + } 4156 + jsoff_t pattern_len = fnpos - pattern_start; 4157 + 4158 + jsval_t arg_val = (arg_idx < nargs) ? args[arg_idx] : js_mkundef(); 4159 + jsval_t r = bind_destruct_pattern(js, &fn[pattern_start], pattern_len, arg_val, function_scope); 4160 + if (is_err(r)) return r; 4161 + 4162 + arg_idx++; 4163 + fnpos = skiptonext(fn, fnlen, fnpos, NULL); 4164 + if (fnpos < fnlen && fn[fnpos] == ',') fnpos++; 4165 + continue; 4166 + } 4167 + 4025 4168 if (tok != TOK_IDENTIFIER) break; 4026 4169 4027 4170 if (is_rest) { ··· 6060 6203 JS_SAVE_STATE(js, end_state); 6061 6204 JS_RESTORE_STATE(js, pattern_state); 6062 6205 6206 + jsval_t picked_keys = exe ? js_mkarr(js) : js_mkundef(); 6207 + if (exe && is_err(picked_keys)) return picked_keys; 6208 + 6063 6209 while (next(js) != TOK_RBRACE && next(js) != TOK_EOF) { 6064 - EXPECT(TOK_IDENTIFIER, ); 6210 + bool is_rest = false; 6211 + if (next(js) == TOK_REST) { 6212 + is_rest = true; 6213 + js->consumed = 1; 6214 + } 6215 + 6216 + if (next(js) != TOK_IDENTIFIER) { 6217 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected in object destructuring"); 6218 + } 6065 6219 jsoff_t src_off = js->toff, src_len = js->tlen; 6066 6220 jsoff_t var_off = src_off, var_len = src_len; 6067 6221 js->consumed = 1; 6068 6222 6069 - if (next(js) == TOK_COLON) { 6223 + bool is_nested_obj = false; 6224 + bool is_nested_arr = false; 6225 + jsoff_t nested_pattern_start = 0; 6226 + 6227 + if (!is_rest && next(js) == TOK_COLON) { 6228 + js->consumed = 1; 6229 + if (next(js) == TOK_LBRACE) { 6230 + is_nested_obj = true; 6231 + nested_pattern_start = js->toff; 6232 + int depth = 1; 6233 + js->consumed = 1; 6234 + while (depth > 0 && next(js) != TOK_EOF) { 6235 + if (js->tok == TOK_LBRACE) depth++; 6236 + else if (js->tok == TOK_RBRACE) depth--; 6237 + if (depth > 0) js->consumed = 1; 6238 + } 6239 + js->consumed = 1; 6240 + } else if (next(js) == TOK_LBRACKET) { 6241 + is_nested_arr = true; 6242 + nested_pattern_start = js->toff; 6243 + int depth = 1; 6244 + js->consumed = 1; 6245 + while (depth > 0 && next(js) != TOK_EOF) { 6246 + if (js->tok == TOK_LBRACKET) depth++; 6247 + else if (js->tok == TOK_RBRACKET) depth--; 6248 + if (depth > 0) js->consumed = 1; 6249 + } 6250 + js->consumed = 1; 6251 + } else { 6252 + EXPECT(TOK_IDENTIFIER, ); 6253 + var_off = js->toff; 6254 + var_len = js->tlen; 6255 + js->consumed = 1; 6256 + } 6257 + } 6258 + 6259 + jsoff_t default_off = 0, default_len = 0; 6260 + if (!is_rest && !is_nested_obj && !is_nested_arr && next(js) == TOK_ASSIGN) { 6261 + js->consumed = 1; 6262 + default_off = js->pos; 6263 + uint8_t sf = js->flags; 6264 + js->flags |= F_NOEXEC; 6265 + jsval_t r = js_expr(js); 6266 + js->flags = sf; 6267 + if (is_err(r)) return r; 6268 + default_len = js->pos - default_off; 6269 + } 6270 + 6271 + if (!exe) goto obj_destruct_next; 6272 + 6273 + if (is_rest) goto obj_destruct_rest; 6274 + if (is_nested_obj || is_nested_arr) goto obj_destruct_nested; 6275 + goto obj_destruct_simple; 6276 + 6277 + obj_destruct_rest:; 6278 + jsval_t rest_obj = mkobj(js, 0); 6279 + if (is_err(rest_obj)) return rest_obj; 6280 + jsoff_t scan = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | CONSTMASK); 6281 + while (scan < js->brk && scan != 0) { 6282 + jsoff_t koff = loadoff(js, scan + (jsoff_t) sizeof(scan)); 6283 + jsoff_t klen = offtolen(loadoff(js, koff)); 6284 + const char *key = (char *) &js->mem[koff + sizeof(koff)]; 6285 + bool is_picked = false; 6286 + jsoff_t picked_len = arr_length(js, picked_keys); 6287 + for (jsoff_t i = 0; i < picked_len; i++) { 6288 + jsval_t pk = arr_get(js, picked_keys, i); 6289 + if (vtype(pk) != T_STR) continue; 6290 + jsoff_t pklen, pkoff = vstr(js, pk, &pklen); 6291 + if (klen == pklen && memcmp(key, &js->mem[pkoff], klen) == 0) { is_picked = true; break; } 6292 + } 6293 + if (!is_picked && !(klen == 9 && memcmp(key, "__proto__", 9) == 0)) { 6294 + jsval_t val = loadval(js, scan + (jsoff_t) (sizeof(scan) + sizeof(koff))); 6295 + jsval_t key_str = js_mkstr(js, key, klen); 6296 + if (is_err(key_str)) return key_str; 6297 + jsval_t res = setprop(js, rest_obj, key_str, val); 6298 + if (is_err(res)) return res; 6299 + } 6300 + scan = loadoff(js, scan) & ~(3U | CONSTMASK); 6301 + } 6302 + { 6303 + const char *vn = &js->code[var_off]; 6304 + if (lkp(js, js->scope, vn, var_len) > 0) return js_mkerr(js, "'%.*s' already declared", (int)var_len, vn); 6305 + jsval_t x = mkprop(js, js->scope, js_mkstr(js, vn, var_len), rest_obj, is_const); 6306 + if (is_err(x)) return x; 6307 + } 6308 + goto obj_destruct_next; 6309 + 6310 + obj_destruct_nested:; 6311 + { 6312 + jsval_t sk = js_mkstr(js, &js->code[src_off], src_len); 6313 + if (is_err(sk)) return sk; 6314 + js_arr_push(js, picked_keys, sk); 6315 + 6316 + jsoff_t poff = lkp(js, obj, &js->code[src_off], src_len); 6317 + jsval_t nobj = poff > 0 ? resolveprop(js, mkval(T_PROP, poff)) : js_mkundef(); 6318 + 6319 + jsoff_t pattern_end = js->pos; 6320 + js->pos = nested_pattern_start; 6321 + js->consumed = 1; 6322 + 6323 + jsval_t saved_obj = obj; 6324 + obj = nobj; 6325 + 6326 + if (!is_nested_obj) goto nested_done; 6327 + if (next(js) != TOK_LBRACE) return js_mkerr_typed(js, JS_ERR_SYNTAX, "expected '{' in nested destructuring"); 6328 + js->consumed = 1; 6329 + 6330 + while (next(js) != TOK_RBRACE && next(js) != TOK_EOF) { 6331 + if (next(js) != TOK_IDENTIFIER) return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected in nested destructuring"); 6332 + jsoff_t isoff = js->toff, islen = js->tlen; 6333 + jsoff_t ivoff = isoff, ivlen = islen; 6334 + js->consumed = 1; 6335 + 6336 + if (next(js) == TOK_COLON) { 6337 + js->consumed = 1; 6338 + EXPECT(TOK_IDENTIFIER, ); 6339 + ivoff = js->toff; ivlen = js->tlen; 6340 + js->consumed = 1; 6341 + } 6342 + 6343 + const char *ivn = &js->code[ivoff]; 6344 + if (lkp(js, js->scope, ivn, ivlen) > 0) return js_mkerr(js, "'%.*s' already declared", (int)ivlen, ivn); 6345 + 6346 + jsoff_t ipoff = lkp(js, nobj, &js->code[isoff], islen); 6347 + jsval_t ival = ipoff > 0 ? resolveprop(js, mkval(T_PROP, ipoff)) : js_mkundef(); 6348 + jsval_t ix = mkprop(js, js->scope, js_mkstr(js, ivn, ivlen), ival, is_const); 6349 + if (is_err(ix)) return ix; 6350 + 6351 + if (next(js) == TOK_RBRACE) break; 6352 + EXPECT(TOK_COMMA, ); 6353 + } 6354 + js->consumed = 1; 6355 + 6356 + nested_done: 6357 + obj = saved_obj; 6358 + js->pos = pattern_end; 6359 + js->consumed = 1; 6360 + } 6361 + goto obj_destruct_next; 6362 + 6363 + obj_destruct_simple:; 6364 + { 6365 + const char *vn = &js->code[var_off]; 6366 + if (lkp(js, js->scope, vn, var_len) > 0) return js_mkerr(js, "'%.*s' already declared", (int)var_len, vn); 6367 + 6368 + jsval_t sk = js_mkstr(js, &js->code[src_off], src_len); 6369 + if (is_err(sk)) return sk; 6370 + js_arr_push(js, picked_keys, sk); 6371 + 6372 + jsoff_t poff = lkp(js, obj, &js->code[src_off], src_len); 6373 + jsval_t pval = poff > 0 ? resolveprop(js, mkval(T_PROP, poff)) : js_mkundef(); 6374 + 6375 + if (vtype(pval) == T_UNDEF && default_len > 0) { 6376 + pval = js_eval_slice(js, default_off, default_len); 6377 + if (is_err(pval)) return pval; 6378 + pval = resolveprop(js, pval); 6379 + } 6380 + 6381 + jsval_t x = mkprop(js, js->scope, js_mkstr(js, vn, var_len), pval, is_const); 6382 + if (is_err(x)) return x; 6383 + } 6384 + 6385 + obj_destruct_next: 6386 + 6387 + if (next(js) == TOK_RBRACE) break; 6388 + EXPECT(TOK_COMMA, ); 6389 + } 6390 + 6391 + JS_RESTORE_STATE(js, end_state); 6392 + } else if (next(js) == TOK_LBRACKET) { 6393 + js->consumed = 1; 6394 + 6395 + js_parse_state_t pattern_state; 6396 + JS_SAVE_STATE(js, pattern_state); 6397 + 6398 + int depth = 1; 6399 + while (depth > 0 && next(js) != TOK_EOF) { 6400 + if (js->tok == TOK_LBRACKET) depth++; 6401 + else if (js->tok == TOK_RBRACKET) depth--; 6402 + if (depth > 0) js->consumed = 1; 6403 + } 6404 + js->consumed = 1; 6405 + 6406 + if (next(js) != TOK_ASSIGN) { 6407 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "array destructuring requires assignment"); 6408 + } 6409 + js->consumed = 1; 6410 + 6411 + jsval_t v = js_expr(js); 6412 + if (is_err(v)) return v; 6413 + 6414 + jsval_t arr = js_mkundef(); 6415 + if (exe) { 6416 + arr = resolveprop(js, v); 6417 + if (vtype(arr) != T_ARR) { 6418 + return js_mkerr(js, "cannot array destructure non-array"); 6419 + } 6420 + } 6421 + 6422 + js_parse_state_t end_state; 6423 + JS_SAVE_STATE(js, end_state); 6424 + JS_RESTORE_STATE(js, pattern_state); 6425 + 6426 + int index = 0; 6427 + while (next(js) != TOK_RBRACKET && next(js) != TOK_EOF) { 6428 + if (next(js) == TOK_COMMA) { 6070 6429 js->consumed = 1; 6071 - EXPECT(TOK_IDENTIFIER, ); 6072 - var_off = js->toff; 6073 - var_len = js->tlen; 6430 + index++; 6431 + continue; 6432 + } 6433 + 6434 + bool is_rest = false; 6435 + if (next(js) == TOK_REST) { 6436 + is_rest = true; 6074 6437 js->consumed = 1; 6075 6438 } 6076 6439 6440 + if (next(js) != TOK_IDENTIFIER) { 6441 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected in array destructuring"); 6442 + } 6443 + jsoff_t var_off = js->toff, var_len = js->tlen; 6444 + js->consumed = 1; 6445 + 6077 6446 jsoff_t default_off = 0, default_len = 0; 6078 - if (next(js) == TOK_ASSIGN) { 6447 + if (!is_rest && next(js) == TOK_ASSIGN) { 6079 6448 js->consumed = 1; 6080 6449 default_off = js->pos; 6081 6450 uint8_t sf = js->flags; ··· 6092 6461 return js_mkerr(js, "'%.*s' already declared", (int)var_len, var_name); 6093 6462 } 6094 6463 6095 - jsoff_t prop_off = lkp(js, obj, &js->code[src_off], src_len); 6096 - jsval_t prop_val = prop_off > 0 ? resolveprop(js, mkval(T_PROP, prop_off)) : js_mkundef(); 6097 - 6098 - if (vtype(prop_val) == T_UNDEF && default_len > 0) { 6099 - prop_val = js_eval_slice(js, default_off, default_len); 6100 - if (is_err(prop_val)) return prop_val; 6101 - prop_val = resolveprop(js, prop_val); 6464 + jsval_t prop_val; 6465 + if (is_rest) { 6466 + jsval_t rest_arr = js_mkarr(js); 6467 + if (is_err(rest_arr)) return rest_arr; 6468 + jsoff_t total_len = arr_length(js, arr); 6469 + for (jsoff_t i = index; i < total_len; i++) { 6470 + jsval_t elem = arr_get(js, arr, i); 6471 + js_arr_push(js, rest_arr, elem); 6472 + } 6473 + prop_val = rest_arr; 6474 + } else { 6475 + prop_val = arr_get(js, arr, index); 6476 + 6477 + if (vtype(prop_val) == T_UNDEF && default_len > 0) { 6478 + prop_val = js_eval_slice(js, default_off, default_len); 6479 + if (is_err(prop_val)) return prop_val; 6480 + prop_val = resolveprop(js, prop_val); 6481 + } 6102 6482 } 6103 6483 6104 6484 jsval_t x = mkprop(js, js->scope, js_mkstr(js, var_name, var_len), prop_val, is_const); 6105 6485 if (is_err(x)) return x; 6106 6486 } 6107 6487 6108 - if (next(js) == TOK_RBRACE) break; 6488 + index++; 6489 + if (next(js) == TOK_RBRACKET) break; 6109 6490 EXPECT(TOK_COMMA, ); 6110 6491 } 6111 6492 ··· 6207 6588 is_rest = true; 6208 6589 js->consumed = 1; 6209 6590 next(js); 6591 + } 6592 + 6593 + if (next(js) == TOK_LBRACE || next(js) == TOK_LBRACKET) { 6594 + uint8_t open_tok = js->tok; 6595 + uint8_t close_tok = (open_tok == TOK_LBRACE) ? TOK_RBRACE : TOK_RBRACKET; 6596 + int depth = 1; 6597 + js->consumed = 1; 6598 + while (depth > 0 && next(js) != TOK_EOF) { 6599 + if (js->tok == open_tok) depth++; 6600 + else if (js->tok == close_tok) depth--; 6601 + if (depth > 0) js->consumed = 1; 6602 + } 6603 + js->consumed = 1; 6604 + param_count++; 6605 + 6606 + if (is_rest && next(js) != TOK_RPAREN) { 6607 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "rest parameter must be last"); 6608 + } 6609 + if (next(js) == TOK_RPAREN) break; 6610 + EXPECT(TOK_COMMA, ); 6611 + continue; 6210 6612 } 6211 6613 6212 6614 if (next(js) != TOK_IDENTIFIER) return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected");