• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/compiler.c

  1 /*
  2  * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io>
  3  *
  4  * Permission to use, copy, modify, and/or distribute this software for any
  5  * purpose with or without fee is hereby granted, provided that the above
  6  * copyright notice and this permission notice appear in all copies.
  7  *
  8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15  */
 16 
 17 #include <assert.h>
 18 #include <errno.h>
 19 
 20 #include "ucode/internal/compiler.h"
 21 #include "ucode/internal/chunk.h"
 22 #include "ucode/internal/vm.h" /* ISA: I_*, uc_vm_insn_t */
 23 #include "ucode/internal/program.h"
 24 #include "ucode/internal/lib.h" /* uc_error_context_format() */
 25 
 26 #ifndef NO_COMPILE
 27 
 28 static void uc_compiler_compile_unary(uc_compiler_t *compiler);
 29 static void uc_compiler_compile_binary(uc_compiler_t *compiler);
 30 static void uc_compiler_compile_delete(uc_compiler_t *compiler);
 31 static void uc_compiler_compile_typeof(uc_compiler_t *compiler);
 32 static void uc_compiler_compile_importcall(uc_compiler_t *compiler);
 33 static void uc_compiler_compile_paren(uc_compiler_t *compiler);
 34 static void uc_compiler_compile_call(uc_compiler_t *compiler);
 35 static void uc_compiler_compile_post_inc(uc_compiler_t *compiler);
 36 static void uc_compiler_compile_constant(uc_compiler_t *compiler);
 37 static void uc_compiler_compile_template(uc_compiler_t *compiler);
 38 static void uc_compiler_compile_comma(uc_compiler_t *compiler);
 39 static void uc_compiler_compile_labelexpr(uc_compiler_t *compiler);
 40 static void uc_compiler_compile_funcexpr(uc_compiler_t *compiler);
 41 static void uc_compiler_compile_and(uc_compiler_t *compiler);
 42 static void uc_compiler_compile_or(uc_compiler_t *compiler);
 43 static void uc_compiler_compile_nullish(uc_compiler_t *compiler);
 44 static void uc_compiler_compile_dot(uc_compiler_t *compiler);
 45 static void uc_compiler_compile_subscript(uc_compiler_t *compiler);
 46 static void uc_compiler_compile_ternary(uc_compiler_t *compiler);
 47 static void uc_compiler_compile_array(uc_compiler_t *compiler);
 48 static void uc_compiler_compile_object(uc_compiler_t *compiler);
 49 
 50 static bool uc_compiler_compile_destructuring(uc_compiler_t *compiler);
 51 static void uc_compiler_compile_destructuring_declaration(uc_compiler_t *compiler, bool constant);
 52 
 53 static uc_tokentype_t uc_compiler_compile_declaration(uc_compiler_t *compiler);
 54 static uc_tokentype_t uc_compiler_compile_statement(uc_compiler_t *compiler);
 55 static uc_tokentype_t uc_compiler_compile_expstmt(uc_compiler_t *compiler);
 56 
 57 static uc_parse_rule_t
 58 uc_compiler_parse_rules[TK_ERROR + 1] = {
 59         [TK_LPAREN]             = { uc_compiler_compile_paren, uc_compiler_compile_call, P_CALL },
 60         [TK_QLPAREN]    = { NULL, uc_compiler_compile_call, P_CALL },
 61         [TK_SUB]                = { uc_compiler_compile_unary, uc_compiler_compile_binary, P_ADD },
 62         [TK_ADD]                = { uc_compiler_compile_unary, uc_compiler_compile_binary, P_ADD },
 63         [TK_COMPL]              = { uc_compiler_compile_unary, NULL, P_UNARY },
 64         [TK_NOT]                = { uc_compiler_compile_unary, NULL, P_UNARY },
 65         [TK_DELETE]             = { uc_compiler_compile_delete, NULL, P_UNARY },
 66         [TK_TYPEOF]             = { uc_compiler_compile_typeof, NULL, P_UNARY },
 67         [TK_IMPORT]             = { uc_compiler_compile_importcall, NULL, P_UNARY },
 68         [TK_INC]                = { uc_compiler_compile_unary, uc_compiler_compile_post_inc, P_INC },
 69         [TK_DEC]                = { uc_compiler_compile_unary, uc_compiler_compile_post_inc, P_INC },
 70         [TK_DIV]                = { NULL, uc_compiler_compile_binary, P_MUL },
 71         [TK_MUL]                = { NULL, uc_compiler_compile_binary, P_MUL },
 72         [TK_MOD]                = { NULL, uc_compiler_compile_binary, P_MUL },
 73         [TK_EXP]                = { NULL, uc_compiler_compile_binary, P_EXP },
 74         [TK_NUMBER]             = { uc_compiler_compile_constant, NULL, P_NONE },
 75         [TK_DOUBLE]             = { uc_compiler_compile_constant, NULL, P_NONE },
 76         [TK_STRING]             = { uc_compiler_compile_constant, NULL, P_NONE },
 77         [TK_TRUE]               = { uc_compiler_compile_constant, NULL, P_NONE },
 78         [TK_FALSE]              = { uc_compiler_compile_constant, NULL, P_NONE },
 79         [TK_NULL]               = { uc_compiler_compile_constant, NULL, P_NONE },
 80         [TK_THIS]               = { uc_compiler_compile_constant, NULL, P_NONE },
 81         [TK_REGEXP]             = { uc_compiler_compile_constant, NULL, P_NONE },
 82         [TK_TEMPLATE]   = { uc_compiler_compile_template, NULL, P_NONE },
 83         [TK_COMMA]              = { NULL, uc_compiler_compile_comma, P_COMMA },
 84         [TK_LABEL]              = { uc_compiler_compile_labelexpr, NULL, P_NONE },
 85         [TK_FUNC]               = { uc_compiler_compile_funcexpr, NULL, P_NONE },
 86         [TK_AND]                = { NULL, uc_compiler_compile_and, P_AND },
 87         [TK_OR]                 = { NULL, uc_compiler_compile_or, P_OR },
 88         [TK_NULLISH]    = { NULL, uc_compiler_compile_nullish, P_OR },
 89         [TK_BOR]                = { NULL, uc_compiler_compile_binary, P_BOR },
 90         [TK_BXOR]               = { NULL, uc_compiler_compile_binary, P_BXOR },
 91         [TK_BAND]               = { NULL, uc_compiler_compile_binary, P_BAND },
 92         [TK_EQ]                 = { NULL, uc_compiler_compile_binary, P_EQUAL },
 93         [TK_EQS]                = { NULL, uc_compiler_compile_binary, P_EQUAL },
 94         [TK_NE]                 = { NULL, uc_compiler_compile_binary, P_EQUAL },
 95         [TK_NES]                = { NULL, uc_compiler_compile_binary, P_EQUAL },
 96         [TK_LT]                 = { NULL, uc_compiler_compile_binary, P_COMPARE },
 97         [TK_LE]                 = { NULL, uc_compiler_compile_binary, P_COMPARE },
 98         [TK_GT]                 = { NULL, uc_compiler_compile_binary, P_COMPARE },
 99         [TK_GE]                 = { NULL, uc_compiler_compile_binary, P_COMPARE },
100         [TK_IN]                 = { NULL, uc_compiler_compile_binary, P_COMPARE },
101         [TK_LSHIFT]             = { NULL, uc_compiler_compile_binary, P_SHIFT },
102         [TK_RSHIFT]             = { NULL, uc_compiler_compile_binary, P_SHIFT },
103         [TK_DOT]                = { NULL, uc_compiler_compile_dot, P_CALL },
104         [TK_QDOT]               = { NULL, uc_compiler_compile_dot, P_CALL },
105         [TK_LBRACK]             = { uc_compiler_compile_array, uc_compiler_compile_subscript, P_CALL },
106         [TK_QLBRACK]    = { NULL, uc_compiler_compile_subscript, P_CALL },
107         [TK_QMARK]              = { NULL, uc_compiler_compile_ternary, P_TERNARY },
108         [TK_LBRACE]             = { uc_compiler_compile_object, NULL, P_NONE },
109 };
110 
111 static ssize_t
112 uc_compiler_declare_local(uc_compiler_t *compiler, uc_value_t *name, bool constant);
113 
114 static ssize_t
115 uc_compiler_initialize_local(uc_compiler_t *compiler);
116 
117 static bool
118 uc_compiler_exprstack_is(uc_compiler_t *compiler, uc_exprflag_t flag)
119 {
120         uc_exprstack_t *expr;
121 
122         for (expr = compiler->exprstack; expr; expr = expr->parent)
123                 if (expr->flags & flag)
124                         return true;
125 
126         return false;
127 }
128 
129 static void
130 uc_compiler_init(uc_compiler_t *compiler, const char *name, uc_source_t *source, size_t srcpos, uc_program_t *program, bool strict)
131 {
132         uc_value_t *varname = ucv_string_new("(callee)");
133         uc_function_t *fn;
134 
135         compiler->scope_depth = 0;
136         compiler->try_depth = 0;
137 
138         compiler->program = program;
139         compiler->function = uc_program_function_new(program, name, source, srcpos);
140 
141         compiler->locals.count = 0;
142         compiler->locals.entries = NULL;
143 
144         compiler->upvals.count = 0;
145         compiler->upvals.entries = NULL;
146 
147         compiler->patchlist = NULL;
148 
149         compiler->parent = NULL;
150 
151         compiler->current_srcpos = srcpos;
152         compiler->tailcall_off = SIZE_MAX;
153 
154         fn = (uc_function_t *)compiler->function;
155         fn->strict = strict;
156 
157         /* reserve stack slot 0 */
158         uc_compiler_declare_local(compiler, varname, false);
159         uc_compiler_initialize_local(compiler);
160         ucv_put(varname);
161 }
162 
163 static uc_chunk_t *
164 uc_compiler_current_chunk(uc_compiler_t *compiler)
165 {
166         uc_function_t *fn = (uc_function_t *)compiler->function;
167 
168         return &fn->chunk;
169 }
170 
171 static uc_source_t *
172 uc_compiler_current_source(uc_compiler_t *compiler)
173 {
174         return uc_program_function_source(compiler->function);
175 }
176 
177 __attribute__((format(printf, 3, 0))) static void
178 uc_compiler_syntax_error(uc_compiler_t *compiler, size_t off, const char *fmt, ...)
179 {
180         uc_source_t *source = uc_compiler_current_source(compiler);
181         uc_stringbuf_t *buf = compiler->parser->error;
182         size_t line = 0, byte = 0, len = 0, startoff = 0, endoff = 0;
183         va_list ap;
184         char *s;
185 
186         if (compiler->parser->synchronizing)
187                 return;
188 
189         compiler->parser->synchronizing = true;
190 
191         if (!buf)
192                 buf = compiler->parser->error = xprintbuf_new();
193 
194         if (!off)
195                 off = uc_program_function_srcpos(compiler->function,
196                         uc_compiler_current_chunk(compiler)->count);
197 
198         byte = off;
199         line = uc_source_get_line(source, &byte);
200 
201         va_start(ap, fmt);
202         len = xvasprintf(&s, fmt, ap);
203         va_end(ap);
204 
205         ucv_stringbuf_append(buf, "Syntax error: ");
206         ucv_stringbuf_addstr(buf, s, len);
207         ucv_stringbuf_append(buf, "\n");
208 
209         free(s);
210 
211         if (line) {
212                 ucv_stringbuf_append(buf, "In ");
213 
214                 if (compiler->program->sources.count > 1) {
215                         len = strlen(source->filename);
216 
217                         if (len > 48)
218                                 ucv_stringbuf_printf(buf, "...%s", source->filename + len - 45);
219                         else
220                                 ucv_stringbuf_addstr(buf, source->filename, len);
221 
222                         ucv_stringbuf_append(buf, ", ");
223                 }
224 
225                 ucv_stringbuf_printf(buf, "line %zu, byte %zu:\n", line, byte);
226         }
227 
228         /* underline the innermost statement being compiled rather than pointing at
229          * the offending token alone; SIZE_MAX lies beyond the last instruction, so
230          * no closed statement can cover it and the lookup comes down to the one
231          * still open, i.e. the statement which the error aborted. Left at zero, and
232          * so ignored, when there is no such statement. */
233         uc_program_function_stmt_bounds(compiler->function, SIZE_MAX, &startoff, &endoff);
234 
235         if (uc_error_context_format(buf, source, NULL, startoff, endoff, off))
236                 ucv_stringbuf_append(buf, "\n\n");
237 }
238 
239 static size_t
240 uc_compiler_set_srcpos(uc_compiler_t *compiler, size_t srcpos)
241 {
242         size_t delta;
243 
244         /* ensure that lines counts are strictly increasing */
245         assert(srcpos == 0 || srcpos >= compiler->current_srcpos ||
246                compiler->parser->error);
247 
248         /* after a syntax error, code may be emitted for tokens in front of the
249          * current position, e.g. after the expression of a template literal
250          * placeholder has been terminated prematurely. The generated code is
251          * discarded, but a negative offset would be taken for an enormous one */
252         if (srcpos < compiler->current_srcpos)
253                 srcpos = 0;
254 
255         delta = srcpos ? srcpos - compiler->current_srcpos : 0;
256         compiler->current_srcpos += delta;
257 
258         return delta;
259 }
260 
261 static void
262 uc_compiler_parse_advance(uc_compiler_t *compiler)
263 {
264         ucv_put(compiler->parser->prev.uv);
265         compiler->parser->prev = compiler->parser->curr;
266 
267         while (true) {
268                 uc_token_t *tok = uc_lexer_next_token(&compiler->parser->lex);
269 
270                 if (tok->type == TK_COMMENT || tok->type == TK_LSTM) {
271                         ucv_put(tok->uv);
272                         continue;
273                 }
274                 else if (tok->type == TK_RSTM) {
275                         tok->type = TK_SCOL;
276                 }
277 
278                 compiler->parser->curr = *tok;
279 
280                 if (compiler->parser->curr.type != TK_ERROR)
281                         break;
282 
283                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, "%s",
284                         ucv_string_get(compiler->parser->curr.uv));
285 
286                 ucv_put(compiler->parser->curr.uv);
287                 compiler->parser->curr.uv = NULL;
288         }
289 }
290 
291 static void
292 uc_compiler_parse_consume(uc_compiler_t *compiler, uc_tokentype_t type)
293 {
294         if (compiler->parser->curr.type == type) {
295                 uc_compiler_parse_advance(compiler);
296 
297                 return;
298         }
299 
300         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
301                 "Unexpected token\nExpecting %s", uc_tokenname(type));
302 }
303 
304 static bool
305 uc_compiler_parse_check(uc_compiler_t *compiler, uc_tokentype_t type)
306 {
307         return (compiler->parser->curr.type == type);
308 }
309 
310 static bool
311 uc_compiler_parse_match(uc_compiler_t *compiler, uc_tokentype_t type)
312 {
313         if (!uc_compiler_parse_check(compiler, type))
314                 return false;
315 
316         uc_compiler_parse_advance(compiler);
317 
318         return true;
319 }
320 
321 static bool
322 uc_compiler_keyword_check(uc_compiler_t *compiler, const char *keyword)
323 {
324         size_t keywordlen = strlen(keyword);
325 
326         return (compiler->parser->curr.type == TK_LABEL &&
327                 ucv_string_length(compiler->parser->curr.uv) == keywordlen &&
328                 strcmp(ucv_string_get(compiler->parser->curr.uv), keyword) == 0);
329 }
330 
331 static bool
332 uc_compiler_keyword_match(uc_compiler_t *compiler, const char *keyword)
333 {
334         if (!uc_compiler_keyword_check(compiler, keyword))
335                 return false;
336 
337         uc_compiler_parse_advance(compiler);
338 
339         return true;
340 }
341 
342 static void
343 uc_compiler_keyword_consume(uc_compiler_t *compiler, const char *keyword)
344 {
345         if (uc_compiler_keyword_check(compiler, keyword)) {
346                 uc_compiler_parse_advance(compiler);
347 
348                 return;
349         }
350 
351         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
352                 "Unexpected token\nExpecting '%s'", keyword);
353 }
354 
355 static void
356 uc_compiler_parse_synchronize(uc_compiler_t *compiler)
357 {
358         compiler->parser->synchronizing = false;
359 
360         while (compiler->parser->curr.type != TK_EOF) {
361                 if (compiler->parser->prev.type == TK_SCOL)
362                         return;
363 
364                 switch (compiler->parser->curr.type) {
365                 case TK_IF:
366                 case TK_FOR:
367                 case TK_WHILE:
368                 case TK_SWITCH:
369                 case TK_FUNC:
370                 case TK_TRY:
371                 case TK_RETURN:
372                 case TK_BREAK:
373                 case TK_CONTINUE:
374                 case TK_LOCAL:
375                         return;
376 
377                 default:
378                         break;
379                 }
380 
381                 uc_compiler_parse_advance(compiler);
382         }
383 }
384 
385 static uc_parse_rule_t *
386 uc_compiler_parse_rule(uc_tokentype_t type)
387 {
388         return &uc_compiler_parse_rules[type];
389 }
390 
391 static bool
392 uc_compiler_parse_at_assignment_op(uc_compiler_t *compiler)
393 {
394         switch (compiler->parser->curr.type) {
395         case TK_ASBAND:
396         case TK_ASBXOR:
397         case TK_ASBOR:
398         case TK_ASLEFT:
399         case TK_ASRIGHT:
400         case TK_ASMUL:
401         case TK_ASDIV:
402         case TK_ASMOD:
403         case TK_ASADD:
404         case TK_ASSUB:
405         case TK_ASAND:
406         case TK_ASOR:
407         case TK_ASEXP:
408         case TK_ASNULLISH:
409         case TK_ASSIGN:
410                 return true;
411 
412         default:
413                 return false;
414         }
415 }
416 
417 static void
418 uc_compiler_backpatch(uc_compiler_t *compiler, size_t break_addr, size_t next_addr);
419 
420 static void
421 uc_compiler_parse_precedence_for_token(uc_compiler_t *compiler, uc_precedence_t precedence, uc_token_t *token)
422 {
423         uc_parse_rule_t *rule;
424 
425         rule = uc_compiler_parse_rule(token->type);
426 
427         if (!rule->prefix) {
428                 uc_compiler_syntax_error(compiler, token->pos, "Expecting expression");
429 
430                 return;
431         }
432 
433         uc_compiler_exprstack_push(compiler, token->type,
434                 (precedence <= P_ASSIGN) ? F_ASSIGNABLE : 0);
435 
436         compiler->patchlist = &(uc_patchlist_t){
437                 .parent = compiler->patchlist,
438                 .token = TK_EXP,
439         };
440 
441         rule->prefix(compiler);
442 
443         while (precedence <= uc_compiler_parse_rule(compiler->parser->curr.type)->precedence) {
444                 compiler->exprstack->token = compiler->parser->curr.type;
445 
446                 rule = uc_compiler_parse_rule(compiler->exprstack->token);
447 
448                 if (!rule->infix) {
449                         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, "Expecting ';' or binary operator");
450                         uc_compiler_parse_advance(compiler);
451 
452                         uc_compiler_backpatch(compiler, compiler->patchlist->depth, 0);
453                         uc_compiler_exprstack_pop(compiler);
454 
455                         return;
456                 }
457 
458                 /* allow reserved words in property accessors */
459                 if (rule->infix == uc_compiler_compile_dot)
460                         compiler->parser->lex.no_keyword = true;
461 
462                 uc_compiler_parse_advance(compiler);
463 
464                 rule->infix(compiler);
465         }
466 
467         uc_compiler_backpatch(compiler, compiler->patchlist->depth, 0);
468 
469         uc_compiler_exprstack_pop(compiler);
470 }
471 
472 static void
473 uc_compiler_parse_precedence(uc_compiler_t *compiler, uc_precedence_t precedence)
474 {
475         uc_token_t token = compiler->parser->curr;
476         uc_parse_rule_t *rule = uc_compiler_parse_rule(token.type);
477 
478         /* allow reserved words as property names in object literals */
479         if (rule->prefix == uc_compiler_compile_object)
480                 compiler->parser->lex.no_keyword = true;
481 
482         /* unless a sub-expression follows, treat subsequent slash as division
483          * operator and not as beginning of regexp literal */
484         if (rule->prefix != uc_compiler_compile_paren &&
485             rule->prefix != uc_compiler_compile_unary &&
486             rule->prefix != uc_compiler_compile_array)
487                 compiler->parser->lex.no_regexp = true;
488 
489         uc_compiler_parse_advance(compiler);
490         uc_compiler_parse_precedence_for_token(compiler, precedence, &token);
491 }
492 
493 static size_t
494 uc_compiler_reladdr32(uc_compiler_t *compiler, size_t from, size_t to)
495 {
496         ssize_t delta = to - from;
497 
498         if (delta < -0x7fffffff || delta > 0x7fffffff) {
499                 uc_compiler_syntax_error(compiler, 0, "Jump address too far");
500 
501                 return 0;
502         }
503 
504         return (size_t)(delta + 0x7fffffff);
505 }
506 
507 static void
508 uc_compiler_emit_stmt_start(uc_compiler_t *compiler, uc_token_t *tok)
509 {
510         uc_chunk_stmt_start(
511                 uc_compiler_current_chunk(compiler),
512                 uc_compiler_set_srcpos(compiler, tok->pos));
513 }
514 
515 static void
516 uc_compiler_emit_stmt_end(uc_compiler_t *compiler)
517 {
518         uc_chunk_stmt_end(
519                 uc_compiler_current_chunk(compiler),
520                 uc_compiler_set_srcpos(compiler, compiler->parser->prev.end));
521 }
522 
523 static size_t
524 uc_compiler_reladdr16(uc_compiler_t *compiler, size_t from, size_t to)
525 {
526         ssize_t delta = to - from;
527 
528         if (delta < -0x7fff || delta > 0x7fff) {
529                 uc_compiler_syntax_error(compiler, 0, "Jump address too far");
530 
531                 return 0;
532         }
533 
534         return (size_t)(delta + 0x7fff);
535 }
536 
537 static size_t
538 uc_compiler_emit_insn(uc_compiler_t *compiler, size_t srcpos, uc_vm_insn_t insn)
539 {
540         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
541         size_t lineoff = uc_compiler_set_srcpos(compiler, srcpos);
542 
543         compiler->last_insn = uc_chunk_add(chunk, (uint8_t)insn, lineoff);
544 
545         return compiler->last_insn;
546 }
547 
548 static size_t
549 uc_compiler_emit_u8(uc_compiler_t *compiler, size_t srcpos, uint8_t n)
550 {
551         return uc_chunk_add(
552                 uc_compiler_current_chunk(compiler),
553                 n,
554                 uc_compiler_set_srcpos(compiler, srcpos));
555 }
556 
557 static size_t
558 uc_compiler_emit_u16(uc_compiler_t *compiler, size_t srcpos, uint16_t n)
559 {
560         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
561         size_t lineoff = uc_compiler_set_srcpos(compiler, srcpos);
562 
563         uc_chunk_add(chunk, n / 0x100, lineoff);
564         uc_chunk_add(chunk, n % 0x100, 0);
565 
566         return chunk->count - 2;
567 }
568 
569 static size_t
570 uc_compiler_emit_u32(uc_compiler_t *compiler, size_t srcpos, uint32_t n)
571 {
572         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
573         size_t lineoff = uc_compiler_set_srcpos(compiler, srcpos);
574 
575         uc_chunk_add(chunk, n / 0x1000000, lineoff);
576         uc_chunk_add(chunk, (n / 0x10000) % 0x100, 0);
577         uc_chunk_add(chunk, (n / 0x100) % 0x100, 0);
578         uc_chunk_add(chunk, n % 0x100, 0);
579 
580         return chunk->count - 4;
581 }
582 
583 static size_t
584 uc_compiler_emit_s32(uc_compiler_t *compiler, size_t srcpos, int32_t n)
585 {
586         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
587         size_t lineoff = uc_compiler_set_srcpos(compiler, srcpos);
588         uint32_t v;
589 
590         if (n <= 0)
591                 v = n + 0x7fffffff;
592         else
593                 v = (uint32_t)n + 0x7fffffff;
594 
595         uc_chunk_add(chunk, v / 0x1000000, lineoff);
596         uc_chunk_add(chunk, (v / 0x10000) % 0x100, 0);
597         uc_chunk_add(chunk, (v / 0x100) % 0x100, 0);
598         uc_chunk_add(chunk, v % 0x100, 0);
599 
600         return chunk->count - 4;
601 }
602 
603 static uint32_t
604 uc_compiler_get_u32(uc_compiler_t *compiler, size_t off)
605 {
606         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
607 
608         return chunk->entries[off + 0] * 0x1000000 +
609                chunk->entries[off + 1] * 0x10000 +
610                chunk->entries[off + 2] * 0x100 +
611                chunk->entries[off + 3];
612 }
613 
614 static void
615 uc_compiler_set_u32(uc_compiler_t *compiler, size_t off, uint32_t n)
616 {
617         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
618 
619         chunk->entries[off + 0] = n / 0x1000000;
620         chunk->entries[off + 1] = (n / 0x10000) % 0x100;
621         chunk->entries[off + 2] = (n / 0x100) % 0x100;
622         chunk->entries[off + 3] = n % 0x100;
623 }
624 
625 /* Returns true if the most recently emitted instruction sequence is a function
626  * call whose operands end exactly at the current end of the chunk, i.e. the call
627  * is the last thing compiled before the upcoming return. */
628 static bool
629 uc_compiler_last_insn_is_tailcall(uc_compiler_t *compiler)
630 {
631         /* tailcall_off records the chunk end right after the last emitted call's
632          * operands; it is a tail call candidate only if nothing has been compiled
633          * since, so it must equal the current chunk end */
634         return compiler->tailcall_off ==
635                 uc_compiler_current_chunk(compiler)->count;
636 }
637 
638 /* Invoking a function in tail position allows the VM to reuse the current call
639  * frame for the callee, which permits unbounded tail recursion.
640  *
641  * A function call in return position is marked by emitting a 0x00 marker byte
642  * immediately after the enclosing I_RETURN. The VM recognizes a call whose
643  * operands are followed by I_RETURN + marker as a tail call and reuses the
644  * current frame for the callee.
645  *
646  * The marker is placed after the return so that neither VM ever executes it:
647  * older VMs return (and unwind) before reaching it, and the optimized VM jumps
648  * to the callee at the call site. It is therefore pure data, and the emitted
649  * bytecode remains compatible with interpreters predating tail call
650  * optimization.
651  *
652  * uc_compiler_tailcall_pending() must be called before the I_RETURN is emitted
653  * (while the call is still the last instruction); if it returns true, the
654  * caller must emit the I_RETURN and then uc_compiler_emit_tailcall_marker(). */
655 
656 static bool
657 uc_compiler_tailcall_pending(uc_compiler_t *compiler)
658 {
659         /* an enclosing try block might need to catch exceptions raised by the
660          * invoked function, which requires the current frame to stay in place */
661         if (compiler->try_depth > 0)
662                 return false;
663 
664         return uc_compiler_last_insn_is_tailcall(compiler);
665 }
666 
667 static void
668 uc_compiler_emit_tailcall_marker(uc_compiler_t *compiler)
669 {
670         uc_chunk_add(uc_compiler_current_chunk(compiler), 0x00, 0);
671 }
672 
673 static size_t
674 uc_compiler_emit_constant_index(uc_compiler_t *compiler, size_t srcpos, uc_value_t *val)
675 {
676         size_t cidx = uc_program_add_constant(compiler->program, val);
677 
678         uc_compiler_emit_u32(compiler, srcpos, cidx);
679 
680         return cidx;
681 }
682 
683 static size_t
684 uc_compiler_emit_constant(uc_compiler_t *compiler, size_t srcpos, uc_value_t *val)
685 {
686         size_t cidx;
687 
688         uc_compiler_emit_insn(compiler, srcpos, I_LOAD);
689 
690         cidx = uc_compiler_emit_constant_index(compiler, srcpos, val);
691 
692         return cidx;
693 }
694 
695 static size_t
696 uc_compiler_emit_regexp(uc_compiler_t *compiler, size_t srcpos, uc_value_t *val)
697 {
698         size_t cidx = uc_program_add_constant(compiler->program, val);
699 
700         uc_compiler_emit_insn(compiler, srcpos, I_LREXP);
701         uc_compiler_emit_u32(compiler, 0, cidx);
702 
703         return cidx;
704 }
705 
706 static size_t
707 uc_compiler_emit_jmp(uc_compiler_t *compiler, size_t srcpos)
708 {
709         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
710 
711         uc_compiler_emit_insn(compiler, srcpos, I_JMP);
712         uc_compiler_emit_u32(compiler, 0, 0);
713 
714         return chunk->count - 5;
715 }
716 
717 static size_t
718 uc_compiler_emit_jmpz(uc_compiler_t *compiler, size_t srcpos)
719 {
720         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
721 
722         uc_compiler_emit_insn(compiler, srcpos, I_JMPZ);
723         uc_compiler_emit_u32(compiler, 0, 0);
724 
725         return chunk->count - 5;
726 }
727 
728 static size_t
729 uc_compiler_emit_jmp_dest(uc_compiler_t *compiler, size_t srcpos, uint32_t dest)
730 {
731         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
732 
733         uc_compiler_emit_insn(compiler, srcpos, I_JMP);
734         uc_compiler_emit_u32(compiler, 0, uc_compiler_reladdr32(compiler, chunk->count - 1, dest));
735 
736         return chunk->count - 5;
737 }
738 
739 static size_t
740 uc_compiler_emit_jmpnt(uc_compiler_t *compiler, size_t srcpos, uint16_t types, uint8_t depth)
741 {
742         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
743 
744         uc_vector_push(compiler->patchlist,
745                 uc_compiler_emit_insn(compiler, srcpos, I_JMPNT));
746 
747         uc_compiler_emit_u32(compiler, 0,
748                 uc_compiler_reladdr16(compiler, 0, TK_BREAK)
749                         | ((types & 0x1fff) << 16)
750                         | ((depth & 0x7) << 29));
751 
752         return chunk->count - 5;
753 }
754 
755 static size_t
756 uc_compiler_emit_copy(uc_compiler_t *compiler, size_t srcpos, uint8_t depth)
757 {
758         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
759 
760         uc_compiler_emit_insn(compiler, srcpos, I_COPY);
761         uc_compiler_emit_u8(compiler, 0, depth);
762 
763         return chunk->count - 2;
764 }
765 
766 /* Invoke a standard library function by slot: the arguments are the values on
767  * the stack, the result is pushed back.
768  *
769  * Naming the slot of uc_stdlib_functions[] with a uc_stdlib_fn_t value instead
770  * of looking the function up in the runtime namespace keeps such a call
771  * independent of user code shadowing its name, and makes the callee readable
772  * in the emitted code; an empty or stale slot is reported by the VM at the
773  * instruction. */
774 static void
775 uc_compiler_emit_stcall(uc_compiler_t *compiler, size_t srcpos, size_t slot, size_t nargs)
776 {
777         assert(slot <= 0xffff && nargs <= 0xffff);
778 
779         /* the instruction is newer than the oldest bytecode this release writes, so
780          * record that this program cannot be run by a VM predating it */
781         uc_program_require_version(compiler->program, UCODE_BYTECODE_VERSION);
782 
783         uc_compiler_emit_insn(compiler, srcpos, I_STCALL);
784         uc_compiler_emit_u32(compiler, 0, ((uint32_t)slot << 16) | (uint32_t)nargs);
785 }
786 
787 static ssize_t
788 uc_compiler_get_jmpaddr(uc_compiler_t *compiler, size_t off)
789 {
790         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
791         size_t width = (chunk->entries[off] == I_JMPNT) ? 2 : 4;
792 
793         assert(chunk->entries[off] == I_JMP || chunk->entries[off] == I_JMPZ || chunk->entries[off] == I_JMPNT);
794         assert(off + 4 < chunk->count);
795 
796         if (width == 2)
797                 return (
798                         chunk->entries[off + 3] * 0x100UL +
799                         chunk->entries[off + 4]
800                 ) - 0x7fff;
801         else
802                 return (
803                         chunk->entries[off + 1] * 0x1000000UL +
804                         chunk->entries[off + 2] * 0x10000UL +
805                         chunk->entries[off + 3] * 0x100UL +
806                         chunk->entries[off + 4]
807                 ) - 0x7fffffff;
808 }
809 
810 static void
811 uc_compiler_set_jmpaddr(uc_compiler_t *compiler, size_t off, uint32_t dest)
812 {
813         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
814         size_t width = (chunk->entries[off] == I_JMPNT) ? 2 : 4;
815         size_t addr;
816 
817         assert(chunk->entries[off] == I_JMP || chunk->entries[off] == I_JMPZ || chunk->entries[off] == I_JMPNT);
818         assert(off + 4 < chunk->count);
819 
820         if (width == 2) {
821                 addr = uc_compiler_reladdr16(compiler, off, dest);
822                 chunk->entries[off + 3] = addr / 0x100;
823                 chunk->entries[off + 4] = addr % 0x100;
824         }
825         else {
826                 addr = uc_compiler_reladdr32(compiler, off, dest);
827                 chunk->entries[off + 1] = addr / 0x1000000;
828                 chunk->entries[off + 2] = (addr / 0x10000) % 0x100;
829                 chunk->entries[off + 3] = (addr / 0x100) % 0x100;
830                 chunk->entries[off + 4] = addr % 0x100;
831         }
832 }
833 
834 static void
835 uc_compiler_inc_exportnum(uc_compiler_t *compiler)
836 {
837         uc_source_t *root = uc_program_function_source(uc_program_entry(compiler->program));
838         uint64_t u;
839 
840         if (root->exports.count == 0) {
841                 uc_vector_push(&root->exports, ucv_uint64_new(1));
842         }
843         else {
844                 u = ucv_uint64_get(root->exports.entries[0]);
845 
846                 ucv_put(root->exports.entries[0]);
847 
848                 root->exports.entries[0] = ucv_uint64_new(u + 1);
849         }
850 }
851 
852 static size_t
853 uc_compiler_get_exportnum(uc_compiler_t *compiler)
854 {
855         uc_source_t *root = uc_program_function_source(uc_program_entry(compiler->program));
856 
857         return root->exports.count ? ucv_uint64_get(root->exports.entries[0]) : 0;
858 }
859 
860 static void
861 uc_compiler_emit_exports(uc_compiler_t *compiler) {
862         size_t i;
863 
864         if (!compiler->patchlist || compiler->patchlist->token != TK_EXPORT)
865                 return;
866 
867         for (i = 0; i < compiler->patchlist->count; i++) {
868                 uc_compiler_emit_insn(compiler, 0, I_EXPORT);
869                 uc_compiler_emit_u32(compiler, 0, compiler->patchlist->entries[i]);
870         }
871 }
872 
873 static uc_function_t *
874 uc_compiler_finish(uc_compiler_t *compiler, uc_tokentype_t last_statement_type)
875 {
876         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
877         uc_locals_t *locals = &compiler->locals;
878         uc_upvals_t *upvals = &compiler->upvals;
879         size_t i;
880 
881         if (compiler->function->module)
882                 uc_compiler_emit_exports(compiler);
883 
884         uc_compiler_emit_insn(compiler, 0, I_LNULL);
885         uc_compiler_emit_insn(compiler, 0, I_RETURN);
886 
887         for (i = 0; i < locals->count; i++) {
888                 uc_chunk_debug_add_variable(chunk,
889                         locals->entries[i].from,
890                         chunk->count,
891                         i,
892                         false,
893                         locals->entries[i].name);
894 
895                 ucv_put(locals->entries[i].name);
896         }
897 
898         for (i = 0; i < upvals->count; i++) {
899                 uc_chunk_debug_add_variable(chunk,
900                         0,
901                         chunk->count,
902                         i,
903                         true,
904                         upvals->entries[i].name);
905 
906                 ucv_put(upvals->entries[i].name);
907         }
908 
909         uc_vector_clear(locals);
910         uc_vector_clear(upvals);
911 
912         if (compiler->parser->error) {
913                 uc_program_function_free(compiler->function);
914 
915                 return NULL;
916         }
917 
918         return compiler->function;
919 }
920 
921 static void
922 uc_compiler_enter_scope(uc_compiler_t *compiler)
923 {
924         compiler->scope_depth++;
925 }
926 
927 static void
928 uc_compiler_leave_scope(uc_compiler_t *compiler)
929 {
930         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
931         uc_locals_t *locals = &compiler->locals;
932 
933         compiler->scope_depth--;
934 
935         while (locals->count > 0 && locals->entries[locals->count - 1].depth > (ssize_t)compiler->scope_depth) {
936                 locals->count--;
937 
938                 uc_chunk_debug_add_variable(chunk,
939                         locals->entries[locals->count].from,
940                         chunk->count,
941                         locals->count,
942                         false,
943                         locals->entries[locals->count].name);
944 
945                 ucv_put(locals->entries[locals->count].name);
946                 locals->entries[locals->count].name = NULL;
947 
948                 uc_compiler_emit_insn(compiler, 0,
949                         locals->entries[locals->count].captured ? I_CUPV : I_POP);
950         }
951 }
952 
953 static bool
954 uc_compiler_is_strict(uc_compiler_t *compiler)
955 {
956         uc_function_t *fn = (uc_function_t *)compiler->function;
957 
958         return fn->strict;
959 }
960 
961 static ssize_t
962 uc_compiler_declare_local(uc_compiler_t *compiler, uc_value_t *name, bool constant)
963 {
964         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
965         uc_locals_t *locals = &compiler->locals;
966         const char *str1, *str2;
967         size_t i, len1, len2;
968 
969         if (locals->count >= 0x00FFFFFF) {
970                 uc_compiler_syntax_error(compiler, 0, "Too many local variables");
971 
972                 return -1;
973         }
974 
975         str1 = ucv_string_get(name);
976         len1 = ucv_string_length(name);
977 
978         for (i = locals->count; i > 0; i--) {
979                 if (locals->entries[i - 1].depth != -1 && locals->entries[i - 1].depth < (ssize_t)compiler->scope_depth)
980                         break;
981 
982                 str2 = ucv_string_get(locals->entries[i - 1].name);
983                 len2 = ucv_string_length(locals->entries[i - 1].name);
984 
985                 if (str1 && str2 && len1 == len2 && !memcmp(str1, str2, len1)) {
986                         if (locals->entries[i - 1].funcstub) {
987                                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
988                                         "Variable '%s' redeclared", str2);
989 
990                                 return -1;
991                         }
992 
993                         if (uc_compiler_is_strict(compiler)) {
994                                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
995                                         "Variable '%s' redeclared", str2);
996 
997                                 return -1;
998                         }
999 
1000                         return i - 1;
1001                 }
1002         }
1003 
1004         uc_vector_push(locals, {
1005                 .name = ucv_get(name),
1006                 .depth = -1,
1007                 .captured = false,
1008                 .from = chunk->count,
1009                 .constant = constant
1010         });
1011 
1012         return -1;
1013 }
1014 
1015 static ssize_t
1016 uc_compiler_initialize_local(uc_compiler_t *compiler)
1017 {
1018         uc_locals_t *locals = &compiler->locals;
1019 
1020         locals->entries[locals->count - 1].depth = compiler->scope_depth;
1021 
1022         return locals->count - 1;
1023 }
1024 
1025 static ssize_t
1026 uc_compiler_resolve_local(uc_compiler_t *compiler, uc_value_t *name, bool *constant)
1027 {
1028         uc_locals_t *locals = &compiler->locals;
1029         const char *str1, *str2;
1030         size_t i, len1, len2;
1031 
1032         str1 = ucv_string_get(name);
1033         len1 = ucv_string_length(name);
1034 
1035         for (i = locals->count; i > 0; i--) {
1036                 str2 = ucv_string_get(locals->entries[i - 1].name);
1037                 len2 = ucv_string_length(locals->entries[i - 1].name);
1038 
1039                 if (!str1 || !str2 || len1 != len2 || memcmp(str1, str2, len1))
1040                         continue;
1041 
1042                 if (locals->entries[i - 1].depth == -1) {
1043                         uc_compiler_syntax_error(compiler, 0,
1044                                 "Can't access lexical declaration '%s' before initialization", str2);
1045 
1046                         return -1;
1047                 }
1048 
1049                 *constant = locals->entries[i - 1].constant;
1050 
1051                 return i - 1;
1052         }
1053 
1054         return -1;
1055 }
1056 
1057 static ssize_t
1058 uc_compiler_resolve_funcstub(uc_compiler_t *compiler, uc_value_t *name)
1059 {
1060         uc_locals_t *locals = &compiler->locals;
1061         const char *str1, *str2;
1062         size_t i, len1, len2;
1063 
1064         str1 = ucv_string_get(name);
1065         len1 = ucv_string_length(name);
1066 
1067         for (i = locals->count; i > 0; i--) {
1068                 if (locals->entries[i - 1].depth != -1 &&
1069                     locals->entries[i - 1].depth < (ssize_t)compiler->scope_depth)
1070                         break;
1071 
1072                 str2 = ucv_string_get(locals->entries[i - 1].name);
1073                 len2 = ucv_string_length(locals->entries[i - 1].name);
1074 
1075                 if (str1 && str2 && len1 == len2 && !memcmp(str1, str2, len1))
1076                         return locals->entries[i - 1].funcstub ? (ssize_t)(i - 1) : -1;
1077         }
1078 
1079         return -1;
1080 }
1081 
1082 static ssize_t
1083 uc_compiler_add_upval(uc_compiler_t *compiler, size_t idx, bool local, uc_value_t *name, bool constant)
1084 {
1085         uc_function_t *function = (uc_function_t *)compiler->function;
1086         uc_upvals_t *upvals = &compiler->upvals;
1087         uc_upval_t *uv;
1088         size_t i;
1089 
1090         for (i = 0, uv = upvals->entries; i < upvals->count; i++, uv = upvals->entries + i)
1091                 if (uv->index == idx && uv->local == local)
1092                         return i;
1093 
1094         /* XXX: encoding... */
1095         if (upvals->count >= (2 << 14)) {
1096                 uc_compiler_syntax_error(compiler, 0, "Too many upvalues");
1097 
1098                 return -1;
1099         }
1100 
1101         uc_vector_push(upvals, {
1102                 .local = local,
1103                 .index = idx,
1104                 .name  = ucv_get(name),
1105                 .constant = constant
1106         });
1107 
1108         function->nupvals++;
1109 
1110         return upvals->count - 1;
1111 }
1112 
1113 static ssize_t
1114 uc_compiler_resolve_upval(uc_compiler_t *compiler, uc_value_t *name, bool *constant)
1115 {
1116         uc_upvals_t *upvals = &compiler->upvals;
1117         uc_upval_t *uv;
1118         ssize_t idx;
1119         size_t i;
1120 
1121         if (!compiler->parent) {
1122                 for (i = 0, uv = upvals->entries; i < upvals->count; i++, uv = upvals->entries + i) {
1123                         if (ucv_is_equal(uv->name, name) && uv->local == false) {
1124                                 *constant = uv->constant;
1125 
1126                                 return i;
1127                         }
1128                 }
1129 
1130                 return -1;
1131         }
1132 
1133         idx = uc_compiler_resolve_local(compiler->parent, name, constant);
1134 
1135         if (idx > -1) {
1136                 compiler->parent->locals.entries[idx].captured = true;
1137 
1138                 return uc_compiler_add_upval(compiler, idx, true, name, *constant);
1139         }
1140 
1141         idx = uc_compiler_resolve_upval(compiler->parent, name, constant);
1142 
1143         if (idx > -1)
1144                 return uc_compiler_add_upval(compiler, idx, false, name, *constant);
1145 
1146         return -1;
1147 }
1148 
1149 static void
1150 uc_compiler_backpatch(uc_compiler_t *compiler, size_t break_addr, size_t next_addr)
1151 {
1152         uc_patchlist_t *pl = compiler->patchlist;
1153         volatile ssize_t jmpaddr;
1154         size_t i;
1155 
1156         for (i = 0; i < pl->count; i++) {
1157                 jmpaddr = uc_compiler_get_jmpaddr(compiler, pl->entries[i]);
1158 
1159                 switch (jmpaddr) {
1160                 case TK_BREAK:
1161                         /* if we have a break addr, patch instruction */
1162                         if (break_addr) {
1163                                 uc_compiler_set_jmpaddr(compiler, pl->entries[i], break_addr);
1164                                 continue;
1165                         }
1166 
1167                         break;
1168 
1169                 case TK_CONTINUE:
1170                         /* if we have a continue addr, patch instruction */
1171                         if (next_addr) {
1172                                 uc_compiler_set_jmpaddr(compiler, pl->entries[i], next_addr);
1173                                 continue;
1174                         }
1175 
1176                         break;
1177                 }
1178 
1179                 /* there should be no unhandled instructions */
1180                 assert(0);
1181         }
1182 
1183         free(pl->entries);
1184 
1185         compiler->patchlist = pl->parent;
1186 }
1187 
1188 static bool
1189 uc_compiler_check_assignment_lhs(uc_compiler_t *compiler)
1190 {
1191         return (
1192                 compiler->patchlist == NULL ||
1193                 compiler->patchlist->count == 0 ||
1194                 compiler->patchlist->token != TK_EXP
1195         );
1196 }
1197 
1198 static void
1199 uc_compiler_emit_inc_dec(uc_compiler_t *compiler, uc_tokentype_t toktype, bool is_postfix)
1200 {
1201         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
1202         uc_value_t *varname = NULL;
1203         uc_vm_insn_t type;
1204         uint32_t cidx = 0;
1205         int insn;
1206 
1207         /* determine kind of emitted load instruction and operand value (if any) */
1208         type = chunk->entries ? chunk->entries[compiler->last_insn] : 0;
1209 
1210         if (type == I_LVAR || type == I_LLOC || type == I_LUPV) {
1211                 cidx = uc_compiler_get_u32(compiler, compiler->last_insn + 1);
1212 
1213                 if (type == I_LLOC && compiler->locals.entries[cidx].constant)
1214                         varname = compiler->locals.entries[cidx].name;
1215                 else if (type == I_LUPV && compiler->upvals.entries[cidx].constant)
1216                         varname = compiler->upvals.entries[cidx].name;
1217 
1218                 if (varname)
1219                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
1220                                 "Invalid increment/decrement of constant '%s'",
1221                                 ucv_string_get(varname));
1222 
1223                 uc_chunk_pop(chunk);
1224                 uc_chunk_pop(chunk);
1225                 uc_chunk_pop(chunk);
1226                 uc_chunk_pop(chunk);
1227                 uc_chunk_pop(chunk);
1228         }
1229 
1230         /* if we're mutating an object or array field, pop the last lval instruction
1231          * to leave object + last field name value on stack */
1232         else if (type == I_LVAL) {
1233                 if (!uc_compiler_check_assignment_lhs(compiler)) {
1234                         uc_compiler_syntax_error(compiler, 0,
1235                                 "Invalid left-hand side expression for increment/decrement");
1236 
1237                         return;
1238                 }
1239 
1240                 uc_chunk_pop(chunk);
1241         }
1242         else {
1243                 uc_compiler_syntax_error(compiler, 0, "Invalid increment/decrement operand");
1244 
1245                 return;
1246         }
1247 
1248         insn = (toktype == TK_INC) ? I_PLUS : I_MINUS;
1249 
1250         /* add / subtract 1 */
1251         uc_compiler_emit_insn(compiler, 0, I_LOAD8);
1252         uc_compiler_emit_u8(compiler, 0, 1);
1253 
1254         /* depending on variable type, emit corresponding increment instruction */
1255         switch (type) {
1256         case I_LVAR:
1257                 uc_compiler_emit_insn(compiler, 0, I_UVAR);
1258                 uc_compiler_emit_u32(compiler, 0, (insn << 24) | cidx);
1259                 break;
1260 
1261         case I_LLOC:
1262                 uc_compiler_emit_insn(compiler, 0, I_ULOC);
1263                 uc_compiler_emit_u32(compiler, 0, (insn << 24) | cidx);
1264                 break;
1265 
1266         case I_LUPV:
1267                 uc_compiler_emit_insn(compiler, 0, I_UUPV);
1268                 uc_compiler_emit_u32(compiler, 0, (insn << 24) | cidx);
1269                 break;
1270 
1271         case I_LVAL:
1272                 uc_compiler_emit_insn(compiler, 0, I_UVAL);
1273                 uc_compiler_emit_u8(compiler, 0, insn);
1274                 break;
1275 
1276         default:
1277                 break;
1278         }
1279 
1280         /* for post increment or decrement, add/subtract 1 to yield final value */
1281         if (is_postfix) {
1282                 uc_compiler_emit_insn(compiler, 0, I_LOAD8);
1283                 uc_compiler_emit_u8(compiler, 0, 1);
1284 
1285                 uc_compiler_emit_insn(compiler, 0, (toktype == TK_INC) ? I_SUB : I_ADD);
1286         }
1287 }
1288 
1289 
1290 static void
1291 uc_compiler_compile_unary(uc_compiler_t *compiler)
1292 {
1293         uc_tokentype_t type = compiler->parser->prev.type;
1294 
1295         uc_compiler_parse_precedence(compiler, P_UNARY);
1296 
1297         switch (type) {
1298         case TK_SUB:
1299                 uc_compiler_emit_insn(compiler, 0, I_MINUS);
1300                 break;
1301 
1302         case TK_ADD:
1303                 uc_compiler_emit_insn(compiler, 0, I_PLUS);
1304                 break;
1305 
1306         case TK_NOT:
1307                 uc_compiler_emit_insn(compiler, 0, I_NOT);
1308                 break;
1309 
1310         case TK_COMPL:
1311                 uc_compiler_emit_insn(compiler, 0, I_COMPL);
1312                 break;
1313 
1314         case TK_INC:
1315         case TK_DEC:
1316                 uc_compiler_emit_inc_dec(compiler, type, false);
1317                 break;
1318 
1319         default:
1320                 return;
1321         }
1322 }
1323 
1324 static void
1325 uc_compiler_compile_binary(uc_compiler_t *compiler)
1326 {
1327         uc_tokentype_t type = compiler->parser->prev.type;
1328 
1329         uc_compiler_parse_precedence(compiler, uc_compiler_parse_rule(type)->precedence + 1);
1330         uc_compiler_emit_insn(compiler, 0, I_BOR + (type - TK_BOR));
1331 }
1332 
1333 static void
1334 uc_compiler_compile_delete(uc_compiler_t *compiler)
1335 {
1336         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
1337         uc_vm_insn_t type;
1338 
1339         uc_compiler_parse_precedence(compiler, P_UNARY);
1340 
1341         type = (compiler->last_insn < chunk->count)
1342                 ? chunk->entries[compiler->last_insn] : 0;
1343 
1344         if (type != I_LVAL) {
1345                 uc_compiler_syntax_error(compiler, 0,
1346                         "expecting a property access expression");
1347 
1348                 return;
1349         }
1350 
1351         chunk->entries[compiler->last_insn] = I_DELETE;
1352 }
1353 
1354 /* `typeof` is sugar for the standard library's type() function; the value's
1355  * type name is pushed, or null for a null value, exactly as type() returns. */
1356 static void
1357 uc_compiler_compile_typeof(uc_compiler_t *compiler)
1358 {
1359         uc_compiler_parse_precedence(compiler, P_UNARY);
1360 
1361         uc_compiler_emit_stcall(compiler, 0, UC_FN_TYPE, 1);
1362 }
1363 
1364 static uc_vm_insn_t
1365 uc_compiler_emit_variable_rw(uc_compiler_t *compiler, uc_value_t *varname, uc_tokentype_t type)
1366 {
1367         uc_vm_insn_t insn;
1368         uint32_t sub_insn;
1369         bool constant;
1370         ssize_t idx;
1371 
1372         switch (type) {
1373         case TK_ASADD:     sub_insn = I_ADD;     break;
1374         case TK_ASSUB:     sub_insn = I_SUB;     break;
1375         case TK_ASMUL:     sub_insn = I_MUL;     break;
1376         case TK_ASDIV:     sub_insn = I_DIV;     break;
1377         case TK_ASMOD:     sub_insn = I_MOD;     break;
1378         case TK_ASBAND:    sub_insn = I_BAND;    break;
1379         case TK_ASBXOR:    sub_insn = I_BXOR;    break;
1380         case TK_ASBOR:     sub_insn = I_BOR;     break;
1381         case TK_ASLEFT:    sub_insn = I_LSHIFT;  break;
1382         case TK_ASRIGHT:   sub_insn = I_RSHIFT;  break;
1383         case TK_ASEXP:     sub_insn = I_EXP;     break;
1384         default:           sub_insn = 0;         break;
1385         }
1386 
1387         if (!varname) {
1388                 if (sub_insn != 0)
1389                         insn = I_UVAL;
1390                 else if (type != 0 && type != TK_QDOT && type != TK_QLBRACK)
1391                         insn = I_SVAL;
1392                 else
1393                         insn = I_LVAL;
1394 
1395                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, insn);
1396 
1397                 if (sub_insn)
1398                         uc_compiler_emit_u8(compiler, compiler->parser->prev.pos, sub_insn);
1399         }
1400         else if ((idx = uc_compiler_resolve_local(compiler, varname, &constant)) > -1) {
1401                 insn = sub_insn ? I_ULOC : (type ? I_SLOC : I_LLOC);
1402 
1403                 if (insn != I_LLOC && constant)
1404                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
1405                                 "Invalid assignment to constant '%s'", ucv_string_get(varname));
1406 
1407                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, insn);
1408                 uc_compiler_emit_u32(compiler, compiler->parser->prev.pos,
1409                         ((sub_insn & 0xff) << 24) | idx);
1410         }
1411         else if ((idx = uc_compiler_resolve_upval(compiler, varname, &constant)) > -1) {
1412                 insn = sub_insn ? I_UUPV : (type ? I_SUPV : I_LUPV);
1413 
1414                 if (insn != I_LUPV && constant)
1415                         uc_compiler_syntax_error(compiler, 0,
1416                                 "Invalid assignment to constant '%s'", ucv_string_get(varname));
1417 
1418                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, insn);
1419                 uc_compiler_emit_u32(compiler, compiler->parser->prev.pos,
1420                         ((sub_insn & 0xff) << 24) | idx);
1421         }
1422         else {
1423                 idx = uc_program_add_constant(compiler->program, varname);
1424                 insn = sub_insn ? I_UVAR : (type ? I_SVAR : I_LVAR);
1425 
1426                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, insn);
1427                 uc_compiler_emit_u32(compiler, compiler->parser->prev.pos,
1428                         ((sub_insn & 0xff) << 24) | idx);
1429         }
1430 
1431         return insn;
1432 }
1433 
1434 static void
1435 uc_compiler_emit_variable_copy(uc_compiler_t *compiler, uc_value_t *var)
1436 {
1437         if (!var) {
1438                 uc_compiler_emit_copy(compiler, 0, 1);
1439                 uc_compiler_emit_copy(compiler, 0, 1);
1440         }
1441 
1442         uc_compiler_emit_variable_rw(compiler, var, 0);
1443 }
1444 
1445 static void
1446 uc_compiler_compile_and(uc_compiler_t *compiler)
1447 {
1448         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
1449         size_t jmpz_off;
1450 
1451         uc_compiler_emit_copy(compiler, 0, 0);
1452         jmpz_off = uc_compiler_emit_jmpz(compiler, 0);
1453         uc_compiler_emit_insn(compiler, 0, I_POP);
1454         uc_compiler_parse_precedence(compiler, P_AND);
1455         uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
1456 }
1457 
1458 static void
1459 uc_compiler_compile_and_assignment(uc_compiler_t *compiler, uc_value_t *var)
1460 {
1461         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
1462         size_t jmpz_off;
1463 
1464         uc_compiler_emit_variable_copy(compiler, var);
1465         uc_compiler_emit_copy(compiler, 0, 0);
1466         jmpz_off = uc_compiler_emit_jmpz(compiler, 0);
1467         uc_compiler_emit_insn(compiler, 0, I_POP);
1468         uc_compiler_parse_precedence(compiler, P_ASSIGN);
1469         uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
1470         uc_compiler_emit_variable_rw(compiler, var, TK_ASSIGN);
1471 }
1472 
1473 static void
1474 uc_compiler_compile_or(uc_compiler_t *compiler)
1475 {
1476         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
1477         size_t jmpz_off, jmp_off;
1478 
1479         uc_compiler_emit_copy(compiler, 0, 0);
1480         jmpz_off = uc_compiler_emit_jmpz(compiler, 0);
1481         jmp_off = uc_compiler_emit_jmp(compiler, 0);
1482         uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
1483         uc_compiler_emit_insn(compiler, 0, I_POP);
1484         uc_compiler_parse_precedence(compiler, P_OR);
1485         uc_compiler_set_jmpaddr(compiler, jmp_off, chunk->count);
1486 }
1487 
1488 static void
1489 uc_compiler_compile_or_assignment(uc_compiler_t *compiler, uc_value_t *var)
1490 {
1491         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
1492         size_t jmpz_off, jmp_off;
1493 
1494         uc_compiler_emit_variable_copy(compiler, var);
1495         jmpz_off = uc_compiler_emit_jmpz(compiler, 0);
1496         uc_compiler_emit_variable_rw(compiler, var, 0);
1497         jmp_off = uc_compiler_emit_jmp(compiler, 0);
1498         uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
1499         uc_compiler_parse_precedence(compiler, P_ASSIGN);
1500         uc_compiler_emit_variable_rw(compiler, var, TK_ASSIGN);
1501         uc_compiler_set_jmpaddr(compiler, jmp_off, chunk->count);
1502 }
1503 
1504 static void
1505 uc_compiler_compile_nullish(uc_compiler_t *compiler)
1506 {
1507         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
1508         size_t jmpz_off, jmp_off;
1509 
1510         uc_compiler_emit_copy(compiler, 0, 0);
1511         uc_compiler_emit_insn(compiler, 0, I_LNULL);
1512         uc_compiler_emit_insn(compiler, 0, I_NES);
1513         jmpz_off = uc_compiler_emit_jmpz(compiler, 0);
1514         jmp_off = uc_compiler_emit_jmp(compiler, 0);
1515         uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
1516         uc_compiler_emit_insn(compiler, 0, I_POP);
1517         uc_compiler_parse_precedence(compiler, P_OR);
1518         uc_compiler_set_jmpaddr(compiler, jmp_off, chunk->count);
1519 }
1520 
1521 static void
1522 uc_compiler_compile_nullish_assignment(uc_compiler_t *compiler, uc_value_t *var)
1523 {
1524         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
1525         size_t jmpz_off, jmp_off;
1526 
1527         uc_compiler_emit_variable_copy(compiler, var);
1528         uc_compiler_emit_insn(compiler, 0, I_LNULL);
1529         uc_compiler_emit_insn(compiler, 0, I_NES);
1530         jmpz_off = uc_compiler_emit_jmpz(compiler, 0);
1531         uc_compiler_emit_variable_rw(compiler, var, 0);
1532         jmp_off = uc_compiler_emit_jmp(compiler, 0);
1533         uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
1534         uc_compiler_parse_precedence(compiler, P_ASSIGN);
1535         uc_compiler_emit_variable_rw(compiler, var, TK_ASSIGN);
1536         uc_compiler_set_jmpaddr(compiler, jmp_off, chunk->count);
1537 }
1538 
1539 static void
1540 uc_compiler_compile_expression(uc_compiler_t *compiler, bool tag_stmt)
1541 {
1542         if (tag_stmt)
1543                 uc_compiler_emit_stmt_start(compiler, &compiler->parser->curr);
1544 
1545         uc_compiler_parse_precedence(compiler, P_COMMA);
1546 
1547         if (tag_stmt)
1548                 uc_compiler_emit_stmt_end(compiler);
1549 }
1550 
1551 static bool
1552 uc_compiler_compile_assignment(uc_compiler_t *compiler, uc_value_t *var)
1553 {
1554         uc_tokentype_t type = compiler->parser->curr.type;
1555 
1556         if (!uc_compiler_parse_at_assignment_op(compiler))
1557                 return false;
1558 
1559         if (!uc_compiler_check_assignment_lhs(compiler)) {
1560                 uc_compiler_syntax_error(compiler, 0,
1561                         "Invalid left-hand side expression for assignment");
1562 
1563                 return false;
1564         }
1565 
1566         switch (type)
1567         {
1568         case TK_ASNULLISH:
1569                 uc_compiler_parse_advance(compiler);
1570                 uc_compiler_compile_nullish_assignment(compiler, var);
1571                 break;
1572 
1573         case TK_ASOR:
1574                 uc_compiler_parse_advance(compiler);
1575                 uc_compiler_compile_or_assignment(compiler, var);
1576                 break;
1577 
1578         case TK_ASAND:
1579                 uc_compiler_parse_advance(compiler);
1580                 uc_compiler_compile_and_assignment(compiler, var);
1581                 break;
1582 
1583         default:
1584                 uc_compiler_parse_advance(compiler);
1585                 uc_compiler_parse_precedence(compiler, P_ASSIGN);
1586                 uc_compiler_emit_variable_rw(compiler, var, type);
1587                 break;
1588         }
1589 
1590         return true;
1591 }
1592 
1593 static bool
1594 uc_compiler_compile_arrowfn(uc_compiler_t *compiler, uc_value_t *args, bool restarg)
1595 {
1596         uc_tokentype_t last_statement_type = TK_NULL;
1597         bool array = (ucv_type(args) == UC_ARRAY);
1598         uc_compiler_t fncompiler = { 0 };
1599         size_t i, pos, load_off;
1600         uc_function_t *fn;
1601         ssize_t slot;
1602 
1603         if (!uc_compiler_parse_match(compiler, TK_ARROW))
1604                 return false;
1605 
1606         pos = compiler->parser->prev.pos;
1607 
1608         uc_compiler_init(&fncompiler, NULL, uc_compiler_current_source(compiler),
1609                 compiler->parser->prev.pos,
1610                 compiler->program,
1611                 uc_compiler_is_strict(compiler));
1612 
1613         fncompiler.parent = compiler;
1614         fncompiler.parser = compiler->parser;
1615         fncompiler.exprstack = compiler->exprstack;
1616 
1617         fn = (uc_function_t *)fncompiler.function;
1618         fn->arrow = true;
1619         fn->vararg = args ? restarg : false;
1620         fn->nargs = array ? ucv_array_length(args) : !!args;
1621 
1622         uc_compiler_enter_scope(&fncompiler);
1623 
1624         /* declare local variables for arguments */
1625         for (i = 0; i < fn->nargs; i++) {
1626                 slot = uc_compiler_declare_local(&fncompiler,
1627                         array ? ucv_array_get(args, i) : args, false);
1628 
1629                 if (slot != -1)
1630                         uc_compiler_syntax_error(&fncompiler, pos,
1631                                 "Duplicate argument names are not allowed in this context");
1632 
1633                 uc_compiler_initialize_local(&fncompiler);
1634         }
1635 
1636         /* parse and compile body */
1637         if (uc_compiler_parse_match(&fncompiler, TK_LBRACE)) {
1638                 while (!uc_compiler_parse_check(&fncompiler, TK_RBRACE) &&
1639                        !uc_compiler_parse_check(&fncompiler, TK_EOF))
1640                         uc_compiler_compile_declaration(&fncompiler);
1641 
1642                 uc_compiler_parse_consume(&fncompiler, TK_RBRACE);
1643 
1644                 /* emit final return */
1645                 if (last_statement_type != TK_RETURN) {
1646                         uc_compiler_emit_insn(&fncompiler, 0, I_LNULL);
1647                         uc_compiler_emit_insn(&fncompiler, 0, I_RETURN);
1648                 }
1649         }
1650         else {
1651                 uc_compiler_emit_stmt_start(&fncompiler, &compiler->parser->curr);
1652                 uc_compiler_parse_precedence(&fncompiler, P_ASSIGN);
1653 
1654                 /* invoke a function call in tail position to avoid growing the stack */
1655                 bool tailcall = uc_compiler_tailcall_pending(&fncompiler);
1656 
1657                 uc_compiler_emit_insn(&fncompiler, 0, I_RETURN);
1658 
1659                 if (tailcall)
1660                         uc_compiler_emit_tailcall_marker(&fncompiler);
1661 
1662                 uc_compiler_emit_stmt_end(&fncompiler);
1663         }
1664 
1665         /* emit load instruction for function value */
1666         uc_compiler_emit_insn(compiler, pos, I_ARFN);
1667         load_off = uc_compiler_emit_u32(compiler, 0, 0);
1668 
1669         /* encode upvalue information */
1670         for (i = 0; i < fn->nupvals; i++)
1671                 uc_compiler_emit_s32(compiler, 0,
1672                         fncompiler.upvals.entries[i].local
1673                                 ? -(fncompiler.upvals.entries[i].index + 1)
1674                                 : fncompiler.upvals.entries[i].index);
1675 
1676         /* finalize function compiler */
1677         fn = uc_compiler_finish(&fncompiler, TK_RETURN);
1678 
1679         if (fn)
1680                 uc_compiler_set_u32(compiler, load_off,
1681                         uc_program_function_id(compiler->program, fn));
1682 
1683         return true;
1684 }
1685 
1686 static uc_tokentype_t
1687 uc_compiler_compile_var_or_arrowfn(uc_compiler_t *compiler, uc_value_t *name)
1688 {
1689         uc_tokentype_t rv;
1690 
1691         if (uc_compiler_exprstack_is(compiler, F_ASSIGNABLE) && uc_compiler_compile_assignment(compiler, name)) {
1692                 rv = TK_ASSIGN;
1693         }
1694         else if (uc_compiler_compile_arrowfn(compiler, name, false)) {
1695                 rv = TK_ARROW;
1696         }
1697         else {
1698                 uc_compiler_emit_variable_rw(compiler, name, 0);
1699                 rv = TK_LABEL;
1700         }
1701 
1702         return rv;
1703 }
1704 
1705 static void
1706 uc_compiler_compile_paren(uc_compiler_t *compiler)
1707 {
1708         uc_value_t *varnames = NULL, *varname;
1709         bool maybe_arrowfn = false;
1710         bool restarg = false;
1711 
1712         /* First try to parse a complete parameter expression and remember the
1713          * consumed label tokens as we go. */
1714         while (true) {
1715                 if (uc_compiler_parse_check(compiler, TK_LABEL)) {
1716                         if (!varnames)
1717                                 varnames = ucv_array_new(NULL);
1718 
1719                         ucv_array_push(varnames, ucv_get(compiler->parser->curr.uv));
1720 
1721                         /* A subsequent slash cannot be a regular expression literal */
1722                         compiler->parser->lex.no_regexp = true;
1723                         uc_compiler_parse_advance(compiler);
1724                 }
1725                 else if (uc_compiler_parse_match(compiler, TK_ELLIP)) {
1726                         uc_compiler_parse_consume(compiler, TK_LABEL);
1727 
1728                         if (!varnames)
1729                                 varnames = ucv_array_new(NULL);
1730 
1731                         ucv_array_push(varnames, ucv_get(compiler->parser->prev.uv));
1732 
1733                         /* A subsequent slash cannot be a regular expression literal */
1734                         compiler->parser->lex.no_regexp = true;
1735                         uc_compiler_parse_consume(compiler, TK_RPAREN);
1736 
1737                         maybe_arrowfn = true;
1738                         restarg = true;
1739 
1740                         break;
1741                 }
1742                 else if (uc_compiler_parse_check(compiler, TK_COMMA)) {
1743                         /* Reject consecutive commas */
1744                         if (compiler->parser->prev.type == TK_COMMA)
1745                                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
1746                                         "Expecting expression");
1747 
1748                         uc_compiler_parse_advance(compiler);
1749 
1750                         continue;
1751                 }
1752                 else {
1753                         maybe_arrowfn = uc_compiler_parse_check(compiler, TK_RPAREN);
1754 
1755                         if (maybe_arrowfn) {
1756                                 /* A subsequent slash cannot be a regular expression literal */
1757                                 compiler->parser->lex.no_regexp = true;
1758                                 uc_compiler_parse_advance(compiler);
1759                         }
1760 
1761                         /* If we encounter a dot, treat potential subsequent keyword as label */
1762                         if (uc_compiler_parse_check(compiler, TK_DOT) ||
1763                             uc_compiler_parse_check(compiler, TK_QDOT))
1764                                 compiler->parser->lex.no_keyword = true;
1765 
1766                         break;
1767                 }
1768         }
1769 
1770         /* The lhs we parsed so far is eligible for an arrow function arg list,
1771          * try to continue compiling into arrow function... */
1772         if (maybe_arrowfn) {
1773                 /* If we can parse the remainder as arrow function, we're done */
1774                 if (uc_compiler_compile_arrowfn(compiler, varnames, restarg))
1775                         goto out;
1776 
1777                 /* ... otherwise disallow the `...` spread operator and empty
1778                  * parenthesized expressions */
1779                 if (restarg || !varnames) {
1780                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
1781                                 "Expecting '=>' after parameter list");
1782 
1783                         goto out;
1784                 }
1785         }
1786 
1787         /* If we reach this, the expression we parsed so far cannot be a parameter
1788          * list for an arrow function and we might have consumed one or multiple
1789          * consecutive labels. */
1790         if (varnames) {
1791                 /* Get last variable name */
1792                 varname = ucv_array_get(varnames,
1793                         ucv_array_length(varnames) - 1);
1794 
1795                 /* If we consumed the right paren, the expression is complete and we
1796                  * only need to emit a variable read operation for the last parsed
1797                  * label since previous read operations are shadowed by subsequent ones
1798                  * in comma expressions and since pure variable reads are without
1799                  * side effects. */
1800                 if (maybe_arrowfn) {
1801                         uc_compiler_emit_variable_rw(compiler, varname, 0);
1802 
1803                         goto out;
1804                 }
1805 
1806                 /* ... otherwise if the last token was a label, try continue parsing as
1807                  * assignment or arrow function expression and if that fails, as
1808                  * relational one */
1809                 if (compiler->parser->prev.type == TK_LABEL) {
1810                         uc_compiler_exprstack_push(compiler, TK_LABEL, F_ASSIGNABLE);
1811 
1812                         if (uc_compiler_compile_var_or_arrowfn(compiler, varname) == TK_LABEL) {
1813                                 /* parse operand and rhs */
1814                                 while (P_TERNARY <= uc_compiler_parse_rule(compiler->parser->curr.type)->precedence) {
1815                                         uc_parse_rule_t *rule =
1816                                                 uc_compiler_parse_rule(compiler->parser->curr.type);
1817 
1818                                         if (!rule->infix)
1819                                                 break;
1820 
1821                                         uc_compiler_parse_advance(compiler);
1822                                         rule->infix(compiler);
1823                                 }
1824                         }
1825 
1826                         /* If we're not at the end of the expression, we require a comma.
1827                          * Also pop intermediate result in this case. */
1828                         if (!uc_compiler_parse_check(compiler, TK_RPAREN)) {
1829                                 uc_compiler_emit_insn(compiler, 0, I_POP);
1830                                 uc_compiler_parse_consume(compiler, TK_COMMA);
1831                         }
1832 
1833                         uc_compiler_exprstack_pop(compiler);
1834                 }
1835         }
1836 
1837         /* When we reach this point, all already complete expression possibilities
1838          * have been eliminated and we either need to compile the next, non-label
1839          * expression or reached the closing paren. If neither applies, we have a
1840          * syntax error. */
1841         if (!uc_compiler_parse_check(compiler, TK_RPAREN))
1842                 uc_compiler_compile_expression(compiler, false);
1843 
1844         /* A subsequent slash cannot be a regular expression literal */
1845         compiler->parser->lex.no_regexp = true;
1846 
1847         /* At this point we expect the end of the parenthesized expression, anything
1848          * else is a syntax error */
1849         uc_compiler_parse_consume(compiler, TK_RPAREN);
1850 
1851 out:
1852         ucv_put(varnames);
1853 }
1854 
1855 static void
1856 uc_compiler_compile_call(uc_compiler_t *compiler)
1857 {
1858         bool optional_chaining = (compiler->parser->prev.type == TK_QLPAREN);
1859         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
1860         uc_jmplist_t spreads = { 0 };
1861         uc_vm_insn_t type;
1862         size_t i, nargs = 0;
1863         bool mcall;
1864 
1865         /* determine the kind of the lhs */
1866         type = (compiler->last_insn < chunk->count)
1867                 ? chunk->entries[compiler->last_insn] : 0;
1868         mcall = (type == I_LVAL);
1869 
1870         if (mcall) {
1871                 uc_chunk_pop(chunk);
1872                 uc_compiler_emit_insn(compiler, 0, I_PVAL);
1873         }
1874 
1875         if (optional_chaining)
1876                 uc_compiler_emit_jmpnt(compiler, compiler->parser->prev.pos,
1877                         (1u << UC_CFUNCTION) | (1u << UC_CLOSURE), mcall);
1878 
1879         /* compile arguments */
1880         if (!uc_compiler_parse_check(compiler, TK_RPAREN)) {
1881                 do {
1882                         /* if this is a spread arg, remember the argument index */
1883                         if (uc_compiler_parse_match(compiler, TK_ELLIP))
1884                                 uc_vector_push(&spreads, nargs);
1885 
1886                         /* compile argument expression */
1887                         uc_compiler_parse_precedence(compiler, P_ASSIGN);
1888                         nargs++;
1889                 }
1890                 while (uc_compiler_parse_match(compiler, TK_COMMA));
1891         }
1892 
1893         /* after a function call expression, no regexp literal can follow */
1894         compiler->parser->lex.no_regexp = true;
1895         uc_compiler_parse_consume(compiler, TK_RPAREN);
1896 
1897         /* if lhs is a dot or bracket expression, emit a method call */
1898         uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_CALL);
1899 
1900         if (nargs > 0xffff || spreads.count > 0x7fff)
1901                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
1902                         "Too many function call arguments");
1903 
1904         /* encode ordinary (bits 0..15) and spread argument (bits 16..30) count
1905            as well as method call indication (bit 31) */
1906         uc_compiler_emit_u32(compiler, 0,
1907                 (mcall ? 0x80000000 : 0) | ((spreads.count & 0x7fff) << 16) | nargs);
1908 
1909         /* encode spread arg positions */
1910         for (i = 0; i < spreads.count; i++)
1911                 uc_compiler_emit_u16(compiler, 0, nargs - spreads.entries[i] - 1);
1912 
1913         uc_vector_clear(&spreads);
1914 
1915         /* remember the chunk end right after the invocation's operands for potential
1916          * tail call optimization */
1917         compiler->tailcall_off = uc_compiler_current_chunk(compiler)->count;
1918 
1919         compiler->patchlist->depth = uc_compiler_current_chunk(compiler)->count;
1920 }
1921 
1922 static void
1923 uc_compiler_compile_post_inc(uc_compiler_t *compiler)
1924 {
1925         uc_compiler_emit_inc_dec(compiler, compiler->parser->prev.type, true);
1926 }
1927 
1928 static bool
1929 uc_compiler_is_use_strict_pragma(uc_compiler_t *compiler)
1930 {
1931         uc_value_t *v;
1932 
1933         if (uc_compiler_current_chunk(compiler)->count > 0)
1934                 return false;
1935 
1936         if (compiler->parser->lex.block != STATEMENTS)
1937                 return false;
1938 
1939         v = compiler->parser->prev.uv;
1940 
1941         return (strcmp(ucv_string_get(v), "use strict") == 0);
1942 }
1943 
1944 static void
1945 uc_compiler_compile_constant(uc_compiler_t *compiler)
1946 {
1947         uc_function_t *fn;
1948         uint64_t u;
1949 
1950         switch (compiler->parser->prev.type) {
1951         case TK_THIS:
1952                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LTHIS);
1953                 break;
1954 
1955         case TK_NULL:
1956                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LNULL);
1957                 break;
1958 
1959         case TK_TRUE:
1960                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LTRUE);
1961                 break;
1962 
1963         case TK_FALSE:
1964                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LFALSE);
1965                 break;
1966 
1967         case TK_STRING:
1968                 if (uc_compiler_is_use_strict_pragma(compiler)) {
1969                         fn = (uc_function_t *)compiler->function;
1970                         fn->strict = true;
1971                 }
1972 
1973                 /* fall through */
1974 
1975         case TK_DOUBLE:
1976                 uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.uv);
1977                 break;
1978 
1979         case TK_REGEXP:
1980                 uc_compiler_emit_regexp(compiler, compiler->parser->prev.pos, compiler->parser->prev.uv);
1981                 break;
1982 
1983         case TK_NUMBER:
1984                 u = ucv_uint64_get(compiler->parser->prev.uv);
1985                 assert(errno == 0);
1986 
1987                 if (u <= 0xff) {
1988                         uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LOAD8);
1989                         uc_compiler_emit_u8(compiler, compiler->parser->prev.pos, u);
1990                 }
1991                 else if (u <= 0xffff) {
1992                         uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LOAD16);
1993                         uc_compiler_emit_u16(compiler, compiler->parser->prev.pos, u);
1994                 }
1995                 else if (u <= 0xffffffff) {
1996                         uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LOAD32);
1997                         uc_compiler_emit_u32(compiler, compiler->parser->prev.pos, u);
1998                 }
1999                 else {
2000                         uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.uv);
2001                 }
2002 
2003                 break;
2004 
2005         default:
2006                 break;
2007         }
2008 }
2009 
2010 static void
2011 uc_compiler_compile_template(uc_compiler_t *compiler)
2012 {
2013         uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.uv);
2014 
2015         while (true) {
2016                 if (uc_compiler_parse_check(compiler, TK_TEMPLATE)) {
2017                         /* a TK_TEMPLATE token only continues the current literal when the
2018                          * previous one was left open by a `${...}` placeholder, in which
2019                          * case the lexer emits a TK_PLACEH token in between; two adjacent
2020                          * TK_TEMPLATE tokens are separate literals and must be joined
2021                          * with an explicit operator
2022                          */
2023                         if (compiler->parser->prev.type == TK_TEMPLATE) {
2024                                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
2025                                         "Adjacent template literals are not implicitly concatenated");
2026 
2027                                 return;
2028                         }
2029 
2030                         uc_compiler_parse_advance(compiler);
2031                         uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.uv);
2032                         uc_compiler_emit_insn(compiler, 0, I_ADD);
2033                 }
2034                 else if (uc_compiler_parse_match(compiler, TK_PLACEH)) {
2035                         uc_compiler_compile_expression(compiler, true);
2036                         uc_compiler_emit_insn(compiler, 0, I_ADD);
2037                         uc_compiler_parse_consume(compiler, TK_RBRACE);
2038                 }
2039                 else {
2040                         break;
2041                 }
2042         }
2043 }
2044 
2045 static void
2046 uc_compiler_compile_comma(uc_compiler_t *compiler)
2047 {
2048         uc_compiler_emit_insn(compiler, compiler->parser->curr.pos, I_POP);
2049         uc_compiler_parse_precedence(compiler, P_ASSIGN);
2050 }
2051 
2052 static void
2053 uc_compiler_compile_labelexpr(uc_compiler_t *compiler)
2054 {
2055         uc_value_t *label = ucv_get(compiler->parser->prev.uv);
2056 
2057         uc_compiler_compile_var_or_arrowfn(compiler, label);
2058         ucv_put(label);
2059 }
2060 
2061 static uc_tokentype_t
2062 uc_compiler_compile_delimitted_block(uc_compiler_t *compiler, uc_tokentype_t endtype)
2063 {
2064         uc_tokentype_t last_statement_type = TK_NULL;
2065 
2066         while (!uc_compiler_parse_check(compiler, endtype) &&
2067                !uc_compiler_parse_check(compiler, TK_EOF))
2068                 last_statement_type = uc_compiler_compile_declaration(compiler);
2069 
2070         return uc_compiler_parse_check(compiler, endtype) ? last_statement_type : TK_EOF;
2071 }
2072 
2073 static void
2074 uc_compiler_compile_funcexpr_common(uc_compiler_t *compiler, bool require_name)
2075 {
2076         uc_tokentype_t last_statement_type = TK_NULL;
2077         uc_compiler_t fncompiler = { 0 };
2078         uc_value_t *name = NULL;
2079         ssize_t slot = -1, pos;
2080         uc_tokentype_t type;
2081         size_t i, load_off;
2082         uc_function_t *fn;
2083 
2084         pos = compiler->parser->prev.pos;
2085         type = compiler->parser->prev.type;
2086 
2087         if (uc_compiler_parse_match(compiler, TK_LABEL)) {
2088                 name = compiler->parser->prev.uv;
2089 
2090                 if (require_name && uc_compiler_parse_check(compiler, TK_SCOL)) {
2091                         slot = uc_compiler_resolve_funcstub(compiler, name);
2092 
2093                         if (slot > -1) {
2094                                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
2095                                         "Function '%s' redeclared", ucv_string_get(name));
2096 
2097                                 return;
2098                         }
2099 
2100                         slot = uc_compiler_declare_local(compiler, name, true);
2101 
2102                         if (slot > -1) {
2103                                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
2104                                         "Variable '%s' redeclared", ucv_string_get(name));
2105 
2106                                 return;
2107                         }
2108 
2109                         compiler->locals.entries[compiler->locals.count - 1].funcstub = true;
2110                         uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LNULL);
2111                         uc_compiler_initialize_local(compiler);
2112                         uc_compiler_parse_consume(compiler, TK_SCOL);
2113 
2114                         return;
2115                 }
2116 
2117                 /* A function declaration binds its name in the enclosing scope. A named
2118                  * function expression must not: its name is only visible inside its own
2119                  * body (for self-reference), and declaring it in the enclosing scope
2120                  * would both leak it and shift the local slots, corrupting the
2121                  * initialisation state of a `let`/`const` the expression initialises. */
2122                 if (require_name) {
2123                         slot = uc_compiler_resolve_funcstub(compiler, name);
2124 
2125                         if (slot > -1) {
2126                                 compiler->locals.entries[slot].funcstub = false;
2127                         }
2128                         else {
2129                                 slot = uc_compiler_declare_local(compiler, name,
2130                                         uc_compiler_is_strict(compiler));
2131 
2132                                 if (slot == -1)
2133                                         uc_compiler_initialize_local(compiler);
2134                                 else if (compiler->locals.entries[slot].constant)
2135                                         uc_compiler_syntax_error(compiler, pos,
2136                                                 "Redeclaration of constant '%s'",
2137                                                 ucv_string_get(name));
2138                         }
2139                 }
2140         }
2141         else if (require_name) {
2142                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, "Expecting function name");
2143         }
2144 
2145         uc_compiler_init(&fncompiler,
2146                 name ? ucv_string_get(name) : NULL,
2147                 uc_compiler_current_source(compiler),
2148                 compiler->parser->prev.pos,
2149                 compiler->program,
2150                 uc_compiler_is_strict(compiler));
2151 
2152         /* Bind a named function expression's name to its own callee slot so the
2153          * body can reference itself for recursion, without touching the enclosing
2154          * scope. Declarations keep the name in the enclosing scope (handled above). */
2155         if (name && !require_name) {
2156                 ucv_put(fncompiler.locals.entries[0].name);
2157                 fncompiler.locals.entries[0].name = ucv_get(name);
2158         }
2159 
2160         fncompiler.parent = compiler;
2161         fncompiler.parser = compiler->parser;
2162         fncompiler.exprstack = compiler->exprstack;
2163         fn = (uc_function_t *)fncompiler.function;
2164 
2165         uc_compiler_parse_consume(&fncompiler, TK_LPAREN);
2166 
2167         uc_compiler_enter_scope(&fncompiler);
2168 
2169         /* compile argument specification */
2170         while (true) {
2171                 if (uc_compiler_parse_check(&fncompiler, TK_RPAREN))
2172                         break;
2173 
2174                 if (uc_compiler_parse_match(&fncompiler, TK_ELLIP))
2175                         fn->vararg = true;
2176 
2177                 if (uc_compiler_parse_match(&fncompiler, TK_LABEL)) {
2178                         fn->nargs++;
2179 
2180                         uc_compiler_declare_local(&fncompiler, fncompiler.parser->prev.uv, false);
2181                         uc_compiler_initialize_local(&fncompiler);
2182 
2183                         if (fn->vararg ||
2184                             !uc_compiler_parse_match(&fncompiler, TK_COMMA))
2185                                 break;
2186                 }
2187                 else {
2188                         uc_compiler_syntax_error(&fncompiler, fncompiler.parser->curr.pos,
2189                                 "Expecting Label");
2190 
2191                         break;
2192                 }
2193         }
2194 
2195         uc_compiler_parse_consume(&fncompiler, TK_RPAREN);
2196 
2197         /* parse and compile function body */
2198         if (uc_compiler_parse_match(&fncompiler, TK_COLON)) {
2199                 last_statement_type = uc_compiler_compile_delimitted_block(&fncompiler, TK_ENDFUNC);
2200                 uc_compiler_parse_consume(&fncompiler, TK_ENDFUNC);
2201         }
2202         else if (uc_compiler_parse_match(&fncompiler, TK_LBRACE)) {
2203                 last_statement_type = uc_compiler_compile_delimitted_block(&fncompiler, TK_RBRACE);
2204                 uc_compiler_parse_consume(&fncompiler, TK_RBRACE);
2205         }
2206         else {
2207                 uc_compiler_syntax_error(&fncompiler, fncompiler.parser->curr.pos,
2208                         "Expecting '{' or ':' after function parameters");
2209         }
2210 
2211         /* emit load instruction for function value */
2212         uc_compiler_emit_insn(compiler, pos, (type == TK_ARROW) ? I_ARFN : I_CLFN);
2213         load_off = uc_compiler_emit_u32(compiler, 0, 0);
2214 
2215         /* encode upvalue information */
2216         for (i = 0; i < fn->nupvals; i++)
2217                 uc_compiler_emit_s32(compiler, 0,
2218                         fncompiler.upvals.entries[i].local
2219                                 ? -(fncompiler.upvals.entries[i].index + 1)
2220                                 : fncompiler.upvals.entries[i].index);
2221 
2222         /* finalize function compiler */
2223         fn = uc_compiler_finish(&fncompiler, last_statement_type);
2224 
2225         if (fn)
2226                 uc_compiler_set_u32(compiler, load_off,
2227                         uc_program_function_id(compiler->program, fn));
2228 
2229         /* if a local variable of the same name already existed, overwrite its value
2230          * with the compiled function here */
2231         if (slot != -1) {
2232                 uc_compiler_emit_insn(compiler, 0, I_SLOC);
2233                 uc_compiler_emit_u32(compiler, 0, slot);
2234                 uc_compiler_emit_insn(compiler, 0, I_POP);
2235         }
2236 }
2237 
2238 static void
2239 uc_compiler_compile_funcexpr(uc_compiler_t *compiler)
2240 {
2241         return uc_compiler_compile_funcexpr_common(compiler, false);
2242 }
2243 
2244 static void
2245 uc_compiler_compile_funcdecl(uc_compiler_t *compiler)
2246 {
2247         return uc_compiler_compile_funcexpr_common(compiler, true);
2248 }
2249 
2250 static void
2251 uc_compiler_compile_dot(uc_compiler_t *compiler)
2252 {
2253         bool optional_chaining = (compiler->parser->prev.type == TK_QDOT);
2254 
2255         /* no regexp literal possible after property access */
2256         compiler->parser->lex.no_regexp = true;
2257 
2258         if (optional_chaining)
2259                 uc_compiler_emit_jmpnt(compiler, compiler->parser->prev.pos,
2260                         (1u << UC_ARRAY) | (1u << UC_OBJECT) | (1u << UC_RESOURCE), 0);
2261 
2262         /* parse label lhs */
2263         uc_compiler_parse_consume(compiler, TK_LABEL);
2264         uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.uv);
2265 
2266         /* depending on context, compile into I_UVAL, I_SVAL or I_LVAL operation */
2267         if (!uc_compiler_exprstack_is(compiler, F_ASSIGNABLE) || !uc_compiler_compile_assignment(compiler, NULL))
2268                 uc_compiler_emit_variable_rw(compiler, NULL, optional_chaining ? TK_QDOT : 0);
2269 
2270         compiler->patchlist->depth = uc_compiler_current_chunk(compiler)->count;
2271 }
2272 
2273 static void
2274 uc_compiler_compile_subscript(uc_compiler_t *compiler)
2275 {
2276         bool optional_chaining = (compiler->parser->prev.type == TK_QLBRACK);
2277 
2278         if (optional_chaining)
2279                 uc_compiler_emit_jmpnt(compiler, compiler->parser->prev.pos,
2280                         (1u << UC_ARRAY) | (1u << UC_OBJECT) | (1u << UC_RESOURCE), 0);
2281 
2282         /* compile lhs */
2283         uc_compiler_compile_expression(compiler, false);
2284 
2285         /* no regexp literal possible after computed property access */
2286         compiler->parser->lex.no_regexp = true;
2287         uc_compiler_parse_consume(compiler, TK_RBRACK);
2288 
2289         /* depending on context, compile into I_UVAL, I_SVAL or I_LVAL operation */
2290         if (!uc_compiler_exprstack_is(compiler, F_ASSIGNABLE) || !uc_compiler_compile_assignment(compiler, NULL))
2291                 uc_compiler_emit_variable_rw(compiler, NULL, optional_chaining ? TK_QLBRACK : 0);
2292 
2293         compiler->patchlist->depth = uc_compiler_current_chunk(compiler)->count;
2294 }
2295 
2296 static void
2297 uc_compiler_compile_ternary(uc_compiler_t *compiler)
2298 {
2299         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
2300         size_t jmpz_off, jmp_off;
2301 
2302         /* jump to false branch */
2303         jmpz_off = uc_compiler_emit_jmpz(compiler, 0);
2304 
2305         /* compile true branch */
2306         uc_compiler_parse_precedence(compiler, P_ASSIGN);
2307 
2308         /* jump after false branch */
2309         jmp_off = uc_compiler_emit_jmp(compiler, 0);
2310 
2311         uc_compiler_parse_consume(compiler, TK_COLON);
2312 
2313         /* compile false branch */
2314         uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
2315         uc_compiler_parse_precedence(compiler, P_TERNARY);
2316         uc_compiler_set_jmpaddr(compiler, jmp_off, chunk->count);
2317 }
2318 
2319 static void
2320 uc_compiler_compile_array(uc_compiler_t *compiler)
2321 {
2322         size_t hint_off, hint_count = 0, len = 0;
2323 
2324         /* a literal followed by `=` is a destructuring assignment */
2325         if (uc_compiler_compile_destructuring(compiler))
2326                 return;
2327 
2328         /* create empty array on stack */
2329         uc_compiler_emit_insn(compiler, 0, I_NARR);
2330         hint_off = uc_compiler_emit_u32(compiler, 0, 0);
2331 
2332         /* parse initializer values */
2333         do {
2334                 if (uc_compiler_parse_check(compiler, TK_RBRACK)) {
2335                         break;
2336                 }
2337                 else if (uc_compiler_parse_match(compiler, TK_ELLIP)) {
2338                         /* push items on stack so far... */
2339                         if (len > 0) {
2340                                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_PARR);
2341                                 uc_compiler_emit_u32(compiler, 0, len);
2342                                 len = 0;
2343                         }
2344 
2345                         /* compile spread value expression */
2346                         uc_compiler_parse_precedence(compiler, P_ASSIGN);
2347 
2348                         /* emit merge operation */
2349                         uc_compiler_emit_insn(compiler, 0, I_MARR);
2350                 }
2351                 else {
2352                         /* push items on stack so far... */
2353                         if (len >= 0xffffffff) {
2354                                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_PARR);
2355                                 uc_compiler_emit_u32(compiler, 0, len);
2356                                 len = 0;
2357                         }
2358 
2359                         /* compile item value expression */
2360                         uc_compiler_parse_precedence(compiler, P_ASSIGN);
2361 
2362                         hint_count++;
2363                         len++;
2364                 }
2365         }
2366         while (uc_compiler_parse_match(compiler, TK_COMMA));
2367 
2368         /* no regexp literal possible after array literal */
2369         compiler->parser->lex.no_regexp = true;
2370         uc_compiler_parse_consume(compiler, TK_RBRACK);
2371 
2372         /* push items on stack */
2373         if (len > 0) {
2374                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_PARR);
2375                 uc_compiler_emit_u32(compiler, 0, len);
2376         }
2377 
2378         /* set initial size hint */
2379         uc_compiler_set_u32(compiler, hint_off, hint_count);
2380 }
2381 
2382 static void
2383 uc_compiler_compile_method(uc_compiler_t *compiler, uc_value_t *method_name)
2384 {
2385         uc_compiler_t fncompiler = { 0 };
2386         uc_function_t *fn;
2387         size_t i, load_off;
2388 
2389         uc_compiler_init(&fncompiler, method_name ? ucv_string_get(method_name) : NULL,
2390                          uc_compiler_current_source(compiler),
2391                          compiler->parser->prev.pos,
2392                          compiler->program,
2393                          uc_compiler_is_strict(compiler));
2394 
2395         fncompiler.parent = compiler;
2396         fncompiler.parser = compiler->parser;
2397         fncompiler.exprstack = compiler->exprstack;
2398 
2399         fn = (uc_function_t *)fncompiler.function;
2400 
2401         /* parse parameters - '(' is already consumed, expect parameters or ')' */
2402         uc_compiler_enter_scope(&fncompiler);
2403 
2404         while (true) {
2405                 if (uc_compiler_parse_check(&fncompiler, TK_RPAREN))
2406                         break;
2407 
2408                 if (uc_compiler_parse_match(&fncompiler, TK_ELLIP))
2409                         fn->vararg = true;
2410 
2411                 uc_compiler_parse_consume(&fncompiler, TK_LABEL);
2412                 fn->nargs++;
2413 
2414                 uc_compiler_declare_local(&fncompiler,
2415                         fncompiler.parser->prev.uv, false);
2416                 uc_compiler_initialize_local(&fncompiler);
2417 
2418                 if (fn->vararg ||
2419                     !uc_compiler_parse_match(&fncompiler, TK_COMMA))
2420                         break;
2421         }
2422 
2423         uc_compiler_parse_consume(&fncompiler, TK_RPAREN);
2424 
2425         /* parse function body - must be a block */
2426         uc_compiler_parse_consume(&fncompiler, TK_LBRACE);
2427 
2428         while (!uc_compiler_parse_check(&fncompiler, TK_RBRACE) &&
2429                !uc_compiler_parse_check(&fncompiler, TK_EOF))
2430                 uc_compiler_compile_declaration(&fncompiler);
2431 
2432         uc_compiler_parse_consume(&fncompiler, TK_RBRACE);
2433 
2434         /* emit load instruction for method */
2435         uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_CLFN);
2436         load_off = uc_compiler_emit_u32(compiler, 0, 0);
2437 
2438         /* encode upvalue information */
2439         for (i = 0; i < fn->nupvals; i++)
2440                 uc_compiler_emit_s32(compiler, 0,
2441                         fncompiler.upvals.entries[i].local
2442                                 ? -(fncompiler.upvals.entries[i].index + 1)
2443                                 : fncompiler.upvals.entries[i].index);
2444 
2445         /* finalize function compiler */
2446         fn = uc_compiler_finish(&fncompiler, TK_RETURN);
2447 
2448         if (fn)
2449                 uc_compiler_set_u32(compiler, load_off,
2450                         uc_program_function_id(compiler->program, fn));
2451 }
2452 
2453 
2454 static void
2455 uc_compiler_compile_object(uc_compiler_t *compiler)
2456 {
2457         size_t hint_off, hint_count = 0, len = 0;
2458 
2459         /* a literal followed by `=` is a destructuring assignment */
2460         if (uc_compiler_compile_destructuring(compiler))
2461                 return;
2462 
2463         /* create empty object on stack */
2464         uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_NOBJ);
2465         hint_off = uc_compiler_emit_u32(compiler, 0, 0);
2466 
2467         /* parse initializer values */
2468         do {
2469                 /* End of object literal */
2470                 if (uc_compiler_parse_check(compiler, TK_RBRACE))
2471                         break;
2472 
2473                 /* Spread operator */
2474                 if (uc_compiler_parse_match(compiler, TK_ELLIP)) {
2475                         /* set items on stack so far... */
2476                         if (len > 0) {
2477                                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_SOBJ);
2478                                 uc_compiler_emit_u32(compiler, 0, len);
2479                                 len = 0;
2480                         }
2481 
2482                         /* compile spread value expression */
2483                         uc_compiler_parse_precedence(compiler, P_ASSIGN);
2484 
2485                         /* emit merge operation */
2486                         uc_compiler_emit_insn(compiler, 0, I_MOBJ);
2487 
2488                         compiler->parser->lex.no_keyword = true;
2489                         continue;
2490                 }
2491 
2492                 /* Computed property/method name */
2493                 if (uc_compiler_parse_match(compiler, TK_LBRACK)) {
2494                         /* parse property name expression */
2495                         uc_compiler_parse_precedence(compiler, P_ASSIGN);
2496 
2497                         /* consume closing bracket */
2498                         uc_compiler_parse_consume(compiler, TK_RBRACK);
2499 
2500                         /* Check if this is a computed method: [expr]() { ... } */
2501                         if (uc_compiler_parse_match(compiler, TK_LPAREN)) {
2502                                 /* compile method - key is already on stack from [expr] */
2503                                 uc_compiler_compile_method(compiler, NULL);
2504                         }
2505                         else {
2506                                 /* regular computed property: [expr]: value */
2507                                 uc_compiler_parse_consume(compiler, TK_COLON);
2508                                 uc_compiler_parse_precedence(compiler, P_ASSIGN);
2509                         }
2510                 }
2511 
2512                 /* Property/method declaration or property shorthand */
2513                 else {
2514                         /* parse key expression */
2515                         uc_tokentype_t key_type = compiler->parser->curr.type;
2516                         if (!uc_compiler_parse_match(compiler, TK_LABEL) &&
2517                             !uc_compiler_parse_match(compiler, TK_STRING))
2518                                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
2519                                         "Expecting label");
2520 
2521                         /* hold a reference to the key: matching TK_LPAREN below advances
2522                          * the parser, which releases the underlying prev.uv token value */
2523                         uc_value_t *key = ucv_get(compiler->parser->prev.uv);
2524 
2525                         /* load label */
2526                         uc_compiler_emit_constant(compiler, compiler->parser->prev.pos,
2527                                 key);
2528 
2529                         /* Check if this is a shorthand method: foo() { ... } */
2530                         if (uc_compiler_parse_match(compiler, TK_LPAREN)) {
2531                                 /* disallow keywords as method names */
2532                                 if (uc_lexer_is_keyword(key))
2533                                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
2534                                                 "Invalid identifier");
2535 
2536                                 uc_compiler_compile_method(compiler, key);
2537                         }
2538                         /* Check if this is property shorthand: foo */
2539                         else if (key_type == TK_LABEL &&
2540                                  (uc_compiler_parse_check(compiler, TK_COMMA) ||
2541                                   uc_compiler_parse_check(compiler, TK_RBRACE))) {
2542                                 /* disallow keywords in this case */
2543                                 if (uc_lexer_is_keyword(key))
2544                                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
2545                                                 "Invalid identifier");
2546 
2547                                 uc_compiler_emit_variable_rw(compiler, key, 0);
2548                         }
2549                         /* ... otherwise treat it as ordinary `key: value` tuple */
2550                         else {
2551                                 uc_compiler_parse_consume(compiler, TK_COLON);
2552 
2553                                 /* parse value expression */
2554                                 uc_compiler_parse_precedence(compiler, P_ASSIGN);
2555                         }
2556 
2557                         ucv_put(key);
2558                 }
2559 
2560                 /* set items on stack so far... */
2561                 if (len >= 0xfffffffe) {
2562                         uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_SOBJ);
2563                         uc_compiler_emit_u32(compiler, 0, len);
2564                         len = 0;
2565                 }
2566 
2567                 hint_count += 2;
2568                 len += 2;
2569 
2570                 compiler->parser->lex.no_keyword = true;
2571         }
2572         while (uc_compiler_parse_match(compiler, TK_COMMA));
2573 
2574         /* no regexp literal possible after object literal */
2575         compiler->parser->lex.no_regexp = true;
2576         uc_compiler_parse_consume(compiler, TK_RBRACE);
2577 
2578         /* set items on stack */
2579         if (len > 0) {
2580                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_SOBJ);
2581                 uc_compiler_emit_u32(compiler, 0, len);
2582         }
2583 
2584         /* set initial size hint */
2585         uc_compiler_set_u32(compiler, hint_off, hint_count);
2586 }
2587 
2588 
2589 static void
2590 uc_compiler_declare_local_null(uc_compiler_t *compiler, size_t srcpos, uc_value_t *varname)
2591 {
2592         ssize_t existing_slot = uc_compiler_declare_local(compiler, varname, false);
2593 
2594         uc_compiler_emit_insn(compiler, srcpos, I_LNULL);
2595 
2596         if (existing_slot == -1) {
2597                 uc_compiler_initialize_local(compiler);
2598         }
2599         else {
2600                 uc_compiler_emit_insn(compiler, 0, I_SLOC);
2601                 uc_compiler_emit_u32(compiler, 0, existing_slot);
2602                 uc_compiler_emit_insn(compiler, 0, I_POP);
2603         }
2604 }
2605 
2606 static size_t
2607 uc_compiler_declare_internal(uc_compiler_t *compiler, size_t srcpos, const char *name)
2608 {
2609         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
2610         uc_locals_t *locals = &compiler->locals;
2611 
2612         uc_vector_push(locals, {
2613                 .name = ucv_string_new(name),
2614                 .depth = compiler->scope_depth,
2615                 .captured = false,
2616                 .from = chunk->count
2617         });
2618 
2619         return locals->count - 1;
2620 }
2621 
2622 /*
2623  * Destructuring
2624  *
2625  * Whether a leading `[` or `{` starts a literal or a pattern is determined by
2626  * scanning ahead to the matching closing bracket and checking whether an `=`
2627  * follows, see uc_compiler_scan_literal(). Nothing is compiled or tokenized
2628  * while doing so, the parser state is not affected.
2629  *
2630  * The initializer of a pattern has to be evaluated first, but follows the
2631  * pattern in the source text. To generate code in source order nevertheless,
2632  * the code of the pattern precedes the code of the initializer and jumps are
2633  * used to run them in the right order, see uc_compiler_compile_pattern_assignment().
2634  */
2635 
2636 static int
2637 uc_bracket_cmp(const void *a, const void *b)
2638 {
2639         size_t x = ((const uc_bracket_t *)a)->pos, y = ((const uc_bracket_t *)b)->pos;
2640 
2641         return (x > y) - (x < y);
2642 }
2643 
2644 /* Whether the literal whose opening bracket has just been consumed is followed
2645  * by an equals sign. */
2646 static uc_follow_t
2647 uc_compiler_literal_follow(uc_compiler_t *compiler)
2648 {
2649         uc_parser_t *parser = compiler->parser;
2650         uc_bracketlist_t enclosed = { 0 };
2651         size_t pos = parser->prev.pos, end;
2652         uc_bracket_t *hit;
2653         uc_follow_t follow;
2654 
2655         /* the first token already tells that most literals are not patterns, which
2656          * start with an assignment target, a nested pattern, a hole or a rest
2657          * element in case of arrays and with a key in case of objects */
2658         switch (parser->curr.type) {
2659         case TK_LABEL:
2660         case TK_LBRACK:
2661         case TK_ELLIP:
2662                 break;
2663 
2664         case TK_THIS:
2665         case TK_LPAREN:
2666         case TK_COMMA:
2667         case TK_LBRACE:
2668         case TK_RBRACK:
2669                 if (parser->prev.type != TK_LBRACK)
2670                         return UC_FOLLOW_OTHER;
2671 
2672                 break;
2673 
2674         case TK_STRING:
2675         case TK_RBRACE:
2676                 if (parser->prev.type != TK_LBRACE)
2677                         return UC_FOLLOW_OTHER;
2678 
2679                 break;
2680 
2681         default:
2682                 return UC_FOLLOW_OTHER;
2683         }
2684 
2685         /* a literal enclosed in one that has been scanned already is known not to
2686          * be followed by an equals sign unless found back then */
2687         if (pos > parser->scanned.from && pos < parser->scanned.to) {
2688                 uc_bracket_t probe = { .pos = pos };
2689 
2690                 if (!parser->scanned.count)
2691                         return UC_FOLLOW_OTHER;
2692 
2693                 hit = bsearch(&probe, parser->scanned.entries, parser->scanned.count,
2694                         sizeof(uc_bracket_t), uc_bracket_cmp);
2695 
2696                 if (!hit)
2697                         return UC_FOLLOW_OTHER;
2698 
2699                 return hit->follow;
2700         }
2701 
2702         if (!uc_lexer_skip_balanced(&parser->lex, parser->prev.end, &end, &follow, &enclosed))
2703                 return UC_FOLLOW_OTHER;
2704 
2705         /* remember the result for the literals enclosed in this one */
2706         free(parser->scanned.entries);
2707 
2708         if (enclosed.count > 1)
2709                 qsort(enclosed.entries, enclosed.count, sizeof(uc_bracket_t), uc_bracket_cmp);
2710 
2711         parser->scanned.from = pos;
2712         parser->scanned.to = end;
2713         parser->scanned.count = enclosed.count;
2714         parser->scanned.entries = enclosed.entries;
2715 
2716         return follow;
2717 }
2718 
2719 static void
2720 uc_compiler_emit_uint(uc_compiler_t *compiler, uint64_t u)
2721 {
2722         if (u <= 0xff) {
2723                 uc_compiler_emit_insn(compiler, 0, I_LOAD8);
2724                 uc_compiler_emit_u8(compiler, 0, u);
2725         }
2726         else if (u <= 0xffff) {
2727                 uc_compiler_emit_insn(compiler, 0, I_LOAD16);
2728                 uc_compiler_emit_u16(compiler, 0, u);
2729         }
2730         else {
2731                 uc_compiler_emit_insn(compiler, 0, I_LOAD32);
2732                 uc_compiler_emit_u32(compiler, 0, u);
2733         }
2734 }
2735 
2736 /* Replace the value on top of the stack by the default value, if it is null.
2737  * The default value expression is the next one in the source text. */
2738 static void
2739 uc_compiler_compile_default(uc_compiler_t *compiler)
2740 {
2741         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
2742         size_t jmpz_off, jmp_off;
2743 
2744         uc_compiler_emit_copy(compiler, 0, 0);
2745         uc_compiler_emit_insn(compiler, 0, I_LNULL);
2746         uc_compiler_emit_insn(compiler, 0, I_NES);
2747         jmpz_off = uc_compiler_emit_jmpz(compiler, 0);
2748         jmp_off = uc_compiler_emit_jmp(compiler, 0);
2749         uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
2750         uc_compiler_emit_insn(compiler, 0, I_POP);
2751         uc_compiler_parse_precedence(compiler, P_ASSIGN);
2752         uc_compiler_set_jmpaddr(compiler, jmp_off, chunk->count);
2753 }
2754 
2755 uc_declare_vector(uc_keylist_t, uc_value_t *);
2756 
2757 typedef struct {
2758         bool array;        /* array pattern, otherwise object pattern */
2759         bool decl;         /* declaration, otherwise assignment */
2760         bool constant;     /* declaration of constants */
2761         size_t slot;       /* declaration: local holding the container */
2762         size_t depth;      /* assignment: stack entries above the container */
2763         size_t index;      /* array pattern: index of the current element */
2764         uc_keylist_t keys; /* object pattern: preceding constant keys */
2765         bool computed;     /* object pattern: preceding computed keys */
2766 } uc_pattern_t;
2767 
2768 static void
2769 uc_compiler_compile_pattern_body(uc_compiler_t *compiler, uc_pattern_t *pat);
2770 
2771 /* Make the variables declared since `first` (in)accessible, e.g. while
2772  * compiling code which runs before they are assigned. */
2773 static void
2774 uc_compiler_locals_set_depth(uc_compiler_t *compiler, size_t first, ssize_t depth)
2775 {
2776         size_t i;
2777 
2778         for (i = first; i < compiler->locals.count; i++)
2779                 compiler->locals.entries[i].depth = depth;
2780 }
2781 
2782 /* Compile a nested pattern. The value to destructure is on top of the stack
2783  * and the opening bracket is the current token. The default value, if any,
2784  * follows the closing bracket in the source text but needs to run first, so
2785  * it is emitted behind the code of the pattern:
2786  *
2787  *       COPY 0; LNULL; NES; JMPZ default
2788  *   pat:  <pattern>
2789  *       JMP end
2790  *   default: POP; <default value>; JMP pat
2791  *   end:
2792  */
2793 static void
2794 uc_compiler_compile_nested_pattern(uc_compiler_t *compiler, bool decl, bool constant)
2795 {
2796         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
2797         uc_pattern_t nested = {
2798                 .array = uc_compiler_parse_check(compiler, TK_LBRACK),
2799                 .decl = decl,
2800                 .constant = constant
2801         };
2802 
2803         size_t jmpz_off = 0, jmp_off = 0, pat_off, first;
2804         uc_follow_t follow;
2805         size_t end;
2806         bool dflt = false;
2807 
2808         if (!nested.array)
2809                 compiler->parser->lex.no_keyword = true;
2810 
2811         uc_compiler_parse_advance(compiler);
2812 
2813         /* the value on the stack becomes a local variable holding the container */
2814         if (decl) {
2815                 nested.slot = uc_compiler_declare_internal(compiler, 0, "(destructure)");
2816                 uc_compiler_initialize_local(compiler);
2817         }
2818 
2819         first = compiler->locals.count;
2820 
2821         if (uc_lexer_skip_balanced(&compiler->parser->lex, compiler->parser->prev.end,
2822                                    &end, &follow, NULL))
2823                 dflt = (follow == UC_FOLLOW_ASSIGN);
2824 
2825         if (dflt) {
2826                 uc_compiler_emit_copy(compiler, 0, 0);
2827                 uc_compiler_emit_insn(compiler, 0, I_LNULL);
2828                 uc_compiler_emit_insn(compiler, 0, I_NES);
2829                 jmpz_off = uc_compiler_emit_jmpz(compiler, 0);
2830         }
2831 
2832         pat_off = chunk->count;
2833 
2834         uc_compiler_compile_pattern_body(compiler, &nested);
2835 
2836         if (dflt && uc_compiler_parse_match(compiler, TK_ASSIGN)) {
2837                 jmp_off = uc_compiler_emit_jmp(compiler, 0);
2838                 uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
2839 
2840                 /* variables of the pattern are not assigned yet */
2841                 uc_compiler_locals_set_depth(compiler, first, -1);
2842 
2843                 uc_compiler_emit_insn(compiler, 0, I_POP);
2844                 uc_compiler_parse_precedence(compiler, P_ASSIGN);
2845                 uc_compiler_emit_jmp_dest(compiler, 0, pat_off);
2846 
2847                 uc_compiler_locals_set_depth(compiler, first, compiler->scope_depth);
2848                 uc_compiler_set_jmpaddr(compiler, jmp_off, chunk->count);
2849         }
2850 }
2851 
2852 /* Emit code loading the property of the container selected by the current
2853  * item. */
2854 static void
2855 uc_compiler_emit_pattern_load(uc_compiler_t *compiler, uc_pattern_t *pat, size_t depth)
2856 {
2857         if (pat->decl) {
2858                 uc_compiler_emit_insn(compiler, 0, I_LLOC);
2859                 uc_compiler_emit_u32(compiler, 0, pat->slot);
2860         }
2861         else if (depth > 0xff) {
2862                 uc_compiler_syntax_error(compiler, 0, "Destructuring pattern too complex");
2863         }
2864         else {
2865                 uc_compiler_emit_copy(compiler, 0, depth);
2866         }
2867 }
2868 
2869 /* Compile a rest element, leaving the collected value on top of the stack.
2870  *
2871  * The copy destination is created *below* the container, so that the merge
2872  * consumes the value the pattern load pushed and the stack stays as balanced
2873  * as it does for an ordinary item.
2874  *
2875  * The container is copied first and the items already bound are taken off the
2876  * copy: an array copy keeps its tail once `splice` removed the bound items
2877  * from it, an object copy keeps its unbound keys once `rawdelete` dropped the
2878  * bound ones. Both copies are plain values, so neither operation dispatches
2879  * metamethods, and the merge is what reports an unsuitable container - `MARR`
2880  * for a non-array, `MOBJ` for a non-container - like a literal spread does. */
2881 static void
2882 uc_compiler_compile_pattern_rest(uc_compiler_t *compiler, uc_pattern_t *pat, size_t depth)
2883 {
2884         size_t i;
2885 
2886         if (pat->array) {
2887                 /* copy the array */
2888                 uc_compiler_emit_insn(compiler, 0, I_NARR);
2889                 uc_compiler_emit_u32(compiler, 0, 0);
2890                 /* the destination was pushed first, so the container lies one deeper */
2891                 uc_compiler_emit_pattern_load(compiler, pat, depth + 1);
2892                 uc_compiler_emit_insn(compiler, 0, I_MARR);
2893 
2894                 /* drop the items already bound; splice removes them from the copy and
2895                  * returns it, so the copy holding the tail is the result */
2896                 uc_compiler_emit_insn(compiler, 0, I_LOAD8);
2897                 uc_compiler_emit_u8(compiler, 0, 0);
2898                 uc_compiler_emit_uint(compiler, pat->index);
2899                 uc_compiler_emit_stcall(compiler, 0, UC_FN_SPLICE, 3);
2900         }
2901         else {
2902                 /* copy the properties */
2903                 uc_compiler_emit_insn(compiler, 0, I_NOBJ);
2904                 uc_compiler_emit_u32(compiler, 0, 0);
2905                 uc_compiler_emit_pattern_load(compiler, pat, depth + 1);
2906                 uc_compiler_emit_insn(compiler, 0, I_MOBJ);
2907 
2908                 /* drop the keys the pattern binds; the call consumes its arguments, so
2909                  * each key is dropped from a duplicate of the copy */
2910                 for (i = 0; i < pat->keys.count; i++) {
2911                         uc_compiler_emit_copy(compiler, 0, 0);
2912                         uc_compiler_emit_constant(compiler, 0, pat->keys.entries[i]);
2913                         uc_compiler_emit_stcall(compiler, 0, UC_FN_RAWDELETE, 2);
2914                         uc_compiler_emit_insn(compiler, 0, I_POP);
2915                 }
2916         }
2917 }
2918 
2919 /* Compile an item of a pattern, returns true for a rest element. */
2920 static bool
2921 uc_compiler_compile_pattern_item(uc_compiler_t *compiler, uc_pattern_t *pat)
2922 {
2923         enum { T_NAME, T_VAR, T_MEMBER, T_NESTED } target = T_NAME;
2924         uc_exprstack_t barrier = { .token = TK_LABEL }, *exprstack;
2925         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
2926         uc_value_t *key = NULL, *name = NULL, *cname;
2927         size_t start, d = pat->depth, operand = 0, tpos = 0;
2928         bool rest, computed = false, loaded = false;
2929         uc_vm_insn_t store = 0, load;
2930         ssize_t slot = -1;
2931 
2932         rest = uc_compiler_parse_match(compiler, TK_ELLIP);
2933 
2934         /* property key */
2935         if (!pat->array && !rest) {
2936                 if (uc_compiler_parse_match(compiler, TK_LBRACK)) {
2937                         computed = true;
2938                         pat->computed = true;
2939 
2940                         if (pat->decl) {
2941                                 /* the container is loaded first, followed by the key */
2942                                 uc_compiler_emit_pattern_load(compiler, pat, 0);
2943                                 uc_compiler_parse_precedence(compiler, P_ASSIGN);
2944                                 uc_compiler_emit_insn(compiler, 0, I_LVAL);
2945                                 loaded = true;
2946                         }
2947                         else {
2948                                 /* the key stays on the stack below the target */
2949                                 uc_compiler_parse_precedence(compiler, P_ASSIGN);
2950                                 d++;
2951                         }
2952 
2953                         uc_compiler_parse_consume(compiler, TK_RBRACK);
2954                         uc_compiler_parse_consume(compiler, TK_COLON);
2955                 }
2956                 else if (uc_compiler_parse_match(compiler, TK_LABEL) ||
2957                          uc_compiler_parse_match(compiler, TK_STRING)) {
2958                         bool label = (compiler->parser->prev.type == TK_LABEL);
2959 
2960                         key = ucv_get(compiler->parser->prev.uv);
2961 
2962                         if (!uc_compiler_parse_match(compiler, TK_COLON)) {
2963                                 if (!label || uc_lexer_is_keyword(key))
2964                                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
2965                                                 label ? "Invalid identifier" : "Unexpected token\nExpecting ':'");
2966 
2967                                 /* shorthand property, the key is also the variable name */
2968                                 name = ucv_get(key);
2969                         }
2970 
2971                         uc_vector_push(&pat->keys, ucv_get(key));
2972                 }
2973                 else {
2974                         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
2975                                 "Expecting label");
2976 
2977                         return true;
2978                 }
2979         }
2980 
2981         /* declarations load the value before the target is parsed */
2982         if (pat->decl && !loaded) {
2983                 if (rest) {
2984                         if (!pat->array && pat->computed)
2985                                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
2986                                         "Computed keys cannot precede a rest element");
2987 
2988                         uc_compiler_compile_pattern_rest(compiler, pat, 0);
2989                 }
2990                 else {
2991                         uc_compiler_emit_pattern_load(compiler, pat, 0);
2992 
2993                         if (pat->array)
2994                                 uc_compiler_emit_uint(compiler, pat->index);
2995                         else
2996                                 uc_compiler_emit_constant(compiler, 0, key);
2997 
2998                         uc_compiler_emit_insn(compiler, 0, I_LVAL);
2999                 }
3000 
3001                 loaded = true;
3002         }
3003 
3004         /* target */
3005         if (name) {
3006                 target = T_NAME;
3007         }
3008         else if (uc_compiler_parse_check(compiler, TK_LBRACK) ||
3009                  uc_compiler_parse_check(compiler, TK_LBRACE)) {
3010                 target = T_NESTED;
3011         }
3012         else if (pat->decl) {
3013                 if (!uc_compiler_parse_match(compiler, TK_LABEL)) {
3014                         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
3015                                 "Expecting variable name or pattern");
3016 
3017                         ucv_put(key);
3018 
3019                         return true;
3020                 }
3021 
3022                 name = ucv_get(compiler->parser->prev.uv);
3023         }
3024         else {
3025                 tpos = compiler->parser->curr.pos;
3026                 start = chunk->count;
3027 
3028                 /* the target must not consume a following `= default` as assignment */
3029                 exprstack = compiler->exprstack;
3030                 compiler->exprstack = &barrier;
3031                 uc_compiler_parse_precedence(compiler, P_CALL);
3032                 compiler->exprstack = exprstack;
3033 
3034                 load = (chunk->count > start) ? chunk->entries[compiler->last_insn] : 0;
3035 
3036                 if (chunk->count - start == 5 && (load == I_LLOC || load == I_LUPV || load == I_LVAR)) {
3037                         operand = uc_compiler_get_u32(compiler, compiler->last_insn + 1);
3038 
3039                         if ((load == I_LLOC && compiler->locals.entries[operand].constant) ||
3040                             (load == I_LUPV && compiler->upvals.entries[operand].constant)) {
3041                                 cname = (load == I_LLOC)
3042                                         ? compiler->locals.entries[operand].name
3043                                         : compiler->upvals.entries[operand].name;
3044 
3045                                 uc_compiler_syntax_error(compiler, tpos,
3046                                         "Invalid assignment to constant '%s'", ucv_string_get(cname));
3047                         }
3048 
3049                         store = (load == I_LLOC) ? I_SLOC : (load == I_LUPV) ? I_SUPV : I_SVAR;
3050                         target = T_VAR;
3051 
3052                         for (int i = 0; i < 5; i++)
3053                                 uc_chunk_pop(chunk);
3054                 }
3055                 else if (load == I_LVAL && uc_compiler_check_assignment_lhs(compiler)) {
3056                         target = T_MEMBER;
3057                         d += 2;
3058 
3059                         uc_chunk_pop(chunk);
3060                 }
3061                 else {
3062                         uc_compiler_syntax_error(compiler, tpos, "Invalid destructuring target");
3063 
3064                         ucv_put(key);
3065 
3066                         return true;
3067                 }
3068         }
3069 
3070         /* a target is followed by a default value or the end of the item */
3071         if (!uc_compiler_parse_check(compiler, TK_COMMA) &&
3072             !uc_compiler_parse_check(compiler, TK_ASSIGN) &&
3073             !uc_compiler_parse_check(compiler, pat->array ? TK_RBRACK : TK_RBRACE) &&
3074             target != T_NESTED) {
3075                 uc_compiler_syntax_error(compiler, tpos ? tpos : compiler->parser->curr.pos,
3076                         "Invalid destructuring target");
3077         }
3078 
3079         /* assignments load the value after evaluating the target */
3080         if (!loaded) {
3081                 if (rest) {
3082                         if (!pat->array && pat->computed)
3083                                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
3084                                         "Computed keys cannot precede a rest element");
3085 
3086                         uc_compiler_compile_pattern_rest(compiler, pat, d);
3087                 }
3088                 else {
3089                         uc_compiler_emit_pattern_load(compiler, pat, d);
3090 
3091                         if (pat->array)
3092                                 uc_compiler_emit_uint(compiler, pat->index);
3093                         else if (key)
3094                                 uc_compiler_emit_constant(compiler, 0, key);
3095                         else
3096                                 uc_compiler_emit_copy(compiler, 0, (target == T_MEMBER ? 2 : 0) + 1);
3097 
3098                         uc_compiler_emit_insn(compiler, 0, I_LVAL);
3099                 }
3100         }
3101 
3102         if (target == T_NESTED) {
3103                 if (rest && uc_compiler_parse_check(compiler, TK_ASSIGN))
3104                         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
3105                                 "Rest element cannot have a default value");
3106 
3107                 uc_compiler_compile_nested_pattern(compiler, pat->decl, pat->constant);
3108 
3109                 if (!pat->decl)
3110                         uc_compiler_emit_insn(compiler, 0, I_POP);
3111         }
3112         else {
3113                 /* declare the variable before parsing the default value so that it
3114                  * cannot refer to itself */
3115                 if (pat->decl)
3116                         slot = uc_compiler_declare_local(compiler, name, pat->constant);
3117 
3118                 if (uc_compiler_parse_match(compiler, TK_ASSIGN)) {
3119                         if (rest)
3120                                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
3121                                         "Rest element cannot have a default value");
3122 
3123                         uc_compiler_compile_default(compiler);
3124                 }
3125 
3126                 if (pat->decl) {
3127                         if (slot == -1) {
3128                                 uc_compiler_initialize_local(compiler);
3129                         }
3130                         else {
3131                                 uc_compiler_emit_insn(compiler, 0, I_SLOC);
3132                                 uc_compiler_emit_u32(compiler, 0, slot);
3133                                 uc_compiler_emit_insn(compiler, 0, I_POP);
3134                         }
3135                 }
3136                 else if (target == T_NAME) {
3137                         uc_compiler_emit_variable_rw(compiler, name, TK_ASSIGN);
3138                         uc_compiler_emit_insn(compiler, 0, I_POP);
3139                 }
3140                 else if (target == T_VAR) {
3141                         uc_compiler_emit_insn(compiler, 0, store);
3142                         uc_compiler_emit_u32(compiler, 0, operand);
3143                         uc_compiler_emit_insn(compiler, 0, I_POP);
3144                 }
3145                 else {
3146                         uc_compiler_emit_insn(compiler, 0, I_SVAL);
3147                         uc_compiler_emit_insn(compiler, 0, I_POP);
3148                 }
3149         }
3150 
3151         if (computed && !pat->decl)
3152                 uc_compiler_emit_insn(compiler, 0, I_POP);
3153 
3154         ucv_put(key);
3155         ucv_put(name);
3156 
3157         return rest;
3158 }
3159 
3160 static void
3161 uc_compiler_compile_pattern_body(uc_compiler_t *compiler, uc_pattern_t *pat)
3162 {
3163         uc_tokentype_t closer = pat->array ? TK_RBRACK : TK_RBRACE;
3164         size_t i;
3165 
3166         while (!uc_compiler_parse_check(compiler, closer)) {
3167                 /* hole */
3168                 if (pat->array && uc_compiler_parse_match(compiler, TK_COMMA)) {
3169                         pat->index++;
3170 
3171                         continue;
3172                 }
3173 
3174                 if (uc_compiler_compile_pattern_item(compiler, pat)) {
3175                         if (!uc_compiler_parse_check(compiler, closer))
3176                                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
3177                                         "Rest element must be last element");
3178 
3179                         break;
3180                 }
3181 
3182                 pat->index++;
3183 
3184                 if (!pat->array)
3185                         compiler->parser->lex.no_keyword = true;
3186 
3187                 if (!uc_compiler_parse_match(compiler, TK_COMMA))
3188                         break;
3189         }
3190 
3191         uc_compiler_parse_consume(compiler, closer);
3192 
3193         for (i = 0; i < pat->keys.count; i++)
3194                 ucv_put(pat->keys.entries[i]);
3195 
3196         uc_vector_clear(&pat->keys);
3197 }
3198 
3199 /* Compile the pattern and initializer of a destructuring assignment or
3200  * declaration. The initializer has to be evaluated first but follows the
3201  * pattern in the source text, so the code of the pattern precedes the code of
3202  * the initializer and jumps are used to run them in the right order:
3203  *
3204  *       JMP init
3205  *   pat:  <pattern>
3206  *       JMP end
3207  *   init: <initializer>
3208  *       JMP pat
3209  *   end:
3210  *
3211  * The opening bracket has been consumed already. */
3212 static void
3213 uc_compiler_compile_pattern_assignment(uc_compiler_t *compiler, uc_pattern_t *pat)
3214 {
3215         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
3216         size_t first = compiler->locals.count, jmp_init, jmp_end, pat_off;
3217 
3218         jmp_init = uc_compiler_emit_jmp(compiler, 0);
3219         pat_off = chunk->count;
3220 
3221         uc_compiler_compile_pattern_body(compiler, pat);
3222 
3223         jmp_end = uc_compiler_emit_jmp(compiler, 0);
3224         uc_compiler_set_jmpaddr(compiler, jmp_init, chunk->count);
3225 
3226         if (!uc_compiler_parse_match(compiler, TK_ASSIGN)) {
3227                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
3228                         "Expecting initializer expression");
3229 
3230                 return;
3231         }
3232 
3233         /* declared variables must not be accessible from the initializer */
3234         uc_compiler_locals_set_depth(compiler, first, -1);
3235 
3236         uc_compiler_parse_precedence(compiler, P_ASSIGN);
3237 
3238         uc_compiler_locals_set_depth(compiler, first, compiler->scope_depth);
3239 
3240         uc_compiler_emit_jmp_dest(compiler, 0, pat_off);
3241         uc_compiler_set_jmpaddr(compiler, jmp_end, chunk->count);
3242 }
3243 
3244 /* Compile a destructuring assignment if the array or object literal whose
3245  * opening bracket has just been consumed is followed by `=`. */
3246 static bool
3247 uc_compiler_compile_destructuring(uc_compiler_t *compiler)
3248 {
3249         uc_pattern_t pat = { .array = (compiler->parser->prev.type == TK_LBRACK) };
3250 
3251         /* a literal starting an assignment expression might be a pattern */
3252         if (!(compiler->exprstack->flags & F_ASSIGNABLE) ||
3253             uc_compiler_literal_follow(compiler) != UC_FOLLOW_ASSIGN)
3254                 return false;
3255 
3256         uc_compiler_compile_pattern_assignment(compiler, &pat);
3257 
3258         return true;
3259 }
3260 
3261 static void
3262 uc_compiler_compile_destructuring_declaration(uc_compiler_t *compiler, bool constant)
3263 {
3264         uc_pattern_t pat = {
3265                 .array = uc_compiler_parse_check(compiler, TK_LBRACK),
3266                 .decl = true,
3267                 .constant = constant
3268         };
3269 
3270         if (!pat.array)
3271                 compiler->parser->lex.no_keyword = true;
3272 
3273         uc_compiler_parse_advance(compiler);
3274 
3275         /* the initializer becomes the container */
3276         pat.slot = uc_compiler_declare_internal(compiler, 0, "(destructure)");
3277 
3278         uc_compiler_compile_pattern_assignment(compiler, &pat);
3279 }
3280 
3281 static void
3282 uc_compiler_compile_declexpr(uc_compiler_t *compiler, bool constant)
3283 {
3284         ssize_t slot;
3285 
3286         do {
3287                 /* destructuring declaration */
3288                 if (uc_compiler_parse_check(compiler, TK_LBRACK) ||
3289                     uc_compiler_parse_check(compiler, TK_LBRACE)) {
3290                         uc_compiler_compile_destructuring_declaration(compiler, constant);
3291 
3292                         continue;
3293                 }
3294 
3295                 /* parse variable name */
3296                 if (!uc_compiler_parse_match(compiler, TK_LABEL)) {
3297                         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
3298                                 "Expecting variable name");
3299 
3300                         return;
3301                 }
3302 
3303                 /* declare local variable */
3304                 slot = uc_compiler_declare_local(compiler, compiler->parser->prev.uv, constant);
3305 
3306                 /* if followed by '=', parse initializer expression */
3307                 if (uc_compiler_parse_match(compiler, TK_ASSIGN))
3308                         uc_compiler_parse_precedence(compiler, P_ASSIGN);
3309                 /* otherwise, for writable variables, load implicit null */
3310                 else if (!constant)
3311                         uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LNULL);
3312                 /* for constant variables, a missing initializer is a syntax error */
3313                 else
3314                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
3315                                 "Expecting initializer expression");
3316 
3317                 /* initialize local */
3318                 if (slot == -1) {
3319                         uc_compiler_initialize_local(compiler);
3320                 }
3321                 /* if the variable was redeclared, overwrite it */
3322                 else {
3323                         uc_compiler_emit_insn(compiler, 0, I_SLOC);
3324                         uc_compiler_emit_u32(compiler, 0, slot);
3325                         uc_compiler_emit_insn(compiler, 0, I_POP);
3326                 }
3327         }
3328         while (uc_compiler_parse_match(compiler, TK_COMMA));
3329 }
3330 
3331 static void
3332 uc_compiler_compile_local(uc_compiler_t *compiler)
3333 {
3334         uc_compiler_emit_stmt_start(compiler, &compiler->parser->prev);
3335         uc_compiler_compile_declexpr(compiler, false);
3336         uc_compiler_parse_consume(compiler, TK_SCOL);
3337         uc_compiler_emit_stmt_end(compiler);
3338 }
3339 
3340 static void
3341 uc_compiler_compile_const(uc_compiler_t *compiler)
3342 {
3343         uc_compiler_emit_stmt_start(compiler, &compiler->parser->prev);
3344         uc_compiler_compile_declexpr(compiler, true);
3345         uc_compiler_parse_consume(compiler, TK_SCOL);
3346         uc_compiler_emit_stmt_end(compiler);
3347 }
3348 
3349 static uc_tokentype_t
3350 uc_compiler_compile_altifblock(uc_compiler_t *compiler)
3351 {
3352         uc_compiler_enter_scope(compiler);
3353 
3354         while (true) {
3355                 switch (compiler->parser->curr.type) {
3356                 case TK_ELIF:
3357                 case TK_ELSE:
3358                 case TK_ENDIF:
3359                 case TK_EOF:
3360                         uc_compiler_leave_scope(compiler);
3361 
3362                         return compiler->parser->curr.type;
3363 
3364                 default:
3365                         uc_compiler_compile_declaration(compiler);
3366                         break;
3367                 }
3368         }
3369 
3370         return 0;
3371 }
3372 
3373 static void
3374 uc_compiler_compile_if(uc_compiler_t *compiler)
3375 {
3376         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
3377         size_t jmpz_off, jmp_off, i;
3378         bool expect_endif = false;
3379         uc_jmplist_t elifs = { 0 };
3380         uc_tokentype_t type;
3381 
3382         /* parse & compile condition expression */
3383         uc_compiler_parse_consume(compiler, TK_LPAREN);
3384         uc_compiler_compile_expression(compiler, true);
3385         uc_compiler_parse_consume(compiler, TK_RPAREN);
3386 
3387         /* conditional jump to else/elif branch */
3388         jmpz_off = uc_compiler_emit_jmpz(compiler, 0);
3389 
3390         if (uc_compiler_parse_match(compiler, TK_COLON)) {
3391                 compiler->exprstack->flags |= F_ALTBLOCKMODE;
3392 
3393                 while (true) {
3394                         /* compile elsif or else branch */
3395                         type = uc_compiler_compile_altifblock(compiler);
3396 
3397                         /* we just compiled an elsif block */
3398                         if (!expect_endif && type == TK_ELIF) {
3399                                 /* emit jump to skip to the end */
3400                                 uc_vector_push(&elifs, uc_compiler_emit_jmp(compiler, 0));
3401 
3402                                 /* point previous conditional jump to beginning of branch */
3403                                 uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
3404 
3405                                 /* parse & compile elsif condition */
3406                                 uc_compiler_parse_advance(compiler);
3407                                 uc_compiler_parse_consume(compiler, TK_LPAREN);
3408                                 uc_compiler_compile_expression(compiler, true);
3409                                 uc_compiler_parse_consume(compiler, TK_RPAREN);
3410                                 uc_compiler_parse_consume(compiler, TK_COLON);
3411 
3412                                 /* conditional jump to else/elif branch */
3413                                 jmpz_off = uc_compiler_emit_jmpz(compiler, 0);
3414                         }
3415                         else if (!expect_endif && type == TK_ELSE) {
3416                                 /* emit jump to skip to the end */
3417                                 uc_vector_push(&elifs, uc_compiler_emit_jmp(compiler, 0));
3418 
3419                                 /* point previous conditional jump to beginning of branch */
3420                                 uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
3421                                 jmpz_off = 0;
3422 
3423                                 /* skip "else" keyword */
3424                                 uc_compiler_parse_advance(compiler);
3425 
3426                                 expect_endif = true;
3427                         }
3428                         else if (type == TK_ENDIF) {
3429                                 /* if no else clause, point previous conditional jump after block */
3430                                 if (jmpz_off)
3431                                         uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
3432 
3433                                 /* patch the elif branch jumps to point here after the else */
3434                                 for (i = 0; i < elifs.count; i++)
3435                                         uc_compiler_set_jmpaddr(compiler, elifs.entries[i],
3436                                                 chunk->count);
3437 
3438                                 /* skip the "endif" keyword */
3439                                 uc_compiler_parse_advance(compiler);
3440                                 break;
3441                         }
3442                         else {
3443                                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
3444                                         expect_endif
3445                                                 ? "Expecting 'endif'"
3446                                                 : "Expecting 'elif', 'else' or 'endif'");
3447 
3448                                 break;
3449                         }
3450                 }
3451 
3452                 uc_vector_clear(&elifs);
3453         }
3454         else {
3455                 /* compile true branch */
3456                 uc_compiler_compile_statement(compiler);
3457 
3458                 /* ... when present, handle false branch */
3459                 if (uc_compiler_parse_match(compiler, TK_ELSE)) {
3460                         /* jump to skip else branch */
3461                         jmp_off = uc_compiler_emit_jmp(compiler, 0);
3462 
3463                         /* set conditional jump address */
3464                         uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
3465 
3466                         /* compile false branch */
3467                         uc_compiler_compile_statement(compiler);
3468 
3469                         /* set else skip jump address */
3470                         uc_compiler_set_jmpaddr(compiler, jmp_off, chunk->count);
3471                 }
3472                 /* ... otherwise point the conditional jump after the true branch */
3473                 else {
3474                         uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
3475                 }
3476         }
3477 }
3478 
3479 static void
3480 uc_compiler_compile_while(uc_compiler_t *compiler)
3481 {
3482         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
3483         uc_patchlist_t p = { .depth = compiler->scope_depth, .token = TK_WHILE };
3484         size_t cond_off, jmpz_off, end_off;
3485 
3486         p.parent = compiler->patchlist;
3487         compiler->patchlist = &p;
3488 
3489         cond_off = chunk->count;
3490 
3491         /* parse & compile loop condition */
3492         uc_compiler_parse_consume(compiler, TK_LPAREN);
3493         uc_compiler_compile_expression(compiler, true);
3494         uc_compiler_parse_consume(compiler, TK_RPAREN);
3495 
3496         /* conditional jump to end */
3497         jmpz_off = uc_compiler_emit_jmpz(compiler, 0);
3498 
3499         /* compile loop body */
3500         if (uc_compiler_parse_match(compiler, TK_COLON)) {
3501                 uc_compiler_enter_scope(compiler);
3502 
3503                 if (uc_compiler_compile_delimitted_block(compiler, TK_ENDWHILE) == TK_EOF)
3504                         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
3505                                 "Expecting 'endwhile'");
3506                 else
3507                         uc_compiler_parse_advance(compiler);
3508 
3509                 uc_compiler_leave_scope(compiler);
3510         }
3511         else {
3512                 uc_compiler_compile_statement(compiler);
3513         }
3514 
3515         end_off = chunk->count;
3516 
3517         /* jump back to condition */
3518         uc_compiler_emit_jmp_dest(compiler, 0, cond_off);
3519 
3520         /* set conditional jump target */
3521         uc_compiler_set_jmpaddr(compiler, jmpz_off, chunk->count);
3522 
3523         /* patch up break/continue */
3524         uc_compiler_backpatch(compiler, chunk->count, end_off);
3525 }
3526 
3527 static void
3528 uc_compiler_compile_for_in(uc_compiler_t *compiler, bool local, uc_token_t *kvar, uc_token_t *vvar)
3529 {
3530         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
3531         uc_patchlist_t p = { .depth = compiler->scope_depth + 1, .token = TK_FOR };
3532         size_t skip_jmp, test_jmp, key_slot, val_slot;
3533 
3534         p.parent = compiler->patchlist;
3535         compiler->patchlist = &p;
3536 
3537         uc_compiler_enter_scope(compiler);
3538 
3539         /* declare internal loop variables */
3540         uc_compiler_emit_insn(compiler, 0, I_LNULL);
3541         key_slot = uc_compiler_declare_internal(compiler, 0, "(for in key)");
3542 
3543         uc_compiler_emit_insn(compiler, 0, I_LNULL);
3544         val_slot = uc_compiler_declare_internal(compiler, 0, "(for in value)");
3545 
3546         /* declare loop variables */
3547         if (local) {
3548                 uc_compiler_declare_local_null(compiler, kvar->pos, kvar->uv);
3549 
3550                 if (vvar)
3551                         uc_compiler_declare_local_null(compiler, vvar->pos, vvar->uv);
3552         }
3553 
3554         /* value to iterate */
3555         uc_compiler_compile_expression(compiler, false);
3556         uc_compiler_emit_stmt_end(compiler);
3557         uc_compiler_parse_consume(compiler, TK_RPAREN);
3558         uc_compiler_emit_insn(compiler, 0, I_SLOC);
3559         uc_compiler_emit_u32(compiler, 0, val_slot);
3560 
3561         /* initial key value */
3562         uc_compiler_emit_insn(compiler, 0, I_LNULL);
3563         uc_compiler_emit_insn(compiler, 0, I_SLOC);
3564         uc_compiler_emit_u32(compiler, 0, key_slot);
3565 
3566         /* jump over variable read for first cycle */
3567         skip_jmp = uc_compiler_emit_jmp(compiler, 0);
3568 
3569         /* read value */
3570         uc_compiler_emit_insn(compiler, 0, I_LLOC);
3571         uc_compiler_emit_u32(compiler, 0, val_slot);
3572 
3573         /* read key */
3574         uc_compiler_emit_insn(compiler, 0, I_LLOC);
3575         uc_compiler_emit_u32(compiler, 0, key_slot);
3576 
3577         /* backpatch skip jump */
3578         uc_compiler_set_jmpaddr(compiler, skip_jmp, chunk->count);
3579 
3580         /* load loop variable and get next key from object */
3581         uc_compiler_emit_insn(compiler, 0, vvar ? I_NEXTKV : I_NEXTK);
3582 
3583         /* set internal key variable */
3584         uc_compiler_emit_insn(compiler, 0, I_SLOC);
3585         uc_compiler_emit_u32(compiler, 0, key_slot);
3586 
3587         /* test for != null */
3588         uc_compiler_emit_insn(compiler, 0, I_LNULL);
3589         uc_compiler_emit_insn(compiler, 0, I_NES);
3590 
3591         /* jump after loop body if no next key */
3592         test_jmp = uc_compiler_emit_jmpz(compiler, 0);
3593 
3594         /* set key and value variables */
3595         if (vvar) {
3596                 uc_compiler_emit_variable_rw(compiler, vvar->uv, TK_ASSIGN);
3597                 uc_compiler_emit_insn(compiler, 0, I_POP);
3598         }
3599 
3600         /* set key variable */
3601         uc_compiler_emit_variable_rw(compiler, kvar->uv, TK_ASSIGN);
3602         uc_compiler_emit_insn(compiler, 0, I_POP);
3603 
3604         /* compile loop body */
3605         if (uc_compiler_parse_match(compiler, TK_COLON)) {
3606                 uc_compiler_enter_scope(compiler);
3607 
3608                 if (uc_compiler_compile_delimitted_block(compiler, TK_ENDFOR) == TK_EOF)
3609                         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
3610                                 "Expecting 'endfor'");
3611                 else
3612                         uc_compiler_parse_advance(compiler);
3613 
3614                 uc_compiler_leave_scope(compiler);
3615         }
3616         else {
3617                 uc_compiler_compile_statement(compiler);
3618         }
3619 
3620         /* jump back to retrieve next key */
3621         uc_compiler_emit_jmp_dest(compiler, 0, skip_jmp + 5);
3622 
3623         /* back patch conditional jump */
3624         uc_compiler_set_jmpaddr(compiler, test_jmp, chunk->count);
3625 
3626         /* pop loop variables */
3627         uc_compiler_emit_insn(compiler, 0, I_POP);
3628 
3629         if (vvar)
3630                 uc_compiler_emit_insn(compiler, 0, I_POP);
3631 
3632         /* patch up break/continue */
3633         uc_compiler_backpatch(compiler, chunk->count, skip_jmp + 5);
3634 
3635         uc_compiler_leave_scope(compiler);
3636 }
3637 
3638 static void
3639 uc_compiler_compile_for_count(uc_compiler_t *compiler, bool local, uc_token_t *predecl, uc_token_t *var)
3640 {
3641         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
3642         size_t test_off = 0, incr_off, skip_off, cond_off = 0;
3643         uc_patchlist_t p = { .depth = compiler->scope_depth + 1, .token = TK_FOR };
3644 
3645         p.parent = compiler->patchlist;
3646         compiler->patchlist = &p;
3647 
3648         uc_compiler_enter_scope(compiler);
3649 
3650         /* Initializer ---------------------------------------------------------- */
3651 
3652         /* A leading declaration without initializer, e.g. the `x` in
3653          * `for (let x, y = 0; ...)`, was consumed while disambiguating for-in */
3654         if (predecl && local)
3655                 uc_compiler_declare_local_null(compiler, predecl->pos, predecl->uv);
3656 
3657         /* If we parsed at least one label, try continue parsing as variable
3658          * expression... */
3659         if (var) {
3660                 /* We parsed a `local x` or `local x, y` expression, so (re)declare
3661                  * last label as local initializer variable */
3662                 if (local)
3663                         uc_compiler_declare_local_null(compiler, var->pos, var->uv);
3664 
3665                 uc_compiler_exprstack_push(compiler, TK_FOR, F_ASSIGNABLE);
3666 
3667                 uc_compiler_compile_labelexpr(compiler);
3668                 uc_compiler_emit_insn(compiler, 0, I_POP);
3669 
3670                 /* If followed by a comma, continue parsing expression */
3671                 if (uc_compiler_parse_match(compiler, TK_COMMA)) {
3672                         /* Is a continuation of a declaration list... */
3673                         if (local) {
3674                                 uc_compiler_compile_declexpr(compiler, false);
3675                         }
3676                         /* ... otherwise an unrelated expression */
3677                         else {
3678                                 uc_compiler_compile_expression(compiler, false);
3679                                 uc_compiler_emit_insn(compiler, 0, I_POP);
3680                         }
3681                 }
3682 
3683                 uc_compiler_exprstack_pop(compiler);
3684         }
3685         /* ... otherwise try parsing an entire expression (which might be absent) */
3686         else if (!uc_compiler_parse_check(compiler, TK_SCOL)) {
3687                 uc_compiler_compile_expression(compiler, false);
3688                 uc_compiler_emit_insn(compiler, 0, I_POP);
3689         }
3690 
3691         uc_compiler_emit_stmt_end(compiler);
3692         uc_compiler_parse_consume(compiler, TK_SCOL);
3693 
3694 
3695         /* Condition ------------------------------------------------------------ */
3696         if (!uc_compiler_parse_check(compiler, TK_SCOL)) {
3697                 cond_off = chunk->count;
3698 
3699                 uc_compiler_compile_expression(compiler, true);
3700 
3701                 test_off = uc_compiler_emit_jmpz(compiler, 0);
3702         }
3703 
3704         uc_compiler_parse_consume(compiler, TK_SCOL);
3705 
3706         /* jump over incrementer */
3707         skip_off = uc_compiler_emit_jmp(compiler, 0);
3708 
3709 
3710         /* Incrementer ---------------------------------------------------------- */
3711         incr_off = chunk->count;
3712 
3713         if (!uc_compiler_parse_check(compiler, TK_RPAREN)) {
3714                 uc_compiler_compile_expression(compiler, true);
3715                 uc_compiler_emit_insn(compiler, 0, I_POP);
3716         }
3717 
3718         uc_compiler_parse_consume(compiler, TK_RPAREN);
3719 
3720         /* if we have a condition, jump back to it, else continue to the loop body */
3721         if (test_off)
3722                 uc_compiler_emit_jmp_dest(compiler, 0, cond_off);
3723 
3724         /* back patch skip address */
3725         uc_compiler_set_jmpaddr(compiler, skip_off, chunk->count);
3726 
3727 
3728         /* Body ----------------------------------------------------------------- */
3729         if (uc_compiler_parse_match(compiler, TK_COLON)) {
3730                 uc_compiler_enter_scope(compiler);
3731 
3732                 if (uc_compiler_compile_delimitted_block(compiler, TK_ENDFOR) == TK_EOF)
3733                         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
3734                                 "Expecting 'endfor'");
3735                 else
3736                         uc_compiler_parse_advance(compiler);
3737 
3738                 uc_compiler_leave_scope(compiler);
3739         }
3740         else {
3741                 uc_compiler_compile_statement(compiler);
3742         }
3743 
3744         /* jump back to incrementer */
3745         uc_compiler_emit_jmp_dest(compiler, 0, incr_off);
3746 
3747         /* back patch conditional jump */
3748         if (test_off)
3749                 uc_compiler_set_jmpaddr(compiler, test_off, chunk->count);
3750 
3751         /* patch up break/continue */
3752         uc_compiler_backpatch(compiler, chunk->count, incr_off);
3753 
3754         uc_compiler_leave_scope(compiler);
3755 }
3756 
3757 static void
3758 uc_compiler_compile_for(uc_compiler_t *compiler)
3759 {
3760         uc_token_t keyvar = { 0 }, valvar = { 0 };
3761         bool local;
3762 
3763         uc_compiler_parse_consume(compiler, TK_LPAREN);
3764 
3765         uc_compiler_emit_stmt_start(compiler, &compiler->parser->curr);
3766 
3767         /* check the next few tokens and see if we have either a
3768          * `let x in` / `let x, y` expression or an ordinary initializer
3769          * statement */
3770 
3771         local = uc_compiler_parse_match(compiler, TK_LOCAL);
3772 
3773         if (uc_compiler_parse_match(compiler, TK_LABEL)) {
3774                 keyvar = compiler->parser->prev;
3775                 ucv_get(keyvar.uv);
3776 
3777                 if (uc_compiler_parse_match(compiler, TK_COMMA)) {
3778                         uc_compiler_parse_consume(compiler, TK_LABEL);
3779 
3780                         valvar = compiler->parser->prev;
3781                         ucv_get(valvar.uv);
3782                 }
3783 
3784                 /* is a for-in loop */
3785                 if (uc_compiler_parse_match(compiler, TK_IN)) {
3786                         uc_compiler_compile_for_in(compiler, local, &keyvar,
3787                                 valvar.type ? &valvar : NULL);
3788 
3789                         goto out;
3790                 }
3791         }
3792         else if (local) {
3793                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
3794                         "Expecting label after 'local'");
3795 
3796                 goto out;
3797         }
3798 
3799         /*
3800          * The previous expression ruled out a for-in loop, so continue parsing
3801          * as counting for loop...
3802          */
3803         if (valvar.uv)
3804                 uc_compiler_compile_for_count(compiler, local,
3805                         keyvar.uv ? &keyvar : NULL, &valvar);
3806         else
3807                 uc_compiler_compile_for_count(compiler, local,
3808                         NULL, keyvar.uv ? &keyvar : NULL);
3809 
3810 out:
3811         ucv_put(keyvar.uv);
3812         ucv_put(valvar.uv);
3813 }
3814 
3815 static void
3816 uc_compiler_compile_switch(uc_compiler_t *compiler)
3817 {
3818         size_t i, test_jmp, skip_jmp, next_jmp = 0, value_slot, default_off = 0;
3819         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
3820         uc_patchlist_t p = { .depth = compiler->scope_depth, .token = TK_SWITCH };
3821         uc_locals_t *locals = &compiler->locals;
3822         uc_jmplist_t cases = { 0 };
3823 
3824         p.parent = compiler->patchlist;
3825         compiler->patchlist = &p;
3826 
3827         uc_compiler_enter_scope(compiler);
3828 
3829         /* parse and compile match value */
3830         uc_compiler_parse_consume(compiler, TK_LPAREN);
3831         uc_compiler_compile_expression(compiler, true);
3832         uc_compiler_parse_consume(compiler, TK_RPAREN);
3833         uc_compiler_parse_consume(compiler, TK_LBRACE);
3834 
3835         value_slot = uc_compiler_declare_internal(compiler, 0, "(switch value)");
3836 
3837         /* jump to branch tests */
3838         test_jmp = uc_compiler_emit_jmp(compiler, 0);
3839 
3840         /* parse and compile case matches */
3841         while (!uc_compiler_parse_check(compiler, TK_RBRACE) &&
3842                !uc_compiler_parse_check(compiler, TK_EOF)) {
3843                 /* handle `default:` */
3844                 if (uc_compiler_parse_match(compiler, TK_DEFAULT)) {
3845                         if (default_off) {
3846                                 uc_vector_clear(&cases);
3847                                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
3848                                         "more than one switch default case");
3849 
3850                                 break;
3851                         }
3852 
3853                         uc_compiler_parse_consume(compiler, TK_COLON);
3854 
3855                         /* remember address of default branch */
3856                         default_off = chunk->count;
3857 
3858                         /* Store three values in case offset list:
3859                          *  1) amount of local variables declared so far
3860                          *  2) beginning of condition expression
3861                          *  3) end of condition expression
3862                          * For the `default` case, beginning and end offsets of the
3863                          * condition expression are equal.
3864                          */
3865                         uc_vector_extend(&cases, 3);
3866                         cases.entries[cases.count++] = (locals->count - 1) - value_slot;
3867                         cases.entries[cases.count++] = chunk->count;
3868                         cases.entries[cases.count++] = chunk->count;
3869                 }
3870 
3871                 /* handle `case …:` */
3872                 else if (uc_compiler_parse_match(compiler, TK_CASE)) {
3873                         /* jump over `case …:` label expression */
3874                         skip_jmp = uc_compiler_emit_jmp(compiler, 0);
3875 
3876                         /* compile case value expression */
3877                         uc_compiler_compile_expression(compiler, false);
3878                         uc_compiler_parse_consume(compiler, TK_COLON);
3879 
3880                         /* Store three values in case offset list:
3881                          *  1) amount of local variables declared so far
3882                          *  2) beginning of condition expression
3883                          *  3) end of condition expression
3884                          */
3885                         uc_vector_extend(&cases, 3);
3886                         cases.entries[cases.count++] = (locals->count - 1) - value_slot;
3887                         cases.entries[cases.count++] = skip_jmp + 5;
3888                         cases.entries[cases.count++] = uc_compiler_emit_jmp(compiler, 0);
3889 
3890                         /* patch jump skipping over the case value */
3891                         uc_compiler_set_jmpaddr(compiler, skip_jmp, chunk->count);
3892                 }
3893 
3894                 /* handle interleaved statement */
3895                 else if (cases.count) {
3896                         uc_compiler_compile_declaration(compiler);
3897                 }
3898 
3899                 /* a statement or expression preceding any `default` or `case` is a
3900                  * syntax error */
3901                 else {
3902                         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
3903                                 "Expecting 'case' or 'default'");
3904 
3905                         break;
3906                 }
3907         }
3908 
3909         uc_compiler_parse_consume(compiler, TK_RBRACE);
3910 
3911         /* evaluate case matches */
3912         if (cases.count) {
3913                 skip_jmp = uc_compiler_emit_jmp(compiler, 0);
3914 
3915                 uc_compiler_set_jmpaddr(compiler, test_jmp, chunk->count);
3916 
3917                 for (i = 0, default_off = cases.count; i < cases.count; i += 3) {
3918                         /* remember and skip default case */
3919                         if (cases.entries[i + 1] == cases.entries[i + 2]) {
3920                                 default_off = i;
3921                                 continue;
3922                         }
3923 
3924                         /* read switch match value */
3925                         uc_compiler_emit_insn(compiler, 0, I_LLOC);
3926                         uc_compiler_emit_u32(compiler, 0, value_slot);
3927 
3928                         /* jump to case value expression code */
3929                         uc_compiler_emit_jmp_dest(compiler, 0, cases.entries[i + 1]);
3930 
3931                         /* patch final case value expression jump back here */
3932                         uc_compiler_set_jmpaddr(compiler, cases.entries[i + 2], chunk->count);
3933 
3934                         /* strict equal test */
3935                         uc_compiler_emit_insn(compiler, 0, I_EQS);
3936 
3937                         /* conditional jump to next match */
3938                         next_jmp = uc_compiler_emit_jmpz(compiler, 0);
3939 
3940                         /* fill local slots */
3941                         while (cases.entries[i + 0] > 0) {
3942                                 uc_compiler_emit_insn(compiler, 0, I_LNULL);
3943                                 cases.entries[i + 0]--;
3944                         }
3945 
3946                         /* jump to target code */
3947                         uc_compiler_emit_jmp_dest(compiler, 0, cases.entries[i + 2] + 5);
3948 
3949                         /* patch next jump */
3950                         uc_compiler_set_jmpaddr(compiler, next_jmp, chunk->count);
3951                 }
3952 
3953                 /* handle default case (if any) */
3954                 if (default_off < cases.count) {
3955                         /* fill local slots */
3956                         while (cases.entries[default_off + 0] > 0) {
3957                                 uc_compiler_emit_insn(compiler, 0, I_LNULL);
3958                                 cases.entries[default_off + 0]--;
3959                         }
3960 
3961                         /* jump to target */
3962                         uc_compiler_emit_jmp_dest(compiler, 0, cases.entries[default_off + 2]);
3963 
3964                         /* do not patch final match failure jump later, we handle it here
3965                          * in the default case */
3966                         next_jmp = 0;
3967                 }
3968 
3969                 uc_compiler_set_jmpaddr(compiler, skip_jmp, chunk->count);
3970         }
3971         else {
3972                 uc_compiler_set_jmpaddr(compiler, test_jmp, test_jmp + 5);
3973         }
3974 
3975         uc_vector_clear(&cases);
3976 
3977         uc_compiler_leave_scope(compiler);
3978 
3979         /* if no default case exists, patch last case match failure jump */
3980         if (next_jmp) {
3981                 /* There's pop instructions for all local variables including the
3982                  * switch test value itself on the stack. Jump onto the last POP
3983                  * instruction (-1) to get rid of the on-stack switch test value
3984                  * but skip the POP instructions for all other scoped local variables
3985                  * which never have been initialized. */
3986                 uc_compiler_set_jmpaddr(compiler, next_jmp, chunk->count - 1);
3987         }
3988 
3989         uc_compiler_backpatch(compiler, chunk->count, 0);
3990 }
3991 
3992 static void
3993 uc_compiler_compile_try(uc_compiler_t *compiler)
3994 {
3995         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
3996         size_t try_from = 0, try_to = 0, jmp_off = 0, ehvar_slot = 0;
3997         uc_ehranges_t *ranges = &chunk->ehranges;
3998 
3999         try_from = chunk->count;
4000         ehvar_slot = compiler->locals.count;
4001 
4002         /* Try block ------------------------------------------------------------ */
4003         uc_compiler_enter_scope(compiler);
4004 
4005         /* while compiling the protected block, tail calls are avoided since the
4006          * current frame must be kept around to catch callee exceptions */
4007         compiler->try_depth++;
4008 
4009         uc_compiler_parse_consume(compiler, TK_LBRACE);
4010 
4011         while (!uc_compiler_parse_check(compiler, TK_RBRACE) &&
4012                !uc_compiler_parse_check(compiler, TK_EOF))
4013                 uc_compiler_compile_declaration(compiler);
4014 
4015         uc_compiler_parse_consume(compiler, TK_RBRACE);
4016 
4017         compiler->try_depth--;
4018 
4019         uc_compiler_leave_scope(compiler);
4020 
4021         /* jump beyond catch branch */
4022         try_to = chunk->count;
4023         jmp_off = uc_compiler_emit_jmp(compiler, 0);
4024 
4025 
4026         /* Catch block ---------------------------------------------------------- */
4027         if (try_to > try_from) {
4028                 uc_vector_push(ranges, {
4029                         .from   = try_from,
4030                         .to     = try_to,
4031                         .target = chunk->count,
4032                         .slot   = ehvar_slot
4033                 });
4034         }
4035 
4036         uc_compiler_enter_scope(compiler);
4037 
4038         uc_compiler_parse_consume(compiler, TK_CATCH);
4039 
4040         /* have exception variable */
4041         if (uc_compiler_parse_match(compiler, TK_LPAREN)) {
4042                 uc_compiler_parse_consume(compiler, TK_LABEL);
4043 
4044                 uc_compiler_declare_local(compiler, compiler->parser->prev.uv, false);
4045                 uc_compiler_initialize_local(compiler);
4046 
4047                 uc_compiler_parse_consume(compiler, TK_RPAREN);
4048         }
4049         /* ... else pop exception object from stack */
4050         else {
4051                 uc_compiler_emit_insn(compiler, 0, I_POP);
4052         }
4053 
4054         uc_compiler_parse_consume(compiler, TK_LBRACE);
4055 
4056         while (!uc_compiler_parse_check(compiler, TK_RBRACE) &&
4057                !uc_compiler_parse_check(compiler, TK_EOF))
4058                 uc_compiler_compile_declaration(compiler);
4059 
4060         uc_compiler_parse_consume(compiler, TK_RBRACE);
4061 
4062         uc_compiler_leave_scope(compiler);
4063 
4064         uc_compiler_set_jmpaddr(compiler, jmp_off, chunk->count);
4065 }
4066 
4067 static void
4068 uc_compiler_compile_control(uc_compiler_t *compiler)
4069 {
4070         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
4071         uc_tokentype_t type = compiler->parser->prev.type;
4072         uc_patchlist_t *p = compiler->patchlist;
4073         uc_locals_t *locals = &compiler->locals;
4074         size_t i, pos = compiler->parser->prev.pos;
4075 
4076         /* select applicable patchlist: for continue statements select the
4077          * first non-switch scope */
4078         while (p) {
4079                 if (type != TK_CONTINUE || p->token != TK_SWITCH)
4080                         break;
4081 
4082                 p = p->parent;
4083         }
4084 
4085         if (!p || p->token == TK_EXPORT) {
4086                 uc_compiler_syntax_error(compiler, pos,
4087                         (type == TK_BREAK)
4088                                 ? "break must be inside loop or switch"
4089                                 : "continue must be inside loop");
4090 
4091                 return;
4092         }
4093 
4094         /* pop locals in all scopes covered by the target patchlist */
4095         for (i = locals->count; i > 0 && (size_t)locals->entries[i - 1].depth > p->depth; i--)
4096                 uc_compiler_emit_insn(compiler, 0,
4097                         locals->entries[i - 1].captured ? I_CUPV : I_POP);
4098 
4099         uc_vector_push(p,
4100                 uc_compiler_emit_jmp_dest(compiler, pos, chunk->count + type));
4101 
4102         uc_compiler_parse_consume(compiler, TK_SCOL);
4103 }
4104 
4105 static void
4106 uc_compiler_compile_return(uc_compiler_t *compiler)
4107 {
4108         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
4109 
4110         if (compiler->function->module) {
4111                 uc_compiler_syntax_error(compiler, 0, "return must be inside function body");
4112 
4113                 return;
4114         }
4115 
4116         /* if we compiled an empty expression statement (`;`), load implicit null */
4117         if (uc_compiler_compile_expstmt(compiler) == TK_NULL)
4118                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LNULL);
4119 
4120         /* otherwise overwrite the final I_POP instruction with I_RETURN */
4121         else
4122                 uc_chunk_pop(chunk);
4123 
4124         /* invoke a function call in tail position to avoid growing the stack */
4125         bool tailcall = uc_compiler_tailcall_pending(compiler);
4126 
4127         uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_RETURN);
4128 
4129         if (tailcall)
4130                 uc_compiler_emit_tailcall_marker(compiler);
4131 }
4132 
4133 /* `throw` is sugar for the standard library's die() function. As a statement
4134  * it leaves nothing on the stack: the expression's value is handed to die() and
4135  * die()'s own result is discarded. */
4136 static void
4137 uc_compiler_compile_throw(uc_compiler_t *compiler)
4138 {
4139         /* a bare `throw` dies without a message, as does die() */
4140         if (uc_compiler_compile_expstmt(compiler) == TK_NULL)
4141                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LNULL);
4142 
4143         /* ... otherwise drop the expression statement's trailing I_POP, so that the
4144          * thrown value stays on the stack to become die()'s argument */
4145         else
4146                 uc_chunk_pop(uc_compiler_current_chunk(compiler));
4147 
4148         uc_compiler_emit_stcall(compiler, 0, UC_FN_DIE, 1);
4149 
4150         uc_compiler_emit_insn(compiler, 0, I_POP);
4151 }
4152 
4153 static void
4154 uc_compiler_compile_tplexp(uc_compiler_t *compiler)
4155 {
4156         uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
4157         size_t off = chunk->count;
4158 
4159         uc_compiler_compile_expression(compiler, true);
4160 
4161         /* XXX: the lexer currently emits a superfluous trailing semicolon... */
4162         uc_compiler_parse_match(compiler, TK_SCOL);
4163 
4164         uc_compiler_parse_consume(compiler, TK_REXP);
4165 
4166         if (chunk->count > off)
4167                 uc_compiler_emit_insn(compiler, 0, I_PRINT);
4168 }
4169 
4170 static void
4171 uc_compiler_compile_text(uc_compiler_t *compiler)
4172 {
4173         uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.uv);
4174         uc_compiler_emit_insn(compiler, 0, I_PRINT);
4175 }
4176 
4177 static uc_tokentype_t
4178 uc_compiler_compile_block(uc_compiler_t *compiler)
4179 {
4180         uc_tokentype_t last_statement_type = TK_NULL;
4181 
4182         uc_compiler_enter_scope(compiler);
4183 
4184         while (!uc_compiler_parse_check(compiler, TK_RBRACE) &&
4185                !uc_compiler_parse_check(compiler, TK_EOF))
4186                 last_statement_type = uc_compiler_compile_declaration(compiler);
4187 
4188         uc_compiler_parse_consume(compiler, TK_RBRACE);
4189 
4190         uc_compiler_leave_scope(compiler);
4191 
4192         return last_statement_type;
4193 }
4194 
4195 static uc_tokentype_t
4196 uc_compiler_compile_expstmt(uc_compiler_t *compiler)
4197 {
4198         /* empty statement */
4199         if (uc_compiler_parse_match(compiler, TK_SCOL))
4200                 return TK_NULL;
4201 
4202         uc_compiler_compile_expression(compiler, false);
4203 
4204         /* allow omitting final semicolon */
4205         switch (compiler->parser->curr.type) {
4206         case TK_RBRACE:
4207         case TK_ELIF:
4208         case TK_ENDIF:
4209         case TK_ENDFOR:
4210         case TK_ENDWHILE:
4211         case TK_ENDFUNC:
4212         case TK_EOF:
4213                 break;
4214 
4215         case TK_ELSE:
4216                 if (!uc_compiler_exprstack_is(compiler, F_ALTBLOCKMODE))
4217                         uc_compiler_parse_consume(compiler, TK_SCOL);
4218 
4219                 break;
4220 
4221         default:
4222                 uc_compiler_parse_consume(compiler, TK_SCOL);
4223 
4224                 break;
4225         }
4226 
4227         uc_compiler_emit_insn(compiler, 0, I_POP);
4228 
4229         return TK_SCOL;
4230 }
4231 
4232 static uc_tokentype_t
4233 uc_compiler_compile_statement(uc_compiler_t *compiler)
4234 {
4235         uc_tokentype_t last_statement_type = compiler->parser->curr.type;
4236         uc_exprstack_t expr = {
4237                 .token = compiler->parser->curr.type,
4238                 .parent = compiler->exprstack
4239         };
4240 
4241         compiler->exprstack = &expr;
4242 
4243         if (uc_compiler_parse_match(compiler, TK_LBRACE)) {
4244                 last_statement_type = uc_compiler_compile_block(compiler);
4245         }
4246         else {
4247                 uc_compiler_emit_stmt_start(compiler, &compiler->parser->curr);
4248 
4249                 if (uc_compiler_parse_match(compiler, TK_IF))
4250                         uc_compiler_compile_if(compiler);
4251                 else if (uc_compiler_parse_match(compiler, TK_WHILE))
4252                         uc_compiler_compile_while(compiler);
4253                 else if (uc_compiler_parse_match(compiler, TK_FOR))
4254                         uc_compiler_compile_for(compiler);
4255                 else if (uc_compiler_parse_match(compiler, TK_SWITCH))
4256                         uc_compiler_compile_switch(compiler);
4257                 else if (uc_compiler_parse_match(compiler, TK_TRY))
4258                         uc_compiler_compile_try(compiler);
4259                 else if (uc_compiler_parse_match(compiler, TK_FUNC))
4260                         uc_compiler_compile_funcdecl(compiler);
4261                 else if (uc_compiler_parse_match(compiler, TK_BREAK))
4262                         uc_compiler_compile_control(compiler);
4263                 else if (uc_compiler_parse_match(compiler, TK_CONTINUE))
4264                         uc_compiler_compile_control(compiler);
4265                 else if (uc_compiler_parse_match(compiler, TK_RETURN))
4266                         uc_compiler_compile_return(compiler);
4267                 else if (uc_compiler_parse_match(compiler, TK_THROW))
4268                         uc_compiler_compile_throw(compiler);
4269                 else if (uc_compiler_parse_match(compiler, TK_TEXT))
4270                         uc_compiler_compile_text(compiler);
4271                 else if (uc_compiler_parse_match(compiler, TK_LEXP))
4272                         uc_compiler_compile_tplexp(compiler);
4273                 else
4274                         last_statement_type = uc_compiler_compile_expstmt(compiler);
4275 
4276                 uc_compiler_emit_stmt_end(compiler);
4277         }
4278 
4279         compiler->exprstack = expr.parent;
4280 
4281         return last_statement_type;
4282 }
4283 
4284 static void
4285 uc_compiler_export_add(uc_compiler_t *compiler, uc_value_t *name, ssize_t slot)
4286 {
4287         uc_source_t *source = uc_compiler_current_source(compiler);
4288 
4289         uc_compiler_inc_exportnum(compiler);
4290 
4291         if (!uc_source_export_add(source, name)) {
4292                 if (name)
4293                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
4294                                 "Duplicate export '%s' for module '%s'", ucv_string_get(name), source->filename);
4295                 else
4296                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
4297                                 "Duplicate default export for module '%s'", source->filename);
4298         }
4299         else {
4300                 uc_vector_push(compiler->patchlist, slot);
4301         }
4302 }
4303 
4304 static void
4305 uc_compiler_compile_exportlist(uc_compiler_t *compiler)
4306 {
4307         uc_value_t *label, *name;
4308         bool constant;
4309         ssize_t slot;
4310 
4311         /* parse export symbols */
4312         do {
4313                 uc_compiler_parse_consume(compiler, TK_LABEL);
4314 
4315                 label = ucv_get(compiler->parser->prev.uv);
4316                 name = NULL;
4317 
4318                 slot = uc_compiler_resolve_local(compiler, label, &constant);
4319 
4320                 if (slot == -1) {
4321                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
4322                                 "Attempt to export undeclared or non-local variable '%s'",
4323                                 ucv_string_get(label));
4324                 }
4325 
4326                 if (uc_compiler_keyword_match(compiler, "as")) {
4327                         if (uc_compiler_parse_match(compiler, TK_LABEL) || uc_compiler_parse_match(compiler, TK_STRING)) {
4328                                 name = ucv_get(compiler->parser->prev.uv);
4329                         }
4330                         else if (!uc_compiler_parse_match(compiler, TK_DEFAULT)) {
4331                                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
4332                                         "Unexpected token\nExpecting Label, String or 'default'");
4333                         }
4334                 }
4335                 else {
4336                         name = ucv_get(label);
4337                 }
4338 
4339                 uc_compiler_export_add(compiler, name, slot);
4340 
4341                 ucv_put(label);
4342                 ucv_put(name);
4343 
4344                 if (uc_compiler_parse_match(compiler, TK_RBRACE))
4345                         break;
4346         }
4347         while (uc_compiler_parse_match(compiler, TK_COMMA));
4348 
4349         uc_compiler_parse_consume(compiler, TK_SCOL);
4350 }
4351 
4352 static void
4353 uc_compiler_compile_export(uc_compiler_t *compiler)
4354 {
4355         uc_locals_t *locals = &compiler->locals;
4356         size_t off = locals->count;
4357         uc_value_t *name;
4358         ssize_t slot;
4359 
4360         if (!compiler->function->module || compiler->scope_depth) {
4361                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
4362                         "Exports may only appear at top level of a module");
4363 
4364                 return;
4365         }
4366 
4367         uc_compiler_emit_stmt_start(compiler, &compiler->parser->prev);
4368 
4369         if (uc_compiler_parse_match(compiler, TK_LBRACE)) {
4370                 uc_compiler_compile_exportlist(compiler);
4371                 uc_compiler_emit_stmt_end(compiler);
4372 
4373                 return;
4374         }
4375 
4376         if (uc_compiler_parse_match(compiler, TK_LOCAL))
4377                 uc_compiler_compile_declexpr(compiler, false);
4378         else if (uc_compiler_parse_match(compiler, TK_CONST))
4379                 uc_compiler_compile_declexpr(compiler, true);
4380         else if (uc_compiler_parse_match(compiler, TK_FUNC)) {
4381                 uc_compiler_compile_funcdecl(compiler);
4382 
4383                 for (; off < locals->count; off++)
4384                         uc_compiler_export_add(compiler, locals->entries[off].name, off);
4385 
4386                 return;
4387         }
4388         else if (uc_compiler_parse_match(compiler, TK_DEFAULT))
4389                 uc_compiler_compile_expression(compiler, false);
4390         else
4391                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
4392                         "Unexpected token\nExpecting 'let', 'const', 'function', 'default' or '{'");
4393 
4394         /* skip internal variables of destructuring declarations */
4395         while (off < locals->count && !strncmp(ucv_string_get(locals->entries[off].name), "(destructure)", 13))
4396                 off++;
4397 
4398         if (off == locals->count) {
4399                 name = ucv_string_new("(module default export)");
4400                 slot = uc_compiler_declare_local(compiler, name, true);
4401                 ucv_put(name);
4402 
4403                 if (slot != -1)
4404                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
4405                                 "Duplicate default export statement");
4406                 else
4407                         uc_compiler_export_add(compiler, NULL, compiler->locals.count - 1);
4408         }
4409         else {
4410                 for (; off < locals->count; off++)
4411                         if (strncmp(ucv_string_get(locals->entries[off].name), "(destructure)", 13))
4412                                 uc_compiler_export_add(compiler, locals->entries[off].name, off);
4413         }
4414 
4415         uc_compiler_parse_consume(compiler, TK_SCOL);
4416 
4417         uc_compiler_emit_stmt_end(compiler);
4418 }
4419 
4420 static uc_program_t *
4421 uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, uc_program_t *prog, char **errp);
4422 
4423 static bool
4424 uc_compiler_compile_dynload(uc_compiler_t *compiler, const char *name, uc_value_t *imports)
4425 {
4426         uc_value_t *modname = ucv_string_new(name);
4427         size_t pos = compiler->parser->prev.pos;
4428         size_t i, n_imports;
4429         uc_value_t *import;
4430 
4431         for (i = 0, n_imports = 0; i < ucv_array_length(imports); i++) {
4432                 import = ucv_array_get(imports, i);
4433 
4434                 if (ucv_boolean_get(import)) {
4435                         uc_compiler_emit_constant(compiler, pos, modname);
4436                         uc_compiler_emit_insn(compiler, pos, I_DYNLOAD);
4437                         uc_compiler_emit_u32(compiler, 0, 0);
4438                 }
4439                 else {
4440                         n_imports++;
4441                 }
4442         }
4443 
4444         if (n_imports > 0) {
4445                 uc_compiler_emit_constant(compiler, pos, modname);
4446                 uc_compiler_emit_insn(compiler, pos, I_DYNLOAD);
4447                 uc_compiler_emit_u32(compiler, 0, n_imports | ((compiler->upvals.count - n_imports) << 16));
4448 
4449                 for (i = 0; i < ucv_array_length(imports); i++) {
4450                         import = ucv_get(ucv_array_get(imports, i));
4451 
4452                         if (!import)
4453                                 import = ucv_string_new("default");
4454 
4455                         if (!ucv_boolean_get(import))
4456                                 uc_compiler_emit_constant_index(compiler, 0, import);
4457 
4458                         ucv_put(import);
4459                 }
4460         }
4461 
4462         ucv_put(modname);
4463 
4464         return true;
4465 }
4466 
4467 static bool
4468 uc_compiler_compile_module_source(uc_compiler_t *compiler, const char *modname, uc_source_t *source, uc_value_t *imports, char **errp)
4469 {
4470         uc_parse_config_t config = {
4471                 .raw_mode = true,
4472                 .strict_declarations = true,
4473                 .module_search_path = compiler->parser->lex.config->module_search_path
4474         };
4475 
4476         size_t i, load_idx = 0, n_imports = 0, n_exports = 0;
4477         bool loaded = false, res;
4478         uc_value_t *import;
4479         ssize_t slot;
4480 
4481         uc_program_function_foreach(compiler->program, fn) {
4482                 if (uc_program_function_source(fn) == source) {
4483                         loaded = true;
4484                         break;
4485                 }
4486         }
4487 
4488         /* An offset of -1 marks a source whose compilation was entered but not yet
4489          * completed. Re-entering it is either a circular dependency (its function is
4490          * still present) or a module whose earlier compilation failed and freed its
4491          * function. Recompiling in either case recurses without bound across a large
4492          * import graph, so report the cycle and propagate the failure instead. */
4493         if (source->exports.offset == (size_t)-1) {
4494                 if (loaded)
4495                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
4496                                 "Circular dependency");
4497                 else if (errp)
4498                         xasprintf(errp, "Module previously failed to compile\n");
4499 
4500                 return false;
4501         }
4502 
4503         if (!loaded) {
4504                 /* We do not yet support linking precompiled modules at compile time,
4505                    turn static import operation into dynamic load one. */
4506                 switch (uc_source_begin(source)) {
4507                 case UC_SOURCE_TYPE_PRECOMPILED:
4508                         uc_source_reset(source);
4509 
4510                         return uc_compiler_compile_dynload(compiler, modname, imports);
4511 
4512                 case UC_SOURCE_TYPE_UNAVAILABLE:
4513                         if (errp)
4514                                 xasprintf(errp, "Unable to open source file %s: %s\n",
4515                                         source->filename, strerror(errno));
4516 
4517                         return false;
4518 
4519                 default:
4520                         break;
4521                 }
4522 
4523                 load_idx = uc_program_function_id(compiler->program,
4524                         uc_program_function_last(compiler->program)) + 1;
4525 
4526                 source->exports.offset = (size_t)-1;
4527                 n_exports = uc_compiler_get_exportnum(compiler);
4528 
4529                 res = uc_compile_from_source(&config, source, compiler->program, errp);
4530 
4531                 uc_source_reset(source);
4532 
4533                 if (!res)
4534                         return false;
4535 
4536                 /* The linked module's own exports are the last ones allocated while
4537                  * compiling it, its offset is the allocation counter minus its count. */
4538                 source->exports.offset = uc_compiler_get_exportnum(compiler) - source->exports.count;
4539 
4540                 /* The importing source's own exports follow everything that got
4541                  * allocated while compiling the import, i.e. the exports of the linked
4542                  * module plus those of all modules it pulled in transitively. */
4543                 uc_compiler_current_source(compiler)->exports.offset +=
4544                         uc_compiler_get_exportnum(compiler) - n_exports;
4545 
4546                 /* emit load, call & pop instructions */
4547                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_CLFN);
4548                 uc_compiler_emit_u32(compiler, 0, load_idx);
4549 
4550                 uc_compiler_emit_insn(compiler, 0, I_CALL);
4551                 uc_compiler_emit_u32(compiler, 0, 0);
4552 
4553                 uc_compiler_emit_insn(compiler, 0, I_POP);
4554         }
4555 
4556         /* count imports, handle wildcard imports */
4557         for (i = 0; i < ucv_array_length(imports); i++) {
4558                 if (ucv_boolean_get(ucv_array_get(imports, i))) {
4559                         if (source->exports.offset > 0xffff || source->exports.count > 0xffff) {
4560                                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
4561                                         "Too many module exports");
4562                         }
4563 
4564                         /* emit import instruction... */
4565                         uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_IMPORT);
4566                         uc_compiler_emit_u32(compiler, 0, source->exports.count | (0xffffu << 16));
4567 
4568                         /* ... followed by first module export offset ... */
4569                         uc_compiler_emit_u16(compiler, 0, source->exports.offset);
4570 
4571                         /* ... and constant indexes for all exported names */
4572                         for (load_idx = 0; load_idx < source->exports.count; load_idx++) {
4573                                 if (source->exports.entries[load_idx])
4574                                         import = ucv_get(source->exports.entries[load_idx]);
4575                                 else
4576                                         import = ucv_string_new("default");
4577 
4578                                 uc_compiler_emit_constant_index(compiler, 0, import);
4579                                 ucv_put(import);
4580                         }
4581 
4582                 }
4583                 else {
4584                         n_imports++;
4585                 }
4586         }
4587 
4588         /* 0xffff is reserved for wildcard import */
4589         if (n_imports > 0xfffe)
4590                 uc_compiler_syntax_error(compiler, 0, "Too many imports");
4591 
4592         /* emit non-wildcard import instructions */
4593         for (i = 0; i < ucv_array_length(imports); i++) {
4594                 import = ucv_array_get(imports, i);
4595 
4596                 if (!ucv_boolean_get(import)) {
4597                         slot = uc_source_export_lookup(source, import);
4598 
4599                         if (slot == -1) {
4600                                 if (import)
4601                                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
4602                                                 "Module %s does not export '%s'", source->filename, ucv_string_get(import));
4603                                 else
4604                                         uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
4605                                                 "Module %s has no default export", source->filename);
4606                         }
4607                         else if (slot > 0xffff) {
4608                                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
4609                                         "Too many module exports");
4610                         }
4611                         else {
4612                                 uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_IMPORT);
4613                                 uc_compiler_emit_u32(compiler, 0,
4614                                         (source->exports.offset + slot) | ((compiler->upvals.count - n_imports + i) << 16));
4615                         }
4616                 }
4617         }
4618 
4619         return true;
4620 }
4621 
4622 static char *
4623 uc_compiler_canonicalize_path(const char *path, const char *runpath)
4624 {
4625         char *p, *resolved;
4626         const char *slash;
4627 
4628         if (*path == '/')
4629                 xasprintf(&p, "%s", path);
4630         else if (runpath && (slash = strrchr(runpath, '/')) != NULL)
4631                 xasprintf(&p, "%.*s/%s", (int)(slash - runpath), runpath, path);
4632         else
4633                 xasprintf(&p, "./%s", path);
4634 
4635         resolved = realpath(p, NULL);
4636 
4637         free(p);
4638 
4639         return resolved;
4640 }
4641 
4642 static char *
4643 uc_compiler_expand_module_path(const char *name, const char *runpath, const char *template)
4644 {
4645         int namelen, prefixlen;
4646         const char *asterix;
4647         char *path, *p;
4648 
4649         asterix = strchr(template, '*');
4650 
4651         if (!asterix)
4652                 return NULL;
4653 
4654         prefixlen = asterix - template;
4655         namelen = strlen(name);
4656 
4657         xasprintf(&path, "%.*s%.*s%s", prefixlen, template, namelen, name, asterix + 1);
4658 
4659         for (p = path + prefixlen; namelen > 0; namelen--, p++)
4660                 if (*p == '.')
4661                         *p = '/';
4662 
4663         p = uc_compiler_canonicalize_path(path, runpath);
4664 
4665         free(path);
4666 
4667         return p;
4668 }
4669 
4670 static char *
4671 uc_compiler_resolve_module_path(uc_compiler_t *compiler, const char *name)
4672 {
4673         uc_search_path_t *search = &compiler->parser->lex.config->module_search_path;
4674         uc_source_t *source = uc_compiler_current_source(compiler);
4675         char *path = NULL;
4676         size_t i;
4677 
4678         if (strchr(name, '/'))
4679                 return uc_compiler_canonicalize_path(name, source->runpath);
4680 
4681         for (i = 0; i < search->count && !path; i++)
4682                 path = uc_compiler_expand_module_path(name, source->runpath, search->entries[i]);
4683 
4684         return path;
4685 }
4686 
4687 static uc_source_t *
4688 uc_compiler_acquire_source(uc_compiler_t *compiler, const char *path)
4689 {
4690         size_t i;
4691 
4692         for (i = 0; i < compiler->program->sources.count; i++)
4693                 if (!strcmp(compiler->program->sources.entries[i]->filename, path))
4694                         return uc_source_get(compiler->program->sources.entries[i]);
4695 
4696         return uc_source_new_file(path);
4697 }
4698 
4699 static bool
4700 uc_compiler_is_dynlink_module(uc_compiler_t *compiler, const char *name, const char *path)
4701 {
4702         uc_search_path_t *dynlink_list = &compiler->parser->config->force_dynlink_list;
4703         const char *dot;
4704         size_t i;
4705 
4706         for (i = 0; i < dynlink_list->count; i++)
4707                 if (!strcmp(dynlink_list->entries[i], name))
4708                         return true;
4709 
4710         if (!path)
4711                 return false;
4712 
4713         dot = strrchr(path, '.');
4714 
4715         return (dot && !strcmp(dot, ".so"));
4716 }
4717 
4718 static bool
4719 uc_compiler_compile_module(uc_compiler_t *compiler, const char *name, uc_value_t *imports)
4720 {
4721         uc_source_t *source;
4722         char *path, *err;
4723         bool res;
4724 
4725         if (!name)
4726                 return false;
4727 
4728         path = uc_compiler_resolve_module_path(compiler, name);
4729 
4730         if (uc_compiler_is_dynlink_module(compiler, name, path)) {
4731                 res = uc_compiler_compile_dynload(compiler, name, imports);
4732         }
4733         else if (path) {
4734                 source = uc_compiler_acquire_source(compiler, path);
4735 
4736                 if (source) {
4737                         err = NULL;
4738                         res = uc_compiler_compile_module_source(compiler, name, source, imports, &err);
4739 
4740                         if (!res) {
4741                                 uc_error_message_indent(&err);
4742                                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
4743                                         "Unable to compile module '%s':\n\n%s", source->filename, err);
4744                         }
4745 
4746                         free(err);
4747                 }
4748                 else {
4749                         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
4750                                 "Unable to open module '%s': %s",
4751                                 path, strerror(errno));
4752 
4753                         res = false;
4754                 }
4755 
4756                 uc_source_put(source);
4757         }
4758         else {
4759                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
4760                         "Unable to resolve path for module '%s'", name);
4761 
4762                 return false;
4763         }
4764 
4765         free(path);
4766 
4767         return res;
4768 }
4769 
4770 static void
4771 uc_compiler_import_add(uc_compiler_t *compiler, uc_value_t *name)
4772 {
4773         bool constant;
4774         ssize_t slot;
4775 
4776         slot = uc_compiler_resolve_local(compiler, name, &constant);
4777 
4778         if (slot != -1) {
4779                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
4780                         "Import name '%s' is already declared as local variable",
4781                         ucv_string_get(name));
4782 
4783                 return;
4784         }
4785 
4786         slot = uc_compiler_resolve_upval(compiler, name, &constant);
4787 
4788         if (slot != -1) {
4789                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
4790                         "Import name '%s' is already used",
4791                         ucv_string_get(name));
4792 
4793                 return;
4794         }
4795 
4796         uc_compiler_add_upval(compiler, (2 << 14) + compiler->upvals.count, false, name, true);
4797 }
4798 
4799 static void
4800 uc_compiler_compile_importlist(uc_compiler_t *compiler, uc_value_t *namelist)
4801 {
4802         uc_value_t *label, *name;
4803 
4804         /* parse export symbols */
4805         do {
4806                 name = NULL;
4807                 label = NULL;
4808 
4809                 if (uc_compiler_parse_match(compiler, TK_DEFAULT)) {
4810                         uc_compiler_keyword_consume(compiler, "as");
4811                         uc_compiler_parse_consume(compiler, TK_LABEL);
4812 
4813                         label = ucv_get(compiler->parser->prev.uv);
4814                 }
4815                 else if (uc_compiler_parse_match(compiler, TK_STRING)) {
4816                         name = ucv_get(compiler->parser->prev.uv);
4817 
4818                         uc_compiler_keyword_consume(compiler, "as");
4819                         uc_compiler_parse_consume(compiler, TK_LABEL);
4820 
4821                         label = ucv_get(compiler->parser->prev.uv);
4822                 }
4823                 else if (uc_compiler_parse_match(compiler, TK_LABEL)) {
4824                         name = ucv_get(compiler->parser->prev.uv);
4825 
4826                         if (uc_compiler_keyword_match(compiler, "as")) {
4827                                 uc_compiler_parse_consume(compiler, TK_LABEL);
4828 
4829                                 label = ucv_get(compiler->parser->prev.uv);
4830                         }
4831                         else {
4832                                 label = ucv_get(name);
4833                         }
4834                 }
4835                 else {
4836                         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
4837                                 "Unexpected token\nExpecting Label, String or 'default'");
4838                 }
4839 
4840                 uc_compiler_import_add(compiler, label);
4841                 ucv_array_push(namelist, name);
4842                 ucv_put(label);
4843 
4844                 if (uc_compiler_parse_match(compiler, TK_RBRACE))
4845                         return;
4846         }
4847         while (uc_compiler_parse_match(compiler, TK_COMMA));
4848 
4849         uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
4850                 "Unexpected token\nExpecting 'as', ',' or '}'");
4851 }
4852 
4853 static void
4854 uc_compiler_compile_importcall(uc_compiler_t *compiler)
4855 {
4856         uc_compiler_parse_consume(compiler, TK_LPAREN);
4857         uc_compiler_parse_precedence(compiler, P_ASSIGN);
4858         uc_compiler_parse_consume(compiler, TK_RPAREN);
4859 
4860         uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_DYNLOAD);
4861         uc_compiler_emit_u32(compiler, 0, 0);
4862 }
4863 
4864 static uc_tokentype_t
4865 uc_compiler_compile_import(uc_compiler_t *compiler)
4866 {
4867         uc_value_t *namelist = ucv_array_new(NULL);
4868 
4869         /* import(...) */
4870         if (uc_compiler_parse_check(compiler, TK_LPAREN)) {
4871                 uc_compiler_parse_precedence_for_token(compiler, P_UNARY,
4872                                                        &compiler->parser->prev);
4873 
4874                 uc_compiler_emit_insn(compiler, 0, I_POP);
4875                 ucv_put(namelist);
4876 
4877                 return TK_SCOL;
4878         }
4879 
4880         if (compiler->scope_depth) {
4881                 uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
4882                         "Imports may only appear at top level");
4883 
4884                 ucv_put(namelist);
4885 
4886                 return TK_IMPORT;
4887         }
4888 
4889         uc_compiler_emit_stmt_start(compiler, &compiler->parser->prev);
4890 
4891         /* import { ... } from */
4892         if (uc_compiler_parse_match(compiler, TK_LBRACE)) {
4893                 uc_compiler_compile_importlist(compiler, namelist);
4894                 uc_compiler_keyword_consume(compiler, "from");
4895         }
4896 
4897         /* import * as name from */
4898         else if (uc_compiler_parse_match(compiler, TK_MUL)) {
4899                 uc_compiler_keyword_consume(compiler, "as");
4900                 uc_compiler_parse_consume(compiler, TK_LABEL);
4901 
4902                 uc_compiler_declare_local(compiler, compiler->parser->prev.uv, true);
4903                 uc_compiler_initialize_local(compiler);
4904                 ucv_array_push(namelist, ucv_boolean_new(true));
4905 
4906                 uc_compiler_keyword_consume(compiler, "from");
4907         }
4908 
4909         /* import defaultExport [, ... ] from */
4910         else if (uc_compiler_parse_match(compiler, TK_LABEL)) {
4911                 uc_compiler_import_add(compiler, compiler->parser->prev.uv);
4912                 ucv_array_push(namelist, NULL);
4913 
4914                 /* import defaultExport, ... from */
4915                 if (uc_compiler_parse_match(compiler, TK_COMMA)) {
4916                         /* import defaultExport, { ... } from */
4917                         if (uc_compiler_parse_match(compiler, TK_LBRACE)) {
4918                                 uc_compiler_compile_importlist(compiler, namelist);
4919                         }
4920 
4921                         /* import defaultExport, * as name from */
4922                         else if (uc_compiler_parse_match(compiler, TK_MUL)) {
4923                                 uc_compiler_keyword_consume(compiler, "as");
4924                                 uc_compiler_parse_consume(compiler, TK_LABEL);
4925 
4926                                 uc_compiler_declare_local(compiler, compiler->parser->prev.uv, true);
4927                                 uc_compiler_initialize_local(compiler);
4928                                 ucv_array_push(namelist, ucv_boolean_new(true));
4929                         }
4930 
4931                         /* error */
4932                         else {
4933                                 uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
4934                                         "Unexpected token\nExpecting '{' or '*'");
4935                         }
4936                 }
4937 
4938                 uc_compiler_keyword_consume(compiler, "from");
4939         }
4940 
4941         uc_compiler_parse_consume(compiler, TK_STRING);
4942 
4943         uc_compiler_compile_module(compiler, ucv_string_get(compiler->parser->prev.uv), namelist);
4944 
4945         uc_compiler_parse_consume(compiler, TK_SCOL);
4946 
4947         uc_compiler_emit_stmt_end(compiler);
4948 
4949         ucv_put(namelist);
4950 
4951         return TK_IMPORT;
4952 }
4953 
4954 static uc_tokentype_t
4955 uc_compiler_compile_declaration(uc_compiler_t *compiler)
4956 {
4957         uc_tokentype_t last_statement_type = compiler->parser->curr.type;
4958 
4959         if (uc_compiler_parse_match(compiler, TK_LOCAL))
4960                 uc_compiler_compile_local(compiler);
4961         else if (uc_compiler_parse_match(compiler, TK_CONST))
4962                 uc_compiler_compile_const(compiler);
4963         else if (uc_compiler_parse_match(compiler, TK_EXPORT))
4964                 uc_compiler_compile_export(compiler);
4965         else if (uc_compiler_parse_match(compiler, TK_IMPORT))
4966                 last_statement_type = uc_compiler_compile_import(compiler);
4967         else
4968                 last_statement_type = uc_compiler_compile_statement(compiler);
4969 
4970         if (compiler->parser->synchronizing)
4971                 uc_compiler_parse_synchronize(compiler);
4972 
4973         return last_statement_type;
4974 }
4975 
4976 #endif /* NO_COMPILE */
4977 
4978 
4979 static uc_program_t *
4980 uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, uc_program_t *prog, char **errp)
4981 {
4982 #ifdef NO_COMPILE
4983         if (errp)
4984                 xasprintf(errp, "Source code compilation not supported\n");
4985 
4986         return NULL;
4987 #else
4988         bool is_module = (prog != NULL) || (config && config->compile_module);
4989         uc_patchlist_t exports = { .token = TK_EXPORT };
4990         uc_exprstack_t expr = { .token = TK_EOF };
4991         uc_parser_t parser = { .config = config };
4992         uc_compiler_t compiler = { .parser = &parser, .exprstack = &expr };
4993         uc_tokentype_t last_statement_type = TK_NULL;
4994         uc_program_t *progptr;
4995         uc_function_t *fn;
4996         const char *name;
4997 
4998         if (!prog) {
4999                 progptr = uc_program_new();
5000                 name = is_module ? "module" : "main";
5001         }
5002         else {
5003                 progptr = prog;
5004                 name = "module";
5005         }
5006 
5007         uc_lexer_init(&parser.lex, config, source);
5008         uc_compiler_init(&compiler, name, source, 0, progptr,
5009                 config && config->strict_declarations);
5010 
5011         if (is_module) {
5012                 compiler.patchlist = &exports;
5013                 compiler.function->module = true;
5014         }
5015 
5016         uc_compiler_parse_advance(&compiler);
5017 
5018         while (!uc_compiler_parse_match(&compiler, TK_EOF))
5019                 last_statement_type = uc_compiler_compile_declaration(&compiler);
5020 
5021         if (!compiler.function->module && last_statement_type == TK_SCOL) {
5022                 uc_chunk_pop(uc_compiler_current_chunk(&compiler));
5023 
5024                 /* invoke a trailing call statement in tail position */
5025                 bool tailcall = uc_compiler_tailcall_pending(&compiler);
5026 
5027                 uc_compiler_emit_insn(&compiler, 0, I_RETURN);
5028 
5029                 if (tailcall)
5030                         uc_compiler_emit_tailcall_marker(&compiler);
5031 
5032                 last_statement_type = TK_RETURN;
5033         }
5034 
5035         fn = uc_compiler_finish(&compiler, last_statement_type);
5036 
5037         if (errp) {
5038                 *errp = parser.error ? parser.error->buf : NULL;
5039                 free(parser.error);
5040         }
5041         else {
5042                 printbuf_free(parser.error);
5043         }
5044 
5045         uc_lexer_free(&parser.lex);
5046         free(parser.scanned.entries);
5047         uc_vector_clear(&exports);
5048 
5049         if (!fn) {
5050                 if (progptr != prog)
5051                         ucv_put(&progptr->header);
5052 
5053                 return NULL;
5054         }
5055 
5056         return progptr;
5057 #endif
5058 }
5059 
5060 static uc_program_t *
5061 uc_compile_from_bytecode(uc_parse_config_t *config, uc_source_t *source, char **errp)
5062 {
5063         uc_program_t *prog;
5064 
5065         prog = uc_program_load(source, errp);
5066 
5067         if (prog && !uc_program_entry(prog)) {
5068                 if (errp)
5069                         xasprintf(errp, "Program file contains no entry function\n");
5070 
5071                 ucv_put(&prog->header);
5072                 prog = NULL;
5073         }
5074 
5075         return prog;
5076 }
5077 
5078 uc_program_t *
5079 uc_compile(uc_parse_config_t *config, uc_source_t *source, char **errp)
5080 {
5081         uc_program_t *prog = NULL;
5082 
5083         if (!config)
5084                 config = &uc_default_parse_config;
5085 
5086         switch (uc_source_begin(source)) {
5087         case UC_SOURCE_TYPE_PLAIN:
5088                 prog = uc_compile_from_source(config, source, NULL, errp);
5089                 break;
5090 
5091         case UC_SOURCE_TYPE_PRECOMPILED:
5092                 prog = uc_compile_from_bytecode(config, source, errp);
5093                 break;
5094 
5095         case UC_SOURCE_TYPE_UNAVAILABLE:
5096                 if (errp)
5097                         xasprintf(errp, "Unable to open source file %s: %s\n",
5098                                 source->filename, strerror(errno));
5099 
5100                 break;
5101 
5102         default:
5103                 if (errp)
5104                         xasprintf(errp, "Unrecognized source type\n");
5105 
5106                 break;
5107         }
5108 
5109         uc_source_reset(source);
5110 
5111         return prog;
5112 }
5113 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt