MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1#include "silver/ast.h"
2#include "silver/compile_ctx.h"
3#include "silver/engine.h"
4#include "silver/compiler.h"
5#include "silver/directives.h"
6
7#include "internal.h"
8#include "debug.h"
9#include "tokens.h"
10#include "runtime.h"
11#include "utils.h"
12#include "ops/coercion.h"
13
14#include <stdlib.h>
15#include <string.h>
16#include <stdio.h>
17
18enum {
19 SV_ITER_HINT_GENERIC = 0,
20 SV_ITER_HINT_ARRAY = 1,
21 SV_ITER_HINT_STRING = 4,
22};
23
24static const char *pin_source_text(const char *source, ant_offset_t source_len) {
25 if (!source || source_len <= 0) return source;
26 const char *pinned = code_arena_alloc(source, (size_t)source_len);
27 return pinned ? pinned : source;
28}
29
30static void emit(sv_compiler_t *c, uint8_t byte) {
31 if (c->code_len >= c->code_cap) {
32 c->code_cap = c->code_cap ? c->code_cap * 2 : 256;
33 c->code = realloc(c->code, (size_t)c->code_cap);
34 }
35 c->code[c->code_len++] = byte;
36}
37
38static void emit_u16(sv_compiler_t *c, uint16_t val) {
39 emit(c, (uint8_t)(val & 0xFF));
40 emit(c, (uint8_t)(val >> 8));
41}
42
43static void emit_u32(sv_compiler_t *c, uint32_t val) {
44 emit(c, (uint8_t)(val & 0xFF));
45 emit(c, (uint8_t)((val >> 8) & 0xFF));
46 emit(c, (uint8_t)((val >> 16) & 0xFF));
47 emit(c, (uint8_t)((val >> 24) & 0xFF));
48}
49
50static void emit_i32(sv_compiler_t *c, int32_t val) {
51 uint32_t u;
52 memcpy(&u, &val, 4);
53 emit_u32(c, u);
54}
55
56static void emit_op(sv_compiler_t *c, sv_op_t op) {
57 emit(c, (uint8_t)op);
58}
59
60static void compile_receiver_property_get(sv_compiler_t *c, sv_ast_t *node);
61static void compile_truthy_test_expr(sv_compiler_t *c, sv_ast_t *node);
62
63static void emit_srcpos(sv_compiler_t *c, sv_ast_t *node) {
64 if (!node) return;
65 const char *code = c->source;
66 ant_offset_t clen = c->source_len;
67 if (!code || clen <= 0) return;
68
69 uint32_t off = node->src_off;
70 if (off > clen) off = (uint32_t)clen;
71 uint32_t end = node->src_end;
72 if (end > clen) end = (uint32_t)clen;
73 if (end < off) end = off;
74 if (end == off && off < (uint32_t)clen) end = off + 1;
75 if (end == off) return;
76
77 if (c->srcpos_count > 0 && c->last_srcpos_off == off && c->last_srcpos_end == end) return;
78
79 uint32_t line, col;
80 if (c->line_table) sv_compile_ctx_line_table_lookup(c->line_table, off, &line, &col);
81 else if (c->srcpos_count > 0 && off >= c->last_srcpos_off) {
82 line = c->srcpos[c->srcpos_count - 1].line;
83 col = c->srcpos[c->srcpos_count - 1].col;
84 for (uint32_t i = c->last_srcpos_off; i < off; i++) {
85 if (code[i] == '\n') { line++; col = 1; }
86 else col++;
87 }
88 } else {
89 line = 1; col = 1;
90 for (uint32_t i = 0; i < off; i++) {
91 if (code[i] == '\n') { line++; col = 1; }
92 else col++;
93 }
94 }
95
96 if (c->srcpos_count >= c->srcpos_cap) {
97 c->srcpos_cap = c->srcpos_cap ? c->srcpos_cap * 2 : 32;
98 c->srcpos = realloc(c->srcpos, (size_t)c->srcpos_cap * sizeof(sv_srcpos_t));
99 }
100 c->srcpos[c->srcpos_count++] = (sv_srcpos_t){
101 .bc_offset = (uint32_t)c->code_len,
102 .line = line,
103 .col = col,
104 .src_off = off,
105 .src_end = end,
106 };
107 c->last_srcpos_off = off;
108 c->last_srcpos_end = end;
109}
110
111static void patch_u32(sv_compiler_t *c, int offset, uint32_t val) {
112 c->code[offset] = (uint8_t)(val & 0xFF);
113 c->code[offset + 1] = (uint8_t)((val >> 8) & 0xFF);
114 c->code[offset + 2] = (uint8_t)((val >> 16) & 0xFF);
115 c->code[offset + 3] = (uint8_t)((val >> 24) & 0xFF);
116}
117
118static int add_constant(sv_compiler_t *c, ant_value_t val) {
119 if (vtype(val) == T_STR) {
120 ant_offset_t slen;
121 ant_offset_t off = vstr(c->js, val, &slen);
122 const char *sptr = (const char *)(uintptr_t)off;
123
124 const_dedup_entry_t *found = NULL;
125 HASH_FIND(hh, c->const_dedup, sptr, (size_t)slen, found);
126 if (found) return found->index;
127
128 int idx = c->const_count;
129 if (c->const_count >= c->const_cap) {
130 c->const_cap = c->const_cap ? c->const_cap * 2 : 16;
131 c->constants = realloc(c->constants, (size_t)c->const_cap * sizeof(ant_value_t));
132 }
133 c->constants[c->const_count++] = val;
134
135 const_dedup_entry_t *entry = malloc(sizeof(const_dedup_entry_t));
136 if (entry) {
137 entry->str = sptr;
138 entry->len = (size_t)slen;
139 entry->index = idx;
140 HASH_ADD_KEYPTR(hh, c->const_dedup, entry->str, entry->len, entry);
141 }
142 return idx;
143 }
144
145 if (c->const_count >= c->const_cap) {
146 c->const_cap = c->const_cap ? c->const_cap * 2 : 16;
147 c->constants = realloc(c->constants, (size_t)c->const_cap * sizeof(ant_value_t));
148 }
149 c->constants[c->const_count] = val;
150 return c->const_count++;
151}
152
153static void build_gc_const_tables(sv_func_t *func) {
154 if (!func || func->const_count <= 0 || !func->constants) return;
155
156 int child_count = 0;
157 for (int i = 0; i < func->const_count; i++) {
158 if (vtype(func->constants[i]) == T_NTARG) child_count++;
159 }
160
161 if (child_count > 0) {
162 func->child_funcs = code_arena_bump((size_t)child_count * sizeof(sv_func_t *));
163 if (func->child_funcs) {
164 int out = 0;
165 for (int i = 0; i < func->const_count; i++) {
166 if (vtype(func->constants[i]) != T_NTARG) continue;
167 func->child_funcs[out++] = (sv_func_t *)(uintptr_t)vdata(func->constants[i]);
168 } func->child_func_count = child_count;
169 }
170 }
171
172 uint8_t *marked_slots = calloc((size_t)func->const_count, sizeof(uint8_t));
173 if (!marked_slots) return;
174
175 int slot_count = 0;
176 for (int pc = 0; pc < func->code_len;) {
177 sv_op_t op = (sv_op_t)func->code[pc];
178 int size = (op < OP__COUNT) ? sv_op_size[op] : 0;
179 if (size <= 0) break;
180
181 if (op == OP_PUT_CONST) {
182 uint32_t idx = sv_get_u32(func->code + pc + 1);
183 if (idx < (uint32_t)func->const_count && !marked_slots[idx]) {
184 marked_slots[idx] = 1; slot_count++;
185 }
186 }
187
188 pc += size;
189 }
190
191 if (slot_count > 0) {
192 func->gc_const_slots = code_arena_bump((size_t)slot_count * sizeof(uint32_t));
193 if (func->gc_const_slots) {
194 int out = 0;
195 for (int i = 0; i < func->const_count; i++) {
196 if (!marked_slots[i]) continue;
197 func->gc_const_slots[out++] = (uint32_t)i;
198 }
199 func->gc_const_slot_count = slot_count;
200 }
201 }
202
203 free(marked_slots);
204}
205
206static void emit_constant(sv_compiler_t *c, ant_value_t val) {
207 int idx = add_constant(c, val);
208 if (idx <= 255) {
209 emit_op(c, OP_CONST8);
210 emit(c, (uint8_t)idx);
211 } else {
212 emit_op(c, OP_CONST);
213 emit_u32(c, (uint32_t)idx);
214 }
215}
216
217static void emit_number(sv_compiler_t *c, double num) {
218 if (num >= -128 && num <= 127 && num == (int)num && num != -0.0) {
219 emit_op(c, OP_CONST_I8);
220 emit(c, (uint8_t)(int8_t)num);
221 } else emit_constant(c, tov(num));
222}
223
224
225static inline bool is_quoted_ident_key(const sv_ast_t *node) {
226 if (!node || node->type != N_IDENT || !node->str || node->len < 2) return false;
227 char open = node->str[0];
228 char close = node->str[node->len - 1];
229 return ((open == '\'' && close == '\'') || (open == '"' && close == '"'));
230}
231
232static inline bool is_template_segment(const sv_ast_t *node) {
233 return node && node->type == N_STRING && (node->flags & FN_TEMPLATE_SEGMENT);
234}
235
236static inline bool is_invalid_cooked_string(const sv_ast_t *node) {
237 return is_template_segment(node) && (node->flags & FN_INVALID_COOKED);
238}
239
240static inline ant_value_t ast_string_const(sv_compiler_t *c, const sv_ast_t *node) {
241 if (!node || !node->str) return js_mkstr_permanent(c->js, "", 0);
242 return js_mkstr_permanent(c->js, node->str, node->len);
243}
244
245static inline void compile_static_property_key(sv_compiler_t *c, sv_ast_t *key) {
246 if (!key) {
247 emit_op(c, OP_UNDEF);
248 return;
249 }
250
251 if (key->type == N_STRING) {
252 emit_constant(c, ast_string_const(c, key));
253 return;
254 }
255
256 if (key->type == N_NUMBER) {
257 char buf[32];
258 int n = snprintf(buf, sizeof(buf), "%g", key->num);
259 emit_constant(c, js_mkstr_permanent(c->js, buf, (size_t)n));
260 return;
261 }
262
263 if (key->type == N_IDENT) {
264 if (is_quoted_ident_key(key))
265 emit_constant(c, js_mkstr_permanent(c->js, key->str + 1, key->len - 2));
266 else
267 emit_constant(c, js_mkstr_permanent(c->js, key->str, key->len));
268 return;
269 }
270
271 compile_expr(c, key);
272}
273
274enum {
275 SV_COMP_PRIVATE_FIELD = 0,
276 SV_COMP_PRIVATE_METHOD = 1,
277 SV_COMP_PRIVATE_GETTER = 3,
278 SV_COMP_PRIVATE_SETTER = 4
279};
280
281static int local_to_frame_slot(sv_compiler_t *c, int local_idx);
282static int add_upvalue(sv_compiler_t *c, uint16_t index, bool is_local, bool is_const);
283static void emit_get_local(sv_compiler_t *c, int local_idx);
284
285static inline bool is_private_name_node(const sv_ast_t *node) {
286 return node && node->type == N_IDENT && node->str && node->len > 0 && node->str[0] == '#';
287}
288
289static sv_private_name_t *private_scope_find_current(
290 sv_private_scope_t *scope, const char *name, uint32_t len
291) {
292 if (!scope || !name) return NULL;
293 for (int i = 0; i < scope->count; i++) {
294 sv_private_name_t *p = &scope->names[i];
295 if (p->len == len && memcmp(p->name, name, len) == 0) return p;
296 }
297 return NULL;
298}
299
300static sv_private_name_t *private_scope_resolve(
301 sv_compiler_t *c, const char *name, uint32_t len
302) {
303 for (sv_private_scope_t *scope = c->private_scope; scope; scope = scope->parent) {
304 sv_private_name_t *p = private_scope_find_current(scope, name, len);
305 if (p) return p;
306 }
307 return NULL;
308}
309
310static bool private_scope_add(
311 sv_compiler_t *c, sv_private_scope_t *scope,
312 sv_ast_t *name, uint8_t kind, bool is_static
313) {
314 if (!is_private_name_node(name)) return true;
315
316 if (name->len == 12 && memcmp(name->str, "#constructor", 12) == 0) {
317 js_mkerr_typed(c->js, JS_ERR_SYNTAX, "Classes may not declare private constructor names");
318 return false;
319 }
320
321 sv_private_name_t *existing = private_scope_find_current(scope, name->str, name->len);
322 bool is_accessor = kind == SV_COMP_PRIVATE_GETTER || kind == SV_COMP_PRIVATE_SETTER;
323 if (existing) {
324 bool existing_accessor = existing->kind == SV_COMP_PRIVATE_GETTER ||
325 existing->kind == SV_COMP_PRIVATE_SETTER;
326 if (!is_accessor || !existing_accessor || existing->is_static != is_static) {
327 js_mkerr_typed(c->js, JS_ERR_SYNTAX, "Duplicate private name '%.*s'", (int)name->len, name->str);
328 return false;
329 }
330 if ((kind == SV_COMP_PRIVATE_GETTER && existing->has_getter) ||
331 (kind == SV_COMP_PRIVATE_SETTER && existing->has_setter)) {
332 js_mkerr_typed(c->js, JS_ERR_SYNTAX, "Duplicate private accessor '%.*s'", (int)name->len, name->str);
333 return false;
334 }
335 if (kind == SV_COMP_PRIVATE_GETTER) existing->has_getter = true;
336 if (kind == SV_COMP_PRIVATE_SETTER) existing->has_setter = true;
337 return true;
338 }
339
340 if (scope->count >= scope->cap) {
341 int new_cap = scope->cap ? scope->cap * 2 : 8;
342 sv_private_name_t *new_names = realloc(scope->names, (size_t)new_cap * sizeof(*scope->names));
343 if (!new_names) return false;
344 scope->names = new_names;
345 scope->cap = new_cap;
346 }
347
348 sv_private_name_t *p = &scope->names[scope->count++];
349
350 uint64_t hash64 = hash_key(name->str, (size_t)name->len);
351 uint32_t hash = (uint32_t)(hash64 ^ (hash64 >> 32));
352
353 *p = (sv_private_name_t){
354 .name = name->str,
355 .len = name->len,
356 .kind = kind,
357 .hash = hash,
358 .is_static = is_static,
359 .has_getter = kind == SV_COMP_PRIVATE_GETTER,
360 .has_setter = kind == SV_COMP_PRIVATE_SETTER,
361 .owner = NULL,
362 .local = -1
363 };
364
365 return true;
366}
367
368static int resolve_private_upvalue(sv_compiler_t *c, sv_private_name_t *p) {
369 if (!c->enclosing || !p || !p->owner || p->local < 0) return -1;
370
371 if (c->enclosing == p->owner) {
372 p->owner->locals[p->local].captured = true;
373 uint16_t slot = (uint16_t)local_to_frame_slot(p->owner, p->local);
374 return add_upvalue(c, slot, true, false);
375 }
376
377 int upvalue = resolve_private_upvalue(c->enclosing, p);
378 if (upvalue == -1) return -1;
379 return add_upvalue(c, (uint16_t)upvalue, false, false);
380}
381
382static bool emit_private_token(sv_compiler_t *c, sv_ast_t *name) {
383 sv_private_name_t *p = private_scope_resolve(c, name->str, name->len);
384 if (!p) {
385 js_mkerr_typed(c->js, JS_ERR_SYNTAX, "Private name '%.*s' is not declared", (int)name->len, name->str);
386 emit_op(c, OP_UNDEF);
387 return false;
388 }
389 if (!p->owner || p->local < 0) {
390 js_mkerr_typed(c->js, JS_ERR_SYNTAX, "Private name '%.*s' is not initialized", (int)name->len, name->str);
391 emit_op(c, OP_UNDEF);
392 return false;
393 }
394 if (p->owner == c) {
395 emit_get_local(c, p->local);
396 return true;
397 }
398 int upvalue = resolve_private_upvalue(c, p);
399 if (upvalue == -1) {
400 js_mkerr_typed(c->js, JS_ERR_SYNTAX, "Private name '%.*s' is not in scope", (int)name->len, name->str);
401 emit_op(c, OP_UNDEF);
402 return false;
403 }
404 emit_op(c, OP_GET_UPVAL);
405 emit_u16(c, (uint16_t)upvalue);
406 return true;
407}
408
409static int add_atom(sv_compiler_t *c, const char *str, uint32_t len) {
410 const char *interned = intern_string(str, (size_t)len);
411 const char *stored = interned;
412 if (!stored) {
413 char *copy = code_arena_bump(len);
414 memcpy(copy, str, len);
415 stored = copy;
416 }
417
418 for (int i = 0; i < c->atom_count; i++) {
419 if (c->atoms[i].len == len && c->atoms[i].str == stored)
420 return i;
421 }
422 if (c->atom_count >= c->atom_cap) {
423 c->atom_cap = c->atom_cap ? c->atom_cap * 2 : 16;
424 c->atoms = realloc(c->atoms, (size_t)c->atom_cap * sizeof(sv_atom_t));
425 }
426 c->atoms[c->atom_count] = (sv_atom_t){ .str = stored, .len = len };
427 return c->atom_count++;
428}
429
430static inline bool sv_op_has_ic_slot(sv_op_t op) {
431 return op == OP_GET_GLOBAL || op == OP_GET_GLOBAL_UNDEF ||
432 op == OP_GET_FIELD || op == OP_GET_FIELD2 || op == OP_PUT_FIELD;
433}
434
435static uint16_t alloc_ic_idx(sv_compiler_t *c) {
436 if (!c || c->ic_count >= (int)UINT16_MAX) return UINT16_MAX;
437 return (uint16_t)c->ic_count++;
438}
439
440static void sv_func_init_obj_sites(sv_func_t *func) {
441 if (!func || !func->code || func->code_len <= 0) return;
442
443 uint32_t count = 0;
444 for (int pc = 0; pc < func->code_len; ) {
445 sv_op_t op = (sv_op_t)func->code[pc];
446 if (op == OP_OBJECT) count++;
447 uint8_t size = (op < OP__COUNT) ? sv_op_size[op] : 1;
448 pc += (size > 0) ? size : 1;
449 }
450 if (count == 0) return;
451
452 func->obj_sites = code_arena_bump((size_t)count * sizeof(sv_obj_site_cache_t));
453 memset(func->obj_sites, 0, (size_t)count * sizeof(sv_obj_site_cache_t));
454 func->obj_site_count = (uint16_t)count;
455
456 uint32_t idx = 0;
457 for (int pc = 0; pc < func->code_len && idx < count; ) {
458 sv_op_t op = (sv_op_t)func->code[pc];
459 if (op == OP_OBJECT) func->obj_sites[idx++].bc_off = (uint32_t)pc;
460 uint8_t size = (op < OP__COUNT) ? sv_op_size[op] : 1;
461 pc += (size > 0) ? size : 1;
462 }
463}
464
465static void emit_atom_idx_op(sv_compiler_t *c, sv_op_t op, uint32_t atom_idx) {
466 emit_op(c, op);
467 emit_u32(c, atom_idx);
468 if (sv_op_has_ic_slot(op))
469 emit_u16(c, alloc_ic_idx(c));
470}
471
472static void emit_atom_op(sv_compiler_t *c, sv_op_t op, const char *str, uint32_t len) {
473 int idx = add_atom(c, str, len);
474 emit_atom_idx_op(c, op, (uint32_t)idx);
475}
476
477static inline void emit_set_function_name(
478 sv_compiler_t *c,
479 const char *name, uint32_t len
480) {
481 if (!name) { name = ""; len = 0; }
482 emit_atom_op(c, OP_SET_NAME, name, len);
483}
484
485static inline bool node_needs_inferred_function_name(const sv_ast_t *node) {
486 return node &&
487 (node->type == N_FUNC || node->type == N_CLASS) &&
488 (!node->str || node->len == 0);
489}
490
491static void compile_expr_with_inferred_name(
492 sv_compiler_t *c, sv_ast_t *node,
493 const char *name, uint32_t len
494) {
495 if (!node_needs_inferred_function_name(node) || !name) {
496 compile_expr(c, node);
497 return;
498 }
499
500 const char *saved_name = c->inferred_name;
501 uint32_t saved_len = c->inferred_name_len;
502
503 c->inferred_name = name;
504 c->inferred_name_len = len;
505 compile_expr(c, node);
506
507 c->inferred_name = saved_name;
508 c->inferred_name_len = saved_len;
509}
510
511static void emit_const_assign_error(sv_compiler_t *c, const char *name, uint32_t len) {
512 static const char prefix[] = "Assignment to constant variable '";
513 static const char suffix[] = "'";
514
515 uint32_t mlen = (uint32_t)(sizeof(prefix) - 1 + len + sizeof(suffix) - 1);
516 char *buf = code_arena_bump(mlen);
517
518 memcpy(buf, prefix, sizeof(prefix) - 1);
519 memcpy(buf + sizeof(prefix) - 1, name, len);
520 memcpy(buf + sizeof(prefix) - 1 + len, suffix, sizeof(suffix) - 1);
521
522 int atom = add_atom(c, buf, mlen);
523 emit_op(c, OP_THROW_ERROR);
524 emit_u32(c, (uint32_t)atom);
525 emit(c, (uint8_t)JS_ERR_TYPE);
526}
527
528static inline bool is_ident_str(
529 const char *name, uint32_t len,
530 const char *lit, uint32_t lit_len
531) {
532 return len == lit_len && memcmp(name, lit, lit_len) == 0;
533}
534
535static inline bool is_strict_restricted_ident(const char *name, uint32_t len) {
536 return
537 is_ident_str(name, len, "eval", 4) ||
538 is_ident_str(name, len, "arguments", 9);
539}
540
541static inline bool is_repl_top_level(const sv_compiler_t *c) {
542 return
543 c->mode == SV_COMPILE_REPL && c->scope_depth == 0 &&
544 c->enclosing && !c->enclosing->enclosing &&
545 !c->is_strict;
546}
547
548static inline bool has_completion_value(const sv_compiler_t *c) {
549 return c && (c->mode == SV_COMPILE_EVAL || c->mode == SV_COMPILE_REPL);
550}
551
552static inline bool is_completion_top_level(const sv_compiler_t *c) {
553 return has_completion_value(c) && c->enclosing && !c->enclosing->enclosing;
554}
555
556static inline bool has_completion_accumulator(const sv_compiler_t *c) {
557 return c && c->completion_local >= 0;
558}
559
560static inline bool has_module_import_binding(const sv_compiler_t *c) {
561 for (const sv_compiler_t *cur = c; cur; cur = cur->enclosing) {
562 if (cur->mode == SV_COMPILE_MODULE) return true;
563 }
564 return false;
565}
566
567static inline bool has_implicit_arguments_obj(const sv_compiler_t *c) {
568 return c && !c->is_arrow && c->enclosing;
569}
570
571static int resolve_local(sv_compiler_t *c, const char *name, uint32_t len) {
572 if (c->local_lookup_heads && c->local_lookup_cap > 0) {
573 uint32_t hash = sv_compile_ctx_hash_local_name(name, len);
574 int bucket = (int)(hash & (uint32_t)(c->local_lookup_cap - 1));
575 for (int i = c->local_lookup_heads[bucket]; i != -1; i = c->locals[i].lookup_next) {
576 sv_local_t *loc = &c->locals[i];
577 if (
578 loc->name_hash == hash &&
579 loc->name_len == len &&
580 memcmp(loc->name, name, len) == 0
581 ) return i;
582 }
583 return -1;
584 }
585
586 for (int i = c->local_count - 1; i >= 0; i--) {
587 sv_local_t *loc = &c->locals[i];
588 if (loc->name_len == len && memcmp(loc->name, name, len) == 0) return i;
589 }
590
591 return -1;
592}
593
594static int add_local(
595 sv_compiler_t *c, const char *name, uint32_t len,
596 bool is_const, int depth
597) {
598 sv_compile_ctx_ensure_local_lookup_capacity(c, c->local_count + 1);
599 if (c->local_count >= c->local_cap) {
600 c->local_cap = c->local_cap ? c->local_cap * 2 : 16;
601 c->locals = realloc(c->locals, (size_t)c->local_cap * sizeof(sv_local_t));
602 }
603 int idx = c->local_count++;
604 if (c->local_count > c->max_local_count)
605 c->max_local_count = c->local_count;
606 c->locals[idx] = (sv_local_t){
607 .name = name, .name_len = len,
608 .name_hash = sv_compile_ctx_hash_local_name(name, len),
609 .lookup_next = -1,
610 .depth = depth, .is_const = is_const, .captured = false,
611 .inferred_type = SV_TI_UNKNOWN,
612 };
613 sv_compile_ctx_local_lookup_insert(c, idx);
614 return idx;
615}
616
617static int reserve_hidden_locals(sv_compiler_t *c, int count) {
618 int base = c->local_count;
619 for (int i = 0; i < count; i++)
620 add_local(c, "", 0, false, c->scope_depth);
621 return base;
622}
623
624static inline bool sv_type_is_known(uint8_t t) {
625 return t != SV_TI_UNKNOWN;
626}
627
628static inline bool sv_type_is_num(uint8_t t) {
629 return t == SV_TI_NUM;
630}
631
632static void ensure_slot_type_cap(sv_compiler_t *c, int slot) {
633 if (slot < 0) return;
634 if (slot < c->slot_type_cap) return;
635 int new_cap = c->slot_type_cap ? c->slot_type_cap : 16;
636 while (new_cap <= slot) new_cap *= 2;
637 sv_type_info_t *next = realloc(c->slot_types, (size_t)new_cap * sizeof(sv_type_info_t));
638 if (!next) return;
639 memset(next + c->slot_type_cap, 0, (size_t)(new_cap - c->slot_type_cap) * sizeof(sv_type_info_t));
640 c->slot_types = next;
641 c->slot_type_cap = new_cap;
642}
643
644static void mark_slot_type(sv_compiler_t *c, int slot, uint8_t type) {
645 if (slot < 0) return;
646 ensure_slot_type_cap(c, slot);
647 if (!c->slot_types || slot >= c->slot_type_cap) return;
648 uint8_t old = c->slot_types[slot].type;
649 if (!sv_type_is_known(type)) {
650 c->slot_types[slot].type = SV_TI_UNKNOWN;
651 return;
652 }
653 if (!sv_type_is_known(old))
654 c->slot_types[slot].type = type;
655 else if (old != type)
656 c->slot_types[slot].type = SV_TI_UNKNOWN;
657}
658
659static void set_local_inferred_type(sv_compiler_t *c, int local_idx, uint8_t type) {
660 if (local_idx < 0 || local_idx >= c->local_count) return;
661 c->locals[local_idx].inferred_type = type;
662 if (c->locals[local_idx].depth == -1) return;
663 int slot = local_idx - c->param_locals;
664 mark_slot_type(c, slot, type);
665}
666
667static inline uint8_t get_local_inferred_type(sv_compiler_t *c, int local_idx) {
668 if (local_idx < 0 || local_idx >= c->local_count) return SV_TI_UNKNOWN;
669 if (c->locals[local_idx].depth == -1) return SV_TI_UNKNOWN;
670 if (c->locals[local_idx].is_tdz) return SV_TI_UNKNOWN;
671 return c->locals[local_idx].inferred_type;
672}
673
674static const char *typeof_name_for_type(uint8_t type) {
675 switch (type) {
676 case SV_TI_NUM: return "number";
677 case SV_TI_STR: return "string";
678 case SV_TI_BOOL: return "boolean";
679 case SV_TI_UNDEF: return "undefined";
680 case SV_TI_ARR:
681 case SV_TI_OBJ:
682 case SV_TI_NULL: return "object";
683 default: return NULL;
684 }
685}
686
687static uint8_t iter_hint_for_type(uint8_t type) {
688 switch (type) {
689 case SV_TI_ARR: return SV_ITER_HINT_ARRAY;
690 case SV_TI_STR: return SV_ITER_HINT_STRING;
691 default: return SV_ITER_HINT_GENERIC;
692 }
693}
694
695static int ensure_local_at_depth(
696 sv_compiler_t *c, const char *name, uint32_t len,
697 bool is_const, int depth
698) {
699 int local = resolve_local(c, name, len);
700 if (local != -1 && c->locals[local].depth == depth)
701 return local;
702 return add_local(c, name, len, is_const, depth);
703}
704
705static int local_to_frame_slot(sv_compiler_t *c, int local_idx) {
706 if (c->locals[local_idx].depth == -1) return local_idx;
707 return c->param_count + (local_idx - c->param_locals);
708}
709
710static int resolve_local_slot(sv_compiler_t *c, const char *name, uint32_t len) {
711 int local = resolve_local(c, name, len);
712 if (local == -1 || c->locals[local].depth == -1) return -1;
713 int slot = local - c->param_locals;
714 return (slot >= 0 && slot <= 255) ? slot : -1;
715}
716
717static int add_upvalue(sv_compiler_t *c, uint16_t index, bool is_local, bool is_const) {
718 for (int i = 0; i < c->upvalue_count; i++) {
719 if (c->upval_descs[i].index == index &&
720 c->upval_descs[i].is_local == is_local)
721 return i;
722 }
723 if (c->upvalue_count >= c->upvalue_cap) {
724 c->upvalue_cap = c->upvalue_cap ? c->upvalue_cap * 2 : 8;
725 c->upval_descs = realloc(
726 c->upval_descs,
727 (size_t)c->upvalue_cap * sizeof(sv_upval_desc_t));
728 }
729 int idx = c->upvalue_count++;
730 c->upval_descs[idx] = (sv_upval_desc_t){
731 .index = index, .is_local = is_local, .is_const = is_const,
732 };
733 return idx;
734}
735
736static int resolve_super_upvalue(sv_compiler_t *c) {
737 if (!c->enclosing) return -1;
738 sv_compiler_t *enc = c->enclosing;
739
740 if (!enc->is_arrow) {
741 if (enc->super_local < 0) return -1;
742 enc->locals[enc->super_local].captured = true;
743 uint16_t slot = (uint16_t)local_to_frame_slot(enc, enc->super_local);
744 return add_upvalue(c, slot, true, false);
745 }
746
747 int upvalue = resolve_super_upvalue(enc);
748 if (upvalue == -1) return -1;
749 return add_upvalue(c, (uint16_t)upvalue, false, false);
750}
751
752static int resolve_arguments_upvalue(sv_compiler_t *c) {
753 if (!c->enclosing) return -1;
754 sv_compiler_t *enc = c->enclosing;
755
756 if (!enc->is_arrow) {
757 if (enc->strict_args_local < 0) return -1;
758 enc->locals[enc->strict_args_local].captured = true;
759 uint16_t slot = (uint16_t)local_to_frame_slot(enc, enc->strict_args_local);
760 return add_upvalue(c, slot, true, false);
761 }
762
763 int upvalue = resolve_arguments_upvalue(enc);
764 if (upvalue == -1) return -1;
765
766 return add_upvalue(c, (uint16_t)upvalue, false, false);
767}
768
769static int resolve_upvalue(sv_compiler_t *c, const char *name, uint32_t len) {
770 if (!c->enclosing) return -1;
771
772 int local = resolve_local(c->enclosing, name, len);
773 if (local != -1) {
774 c->enclosing->locals[local].captured = true;
775 uint16_t slot = (uint16_t)local_to_frame_slot(c->enclosing, local);
776 return add_upvalue(c, slot, true, c->enclosing->locals[local].is_const);
777 }
778
779 int upvalue = resolve_upvalue(c->enclosing, name, len);
780 if (upvalue != -1) {
781 bool uv_const = c->enclosing->upval_descs[upvalue].is_const;
782 return add_upvalue(c, (uint16_t)upvalue, false, uv_const);
783 }
784
785 return -1;
786}
787
788static int emit_jump(sv_compiler_t *c, sv_op_t op) {
789 emit_op(c, op);
790 int offset = c->code_len;
791 emit_i32(c, 0);
792 return offset;
793}
794
795static void patch_jump(sv_compiler_t *c, int offset) {
796 int32_t delta = (int32_t)(c->code_len - offset - 4);
797 patch_u32(c, offset, (uint32_t)delta);
798}
799
800static void emit_loop(sv_compiler_t *c, int loop_start) {
801 emit_op(c, OP_JMP);
802 int32_t delta = (int32_t)(loop_start - c->code_len - 4);
803 emit_i32(c, delta);
804}
805
806static void patch_list_add(sv_patch_list_t *pl, int offset) {
807 if (pl->count >= pl->cap) {
808 pl->cap = pl->cap ? pl->cap * 2 : 4;
809 pl->offsets = realloc(pl->offsets, (size_t)pl->cap * sizeof(int));
810 }
811 pl->offsets[pl->count++] = offset;
812}
813
814static void patch_list_resolve(sv_compiler_t *c, sv_patch_list_t *pl) {
815 for (int i = 0; i < pl->count; i++)
816 patch_jump(c, pl->offsets[i]);
817 free(pl->offsets);
818 *pl = (sv_patch_list_t){0};
819}
820
821static void push_loop(
822 sv_compiler_t *c, int loop_start,
823 const char *label, uint32_t label_len,
824 bool is_switch
825) {
826 if (c->loop_count >= c->loop_cap) {
827 c->loop_cap = c->loop_cap ? c->loop_cap * 2 : 4;
828 c->loops = realloc(c->loops, (size_t)c->loop_cap * sizeof(sv_loop_t));
829 }
830 if (!label && c->pending_label) {
831 label = c->pending_label;
832 label_len = c->pending_label_len;
833 c->pending_label = NULL;
834 c->pending_label_len = 0;
835 }
836 c->loops[c->loop_count++] = (sv_loop_t){
837 .loop_start = loop_start,
838 .scope_depth = c->scope_depth,
839 .label = label, .label_len = label_len,
840 .is_switch = is_switch,
841 };
842}
843
844static void pop_loop(sv_compiler_t *c) {
845 sv_loop_t *loop = &c->loops[--c->loop_count];
846 patch_list_resolve(c, &loop->breaks);
847 free(loop->continues.offsets);
848}
849
850static void begin_scope(sv_compiler_t *c) {
851 c->scope_depth++;
852}
853
854static void end_scope(sv_compiler_t *c) {
855 while (
856 c->local_count > 0 &&
857 c->locals[c->local_count - 1].depth >= c->scope_depth
858 ) {
859 sv_local_t *loc = &c->locals[c->local_count - 1];
860 if (loc->captured) {
861 int frame_slot = local_to_frame_slot(c, c->local_count - 1);
862 emit_op(c, OP_CLOSE_UPVAL);
863 emit_u16(c, (uint16_t)frame_slot);
864 }
865 sv_compile_ctx_local_lookup_remove(c, c->local_count - 1);
866 c->local_count--;
867 }
868 c->scope_depth--;
869}
870
871static void emit_close_upvals(sv_compiler_t *c) {
872 for (int i = 0; i < c->local_count; i++) {
873 if (c->locals[i].captured) {
874 int frame_slot = local_to_frame_slot(c, i);
875 emit_op(c, OP_CLOSE_UPVAL);
876 emit_u16(c, (uint16_t)frame_slot);
877 return;
878 }}
879}
880
881static void emit_with_get(
882 sv_compiler_t *c, const char *name, uint32_t len,
883 uint8_t fb_kind, uint16_t fb_idx
884) {
885 int atom = add_atom(c, name, len);
886 emit_op(c, OP_WITH_GET_VAR);
887 emit_u32(c, (uint32_t)atom);
888 emit(c, fb_kind);
889 emit_u16(c, fb_idx);
890}
891
892static void emit_with_put(
893 sv_compiler_t *c, const char *name, uint32_t len,
894 uint8_t fb_kind, uint16_t fb_idx
895) {
896 int atom = add_atom(c, name, len);
897 emit_op(c, OP_WITH_PUT_VAR);
898 emit_u32(c, (uint32_t)atom);
899 emit(c, fb_kind);
900 emit_u16(c, fb_idx);
901}
902
903static void emit_get_local(sv_compiler_t *c, int local_idx);
904static void emit_put_local(sv_compiler_t *c, int local_idx);
905static void emit_put_local_typed(sv_compiler_t *c, int local_idx, uint8_t type);
906
907static inline void emit_get_module_import_binding(sv_compiler_t *c) {
908 emit_op(c, OP_SPECIAL_OBJ);
909 emit(c, 3);
910}
911
912static void emit_get_var(sv_compiler_t *c, const char *name, uint32_t len) {
913 bool is_super = is_ident_str(name, len, "super", 5);
914
915 if (is_super && c->super_local >= 0) {
916 emit_get_local(c, c->super_local);
917 return;
918 }
919
920 if (is_super && c->is_arrow) {
921 int super_upval = resolve_super_upvalue(c);
922 if (super_upval != -1) {
923 emit_op(c, OP_GET_UPVAL);
924 emit_u16(c, (uint16_t)super_upval);
925 return;
926 }}
927
928 int local = resolve_local(c, name, len);
929 if (local != -1) {
930 if (c->with_depth > 0) {
931 uint8_t kind = c->locals[local].depth == -1 ? WITH_FB_ARG : WITH_FB_LOCAL;
932 uint16_t idx = kind == WITH_FB_ARG
933 ? (uint16_t)local
934 : (uint16_t)(local - c->param_locals);
935 emit_with_get(c, name, len, kind, idx);
936 return;
937 }
938 if (c->locals[local].depth == -1) {
939 emit_op(c, OP_GET_ARG);
940 emit_u16(c, (uint16_t)local);
941 } else {
942 int slot = local - c->param_locals;
943 if (c->locals[local].is_tdz) {
944 int ai = add_atom(c, name, len);
945 emit_op(c, OP_GET_LOCAL_CHK);
946 emit_u16(c, (uint16_t)slot);
947 emit_u32(c, (uint32_t)ai);
948 } else if (slot <= 255) {
949 emit_op(c, OP_GET_LOCAL8);
950 emit(c, (uint8_t)slot);
951 } else {
952 emit_op(c, OP_GET_LOCAL);
953 emit_u16(c, (uint16_t)slot);
954 }
955 }
956 return;
957 }
958
959 int upval = resolve_upvalue(c, name, len);
960 if (upval != -1) {
961 if (c->with_depth > 0) {
962 emit_with_get(c, name, len, WITH_FB_UPVAL, (uint16_t)upval);
963 return;
964 }
965 emit_op(c, OP_GET_UPVAL);
966 emit_u16(c, (uint16_t)upval);
967 return;
968 }
969
970 if (is_ident_str(name, len, "arguments", 9)) {
971 if (has_implicit_arguments_obj(c)) {
972 if (c->strict_args_local >= 0) {
973 emit_get_local(c, c->strict_args_local);
974 } else {
975 emit_op(c, OP_SPECIAL_OBJ);
976 emit(c, 0);
977 }
978 return;
979 }
980 if (c->is_arrow) {
981 int args_upval = resolve_arguments_upvalue(c);
982 if (args_upval != -1) {
983 emit_op(c, OP_GET_UPVAL);
984 emit_u16(c, (uint16_t)args_upval);
985 return;
986 }
987 }
988 }
989
990 if (has_module_import_binding(c) && is_ident_str(name, len, "import", 6)) {
991 emit_get_module_import_binding(c);
992 return;
993 }
994
995 if (c->with_depth > 0) emit_with_get(c, name, len, WITH_FB_GLOBAL, 0);
996 else emit_atom_op(c, OP_GET_GLOBAL, name, len);
997}
998
999static void emit_set_var(sv_compiler_t *c, const char *name, uint32_t len, bool keep) {
1000 int local = resolve_local(c, name, len);
1001 if (local != -1) {
1002 if (c->locals[local].is_const) {
1003 emit_const_assign_error(c, name, len);
1004 return;
1005 }
1006 set_local_inferred_type(c, local, SV_TI_UNKNOWN);
1007
1008 if (c->with_depth > 0) {
1009 uint8_t kind = c->locals[local].depth == -1 ? WITH_FB_ARG : WITH_FB_LOCAL;
1010 uint16_t idx = kind == WITH_FB_ARG
1011 ? (uint16_t)local
1012 : (uint16_t)(local - c->param_locals);
1013 if (keep) emit_op(c, OP_DUP);
1014 emit_with_put(c, name, len, kind, idx);
1015 return;
1016 }
1017 if (c->locals[local].depth == -1) {
1018 emit_op(c, keep ? OP_SET_ARG : OP_PUT_ARG);
1019 emit_u16(c, (uint16_t)local);
1020 } else {
1021 int slot = local - c->param_locals;
1022 sv_op_t op = keep
1023 ? (slot <= 255 ? OP_SET_LOCAL8 : OP_SET_LOCAL)
1024 : (slot <= 255 ? OP_PUT_LOCAL8 : OP_PUT_LOCAL);
1025 emit_op(c, op);
1026 if (slot <= 255) emit(c, (uint8_t)slot);
1027 else emit_u16(c, (uint16_t)slot);
1028 }
1029 return;
1030 }
1031 int upval = resolve_upvalue(c, name, len);
1032 if (upval != -1) {
1033 if (c->upval_descs[upval].is_const) {
1034 emit_const_assign_error(c, name, len);
1035 return;
1036 }
1037 if (c->with_depth > 0) {
1038 if (keep) emit_op(c, OP_DUP);
1039 emit_with_put(c, name, len, WITH_FB_UPVAL, (uint16_t)upval);
1040 return;
1041 }
1042 emit_op(c, keep ? OP_SET_UPVAL : OP_PUT_UPVAL);
1043 emit_u16(c, (uint16_t)upval);
1044 return;
1045 }
1046 if (has_module_import_binding(c) && is_ident_str(name, len, "import", 6)) {
1047 emit_const_assign_error(c, name, len);
1048 return;
1049 }
1050 if (c->with_depth > 0) {
1051 if (keep) emit_op(c, OP_DUP);
1052 emit_with_put(c, name, len, WITH_FB_GLOBAL, 0);
1053 } else {
1054 if (keep) {
1055 emit_op(c, OP_DUP);
1056 emit_atom_op(c, OP_PUT_GLOBAL, name, len);
1057 } else emit_atom_op(c, OP_PUT_GLOBAL, name, len);
1058 }
1059}
1060
1061static void emit_put_local_typed(sv_compiler_t *c, int local_idx, uint8_t type) {
1062 int slot = local_idx - c->param_locals;
1063 if (slot <= 255) { emit_op(c, OP_PUT_LOCAL8); emit(c, (uint8_t)slot); }
1064 else { emit_op(c, OP_PUT_LOCAL); emit_u16(c, (uint16_t)slot); }
1065 set_local_inferred_type(c, local_idx, type);
1066}
1067
1068static inline void emit_slot_op(sv_compiler_t *c, sv_op_t op, uint16_t slot) {
1069 emit_op(c, op);
1070 emit_u16(c, slot);
1071}
1072
1073static void emit_put_local(sv_compiler_t *c, int local_idx) {
1074 emit_put_local_typed(c, local_idx, SV_TI_UNKNOWN);
1075}
1076
1077static void emit_set_completion_from_stack(sv_compiler_t *c) {
1078 if (has_completion_accumulator(c)) emit_put_local(c, c->completion_local);
1079 else emit_op(c, OP_POP);
1080}
1081
1082static void emit_set_completion_undefined(sv_compiler_t *c) {
1083 if (!has_completion_accumulator(c)) return;
1084 emit_op(c, OP_UNDEF);
1085 emit_put_local(c, c->completion_local);
1086}
1087
1088static uint8_t infer_expr_type(sv_compiler_t *c, sv_ast_t *node);
1089
1090static void emit_get_local(sv_compiler_t *c, int local_idx) {
1091 int slot = local_idx - c->param_locals;
1092 if (slot <= 255) { emit_op(c, OP_GET_LOCAL8); emit(c, (uint8_t)slot); }
1093 else { emit_op(c, OP_GET_LOCAL); emit_u16(c, (uint16_t)slot); }
1094}
1095
1096static bool match_self_append_local(
1097 sv_compiler_t *c, sv_ast_t *node,
1098 int *out_local_idx, uint16_t *out_slot, sv_ast_t **out_rhs
1099) {
1100 if (!c || !node || node->type != N_ASSIGN || !node->left || node->left->type != N_IDENT)
1101 return false;
1102 if (c->with_depth > 0) return false;
1103
1104 int local = resolve_local(c, node->left->str, node->left->len);
1105 if (local < 0 || c->locals[local].is_const) return false;
1106 if (c->locals[local].is_tdz) return false;
1107 if (c->locals[local].depth == -1 && c->strict_args_local >= 0) return false;
1108
1109 sv_ast_t *rhs = NULL;
1110 if (node->op == TOK_PLUS_ASSIGN) rhs = node->right;
1111 else if (
1112 node->op == TOK_ASSIGN &&
1113 node->right && node->right->type == N_BINARY && node->right->op == TOK_PLUS &&
1114 node->right->left && node->right->left->type == N_IDENT &&
1115 node->right->left->len == node->left->len &&
1116 memcmp(node->right->left->str, node->left->str, node->left->len) == 0
1117 ) rhs = node->right->right;
1118
1119 if (!rhs) return false;
1120 uint8_t local_type = get_local_inferred_type(c, local);
1121 uint8_t rhs_type = infer_expr_type(c, rhs);
1122 if (local_type != SV_TI_STR && rhs_type != SV_TI_STR)
1123 return false;
1124
1125 if (out_local_idx) *out_local_idx = local;
1126 if (out_slot) *out_slot = (uint16_t)local_to_frame_slot(c, local);
1127 if (out_rhs) *out_rhs = rhs;
1128
1129 return true;
1130}
1131
1132static bool is_self_append_inplace_safe_ident(sv_compiler_t *c, sv_ast_t *node) {
1133 if (!c || !node || node->type != N_IDENT) return false;
1134
1135 if (resolve_local(c, node->str, node->len) != -1) return true;
1136 if (resolve_upvalue(c, node->str, node->len) != -1) return true;
1137
1138 if (is_ident_str(node->str, node->len, "arguments", 9)) {
1139 if (has_implicit_arguments_obj(c)) return true;
1140 if (c->is_arrow && resolve_arguments_upvalue(c) != -1) return true;
1141 }
1142
1143 if (c->is_arrow && is_ident_str(node->str, node->len, "super", 5))
1144 return resolve_super_upvalue(c) != -1;
1145
1146 if (has_module_import_binding(c) && is_ident_str(node->str, node->len, "import", 6))
1147 return true;
1148
1149 return false;
1150}
1151
1152static bool is_self_append_inplace_safe_expr(sv_compiler_t *c, sv_ast_t *node) {
1153 if (!node) return false;
1154
1155 switch (node->type) {
1156 case N_NUMBER:
1157 case N_STRING:
1158 case N_BIGINT:
1159 case N_BOOL:
1160 case N_NULL:
1161 case N_UNDEF:
1162 return true;
1163
1164 case N_IDENT:
1165 return is_self_append_inplace_safe_ident(c, node);
1166
1167 case N_BINARY: return
1168 is_self_append_inplace_safe_expr(c, node->left) &&
1169 is_self_append_inplace_safe_expr(c, node->right);
1170
1171 case N_UNARY:
1172 case N_TYPEOF:
1173 case N_VOID:
1174 return is_self_append_inplace_safe_expr(c, node->left);
1175
1176 default:
1177 return false;
1178 }
1179}
1180
1181static bool compile_self_append_stmt(sv_compiler_t *c, sv_ast_t *node) {
1182 int local = -1;
1183 uint16_t slot = 0;
1184 sv_ast_t *rhs = NULL;
1185 if (!match_self_append_local(c, node, &local, &slot, &rhs)) return false;
1186 if (is_self_append_inplace_safe_expr(c, rhs)) {
1187 compile_expr(c, rhs);
1188 emit_slot_op(c, OP_STR_APPEND_LOCAL, slot);
1189 } else {
1190 emit_slot_op(c, OP_GET_SLOT_RAW, slot);
1191 compile_expr(c, rhs);
1192 emit_slot_op(c, OP_STR_ALC_SNAPSHOT, slot);
1193 }
1194 set_local_inferred_type(c, local, SV_TI_UNKNOWN);
1195 return true;
1196}
1197
1198
1199static inline bool is_ident_name(sv_ast_t *node, const char *name) {
1200 size_t n = strlen(name);
1201 return node
1202 && node->type == N_IDENT && node->len == (uint32_t)n
1203 && memcmp(node->str, name, n) == 0;
1204}
1205
1206static void hoist_var_pattern(sv_compiler_t *c, sv_ast_t *pat) {
1207 if (!pat) return;
1208 switch (pat->type) {
1209 case N_IDENT:
1210 if (resolve_local(c, pat->str, pat->len) == -1)
1211 add_local(c, pat->str, pat->len, false, 0);
1212 break;
1213 case N_ARRAY: case N_ARRAY_PAT:
1214 for (int i = 0; i < pat->args.count; i++)
1215 hoist_var_pattern(c, pat->args.items[i]);
1216 break;
1217 case N_OBJECT: case N_OBJECT_PAT:
1218 for (int i = 0; i < pat->args.count; i++) {
1219 sv_ast_t *prop = pat->args.items[i];
1220 if (!prop) continue;
1221 if (prop->type == N_PROPERTY)
1222 hoist_var_pattern(c, prop->right);
1223 else if (prop->type == N_REST || prop->type == N_SPREAD)
1224 hoist_var_pattern(c, prop->right);
1225 }
1226 break;
1227 case N_ASSIGN_PAT:
1228 hoist_var_pattern(c, pat->left);
1229 break;
1230 case N_ASSIGN:
1231 hoist_var_pattern(c, pat->left);
1232 break;
1233 case N_REST: case N_SPREAD:
1234 hoist_var_pattern(c, pat->right);
1235 break;
1236 default:
1237 break;
1238 }
1239}
1240
1241static void hoist_var_decls(sv_compiler_t *c, sv_ast_t *node) {
1242 if (!node) return;
1243 switch (node->type) {
1244 case N_VAR:
1245 if (node->var_kind == SV_VAR_VAR) {
1246 for (int i = 0; i < node->args.count; i++) {
1247 sv_ast_t *decl = node->args.items[i];
1248 if (decl->type == N_VARDECL && decl->left)
1249 hoist_var_pattern(c, decl->left);
1250 }
1251 }
1252 break;
1253 case N_BLOCK:
1254 for (int i = 0; i < node->args.count; i++)
1255 hoist_var_decls(c, node->args.items[i]);
1256 break;
1257 case N_IF:
1258 hoist_var_decls(c, node->left);
1259 hoist_var_decls(c, node->right);
1260 break;
1261 case N_WHILE: case N_DO_WHILE: case N_LABEL:
1262 hoist_var_decls(c, node->body);
1263 break;
1264 case N_FOR:
1265 hoist_var_decls(c, node->init);
1266 hoist_var_decls(c, node->body);
1267 break;
1268 case N_FOR_IN: case N_FOR_OF: case N_FOR_AWAIT_OF:
1269 hoist_var_decls(c, node->left);
1270 hoist_var_decls(c, node->body);
1271 break;
1272 case N_SWITCH:
1273 for (int i = 0; i < node->args.count; i++) {
1274 sv_ast_t *cas = node->args.items[i];
1275 for (int j = 0; j < cas->args.count; j++)
1276 hoist_var_decls(c, cas->args.items[j]);
1277 }
1278 break;
1279 case N_TRY:
1280 hoist_var_decls(c, node->body);
1281 hoist_var_decls(c, node->catch_body);
1282 hoist_var_decls(c, node->finally_body);
1283 break;
1284 case N_EXPORT:
1285 hoist_var_decls(c, node->left);
1286 break;
1287 default: break;
1288 }
1289}
1290
1291static void hoist_lexical_pattern(sv_compiler_t *c, sv_ast_t *pat,
1292 bool is_const) {
1293 if (!pat) return;
1294
1295 switch (pat->type) {
1296 case N_IDENT:
1297 ensure_local_at_depth(c, pat->str, pat->len, is_const, c->scope_depth);
1298 break;
1299 case N_ASSIGN_PAT:
1300 case N_ASSIGN:
1301 hoist_lexical_pattern(c, pat->left, is_const);
1302 break;
1303 case N_REST:
1304 case N_SPREAD:
1305 hoist_lexical_pattern(c, pat->right, is_const);
1306 break;
1307 case N_ARRAY:
1308 case N_ARRAY_PAT:
1309 for (int i = 0; i < pat->args.count; i++)
1310 hoist_lexical_pattern(c, pat->args.items[i], is_const);
1311 break;
1312 case N_OBJECT:
1313 case N_OBJECT_PAT:
1314 for (int i = 0; i < pat->args.count; i++) {
1315 sv_ast_t *prop = pat->args.items[i];
1316 if (!prop) continue;
1317 if (prop->type == N_PROPERTY)
1318 hoist_lexical_pattern(c, prop->right, is_const);
1319 else if (prop->type == N_REST || prop->type == N_SPREAD)
1320 hoist_lexical_pattern(c, prop->right, is_const);
1321 }
1322 break;
1323 default:
1324 break;
1325 }
1326}
1327
1328static void annex_b_collect_funcs(sv_ast_t *node, sv_ast_list_t *out) {
1329 if (!node) return;
1330 if (node->type == N_FUNC && node->str && !(node->flags & (FN_ARROW | FN_PAREN))) {
1331 sv_ast_list_push(out, node);
1332 return;
1333 }
1334 if (node->type == N_IF) {
1335 annex_b_collect_funcs(node->left, out);
1336 annex_b_collect_funcs(node->right, out);
1337 } else if (node->type == N_LABEL) annex_b_collect_funcs(node->body, out);
1338}
1339
1340static void hoist_lexical_decls(sv_compiler_t *c, sv_ast_list_t *stmts) {
1341 for (int i = 0; i < stmts->count; i++) {
1342 sv_ast_t *node = stmts->items[i];
1343 if (!node) continue;
1344 sv_ast_t *decl_node = (node->type == N_EXPORT) ? node->left : node;
1345 if (!decl_node) continue;
1346
1347 if (decl_node->type == N_VAR && decl_node->var_kind != SV_VAR_VAR) {
1348 bool is_const =
1349 (decl_node->var_kind == SV_VAR_CONST ||
1350 decl_node->var_kind == SV_VAR_USING ||
1351 decl_node->var_kind == SV_VAR_AWAIT_USING);
1352 int lb = c->local_count;
1353 for (int j = 0; j < decl_node->args.count; j++) {
1354 sv_ast_t *decl = decl_node->args.items[j];
1355 if (!decl || decl->type != N_VARDECL || !decl->left) continue;
1356 hoist_lexical_pattern(c, decl->left, is_const);
1357 }
1358 for (int j = lb; j < c->local_count; j++) {
1359 c->locals[j].is_tdz = true;
1360 set_local_inferred_type(c, j, SV_TI_UNKNOWN);
1361 int slot = j - c->param_locals;
1362 emit_op(c, OP_SET_LOCAL_UNDEF);
1363 emit_u16(c, (uint16_t)slot);
1364 }
1365 } else if (decl_node->type == N_IMPORT_DECL) {
1366 for (int j = 0; j < decl_node->args.count; j++) {
1367 sv_ast_t *spec = decl_node->args.items[j];
1368 if (!spec || spec->type != N_IMPORT_SPEC ||
1369 !spec->right || spec->right->type != N_IDENT)
1370 continue;
1371 ensure_local_at_depth(c, spec->right->str, spec->right->len, true, c->scope_depth);
1372 }
1373 } else if (decl_node->type == N_CLASS && decl_node->str) {
1374 int lb = c->local_count;
1375 ensure_local_at_depth(c, decl_node->str, decl_node->len, false, c->scope_depth);
1376 if (c->local_count > lb) {
1377 c->locals[c->local_count - 1].is_tdz = true;
1378 set_local_inferred_type(c, c->local_count - 1, SV_TI_UNKNOWN);
1379 int slot = (c->local_count - 1) - c->param_locals;
1380 emit_op(c, OP_SET_LOCAL_UNDEF);
1381 emit_u16(c, (uint16_t)slot);
1382 }
1383 } else if (decl_node->type == N_FUNC && decl_node->str && !(decl_node->flags & (FN_ARROW | FN_PAREN))) {
1384 ensure_local_at_depth(c, decl_node->str, decl_node->len, false, c->scope_depth);
1385 }
1386 if (!c->is_strict && (decl_node->type == N_IF || decl_node->type == N_LABEL)) {
1387 sv_ast_list_t funcs = {0};
1388 annex_b_collect_funcs(decl_node, &funcs);
1389 for (int j = 0; j < funcs.count; j++) {
1390 sv_ast_t *fn = funcs.items[j];
1391 if (resolve_local(c, fn->str, fn->len) == -1)
1392 add_local(c, fn->str, fn->len, false, c->scope_depth);
1393 }
1394 }
1395 }
1396}
1397
1398static void hoist_one_func(sv_compiler_t *c, sv_ast_t *node) {
1399 sv_func_t *fn = compile_function_body(c, node, c->mode);
1400 if (!fn) return;
1401 int idx = add_constant(c, mkval(T_NTARG, (uintptr_t)fn));
1402 emit_op(c, OP_CLOSURE);
1403 emit_u32(c, (uint32_t)idx);
1404 emit_set_function_name(c, node->str, node->len);
1405 if (is_repl_top_level(c)) {
1406 emit_atom_op(c, OP_PUT_GLOBAL, node->str, node->len);
1407 } else {
1408 int local = resolve_local(c, node->str, node->len);
1409 emit_put_local(c, local);
1410 }
1411}
1412
1413static void hoist_func_decls(sv_compiler_t *c, sv_ast_list_t *stmts) {
1414 for (int i = 0; i < stmts->count; i++) {
1415 sv_ast_t *node = stmts->items[i];
1416 if (node && node->type == N_EXPORT && node->left)
1417 node = node->left;
1418 if (!node) continue;
1419 if (node->type == N_FUNC && node->str && !(node->flags & (FN_ARROW | FN_PAREN))) {
1420 hoist_one_func(c, node);
1421 }
1422 if (!c->is_strict && (node->type == N_IF || node->type == N_LABEL)) {
1423 sv_ast_list_t funcs = {0};
1424 annex_b_collect_funcs(node, &funcs);
1425 for (int j = 0; j < funcs.count; j++)
1426 hoist_one_func(c, funcs.items[j]);
1427 }
1428 }
1429}
1430
1431static uint8_t infer_expr_type(sv_compiler_t *c, sv_ast_t *node) {
1432 if (!node) return SV_TI_UNDEF;
1433
1434 switch (node->type) {
1435 case N_NUMBER: return SV_TI_NUM;
1436 case N_STRING: return SV_TI_STR;
1437 case N_BOOL: return SV_TI_BOOL;
1438 case N_NULL: return SV_TI_NULL;
1439 case N_UNDEF: return SV_TI_UNDEF;
1440 case N_ARRAY: return SV_TI_ARR;
1441 case N_OBJECT: return SV_TI_OBJ;
1442 case N_TEMPLATE: return SV_TI_STR;
1443 case N_TYPEOF: return SV_TI_STR;
1444 case N_VOID: return SV_TI_UNDEF;
1445 case N_NEW: return SV_TI_OBJ;
1446
1447 case N_IDENT: {
1448 int local = resolve_local(c, node->str, node->len);
1449 if (local >= 0) return get_local_inferred_type(c, local);
1450 return SV_TI_UNKNOWN;
1451 }
1452
1453 case N_SEQUENCE:
1454 return infer_expr_type(c, node->right);
1455
1456 case N_TERNARY: {
1457 uint8_t lt = infer_expr_type(c, node->left);
1458 uint8_t rhs_type = infer_expr_type(c, node->right);
1459 if (lt == rhs_type && sv_type_is_known(lt)) return lt;
1460 return SV_TI_UNKNOWN;
1461 }
1462
1463 case N_UNARY: {
1464 uint8_t rhs_type = infer_expr_type(c, node->right);
1465 switch (node->op) {
1466 case TOK_UPLUS:
1467 case TOK_UMINUS:
1468 return sv_type_is_num(rhs_type) ? SV_TI_NUM : SV_TI_UNKNOWN;
1469 case TOK_NOT:
1470 return SV_TI_BOOL;
1471 default:
1472 return SV_TI_UNKNOWN;
1473 }
1474 }
1475
1476 case N_BINARY: {
1477 uint8_t lt = infer_expr_type(c, node->left);
1478 uint8_t rhs_type = infer_expr_type(c, node->right);
1479 switch (node->op) {
1480 case TOK_PLUS:
1481 if (lt == SV_TI_NUM && rhs_type == SV_TI_NUM) return SV_TI_NUM;
1482 if (lt == SV_TI_STR && rhs_type == SV_TI_STR) return SV_TI_STR;
1483 return SV_TI_UNKNOWN;
1484 case TOK_MINUS:
1485 case TOK_MUL:
1486 case TOK_DIV:
1487 return (lt == SV_TI_NUM && rhs_type == SV_TI_NUM) ? SV_TI_NUM : SV_TI_UNKNOWN;
1488 case TOK_LT:
1489 case TOK_LE:
1490 case TOK_GT:
1491 case TOK_GE:
1492 case TOK_EQ:
1493 case TOK_NE:
1494 case TOK_SEQ:
1495 case TOK_SNE:
1496 case TOK_INSTANCEOF:
1497 case TOK_IN:
1498 return SV_TI_BOOL;
1499 case TOK_LAND:
1500 case TOK_LOR:
1501 case TOK_NULLISH:
1502 if (lt == rhs_type && sv_type_is_known(lt)) return lt;
1503 return SV_TI_UNKNOWN;
1504 default:
1505 return SV_TI_UNKNOWN;
1506 }
1507 }
1508
1509 default:
1510 return SV_TI_UNKNOWN;
1511 }
1512}
1513
1514static void compile_yield_star_expr(sv_compiler_t *c, sv_ast_t *node) {
1515 if (node->right) compile_expr(c, node->right);
1516 else emit_op(c, OP_UNDEF);
1517
1518 int base_local = reserve_hidden_locals(c, 4);
1519 uint16_t base_slot = (uint16_t)(base_local - c->param_locals);
1520
1521 emit_op(c, OP_YIELD_STAR_INIT);
1522 emit_u16(c, base_slot);
1523
1524 emit_op(c, OP_UNDEF);
1525 emit_op(c, OP_YIELD_STAR_NEXT);
1526 emit_u16(c, base_slot);
1527}
1528
1529void compile_expr(sv_compiler_t *c, sv_ast_t *node) {
1530 if (!node) { emit_op(c, OP_UNDEF); return; }
1531 emit_srcpos(c, node);
1532
1533 switch (node->type) {
1534 case N_NUMBER:
1535 emit_number(c, node->num);
1536 break;
1537
1538 case N_STRING: {
1539 emit_constant(c, ast_string_const(c, node));
1540 break;
1541 }
1542
1543 case N_BIGINT: {
1544 bool neg = false;
1545 const char *digits = node->str;
1546 uint32_t dlen = node->len;
1547 if (dlen > 0 && digits[0] == '-') {
1548 neg = true; digits++; dlen--;
1549 }
1550 if (dlen > 0 && digits[dlen - 1] == 'n') dlen--;
1551 ant_value_t bi = js_mkbigint(c->js, digits, dlen, neg);
1552 emit_constant(c, bi);
1553 break;
1554 }
1555
1556 case N_BOOL:
1557 emit_op(c, node->num != 0.0 ? OP_TRUE : OP_FALSE);
1558 break;
1559
1560 case N_NULL:
1561 emit_op(c, OP_NULL);
1562 break;
1563
1564 case N_UNDEF:
1565 emit_op(c, OP_UNDEF);
1566 break;
1567
1568 case N_THIS:
1569 emit_op(c, OP_THIS);
1570 break;
1571
1572 case N_GLOBAL_THIS:
1573 emit_op(c, OP_GLOBAL);
1574 break;
1575
1576 case N_NEW_TARGET: {
1577 static const char nt_name[] = "\x01new.target";
1578 int local = resolve_local(c, nt_name, sizeof(nt_name) - 1);
1579 if (local >= 0) {
1580 emit_get_local(c, local);
1581 } else {
1582 int upval = resolve_upvalue(c, nt_name, sizeof(nt_name) - 1);
1583 if (upval >= 0) {
1584 emit_op(c, OP_GET_UPVAL);
1585 emit_u16(c, (uint16_t)upval);
1586 } else {
1587 emit_op(c, OP_UNDEF);
1588 }
1589 }
1590 break;
1591 }
1592
1593 case N_IDENT:
1594 if (is_private_name_node(node)) {
1595 js_mkerr_typed(c->js, JS_ERR_SYNTAX, "Private names may only be used as class member names");
1596 emit_op(c, OP_UNDEF);
1597 break;
1598 }
1599 emit_get_var(c, node->str, node->len);
1600 break;
1601
1602 case N_BINARY:
1603 compile_binary(c, node);
1604 break;
1605
1606 case N_UNARY:
1607 compile_unary(c, node);
1608 break;
1609
1610 case N_UPDATE:
1611 compile_update(c, node);
1612 break;
1613
1614 case N_ASSIGN:
1615 compile_assign(c, node);
1616 break;
1617
1618 case N_TERNARY:
1619 compile_ternary(c, node);
1620 break;
1621
1622 case N_CALL:
1623 compile_call(c, node);
1624 break;
1625
1626 case N_NEW:
1627 compile_new(c, node);
1628 break;
1629
1630 case N_MEMBER:
1631 compile_member(c, node);
1632 break;
1633
1634 case N_OPTIONAL:
1635 compile_optional(c, node);
1636 break;
1637
1638 case N_ARRAY:
1639 compile_array(c, node);
1640 break;
1641
1642 case N_OBJECT:
1643 compile_object(c, node);
1644 break;
1645
1646 case N_FUNC:
1647 compile_func_expr(c, node);
1648 break;
1649
1650 case N_CLASS:
1651 compile_class(c, node);
1652 break;
1653
1654 case N_SEQUENCE:
1655 compile_expr(c, node->left);
1656 emit_op(c, OP_POP);
1657 compile_expr(c, node->right);
1658 break;
1659
1660 case N_TYPEOF:
1661 compile_typeof(c, node);
1662 break;
1663
1664 case N_VOID:
1665 compile_expr(c, node->right);
1666 emit_op(c, OP_VOID);
1667 break;
1668
1669 case N_DELETE:
1670 compile_delete(c, node);
1671 break;
1672
1673 case N_SPREAD:
1674 compile_expr(c, node->right);
1675 break;
1676
1677 case N_TEMPLATE:
1678 compile_template(c, node);
1679 break;
1680
1681 case N_AWAIT:
1682 compile_expr(c, node->right);
1683 emit_op(c, OP_AWAIT);
1684 if (c->enclosing && !c->enclosing->enclosing)
1685 c->is_tla = true;
1686 break;
1687
1688 case N_YIELD:
1689 if (node->flags) compile_yield_star_expr(c, node);
1690 else {
1691 if (node->right) compile_expr(c, node->right);
1692 else emit_op(c, OP_UNDEF);
1693 emit_op(c, OP_YIELD);
1694 }
1695 break;
1696
1697 case N_THROW:
1698 compile_expr(c, node->right);
1699 emit_op(c, OP_THROW);
1700 break;
1701
1702 case N_TAGGED_TEMPLATE: {
1703 compile_expr(c, node->left);
1704 sv_ast_t *tpl = node->right;
1705 int n = tpl->args.count;
1706 int n_strings = 0, n_exprs = 0;
1707 for (int i = 0; i < n; i++) {
1708 if (is_template_segment(tpl->args.items[i])) n_strings++;
1709 else n_exprs++;
1710 }
1711 int cache_idx = add_constant(c, js_mkundef());
1712 emit_op(c, OP_CONST);
1713 emit_u32(c, (uint32_t)cache_idx);
1714 int skip_jump = emit_jump(c, OP_JMP_TRUE_PEEK);
1715 emit_op(c, OP_POP);
1716 for (int i = 0; i < n; i++) {
1717 sv_ast_t *item = tpl->args.items[i];
1718 if (!is_template_segment(item)) continue;
1719 if (is_invalid_cooked_string(item))
1720 emit_op(c, OP_UNDEF);
1721 else emit_constant(c, ast_string_const(c, item));
1722 }
1723 emit_op(c, OP_ARRAY);
1724 emit_u16(c, (uint16_t)n_strings);
1725 for (int i = 0; i < n; i++) {
1726 sv_ast_t *item = tpl->args.items[i];
1727 if (!is_template_segment(item)) continue;
1728 const char *raw = item->aux ? item->aux : item->str;
1729 uint32_t raw_len = item->aux ? item->aux_len : item->len;
1730 emit_constant(c, js_mkstr_permanent(c->js, raw ? raw : "", raw_len));
1731 }
1732 emit_op(c, OP_ARRAY);
1733 emit_u16(c, (uint16_t)n_strings);
1734 emit_atom_op(c, OP_GET_GLOBAL, "Object", 6);
1735 emit_atom_op(c, OP_GET_FIELD2, "freeze", 6);
1736 emit_op(c, OP_ROT3L);
1737 emit_op(c, OP_CALL_METHOD);
1738 emit_u16(c, 1);
1739 emit_atom_op(c, OP_DEFINE_FIELD, "raw", 3);
1740 emit_atom_op(c, OP_GET_GLOBAL, "Object", 6);
1741 emit_atom_op(c, OP_GET_FIELD2, "freeze", 6);
1742 emit_op(c, OP_ROT3L);
1743 emit_op(c, OP_CALL_METHOD);
1744 emit_u16(c, 1);
1745 emit_op(c, OP_SET_BRAND);
1746 emit(c, BRAND_TEMPLATE_OBJECT);
1747 emit_op(c, OP_DUP);
1748 emit_op(c, OP_PUT_CONST);
1749 emit_u32(c, (uint32_t)cache_idx);
1750 patch_jump(c, skip_jump);
1751 for (int i = 0; i < n; i++) {
1752 sv_ast_t *item = tpl->args.items[i];
1753 if (is_template_segment(item)) continue;
1754 compile_expr(c, item);
1755 }
1756 emit_op(c, OP_CALL);
1757 emit_u16(c, (uint16_t)(1 + n_exprs));
1758 break;
1759 }
1760
1761 case N_IMPORT:
1762 compile_expr(c, node->right);
1763 if (has_module_import_binding(c)) {
1764 emit_get_module_import_binding(c);
1765 emit_op(c, OP_SWAP);
1766 emit_op(c, OP_CALL);
1767 emit_u16(c, 1);
1768 } else emit_op(c, OP_IMPORT);
1769 break;
1770
1771 case N_REGEXP:
1772 emit_constant(c, js_mkstr_permanent(c->js, node->str ? node->str : "", node->len));
1773 emit_constant(c, js_mkstr_permanent(c->js, node->aux ? node->aux : "", node->aux_len));
1774 emit_op(c, OP_REGEXP);
1775 break;
1776
1777 default:
1778 emit_op(c, OP_UNDEF);
1779 break;
1780 }
1781}
1782
1783void compile_binary(sv_compiler_t *c, sv_ast_t *node) {
1784 uint8_t op = node->op;
1785
1786 if (op == TOK_LAND) {
1787 compile_expr(c, node->left);
1788 int jump = emit_jump(c, OP_JMP_FALSE_PEEK);
1789 emit_op(c, OP_POP);
1790 compile_expr(c, node->right);
1791 patch_jump(c, jump);
1792 return;
1793 }
1794
1795 if (op == TOK_LOR) {
1796 compile_expr(c, node->left);
1797 int jump = emit_jump(c, OP_JMP_TRUE_PEEK);
1798 emit_op(c, OP_POP);
1799 compile_expr(c, node->right);
1800 patch_jump(c, jump);
1801 return;
1802 }
1803
1804 if (op == TOK_NULLISH) {
1805 compile_expr(c, node->left);
1806 int jump = emit_jump(c, OP_JMP_NOT_NULLISH);
1807 emit_op(c, OP_POP);
1808 compile_expr(c, node->right);
1809 patch_jump(c, jump);
1810 return;
1811 }
1812
1813 if (op == TOK_IN && node->left->type == N_IDENT &&
1814 node->left->len > 0 && node->left->str[0] == '#') {
1815 compile_expr(c, node->right);
1816 emit_private_token(c, node->left);
1817 emit_op(c, OP_HAS_PRIVATE);
1818 return;
1819 }
1820
1821 uint8_t left_type = SV_TI_UNKNOWN;
1822 uint8_t right_type = SV_TI_UNKNOWN;
1823 if (op == TOK_PLUS || op == TOK_MINUS || op == TOK_MUL || op == TOK_DIV) {
1824 left_type = infer_expr_type(c, node->left);
1825 right_type = infer_expr_type(c, node->right);
1826 }
1827
1828 compile_expr(c, node->left);
1829 compile_expr(c, node->right);
1830
1831 switch (op) {
1832 case TOK_PLUS:
1833 emit_op(c, (left_type == SV_TI_NUM && right_type == SV_TI_NUM) ? OP_ADD_NUM : OP_ADD);
1834 break;
1835 case TOK_MINUS:
1836 emit_op(c, (left_type == SV_TI_NUM && right_type == SV_TI_NUM) ? OP_SUB_NUM : OP_SUB);
1837 break;
1838 case TOK_MUL:
1839 emit_op(c, (left_type == SV_TI_NUM && right_type == SV_TI_NUM) ? OP_MUL_NUM : OP_MUL);
1840 break;
1841 case TOK_DIV:
1842 emit_op(c, (left_type == SV_TI_NUM && right_type == SV_TI_NUM) ? OP_DIV_NUM : OP_DIV);
1843 break;
1844 case TOK_REM: emit_op(c, OP_MOD); break;
1845 case TOK_EXP: emit_op(c, OP_EXP); break;
1846 case TOK_LT: emit_op(c, OP_LT); break;
1847 case TOK_LE: emit_op(c, OP_LE); break;
1848 case TOK_GT: emit_op(c, OP_GT); break;
1849 case TOK_GE: emit_op(c, OP_GE); break;
1850 case TOK_EQ: emit_op(c, OP_EQ); break;
1851 case TOK_NE: emit_op(c, OP_NE); break;
1852 case TOK_SEQ: emit_op(c, OP_SEQ); break;
1853 case TOK_SNE: emit_op(c, OP_SNE); break;
1854 case TOK_AND: emit_op(c, OP_BAND); break;
1855 case TOK_OR: emit_op(c, OP_BOR); break;
1856 case TOK_XOR: emit_op(c, OP_BXOR); break;
1857 case TOK_SHL: emit_op(c, OP_SHL); break;
1858 case TOK_SHR: emit_op(c, OP_SHR); break;
1859 case TOK_ZSHR: emit_op(c, OP_USHR); break;
1860 case TOK_INSTANCEOF:
1861 emit_op(c, OP_INSTANCEOF);
1862 emit_u16(c, alloc_ic_idx(c));
1863 break;
1864 case TOK_IN: emit_op(c, OP_IN); break;
1865 default: emit_op(c, OP_UNDEF); break;
1866 }
1867}
1868
1869void compile_unary(sv_compiler_t *c, sv_ast_t *node) {
1870 compile_expr(c, node->right);
1871 switch (node->op) {
1872 case TOK_NOT: emit_op(c, OP_NOT); break;
1873 case TOK_TILDA: emit_op(c, OP_BNOT); break;
1874 case TOK_UPLUS: emit_op(c, OP_UPLUS); break;
1875 case TOK_UMINUS: emit_op(c, OP_NEG); break;
1876 default: break;
1877 }
1878}
1879
1880
1881void compile_update(sv_compiler_t *c, sv_ast_t *node) {
1882 bool prefix = (node->flags & 1);
1883 bool is_inc = (node->op == TOK_POSTINC);
1884 sv_ast_t *target = node->right;
1885
1886 if (target->type == N_IDENT) {
1887 if (prefix) {
1888 emit_get_var(c, target->str, target->len);
1889 emit_op(c, is_inc ? OP_INC : OP_DEC);
1890 emit_set_var(c, target->str, target->len, true);
1891 } else {
1892 emit_get_var(c, target->str, target->len);
1893 emit_op(c, is_inc ? OP_POST_INC : OP_POST_DEC);
1894 emit_set_var(c, target->str, target->len, false);
1895 }
1896 } else if (target->type == N_MEMBER && !(target->flags & 1) && is_private_name_node(target->right)) {
1897 compile_expr(c, target->left);
1898 emit_op(c, OP_DUP);
1899 emit_private_token(c, target->right);
1900 emit_op(c, OP_GET_PRIVATE);
1901 if (prefix) {
1902 emit_op(c, is_inc ? OP_INC : OP_DEC);
1903 emit_private_token(c, target->right);
1904 emit_op(c, OP_PUT_PRIVATE);
1905 } else {
1906 emit_op(c, is_inc ? OP_POST_INC : OP_POST_DEC);
1907 emit_op(c, OP_SWAP_UNDER);
1908 emit_private_token(c, target->right);
1909 emit_op(c, OP_PUT_PRIVATE);
1910 emit_op(c, OP_POP);
1911 }
1912 } else if (target->type == N_MEMBER && !(target->flags & 1)) {
1913 compile_expr(c, target->left);
1914 emit_op(c, OP_DUP);
1915 int atom = add_atom(c, target->right->str, target->right->len);
1916 emit_atom_idx_op(c, OP_GET_FIELD, (uint32_t)atom);
1917 if (prefix) {
1918 emit_op(c, is_inc ? OP_INC : OP_DEC);
1919 emit_op(c, OP_INSERT2);
1920 emit_atom_idx_op(c, OP_PUT_FIELD, (uint32_t)atom);
1921 } else {
1922 emit_op(c, is_inc ? OP_POST_INC : OP_POST_DEC);
1923 emit_op(c, OP_SWAP_UNDER);
1924 emit_atom_idx_op(c, OP_PUT_FIELD, (uint32_t)atom);
1925 }
1926 } else if (target->type == N_MEMBER && (target->flags & 1)) {
1927 compile_expr(c, target->left);
1928 compile_expr(c, target->right);
1929 emit_op(c, OP_DUP2);
1930 emit_op(c, OP_GET_ELEM);
1931 if (prefix) {
1932 emit_op(c, is_inc ? OP_INC : OP_DEC);
1933 emit_op(c, OP_INSERT3);
1934 emit_op(c, OP_PUT_ELEM);
1935 } else {
1936 emit_op(c, is_inc ? OP_POST_INC : OP_POST_DEC);
1937 emit_op(c, OP_ROT4_UNDER);
1938 emit_op(c, OP_PUT_ELEM);
1939 }
1940 } else {
1941 emit_op(c, OP_UNDEF);
1942 }
1943}
1944
1945void compile_assign(sv_compiler_t *c, sv_ast_t *node) {
1946 sv_ast_t *target = node->left;
1947 uint8_t op = node->op;
1948 int append_local = -1;
1949 uint16_t append_slot = 0;
1950 sv_ast_t *append_rhs = NULL;
1951
1952 bool can_append_builder = match_self_append_local(
1953 c, node, &append_local,
1954 &append_slot, &append_rhs
1955 );
1956
1957 if (op == TOK_ASSIGN) {
1958 if (target->type == N_MEMBER && !(target->flags & 1) && is_private_name_node(target->right)) {
1959 compile_expr(c, target->left);
1960 compile_expr(c, node->right);
1961 emit_private_token(c, target->right);
1962 emit_op(c, OP_PUT_PRIVATE);
1963 return;
1964 }
1965
1966 if (target->type == N_MEMBER && !(target->flags & 1)) {
1967 int atom = add_atom(c, target->right->str, target->right->len);
1968 compile_expr(c, target->left);
1969 compile_expr(c, node->right);
1970 emit_op(c, OP_INSERT2);
1971 emit_atom_idx_op(c, OP_PUT_FIELD, (uint32_t)atom);
1972 return;
1973 }
1974
1975 if (target->type == N_MEMBER && (target->flags & 1)) {
1976 compile_expr(c, target->left);
1977 compile_expr(c, target->right);
1978 compile_expr(c, node->right);
1979 emit_op(c, OP_INSERT3);
1980 emit_op(c, OP_PUT_ELEM);
1981 return;
1982 }
1983
1984 if (can_append_builder) {
1985 if (is_self_append_inplace_safe_expr(c, append_rhs)) {
1986 compile_expr(c, append_rhs);
1987 emit_slot_op(c, OP_STR_APPEND_LOCAL, append_slot);
1988 } else {
1989 emit_slot_op(c, OP_GET_SLOT_RAW, append_slot);
1990 compile_expr(c, append_rhs);
1991 emit_slot_op(c, OP_STR_ALC_SNAPSHOT, append_slot);
1992 }
1993 emit_get_var(c, target->str, target->len);
1994 set_local_inferred_type(c, append_local, SV_TI_UNKNOWN);
1995 return;
1996 }
1997
1998 compile_expr(c, node->right);
1999 compile_lhs_set(c, target, true);
2000 return;
2001 }
2002
2003 if (target->type == N_IDENT) {
2004 int lhs_local = resolve_local(c, target->str, target->len);
2005 uint8_t lhs_type = (lhs_local >= 0) ? get_local_inferred_type(c, lhs_local) : SV_TI_UNKNOWN;
2006 uint8_t rhs_type = infer_expr_type(c, node->right);
2007
2008 if (can_append_builder) {
2009 if (is_self_append_inplace_safe_expr(c, append_rhs)) {
2010 compile_expr(c, append_rhs);
2011 emit_slot_op(c, OP_STR_APPEND_LOCAL, append_slot);
2012 } else {
2013 emit_slot_op(c, OP_GET_SLOT_RAW, append_slot);
2014 compile_expr(c, append_rhs);
2015 emit_slot_op(c, OP_STR_ALC_SNAPSHOT, append_slot);
2016 }
2017 emit_get_var(c, target->str, target->len);
2018 set_local_inferred_type(c, append_local, SV_TI_UNKNOWN);
2019 return;
2020 }
2021
2022 if (op == TOK_PLUS_ASSIGN) {
2023 int slot = resolve_local_slot(c, target->str, target->len);
2024 if (slot >= 0 && !c->locals[slot + c->param_locals].is_const) {
2025 sv_ast_t *rhs = node->right;
2026 bool rhs_pure = rhs && (
2027 rhs->type == N_NUMBER || rhs->type == N_STRING ||
2028 rhs->type == N_BOOL || rhs->type == N_NULL ||
2029 rhs->type == N_UNDEF || rhs->type == N_IDENT
2030 );
2031 if (rhs_pure) {
2032 compile_expr(c, rhs);
2033 emit_op(c, OP_ADD_LOCAL);
2034 emit(c, (uint8_t)slot);
2035 emit_get_local(c, c->param_locals + slot);
2036 set_local_inferred_type(c, c->param_locals + slot, SV_TI_UNKNOWN);
2037 return;
2038 }
2039 }
2040 }
2041
2042 if (op == TOK_LOR_ASSIGN || op == TOK_LAND_ASSIGN ||
2043 op == TOK_NULLISH_ASSIGN) {
2044 emit_get_var(c, target->str, target->len);
2045 int skip = emit_jump(c,
2046 op == TOK_LOR_ASSIGN ? OP_JMP_TRUE_PEEK :
2047 op == TOK_LAND_ASSIGN ? OP_JMP_FALSE_PEEK : OP_JMP_NOT_NULLISH);
2048 emit_op(c, OP_POP);
2049 compile_expr(c, node->right);
2050 emit_set_var(c, target->str, target->len, true);
2051 patch_jump(c, skip);
2052 return;
2053 }
2054
2055 emit_get_var(c, target->str, target->len);
2056 compile_expr(c, node->right);
2057 switch (op) {
2058 case TOK_PLUS_ASSIGN:
2059 emit_op(c, (lhs_type == SV_TI_NUM && rhs_type == SV_TI_NUM) ? OP_ADD_NUM : OP_ADD);
2060 break;
2061 case TOK_MINUS_ASSIGN:
2062 emit_op(c, (lhs_type == SV_TI_NUM && rhs_type == SV_TI_NUM) ? OP_SUB_NUM : OP_SUB);
2063 break;
2064 case TOK_MUL_ASSIGN:
2065 emit_op(c, (lhs_type == SV_TI_NUM && rhs_type == SV_TI_NUM) ? OP_MUL_NUM : OP_MUL);
2066 break;
2067 case TOK_DIV_ASSIGN:
2068 emit_op(c, (lhs_type == SV_TI_NUM && rhs_type == SV_TI_NUM) ? OP_DIV_NUM : OP_DIV);
2069 break;
2070 case TOK_REM_ASSIGN: emit_op(c, OP_MOD); break;
2071 case TOK_SHL_ASSIGN: emit_op(c, OP_SHL); break;
2072 case TOK_SHR_ASSIGN: emit_op(c, OP_SHR); break;
2073 case TOK_ZSHR_ASSIGN: emit_op(c, OP_USHR); break;
2074 case TOK_AND_ASSIGN: emit_op(c, OP_BAND); break;
2075 case TOK_XOR_ASSIGN: emit_op(c, OP_BXOR); break;
2076 case TOK_OR_ASSIGN: emit_op(c, OP_BOR); break;
2077 case TOK_EXP_ASSIGN: emit_op(c, OP_EXP); break;
2078 default: break;
2079 }
2080 emit_set_var(c, target->str, target->len, true);
2081 } else if (target->type == N_MEMBER && !(target->flags & 1) && is_private_name_node(target->right)) {
2082 if (op == TOK_LOR_ASSIGN || op == TOK_LAND_ASSIGN ||
2083 op == TOK_NULLISH_ASSIGN) {
2084 compile_expr(c, target->left);
2085 emit_op(c, OP_DUP);
2086 emit_private_token(c, target->right);
2087 emit_op(c, OP_GET_PRIVATE);
2088 int skip = emit_jump(c,
2089 op == TOK_LOR_ASSIGN ? OP_JMP_TRUE_PEEK :
2090 op == TOK_LAND_ASSIGN ? OP_JMP_FALSE_PEEK : OP_JMP_NOT_NULLISH);
2091 emit_op(c, OP_POP);
2092 compile_expr(c, node->right);
2093 emit_private_token(c, target->right);
2094 emit_op(c, OP_PUT_PRIVATE);
2095 int end = emit_jump(c, OP_JMP);
2096 patch_jump(c, skip);
2097 emit_op(c, OP_NIP);
2098 patch_jump(c, end);
2099 return;
2100 }
2101
2102 compile_expr(c, target->left);
2103 emit_op(c, OP_DUP);
2104 emit_private_token(c, target->right);
2105 emit_op(c, OP_GET_PRIVATE);
2106 compile_expr(c, node->right);
2107 switch (op) {
2108 case TOK_PLUS_ASSIGN: emit_op(c, OP_ADD); break;
2109 case TOK_MINUS_ASSIGN: emit_op(c, OP_SUB); break;
2110 case TOK_MUL_ASSIGN: emit_op(c, OP_MUL); break;
2111 case TOK_DIV_ASSIGN: emit_op(c, OP_DIV); break;
2112 case TOK_REM_ASSIGN: emit_op(c, OP_MOD); break;
2113 case TOK_SHL_ASSIGN: emit_op(c, OP_SHL); break;
2114 case TOK_SHR_ASSIGN: emit_op(c, OP_SHR); break;
2115 case TOK_ZSHR_ASSIGN: emit_op(c, OP_USHR); break;
2116 case TOK_AND_ASSIGN: emit_op(c, OP_BAND); break;
2117 case TOK_XOR_ASSIGN: emit_op(c, OP_BXOR); break;
2118 case TOK_OR_ASSIGN: emit_op(c, OP_BOR); break;
2119 case TOK_EXP_ASSIGN: emit_op(c, OP_EXP); break;
2120 default: break;
2121 }
2122 emit_private_token(c, target->right);
2123 emit_op(c, OP_PUT_PRIVATE);
2124 } else if (target->type == N_MEMBER && !(target->flags & 1)) {
2125 int atom = add_atom(c, target->right->str, target->right->len);
2126
2127 if (op == TOK_LOR_ASSIGN || op == TOK_LAND_ASSIGN ||
2128 op == TOK_NULLISH_ASSIGN) {
2129 compile_expr(c, target->left);
2130 emit_op(c, OP_DUP);
2131 emit_atom_idx_op(c, OP_GET_FIELD, (uint32_t)atom);
2132 int skip = emit_jump(c,
2133 op == TOK_LOR_ASSIGN ? OP_JMP_TRUE_PEEK :
2134 op == TOK_LAND_ASSIGN ? OP_JMP_FALSE_PEEK : OP_JMP_NOT_NULLISH);
2135 emit_op(c, OP_POP);
2136 compile_expr(c, node->right);
2137 emit_op(c, OP_INSERT2);
2138 emit_atom_idx_op(c, OP_PUT_FIELD, (uint32_t)atom);
2139 int end = emit_jump(c, OP_JMP);
2140 patch_jump(c, skip);
2141 emit_op(c, OP_NIP);
2142 patch_jump(c, end);
2143 return;
2144 }
2145
2146 compile_expr(c, target->left);
2147 emit_op(c, OP_DUP);
2148 emit_atom_idx_op(c, OP_GET_FIELD, (uint32_t)atom);
2149 compile_expr(c, node->right);
2150 switch (op) {
2151 case TOK_PLUS_ASSIGN: emit_op(c, OP_ADD); break;
2152 case TOK_MINUS_ASSIGN: emit_op(c, OP_SUB); break;
2153 case TOK_MUL_ASSIGN: emit_op(c, OP_MUL); break;
2154 case TOK_DIV_ASSIGN: emit_op(c, OP_DIV); break;
2155 case TOK_REM_ASSIGN: emit_op(c, OP_MOD); break;
2156 case TOK_SHL_ASSIGN: emit_op(c, OP_SHL); break;
2157 case TOK_SHR_ASSIGN: emit_op(c, OP_SHR); break;
2158 case TOK_ZSHR_ASSIGN: emit_op(c, OP_USHR); break;
2159 case TOK_AND_ASSIGN: emit_op(c, OP_BAND); break;
2160 case TOK_XOR_ASSIGN: emit_op(c, OP_BXOR); break;
2161 case TOK_OR_ASSIGN: emit_op(c, OP_BOR); break;
2162 case TOK_EXP_ASSIGN: emit_op(c, OP_EXP); break;
2163 default: break;
2164 }
2165 emit_op(c, OP_INSERT2);
2166 emit_atom_idx_op(c, OP_PUT_FIELD, (uint32_t)atom);
2167 } else if (target->type == N_MEMBER && (target->flags & 1)) {
2168
2169 if (op == TOK_LOR_ASSIGN || op == TOK_LAND_ASSIGN ||
2170 op == TOK_NULLISH_ASSIGN) {
2171 compile_expr(c, target->left);
2172 compile_expr(c, target->right);
2173 emit_op(c, OP_DUP2);
2174 emit_op(c, OP_GET_ELEM);
2175 int skip = emit_jump(c,
2176 op == TOK_LOR_ASSIGN ? OP_JMP_TRUE_PEEK :
2177 op == TOK_LAND_ASSIGN ? OP_JMP_FALSE_PEEK : OP_JMP_NOT_NULLISH);
2178 emit_op(c, OP_POP);
2179 compile_expr(c, node->right);
2180 emit_op(c, OP_INSERT3);
2181 emit_op(c, OP_PUT_ELEM);
2182 int end = emit_jump(c, OP_JMP);
2183 patch_jump(c, skip);
2184 emit_op(c, OP_NIP2);
2185 patch_jump(c, end);
2186 return;
2187 }
2188
2189 compile_expr(c, target->left);
2190 compile_expr(c, target->right);
2191 emit_op(c, OP_DUP2);
2192 emit_op(c, OP_GET_ELEM);
2193 compile_expr(c, node->right);
2194 switch (op) {
2195 case TOK_PLUS_ASSIGN: emit_op(c, OP_ADD); break;
2196 case TOK_MINUS_ASSIGN: emit_op(c, OP_SUB); break;
2197 case TOK_MUL_ASSIGN: emit_op(c, OP_MUL); break;
2198 case TOK_DIV_ASSIGN: emit_op(c, OP_DIV); break;
2199 case TOK_REM_ASSIGN: emit_op(c, OP_MOD); break;
2200 case TOK_SHL_ASSIGN: emit_op(c, OP_SHL); break;
2201 case TOK_SHR_ASSIGN: emit_op(c, OP_SHR); break;
2202 case TOK_ZSHR_ASSIGN: emit_op(c, OP_USHR); break;
2203 case TOK_AND_ASSIGN: emit_op(c, OP_BAND); break;
2204 case TOK_XOR_ASSIGN: emit_op(c, OP_BXOR); break;
2205 case TOK_OR_ASSIGN: emit_op(c, OP_BOR); break;
2206 case TOK_EXP_ASSIGN: emit_op(c, OP_EXP); break;
2207 default: break;
2208 }
2209 emit_op(c, OP_INSERT3);
2210 emit_op(c, OP_PUT_ELEM);
2211 } else {
2212 compile_expr(c, node->right);
2213 }
2214}
2215
2216void compile_lhs_set(sv_compiler_t *c, sv_ast_t *target, bool keep) {
2217 if (target->type == N_IDENT) {
2218 emit_set_var(c, target->str, target->len, keep);
2219 } else if (target->type == N_MEMBER && !(target->flags & 1) && is_private_name_node(target->right)) {
2220 (void)keep;
2221 compile_expr(c, target->left);
2222 emit_op(c, OP_SWAP);
2223 emit_private_token(c, target->right);
2224 emit_op(c, OP_PUT_PRIVATE);
2225 } else if (target->type == N_MEMBER && !(target->flags & 1)) {
2226 if (keep) emit_op(c, OP_DUP);
2227 compile_expr(c, target->left);
2228 emit_op(c, OP_SWAP);
2229 emit_atom_op(c, OP_PUT_FIELD, target->right->str, target->right->len);
2230 } else if (target->type == N_MEMBER && (target->flags & 1)) {
2231 if (keep) emit_op(c, OP_DUP);
2232 compile_expr(c, target->left);
2233 compile_expr(c, target->right);
2234 emit_op(c, OP_ROT3L);
2235 emit_op(c, OP_PUT_ELEM);
2236 } else if (target->type == N_ARRAY_PAT || target->type == N_ARRAY) {
2237 compile_array_destructure(c, target, keep);
2238 } else if (target->type == N_OBJECT_PAT || target->type == N_OBJECT) {
2239 compile_object_destructure(c, target, keep);
2240 }
2241}
2242
2243void compile_ternary(sv_compiler_t *c, sv_ast_t *node) {
2244 compile_truthy_test_expr(c, node->cond);
2245 int else_jump = emit_jump(c, OP_JMP_FALSE);
2246 compile_expr(c, node->left);
2247 int end_jump = emit_jump(c, OP_JMP);
2248 patch_jump(c, else_jump);
2249 compile_expr(c, node->right);
2250 patch_jump(c, end_jump);
2251}
2252
2253void compile_typeof(sv_compiler_t *c, sv_ast_t *node) {
2254 sv_ast_t *arg = node->right;
2255 if (arg->type == N_IDENT) {
2256 int local = resolve_local(c, arg->str, arg->len);
2257 if (local != -1) {
2258 uint8_t inferred = get_local_inferred_type(c, local);
2259 const char *known = typeof_name_for_type(inferred);
2260 if (known) {
2261 emit_constant(c, js_mkstr_permanent(c->js, known, strlen(known)));
2262 return;
2263 }
2264 emit_get_var(c, arg->str, arg->len);
2265 } else {
2266 int upval = resolve_upvalue(c, arg->str, arg->len);
2267 if (upval != -1) {
2268 emit_op(c, OP_GET_UPVAL);
2269 emit_u16(c, (uint16_t)upval);
2270 } else if (
2271 has_implicit_arguments_obj(c) &&
2272 is_ident_str(arg->str, arg->len, "arguments", 9)
2273 ) {
2274 if (c->strict_args_local >= 0) {
2275 emit_get_local(c, c->strict_args_local);
2276 } else {
2277 emit_op(c, OP_SPECIAL_OBJ);
2278 emit(c, 0);
2279 }
2280 } else emit_atom_op(c, OP_GET_GLOBAL_UNDEF, arg->str, arg->len);
2281 }
2282 } else compile_expr(c, arg);
2283 emit_op(c, OP_TYPEOF);
2284}
2285
2286static bool sv_node_has_optional_base(sv_ast_t *n) {
2287 while (n) {
2288 if (n->type == N_OPTIONAL) return true;
2289 if (n->type == N_MEMBER || n->type == N_CALL) n = n->left;
2290 else break;
2291 }
2292 return false;
2293}
2294
2295static void compile_delete_optional(sv_compiler_t *c, sv_ast_t *arg) {
2296 compile_expr(c, arg->left);
2297 int ok_jump = emit_jump(c, OP_JMP_NOT_NULLISH);
2298 emit_op(c, OP_POP);
2299 emit_op(c, OP_TRUE);
2300 int end_jump = emit_jump(c, OP_JMP);
2301 patch_jump(c, ok_jump);
2302 if (arg->flags & 1) {
2303 compile_expr(c, arg->right);
2304 } else {
2305 ant_value_t key = js_mkstr_permanent(c->js, arg->right->str, arg->right->len);
2306 emit_constant(c, key);
2307 }
2308 emit_op(c, OP_DELETE);
2309 patch_jump(c, end_jump);
2310}
2311
2312void compile_delete(sv_compiler_t *c, sv_ast_t *node) {
2313 sv_ast_t *arg = node->right;
2314 if ((arg->type == N_MEMBER || arg->type == N_OPTIONAL) &&
2315 arg->right && is_private_name_node(arg->right)) {
2316 js_mkerr_typed(c->js, JS_ERR_SYNTAX, "Cannot delete private fields");
2317 emit_op(c, OP_TRUE);
2318 return;
2319 }
2320 if (arg->type == N_OPTIONAL) {
2321 compile_delete_optional(c, arg);
2322 } else if (arg->type == N_MEMBER && sv_node_has_optional_base(arg->left)) {
2323 compile_delete_optional(c, arg);
2324 } else if (arg->type == N_MEMBER && !(arg->flags & 1)) {
2325 compile_expr(c, arg->left);
2326 ant_value_t key = js_mkstr_permanent(c->js, arg->right->str, arg->right->len);
2327 emit_constant(c, key);
2328 emit_op(c, OP_DELETE);
2329 } else if (arg->type == N_MEMBER && (arg->flags & 1)) {
2330 compile_expr(c, arg->left);
2331 compile_expr(c, arg->right);
2332 emit_op(c, OP_DELETE);
2333 } else if (arg->type == N_IDENT) {
2334 emit_atom_op(c, OP_DELETE_VAR, arg->str, arg->len);
2335 } else {
2336 compile_expr(c, arg);
2337 emit_op(c, OP_POP);
2338 emit_op(c, OP_TRUE);
2339 }
2340}
2341
2342void compile_template(sv_compiler_t *c, sv_ast_t *node) {
2343 int n = node->args.count;
2344 if (n == 0) {
2345 emit_constant(c, js_mkstr_permanent(c->js, "", 0));
2346 return;
2347 }
2348 for (int i = 0; i < n; i++) {
2349 sv_ast_t *item = node->args.items[i];
2350 if (is_invalid_cooked_string(item)) {
2351 static const char msg[] = "Invalid or unexpected token";
2352 int atom = add_atom(c, msg, sizeof(msg) - 1);
2353 emit_op(c, OP_THROW_ERROR);
2354 emit_u32(c, (uint32_t)atom);
2355 emit(c, (uint8_t)JS_ERR_SYNTAX);
2356 return;
2357 }
2358 }
2359 compile_expr(c, node->args.items[0]);
2360 if (!is_template_segment(node->args.items[0]))
2361 emit_op(c, OP_TO_PROPKEY);
2362 for (int i = 1; i < n; i++) {
2363 compile_expr(c, node->args.items[i]);
2364 if (!is_template_segment(node->args.items[i]))
2365 emit_op(c, OP_TO_PROPKEY);
2366 emit_op(c, OP_ADD);
2367 }
2368}
2369
2370static bool call_has_spread_arg(const sv_ast_t *node) {
2371 if (!node) return false;
2372 for (int i = 0; i < node->args.count; i++) {
2373 sv_ast_t *arg = node->args.items[i];
2374 if (arg && arg->type == N_SPREAD) return true;
2375 }
2376 return false;
2377}
2378
2379static void compile_push_arg_to_array(sv_compiler_t *c, sv_ast_t *arg) {
2380 emit_op(c, OP_DUP);
2381 emit_op(c, OP_DUP);
2382 emit_atom_op(c, OP_GET_FIELD, "push", 4);
2383 compile_expr(c, arg);
2384 emit_op(c, OP_CALL_METHOD);
2385 emit_u16(c, 1);
2386 emit_op(c, OP_POP);
2387}
2388
2389static void compile_concat_spread_to_array(sv_compiler_t *c, sv_ast_t *spread_arg) {
2390 compile_expr(c, spread_arg->right);
2391 emit_op(c, OP_SPREAD);
2392}
2393
2394static void compile_call_args_array(sv_compiler_t *c, sv_ast_t *call_node) {
2395 emit_op(c, OP_ARRAY);
2396 emit_u16(c, 0);
2397 for (int i = 0; i < call_node->args.count; i++) {
2398 sv_ast_t *arg = call_node->args.items[i];
2399 if (arg && arg->type == N_SPREAD) compile_concat_spread_to_array(c, arg);
2400 else compile_push_arg_to_array(c, arg);
2401 }
2402}
2403
2404typedef enum {
2405 SV_CALL_DIRECT = 0,
2406 SV_CALL_METHOD = 1,
2407 SV_CALL_SUPER = 2,
2408} sv_call_kind_t;
2409
2410static inline bool sv_call_kind_has_receiver(sv_call_kind_t kind) {
2411 return kind == SV_CALL_METHOD || kind == SV_CALL_SUPER;
2412}
2413
2414static void compile_receiver_property_get(sv_compiler_t *c, sv_ast_t *node) {
2415 emit_op(c, OP_DUP);
2416 if (node->flags & 1) {
2417 compile_expr(c, node->right);
2418 emit_op(c, OP_GET_ELEM);
2419 } else if (is_private_name_node(node->right)) {
2420 emit_private_token(c, node->right);
2421 emit_op(c, OP_GET_PRIVATE);
2422 } else {
2423 emit_srcpos(c, node->right);
2424 emit_atom_op(c, OP_GET_FIELD, node->right->str, node->right->len);
2425 }
2426}
2427
2428static void compile_call_emit_invoke(
2429 sv_compiler_t *c, sv_ast_t *node,
2430 sv_call_kind_t kind, bool has_spread
2431) {
2432 int argc = node->args.count;
2433 if (has_spread) {
2434 if (sv_call_kind_has_receiver(kind)) emit_op(c, OP_SWAP);
2435 else emit_op(c, OP_GLOBAL);
2436 compile_call_args_array(c, node);
2437 emit_op(c, kind == SV_CALL_SUPER ? OP_SUPER_APPLY : OP_APPLY);
2438 emit_u16(c, 1);
2439 return;
2440 }
2441
2442 for (int i = 0; i < argc; i++)
2443 compile_expr(c, node->args.items[i]);
2444 emit_op(c, sv_call_kind_has_receiver(kind) ? OP_CALL_METHOD : OP_CALL);
2445 emit_u16(c, (uint16_t)argc);
2446}
2447
2448static sv_call_kind_t compile_call_setup_non_optional(sv_compiler_t *c, sv_ast_t *callee) {
2449 if (is_ident_name(callee, "super")) {
2450 emit_op(c, OP_THIS);
2451 emit_get_var(c, "super", 5);
2452 return SV_CALL_SUPER;
2453 }
2454
2455 if (callee->type == N_MEMBER && is_ident_name(callee->left, "super")) {
2456 if (!(callee->flags & 1) && is_private_name_node(callee->right)) {
2457 js_mkerr_typed(c->js, JS_ERR_SYNTAX, "Cannot access private member through super");
2458 emit_op(c, OP_UNDEF);
2459 return SV_CALL_DIRECT;
2460 }
2461 emit_op(c, OP_THIS);
2462 emit_op(c, OP_THIS);
2463 emit_get_var(c, "super", 5);
2464 if (callee->flags & 1)
2465 compile_expr(c, callee->right);
2466 else
2467 emit_constant(c, js_mkstr_permanent(c->js, callee->right->str, callee->right->len));
2468 emit_op(c, OP_GET_SUPER_VAL);
2469 return SV_CALL_METHOD;
2470 }
2471
2472 if (callee->type == N_MEMBER) {
2473 compile_expr(c, callee->left);
2474 compile_receiver_property_get(c, callee);
2475 return SV_CALL_METHOD;
2476 }
2477
2478 compile_expr(c, callee);
2479 return SV_CALL_DIRECT;
2480}
2481
2482static bool compile_call_is_proto_intrinsic(
2483 sv_compiler_t *c, sv_ast_t *node, bool has_spread
2484) {
2485 if (!node || has_spread || node->args.count != 1) return false;
2486 sv_ast_t *callee = node->left;
2487 if (!callee || callee->type != N_MEMBER) return false;
2488 if ((callee->flags & 1) || !callee->right || !callee->right->str) return false;
2489 if (is_ident_name(callee->left, "super")) return false;
2490 if (!is_ident_str(callee->right->str, callee->right->len, "isPrototypeOf", 13))
2491 return false;
2492
2493 compile_expr(c, callee->left);
2494 compile_receiver_property_get(c, callee);
2495 compile_expr(c, node->args.items[0]);
2496 emit_op(c, OP_CALL_IS_PROTO);
2497 emit_u16(c, alloc_ic_idx(c));
2498 return true;
2499}
2500
2501static bool compile_call_array_includes_intrinsic(
2502 sv_compiler_t *c, sv_ast_t *node, bool has_spread
2503) {
2504 if (!node || has_spread || node->args.count > UINT16_MAX) return false;
2505 sv_ast_t *callee = node->left;
2506
2507 if (!callee || callee->type != N_MEMBER) return false;
2508 if ((callee->flags & 1) || !callee->right || !callee->right->str) return false;
2509 if (is_ident_name(callee->left, "super")) return false;
2510 if (!is_ident_str(callee->right->str, callee->right->len, "includes", 8))
2511 return false;
2512
2513 compile_expr(c, callee->left);
2514 compile_receiver_property_get(c, callee);
2515 for (int i = 0; i < node->args.count; i++)
2516 compile_expr(c, node->args.items[i]);
2517 emit_op(c, OP_CALL_ARRAY_INCLUDES);
2518 emit_u16(c, (uint16_t)node->args.count);
2519
2520 return true;
2521}
2522
2523static bool compile_regexp_exec_truthy_intrinsic(
2524 sv_compiler_t *c, sv_ast_t *node
2525) {
2526 if (!node || node->type != N_CALL || call_has_spread_arg(node) || node->args.count != 1)
2527 return false;
2528
2529 sv_ast_t *callee = node->left;
2530 if (!callee || callee->type != N_MEMBER) return false;
2531 if ((callee->flags & 1) || !callee->right || !callee->right->str) return false;
2532 if (is_ident_name(callee->left, "super")) return false;
2533 if (!is_ident_str(callee->right->str, callee->right->len, "exec", 4))
2534 return false;
2535
2536 compile_expr(c, callee->left);
2537 compile_receiver_property_get(c, callee);
2538 compile_expr(c, node->args.items[0]);
2539 emit_op(c, OP_RE_EXEC_TRUTHY);
2540
2541 return true;
2542}
2543
2544static void compile_truthy_test_expr(sv_compiler_t *c, sv_ast_t *node) {
2545 if (compile_regexp_exec_truthy_intrinsic(c, node)) return;
2546 compile_expr(c, node);
2547}
2548
2549static void compile_optional_call_after_setup(
2550 sv_compiler_t *c, sv_ast_t *call_node,
2551 sv_call_kind_t kind, bool has_spread
2552) {
2553 emit_op(c, OP_DUP);
2554 emit_op(c, OP_IS_UNDEF_OR_NULL);
2555 int j_do_call = emit_jump(c, OP_JMP_FALSE);
2556 emit_op(c, OP_POP);
2557 if (sv_call_kind_has_receiver(kind))
2558 emit_op(c, OP_POP);
2559 emit_op(c, OP_UNDEF);
2560 int j_end = emit_jump(c, OP_JMP);
2561 patch_jump(c, j_do_call);
2562 compile_call_emit_invoke(c, call_node, kind, has_spread);
2563 patch_jump(c, j_end);
2564}
2565
2566static void compile_call_optional(
2567 sv_compiler_t *c, sv_ast_t *node,
2568 sv_ast_t *opt_callee, bool has_spread
2569) {
2570 if (opt_callee->right) {
2571 compile_expr(c, opt_callee->left);
2572 emit_op(c, OP_DUP);
2573 emit_op(c, OP_IS_UNDEF_OR_NULL);
2574 int j_have_obj = emit_jump(c, OP_JMP_FALSE);
2575 emit_op(c, OP_POP);
2576 emit_op(c, OP_UNDEF);
2577 int j_end = emit_jump(c, OP_JMP);
2578 patch_jump(c, j_have_obj);
2579
2580 compile_receiver_property_get(c, opt_callee);
2581 compile_call_emit_invoke(c, node, SV_CALL_METHOD, has_spread);
2582 patch_jump(c, j_end);
2583
2584 return;
2585 }
2586
2587 sv_ast_t *target = opt_callee->left;
2588 if (target && target->type == N_OPTIONAL && target->right) {
2589 compile_expr(c, target->left);
2590 emit_op(c, OP_DUP);
2591 emit_op(c, OP_IS_UNDEF_OR_NULL);
2592 int j_have_obj = emit_jump(c, OP_JMP_FALSE);
2593 emit_op(c, OP_POP);
2594 emit_op(c, OP_UNDEF);
2595 int j_end = emit_jump(c, OP_JMP);
2596 patch_jump(c, j_have_obj);
2597
2598 compile_receiver_property_get(c, target);
2599 compile_optional_call_after_setup(c, node, SV_CALL_METHOD, has_spread);
2600 patch_jump(c, j_end);
2601 return;
2602 }
2603
2604 sv_call_kind_t kind = compile_call_setup_non_optional(c, target);
2605 compile_optional_call_after_setup(c, node, kind, has_spread);
2606}
2607
2608void compile_call(sv_compiler_t *c, sv_ast_t *node) {
2609 sv_ast_t *callee = node->left;
2610 bool has_spread = call_has_spread_arg(node);
2611
2612 if (callee->type == N_OPTIONAL) {
2613 compile_call_optional(c, node, callee, has_spread);
2614 return;
2615 }
2616
2617 if (compile_call_is_proto_intrinsic(c, node, has_spread))
2618 return;
2619
2620 if (compile_call_array_includes_intrinsic(c, node, has_spread))
2621 return;
2622
2623 if (
2624 !has_spread && node->args.count >= 2 &&
2625 callee->type == N_MEMBER &&
2626 is_ident_name(callee->left, "Ant") &&
2627 resolve_local(c, "Ant", 3) == -1 &&
2628 callee->right && callee->right->type == N_IDENT &&
2629 callee->right->len == 5 && memcmp(callee->right->str, "match", 5) == 0 &&
2630 node->args.items[1]->type == N_OBJECT
2631 ) {
2632 sv_ast_t *obj = node->args.items[1];
2633 sv_ast_t *param = sv_ast_new(N_IDENT);
2634
2635 param->str = "$"; param->len = 1;
2636 sv_ast_t *arrow = sv_ast_new(N_FUNC);
2637
2638 arrow->flags = FN_ARROW;
2639 arrow->body = obj;
2640 arrow->line = obj->line; arrow->col = obj->col;
2641 arrow->src_off = obj->src_off; arrow->src_end = obj->src_end;
2642
2643 sv_ast_list_push(&arrow->args, param);
2644 node->args.items[1] = arrow;
2645 }
2646
2647 if (!has_spread && is_ident_name(callee, "eval")) {
2648 if (node->args.count > 0)
2649 compile_expr(c, node->args.items[0]);
2650 else
2651 emit_op(c, OP_UNDEF);
2652 for (int i = 1; i < node->args.count; i++) {
2653 compile_expr(c, node->args.items[i]);
2654 emit_op(c, OP_POP);
2655 }
2656
2657 emit_op(c, OP_EVAL);
2658 emit_u32(c, 0);
2659
2660 return;
2661 }
2662
2663 if (callee->type == N_MEMBER && sv_node_has_optional_base(callee->left)) {
2664 compile_expr(c, callee->left);
2665 int ok_jump = emit_jump(c, OP_JMP_NOT_NULLISH);
2666 emit_op(c, OP_POP);
2667 emit_op(c, OP_UNDEF);
2668 int end_jump = emit_jump(c, OP_JMP);
2669 patch_jump(c, ok_jump);
2670 compile_receiver_property_get(c, callee);
2671 compile_call_emit_invoke(c, node, SV_CALL_METHOD, has_spread);
2672 patch_jump(c, end_jump);
2673 return;
2674 }
2675
2676 sv_call_kind_t kind = compile_call_setup_non_optional(c, callee);
2677 compile_call_emit_invoke(c, node, kind, has_spread);
2678}
2679
2680void compile_new(sv_compiler_t *c, sv_ast_t *node) {
2681 compile_expr(c, node->left);
2682 emit_op(c, OP_DUP);
2683 if (call_has_spread_arg(node)) {
2684 compile_call_args_array(c, node);
2685 emit_op(c, OP_NEW_APPLY);
2686 emit_u16(c, 1);
2687 } else {
2688 int argc = node->args.count;
2689 for (int i = 0; i < argc; i++)
2690 compile_expr(c, node->args.items[i]);
2691 emit_op(c, OP_NEW);
2692 emit_u16(c, (uint16_t)argc);
2693 }
2694}
2695
2696void compile_member(sv_compiler_t *c, sv_ast_t *node) {
2697 if (is_ident_name(node->left, "super")) {
2698 if (!(node->flags & 1) && is_private_name_node(node->right)) {
2699 js_mkerr_typed(c->js, JS_ERR_SYNTAX, "Cannot access private member through super");
2700 emit_op(c, OP_UNDEF);
2701 return;
2702 }
2703 emit_op(c, OP_THIS);
2704 emit_get_var(c, "super", 5);
2705 if (node->flags & 1)
2706 compile_expr(c, node->right);
2707 else
2708 emit_constant(c, js_mkstr_permanent(c->js, node->right->str, node->right->len));
2709 emit_op(c, OP_GET_SUPER_VAL);
2710 return;
2711 }
2712
2713 compile_expr(c, node->left);
2714
2715 int ok_jump = -1, end_jump = -1;
2716 if (sv_node_has_optional_base(node->left)) {
2717 ok_jump = emit_jump(c, OP_JMP_NOT_NULLISH);
2718 end_jump = emit_jump(c, OP_JMP);
2719 patch_jump(c, ok_jump);
2720 }
2721
2722 if (node->flags & 1) {
2723 compile_expr(c, node->right);
2724 emit_op(c, OP_GET_ELEM);
2725 } else if (is_private_name_node(node->right)) {
2726 emit_private_token(c, node->right);
2727 emit_op(c, OP_GET_PRIVATE);
2728 } else {
2729 if (node->right->len == 6 && memcmp(node->right->str, "length", 6) == 0)
2730 emit_op(c, OP_GET_LENGTH);
2731 else {
2732 emit_srcpos(c, node->right);
2733 emit_atom_op(c, OP_GET_FIELD, node->right->str, node->right->len);
2734 }
2735 }
2736
2737 if (end_jump >= 0) patch_jump(c, end_jump);
2738}
2739
2740void compile_optional_get(sv_compiler_t *c, sv_ast_t *node) {
2741 if (node->flags & 1) {
2742 compile_expr(c, node->right);
2743 emit_op(c, OP_GET_ELEM_OPT);
2744 } else if (is_private_name_node(node->right)) {
2745 emit_private_token(c, node->right);
2746 emit_op(c, OP_GET_PRIVATE_OPT);
2747 } else {
2748 emit_srcpos(c, node->right);
2749 emit_atom_op(c, OP_GET_FIELD_OPT, node->right->str, node->right->len);
2750 }
2751}
2752
2753void compile_optional(sv_compiler_t *c, sv_ast_t *node) {
2754 compile_expr(c, node->left);
2755 compile_optional_get(c, node);
2756}
2757
2758void compile_array(sv_compiler_t *c, sv_ast_t *node) {
2759 int count = node->args.count;
2760 bool has_spread = false;
2761 for (int i = 0; i < count; i++) {
2762 sv_ast_t *elem = node->args.items[i];
2763 if (elem && elem->type == N_SPREAD) {
2764 has_spread = true;
2765 break;
2766 }
2767 }
2768
2769 if (!has_spread) {
2770 for (int i = 0; i < count; i++) {
2771 sv_ast_t *elem = node->args.items[i];
2772 if (elem && elem->type == N_EMPTY)
2773 emit_op(c, OP_EMPTY);
2774 else
2775 compile_expr(c, elem);
2776 }
2777 emit_op(c, OP_ARRAY);
2778 emit_u16(c, (uint16_t)count);
2779 return;
2780 }
2781
2782 emit_op(c, OP_ARRAY);
2783 emit_u16(c, 0);
2784 for (int i = 0; i < count; i++) {
2785 sv_ast_t *elem = node->args.items[i];
2786 if (elem && elem->type == N_SPREAD) compile_concat_spread_to_array(c, elem);
2787 else compile_push_arg_to_array(c, elem);
2788 }
2789}
2790
2791void compile_object(sv_compiler_t *c, sv_ast_t *node) {
2792 emit_op(c, OP_OBJECT);
2793 for (int i = 0; i < node->args.count; i++) {
2794 sv_ast_t *prop = node->args.items[i];
2795 if (prop->type == N_SPREAD) {
2796 compile_expr(c, prop->right);
2797 emit_op(c, OP_COPY_DATA_PROPS);
2798 emit(c, 0);
2799 emit_op(c, OP_POP);
2800 continue;
2801 }
2802
2803 if (prop->type != N_PROPERTY) continue;
2804 if (prop->flags & FN_GETTER || prop->flags & FN_SETTER) {
2805 compile_expr(c, prop->right);
2806 uint8_t flags = 0;
2807 if (prop->flags & FN_GETTER) flags |= SV_DEFINE_METHOD_GETTER;
2808 if (prop->flags & FN_SETTER) flags |= SV_DEFINE_METHOD_SETTER;
2809 flags |= SV_DEFINE_METHOD_SET_NAME;
2810 if (prop->flags & FN_COMPUTED) compile_expr(c, prop->left);
2811 else compile_static_property_key(c, prop->left);
2812 emit_op(c, OP_SWAP);
2813 emit_op(c, OP_DEFINE_METHOD_COMP);
2814 emit(c, flags);
2815 } else if (prop->flags & FN_COMPUTED) {
2816 compile_expr(c, prop->left);
2817 compile_expr(c, prop->right);
2818 emit_op(c, OP_DEFINE_METHOD_COMP);
2819 emit(c, node_needs_inferred_function_name(prop->right) ? SV_DEFINE_METHOD_SET_NAME : 0);
2820 } else {
2821 if (prop->left && prop->left->type == N_IDENT && !is_quoted_ident_key(prop->left))
2822 compile_expr_with_inferred_name(c, prop->right, prop->left->str, prop->left->len);
2823 else compile_expr(c, prop->right);
2824 if ((prop->flags & FN_COLON) &&
2825 prop->left->type == N_IDENT && !is_quoted_ident_key(prop->left) &&
2826 is_ident_str(prop->left->str, prop->left->len, "__proto__", 9)) {
2827 emit_op(c, OP_SET_PROTO);
2828 continue;
2829 }
2830 if (prop->left->type == N_IDENT && !is_quoted_ident_key(prop->left)) {
2831 emit_atom_op(c, OP_DEFINE_FIELD, prop->left->str, prop->left->len);
2832 } else if (is_quoted_ident_key(prop->left)) {
2833 emit_atom_op(c, OP_DEFINE_FIELD, prop->left->str + 1, prop->left->len - 2);
2834 } else if (prop->left->type == N_STRING) {
2835 emit_atom_op(c, OP_DEFINE_FIELD, prop->left->str ? prop->left->str : "", prop->left->len);
2836 } else if (prop->left->type == N_NUMBER) {
2837 char buf[32];
2838 int n = snprintf(buf, sizeof(buf), "%g", prop->left->num);
2839 emit_atom_op(c, OP_DEFINE_FIELD, buf, (uint32_t)n);
2840 } else emit_atom_op(c, OP_DEFINE_FIELD, prop->left->str, prop->left->len);
2841 }
2842 }
2843}
2844
2845void compile_func_expr(sv_compiler_t *c, sv_ast_t *node) {
2846 bool has_name = node->str && node->len > 0 && !(node->flags & FN_ARROW);
2847 int name_local = -1;
2848
2849 if (has_name) {
2850 begin_scope(c);
2851 name_local = add_local(c, node->str, node->len, true, c->scope_depth);
2852 emit_op(c, OP_UNDEF);
2853 emit_put_local(c, name_local);
2854 }
2855
2856 sv_func_t *fn = compile_function_body(c, node, SV_COMPILE_SCRIPT);
2857 if (!fn) {
2858 emit_op(c, OP_UNDEF);
2859 if (has_name) end_scope(c);
2860 return;
2861 }
2862
2863 int idx = add_constant(c, mkval(T_NTARG, (uintptr_t)fn));
2864 emit_op(c, OP_CLOSURE);
2865 emit_u32(c, (uint32_t)idx);
2866
2867 if (node->str && node->len > 0) {
2868 emit_set_function_name(c, node->str, node->len);
2869 } else if (c->inferred_name) {
2870 emit_set_function_name(c, c->inferred_name, c->inferred_name_len);
2871 c->inferred_name = NULL;
2872 c->inferred_name_len = 0;
2873 } else {
2874 emit_set_function_name(c, NULL, 0);
2875 }
2876
2877 if (has_name) {
2878 emit_op(c, OP_DUP);
2879 emit_put_local(c, name_local);
2880 end_scope(c);
2881 }
2882}
2883
2884typedef enum {
2885 DESTRUCTURE_ASSIGN = 0,
2886 DESTRUCTURE_BIND = 1,
2887} sv_destructure_mode_t;
2888
2889static void emit_build_object_rest(sv_compiler_t *c) {
2890 emit_op(c, OP_DUP);
2891 emit_op(c, OP_OBJECT);
2892 emit_op(c, OP_SWAP);
2893 emit_op(c, OP_COPY_DATA_PROPS);
2894 emit(c, 0);
2895 emit_op(c, OP_POP);
2896}
2897
2898static void emit_delete_rest_key(sv_compiler_t *c, sv_ast_t *key) {
2899 emit_op(c, OP_DUP);
2900 if (key->type == N_IDENT) {
2901 emit_constant(c, js_mkstr_permanent(c->js, key->str, key->len));
2902 } else if (key->type == N_STRING) {
2903 emit_constant(c, ast_string_const(c, key));
2904 } else if (key->type == N_NUMBER) {
2905 emit_number(c, key->num);
2906 } else {
2907 compile_expr(c, key);
2908 }
2909 emit_op(c, OP_DELETE);
2910 emit_op(c, OP_POP);
2911}
2912
2913static bool is_destructure_pattern_node(sv_ast_t *node) {
2914 return node && (node->type == N_ARRAY_PAT || node->type == N_ARRAY ||
2915 node->type == N_OBJECT_PAT || node->type == N_OBJECT);
2916}
2917
2918static void compile_destructure_pattern(sv_compiler_t *c, sv_ast_t *pat,
2919 bool keep, bool consume_source,
2920 sv_destructure_mode_t mode,
2921 sv_var_kind_t kind);
2922
2923static void compile_destructure_store(sv_compiler_t *c, sv_ast_t *target,
2924 sv_destructure_mode_t mode,
2925 sv_var_kind_t kind) {
2926 if (!target) return;
2927
2928 if (mode == DESTRUCTURE_ASSIGN) {
2929 compile_lhs_set(c, target, false);
2930 return;
2931 }
2932
2933 if (target->type == N_IDENT) {
2934 bool is_const = (kind == SV_VAR_CONST);
2935 int idx = ensure_local_at_depth(c, target->str, target->len,
2936 is_const, c->scope_depth);
2937 emit_put_local(c, idx);
2938 return;
2939 }
2940
2941 if (is_destructure_pattern_node(target)) {
2942 compile_destructure_pattern(c, target, false, true, mode, kind);
2943 return;
2944 }
2945
2946 compile_lhs_set(c, target, false);
2947}
2948
2949static void compile_destructure_pattern(
2950 sv_compiler_t *c, sv_ast_t *pat,
2951 bool keep, bool consume_source,
2952 sv_destructure_mode_t mode,
2953 sv_var_kind_t kind
2954) {
2955 if (!pat) return;
2956 if (keep) emit_op(c, OP_DUP);
2957
2958 if (pat->type == N_ARRAY_PAT || pat->type == N_ARRAY) {
2959 if (!consume_source && !keep) emit_op(c, OP_DUP);
2960 emit_op(c, OP_DESTRUCTURE_INIT);
2961
2962 int err_local = add_local(c, "", 0, false, c->scope_depth);
2963 int try_jump = emit_jump(c, OP_TRY_PUSH);
2964 c->try_depth++;
2965
2966 for (int i = 0; i < pat->args.count; i++) {
2967 sv_ast_t *elem = pat->args.items[i];
2968 if (!elem || elem->type == N_EMPTY) {
2969 emit_op(c, OP_DESTRUCTURE_NEXT);
2970 emit_op(c, OP_POP);
2971 continue;
2972 }
2973
2974 if (elem->type == N_REST || elem->type == N_SPREAD) {
2975 emit_op(c, OP_DESTRUCTURE_REST);
2976 compile_destructure_store(c, elem->right, mode, kind);
2977 continue;
2978 }
2979
2980 sv_ast_t *target = elem;
2981 sv_ast_t *default_val = NULL;
2982 if (elem->type == N_ASSIGN_PAT ||
2983 (elem->type == N_ASSIGN && elem->op == TOK_ASSIGN)) {
2984 target = elem->left;
2985 default_val = elem->right;
2986 }
2987
2988 emit_op(c, OP_DESTRUCTURE_NEXT);
2989
2990 if (default_val) {
2991 emit_op(c, OP_DUP);
2992 emit_op(c, OP_IS_UNDEF);
2993 int skip = emit_jump(c, OP_JMP_FALSE);
2994 emit_op(c, OP_POP);
2995 compile_expr(c, default_val);
2996 patch_jump(c, skip);
2997 }
2998
2999 compile_destructure_store(c, target, mode, kind);
3000 }
3001
3002 emit_op(c, OP_TRY_POP);
3003 emit_op(c, OP_DESTRUCTURE_CLOSE);
3004 int end_jump = emit_jump(c, OP_JMP);
3005
3006 patch_jump(c, try_jump);
3007 int catch_tag = emit_jump(c, OP_CATCH);
3008
3009 emit_put_local(c, err_local);
3010 emit_op(c, OP_DESTRUCTURE_CLOSE);
3011 emit_get_local(c, err_local);
3012 emit_op(c, OP_THROW);
3013 patch_jump(c, catch_tag);
3014 patch_jump(c, end_jump);
3015 c->try_depth--;
3016
3017 return;
3018 } else if (pat->type == N_OBJECT_PAT || pat->type == N_OBJECT) {
3019 for (int i = 0; i < pat->args.count; i++) {
3020 sv_ast_t *prop = pat->args.items[i];
3021 if (!prop) continue;
3022
3023 if (prop->type == N_REST || prop->type == N_SPREAD) {
3024 emit_build_object_rest(c);
3025 for (int j = 0; j < i; j++) {
3026 sv_ast_t *prev = pat->args.items[j];
3027 if (!prev || prev->type != N_PROPERTY || !prev->left) continue;
3028 emit_delete_rest_key(c, prev->left);
3029 }
3030 compile_destructure_store(c, prop->right, mode, kind);
3031 continue;
3032 }
3033 if (prop->type != N_PROPERTY) continue;
3034
3035 sv_ast_t *key = prop->left;
3036 sv_ast_t *value = prop->right;
3037 sv_ast_t *default_val = NULL;
3038 if (value && (value->type == N_ASSIGN_PAT ||
3039 (value->type == N_ASSIGN && value->op == TOK_ASSIGN))) {
3040 default_val = value->right;
3041 value = value->left;
3042 }
3043
3044 emit_op(c, OP_DUP);
3045 if ((prop->flags & FN_COMPUTED)) {
3046 compile_expr(c, key);
3047 emit_op(c, OP_GET_ELEM);
3048 } else if (key->type == N_IDENT) {
3049 emit_atom_op(c, OP_GET_FIELD, key->str, key->len);
3050 } else {
3051 compile_expr(c, key);
3052 emit_op(c, OP_GET_ELEM);
3053 }
3054
3055 if (default_val) {
3056 emit_op(c, OP_DUP);
3057 emit_op(c, OP_IS_UNDEF);
3058 int skip = emit_jump(c, OP_JMP_FALSE);
3059 emit_op(c, OP_POP);
3060 compile_expr(c, default_val);
3061 patch_jump(c, skip);
3062 }
3063
3064 compile_destructure_store(c, value, mode, kind);
3065 }
3066 }
3067
3068 if (consume_source) emit_op(c, OP_POP);
3069}
3070
3071void compile_array_destructure(sv_compiler_t *c, sv_ast_t *pat, bool keep) {
3072 compile_destructure_pattern(c, pat, keep, true, DESTRUCTURE_ASSIGN, SV_VAR_LET);
3073}
3074
3075void compile_object_destructure(sv_compiler_t *c, sv_ast_t *pat, bool keep) {
3076 compile_destructure_pattern(c, pat, keep, true, DESTRUCTURE_ASSIGN, SV_VAR_LET);
3077}
3078
3079static bool is_tail_callable(sv_compiler_t *c, sv_ast_t *node) {
3080 if (c->try_depth > 0) return false;
3081 if (c->using_cleanup_count > 0) return false;
3082 if (node->type != N_CALL) return false;
3083 if (call_has_spread_arg(node)) return false;
3084
3085 sv_ast_t *callee = node->left;
3086 if (
3087 callee->type == N_IDENT &&
3088 callee->len == 5 && memcmp(callee->str, "super", 5) == 0
3089 ) return false;
3090
3091 return true;
3092}
3093
3094static void emit_using_dispose_call(
3095 sv_compiler_t *c,
3096 int stack_local,
3097 int completion_local,
3098 bool is_async,
3099 bool suppressed_completion
3100) {
3101 emit_get_local(c, stack_local);
3102 if (suppressed_completion) {
3103 emit_get_local(c, completion_local);
3104 }
3105 if (is_async && suppressed_completion) emit_op(c, OP_USING_DISPOSE_ASYNC_SUPPRESSED);
3106 else if (is_async) emit_op(c, OP_USING_DISPOSE_ASYNC);
3107 else if (suppressed_completion) emit_op(c, OP_USING_DISPOSE_SUPPRESSED);
3108 else emit_op(c, OP_USING_DISPOSE);
3109 if (is_async) emit_op(c, OP_AWAIT);
3110}
3111
3112static void emit_using_cleanups_to_depth(sv_compiler_t *c, int target_depth) {
3113for (int i = c->using_cleanup_count - 1; i >= 0; i--) {
3114 sv_using_cleanup_t *cleanup = &c->using_cleanups[i];
3115 if (cleanup->scope_depth <= target_depth) break;
3116 emit_using_dispose_call(c, cleanup->stack_local, -1, cleanup->is_async, false);
3117 emit_op(c, OP_POP);
3118}}
3119
3120static void emit_return_from_stack(sv_compiler_t *c) {
3121 emit_using_cleanups_to_depth(c, -1);
3122 emit_close_upvals(c);
3123 emit_op(c, OP_RETURN);
3124}
3125
3126static void compile_tail_call(sv_compiler_t *c, sv_ast_t *node) {
3127 sv_ast_t *callee = node->left;
3128
3129 if (callee->type == N_OPTIONAL) {
3130 compile_call(c, node);
3131 emit_return_from_stack(c);
3132 return;
3133 }
3134
3135 sv_call_kind_t kind = compile_call_setup_non_optional(c, callee);
3136 int argc = node->args.count;
3137 for (int i = 0; i < argc; i++)
3138 compile_expr(c, node->args.items[i]);
3139
3140 emit_close_upvals(c);
3141 emit_op(c, kind == SV_CALL_METHOD ? OP_TAIL_CALL_METHOD : OP_TAIL_CALL);
3142 emit_u16(c, (uint16_t)argc);
3143}
3144
3145void compile_tail_return_expr(sv_compiler_t *c, sv_ast_t *expr) {
3146 if (expr->type == N_TERNARY) {
3147 compile_truthy_test_expr(c, expr->cond);
3148 int else_jump = emit_jump(c, OP_JMP_FALSE);
3149 compile_tail_return_expr(c, expr->left);
3150 patch_jump(c, else_jump);
3151 compile_tail_return_expr(c, expr->right);
3152 return;
3153 }
3154
3155 if (expr->type == N_AWAIT && c->is_async && c->try_depth == 0 && !c->is_tla &&
3156 c->using_cleanup_count == 0) {
3157 compile_expr(c, expr->right);
3158 emit_return_from_stack(c);
3159 return;
3160 }
3161
3162 if (is_tail_callable(c, expr)) {
3163 compile_tail_call(c, expr);
3164 return;
3165 }
3166
3167 compile_expr(c, expr);
3168 emit_return_from_stack(c);
3169}
3170
3171void compile_stmts(sv_compiler_t *c, sv_ast_list_t *list) {
3172 for (int i = 0; i < list->count; i++) compile_stmt(c, list->items[i]);
3173}
3174
3175static bool stmt_list_has_using_decl(sv_ast_list_t *list, bool *has_await_using) {
3176 bool found = false;
3177 for (int i = 0; i < list->count; i++) {
3178 sv_ast_t *node = list->items[i];
3179 if (!node) continue;
3180
3181 sv_ast_t *decl = (node->type == N_EXPORT) ? node->left : node;
3182 if (!decl || decl->type != N_VAR) continue;
3183
3184 if (decl->var_kind == SV_VAR_USING || decl->var_kind == SV_VAR_AWAIT_USING) {
3185 if (decl->var_kind == SV_VAR_AWAIT_USING && has_await_using) *has_await_using = true;
3186 found = true;
3187 }
3188 }
3189
3190 return found;
3191}
3192
3193static void emit_empty_disposal_stack(sv_compiler_t *c) {
3194 emit_op(c, OP_ARRAY);
3195 emit_u16(c, 0);
3196}
3197
3198static void emit_using_push(sv_compiler_t *c, bool is_async) {
3199 emit_op(c, is_async ? OP_USING_PUSH_ASYNC : OP_USING_PUSH);
3200}
3201
3202static void pop_using_cleanup(sv_compiler_t *c) {
3203 if (c->using_cleanup_count > 0) c->using_cleanup_count--;
3204}
3205
3206static void emit_dispose_resource(sv_compiler_t *c, bool is_async) {
3207 emit_op(c, is_async ? OP_DISPOSE_RESOURCE_ASYNC : OP_DISPOSE_RESOURCE);
3208 if (is_async) emit_op(c, OP_AWAIT);
3209}
3210
3211static void push_using_cleanup(
3212 sv_compiler_t *c,
3213 int stack_local,
3214 int scope_depth,
3215 bool is_async
3216) {
3217 if (c->using_cleanup_count >= c->using_cleanup_cap) {
3218 int cap = c->using_cleanup_cap ? c->using_cleanup_cap * 2 : 4;
3219 c->using_cleanups = realloc(c->using_cleanups, (size_t)cap * sizeof(sv_using_cleanup_t));
3220 c->using_cleanup_cap = cap;
3221 }
3222
3223 c->using_cleanups[c->using_cleanup_count++] = (sv_using_cleanup_t){
3224 .stack_local = stack_local,
3225 .scope_depth = scope_depth,
3226 .is_async = is_async,
3227 };
3228}
3229
3230static void compile_block_with_using(sv_compiler_t *c, sv_ast_t *node) {
3231 bool has_await_using = false;
3232 bool has_using = stmt_list_has_using_decl(&node->args, &has_await_using);
3233
3234 begin_scope(c);
3235 hoist_lexical_decls(c, &node->args);
3236 hoist_func_decls(c, &node->args);
3237
3238 if (!has_using) {
3239 compile_stmts(c, &node->args);
3240 end_scope(c);
3241 return;
3242 }
3243
3244 emit_empty_disposal_stack(c);
3245 int stack_local = add_local(c, "", 0, false, c->scope_depth);
3246
3247 emit_put_local(c, stack_local);
3248 int err_local = add_local(c, "", 0, false, c->scope_depth);
3249
3250 int old_using_stack = c->using_stack_local;
3251 bool old_using_async = c->using_stack_async;
3252
3253 c->using_stack_local = stack_local;
3254 c->using_stack_async = has_await_using;
3255 push_using_cleanup(c, stack_local, c->scope_depth, has_await_using);
3256
3257 c->try_depth++;
3258 int try_jump = emit_jump(c, OP_TRY_PUSH);
3259 compile_stmts(c, &node->args);
3260 emit_op(c, OP_TRY_POP);
3261 c->try_depth--;
3262
3263 emit_using_dispose_call(c, stack_local, -1, has_await_using, false);
3264 emit_op(c, OP_POP);
3265 int end_jump = emit_jump(c, OP_JMP);
3266
3267 patch_jump(c, try_jump);
3268 int catch_tag = emit_jump(c, OP_CATCH);
3269
3270 emit_put_local(c, err_local);
3271 emit_using_dispose_call(c, stack_local, err_local, has_await_using, true);
3272
3273 if (!has_await_using) emit_op(c, OP_THROW);
3274 patch_jump(c, catch_tag);
3275 patch_jump(c, end_jump);
3276
3277 c->using_stack_local = old_using_stack;
3278 c->using_stack_async = old_using_async;
3279
3280 pop_using_cleanup(c);
3281 end_scope(c);
3282}
3283
3284void compile_stmt(sv_compiler_t *c, sv_ast_t *node) {
3285 if (!node) return;
3286 emit_srcpos(c, node);
3287
3288 switch (node->type) {
3289 case N_EMPTY:
3290 case N_DEBUGGER:
3291 break;
3292
3293 case N_BLOCK:
3294 compile_block_with_using(c, node);
3295 break;
3296
3297 case N_VAR:
3298 compile_var_decl(c, node);
3299 break;
3300
3301 case N_IMPORT_DECL:
3302 compile_import_decl(c, node);
3303 break;
3304
3305 case N_EXPORT:
3306 compile_export_decl(c, node);
3307 break;
3308
3309 case N_IF:
3310 compile_if(c, node);
3311 break;
3312
3313 case N_WHILE:
3314 compile_while(c, node);
3315 break;
3316
3317 case N_DO_WHILE:
3318 compile_do_while(c, node);
3319 break;
3320
3321 case N_FOR:
3322 compile_for(c, node);
3323 break;
3324
3325 case N_FOR_IN:
3326 compile_for_in(c, node);
3327 break;
3328
3329 case N_FOR_OF:
3330 compile_for_of(c, node);
3331 break;
3332
3333 case N_FOR_AWAIT_OF:
3334 if (c->enclosing && !c->enclosing->enclosing) c->is_tla = true;
3335 compile_for_of(c, node);
3336 break;
3337
3338 case N_RETURN:
3339 if (node->right) {
3340 compile_tail_return_expr(c, node->right);
3341 } else {
3342 emit_op(c, OP_UNDEF);
3343 emit_return_from_stack(c);
3344 }
3345 break;
3346
3347 case N_THROW:
3348 compile_expr(c, node->right);
3349 emit_op(c, OP_THROW);
3350 break;
3351
3352 case N_BREAK:
3353 compile_break(c, node);
3354 break;
3355
3356 case N_CONTINUE:
3357 compile_continue(c, node);
3358 break;
3359
3360 case N_TRY:
3361 compile_try(c, node);
3362 break;
3363
3364 case N_SWITCH:
3365 compile_switch(c, node);
3366 break;
3367
3368 case N_LABEL:
3369 compile_label(c, node);
3370 break;
3371
3372 case N_ASSIGN:
3373 if (!has_completion_accumulator(c) && compile_self_append_stmt(c, node)) break;
3374 compile_expr(c, node);
3375 emit_set_completion_from_stack(c);
3376 break;
3377
3378 case N_FUNC:
3379 if (node->str && !(node->flags & (FN_ARROW | FN_PAREN))) break;
3380 compile_expr(c, node);
3381 emit_set_completion_from_stack(c);
3382 break;
3383
3384 case N_CLASS:
3385 compile_class(c, node);
3386 if (node->flags & FN_PAREN) emit_set_completion_from_stack(c);
3387 else emit_op(c, OP_POP);
3388 break;
3389
3390 case N_WITH:
3391 emit_set_completion_undefined(c);
3392 compile_expr(c, node->left);
3393 emit_op(c, OP_ENTER_WITH);
3394 c->with_depth++;
3395 compile_stmt(c, node->body);
3396 c->with_depth--;
3397 emit_op(c, OP_EXIT_WITH);
3398 break;
3399
3400 default:
3401 compile_expr(c, node);
3402 emit_set_completion_from_stack(c);
3403 break;
3404 }
3405}
3406
3407enum {
3408 IMPORT_BIND_DEFAULT = 1 << 0,
3409 IMPORT_BIND_NAMESPACE = 1 << 1,
3410};
3411
3412void compile_import_decl(sv_compiler_t *c, sv_ast_t *node) {
3413 if (!node->right) return;
3414 bool repl_top = is_repl_top_level(c);
3415
3416 compile_expr(c, node->right);
3417 emit_op(c, OP_IMPORT_SYNC);
3418
3419 if (node->args.count == 0) {
3420 emit_op(c, OP_POP);
3421 return;
3422 }
3423
3424 int ns_local = add_local(c, "", 0, false, c->scope_depth);
3425 emit_put_local(c, ns_local);
3426
3427 for (int i = 0; i < node->args.count; i++) {
3428 sv_ast_t *spec = node->args.items[i];
3429 if (!spec || spec->type != N_IMPORT_SPEC ||
3430 !spec->right || spec->right->type != N_IDENT)
3431 continue;
3432
3433 emit_get_local(c, ns_local);
3434
3435 if (!(spec->flags & IMPORT_BIND_NAMESPACE)) {
3436 if ((spec->flags & IMPORT_BIND_DEFAULT) ||
3437 !spec->left || spec->left->type != N_IDENT) {
3438 emit_op(c, OP_IMPORT_DEFAULT);
3439 } else {
3440 emit_atom_op(c, OP_IMPORT_NAMED, spec->left->str, spec->left->len);
3441 }
3442 }
3443
3444 if (repl_top) {
3445 emit_atom_op(c, OP_PUT_GLOBAL, spec->right->str, spec->right->len);
3446 } else {
3447 int idx = ensure_local_at_depth(c, spec->right->str, spec->right->len,
3448 true, c->scope_depth);
3449 emit_put_local(c, idx);
3450 }
3451 }
3452}
3453
3454static void compile_export_emit(sv_compiler_t *c, const char *name, uint32_t len) {
3455 emit_get_var(c, name, len);
3456 emit_atom_op(c, OP_EXPORT, name, len);
3457}
3458
3459static void defer_export(sv_compiler_t *c, const char *name, uint32_t len) {
3460 if (c->deferred_export_count >= c->deferred_export_cap) {
3461 int cap = c->deferred_export_cap ? c->deferred_export_cap * 2 : 8;
3462 c->deferred_exports = realloc(c->deferred_exports, cap * sizeof(sv_deferred_export_t));
3463 c->deferred_export_cap = cap;
3464 }
3465 c->deferred_exports[c->deferred_export_count++] =
3466 (sv_deferred_export_t){ .name = name, .len = len };
3467}
3468
3469static void defer_export_pattern(sv_compiler_t *c, sv_ast_t *pat) {
3470 if (!pat) return;
3471 switch (pat->type) {
3472 case N_IDENT:
3473 defer_export(c, pat->str, pat->len);
3474 break;
3475 case N_ASSIGN_PAT:
3476 defer_export_pattern(c, pat->left);
3477 break;
3478 case N_REST:
3479 case N_SPREAD:
3480 defer_export_pattern(c, pat->right);
3481 break;
3482 case N_ARRAY:
3483 case N_ARRAY_PAT:
3484 for (int i = 0; i < pat->args.count; i++)
3485 defer_export_pattern(c, pat->args.items[i]);
3486 break;
3487 case N_OBJECT:
3488 case N_OBJECT_PAT:
3489 for (int i = 0; i < pat->args.count; i++) {
3490 sv_ast_t *prop = pat->args.items[i];
3491 if (!prop) continue;
3492 if (prop->type == N_PROPERTY) defer_export_pattern(c, prop->right);
3493 else defer_export_pattern(c, prop);
3494 }
3495 break;
3496 default:
3497 break;
3498 }
3499}
3500
3501static void compile_export_pattern(sv_compiler_t *c, sv_ast_t *pat) {
3502 if (!pat) return;
3503 switch (pat->type) {
3504 case N_IDENT:
3505 compile_export_emit(c, pat->str, pat->len);
3506 break;
3507 case N_ASSIGN_PAT:
3508 compile_export_pattern(c, pat->left);
3509 break;
3510 case N_REST:
3511 case N_SPREAD:
3512 compile_export_pattern(c, pat->right);
3513 break;
3514 case N_ARRAY:
3515 case N_ARRAY_PAT:
3516 for (int i = 0; i < pat->args.count; i++)
3517 compile_export_pattern(c, pat->args.items[i]);
3518 break;
3519 case N_OBJECT:
3520 case N_OBJECT_PAT:
3521 for (int i = 0; i < pat->args.count; i++) {
3522 sv_ast_t *prop = pat->args.items[i];
3523 if (!prop) continue;
3524 if (prop->type == N_PROPERTY) compile_export_pattern(c, prop->right);
3525 else compile_export_pattern(c, prop);
3526 }
3527 break;
3528 default:
3529 break;
3530 }
3531}
3532
3533void compile_export_decl(sv_compiler_t *c, sv_ast_t *node) {
3534 if (!node) return;
3535
3536 if (node->flags & EX_DEFAULT) {
3537 if (node->left) compile_expr(c, node->left);
3538 else emit_op(c, OP_UNDEF);
3539 emit_atom_op(c, OP_EXPORT, "default", 7);
3540 return;
3541 }
3542
3543 if ((node->flags & EX_DECL) && node->left) {
3544 sv_ast_t *decl = node->left;
3545 if (decl->type == N_VAR) {
3546 compile_var_decl(c, decl);
3547 bool is_var = decl->var_kind == SV_VAR_VAR;
3548 for (int i = 0; i < decl->args.count; i++) {
3549 sv_ast_t *var = decl->args.items[i];
3550 if (!var || var->type != N_VARDECL) continue;
3551 if (is_var && c->mode == SV_COMPILE_MODULE)
3552 defer_export_pattern(c, var->left);
3553 else
3554 compile_export_pattern(c, var->left);
3555 }
3556 return;
3557 }
3558
3559 compile_stmt(c, decl);
3560 if ((decl->type == N_FUNC || decl->type == N_CLASS) &&
3561 decl->str && decl->len > 0) {
3562 compile_export_emit(c, decl->str, decl->len);
3563 }
3564 return;
3565 }
3566
3567 if ((node->flags & EX_STAR) && (node->flags & EX_FROM) && node->right) {
3568 compile_expr(c, node->right);
3569 emit_op(c, OP_IMPORT_SYNC);
3570
3571 if (node->flags & EX_NAMESPACE) {
3572 if (node->args.count > 0) {
3573 sv_ast_t *spec = node->args.items[0];
3574 if (spec && spec->type == N_IMPORT_SPEC &&
3575 spec->right && spec->right->type == N_IDENT) {
3576 emit_atom_op(c, OP_EXPORT, spec->right->str, spec->right->len);
3577 return;
3578 }
3579 }
3580 emit_op(c, OP_POP);
3581 return;
3582 }
3583
3584 emit_op(c, OP_EXPORT_ALL);
3585 return;
3586 }
3587
3588 if (!(node->flags & EX_NAMED) || node->args.count == 0) return;
3589
3590 int ns_local = -1;
3591 if (node->flags & EX_FROM) {
3592 if (!node->right) return;
3593 compile_expr(c, node->right);
3594 emit_op(c, OP_IMPORT_SYNC);
3595 ns_local = add_local(c, "", 0, false, c->scope_depth);
3596 emit_put_local(c, ns_local);
3597 }
3598
3599 for (int i = 0; i < node->args.count; i++) {
3600 sv_ast_t *spec = node->args.items[i];
3601 if (!spec || spec->type != N_IMPORT_SPEC || !spec->left || !spec->right ||
3602 spec->left->type != N_IDENT || spec->right->type != N_IDENT)
3603 continue;
3604
3605 if (node->flags & EX_FROM) {
3606 emit_get_local(c, ns_local);
3607 if (spec->left->len == 7 && memcmp(spec->left->str, "default", 7) == 0)
3608 emit_op(c, OP_IMPORT_DEFAULT);
3609 else
3610 emit_atom_op(c, OP_IMPORT_NAMED, spec->left->str, spec->left->len);
3611 emit_atom_op(c, OP_EXPORT, spec->right->str, spec->right->len);
3612 } else {
3613 emit_get_var(c, spec->left->str, spec->left->len);
3614 emit_atom_op(c, OP_EXPORT, spec->right->str, spec->right->len);
3615 }
3616 }
3617}
3618
3619void compile_var_decl(sv_compiler_t *c, sv_ast_t *node) {
3620 sv_var_kind_t kind = node->var_kind;
3621
3622 bool is_using = (kind == SV_VAR_USING || kind == SV_VAR_AWAIT_USING);
3623 bool is_await_using = (kind == SV_VAR_AWAIT_USING);
3624 bool is_const = (kind == SV_VAR_CONST || is_using);
3625 bool repl_top = is_repl_top_level(c);
3626
3627 for (int i = 0; i < node->args.count; i++) {
3628 sv_ast_t *decl = node->args.items[i];
3629 if (decl->type != N_VARDECL) continue;
3630 sv_ast_t *target = decl->left;
3631
3632 if (repl_top) {
3633 if (!decl->right && kind == SV_VAR_VAR) continue;
3634 if (decl->right) {
3635 if (target->type == N_IDENT)
3636 compile_expr_with_inferred_name(c, decl->right, target->str, target->len);
3637 else compile_expr(c, decl->right);
3638 } else emit_op(c, OP_UNDEF);
3639 if (target->type == N_IDENT) {
3640 emit_atom_op(c, OP_PUT_GLOBAL, target->str, target->len);
3641 } else compile_destructure_pattern(c, target, false, true, DESTRUCTURE_ASSIGN, kind);
3642 } else if (kind == SV_VAR_VAR) {
3643 if (decl->right) {
3644 uint8_t init_type = infer_expr_type(c, decl->right);
3645 if (target->type == N_IDENT)
3646 compile_expr_with_inferred_name(c, decl->right, target->str, target->len);
3647 else compile_expr(c, decl->right);
3648 if (target->type == N_IDENT) {
3649 int idx = resolve_local(c, target->str, target->len);
3650 if (idx >= 0 && c->locals[idx].depth != -1)
3651 emit_put_local_typed(c, idx, init_type);
3652 else compile_lhs_set(c, target, false);
3653 } else compile_lhs_set(c, target, false);
3654 }
3655 } else {
3656 if (target->type == N_IDENT) {
3657 int idx = ensure_local_at_depth(c, target->str, target->len, is_const, c->scope_depth);
3658 uint8_t init_type = SV_TI_UNKNOWN;
3659 if (decl->right) {
3660 init_type = infer_expr_type(c, decl->right);
3661 compile_expr_with_inferred_name(c, decl->right, target->str, target->len);
3662 } else if (!is_const) {
3663 emit_op(c, OP_UNDEF);
3664 init_type = SV_TI_UNDEF;
3665 }
3666 if (decl->right || !is_const) {
3667 emit_put_local_typed(c, idx, init_type);
3668 c->locals[idx].is_tdz = false;
3669 if (is_using) {
3670 if (c->using_stack_local >= 0) {
3671 emit_get_local(c, c->using_stack_local);
3672 emit_get_local(c, idx);
3673 emit_using_push(c, is_await_using);
3674 } else {
3675 emit_get_local(c, idx);
3676 emit_dispose_resource(c, is_await_using);
3677 }
3678 emit_op(c, OP_POP);
3679 }
3680 }
3681 } else {
3682 if (decl->right) {
3683 compile_expr(c, decl->right);
3684 compile_destructure_binding(c, target, kind);
3685 emit_op(c, OP_POP);
3686 }
3687 }
3688 }
3689 }
3690}
3691
3692void compile_destructure_binding(sv_compiler_t *c, sv_ast_t *pat, sv_var_kind_t kind) {
3693 compile_destructure_pattern(c, pat, false, false, DESTRUCTURE_BIND, kind);
3694}
3695
3696static bool fold_static_typeof_compare(
3697 sv_compiler_t *c, sv_ast_t *cond, bool *out_truth
3698) {
3699 if (!cond || cond->type != N_BINARY) return false;
3700 if (!(cond->op == TOK_SEQ || cond->op == TOK_SNE ||
3701 cond->op == TOK_EQ || cond->op == TOK_NE))
3702 return false;
3703
3704 sv_ast_t *typeof_node = NULL;
3705 sv_ast_t *str_node = NULL;
3706 if (cond->left && cond->left->type == N_TYPEOF &&
3707 cond->right && cond->right->type == N_STRING) {
3708 typeof_node = cond->left;
3709 str_node = cond->right;
3710 } else if (cond->right && cond->right->type == N_TYPEOF &&
3711 cond->left && cond->left->type == N_STRING) {
3712 typeof_node = cond->right;
3713 str_node = cond->left;
3714 } else return false;
3715
3716 if (!typeof_node->right || typeof_node->right->type != N_IDENT) return false;
3717 sv_ast_t *ident = typeof_node->right;
3718 int local = resolve_local(c, ident->str, ident->len);
3719 if (local < 0) return false;
3720 const char *known = typeof_name_for_type(get_local_inferred_type(c, local));
3721 if (!known) return false;
3722
3723 bool is_equal = (strlen(known) == str_node->len &&
3724 memcmp(known, str_node->str, str_node->len) == 0);
3725 bool truth = (cond->op == TOK_SEQ || cond->op == TOK_EQ) ? is_equal : !is_equal;
3726 *out_truth = truth;
3727 return true;
3728}
3729
3730void compile_if(sv_compiler_t *c, sv_ast_t *node) {
3731 emit_set_completion_undefined(c);
3732
3733 bool folded_truth = false;
3734 if (fold_static_typeof_compare(c, node->cond, &folded_truth)) {
3735 if (folded_truth) compile_stmt(c, node->left);
3736 else if (node->right) compile_stmt(c, node->right);
3737 return;
3738 }
3739
3740 compile_truthy_test_expr(c, node->cond);
3741 int else_jump = emit_jump(c, OP_JMP_FALSE);
3742 compile_stmt(c, node->left);
3743 if (node->right) {
3744 int end_jump = emit_jump(c, OP_JMP);
3745 patch_jump(c, else_jump);
3746 compile_stmt(c, node->right);
3747 patch_jump(c, end_jump);
3748 } else {
3749 patch_jump(c, else_jump);
3750 }
3751}
3752
3753void compile_while(sv_compiler_t *c, sv_ast_t *node) {
3754 emit_set_completion_undefined(c);
3755
3756 int loop_start = c->code_len;
3757 push_loop(c, loop_start, NULL, 0, false);
3758
3759 compile_truthy_test_expr(c, node->cond);
3760 int exit_jump = emit_jump(c, OP_JMP_FALSE);
3761 compile_stmt(c, node->body);
3762
3763 sv_loop_t *loop = &c->loops[c->loop_count - 1];
3764 for (int i = 0; i < loop->continues.count; i++)
3765 patch_jump(c, loop->continues.offsets[i]);
3766
3767 emit_loop(c, loop_start);
3768 patch_jump(c, exit_jump);
3769 pop_loop(c);
3770}
3771
3772void compile_do_while(sv_compiler_t *c, sv_ast_t *node) {
3773 emit_set_completion_undefined(c);
3774
3775 int loop_start = c->code_len;
3776 push_loop(c, loop_start, NULL, 0, false);
3777 compile_stmt(c, node->body);
3778
3779 sv_loop_t *loop = &c->loops[c->loop_count - 1];
3780 for (int i = 0; i < loop->continues.count; i++)
3781 patch_jump(c, loop->continues.offsets[i]);
3782
3783 compile_truthy_test_expr(c, node->cond);
3784 int exit_jump = emit_jump(c, OP_JMP_FALSE);
3785 emit_loop(c, loop_start);
3786 patch_jump(c, exit_jump);
3787 pop_loop(c);
3788}
3789
3790static void for_add_slot_unique(int **slots, int *count, int *cap, int slot) {
3791 if (slot < 0) return;
3792 for (int i = 0; i < *count; i++) {
3793 if ((*slots)[i] == slot) return;
3794 }
3795 if (*count >= *cap) {
3796 int new_cap = (*cap > 0) ? (*cap * 2) : 8;
3797 int *new_slots = realloc(*slots, (size_t)new_cap * sizeof(int));
3798 if (!new_slots) return;
3799 *slots = new_slots;
3800 *cap = new_cap;
3801 }
3802 (*slots)[(*count)++] = slot;
3803}
3804
3805static void for_collect_pattern_slots(sv_compiler_t *c, sv_ast_t *pat, int **slots, int *count, int *cap) {
3806 if (!pat) return;
3807 switch (pat->type) {
3808 case N_IDENT: {
3809 int slot = resolve_local(c, pat->str, pat->len);
3810 for_add_slot_unique(slots, count, cap, slot);
3811 break;
3812 }
3813 case N_ASSIGN_PAT:
3814 case N_ASSIGN:
3815 for_collect_pattern_slots(c, pat->left, slots, count, cap);
3816 break;
3817 case N_REST:
3818 case N_SPREAD:
3819 for_collect_pattern_slots(c, pat->right, slots, count, cap);
3820 break;
3821 case N_ARRAY:
3822 case N_ARRAY_PAT:
3823 for (int i = 0; i < pat->args.count; i++)
3824 for_collect_pattern_slots(c, pat->args.items[i], slots, count, cap);
3825 break;
3826 case N_OBJECT:
3827 case N_OBJECT_PAT:
3828 for (int i = 0; i < pat->args.count; i++) {
3829 sv_ast_t *prop = pat->args.items[i];
3830 if (!prop) continue;
3831 if (prop->type == N_PROPERTY)
3832 for_collect_pattern_slots(c, prop->right, slots, count, cap);
3833 else
3834 for_collect_pattern_slots(c, prop, slots, count, cap);
3835 }
3836 break;
3837 default:
3838 break;
3839 }
3840}
3841
3842static void for_collect_var_decl_slots(sv_compiler_t *c, sv_ast_t *init_var, int **slots, int *count, int *cap) {
3843 if (!init_var || init_var->type != N_VAR) return;
3844 for (int i = 0; i < init_var->args.count; i++) {
3845 sv_ast_t *decl = init_var->args.items[i];
3846 if (!decl || decl->type != N_VARDECL || !decl->left) continue;
3847 for_collect_pattern_slots(c, decl->left, slots, count, cap);
3848 }
3849}
3850
3851void compile_for(sv_compiler_t *c, sv_ast_t *node) {
3852 emit_set_completion_undefined(c);
3853 begin_scope(c);
3854
3855 int *iter_slots = NULL;
3856 int iter_count = 0;
3857 int iter_cap = 0;
3858
3859 if (node->init) {
3860 if (node->init->type == N_VAR) {
3861 sv_var_kind_t kind = node->init->var_kind;
3862 compile_var_decl(c, node->init);
3863 if (kind == SV_VAR_LET || kind == SV_VAR_CONST)
3864 for_collect_var_decl_slots(c, node->init, &iter_slots, &iter_count, &iter_cap);
3865 } else {
3866 compile_expr(c, node->init);
3867 emit_op(c, OP_POP);
3868 }
3869 }
3870
3871 int loop_start = c->code_len;
3872 push_loop(c, loop_start, NULL, 0, false);
3873
3874 int exit_jump = -1;
3875 if (node->cond) {
3876 compile_truthy_test_expr(c, node->cond);
3877 exit_jump = emit_jump(c, OP_JMP_FALSE);
3878 }
3879
3880 int iter_inner_start = -1;
3881 if (iter_count > 0) {
3882 begin_scope(c);
3883 iter_inner_start = c->local_count;
3884 for (int i = 0; i < iter_count; i++) {
3885 int outer_idx = iter_slots[i];
3886 sv_local_t outer = c->locals[outer_idx];
3887 emit_get_local(c, outer_idx);
3888 int inner_idx = add_local(c, outer.name, outer.name_len, outer.is_const, c->scope_depth);
3889 emit_put_local(c, inner_idx);
3890 }}
3891
3892 compile_stmt(c, node->body);
3893 sv_loop_t *loop = &c->loops[c->loop_count - 1];
3894 for (int i = 0; i < loop->continues.count; i++)
3895 patch_jump(c, loop->continues.offsets[i]);
3896
3897 int break_close_slot = -1;
3898 if (iter_count > 0) {
3899 for (int i = 0; i < iter_count; i++) {
3900 int inner_idx = iter_inner_start + i;
3901 if (!c->locals[inner_idx].captured) continue;
3902 int slot = local_to_frame_slot(c, inner_idx);
3903 if (break_close_slot < 0 || slot < break_close_slot)
3904 break_close_slot = slot;
3905 }
3906
3907 for (int i = 0; i < iter_count; i++) {
3908 emit_get_local(c, iter_inner_start + i);
3909 emit_put_local(c, iter_slots[i]);
3910 }
3911 end_scope(c);
3912 }
3913
3914 if (node->update) {
3915 sv_ast_t *upd = node->update;
3916 int slot;
3917 if (upd->type == N_UPDATE && upd->right && upd->right->type == N_IDENT &&
3918 (slot = resolve_local_slot(c, upd->right->str, upd->right->len)) >= 0) {
3919 emit_op(c, upd->op == TOK_POSTINC ? OP_INC_LOCAL : OP_DEC_LOCAL);
3920 emit(c, (uint8_t)slot);
3921 set_local_inferred_type(c, c->param_locals + slot, SV_TI_UNKNOWN);
3922 } else {
3923 compile_expr(c, upd);
3924 emit_op(c, OP_POP);
3925 }
3926 }
3927
3928 emit_loop(c, loop_start);
3929 if (exit_jump >= 0) patch_jump(c, exit_jump);
3930
3931 int skip_break_cleanup = -1;
3932 if (break_close_slot >= 0)
3933 skip_break_cleanup = emit_jump(c, OP_JMP);
3934
3935 pop_loop(c);
3936
3937 if (break_close_slot >= 0) {
3938 emit_op(c, OP_CLOSE_UPVAL);
3939 emit_u16(c, (uint16_t)break_close_slot);
3940 patch_jump(c, skip_break_cleanup);
3941 }
3942
3943 free(iter_slots);
3944 end_scope(c);
3945}
3946
3947
3948static void compile_for_each(sv_compiler_t *c, sv_ast_t *node, bool is_for_of);
3949
3950void compile_for_in(sv_compiler_t *c, sv_ast_t *node) {
3951 compile_for_each(c, node, false);
3952}
3953
3954
3955void compile_for_of(sv_compiler_t *c, sv_ast_t *node) {
3956 compile_for_each(c, node, true);
3957}
3958
3959static void compile_for_each_assign_target(sv_compiler_t *c, sv_ast_t *lhs) {
3960 if (!lhs) return;
3961 if (lhs->type == N_VAR && lhs->args.count > 0) {
3962 sv_ast_t *decl = lhs->args.items[0];
3963 sv_ast_t *target = decl->left ? decl->left : decl;
3964 if (target->type == N_IDENT) {
3965 int loc = resolve_local(c, target->str, target->len);
3966 if (loc == -1) {
3967 bool is_const = (lhs->var_kind == SV_VAR_CONST ||
3968 lhs->var_kind == SV_VAR_USING ||
3969 lhs->var_kind == SV_VAR_AWAIT_USING);
3970 loc = add_local(c, target->str, target->len, is_const, c->scope_depth);
3971 }
3972 emit_put_local(c, loc);
3973 } else {
3974 if (lhs->var_kind == SV_VAR_VAR) {
3975 compile_lhs_set(c, target, false);
3976 } else {
3977 compile_destructure_binding(c, target, lhs->var_kind);
3978 emit_op(c, OP_POP);
3979 }
3980 }
3981 return;
3982 }
3983 if (lhs->type == N_IDENT) {
3984 emit_set_var(c, lhs->str, lhs->len, false);
3985 return;
3986 }
3987 compile_lhs_set(c, lhs, false);
3988}
3989
3990static void compile_using_dispose_target(sv_compiler_t *c, sv_ast_t *lhs) {
3991 if (!lhs || lhs->type != N_VAR) return;
3992 bool is_await_using = lhs->var_kind == SV_VAR_AWAIT_USING;
3993 if (lhs->var_kind != SV_VAR_USING && !is_await_using) return;
3994 if (lhs->args.count == 0) return;
3995
3996 sv_ast_t *decl = lhs->args.items[0];
3997 if (!decl || decl->type != N_VARDECL || !decl->left || decl->left->type != N_IDENT) return;
3998
3999 emit_get_var(c, decl->left->str, decl->left->len);
4000 emit_dispose_resource(c, is_await_using);
4001 emit_op(c, OP_POP);
4002}
4003
4004static bool compile_using_push_target(sv_compiler_t *c, sv_ast_t *lhs, int stack_local) {
4005 if (!lhs || lhs->type != N_VAR) return false;
4006 bool is_await_using = lhs->var_kind == SV_VAR_AWAIT_USING;
4007 if (lhs->var_kind != SV_VAR_USING && !is_await_using) return false;
4008 if (lhs->args.count == 0) return false;
4009
4010 sv_ast_t *decl = lhs->args.items[0];
4011 if (!decl || decl->type != N_VARDECL || !decl->left || decl->left->type != N_IDENT) return false;
4012
4013 emit_get_local(c, stack_local);
4014 emit_get_var(c, decl->left->str, decl->left->len);
4015 emit_using_push(c, is_await_using);
4016 emit_op(c, OP_POP);
4017
4018 return true;
4019}
4020
4021static void compile_for_each(sv_compiler_t *c, sv_ast_t *node, bool is_for_of) {
4022 emit_set_completion_undefined(c);
4023 begin_scope(c);
4024
4025 int *iter_slots = NULL;
4026 int iter_count = 0;
4027 int iter_cap = 0;
4028
4029 if (node->left && node->left->type == N_VAR &&
4030 node->left->var_kind != SV_VAR_VAR) {
4031 bool is_const =
4032 (node->left->var_kind == SV_VAR_CONST ||
4033 node->left->var_kind == SV_VAR_USING ||
4034 node->left->var_kind == SV_VAR_AWAIT_USING);
4035 int lb = c->local_count;
4036 for (int i = 0; i < node->left->args.count; i++) {
4037 sv_ast_t *decl = node->left->args.items[i];
4038 if (!decl || decl->type != N_VARDECL || !decl->left) continue;
4039 hoist_lexical_pattern(c, decl->left, is_const);
4040 }
4041 for (int i = lb; i < c->local_count; i++) {
4042 c->locals[i].is_tdz = true;
4043 set_local_inferred_type(c, i, SV_TI_UNKNOWN);
4044 int slot = i - c->param_locals;
4045 emit_op(c, OP_SET_LOCAL_UNDEF);
4046 emit_u16(c, (uint16_t)slot);
4047 }
4048 for_collect_var_decl_slots(c, node->left, &iter_slots, &iter_count, &iter_cap);
4049 }
4050
4051 if (!is_for_of && node->left && node->left->type == N_VAR &&
4052 node->left->var_kind == SV_VAR_VAR && node->left->args.count > 0) {
4053 sv_ast_t *decl = node->left->args.items[0];
4054 if (decl && decl->right) {
4055 compile_expr(c, decl->right);
4056 sv_ast_t *target = decl->left ? decl->left : decl;
4057 if (target->type == N_IDENT) {
4058 int loc = resolve_local(c, target->str, target->len);
4059 if (loc == -1)
4060 loc = add_local(c, target->str, target->len, false, c->scope_depth);
4061 emit_put_local(c, loc);
4062 } else {
4063 compile_lhs_set(c, target, false);
4064 }
4065 }
4066 }
4067
4068 int iter_local = -1;
4069 int idx_local = -1;
4070 int exit_jump = -1;
4071 int try_jump_for_of = -1;
4072 int iter_err_local = -1;
4073 int break_close_slot = -1;
4074 int iter_inner_start = -1;
4075 int using_stack_local = -1;
4076
4077 bool is_for_await = (node->type == N_FOR_AWAIT_OF);
4078 bool is_using_loop = node->left && node->left->type == N_VAR &&
4079 (node->left->var_kind == SV_VAR_USING || node->left->var_kind == SV_VAR_AWAIT_USING);
4080 bool is_await_using_loop = is_using_loop && node->left->var_kind == SV_VAR_AWAIT_USING;
4081 int old_using_stack = c->using_stack_local;
4082 bool old_using_async = c->using_stack_async;
4083 uint8_t iter_hint = 0;
4084 if (is_for_of && !is_for_await)
4085 iter_hint = iter_hint_for_type(infer_expr_type(c, node->right));
4086
4087 if (is_using_loop) {
4088 emit_empty_disposal_stack(c);
4089 using_stack_local = add_local(c, "", 0, false, c->scope_depth);
4090 emit_put_local(c, using_stack_local);
4091 }
4092
4093 compile_expr(c, node->right);
4094 if (is_for_of) {
4095 emit_op(c, is_for_await ? OP_FOR_AWAIT_OF : OP_FOR_OF);
4096 iter_err_local = add_local(c, "", 0, false, c->scope_depth);
4097 try_jump_for_of = emit_jump(c, OP_TRY_PUSH);
4098 c->try_depth++;
4099 } else {
4100 emit_op(c, OP_FOR_IN);
4101 iter_local = add_local(c, "", 0, false, c->scope_depth);
4102 emit_put_local(c, iter_local);
4103
4104 emit_number(c, 0);
4105 idx_local = add_local(c, "", 0, false, c->scope_depth);
4106 emit_put_local(c, idx_local);
4107 }
4108
4109 int loop_start = c->code_len;
4110 push_loop(c, loop_start, NULL, 0, false);
4111
4112 if (is_using_loop) {
4113 emit_empty_disposal_stack(c);
4114 emit_put_local(c, using_stack_local);
4115 }
4116
4117 if (is_for_of) {
4118 if (is_for_await) {
4119 emit_op(c, OP_AWAIT_ITER_NEXT);
4120 } else {
4121 emit_op(c, OP_ITER_NEXT);
4122 emit(c, iter_hint);
4123 }
4124 exit_jump = emit_jump(c, OP_JMP_TRUE);
4125 } else {
4126 emit_get_local(c, idx_local);
4127 emit_get_local(c, iter_local);
4128 emit_op(c, OP_GET_LENGTH);
4129 emit_op(c, OP_LT);
4130 exit_jump = emit_jump(c, OP_JMP_FALSE);
4131
4132 emit_get_local(c, iter_local);
4133 emit_get_local(c, idx_local);
4134 emit_op(c, OP_GET_ELEM);
4135 }
4136
4137 compile_for_each_assign_target(c, node->left);
4138
4139 if (iter_count > 0) {
4140 begin_scope(c);
4141 iter_inner_start = c->local_count;
4142 for (int i = 0; i < iter_count; i++) {
4143 int outer_idx = iter_slots[i];
4144 sv_local_t outer = c->locals[outer_idx];
4145 emit_get_local(c, outer_idx);
4146 int inner_idx = add_local(c, outer.name, outer.name_len,
4147 outer.is_const, c->scope_depth);
4148 emit_put_local(c, inner_idx);
4149 }
4150 }
4151
4152 if (is_using_loop) {
4153 c->using_stack_local = using_stack_local;
4154 c->using_stack_async = is_await_using_loop;
4155 push_using_cleanup(c, using_stack_local, c->scope_depth, is_await_using_loop);
4156 compile_using_push_target(c, node->left, using_stack_local);
4157 }
4158
4159 compile_stmt(c, node->body);
4160 sv_loop_t *loop = &c->loops[c->loop_count - 1];
4161 for (int i = 0; i < loop->continues.count; i++)
4162 patch_jump(c, loop->continues.offsets[i]);
4163
4164 if (is_using_loop) {
4165 emit_using_dispose_call(c, using_stack_local, -1, is_await_using_loop, false);
4166 emit_op(c, OP_POP);
4167
4168 c->using_stack_local = old_using_stack;
4169 c->using_stack_async = old_using_async;
4170 pop_using_cleanup(c);
4171 } else compile_using_dispose_target(c, node->left);
4172
4173 if (iter_count > 0) {
4174 for (int i = 0; i < iter_count; i++) {
4175 int inner_idx = iter_inner_start + i;
4176 if (!c->locals[inner_idx].captured) continue;
4177 int slot = local_to_frame_slot(c, inner_idx);
4178 if (break_close_slot < 0 || slot < break_close_slot)
4179 break_close_slot = slot;
4180 }
4181 end_scope(c);
4182 }
4183
4184 if (!is_for_of) {
4185 emit_get_local(c, idx_local);
4186 emit_op(c, OP_INC);
4187 emit_put_local(c, idx_local);
4188 }
4189
4190 emit_loop(c, loop_start);
4191 patch_jump(c, exit_jump);
4192
4193 if (is_for_of) {
4194 emit_op(c, OP_POP);
4195 emit_op(c, OP_TRY_POP);
4196
4197 int skip_break_cleanup = -1;
4198 if (break_close_slot >= 0)
4199 skip_break_cleanup = emit_jump(c, OP_JMP);
4200
4201 pop_loop(c);
4202 if (break_close_slot >= 0) {
4203 emit_op(c, OP_CLOSE_UPVAL);
4204 emit_u16(c, (uint16_t)break_close_slot);
4205 patch_jump(c, skip_break_cleanup);
4206 }
4207 emit_op(c, OP_TRY_POP);
4208 emit_op(c, OP_ITER_CLOSE);
4209 int end_jump = emit_jump(c, OP_JMP);
4210
4211 patch_jump(c, try_jump_for_of);
4212 int catch_tag = emit_jump(c, OP_CATCH);
4213 emit_put_local(c, iter_err_local);
4214
4215 if (is_using_loop) {
4216 emit_using_dispose_call(c, using_stack_local, iter_err_local, is_await_using_loop, true);
4217 emit_put_local(c, iter_err_local);
4218 }
4219
4220 emit_op(c, OP_ITER_CLOSE);
4221 emit_get_local(c, iter_err_local);
4222 emit_op(c, OP_THROW);
4223 patch_jump(c, catch_tag);
4224
4225 patch_jump(c, end_jump);
4226 c->try_depth--;
4227 } else {
4228 int skip_break_cleanup = -1;
4229 if (break_close_slot >= 0)
4230 skip_break_cleanup = emit_jump(c, OP_JMP);
4231
4232 pop_loop(c);
4233 if (break_close_slot >= 0) {
4234 emit_op(c, OP_CLOSE_UPVAL);
4235 emit_u16(c, (uint16_t)break_close_slot);
4236 patch_jump(c, skip_break_cleanup);
4237 }
4238 }
4239
4240 free(iter_slots);
4241 end_scope(c);
4242}
4243
4244
4245static void emit_close_upvals_to_depth(sv_compiler_t *c, int target_depth) {
4246for (int i = c->local_count - 1; i >= 0; i--) {
4247 if (c->locals[i].depth <= target_depth) break;
4248 if (c->locals[i].captured) {
4249 int frame_slot = local_to_frame_slot(c, i);
4250 emit_op(c, OP_CLOSE_UPVAL);
4251 emit_u16(c, (uint16_t)frame_slot);
4252 }
4253}}
4254
4255void compile_break(sv_compiler_t *c, sv_ast_t *node) {
4256 if (c->loop_count == 0) return;
4257
4258 int target = c->loop_count - 1;
4259 if (node->str) for (int i = c->loop_count - 1; i >= 0; i--) if (
4260 c->loops[i].label &&
4261 c->loops[i].label_len == node->len &&
4262 memcmp(c->loops[i].label, node->str, node->len) == 0
4263 ) { target = i; break; }
4264
4265 emit_close_upvals_to_depth(c, c->loops[target].scope_depth);
4266 emit_using_cleanups_to_depth(c, c->loops[target].scope_depth);
4267
4268 int offset = emit_jump(c, OP_JMP);
4269 patch_list_add(&c->loops[target].breaks, offset);
4270}
4271
4272
4273void compile_continue(sv_compiler_t *c, sv_ast_t *node) {
4274 for (int i = c->loop_count - 1; i >= 0; i--) if (node->str) {
4275 if (
4276 c->loops[i].label &&
4277 c->loops[i].label_len == node->len &&
4278 memcmp(c->loops[i].label, node->str, node->len) == 0
4279 ) {
4280 emit_close_upvals_to_depth(c, c->loops[i].scope_depth);
4281 emit_using_cleanups_to_depth(c, c->loops[i].scope_depth);
4282 patch_list_add(&c->loops[i].continues, emit_jump(c, OP_JMP));
4283 return;
4284 }
4285 } else if (!c->loops[i].is_switch) {
4286 emit_close_upvals_to_depth(c, c->loops[i].scope_depth);
4287 emit_using_cleanups_to_depth(c, c->loops[i].scope_depth);
4288 patch_list_add(&c->loops[i].continues, emit_jump(c, OP_JMP));
4289 return;
4290 }
4291}
4292
4293static void compile_finally_block(sv_compiler_t *c, sv_ast_t *finally_body) {
4294 int finally_jump = emit_jump(c, OP_FINALLY);
4295 compile_stmt(c, finally_body);
4296 emit_op(c, OP_FINALLY_RET);
4297 patch_jump(c, finally_jump);
4298}
4299
4300static void compile_catch_body(sv_compiler_t *c, sv_ast_t *node) {
4301 begin_scope(c);
4302 if (node->catch_param && node->catch_param->type == N_IDENT) {
4303 int loc = add_local(c, node->catch_param->str, node->catch_param->len, false, c->scope_depth);
4304 emit_put_local(c, loc);
4305 } else if (node->catch_param && is_destructure_pattern_node(node->catch_param)) {
4306 compile_destructure_binding(c, node->catch_param, SV_VAR_LET);
4307 emit_op(c, OP_POP);
4308 } else emit_op(c, OP_POP);
4309
4310 compile_stmt(c, node->catch_body);
4311 end_scope(c);
4312}
4313
4314void compile_try(sv_compiler_t *c, sv_ast_t *node) {
4315 emit_set_completion_undefined(c);
4316
4317 c->try_depth++;
4318 int try_jump = emit_jump(c, OP_TRY_PUSH);
4319
4320 compile_stmt(c, node->body);
4321 emit_op(c, OP_TRY_POP);
4322
4323 bool has_catch = (node->catch_body != NULL);
4324 bool has_finally = (node->finally_body != NULL);
4325
4326 if (!has_finally) {
4327 int end_jump = emit_jump(c, OP_JMP);
4328 patch_jump(c, try_jump);
4329 int catch_tag = emit_jump(c, OP_CATCH);
4330 if (has_catch)
4331 compile_catch_body(c, node);
4332 else
4333 emit_op(c, OP_POP);
4334 patch_jump(c, catch_tag);
4335 patch_jump(c, end_jump);
4336 c->try_depth--;
4337 return;
4338 }
4339
4340 int to_finally_from_try = emit_jump(c, OP_JMP);
4341 int to_finally_from_catch = -1;
4342 int to_finally_from_throw = -1;
4343
4344 patch_jump(c, try_jump);
4345
4346 if (has_catch) {
4347 int catch_tag = emit_jump(c, OP_CATCH);
4348 int catch_throw_jump = emit_jump(c, OP_TRY_PUSH);
4349
4350 compile_catch_body(c, node);
4351 emit_op(c, OP_TRY_POP);
4352 to_finally_from_catch = emit_jump(c, OP_JMP);
4353
4354 patch_jump(c, catch_throw_jump);
4355 emit_op(c, OP_POP);
4356 to_finally_from_throw = emit_jump(c, OP_JMP);
4357
4358 patch_jump(c, catch_tag);
4359 } else {
4360 emit_op(c, OP_POP);
4361 to_finally_from_throw = emit_jump(c, OP_JMP);
4362 }
4363
4364 patch_jump(c, to_finally_from_try);
4365 if (to_finally_from_catch >= 0) patch_jump(c, to_finally_from_catch);
4366 if (to_finally_from_throw >= 0) patch_jump(c, to_finally_from_throw);
4367
4368 compile_finally_block(c, node->finally_body);
4369
4370 c->try_depth--;
4371}
4372
4373
4374void compile_switch(sv_compiler_t *c, sv_ast_t *node) {
4375 emit_set_completion_undefined(c);
4376
4377 int case_count = node->args.count;
4378 int default_case = -1;
4379 int *match_to_stub = NULL;
4380 int *stub_to_body = NULL;
4381
4382 if (case_count > 0) {
4383 match_to_stub = calloc((size_t)case_count, sizeof(int));
4384 stub_to_body = calloc((size_t)case_count, sizeof(int));
4385 for (int i = 0; i < case_count; i++) {
4386 match_to_stub[i] = -1;
4387 stub_to_body[i] = -1;
4388 }
4389 }
4390
4391 compile_expr(c, node->cond);
4392 begin_scope(c);
4393 push_loop(c, c->code_len, NULL, 0, true);
4394
4395 for (int i = 0; i < case_count; i++) {
4396 sv_ast_t *cas = node->args.items[i];
4397 if (!cas->left) {
4398 default_case = i;
4399 continue;
4400 }
4401 emit_op(c, OP_DUP);
4402 compile_expr(c, cas->left);
4403 emit_op(c, OP_SEQ);
4404 match_to_stub[i] = emit_jump(c, OP_JMP_TRUE);
4405 }
4406
4407 int miss_jump = emit_jump(c, OP_JMP);
4408 int default_to_body = -1;
4409 int miss_to_end = -1;
4410
4411 for (int i = 0; i < case_count; i++) {
4412 if (match_to_stub[i] < 0) continue;
4413 patch_jump(c, match_to_stub[i]);
4414 emit_op(c, OP_POP);
4415 stub_to_body[i] = emit_jump(c, OP_JMP);
4416 }
4417
4418 patch_jump(c, miss_jump);
4419 emit_op(c, OP_POP);
4420 if (default_case >= 0)
4421 default_to_body = emit_jump(c, OP_JMP);
4422 else
4423 miss_to_end = emit_jump(c, OP_JMP);
4424
4425 for (int i = 0; i < case_count; i++) {
4426 if (i == default_case && default_to_body >= 0)
4427 patch_jump(c, default_to_body);
4428 if (stub_to_body[i] >= 0)
4429 patch_jump(c, stub_to_body[i]);
4430
4431 sv_ast_t *cas = node->args.items[i];
4432 compile_stmts(c, &cas->args);
4433 }
4434
4435 if (miss_to_end >= 0)
4436 patch_jump(c, miss_to_end);
4437
4438 free(match_to_stub);
4439 free(stub_to_body);
4440 pop_loop(c);
4441 end_scope(c);
4442}
4443
4444
4445static inline bool is_loop_node(sv_ast_t *n) {
4446 return n &&
4447 (n->type == N_WHILE || n->type == N_DO_WHILE ||
4448 n->type == N_FOR || n->type == N_FOR_IN ||
4449 n->type == N_FOR_OF || n->type == N_FOR_AWAIT_OF);
4450}
4451
4452void compile_label(sv_compiler_t *c, sv_ast_t *node) {
4453 if (is_loop_node(node->body)) {
4454 c->pending_label = node->str;
4455 c->pending_label_len = node->len;
4456 compile_stmt(c, node->body);
4457 c->pending_label = NULL;
4458 c->pending_label_len = 0;
4459 } else {
4460 push_loop(c, c->code_len, node->str, node->len, false);
4461 compile_stmt(c, node->body);
4462 pop_loop(c);
4463 }
4464}
4465
4466static inline bool is_class_method_def(const sv_ast_t *m);
4467static void emit_field_inits(sv_compiler_t *c, sv_ast_t **fields, int count) {
4468 sv_compiler_t *enc = c->enclosing;
4469 for (int i = 0; i < count; i++) {
4470 sv_ast_t *m = fields[i];
4471 bool is_fn = is_class_method_def(m);
4472 if (is_private_name_node(m->left)) {
4473 emit_op(c, OP_THIS);
4474 emit_private_token(c, m->left);
4475 if (is_fn) compile_func_expr(c, m->right);
4476 else if (m->right) compile_expr(c, m->right);
4477 else emit_op(c, OP_UNDEF);
4478 emit_op(c, OP_DEF_PRIVATE);
4479 if (m->flags & FN_GETTER) emit(c, SV_COMP_PRIVATE_GETTER);
4480 else if (m->flags & FN_SETTER) emit(c, SV_COMP_PRIVATE_SETTER);
4481 else emit(c, is_fn ? SV_COMP_PRIVATE_METHOD : SV_COMP_PRIVATE_FIELD);
4482 emit_op(c, OP_POP);
4483 continue;
4484 }
4485
4486 emit_op(c, OP_THIS);
4487 if (m->right) compile_expr(c, m->right);
4488 else emit_op(c, OP_UNDEF);
4489 if (m->flags & FN_COMPUTED) {
4490 int key_local = enc->computed_key_locals[i];
4491 enc->locals[key_local].captured = true;
4492 uint16_t slot = (uint16_t)local_to_frame_slot(enc, key_local);
4493 int uv = add_upvalue(c, slot, true, false);
4494 emit_op(c, OP_GET_UPVAL);
4495 emit_u16(c, (uint16_t)uv);
4496 } else {
4497 compile_static_property_key(c, m->left);
4498 }
4499 emit_op(c, OP_SWAP);
4500 emit_op(c, OP_DEFINE_METHOD_COMP);
4501 emit(c, 0);
4502 emit_op(c, OP_POP);
4503 }
4504}
4505
4506
4507static sv_ast_t *find_class_constructor(sv_ast_t *node) {
4508 for (int i = 0; i < node->args.count; i++) {
4509 sv_ast_t *m = node->args.items[i];
4510 if (m->type == N_METHOD && m->left && m->left->type == N_IDENT &&
4511 m->left->len == 11 &&
4512 memcmp(m->left->str, "constructor", 11) == 0) {
4513 return m;
4514 }
4515 }
4516 return NULL;
4517}
4518
4519static inline bool is_class_method_def(const sv_ast_t *m) {
4520 return
4521 m && m->right && m->right->type == N_FUNC &&
4522 (m->right->flags & FN_METHOD);
4523}
4524
4525static void compile_class_method(
4526 sv_compiler_t *c, sv_ast_t *m,
4527 int ctor_local, int proto_local,
4528 int preeval_key
4529) {
4530 bool is_static = !!(m->flags & FN_STATIC);
4531 int home_local = is_static ? ctor_local : proto_local;
4532 bool is_fn = is_class_method_def(m);
4533
4534 if (is_fn) {
4535 if (is_static) m->right->flags |= FN_STATIC;
4536 compile_func_expr(c, m->right);
4537 emit_get_local(c, home_local);
4538 emit_op(c, OP_SET_HOME_OBJ);
4539 emit_op(c, OP_SWAP);
4540 } else {
4541 emit_get_local(c, home_local);
4542 if (m->right) compile_expr(c, m->right);
4543 else emit_op(c, OP_UNDEF);
4544 }
4545
4546 uint8_t method_flags = 0;
4547 if (m->flags & FN_GETTER) method_flags |= SV_DEFINE_METHOD_GETTER;
4548 if (m->flags & FN_SETTER) method_flags |= SV_DEFINE_METHOD_SETTER;
4549 if (is_fn) method_flags |= SV_DEFINE_METHOD_SET_NAME;
4550
4551 if (m->flags & FN_COMPUTED) {
4552 if (preeval_key >= 0) emit_get_local(c, preeval_key);
4553 else compile_expr(c, m->left);
4554 } else compile_static_property_key(c, m->left);
4555
4556 emit_op(c, OP_SWAP);
4557 emit_op(c, OP_DEFINE_METHOD_COMP);
4558 emit(c, method_flags);
4559 emit_op(c, OP_POP);
4560}
4561
4562static void compile_private_static_element(sv_compiler_t *c, sv_ast_t *m, int ctor_local) {
4563 bool is_fn = is_class_method_def(m);
4564 emit_get_local(c, ctor_local);
4565 emit_private_token(c, m->left);
4566 if (is_fn) {
4567 if (m->flags & FN_STATIC) m->right->flags |= FN_STATIC;
4568 compile_func_expr(c, m->right);
4569 } else if (m->right) compile_expr(c, m->right);
4570 else emit_op(c, OP_UNDEF);
4571
4572 emit_op(c, OP_DEF_PRIVATE);
4573 if (m->flags & FN_GETTER) emit(c, SV_COMP_PRIVATE_GETTER);
4574 else if (m->flags & FN_SETTER) emit(c, SV_COMP_PRIVATE_SETTER);
4575 else emit(c, is_fn ? SV_COMP_PRIVATE_METHOD : SV_COMP_PRIVATE_FIELD);
4576 emit_op(c, OP_POP);
4577}
4578
4579static inline int compile_class_precompute_key(sv_compiler_t *c, sv_ast_t *key_expr) {
4580 compile_expr(c, key_expr);
4581 int loc = add_local(c, "", 0, false, c->scope_depth);
4582 emit_put_local(c, loc);
4583 return loc;
4584}
4585
4586void compile_class(sv_compiler_t *c, sv_ast_t *node) {
4587 int outer_name_local = -1;
4588 bool class_repl_top = is_repl_top_level(c);
4589
4590 sv_ast_t *ctor_method = NULL;
4591 bool has_static_name = false;
4592
4593 int field_count = 0;
4594 int computed_method_count = 0;
4595
4596 if (node->str) outer_name_local = resolve_local(c, node->str, node->len);
4597 if (node->left) compile_expr(c, node->left);
4598 else emit_op(c, OP_UNDEF);
4599
4600 sv_private_scope_t private_scope = { .parent = c->private_scope };
4601 sv_private_scope_t *saved_private_scope = c->private_scope;
4602 c->private_scope = &private_scope;
4603
4604 for (int i = 0; i < node->args.count; i++) {
4605 sv_ast_t *m = node->args.items[i];
4606 if (m->type != N_METHOD) continue;
4607 bool is_fn = is_class_method_def(m);
4608 bool is_private = is_private_name_node(m->left);
4609
4610 if (is_private) {
4611 uint8_t private_kind = (m->flags & FN_GETTER) ? SV_COMP_PRIVATE_GETTER :
4612 (m->flags & FN_SETTER) ? SV_COMP_PRIVATE_SETTER :
4613 is_fn ? SV_COMP_PRIVATE_METHOD : SV_COMP_PRIVATE_FIELD;
4614 if (!private_scope_add(c, &private_scope, m->left, private_kind, !!(m->flags & FN_STATIC))) {
4615 c->private_scope = saved_private_scope;
4616 free(private_scope.names);
4617 emit_op(c, OP_UNDEF);
4618 return;
4619 }
4620 }
4621
4622 if (
4623 !(m->flags & FN_STATIC) &&
4624 !(m->flags & FN_COMPUTED) &&
4625 m->left && m->left->type == N_IDENT &&
4626 m->left->len == 11 &&
4627 memcmp(m->left->str, "constructor", 11) == 0
4628 ) { ctor_method = m; continue; }
4629
4630 if (
4631 (m->flags & FN_STATIC) &&
4632 !(m->flags & FN_COMPUTED) &&
4633 m->left && m->left->str &&
4634 m->left->len == 4 &&
4635 memcmp(m->left->str, "name", 4) == 0
4636 ) has_static_name = true;
4637
4638 if (!(m->flags & FN_STATIC) && (is_private || !is_fn)) field_count++;
4639 if (!is_private && node->str && (m->flags & FN_COMPUTED) && (is_fn || (m->flags & FN_STATIC))) computed_method_count++;
4640 }
4641
4642 sv_ast_t **field_inits = NULL;
4643 int *computed_key_locals = NULL;
4644 int *method_comp_keys = NULL;
4645 if (field_count > 0) {
4646 field_inits = malloc(sizeof(sv_ast_t *) * field_count);
4647 computed_key_locals = malloc(sizeof(int) * field_count);
4648 }
4649 if (computed_method_count > 0) {
4650 method_comp_keys = malloc(sizeof(int) * node->args.count);
4651 for (int i = 0; i < node->args.count; i++) method_comp_keys[i] = -1;
4652 }
4653
4654 if (field_count > 0 || method_comp_keys) {
4655 int fi = 0;
4656 for (int i = 0; i < node->args.count; i++) {
4657 sv_ast_t *m = node->args.items[i];
4658 if (m->type != N_METHOD || m == ctor_method) continue;
4659
4660 bool is_fn = is_class_method_def(m);
4661 bool is_private = is_private_name_node(m->left);
4662 bool needs_instance_init = !(m->flags & FN_STATIC) && (is_private || !is_fn);
4663
4664 if (needs_instance_init) {
4665 if (field_inits) field_inits[fi] = m;
4666 if (computed_key_locals) computed_key_locals[fi] = (!is_private && (m->flags & FN_COMPUTED))
4667 ? compile_class_precompute_key(c, m->left) : -1;
4668 fi++;
4669 continue;
4670 }
4671
4672 if (is_private || !method_comp_keys || !(m->flags & FN_COMPUTED)) continue;
4673 method_comp_keys[i] = compile_class_precompute_key(c, m->left);
4674 }}
4675
4676 int inner_name_local = -1;
4677 bool has_class_scope = node->str || private_scope.count > 0;
4678 if (has_class_scope) {
4679 begin_scope(c);
4680 if (node->str)
4681 inner_name_local = add_local(c, node->str, node->len, true, c->scope_depth);
4682 for (int i = 0; i < private_scope.count; i++) {
4683 sv_private_name_t *p = &private_scope.names[i];
4684 p->owner = c;
4685 p->local = add_local(c, "", 0, true, c->scope_depth);
4686 emit_op(c, OP_PRIVATE_TOKEN);
4687 emit_u32(c, p->hash);
4688 emit_put_local(c, p->local);
4689 }
4690 }
4691
4692 if (ctor_method && ctor_method->right) {
4693 c->field_inits = field_inits;
4694 c->field_init_count = field_count;
4695 c->computed_key_locals = computed_key_locals;
4696 compile_func_expr(c, ctor_method->right);
4697 c->field_inits = NULL;
4698 c->field_init_count = 0;
4699 c->computed_key_locals = NULL;
4700 } else if (field_count > 0) {
4701 c->computed_key_locals = computed_key_locals;
4702 sv_compiler_t comp;
4703 sv_compile_ctx_init_child(&comp, c, NULL, c->mode);
4704
4705 if (node->left) {
4706 emit_op(&comp, OP_THIS);
4707 emit_op(&comp, OP_SPECIAL_OBJ);
4708 emit(&comp, 2);
4709 emit_op(&comp, OP_SWAP);
4710 emit_op(&comp, OP_SPECIAL_OBJ);
4711 emit(&comp, 0);
4712 emit_op(&comp, OP_SUPER_APPLY);
4713 emit_u16(&comp, 1);
4714 emit_op(&comp, OP_POP);
4715 }
4716
4717 emit_field_inits(&comp, field_inits, field_count);
4718 emit_op(&comp, OP_RETURN_UNDEF);
4719
4720 sv_func_t *fn = code_arena_bump(sizeof(sv_func_t));
4721 memset(fn, 0, sizeof(sv_func_t));
4722 fn->code = code_arena_bump((size_t)comp.code_len);
4723 memcpy(fn->code, comp.code, (size_t)comp.code_len);
4724 fn->code_len = comp.code_len;
4725 sv_func_init_obj_sites(fn);
4726 if (comp.const_count > 0) {
4727 fn->constants = code_arena_bump((size_t)comp.const_count * sizeof(ant_value_t));
4728 memcpy(fn->constants, comp.constants, (size_t)comp.const_count * sizeof(ant_value_t));
4729 fn->const_count = comp.const_count;
4730 build_gc_const_tables(fn);
4731 }
4732 if (comp.atom_count > 0) {
4733 fn->atoms = code_arena_bump((size_t)comp.atom_count * sizeof(sv_atom_t));
4734 memcpy(fn->atoms, comp.atoms, (size_t)comp.atom_count * sizeof(sv_atom_t));
4735 fn->atom_count = comp.atom_count;
4736 }
4737 fn->ic_count = (uint16_t)comp.ic_count;
4738 if (fn->ic_count > 0) {
4739 fn->ic_slots = code_arena_bump((size_t)fn->ic_count * sizeof(sv_ic_entry_t));
4740 memset(fn->ic_slots, 0, (size_t)fn->ic_count * sizeof(sv_ic_entry_t));
4741 }
4742 if (comp.upvalue_count > 0) {
4743 fn->upval_descs = code_arena_bump(
4744 (size_t)comp.upvalue_count * sizeof(sv_upval_desc_t));
4745 memcpy(fn->upval_descs, comp.upval_descs,
4746 (size_t)comp.upvalue_count * sizeof(sv_upval_desc_t));
4747 fn->upvalue_count = comp.upvalue_count;
4748 }
4749 fn->max_locals = comp.max_local_count;
4750 fn->max_stack = fn->max_locals + 64;
4751 fn->local_type_count = fn->max_locals;
4752 if (fn->max_locals > 0) {
4753 fn->local_types = code_arena_bump((size_t)fn->max_locals * sizeof(sv_type_info_t));
4754 memset(fn->local_types, 0, (size_t)fn->max_locals * sizeof(sv_type_info_t));
4755 if (comp.slot_types) {
4756 int ncopy = fn->max_locals < comp.slot_type_cap ? fn->max_locals : comp.slot_type_cap;
4757 memcpy(fn->local_types, comp.slot_types, (size_t)ncopy * sizeof(sv_type_info_t));
4758 }
4759 }
4760
4761 fn->param_count = (uint16_t)comp.param_count;
4762 fn->function_length = (uint16_t)comp.param_count;
4763 fn->is_strict = comp.is_strict;
4764 fn->filename = c->js->filename;
4765 fn->source_line = (int)node->line;
4766
4767 if (node->str && node->len > 0) {
4768 char *name = code_arena_bump(node->len + 1);
4769 memcpy(name, node->str, node->len);
4770 name[node->len] = '\0';
4771 fn->name = name;
4772 }
4773
4774 sv_compile_ctx_cleanup(&comp);
4775 int idx = add_constant(c, mkval(T_NTARG, (uintptr_t)fn));
4776 emit_op(c, OP_CLOSURE);
4777 emit_u32(c, (uint32_t)idx);
4778 } else emit_op(c, OP_UNDEF);
4779
4780 free(field_inits);
4781 free(computed_key_locals);
4782 c->computed_key_locals = NULL;
4783
4784 const char *class_name = node->str;
4785 uint32_t class_name_len = node->len;
4786 bool consumed_inferred_name = false;
4787
4788 if (!class_name && c->inferred_name) {
4789 class_name = c->inferred_name;
4790 class_name_len = c->inferred_name_len;
4791 consumed_inferred_name = true;
4792 }
4793
4794 if (!has_static_name) {
4795 int atom = class_name
4796 ? add_atom(c, class_name, class_name_len)
4797 : add_atom(c, "", 0);
4798 emit_op(c, OP_DEFINE_CLASS);
4799 emit_u32(c, (uint32_t)atom);
4800 emit(c, 1);
4801 } else {
4802 emit_op(c, OP_DEFINE_CLASS);
4803 emit_u32(c, 0);
4804 emit(c, 0);
4805 }
4806
4807 if (consumed_inferred_name) {
4808 c->inferred_name = NULL;
4809 c->inferred_name_len = 0;
4810 }
4811
4812 emit_u32(c, node->src_off);
4813 emit_u32(c, node->src_end);
4814
4815 int proto_local = add_local(c, "", 0, false, c->scope_depth);
4816 int ctor_local = add_local(c, "", 0, false, c->scope_depth);
4817 emit_put_local(c, proto_local);
4818 emit_put_local(c, ctor_local);
4819
4820 if (inner_name_local >= 0) {
4821 emit_get_local(c, ctor_local);
4822 emit_put_local(c, inner_name_local);
4823 }
4824
4825 for (int i = 0; i < node->args.count; i++) {
4826 sv_ast_t *m = node->args.items[i];
4827 if (m->type == N_STATIC_BLOCK) {
4828 begin_scope(c);
4829 int saved_completion_local = c->completion_local;
4830 c->completion_local = -1;
4831 compile_stmts(c, &m->args);
4832 c->completion_local = saved_completion_local;
4833 end_scope(c);
4834 continue;
4835 }
4836
4837 if (m->type != N_METHOD) continue;
4838 if (m == ctor_method) continue;
4839 if (is_private_name_node(m->left)) {
4840 if (m->flags & FN_STATIC) compile_private_static_element(c, m, ctor_local);
4841 continue;
4842 }
4843
4844 bool is_fn = is_class_method_def(m);
4845 if (!is_fn && !(m->flags & FN_STATIC)) continue;
4846
4847 compile_class_method(
4848 c, m, ctor_local, proto_local,
4849 method_comp_keys ? method_comp_keys[i] : -1
4850 );
4851 }
4852
4853 free(method_comp_keys);
4854 emit_get_local(c, ctor_local);
4855
4856 if (class_repl_top && node->str) {
4857 emit_op(c, OP_DUP);
4858 emit_atom_op(c, OP_PUT_GLOBAL, node->str, node->len);
4859 } else if (outer_name_local >= 0) {
4860 emit_op(c, OP_DUP);
4861 emit_put_local(c, outer_name_local);
4862 c->locals[outer_name_local].is_tdz = false;
4863 }
4864
4865 if (has_class_scope) end_scope(c);
4866 c->private_scope = saved_private_scope;
4867 free(private_scope.names);
4868}
4869
4870static bool ast_contains_await_expr(const sv_ast_t *node) {
4871 if (!node) return false;
4872
4873 if (node->type == N_AWAIT) return true;
4874 if (node->type == N_FUNC) return false;
4875
4876 if (ast_contains_await_expr(node->left)) return true;
4877 if (ast_contains_await_expr(node->right)) return true;
4878 if (ast_contains_await_expr(node->cond)) return true;
4879 if (ast_contains_await_expr(node->body)) return true;
4880 if (ast_contains_await_expr(node->catch_body)) return true;
4881 if (ast_contains_await_expr(node->finally_body)) return true;
4882 if (ast_contains_await_expr(node->catch_param)) return true;
4883 if (ast_contains_await_expr(node->init)) return true;
4884 if (ast_contains_await_expr(node->update)) return true;
4885
4886 for (int i = 0; i < node->args.count; i++) {
4887 if (ast_contains_await_expr(node->args.items[i])) return true;
4888 }
4889
4890 return false;
4891}
4892
4893static bool func_params_contain_await(const sv_ast_t *node) {
4894 if (!node) return false;
4895 for (int i = 0; i < node->args.count; i++) {
4896 if (ast_contains_await_expr(node->args.items[i])) return true;
4897 }
4898 return false;
4899}
4900
4901static uint16_t function_length_from_params(const sv_ast_t *node) {
4902 if (!node) return 0;
4903 uint16_t length = 0;
4904 for (int i = 0; i < node->args.count; i++) {
4905 sv_ast_t *param = node->args.items[i];
4906 if (!param || param->type == N_REST || param->type == N_ASSIGN_PAT) break;
4907 length++;
4908 }
4909 return length;
4910}
4911
4912sv_func_t *compile_function_body(
4913 sv_compiler_t *enclosing,
4914 sv_ast_t *node,
4915 sv_compile_mode_t mode
4916) {
4917 if (node->args.count > UINT16_MAX) {
4918 js_mkerr_typed(
4919 enclosing->js, JS_ERR_SYNTAX,
4920 "too many function parameters");
4921 return NULL;
4922 }
4923
4924 if ((node->flags & FN_ASYNC) && func_params_contain_await(node)) {
4925 js_mkerr_typed(
4926 enclosing->js, JS_ERR_SYNTAX,
4927 "await is not allowed in async function parameters");
4928 return NULL;
4929 }
4930
4931 sv_compiler_t comp;
4932 sv_compile_ctx_init_child(&comp, enclosing, node, mode);
4933
4934 for (int i = 0; i < node->args.count; i++) {
4935 sv_ast_t *p = node->args.items[i];
4936 if (p->type == N_IDENT) {
4937 add_local(&comp, p->str, p->len, false, -1);
4938 } else if (p->type == N_REST && p->right && p->right->type == N_IDENT) {
4939 add_local(&comp, p->right->str, p->right->len, false, -1);
4940 } else if (p->type == N_ASSIGN_PAT && p->left && p->left->type == N_IDENT) {
4941 add_local(&comp, p->left->str, p->left->len, false, -1);
4942 } else add_local(&comp, "", 0, false, -1);
4943 }
4944
4945 comp.param_locals = comp.local_count;
4946
4947 bool has_own_use_strict = false;
4948 if (node->body && node->body->type == N_BLOCK) for (int i = 0; i < node->body->args.count; i++) {
4949 sv_ast_t *stmt = node->body->args.items[i];
4950 if (!stmt || stmt->type == N_EMPTY) continue;
4951 if (stmt->type != N_STRING) break;
4952 if (sv_ast_is_use_strict(comp.js, stmt)) {
4953 has_own_use_strict = true;
4954 comp.is_strict = true;
4955 }
4956 }
4957
4958 if (comp.is_strict) {
4959 const char *param_names[256];
4960 uint32_t param_lens[256];
4961 int param_name_count = 0;
4962
4963 for (int i = 0; i < node->args.count; i++) {
4964 sv_ast_t *p = node->args.items[i];
4965 const char *pname = NULL;
4966 uint32_t plen = 0;
4967
4968 if (p && p->type == N_IDENT) {
4969 pname = p->str; plen = p->len;
4970 } else if (p && p->type == N_REST && p->right && p->right->type == N_IDENT) {
4971 pname = p->right->str; plen = p->right->len;
4972 } else if (p && p->type == N_ASSIGN_PAT && p->left && p->left->type == N_IDENT) {
4973 pname = p->left->str; plen = p->left->len;
4974 }
4975
4976 if (!pname || plen == 0) continue;
4977
4978 if (is_strict_restricted_ident(pname, plen)) {
4979 js_mkerr_typed(
4980 comp.js, JS_ERR_SYNTAX,
4981 "strict mode forbids '%.*s' as a parameter name",
4982 (int)plen, pname);
4983 return NULL;
4984 }
4985
4986 for (int j = 0; j < param_name_count; j++) {
4987 if (param_lens[j] == plen &&
4988 memcmp(param_names[j], pname, plen) == 0) {
4989 js_mkerr_typed(
4990 comp.js, JS_ERR_SYNTAX,
4991 "duplicate parameter name '%.*s' in strict mode",
4992 (int)plen, pname);
4993 return NULL;
4994 }
4995 }
4996
4997 if (param_name_count < (int)(sizeof(param_names) / sizeof(param_names[0]))) {
4998 param_names[param_name_count] = pname;
4999 param_lens[param_name_count] = plen;
5000 param_name_count++;
5001 }
5002 }
5003 }
5004
5005 bool has_non_simple_params = false;
5006 for (int i = 0; i < node->args.count; i++) {
5007 sv_ast_t *p = node->args.items[i];
5008 if (p->type != N_IDENT) { has_non_simple_params = true; break; }
5009 }
5010
5011 if (has_own_use_strict && has_non_simple_params) {
5012 js_mkerr_typed(
5013 comp.js, JS_ERR_SYNTAX,
5014 "Illegal 'use strict' directive in function with non-simple parameter list");
5015 return NULL;
5016 }
5017
5018 bool repl_top = is_repl_top_level(&comp);
5019 if (!has_non_simple_params && node->body) {
5020 if (node->body->type == N_BLOCK) {
5021 if (!repl_top) {
5022 for (int i = 0; i < node->body->args.count; i++)
5023 hoist_var_decls(&comp, node->body->args.items[i]);
5024 hoist_lexical_decls(&comp, &node->body->args);
5025 }
5026 hoist_func_decls(&comp, &node->body->args);
5027 } else if (!repl_top) hoist_var_decls(&comp, node->body);
5028 }
5029
5030 if (!has_non_simple_params) {
5031 for (int i = 0; i < node->args.count; i++) {
5032 sv_ast_t *p = node->args.items[i];
5033 if (p->type == N_ASSIGN_PAT) {
5034 emit_op(&comp, OP_GET_ARG);
5035 emit_u16(&comp, (uint16_t)i);
5036 emit_op(&comp, OP_DUP);
5037 emit_op(&comp, OP_IS_UNDEF);
5038 int skip = emit_jump(&comp, OP_JMP_FALSE);
5039 emit_op(&comp, OP_POP);
5040 compile_expr(&comp, p->right);
5041 patch_jump(&comp, skip);
5042 if (p->left && p->left->type == N_IDENT) {
5043 emit_op(&comp, OP_PUT_ARG);
5044 emit_u16(&comp, (uint16_t)i);
5045 } else if (p->left) {
5046 compile_destructure_binding(&comp, p->left, SV_VAR_LET);
5047 emit_op(&comp, OP_POP);
5048 } else emit_op(&comp, OP_POP);
5049 } else if (
5050 p->type == N_ARRAY_PAT || p->type == N_ARRAY ||
5051 p->type == N_OBJECT_PAT || p->type == N_OBJECT) {
5052 emit_op(&comp, OP_GET_ARG);
5053 emit_u16(&comp, (uint16_t)i);
5054 compile_destructure_binding(&comp, p, SV_VAR_LET);
5055 emit_op(&comp, OP_POP);
5056 } else if (p->type == N_REST && p->right && p->right->type == N_IDENT) {
5057 emit_op(&comp, OP_REST);
5058 emit_u16(&comp, (uint16_t)i);
5059 int loc = resolve_local(&comp, p->right->str, p->right->len);
5060 if (loc >= 0) {
5061 emit_op(&comp, OP_PUT_ARG);
5062 emit_u16(&comp, (uint16_t)loc);
5063 }
5064 } else if (p->type == N_REST && p->right) {
5065 emit_op(&comp, OP_REST);
5066 emit_u16(&comp, (uint16_t)i);
5067 compile_destructure_binding(&comp, p->right, SV_VAR_LET);
5068 emit_op(&comp, OP_POP);
5069 }
5070 }
5071 } else {
5072 int *param_bind_locals = NULL;
5073 int param_bind_count = 0;
5074 int param_bind_cap = 0;
5075
5076 for (int i = 0; i < node->args.count; i++) {
5077 sv_ast_t *p = node->args.items[i];
5078 const char *pname = NULL;
5079 uint32_t plen = 0;
5080 if (p->type == N_IDENT) {
5081 pname = p->str; plen = p->len;
5082 } else if ((
5083 p->type == N_ASSIGN_PAT) && p->left &&
5084 p->left->type == N_IDENT) {
5085 pname = p->left->str; plen = p->left->len;
5086 } else if (
5087 p->type == N_REST && p->right &&
5088 p->right->type == N_IDENT) {
5089 pname = p->right->str; plen = p->right->len;
5090 }
5091
5092 int lb = comp.local_count;
5093 if (pname && plen) {
5094 int loc = add_local(&comp, pname, plen, false, 0);
5095 comp.locals[loc].is_tdz = true;
5096 set_local_inferred_type(&comp, loc, SV_TI_UNKNOWN);
5097 int slot = loc - comp.param_locals;
5098 emit_op(&comp, OP_SET_LOCAL_UNDEF);
5099 emit_u16(&comp, (uint16_t)slot);
5100 }
5101
5102 if (param_bind_count >= param_bind_cap) {
5103 param_bind_cap = param_bind_cap ? param_bind_cap * 2 : 8;
5104 param_bind_locals = realloc(
5105 param_bind_locals,
5106 (size_t)param_bind_cap * sizeof(int));
5107 }
5108 param_bind_locals[param_bind_count++] = lb;
5109 }
5110
5111 for (int i = 0; i < node->args.count; i++) {
5112 sv_ast_t *p = node->args.items[i];
5113 int bind_lb = param_bind_locals[i];
5114
5115 if (p->type == N_IDENT) {
5116 if (bind_lb < comp.local_count) {
5117 emit_op(&comp, OP_GET_ARG);
5118 emit_u16(&comp, (uint16_t)i);
5119 int slot = bind_lb - comp.param_locals;
5120 comp.locals[bind_lb].is_tdz = false;
5121 if (slot <= 255) { emit_op(&comp, OP_PUT_LOCAL8); emit(&comp, (uint8_t)slot); }
5122 else { emit_op(&comp, OP_PUT_LOCAL); emit_u16(&comp, (uint16_t)slot); }
5123 set_local_inferred_type(&comp, bind_lb, SV_TI_UNKNOWN);
5124 }
5125 } else if (p->type == N_ASSIGN_PAT) {
5126 emit_op(&comp, OP_GET_ARG);
5127 emit_u16(&comp, (uint16_t)i);
5128 emit_op(&comp, OP_DUP);
5129 emit_op(&comp, OP_IS_UNDEF);
5130 int skip = emit_jump(&comp, OP_JMP_FALSE);
5131 emit_op(&comp, OP_POP);
5132 compile_expr(&comp, p->right);
5133 patch_jump(&comp, skip);
5134 if (p->left && p->left->type == N_IDENT && bind_lb < comp.local_count) {
5135 int slot = bind_lb - comp.param_locals;
5136 comp.locals[bind_lb].is_tdz = false;
5137 if (slot <= 255) { emit_op(&comp, OP_PUT_LOCAL8); emit(&comp, (uint8_t)slot); }
5138 else { emit_op(&comp, OP_PUT_LOCAL); emit_u16(&comp, (uint16_t)slot); }
5139 set_local_inferred_type(&comp, bind_lb, SV_TI_UNKNOWN);
5140 } else if (p->left) {
5141 compile_destructure_binding(&comp, p->left, SV_VAR_LET);
5142 emit_op(&comp, OP_POP);
5143 } else {
5144 emit_op(&comp, OP_POP);
5145 }
5146 } else if (
5147 p->type == N_ARRAY_PAT || p->type == N_ARRAY ||
5148 p->type == N_OBJECT_PAT || p->type == N_OBJECT) {
5149 emit_op(&comp, OP_GET_ARG);
5150 emit_u16(&comp, (uint16_t)i);
5151 compile_destructure_binding(&comp, p, SV_VAR_LET);
5152 emit_op(&comp, OP_POP);
5153 } else if (
5154 p->type == N_REST && p->right && p->right->type == N_IDENT &&
5155 bind_lb < comp.local_count) {
5156 emit_op(&comp, OP_REST);
5157 emit_u16(&comp, (uint16_t)i);
5158 int slot = bind_lb - comp.param_locals;
5159 comp.locals[bind_lb].is_tdz = false;
5160 if (slot <= 255) { emit_op(&comp, OP_PUT_LOCAL8); emit(&comp, (uint8_t)slot); }
5161 else { emit_op(&comp, OP_PUT_LOCAL); emit_u16(&comp, (uint16_t)slot); }
5162 set_local_inferred_type(&comp, bind_lb, SV_TI_UNKNOWN);
5163 } else if (p->type == N_REST && p->right) {
5164 emit_op(&comp, OP_REST);
5165 emit_u16(&comp, (uint16_t)i);
5166 compile_destructure_binding(&comp, p->right, SV_VAR_LET);
5167 emit_op(&comp, OP_POP);
5168 }
5169 }
5170
5171 free(param_bind_locals);
5172 sv_ast_t *body = node->body;
5173
5174 if (body && body->type != N_BLOCK) {
5175 if (!repl_top) hoist_var_decls(&comp, body);
5176 } else if (body) {
5177 if (!repl_top) {
5178 for (int i = 0; i < body->args.count; i++)
5179 hoist_var_decls(&comp, body->args.items[i]);
5180 hoist_lexical_decls(&comp, &body->args);
5181 }
5182 hoist_func_decls(&comp, &body->args);
5183 }
5184 }
5185
5186 if (!comp.is_arrow && has_implicit_arguments_obj(&comp) && (node->flags & FN_USES_ARGS)) {
5187 static const char args_name[] = "\x01arguments";
5188 comp.strict_args_local = add_local(&comp, args_name, sizeof(args_name) - 1, false, comp.scope_depth);
5189 emit_op(&comp, OP_SPECIAL_OBJ);
5190 emit(&comp, 0);
5191 emit_put_local(&comp, comp.strict_args_local);
5192 }
5193
5194 if (!comp.is_arrow && comp.enclosing && (node->flags & FN_USES_NEW_TARGET)) {
5195 static const char nt_name[] = "\x01new.target";
5196 comp.new_target_local = add_local(&comp, nt_name, sizeof(nt_name) - 1, false, comp.scope_depth);
5197 emit_op(&comp, OP_SPECIAL_OBJ);
5198 emit(&comp, 1);
5199 emit_put_local(&comp, comp.new_target_local);
5200 }
5201
5202 if (!comp.is_arrow && comp.enclosing && (node->flags & (FN_METHOD | FN_GETTER | FN_SETTER | FN_STATIC))) {
5203 static const char sv_name[] = "\x01super";
5204 comp.super_local = add_local(&comp, sv_name, sizeof(sv_name) - 1, false, comp.scope_depth);
5205 emit_op(&comp, OP_SPECIAL_OBJ);
5206 emit(&comp, 2);
5207 emit_put_local(&comp, comp.super_local);
5208 }
5209
5210 if (enclosing->field_init_count > 0) {
5211 emit_field_inits(&comp, enclosing->field_inits, enclosing->field_init_count);
5212 }
5213
5214 bool body_has_await_using = false;
5215 bool body_has_using = node->body && node->body->type == N_BLOCK &&
5216 stmt_list_has_using_decl(&node->body->args, &body_has_await_using);
5217 int body_using_try_jump = -1;
5218 int body_using_err_local = -1;
5219 int old_using_stack = comp.using_stack_local;
5220 bool old_using_async = comp.using_stack_async;
5221
5222 if (body_has_using) {
5223 emit_empty_disposal_stack(&comp);
5224 int body_using_stack = add_local(&comp, "", 0, false, comp.scope_depth);
5225 emit_put_local(&comp, body_using_stack);
5226 body_using_err_local = add_local(&comp, "", 0, false, comp.scope_depth);
5227
5228 comp.using_stack_local = body_using_stack;
5229 comp.using_stack_async = body_has_await_using;
5230 push_using_cleanup(&comp, body_using_stack, comp.scope_depth, body_has_await_using);
5231
5232 comp.try_depth++;
5233 body_using_try_jump = emit_jump(&comp, OP_TRY_PUSH);
5234 }
5235
5236 bool completion_top = is_completion_top_level(&comp);
5237 if (completion_top) {
5238 emit_op(&comp, OP_UNDEF);
5239 comp.completion_local = add_local(&comp, "", 0, false, comp.scope_depth);
5240 emit_put_local(&comp, comp.completion_local);
5241 }
5242
5243 if (node->body) {
5244 if (node->body->type == N_BLOCK) {
5245 for (int i = 0; i < node->body->args.count; i++)
5246 compile_stmt(&comp, node->body->args.items[i]);
5247 } else compile_tail_return_expr(&comp, node->body);
5248 }
5249
5250 for (int i = 0; i < comp.deferred_export_count; i++) {
5251 sv_deferred_export_t *e = &comp.deferred_exports[i];
5252 compile_export_emit(&comp, e->name, e->len);
5253 }
5254
5255 if (body_has_using) {
5256 emit_op(&comp, OP_TRY_POP);
5257 comp.try_depth--;
5258
5259 emit_using_dispose_call(&comp, comp.using_stack_local, -1, body_has_await_using, false);
5260 emit_op(&comp, OP_POP);
5261 int end_jump = emit_jump(&comp, OP_JMP);
5262
5263 patch_jump(&comp, body_using_try_jump);
5264 int catch_tag = emit_jump(&comp, OP_CATCH);
5265 emit_put_local(&comp, body_using_err_local);
5266 emit_using_dispose_call(&comp, comp.using_stack_local, body_using_err_local, body_has_await_using, true);
5267 if (!body_has_await_using) emit_op(&comp, OP_THROW);
5268 patch_jump(&comp, catch_tag);
5269 patch_jump(&comp, end_jump);
5270
5271 pop_using_cleanup(&comp);
5272 comp.using_stack_local = old_using_stack;
5273 comp.using_stack_async = old_using_async;
5274 }
5275
5276 if (completion_top) {
5277 emit_get_local(&comp, comp.completion_local);
5278 emit_return_from_stack(&comp);
5279 }
5280
5281 emit_using_cleanups_to_depth(&comp, -1);
5282 emit_close_upvals(&comp);
5283 emit_op(&comp, OP_RETURN_UNDEF);
5284
5285 int max_locals = comp.max_local_count - comp.param_locals;
5286 sv_func_t *func = code_arena_bump(sizeof(sv_func_t));
5287 memset(func, 0, sizeof(sv_func_t));
5288
5289 func->code = code_arena_bump((size_t)comp.code_len);
5290 memcpy(func->code, comp.code, (size_t)comp.code_len);
5291 func->code_len = comp.code_len;
5292 sv_func_init_obj_sites(func);
5293
5294 if (comp.const_count > 0) {
5295 func->constants = code_arena_bump((size_t)comp.const_count * sizeof(ant_value_t));
5296 memcpy(func->constants, comp.constants, (size_t)comp.const_count * sizeof(ant_value_t));
5297 func->const_count = comp.const_count;
5298 build_gc_const_tables(func);
5299 }
5300
5301 if (comp.atom_count > 0) {
5302 func->atoms = code_arena_bump((size_t)comp.atom_count * sizeof(sv_atom_t));
5303 memcpy(func->atoms, comp.atoms, (size_t)comp.atom_count * sizeof(sv_atom_t));
5304 func->atom_count = comp.atom_count;
5305 }
5306
5307 func->ic_count = (uint16_t)comp.ic_count;
5308 if (func->ic_count > 0) {
5309 func->ic_slots = code_arena_bump((size_t)func->ic_count * sizeof(sv_ic_entry_t));
5310 memset(func->ic_slots, 0, (size_t)func->ic_count * sizeof(sv_ic_entry_t));
5311 }
5312
5313 if (comp.upvalue_count > 0) {
5314 func->upval_descs = code_arena_bump(
5315 (size_t)comp.upvalue_count * sizeof(sv_upval_desc_t));
5316 memcpy(func->upval_descs, comp.upval_descs,
5317 (size_t)comp.upvalue_count * sizeof(sv_upval_desc_t));
5318 func->upvalue_count = comp.upvalue_count;
5319 }
5320
5321 if (comp.srcpos_count > 0) {
5322 func->srcpos = code_arena_bump((size_t)comp.srcpos_count * sizeof(sv_srcpos_t));
5323 memcpy(func->srcpos, comp.srcpos, (size_t)comp.srcpos_count * sizeof(sv_srcpos_t));
5324 func->srcpos_count = comp.srcpos_count;
5325 }
5326
5327 if (enclosing->source && enclosing->source_len > 0) {
5328 func->source = enclosing->source;
5329 func->source_len = (int)enclosing->source_len;
5330 func->source_start = (int)node->src_off;
5331 func->source_end = (node->src_end > node->src_off)
5332 ? (int)node->src_end : func->source_len;
5333 }
5334
5335 func->max_locals = max_locals;
5336 func->max_stack = max_locals + 64;
5337 func->local_type_count = max_locals;
5338 if (max_locals > 0) {
5339 func->local_types = code_arena_bump((size_t)max_locals * sizeof(sv_type_info_t));
5340 memset(func->local_types, 0, (size_t)max_locals * sizeof(sv_type_info_t));
5341 if (comp.slot_types) {
5342 int ncopy = max_locals < comp.slot_type_cap ? max_locals : comp.slot_type_cap;
5343 memcpy(func->local_types, comp.slot_types, (size_t)ncopy * sizeof(sv_type_info_t));
5344 }
5345 }
5346
5347 func->param_count = (uint16_t)comp.param_count;
5348 func->function_length = function_length_from_params(node);
5349 func->is_strict = comp.is_strict;
5350 func->is_arrow = comp.is_arrow;
5351
5352 func->is_async = !!(node->flags & FN_ASYNC);
5353 func->has_await = false;
5354 func->is_generator = !!(node->flags & FN_GENERATOR);
5355 func->is_method = !!(node->flags & FN_METHOD);
5356 func->is_static = !!(node->flags & FN_STATIC);
5357 func->is_tla = comp.is_tla;
5358 func->filename = enclosing->filename ? enclosing->filename : enclosing->js->filename;
5359 func->source_line = (int)node->line;
5360
5361 if (node->str && node->len > 0) {
5362 char *name = code_arena_bump(node->len + 1);
5363 memcpy(name, node->str, node->len);
5364 name[node->len] = '\0';
5365 func->name = name;
5366 } else if (enclosing->inferred_name && enclosing->inferred_name_len > 0) {
5367 char *name = code_arena_bump(enclosing->inferred_name_len + 1);
5368 memcpy(name, enclosing->inferred_name, enclosing->inferred_name_len);
5369 name[enclosing->inferred_name_len] = '\0';
5370 func->name = name;
5371 }
5372
5373 if (func->is_async || func->is_tla) {
5374 const uint8_t *ip = func->code;
5375 const uint8_t *end = func->code + func->code_len;
5376 while (ip < end) {
5377 sv_op_t op = (sv_op_t)*ip;
5378 if (op == OP_AWAIT || op == OP_FOR_AWAIT_OF || op == OP_AWAIT_ITER_NEXT) {
5379 func->has_await = true;
5380 break;
5381 }
5382 int sz = sv_op_size[op];
5383 if (sz <= 0) break;
5384 ip += sz;
5385 }}
5386
5387 sv_compile_ctx_cleanup(&comp);
5388 return func;
5389}
5390
5391const char *const sv_op_names[OP__COUNT] = {
5392#define OP_DEF(name, size, n_pop, n_push, f) [OP_##name] = #name,
5393#include "silver/opcode.h"
5394};
5395
5396enum {
5397 SVF_none, SVF_u8, SVF_i8, SVF_u16, SVF_i16, SVF_u32, SVF_i32,
5398 SVF_atom, SVF_atom_u8, SVF_label, SVF_label8, SVF_loc, SVF_loc8,
5399 SVF_loc_atom, SVF_arg, SVF_const, SVF_const8, SVF_npop, SVF_var_ref,
5400};
5401
5402static const uint8_t sv_op_fmts[OP__COUNT] = {
5403#define OP_DEF(name, size, n_pop, n_push, f) [OP_##name] = SVF_##f,
5404#include "silver/opcode.h"
5405};
5406
5407void sv_disasm(ant_t *js, sv_func_t *func, const char *label) {
5408 const char *fname = func->name ? func->name : "";
5409
5410 fprintf(stderr, "[generated bytecode for function: %s (%p <SharedFunctionInfo %s>)]\n",
5411 fname, (void *)func, fname);
5412 fprintf(stderr, "Bytecode length: %d\n", func->code_len);
5413 fprintf(stderr, "Parameter count %d\n", func->param_count);
5414 fprintf(stderr, "Register count %d\n", func->max_locals);
5415 fprintf(stderr, "Frame size %d\n", func->max_locals * (int)sizeof(ant_value_t));
5416
5417 int pc = 0;
5418 while (pc < func->code_len) {
5419 uint8_t op = func->code[pc];
5420 const char *name = (op < OP__COUNT) ? sv_op_names[op] : "???";
5421 uint8_t size = (op < OP__COUNT) ? sv_op_size[op] : 1;
5422 uint8_t fmt = (op < OP__COUNT) ? sv_op_fmts[op] : SVF_none;
5423
5424 uint32_t line, col;
5425 if (sv_lookup_srcpos(func, pc, &line, &col))
5426 fprintf(stderr, "%5u S> ", line);
5427 else
5428 fprintf(stderr, " ");
5429
5430 fprintf(stderr, "%p @ %4d : ", (void *)(func->code + pc), pc);
5431
5432 char hex[32];
5433 int hlen = 0;
5434 for (int i = 0; i < size && i < 8; i++)
5435 hlen += snprintf(hex + hlen, sizeof(hex) - hlen, "%02x ", func->code[pc + i]);
5436
5437 fprintf(stderr, "%-18s", hex);
5438 fprintf(stderr, "%s", name ? name : "???");
5439
5440 switch (fmt) {
5441 case SVF_u8:
5442 fprintf(stderr, " [%d]", func->code[pc + 1]);
5443 break;
5444 case SVF_i8:
5445 fprintf(stderr, " [%d]", (int8_t)func->code[pc + 1]);
5446 break;
5447 case SVF_u16:
5448 fprintf(stderr, " [%d]", sv_get_u16(func->code + pc + 1));
5449 break;
5450 case SVF_i16:
5451 fprintf(stderr, " [%d]", (int16_t)sv_get_u16(func->code + pc + 1));
5452 break;
5453 case SVF_u32:
5454 fprintf(stderr, " [%d]", (int)sv_get_u32(func->code + pc + 1));
5455 break;
5456 case SVF_i32:
5457 fprintf(stderr, " [%d]", (int32_t)sv_get_u32(func->code + pc + 1));
5458 break;
5459 case SVF_atom: {
5460 uint32_t idx = sv_get_u32(func->code + pc + 1);
5461 if (idx < (uint32_t)func->atom_count)
5462 fprintf(stderr, " [%.*s]", (int)func->atoms[idx].len, func->atoms[idx].str);
5463 else
5464 fprintf(stderr, " a%u", idx);
5465 if ((op == OP_GET_GLOBAL || op == OP_GET_GLOBAL_UNDEF ||
5466 op == OP_GET_FIELD || op == OP_GET_FIELD2 || op == OP_PUT_FIELD) && size >= 7)
5467 fprintf(stderr, " ic[%u]", sv_get_u16(func->code + pc + 5));
5468 break;
5469 }
5470 case SVF_atom_u8: {
5471 uint32_t idx = sv_get_u32(func->code + pc + 1);
5472 uint8_t extra = func->code[pc + 5];
5473 if (idx < (uint32_t)func->atom_count)
5474 fprintf(stderr, " [%.*s], [%d]", (int)func->atoms[idx].len, func->atoms[idx].str, extra);
5475 else
5476 fprintf(stderr, " a%u, [%d]", idx, extra);
5477 break;
5478 }
5479 case SVF_label: {
5480 int32_t off = (int32_t)sv_get_u32(func->code + pc + 1);
5481 fprintf(stderr, " [%d] (%d)", off, pc + size + off);
5482 break;
5483 }
5484 case SVF_label8: {
5485 int8_t off = (int8_t)func->code[pc + 1];
5486 fprintf(stderr, " [%d] (%d)", off, pc + size + off);
5487 break;
5488 }
5489 case SVF_loc:
5490 fprintf(stderr, " r%d", sv_get_u16(func->code + pc + 1));
5491 break;
5492 case SVF_loc8:
5493 fprintf(stderr, " r%d", func->code[pc + 1]);
5494 break;
5495 case SVF_loc_atom: {
5496 uint16_t slot = sv_get_u16(func->code + pc + 1);
5497 uint32_t aidx = sv_get_u32(func->code + pc + 3);
5498 fprintf(stderr, " r%d", slot);
5499 if (aidx < (uint32_t)func->atom_count)
5500 fprintf(stderr, ", [%.*s]", (int)func->atoms[aidx].len, func->atoms[aidx].str);
5501 else
5502 fprintf(stderr, ", a%u", aidx);
5503 break;
5504 }
5505 case SVF_arg:
5506 fprintf(stderr, " a%d", sv_get_u16(func->code + pc + 1));
5507 break;
5508 case SVF_const: {
5509 uint32_t idx = sv_get_u32(func->code + pc + 1);
5510 fprintf(stderr, " [%u]", idx);
5511 break;
5512 }
5513 case SVF_const8:
5514 fprintf(stderr, " [%d]", func->code[pc + 1]);
5515 break;
5516 case SVF_npop:
5517 fprintf(stderr, " %d", sv_get_u16(func->code + pc + 1));
5518 break;
5519 case SVF_var_ref:
5520 fprintf(stderr, " [%d]", sv_get_u16(func->code + pc + 1));
5521 break;
5522 default:
5523 break;
5524 }
5525
5526 fprintf(stderr, "\n");
5527 pc += size;
5528 }
5529
5530 fprintf(stderr, "Constant pool (size = %d)\n", func->const_count);
5531 for (int i = 0; i < func->const_count; i++) {
5532 ant_value_t v = func->constants[i];
5533 uint8_t t = vtype(v);
5534 if (t == T_STR) {
5535 ant_offset_t slen;
5536 ant_offset_t soff = vstr(js, v, &slen);
5537 fprintf(stderr, " %d: <String[%d]: #%.*s>\n", i, (int)slen, (int)slen, (const char *)(uintptr_t)soff);
5538 } else if (t == T_NUM) {
5539 fprintf(stderr, " %d: <Number [%g]>\n", i, tod(v));
5540 } else if (t == T_CFUNC) {
5541 sv_func_t *child = (sv_func_t *)(uintptr_t)vdata(v);
5542 const char *cname = child->name ? child->name : "";
5543 fprintf(stderr, " %d: <SharedFunctionInfo %s>\n", i, cname);
5544 } else fprintf(stderr, " %d: <Unknown type=%d>\n", i, t);
5545 }
5546
5547 if (func->atom_count > 0) {
5548 fprintf(stderr, "Atom table (size = %d)\n", func->atom_count);
5549 for (int i = 0; i < func->atom_count; i++)
5550 fprintf(stderr, " %d: <String[%d]: #%.*s>\n",
5551 i, (int)func->atoms[i].len, (int)func->atoms[i].len, func->atoms[i].str);
5552 }
5553
5554 fprintf(stderr, "Handler Table (size = 0)\n");
5555 fprintf(stderr, "Source Position Table (size = %d)\n", func->srcpos_count);
5556 fprintf(stderr, "\n");
5557
5558 for (int i = 0; i < func->const_count; i++) {
5559 if (vtype(func->constants[i]) == T_NTARG) {
5560 sv_func_t *child = (sv_func_t *)(uintptr_t)vdata(func->constants[i]);
5561 char child_label[256];
5562 snprintf(child_label, sizeof(child_label), "%s/closure[%d]", label, i);
5563 sv_disasm(js, child, child_label);
5564 }}
5565}
5566
5567sv_func_t *sv_compile(ant_t *js, sv_ast_t *program, sv_compile_mode_t mode, const char *source, ant_offset_t source_len) {
5568 if (!program || program->type != N_PROGRAM) return NULL;
5569 if (sv_compile_trace_unlikely) fprintf(
5570 stderr, "[compile] start kind=program mode=%d len=%u body=%d strict=%d\n",
5571 (int)mode, (unsigned)source_len,
5572 program->args.count, (program->flags & FN_PARSE_STRICT) != 0 ? 1 : 0
5573 );
5574
5575 static const char *k_top_name_script = "<script>";
5576 static const char *k_top_name_module = "<module>";
5577 static const char *k_top_name_eval = "<eval>";
5578 static const char *k_top_name_repl = "<repl>";
5579 const char *top_name = k_top_name_script;
5580
5581 switch (mode) {
5582 case SV_COMPILE_MODULE: top_name = k_top_name_module; break;
5583 case SV_COMPILE_EVAL: top_name = k_top_name_eval; break;
5584 case SV_COMPILE_REPL: top_name = k_top_name_repl; break;
5585 case SV_COMPILE_SCRIPT:
5586 default: top_name = k_top_name_script; break;
5587 }
5588
5589 sv_ast_t top_fn;
5590 memset(&top_fn, 0, sizeof(top_fn));
5591
5592 top_fn.type = N_FUNC;
5593 top_fn.line = 1;
5594 top_fn.str = top_name;
5595 top_fn.len = (uint32_t)strlen(top_name);
5596 top_fn.src_off = 0;
5597 top_fn.src_end = (source_len > 0) ? (uint32_t)source_len : 0;
5598 top_fn.body = sv_ast_new(N_BLOCK);
5599 top_fn.body->args = program->args;
5600
5601 sv_compiler_t root;
5602 sv_compile_ctx_init_root(
5603 &root, js, js->filename,
5604 pin_source_text(source, source_len),
5605 source_len, mode,
5606 (program->flags & FN_PARSE_STRICT) != 0, NULL
5607 );
5608
5609 root.line_table = sv_compile_ctx_build_line_table(root.source, source_len);
5610 sv_func_t *func = compile_function_body(&root, &top_fn, mode);
5611 sv_compile_ctx_free_line_table(root.line_table);
5612
5613 if (sv_compile_trace_unlikely) fprintf(
5614 stderr, "[compile] end kind=program mode=%d thrown=%d func=%p\n",
5615 (int)mode, js->thrown_exists ? 1 : 0, (void *)func
5616 );
5617
5618 if (js->thrown_exists || !func) return NULL;
5619 return func;
5620}
5621
5622sv_func_t *sv_compile_function(ant_t *js, const char *source, size_t len, bool is_async, bool is_generator) {
5623 if (sv_compile_trace_unlikely) fprintf(
5624 stderr, "[compile] start kind=function len=%u async=%d generator=%d\n",
5625 (unsigned)len, is_async ? 1 : 0, is_generator ? 1 : 0
5626 );
5627
5628 const char *prefix = is_async
5629 ? (is_generator ? "(async function*" : "(async function")
5630 : (is_generator ? "(function*" : "(function");
5631
5632 size_t prefix_len = strlen(prefix);
5633 size_t wrapped_len = prefix_len + len + 1;
5634
5635 char *wrapped = malloc(wrapped_len + 1);
5636 if (!wrapped) return NULL;
5637
5638 memcpy(wrapped, prefix, prefix_len);
5639 memcpy(wrapped + prefix_len, source, len);
5640 wrapped[prefix_len + len] = ')';
5641 wrapped[wrapped_len] = '\0';
5642
5643 bool parse_strict = sv_vm_is_strict(js->vm);
5644 code_arena_mark_t parse_mark = parse_arena_mark();
5645 sv_ast_t *program = sv_parse(js, wrapped, (ant_offset_t)wrapped_len, parse_strict);
5646
5647 if (!program) {
5648 parse_arena_rewind(parse_mark);
5649 free(wrapped);
5650 return NULL;
5651 }
5652
5653 sv_ast_t *func_node = NULL;
5654 if (program->args.count > 0) {
5655 sv_ast_t *stmt = program->args.items[0];
5656 if (stmt && stmt->type == N_FUNC) func_node = stmt;
5657 else if (stmt && stmt->left && stmt->left->type == N_FUNC) func_node = stmt->left;
5658 }
5659
5660 if (!func_node) {
5661 parse_arena_rewind(parse_mark);
5662 free(wrapped);
5663 return NULL;
5664 }
5665
5666 sv_compiler_t root;
5667 sv_compile_ctx_init_root(
5668 &root, js, js->filename,
5669 pin_source_text(wrapped, (ant_offset_t)wrapped_len),
5670 (ant_offset_t)wrapped_len, SV_COMPILE_SCRIPT,
5671 (program->flags & FN_PARSE_STRICT) != 0, NULL
5672 );
5673
5674 root.line_table = sv_compile_ctx_build_line_table(root.source, (ant_offset_t)wrapped_len);
5675 sv_func_t *func = compile_function_body(&root, func_node, SV_COMPILE_SCRIPT);
5676
5677 sv_compile_ctx_free_line_table(root.line_table);
5678 parse_arena_rewind(parse_mark);
5679 free(wrapped);
5680
5681 if (sv_compile_trace_unlikely) fprintf(
5682 stderr, "[compile] end kind=function thrown=%d func=%p\n",
5683 js->thrown_exists ? 1 : 0, (void *)func
5684 );
5685
5686 if (js->thrown_exists || !func) return NULL;
5687 return func;
5688}
5689
5690sv_func_t *sv_compile_function_with_params(
5691 ant_t *js,
5692 const sv_param_t *params,
5693 int param_count,
5694 const char *body,
5695 size_t body_len,
5696 bool is_async
5697) {
5698 if (sv_compile_trace_unlikely) fprintf(
5699 stderr, "[compile] start kind=function-with-params len=%u params=%d async=%d\n",
5700 (unsigned)body_len, param_count, is_async ? 1 : 0
5701 );
5702
5703 if (!body) {
5704 body = "";
5705 body_len = 0;
5706 }
5707
5708 bool parse_strict = sv_vm_is_strict(js->vm);
5709 code_arena_mark_t parse_mark = parse_arena_mark();
5710 sv_ast_t *program = sv_parse(js, body, (ant_offset_t)body_len, parse_strict);
5711
5712 if (!program) {
5713 parse_arena_rewind(parse_mark);
5714 return NULL;
5715 }
5716
5717 static const char *k_top_name_function = "<function>";
5718 static const char *k_top_name_async_function = "<async function>";
5719 const char *top_name = is_async ? k_top_name_async_function : k_top_name_function;
5720
5721 sv_ast_t top_fn;
5722 memset(&top_fn, 0, sizeof(top_fn));
5723
5724 top_fn.type = N_FUNC;
5725 top_fn.line = 1;
5726 top_fn.str = top_name;
5727 top_fn.len = (uint32_t)strlen(top_name);
5728 top_fn.src_off = 0;
5729 top_fn.src_end = (body_len > 0) ? (uint32_t)body_len : 0;
5730 if (is_async) top_fn.flags |= FN_ASYNC;
5731
5732 for (int i = 0; i < param_count; i++) {
5733 const char *name = (params && params[i].name) ? params[i].name : "";
5734 size_t name_len = 0;
5735 if (params && params[i].name) {
5736 name_len = params[i].len ? params[i].len : strlen(name);
5737 }
5738
5739 sv_ast_t *ident = sv_ast_new(N_IDENT);
5740 if (!ident) {
5741 parse_arena_rewind(parse_mark);
5742 return NULL;
5743 }
5744
5745 ident->str = name;
5746 ident->len = (uint32_t)name_len;
5747 ident->line = 1;
5748 ident->col = 1;
5749 sv_ast_list_push(&top_fn.args, ident);
5750 }
5751
5752 top_fn.body = sv_ast_new(N_BLOCK);
5753 if (!top_fn.body) {
5754 parse_arena_rewind(parse_mark);
5755 return NULL;
5756 }
5757
5758 top_fn.body->args = program->args;
5759 sv_compiler_t root;
5760
5761 sv_compile_ctx_init_root(
5762 &root, js, js->filename,
5763 pin_source_text(body, (ant_offset_t)body_len),
5764 (ant_offset_t)body_len, SV_COMPILE_SCRIPT,
5765 (program->flags & FN_PARSE_STRICT) != 0, NULL
5766 );
5767
5768 root.line_table = sv_compile_ctx_build_line_table(root.source, (ant_offset_t)body_len);
5769 sv_func_t *func = compile_function_body(&root, &top_fn, SV_COMPILE_SCRIPT);
5770
5771 sv_compile_ctx_free_line_table(root.line_table);
5772 parse_arena_rewind(parse_mark);
5773
5774 if (sv_compile_trace_unlikely) fprintf(
5775 stderr, "[compile] end kind=function-with-params thrown=%d func=%p\n",
5776 js->thrown_exists ? 1 : 0, (void *)func
5777 );
5778
5779 if (js->thrown_exists || !func) return NULL;
5780 return func;
5781}