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.

move iteration to new opcodes

+131 -42
+12
examples/spec/destructuring.js
··· 19 19 test('array rest head', head, 1); 20 20 testDeep('array rest tail', tail, [2, 3, 4]); 21 21 22 + const [astral] = '𠮷𠮶'; 23 + test('array destructure astral string', astral, '𠮷'); 24 + 25 + let astralAssign; 26 + [astralAssign] = '𠮷𠮶'; 27 + test('array destructure assign astral string', astralAssign, '𠮷'); 28 + 22 29 const { name, age } = { name: 'Alice', age: 30 }; 23 30 test('object destructure name', name, 'Alice'); 24 31 test('object destructure age', age, 30); ··· 47 54 return x * y; 48 55 } 49 56 test('array param destructure', arrayParam([3, 4]), 12); 57 + 58 + function arrayAstralParam([ch]) { 59 + return ch; 60 + } 61 + test('array param destructure astral string', arrayAstralParam('𠮷𠮶'), '𠮷'); 50 62 51 63 const swap = ([a, b]) => [b, a]; 52 64 testDeep('swap via destructure', swap([1, 2]), [2, 1]);
+4
include/silver/opcode.h
··· 187 187 OP_DEF( ITER_CLOSE, 1, 3, 0, none) /* close iterator */ 188 188 OP_DEF( ITER_CALL, 2, 4, 5, u8) /* call iterator method */ 189 189 OP_DEF( AWAIT_ITER_NEXT, 1, 3, 4, none) /* async iterator next */ 190 + OP_DEF( DESTRUCTURE_INIT, 1, 1, 3, none) /* iterable -> iter next tag */ 191 + OP_DEF( DESTRUCTURE_NEXT, 1, 3, 4, none) /* iter next tag -> iter next tag value|undef */ 192 + OP_DEF( DESTRUCTURE_REST, 1, 3, 4, none) /* iter next tag -> iter next tag array */ 193 + OP_DEF( DESTRUCTURE_CLOSE, 1, 3, 0, none) /* close destructuring iterator */ 190 194 191 195 OP_DEF( AWAIT, 1, 1, 1, none) /* promise -> resolved value */ 192 196 OP_DEF( YIELD, 1, 1, 2, none) /* val -> received */
+42 -19
src/silver/compiler.c
··· 2460 2460 compile_lhs_set(c, target, false); 2461 2461 } 2462 2462 2463 - static void compile_destructure_pattern(sv_compiler_t *c, sv_ast_t *pat, 2464 - bool keep, bool consume_source, 2465 - sv_destructure_mode_t mode, 2466 - sv_var_kind_t kind) { 2463 + static void compile_destructure_pattern( 2464 + sv_compiler_t *c, sv_ast_t *pat, 2465 + bool keep, bool consume_source, 2466 + sv_destructure_mode_t mode, 2467 + sv_var_kind_t kind 2468 + ) { 2467 2469 if (!pat) return; 2468 2470 if (keep) emit_op(c, OP_DUP); 2469 2471 2470 2472 if (pat->type == N_ARRAY_PAT || pat->type == N_ARRAY) { 2473 + if (!consume_source && !keep) emit_op(c, OP_DUP); 2474 + emit_op(c, OP_DESTRUCTURE_INIT); 2475 + 2476 + int err_local = add_local(c, "", 0, false, c->scope_depth); 2477 + int try_jump = emit_jump(c, OP_TRY_PUSH); 2478 + c->try_depth++; 2479 + 2471 2480 for (int i = 0; i < pat->args.count; i++) { 2472 2481 sv_ast_t *elem = pat->args.items[i]; 2473 - if (!elem || elem->type == N_EMPTY) continue; 2474 - 2482 + if (!elem || elem->type == N_EMPTY) { 2483 + emit_op(c, OP_DESTRUCTURE_NEXT); 2484 + emit_op(c, OP_POP); 2485 + continue; 2486 + } 2487 + 2475 2488 if (elem->type == N_REST || elem->type == N_SPREAD) { 2476 - emit_op(c, OP_DUP); 2477 - emit_op(c, OP_DUP); 2478 - emit_atom_op(c, OP_GET_FIELD, "slice", 5); 2479 - emit_number(c, (double)i); 2480 - emit_op(c, OP_CALL_METHOD); 2481 - emit_u16(c, 1); 2489 + emit_op(c, OP_DESTRUCTURE_REST); 2482 2490 compile_destructure_store(c, elem->right, mode, kind); 2483 2491 continue; 2484 2492 } 2485 - 2493 + 2486 2494 sv_ast_t *target = elem; 2487 2495 sv_ast_t *default_val = NULL; 2488 2496 if (elem->type == N_ASSIGN_PAT || ··· 2490 2498 target = elem->left; 2491 2499 default_val = elem->right; 2492 2500 } 2493 - 2494 - emit_op(c, OP_DUP); 2495 - emit_number(c, (double)i); 2496 - emit_op(c, OP_GET_ELEM); 2497 - 2501 + 2502 + emit_op(c, OP_DESTRUCTURE_NEXT); 2503 + 2498 2504 if (default_val) { 2499 2505 emit_op(c, OP_DUP); 2500 2506 emit_op(c, OP_IS_UNDEF); ··· 2503 2509 compile_expr(c, default_val); 2504 2510 patch_jump(c, skip); 2505 2511 } 2506 - 2512 + 2507 2513 compile_destructure_store(c, target, mode, kind); 2508 2514 } 2515 + 2516 + emit_op(c, OP_TRY_POP); 2517 + emit_op(c, OP_DESTRUCTURE_CLOSE); 2518 + int end_jump = emit_jump(c, OP_JMP); 2519 + 2520 + patch_jump(c, try_jump); 2521 + int catch_tag = emit_jump(c, OP_CATCH); 2522 + 2523 + emit_put_local(c, err_local); 2524 + emit_op(c, OP_DESTRUCTURE_CLOSE); 2525 + emit_get_local(c, err_local); 2526 + emit_op(c, OP_THROW); 2527 + patch_jump(c, catch_tag); 2528 + patch_jump(c, end_jump); 2529 + c->try_depth--; 2530 + 2531 + return; 2509 2532 } else if (pat->type == N_OBJECT_PAT || pat->type == N_OBJECT) { 2510 2533 for (int i = 0; i < pat->args.count; i++) { 2511 2534 sv_ast_t *prop = pat->args.items[i];
+4
src/silver/engine.c
··· 1200 1200 L_ITER_CLOSE: { sv_op_iter_close(vm, js); NEXT(1); } 1201 1201 L_ITER_CALL: { VM_CHECK(sv_op_iter_call(vm, js, ip)); NEXT(2); } 1202 1202 L_AWAIT_ITER_NEXT: { VM_CHECK(sv_op_await_iter_next(vm, js)); NEXT(1); } 1203 + L_DESTRUCTURE_INIT: { VM_CHECK(sv_op_destructure_init(vm, js)); NEXT(1); } 1204 + L_DESTRUCTURE_NEXT: { VM_CHECK(sv_op_destructure_next(vm, js)); NEXT(1); } 1205 + L_DESTRUCTURE_REST: { VM_CHECK(sv_op_destructure_rest(vm, js)); NEXT(1); } 1206 + L_DESTRUCTURE_CLOSE:{ sv_op_destructure_close(vm, js); NEXT(1); } 1203 1207 1204 1208 L_AWAIT: { 1205 1209 ant_value_t await_val = vm->stack[--vm->sp];
+69 -23
src/silver/ops/iteration.h
··· 134 134 return tov(0); 135 135 } 136 136 137 - static inline ant_value_t sv_op_iter_next(sv_vm_t *vm, ant_t *js, uint8_t *ip) { 138 - int hint = (int)sv_get_u8(ip + 1); 137 + static inline ant_value_t sv_iter_advance( 138 + sv_vm_t *vm, ant_t *js, int hint, ant_value_t *out_value, bool *out_done 139 + ) { 139 140 int tag = hint ? hint : (int)js_getnum(vm->stack[vm->sp - 1]); 140 141 switch (tag) { 141 142 case SV_ITER_ARRAY: { ··· 143 144 int idx = (int)js_getnum(vm->stack[vm->sp - 2]); 144 145 ant_offset_t len = js_arr_len(js, arr); 145 146 if (idx >= (int)len) { 146 - vm->stack[vm->sp++] = js_mkundef(); 147 - vm->stack[vm->sp++] = js_true; 147 + *out_value = js_mkundef(); 148 + *out_done = true; 148 149 } else { 149 - vm->stack[vm->sp++] = js_arr_get(js, arr, (ant_offset_t)idx); 150 - vm->stack[vm->sp++] = js_false; 151 - vm->stack[vm->sp - 4] = tov(idx + 1); 150 + *out_value = js_arr_get(js, arr, (ant_offset_t)idx); 151 + *out_done = false; 152 + vm->stack[vm->sp - 2] = tov(idx + 1); 152 153 } 153 154 return tov(0); 154 155 } ··· 157 158 map_iterator_state_t *st = 158 159 (map_iterator_state_t *)(uintptr_t)js_getnum(vm->stack[vm->sp - 3]); 159 160 if (!st->current) { 160 - vm->stack[vm->sp++] = js_mkundef(); 161 - vm->stack[vm->sp++] = js_true; 161 + *out_value = js_mkundef(); 162 + *out_done = true; 162 163 } else { 163 164 map_entry_t *entry = st->current; 164 165 ant_value_t value; ··· 180 181 value = js_mkundef(); 181 182 } 182 183 st->current = entry->hh.next; 183 - vm->stack[vm->sp++] = value; 184 - vm->stack[vm->sp++] = js_false; 184 + *out_value = value; 185 + *out_done = false; 185 186 } 186 187 return tov(0); 187 188 } ··· 190 191 set_iterator_state_t *st = 191 192 (set_iterator_state_t *)(uintptr_t)js_getnum(vm->stack[vm->sp - 3]); 192 193 if (!st->current) { 193 - vm->stack[vm->sp++] = js_mkundef(); 194 - vm->stack[vm->sp++] = js_true; 194 + *out_value = js_mkundef(); 195 + *out_done = true; 195 196 } else { 196 197 set_entry_t *entry = st->current; 197 198 ant_value_t value; ··· 204 205 value = entry->value; 205 206 } 206 207 st->current = entry->hh.next; 207 - vm->stack[vm->sp++] = value; 208 - vm->stack[vm->sp++] = js_false; 208 + *out_value = value; 209 + *out_done = false; 209 210 } 210 211 return tov(0); 211 212 } ··· 215 216 int idx = (int)js_getnum(vm->stack[vm->sp - 2]); 216 217 ant_offset_t slen = str_len_fast(js, str); 217 218 if (idx >= (int)slen) { 218 - vm->stack[vm->sp++] = js_mkundef(); 219 - vm->stack[vm->sp++] = js_true; 219 + *out_value = js_mkundef(); 220 + *out_done = true; 220 221 } else { 221 222 ant_offset_t off = vstr(js, str, NULL); 222 223 utf8proc_int32_t cp; ··· 225 226 (utf8proc_ssize_t)(slen - idx), 226 227 &cp 227 228 ); 228 - vm->stack[vm->sp++] = js_mkstr(js, (const void *)(uintptr_t)(off + idx), cb_len); 229 - vm->stack[vm->sp++] = js_false; 230 - vm->stack[vm->sp - 4] = tov(idx + (int)cb_len); 229 + *out_value = js_mkstr(js, (const void *)(uintptr_t)(off + idx), cb_len); 230 + *out_done = false; 231 + vm->stack[vm->sp - 2] = tov(idx + (int)cb_len); 231 232 } 232 233 return tov(0); 233 234 } ··· 243 244 if (!is_object_type(result)) 244 245 return js_mkerr_typed(js, JS_ERR_TYPE, "Iterator result is not an object"); 245 246 ant_value_t done = js_getprop_fallback(js, result, "done"); 246 - ant_value_t value = js_getprop_fallback(js, result, "value"); 247 - vm->stack[vm->sp++] = value; 248 - vm->stack[vm->sp++] = mkval(T_BOOL, js_truthy(js, done)); 247 + *out_value = js_getprop_fallback(js, result, "value"); 248 + *out_done = js_truthy(js, done); 249 249 return tov(0); 250 250 }} 251 251 } 252 252 253 + static inline ant_value_t sv_op_iter_next(sv_vm_t *vm, ant_t *js, uint8_t *ip) { 254 + int hint = (int)sv_get_u8(ip + 1); 255 + ant_value_t value; 256 + bool done = false; 257 + 258 + ant_value_t status = sv_iter_advance(vm, js, hint, &value, &done); 259 + if (is_err(status)) return status; 260 + vm->stack[vm->sp++] = value; 261 + vm->stack[vm->sp++] = done ? js_true : js_false; 262 + 263 + return tov(0); 264 + } 265 + 253 266 static inline void sv_op_iter_get_value(sv_vm_t *vm, ant_t *js) { 254 267 ant_value_t obj = vm->stack[--vm->sp]; 255 268 ant_value_t done = js_getprop_fallback(js, obj, "done"); ··· 268 281 sv_vm_call(vm, js, return_fn, iterator, NULL, 0, NULL, false); 269 282 } 270 283 vm->sp -= 3; 284 + } 285 + 286 + static inline ant_value_t sv_op_destructure_init(sv_vm_t *vm, ant_t *js) { 287 + return sv_op_for_of(vm, js); 288 + } 289 + 290 + static inline void sv_op_destructure_close(sv_vm_t *vm, ant_t *js) { 291 + sv_op_iter_close(vm, js); 292 + } 293 + 294 + static inline ant_value_t sv_op_destructure_next(sv_vm_t *vm, ant_t *js) { 295 + ant_value_t value; 296 + bool done = false; 297 + 298 + ant_value_t status = sv_iter_advance(vm, js, 0, &value, &done); 299 + if (is_err(status)) return status; 300 + vm->stack[vm->sp++] = done ? js_mkundef() : value; 301 + 302 + return tov(0); 303 + } 304 + 305 + static inline ant_value_t sv_op_destructure_rest(sv_vm_t *vm, ant_t *js) { 306 + ant_value_t rest = js_mkarr(js); 307 + for (;;) { 308 + ant_value_t value; 309 + bool done = false; 310 + ant_value_t status = sv_iter_advance(vm, js, 0, &value, &done); 311 + if (is_err(status)) return status; 312 + if (done) break; 313 + js_arr_push(js, rest, value); 314 + } 315 + vm->stack[vm->sp++] = rest; 316 + return tov(0); 271 317 } 272 318 273 319 static inline ant_value_t sv_op_iter_call(sv_vm_t *vm, ant_t *js, uint8_t *ip) {