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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt