diff options
-rw-r--r-- | compiler.c | 546 | ||||
-rw-r--r-- | include/ucode/program.h | 2 | ||||
-rw-r--r-- | tests/custom/04_modules/01_export_variable_declaration | 29 | ||||
-rw-r--r-- | tests/custom/04_modules/02_export_function_declaration | 22 | ||||
-rw-r--r-- | tests/custom/04_modules/03_export_list | 27 | ||||
-rw-r--r-- | tests/custom/04_modules/04_export_rename | 28 | ||||
-rw-r--r-- | tests/custom/04_modules/05_export_default | 38 | ||||
-rw-r--r-- | tests/custom/04_modules/06_export_errors | 89 | ||||
-rw-r--r-- | tests/custom/04_modules/07_import_default | 99 | ||||
-rw-r--r-- | tests/custom/04_modules/08_import_list | 105 | ||||
-rw-r--r-- | tests/custom/04_modules/09_import_wildcard | 73 | ||||
-rw-r--r-- | tests/custom/04_modules/10_import_none | 18 | ||||
-rw-r--r-- | tests/custom/04_modules/11_import_many_exec_once | 28 | ||||
-rw-r--r-- | tests/custom/04_modules/12_import_immutability | 52 | ||||
-rw-r--r-- | tests/custom/04_modules/13_import_liveness | 29 | ||||
-rw-r--r-- | tests/custom/99_bugs/01_try_catch_stack_mismatch (renamed from tests/custom/04_bugs/01_try_catch_stack_mismatch) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/02_array_pop_use_after_free (renamed from tests/custom/04_bugs/02_array_pop_use_after_free) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/03_switch_fallthrough_miscompilation (renamed from tests/custom/04_bugs/03_switch_fallthrough_miscompilation) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/04_property_set_abort (renamed from tests/custom/04_bugs/04_property_set_abort) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/05_duplicate_resource_type (renamed from tests/custom/04_bugs/05_duplicate_resource_type) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/06_lexer_escape_at_boundary (renamed from tests/custom/04_bugs/06_lexer_escape_at_boundary) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/07_lexer_overlong_lines (renamed from tests/custom/04_bugs/07_lexer_overlong_lines) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/08_compiler_arrow_fn_expressions (renamed from tests/custom/04_bugs/08_compiler_arrow_fn_expressions) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/09_reject_invalid_array_indexes (renamed from tests/custom/04_bugs/09_reject_invalid_array_indexes) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/10_break_stack_mismatch (renamed from tests/custom/04_bugs/10_break_stack_mismatch) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/11_switch_stack_mismatch (renamed from tests/custom/04_bugs/11_switch_stack_mismatch) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/12_altblock_stack_mismatch (renamed from tests/custom/04_bugs/12_altblock_stack_mismatch) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/13_split_by_string_leading_trailing (renamed from tests/custom/04_bugs/13_split_by_string_leading_trailing) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/14_incomplete_expression_at_eof (renamed from tests/custom/04_bugs/14_incomplete_expression_at_eof) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/15_segfault_on_prefix_increment (renamed from tests/custom/04_bugs/15_segfault_on_prefix_increment) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/16_hang_on_regexp_at_eof (renamed from tests/custom/04_bugs/16_hang_on_regexp_at_eof) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/17_hang_on_unclosed_expression_block (renamed from tests/custom/04_bugs/17_hang_on_unclosed_expression_block) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/18_hang_on_line_comments_at_eof (renamed from tests/custom/04_bugs/18_hang_on_line_comments_at_eof) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/19_truncated_format_string (renamed from tests/custom/04_bugs/19_truncated_format_string) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/20_use_strict_stack_mismatch (renamed from tests/custom/04_bugs/20_use_strict_stack_mismatch) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/21_compiler_parenthesized_prop_keyword (renamed from tests/custom/04_bugs/21_compiler_parenthesized_prop_keyword) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/22_compiler_break_continue_scoping (renamed from tests/custom/04_bugs/22_compiler_break_continue_scoping) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/23_compiler_parenthesized_division (renamed from tests/custom/04_bugs/23_compiler_parenthesized_division) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/24_compiler_local_for_loop_declaration (renamed from tests/custom/04_bugs/24_compiler_local_for_loop_declaration) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/25_lexer_shifted_offsets (renamed from tests/custom/04_bugs/25_lexer_shifted_offsets) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/26_compiler_jmp_to_zero (renamed from tests/custom/04_bugs/26_compiler_jmp_to_zero) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/27_invalid_sparse_array_set (renamed from tests/custom/04_bugs/27_invalid_sparse_array_set) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/28_null_equality (renamed from tests/custom/04_bugs/28_null_equality) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/29_empty_string_as_number (renamed from tests/custom/04_bugs/29_empty_string_as_number) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/30_nan_strict_equality (renamed from tests/custom/04_bugs/30_nan_strict_equality) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/31_vallist_8bit_shortstrings (renamed from tests/custom/04_bugs/31_vallist_8bit_shortstrings) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/32_compiler_switch_patchlist_corruption (renamed from tests/custom/04_bugs/32_compiler_switch_patchlist_corruption) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/33_vm_computed_prop_decl_crash (renamed from tests/custom/04_bugs/33_vm_computed_prop_decl_crash) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/34_dirname_off_by_one (renamed from tests/custom/04_bugs/34_dirname_off_by_one) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/35_vm_callframe_double_free (renamed from tests/custom/04_bugs/35_vm_callframe_double_free) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/36_vm_nested_call_return (renamed from tests/custom/04_bugs/36_vm_nested_call_return) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/37_compiler_unexpected_unary_op (renamed from tests/custom/04_bugs/37_compiler_unexpected_unary_op) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/38_index_segfault (renamed from tests/custom/04_bugs/38_index_segfault) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/39_compiler_switch_continue_mismatch (renamed from tests/custom/04_bugs/39_compiler_switch_continue_mismatch) | 0 | ||||
-rw-r--r-- | tests/custom/99_bugs/40_lexer_bug_on_lstrip_off (renamed from tests/custom/04_bugs/40_lexer_bug_on_lstrip_off) | 0 |
55 files changed, 1175 insertions, 10 deletions
@@ -497,12 +497,23 @@ uc_compiler_set_u32(uc_compiler_t *compiler, size_t off, uint32_t n) } static size_t -uc_compiler_emit_constant(uc_compiler_t *compiler, size_t srcpos, uc_value_t *val) +uc_compiler_emit_constant_index(uc_compiler_t *compiler, size_t srcpos, uc_value_t *val) { size_t cidx = uc_program_add_constant(compiler->program, val); + uc_compiler_emit_u32(compiler, srcpos, cidx); + + return cidx; +} + +static size_t +uc_compiler_emit_constant(uc_compiler_t *compiler, size_t srcpos, uc_value_t *val) +{ + size_t cidx; + uc_compiler_emit_insn(compiler, srcpos, I_LOAD); - uc_compiler_emit_u32(compiler, 0, cidx); + + cidx = uc_compiler_emit_constant_index(compiler, srcpos, val); return cidx; } @@ -2924,13 +2935,516 @@ uc_compiler_compile_statement(uc_compiler_t *compiler) } static void -uc_compiler_compile_declaration(uc_compiler_t *compiler) +uc_compiler_export_add(uc_compiler_t *compiler, uc_value_t *name, ssize_t slot) +{ + uc_source_t *source = uc_compiler_current_source(compiler); + + if (!uc_source_export_add(source, name)) { + if (name) + uc_compiler_syntax_error(compiler, compiler->parser->prev.pos, + "Duplicate export '%s' for module '%s'", ucv_string_get(name), source->filename); + else + uc_compiler_syntax_error(compiler, compiler->parser->prev.pos, + "Duplicate default export for module '%s'", source->filename); + } + else { + uc_compiler_emit_insn(compiler, 0, I_EXPORT); + uc_compiler_emit_u32(compiler, 0, slot); + } +} + +static void +uc_compiler_compile_exportlist(uc_compiler_t *compiler) +{ + uc_value_t *label, *name; + bool constant; + ssize_t slot; + + /* parse export symbols */ + do { + uc_compiler_parse_consume(compiler, TK_LABEL); + + label = ucv_get(compiler->parser->prev.uv); + name = NULL; + + slot = uc_compiler_resolve_local(compiler, label, &constant); + + if (slot == -1) { + uc_compiler_syntax_error(compiler, compiler->parser->prev.pos, + "Attempt to export undeclared or non-local variable '%s'", + ucv_string_get(label)); + } + + if (uc_compiler_parse_match(compiler, TK_AS)) { + if (uc_compiler_parse_match(compiler, TK_LABEL) || uc_compiler_parse_match(compiler, TK_STRING)) { + name = ucv_get(compiler->parser->prev.uv); + } + else if (!uc_compiler_parse_match(compiler, TK_DEFAULT)) { + uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, + "Unexpected token\nExpecting Label, String or 'default'"); + } + } + else { + name = ucv_get(label); + } + + uc_compiler_export_add(compiler, name, slot); + + ucv_put(label); + ucv_put(name); + + if (uc_compiler_parse_match(compiler, TK_RBRACE)) + break; + } + while (uc_compiler_parse_match(compiler, TK_COMMA)); + + uc_compiler_parse_consume(compiler, TK_SCOL); +} + +static void +uc_compiler_compile_export(uc_compiler_t *compiler) +{ + uc_locals_t *locals = &compiler->locals; + size_t off = locals->count; + uc_value_t *name; + ssize_t slot; + + if (compiler->program->sources.count == 1 || compiler->scope_depth) { + uc_compiler_syntax_error(compiler, compiler->parser->prev.pos, + "Exports may only appear at top level of a module"); + + return; + } + + if (uc_compiler_parse_match(compiler, TK_LBRACE)) { + uc_compiler_compile_exportlist(compiler); + + return; + } + + if (uc_compiler_parse_match(compiler, TK_LOCAL)) + uc_compiler_compile_declexpr(compiler, false); + else if (uc_compiler_parse_match(compiler, TK_CONST)) + uc_compiler_compile_declexpr(compiler, true); + else if (uc_compiler_parse_match(compiler, TK_FUNC)) + uc_compiler_compile_funcdecl(compiler); + else if (uc_compiler_parse_match(compiler, TK_DEFAULT)) + uc_compiler_compile_expression(compiler); + else + uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, + "Unexpected token\nExpecting 'let', 'const', 'function', 'default' or '{'"); + + if (off == locals->count) { + name = ucv_string_new("(module default export)"); + slot = uc_compiler_declare_local(compiler, name, true); + ucv_put(name); + + if (slot != -1) + uc_compiler_syntax_error(compiler, compiler->parser->prev.pos, + "Duplicate default export statement"); + else + uc_compiler_export_add(compiler, NULL, compiler->locals.count - 1); + } + else { + for (; off < locals->count; off++) + uc_compiler_export_add(compiler, locals->entries[off].name, off); + } + + uc_compiler_parse_consume(compiler, TK_SCOL); +} + +static uc_program_t * +uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, uc_program_t *prog, char **errp); + +static bool +uc_compiler_compile_module_source(uc_compiler_t *compiler, uc_source_t *source, uc_value_t *imports, char **errp) +{ + uc_parse_config_t config = { + .raw_mode = true, + .strict_declarations = true, + .module_search_path = compiler->parser->lex.config->module_search_path + }; + + size_t i, load_idx = 0, n_imports = 0; + bool loaded = false; + uc_value_t *import; + ssize_t slot; + + uc_program_function_foreach(compiler->program, fn) { + if (uc_program_function_source(fn) == source) { + loaded = true; + break; + } + } + + if (!loaded) { + load_idx = uc_program_function_id(compiler->program, + uc_program_function_last(compiler->program)) + 1; + + if (!uc_compile_from_source(&config, source, compiler->program, errp)) + return false; + + /* emit load, call & pop instructions */ + uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_CLFN); + uc_compiler_emit_u32(compiler, 0, load_idx); + + uc_compiler_emit_insn(compiler, 0, I_CALL); + uc_compiler_emit_u32(compiler, 0, 0); + + uc_compiler_emit_insn(compiler, 0, I_POP); + } + + /* count imports, handle wildcard imports */ + for (i = 0; i < ucv_array_length(imports); i++) { + if (ucv_boolean_get(ucv_array_get(imports, i))) { + /* find index of first module export */ + slot = uc_program_export_lookup(compiler->program, source, source->exports.entries[0]); + + if (slot > 0xffff || source->exports.count > 0xffff) { + uc_compiler_syntax_error(compiler, compiler->parser->prev.pos, + "Too many module exports"); + } + + /* emit import instruction... */ + uc_compiler_emit_insn(compiler, 0, I_IMPORT); + uc_compiler_emit_u32(compiler, 0, source->exports.count | (0xffff << 16)); + + /* ... followed by first module export offset ... */ + uc_compiler_emit_u16(compiler, 0, slot); + + /* ... and constant indexes for all exported names */ + for (load_idx = 0; load_idx < source->exports.count; load_idx++) { + if (source->exports.entries[load_idx]) + import = ucv_get(source->exports.entries[load_idx]); + else + import = ucv_string_new("default"); + + uc_compiler_emit_constant_index(compiler, 0, import); + ucv_put(import); + } + + } + else { + n_imports++; + } + } + + /* 0xffff is reserved for wildcard import */ + if (n_imports > 0xfffe) + uc_compiler_syntax_error(compiler, 0, "Too many imports"); + + /* emit non-wilcard import instructions */ + for (i = 0; i < ucv_array_length(imports); i++) { + import = ucv_array_get(imports, i); + + if (!ucv_boolean_get(import)) { + slot = uc_program_export_lookup(compiler->program, source, import); + + if (slot == -1) { + if (import) + uc_compiler_syntax_error(compiler, compiler->parser->prev.pos, + "Module %s does not export '%s'", source->filename, ucv_string_get(import)); + else + uc_compiler_syntax_error(compiler, compiler->parser->prev.pos, + "Module %s has no default export", source->filename); + } + else if (slot > 0xffff) { + uc_compiler_syntax_error(compiler, compiler->parser->prev.pos, + "Too many module exports"); + } + else { + uc_compiler_emit_insn(compiler, 0, I_IMPORT); + uc_compiler_emit_u32(compiler, 0, slot | ((compiler->upvals.count - n_imports + i) << 16)); + } + } + } + + return true; +} + +static char * +uc_compiler_canonicalize_path(const char *path, const char *basedir) +{ + char *p, *resolved; + + if (*path == '/') + xasprintf(&p, "%s", path); + else if (basedir) + xasprintf(&p, "%s/%s", basedir, path); + else + xasprintf(&p, "./%s", path); + + resolved = realpath(p, NULL); + + free(p); + + return resolved; +} + +static char * +uc_compiler_expand_module_path(const char *name, const char *basedir, const char *template) +{ + int namelen, prefixlen; + char *path, *p; + + p = strchr(template, '*'); + + if (!p) + return NULL; + + prefixlen = p - template; + namelen = strlen(name); + + xasprintf(&path, "%.*s%.*s%s", prefixlen, template, namelen, name, p + 1); + + for (p = path + prefixlen; namelen > 0; namelen--, p++) + if (*p == '.') + *p = '/'; + + p = uc_compiler_canonicalize_path(path, basedir); + + free(path); + + return p; +} + +static char * +uc_compiler_resolve_module_path(uc_compiler_t *compiler, const char *name) +{ + uc_search_path_t *search = &compiler->parser->lex.config->module_search_path; + uc_source_t *source = uc_compiler_current_source(compiler); + char *path = NULL; + size_t i; + + if (strchr(name, '/')) + return uc_compiler_canonicalize_path(name, source->runpath); + + for (i = 0; i < search->count && !path; i++) + path = uc_compiler_expand_module_path(name, source->runpath, search->entries[i]); + + return path; +} + +static uc_source_t * +uc_compiler_acquire_source(uc_compiler_t *compiler, const char *path) +{ + size_t i; + + for (i = 0; i < compiler->program->sources.count; i++) + if (!strcmp(compiler->program->sources.entries[i]->filename, path)) + return uc_source_get(compiler->program->sources.entries[i]); + + return uc_source_new_file(path); +} + +static bool +uc_compiler_compile_module(uc_compiler_t *compiler, const char *name, uc_value_t *imports) +{ + uc_source_t *source; + char *path, *err; + bool res; + + if (!name) + return false; + + path = uc_compiler_resolve_module_path(compiler, name); + + if (path) { + source = uc_compiler_acquire_source(compiler, path); + + if (source) { + err = NULL; + res = uc_compiler_compile_module_source(compiler, source, imports, &err); + + if (!res) + uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, + "Unable to compile module '%s':\n%s", source->filename, err); + + free(err); + } + else { + uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, + "Unable to open module '%s': %s", + path, strerror(errno)); + + res = false; + } + } + else { + uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, + "Unable to resolve path for module '%s'", name); + + return false; + } + + uc_source_put(source); + free(path); + + return res; +} + +static void +uc_compiler_import_add(uc_compiler_t *compiler, uc_value_t *name) +{ + bool constant; + ssize_t slot; + + slot = uc_compiler_resolve_local(compiler, name, &constant); + + if (slot != -1) { + uc_compiler_syntax_error(compiler, compiler->parser->prev.pos, + "Import name '%s' is already declared as local variable", + ucv_string_get(name)); + + return; + } + + slot = uc_compiler_resolve_upval(compiler, name, &constant); + + if (slot != -1) { + uc_compiler_syntax_error(compiler, compiler->parser->prev.pos, + "Import name '%s' is already used", + ucv_string_get(name)); + + return; + } + + uc_compiler_add_upval(compiler, (2 << 14) + compiler->upvals.count, false, name, true); +} + +static void +uc_compiler_compile_importlist(uc_compiler_t *compiler, uc_value_t *namelist) { + uc_value_t *label, *name; + /* parse export symbols */ + do { + name = NULL; + label = NULL; + + if (uc_compiler_parse_match(compiler, TK_DEFAULT)) { + uc_compiler_parse_consume(compiler, TK_AS); + uc_compiler_parse_consume(compiler, TK_LABEL); + + label = ucv_get(compiler->parser->prev.uv); + } + else if (uc_compiler_parse_match(compiler, TK_STRING)) { + name = ucv_get(compiler->parser->prev.uv); + + uc_compiler_parse_consume(compiler, TK_AS); + uc_compiler_parse_consume(compiler, TK_LABEL); + + label = ucv_get(compiler->parser->prev.uv); + } + else if (uc_compiler_parse_match(compiler, TK_LABEL)) { + name = ucv_get(compiler->parser->prev.uv); + + if (uc_compiler_parse_match(compiler, TK_AS)) { + uc_compiler_parse_consume(compiler, TK_LABEL); + + label = ucv_get(compiler->parser->prev.uv); + } + else { + label = ucv_get(name); + } + } + else { + uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, + "Unexpected token\nExpecting Label, String or 'default'"); + } + + uc_compiler_import_add(compiler, label); + ucv_array_push(namelist, name); + ucv_put(label); + + if (uc_compiler_parse_match(compiler, TK_RBRACE)) + break; + } + while (uc_compiler_parse_match(compiler, TK_COMMA)); +} + +static void +uc_compiler_compile_import(uc_compiler_t *compiler) +{ + uc_value_t *namelist = ucv_array_new(NULL); + + if (compiler->scope_depth) { + uc_compiler_syntax_error(compiler, compiler->parser->prev.pos, + "Imports may only appear at top level"); + + return; + } + + /* import { ... } from */ + if (uc_compiler_parse_match(compiler, TK_LBRACE)) { + uc_compiler_compile_importlist(compiler, namelist); + uc_compiler_parse_consume(compiler, TK_FROM); + } + + /* import * as name from */ + else if (uc_compiler_parse_match(compiler, TK_MUL)) { + uc_compiler_parse_consume(compiler, TK_AS); + uc_compiler_parse_consume(compiler, TK_LABEL); + + uc_compiler_declare_local(compiler, compiler->parser->prev.uv, true); + uc_compiler_initialize_local(compiler); + ucv_array_push(namelist, ucv_boolean_new(true)); + + uc_compiler_parse_consume(compiler, TK_FROM); + } + + /* import defaultExport [, ... ] from */ + else if (uc_compiler_parse_match(compiler, TK_LABEL)) { + uc_compiler_import_add(compiler, compiler->parser->prev.uv); + ucv_array_push(namelist, NULL); + + /* import defaultExport, ... from */ + if (uc_compiler_parse_match(compiler, TK_COMMA)) { + /* import defaultExport, { ... } from */ + if (uc_compiler_parse_match(compiler, TK_LBRACE)) { + uc_compiler_compile_importlist(compiler, namelist); + } + + /* import defaultExport, * as name from */ + else if (uc_compiler_parse_match(compiler, TK_MUL)) { + uc_compiler_parse_consume(compiler, TK_AS); + uc_compiler_parse_consume(compiler, TK_LABEL); + + uc_compiler_declare_local(compiler, compiler->parser->prev.uv, true); + uc_compiler_initialize_local(compiler); + ucv_array_push(namelist, ucv_boolean_new(true)); + } + + /* error */ + else { + uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, + "Unexpected token\nExpecting '{' or '*'"); + } + } + + uc_compiler_parse_consume(compiler, TK_FROM); + } + + uc_compiler_parse_consume(compiler, TK_STRING); + + uc_compiler_compile_module(compiler, ucv_string_get(compiler->parser->prev.uv), namelist); + + uc_compiler_parse_consume(compiler, TK_SCOL); + + ucv_put(namelist); +} + +static void +uc_compiler_compile_declaration(uc_compiler_t *compiler) +{ if (uc_compiler_parse_match(compiler, TK_LOCAL)) uc_compiler_compile_local(compiler); else if (uc_compiler_parse_match(compiler, TK_CONST)) uc_compiler_compile_const(compiler); + else if (uc_compiler_parse_match(compiler, TK_EXPORT)) + uc_compiler_compile_export(compiler); + else if (uc_compiler_parse_match(compiler, TK_IMPORT)) + uc_compiler_compile_import(compiler); else uc_compiler_compile_statement(compiler); @@ -2942,7 +3456,7 @@ uc_compiler_compile_declaration(uc_compiler_t *compiler) static uc_program_t * -uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, char **errp) +uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, uc_program_t *prog, char **errp) { #ifdef NO_COMPILE if (errp) @@ -2953,13 +3467,21 @@ uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, char **er uc_exprstack_t expr = { .token = TK_EOF }; uc_parser_t parser = { .config = config }; uc_compiler_t compiler = { .parser = &parser, .exprstack = &expr }; - uc_program_t *prog; + uc_program_t *progptr; uc_function_t *fn; + const char *name; - prog = uc_program_new(); + if (!prog) { + progptr = uc_program_new(); + name = "main"; + } + else { + progptr = prog; + name = "module"; + } uc_lexer_init(&parser.lex, config, source); - uc_compiler_init(&compiler, "main", source, 0, prog, + uc_compiler_init(&compiler, name, source, 0, progptr, config && config->strict_declarations); uc_compiler_parse_advance(&compiler); @@ -2980,12 +3502,13 @@ uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, char **er uc_lexer_free(&parser.lex); if (!fn) { - ucv_put(&prog->header); + if (progptr != prog) + ucv_put(&progptr->header); return NULL; } - return prog; + return progptr; #endif } @@ -3011,9 +3534,12 @@ uc_compile(uc_parse_config_t *config, uc_source_t *source, char **errp) { uc_program_t *prog = NULL; + if (!config) + config = &uc_default_parse_config; + switch (uc_source_type_test(source)) { case UC_SOURCE_TYPE_PLAIN: - prog = uc_compile_from_source(config, source, errp); + prog = uc_compile_from_source(config, source, NULL, errp); break; case UC_SOURCE_TYPE_PRECOMPILED: diff --git a/include/ucode/program.h b/include/ucode/program.h index 4fb4a9b..c350fea 100644 --- a/include/ucode/program.h +++ b/include/ucode/program.h @@ -46,6 +46,8 @@ uc_program_put(uc_program_t *prog) { fn = fn##_tmp, \ fn##_tmp = (uc_function_t *)fn##_tmp->progref.prev) +#define uc_program_function_last(prog) (uc_function_t *)prog->functions.next + uc_function_t *uc_program_function_new(uc_program_t *, const char *, uc_source_t *, size_t); size_t uc_program_function_id(uc_program_t *, uc_function_t *); uc_function_t *uc_program_function_load(uc_program_t *, size_t); diff --git a/tests/custom/04_modules/01_export_variable_declaration b/tests/custom/04_modules/01_export_variable_declaration new file mode 100644 index 0000000..19a1c11 --- /dev/null +++ b/tests/custom/04_modules/01_export_variable_declaration @@ -0,0 +1,29 @@ +Variable declarations can be prepended with `export` to automatically +export each variable using the same name as the variable itself. + +Updates to the variable after the export are reflected properly in +the including scope. + +-- File test-var-decl.uc -- +export let a, b, c; +export let d = 4, e = 5, f = 6; +export const g = 7, h = 8, i = 9; + +a = 1; +b = 2; +c = 3; +-- End -- + +-- Testcase -- +import { a, b, c, d, e, f, g, h, i } from "./files/test-var-decl.uc"; + +print([ a, b, c, d, e, f, g, h, i ], "\n"); +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] +-- End -- diff --git a/tests/custom/04_modules/02_export_function_declaration b/tests/custom/04_modules/02_export_function_declaration new file mode 100644 index 0000000..4067da9 --- /dev/null +++ b/tests/custom/04_modules/02_export_function_declaration @@ -0,0 +1,22 @@ +A named function declaration can be prepended with `export` to +automatically export the function. + +-- File test-func-decl.uc -- +export function func() { + print("Hello, world!\n"); +}; +-- End -- + +-- Testcase -- +import { func } from "./files/test-func-decl.uc"; + +func(); +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +Hello, world! +-- End -- diff --git a/tests/custom/04_modules/03_export_list b/tests/custom/04_modules/03_export_list new file mode 100644 index 0000000..8f93f08 --- /dev/null +++ b/tests/custom/04_modules/03_export_list @@ -0,0 +1,27 @@ +Already declared local variables and functions may be exported using the +curly brace export list syntax. + +-- File test-var-decl.uc -- +let testvar = 123; +const testconst = "Test"; + +function testfunc() { + print("Hello, world!\n"); +} + +export { testvar, testconst, testfunc }; +-- End -- + +-- Testcase -- +import { testvar, testconst, testfunc } from "./files/test-var-decl.uc"; + +print([ testvar, testconst, testfunc ], "\n"); +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 123, "Test", "function testfunc() { ... }" ] +-- End -- diff --git a/tests/custom/04_modules/04_export_rename b/tests/custom/04_modules/04_export_rename new file mode 100644 index 0000000..49057fd --- /dev/null +++ b/tests/custom/04_modules/04_export_rename @@ -0,0 +1,28 @@ +By using the `as` keyword, exports may be renamed when using the export +list syntax. It is also possible to specify string aliases which are not +valid variable names, in this case a rename on import is mandatory. + +-- File test.uc -- +let testvar = 123; +const testconst = "Test"; + +function testfunc() { + print("Hello, world!\n"); +} + +export { testvar as modvar, testconst as 'define', testfunc as "module-function" }; +-- End -- + +-- Testcase -- +import { modvar, define, "module-function" as func } from "./files/test.uc"; + +print([ modvar, define, func ], "\n"); +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 123, "Test", "function testfunc() { ... }" ] +-- End -- diff --git a/tests/custom/04_modules/05_export_default b/tests/custom/04_modules/05_export_default new file mode 100644 index 0000000..a4c8a43 --- /dev/null +++ b/tests/custom/04_modules/05_export_default @@ -0,0 +1,38 @@ +The `export default` statement can be used to declare a default export +value for a module. The value for `export default` can be an arbitrary +expression, it must not refer to a local variable. + +When using the export list syntax, the alias "default" can be used to +designate the default export. + +-- File test-default-expr.uc -- +export default 7 * 21; +-- End -- + +-- File test-default-func.uc -- +export default function() { + return "Hello, world!"; +}; +-- End -- + +-- File test-default-alias.uc -- +let a = 1, b = 2, c = 3; + +export { a, b as default, c }; +-- End -- + +-- Testcase -- +import def1 from "./files/test-default-expr.uc"; +import def2 from "./files/test-default-func.uc"; +import def3 from "./files/test-default-alias.uc"; + +print([ def1, def2(), def3 ], "\n"); +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 147, "Hello, world!", 2 ] +-- End -- diff --git a/tests/custom/04_modules/06_export_errors b/tests/custom/04_modules/06_export_errors new file mode 100644 index 0000000..c02a547 --- /dev/null +++ b/tests/custom/04_modules/06_export_errors @@ -0,0 +1,89 @@ +Export statements are only allowed at the toplevel of a module. + +-- Testcase -- +export let x = 1; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Exports may only appear at top level of a module + + `export let x = 1;` + ^-- Near here + + +-- End -- + + +Export statements are not allowed within functions or nested blocks. + +-- Testcase -- +import "./files/test.uc"; +-- End -- + +-- File test.uc -- +{ + export let x = 1; +} +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Unable to compile module './files/test.uc': +Syntax error: Exports may only appear at top level of a module +In line 2, byte 2: + + ` export let x = 1;` + ^-- Near here + + + +In line 1, byte 25: + + `import "./files/test.uc";` + Near here --------------^ + + +-- End -- + + +Duplicate export names should result in an error. + +-- Testcase -- +import "./files/test-duplicate.uc"; +-- End -- + +-- File test-duplicate.uc -- +let x = 1, y = 2; + +export { x }; +export { y as x }; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Unable to compile module './files/test-duplicate.uc': +Syntax error: Duplicate export 'x' for module './files/test-duplicate.uc' +In line 4, byte 15: + + `export { y as x };` + Near here ----^ + + + +In line 1, byte 35: + + `import "./files/test-duplicate.uc";` + Near here ------------------------^ + + +-- End -- diff --git a/tests/custom/04_modules/07_import_default b/tests/custom/04_modules/07_import_default new file mode 100644 index 0000000..7190a22 --- /dev/null +++ b/tests/custom/04_modules/07_import_default @@ -0,0 +1,99 @@ +An `import` statement with a sole label will import the modules default +export and bind it to a local variable named after the label. + +-- Testcase -- +import defVal from "./files/test1.uc"; + +print(defVal, "\n"); +-- End -- + +-- File test1.uc -- +export default "This is the default export"; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +This is the default export +-- End -- + + +Attemping to import a default export from a module without default +export will raise an error. + +-- Testcase -- +import defVal from "./files/test2.uc"; + +print(defVal, "\n"); +-- End -- + +-- File test2.uc -- +export const x = "This is a non-default export"; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Module ./files/test2.uc has no default export +In line 1, byte 20: + + `import defVal from "./files/test2.uc";` + Near here ---------^ + + +-- End -- + + +In import statements usign the list syntax, the `default` keyword can be +used to refer to default exports. + +-- Testcase -- +import { default as defVal } from "./files/test3.uc"; + +print(defVal, "\n"); +-- End -- + +-- File test3.uc -- +export default "This is the default export"; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +This is the default export +-- End -- + + +When using the default keyword within the list syntax, the `as` keyword is +mandatory to assign a non-reserved keyword as name. + +-- Testcase -- +import { default } from "./files/test4.uc"; + +print(defVal, "\n"); +-- End -- + +-- File test4.uc -- +export default "This is the default export"; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Unexpected token +Expecting 'as' +In line 1, byte 18: + + `import { default } from "./files/test4.uc";` + Near here -------^ + + +-- End -- diff --git a/tests/custom/04_modules/08_import_list b/tests/custom/04_modules/08_import_list new file mode 100644 index 0000000..1a4f116 --- /dev/null +++ b/tests/custom/04_modules/08_import_list @@ -0,0 +1,105 @@ +An `import` statement followed by a curly brace enclosed list of names +will import the corresponding exports from the module. + +-- Testcase -- +import { a, b, c } from "./files/test1.uc"; + +print([ a, b, c ], "\n"); +-- End -- + +-- File test1.uc -- +export const a = 1, b = 2, c = 3; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 1, 2, 3 ] +-- End -- + + +Attemping to import a not exported name will raise an error. + +-- Testcase -- +import y from "./files/test2.uc"; + +print(y, "\n"); +-- End -- + +-- File test2.uc -- +export const x = "This is a test"; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Module ./files/test2.uc has no default export +In line 1, byte 15: + + `import y from "./files/test2.uc";` + Near here ----^ + + +-- End -- + + +Imports may be renamed to assign an alternative local name to the +exported module symbols. Renaming is also required for string export +names which are no valid variable identifiers. + +-- Testcase -- +import { a as var1, bool as var2, "my function" as var3 } from "./files/test3.uc"; + +print([ var1, var2, var3 ], "\n"); +-- End -- + +-- File test3.uc -- +const a = "A string"; + +let b = 123; + +function c() { + return "A function" +} + +export { + a, + b as bool, + c as "my function" +}; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ "A string", 123, "function c() { ... }" ] +-- End -- + + +A list expression may follow a default import expression in an `import` +statment. + +-- Testcase -- +import defVal, { a as x, b as y, c as z } from "./files/test4.uc"; + +print([defVal, x, y, z], "\n"); +-- End -- + +-- File test4.uc -- +export const a = 1, b = 2, c = 3; +export default a + b + c; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 6, 1, 2, 3 ] +-- End -- diff --git a/tests/custom/04_modules/09_import_wildcard b/tests/custom/04_modules/09_import_wildcard new file mode 100644 index 0000000..aa3dc82 --- /dev/null +++ b/tests/custom/04_modules/09_import_wildcard @@ -0,0 +1,73 @@ +By specifying `*` instead of a label or an import list after an `import` +keyword, all of the modules exports are aggregated into an object whose +keys and values refer to the exported names and their corresponding +values respectively. + +-- Testcase -- +import * as mod from "./files/test1.uc"; + +print(mod, "\n"); +-- End -- + +-- File test1.uc -- +export const a = 1, b = 2, c = 3; +export default a + b + c; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +{ "a": 1, "b": 2, "c": 3, "default": 6 } +-- End -- + + +When using the wildcard import syntax, assigning a name using the `as` +expression is mandatory. + +-- Testcase -- +import * from "./files/test2.uc"; +-- End -- + +-- File test2.uc -- +export const x = "This is a test"; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Unexpected token +Expecting 'as' +In line 1, byte 10: + + `import * from "./files/test2.uc";` + ^-- Near here + + +-- End -- + + +A wildcard expression may follow a default import expression in an `import` +statment. + +-- Testcase -- +import defVal, * as mod from "./files/test3.uc"; + +print([defVal, mod], "\n"); +-- End -- + +-- File test3.uc -- +export const a = 1, b = 2, c = 3; +export default a + b + c; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +[ 6, { "a": 1, "b": 2, "c": 3, "default": 6 } ] +-- End -- diff --git a/tests/custom/04_modules/10_import_none b/tests/custom/04_modules/10_import_none new file mode 100644 index 0000000..be30106 --- /dev/null +++ b/tests/custom/04_modules/10_import_none @@ -0,0 +1,18 @@ +An `import` statement may omit a default name, wildcard expression or name +lsit entirely to execute a module code solely for its side effects. + +-- Testcase -- +import "./files/test.uc"; +-- End -- + +-- File test.uc -- +print("This is the test module running\n"); +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +This is the test module running +-- End -- diff --git a/tests/custom/04_modules/11_import_many_exec_once b/tests/custom/04_modules/11_import_many_exec_once new file mode 100644 index 0000000..f469c7f --- /dev/null +++ b/tests/custom/04_modules/11_import_many_exec_once @@ -0,0 +1,28 @@ +When multiple imports refer to the same module, the module will only be +executed once. The equivalence of module paths is tested after canonicalizing +the requested path. + +-- Testcase -- +import { counter as counter1 } from "./files/test/example.uc"; +import { counter as counter2 } from "files/test/example.uc"; +import { counter as counter3 } from "test.example"; + +print([ counter1, counter2, counter3 ], "\n"); +-- End -- + +-- File test/example.uc -- +print("This is the test module running\n"); + +export let counter = 0; + +counter++; +-- End -- + +-- Args -- +-R -L ./files +-- End -- + +-- Expect stdout -- +This is the test module running +[ 1, 1, 1 ] +-- End -- diff --git a/tests/custom/04_modules/12_import_immutability b/tests/custom/04_modules/12_import_immutability new file mode 100644 index 0000000..37c0bc6 --- /dev/null +++ b/tests/custom/04_modules/12_import_immutability @@ -0,0 +1,52 @@ +Module imports are read-only bindings to the exported module variables. + +-- Testcase -- +import { a } from "./files/test.uc"; + +a = 2; +-- End -- + +-- File test.uc -- +export let a = 1; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Syntax error: Invalid assignment to constant 'a' +In line 3, byte 5: + + `a = 2;` + ^-- Near here + + +-- End -- + + +Aggregated module objects are read-only as well. + +-- Testcase -- +import * as mod from "./files/test.uc"; + +mod.a = 2; +-- End -- + +-- File test.uc -- +export let a = 1; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stderr -- +Type error: object value is immutable +In line 3, byte 9: + + `mod.a = 2;` + ^-- Near here + + +-- End -- diff --git a/tests/custom/04_modules/13_import_liveness b/tests/custom/04_modules/13_import_liveness new file mode 100644 index 0000000..ca7ff35 --- /dev/null +++ b/tests/custom/04_modules/13_import_liveness @@ -0,0 +1,29 @@ +Imported bindings to exported module variables are live, they'll reflect +every change to the exported variable values. + +-- Testcase -- +import { counter, count } from "./files/test.uc"; + +print(counter, "\n"); +count(); +print(counter, "\n"); +-- End -- + +-- File test.uc -- +let counter = 1; + +function count() { + counter++; +} + +export { counter, count }; +-- End -- + +-- Args -- +-R +-- End -- + +-- Expect stdout -- +1 +2 +-- End -- diff --git a/tests/custom/04_bugs/01_try_catch_stack_mismatch b/tests/custom/99_bugs/01_try_catch_stack_mismatch index f6e5a0a..f6e5a0a 100644 --- a/tests/custom/04_bugs/01_try_catch_stack_mismatch +++ b/tests/custom/99_bugs/01_try_catch_stack_mismatch diff --git a/tests/custom/04_bugs/02_array_pop_use_after_free b/tests/custom/99_bugs/02_array_pop_use_after_free index 22f63ff..22f63ff 100644 --- a/tests/custom/04_bugs/02_array_pop_use_after_free +++ b/tests/custom/99_bugs/02_array_pop_use_after_free diff --git a/tests/custom/04_bugs/03_switch_fallthrough_miscompilation b/tests/custom/99_bugs/03_switch_fallthrough_miscompilation index 3e6410e..3e6410e 100644 --- a/tests/custom/04_bugs/03_switch_fallthrough_miscompilation +++ b/tests/custom/99_bugs/03_switch_fallthrough_miscompilation diff --git a/tests/custom/04_bugs/04_property_set_abort b/tests/custom/99_bugs/04_property_set_abort index 8af477f..8af477f 100644 --- a/tests/custom/04_bugs/04_property_set_abort +++ b/tests/custom/99_bugs/04_property_set_abort diff --git a/tests/custom/04_bugs/05_duplicate_resource_type b/tests/custom/99_bugs/05_duplicate_resource_type index 6d8d8f5..6d8d8f5 100644 --- a/tests/custom/04_bugs/05_duplicate_resource_type +++ b/tests/custom/99_bugs/05_duplicate_resource_type diff --git a/tests/custom/04_bugs/06_lexer_escape_at_boundary b/tests/custom/99_bugs/06_lexer_escape_at_boundary index e80b0a1..e80b0a1 100644 --- a/tests/custom/04_bugs/06_lexer_escape_at_boundary +++ b/tests/custom/99_bugs/06_lexer_escape_at_boundary diff --git a/tests/custom/04_bugs/07_lexer_overlong_lines b/tests/custom/99_bugs/07_lexer_overlong_lines index d2dd3be..d2dd3be 100644 --- a/tests/custom/04_bugs/07_lexer_overlong_lines +++ b/tests/custom/99_bugs/07_lexer_overlong_lines diff --git a/tests/custom/04_bugs/08_compiler_arrow_fn_expressions b/tests/custom/99_bugs/08_compiler_arrow_fn_expressions index 5cd8960..5cd8960 100644 --- a/tests/custom/04_bugs/08_compiler_arrow_fn_expressions +++ b/tests/custom/99_bugs/08_compiler_arrow_fn_expressions diff --git a/tests/custom/04_bugs/09_reject_invalid_array_indexes b/tests/custom/99_bugs/09_reject_invalid_array_indexes index a7e5272..a7e5272 100644 --- a/tests/custom/04_bugs/09_reject_invalid_array_indexes +++ b/tests/custom/99_bugs/09_reject_invalid_array_indexes diff --git a/tests/custom/04_bugs/10_break_stack_mismatch b/tests/custom/99_bugs/10_break_stack_mismatch index c9c82c5..c9c82c5 100644 --- a/tests/custom/04_bugs/10_break_stack_mismatch +++ b/tests/custom/99_bugs/10_break_stack_mismatch diff --git a/tests/custom/04_bugs/11_switch_stack_mismatch b/tests/custom/99_bugs/11_switch_stack_mismatch index 0cf82f0..0cf82f0 100644 --- a/tests/custom/04_bugs/11_switch_stack_mismatch +++ b/tests/custom/99_bugs/11_switch_stack_mismatch diff --git a/tests/custom/04_bugs/12_altblock_stack_mismatch b/tests/custom/99_bugs/12_altblock_stack_mismatch index e350660..e350660 100644 --- a/tests/custom/04_bugs/12_altblock_stack_mismatch +++ b/tests/custom/99_bugs/12_altblock_stack_mismatch diff --git a/tests/custom/04_bugs/13_split_by_string_leading_trailing b/tests/custom/99_bugs/13_split_by_string_leading_trailing index 10a6062..10a6062 100644 --- a/tests/custom/04_bugs/13_split_by_string_leading_trailing +++ b/tests/custom/99_bugs/13_split_by_string_leading_trailing diff --git a/tests/custom/04_bugs/14_incomplete_expression_at_eof b/tests/custom/99_bugs/14_incomplete_expression_at_eof index 474e87c..474e87c 100644 --- a/tests/custom/04_bugs/14_incomplete_expression_at_eof +++ b/tests/custom/99_bugs/14_incomplete_expression_at_eof diff --git a/tests/custom/04_bugs/15_segfault_on_prefix_increment b/tests/custom/99_bugs/15_segfault_on_prefix_increment index 280b680..280b680 100644 --- a/tests/custom/04_bugs/15_segfault_on_prefix_increment +++ b/tests/custom/99_bugs/15_segfault_on_prefix_increment diff --git a/tests/custom/04_bugs/16_hang_on_regexp_at_eof b/tests/custom/99_bugs/16_hang_on_regexp_at_eof index d8702ca..d8702ca 100644 --- a/tests/custom/04_bugs/16_hang_on_regexp_at_eof +++ b/tests/custom/99_bugs/16_hang_on_regexp_at_eof diff --git a/tests/custom/04_bugs/17_hang_on_unclosed_expression_block b/tests/custom/99_bugs/17_hang_on_unclosed_expression_block index 29553ab..29553ab 100644 --- a/tests/custom/04_bugs/17_hang_on_unclosed_expression_block +++ b/tests/custom/99_bugs/17_hang_on_unclosed_expression_block diff --git a/tests/custom/04_bugs/18_hang_on_line_comments_at_eof b/tests/custom/99_bugs/18_hang_on_line_comments_at_eof index 5fc811e..5fc811e 100644 --- a/tests/custom/04_bugs/18_hang_on_line_comments_at_eof +++ b/tests/custom/99_bugs/18_hang_on_line_comments_at_eof diff --git a/tests/custom/04_bugs/19_truncated_format_string b/tests/custom/99_bugs/19_truncated_format_string index ead0fdb..ead0fdb 100644 --- a/tests/custom/04_bugs/19_truncated_format_string +++ b/tests/custom/99_bugs/19_truncated_format_string diff --git a/tests/custom/04_bugs/20_use_strict_stack_mismatch b/tests/custom/99_bugs/20_use_strict_stack_mismatch index 7294d23..7294d23 100644 --- a/tests/custom/04_bugs/20_use_strict_stack_mismatch +++ b/tests/custom/99_bugs/20_use_strict_stack_mismatch diff --git a/tests/custom/04_bugs/21_compiler_parenthesized_prop_keyword b/tests/custom/99_bugs/21_compiler_parenthesized_prop_keyword index 472b2af..472b2af 100644 --- a/tests/custom/04_bugs/21_compiler_parenthesized_prop_keyword +++ b/tests/custom/99_bugs/21_compiler_parenthesized_prop_keyword diff --git a/tests/custom/04_bugs/22_compiler_break_continue_scoping b/tests/custom/99_bugs/22_compiler_break_continue_scoping index 461b144..461b144 100644 --- a/tests/custom/04_bugs/22_compiler_break_continue_scoping +++ b/tests/custom/99_bugs/22_compiler_break_continue_scoping diff --git a/tests/custom/04_bugs/23_compiler_parenthesized_division b/tests/custom/99_bugs/23_compiler_parenthesized_division index a70703f..a70703f 100644 --- a/tests/custom/04_bugs/23_compiler_parenthesized_division +++ b/tests/custom/99_bugs/23_compiler_parenthesized_division diff --git a/tests/custom/04_bugs/24_compiler_local_for_loop_declaration b/tests/custom/99_bugs/24_compiler_local_for_loop_declaration index aafde55..aafde55 100644 --- a/tests/custom/04_bugs/24_compiler_local_for_loop_declaration +++ b/tests/custom/99_bugs/24_compiler_local_for_loop_declaration diff --git a/tests/custom/04_bugs/25_lexer_shifted_offsets b/tests/custom/99_bugs/25_lexer_shifted_offsets index db10121..db10121 100644 --- a/tests/custom/04_bugs/25_lexer_shifted_offsets +++ b/tests/custom/99_bugs/25_lexer_shifted_offsets diff --git a/tests/custom/04_bugs/26_compiler_jmp_to_zero b/tests/custom/99_bugs/26_compiler_jmp_to_zero index e7e0127..e7e0127 100644 --- a/tests/custom/04_bugs/26_compiler_jmp_to_zero +++ b/tests/custom/99_bugs/26_compiler_jmp_to_zero diff --git a/tests/custom/04_bugs/27_invalid_sparse_array_set b/tests/custom/99_bugs/27_invalid_sparse_array_set index 4c47039..4c47039 100644 --- a/tests/custom/04_bugs/27_invalid_sparse_array_set +++ b/tests/custom/99_bugs/27_invalid_sparse_array_set diff --git a/tests/custom/04_bugs/28_null_equality b/tests/custom/99_bugs/28_null_equality index b71a3b1..b71a3b1 100644 --- a/tests/custom/04_bugs/28_null_equality +++ b/tests/custom/99_bugs/28_null_equality diff --git a/tests/custom/04_bugs/29_empty_string_as_number b/tests/custom/99_bugs/29_empty_string_as_number index 51a93b2..51a93b2 100644 --- a/tests/custom/04_bugs/29_empty_string_as_number +++ b/tests/custom/99_bugs/29_empty_string_as_number diff --git a/tests/custom/04_bugs/30_nan_strict_equality b/tests/custom/99_bugs/30_nan_strict_equality index 4ec32e2..4ec32e2 100644 --- a/tests/custom/04_bugs/30_nan_strict_equality +++ b/tests/custom/99_bugs/30_nan_strict_equality diff --git a/tests/custom/04_bugs/31_vallist_8bit_shortstrings b/tests/custom/99_bugs/31_vallist_8bit_shortstrings index 9d02f42..9d02f42 100644 --- a/tests/custom/04_bugs/31_vallist_8bit_shortstrings +++ b/tests/custom/99_bugs/31_vallist_8bit_shortstrings diff --git a/tests/custom/04_bugs/32_compiler_switch_patchlist_corruption b/tests/custom/99_bugs/32_compiler_switch_patchlist_corruption index d256de5..d256de5 100644 --- a/tests/custom/04_bugs/32_compiler_switch_patchlist_corruption +++ b/tests/custom/99_bugs/32_compiler_switch_patchlist_corruption diff --git a/tests/custom/04_bugs/33_vm_computed_prop_decl_crash b/tests/custom/99_bugs/33_vm_computed_prop_decl_crash index 60b276c..60b276c 100644 --- a/tests/custom/04_bugs/33_vm_computed_prop_decl_crash +++ b/tests/custom/99_bugs/33_vm_computed_prop_decl_crash diff --git a/tests/custom/04_bugs/34_dirname_off_by_one b/tests/custom/99_bugs/34_dirname_off_by_one index 34ef7c7..34ef7c7 100644 --- a/tests/custom/04_bugs/34_dirname_off_by_one +++ b/tests/custom/99_bugs/34_dirname_off_by_one diff --git a/tests/custom/04_bugs/35_vm_callframe_double_free b/tests/custom/99_bugs/35_vm_callframe_double_free index bb816eb..bb816eb 100644 --- a/tests/custom/04_bugs/35_vm_callframe_double_free +++ b/tests/custom/99_bugs/35_vm_callframe_double_free diff --git a/tests/custom/04_bugs/36_vm_nested_call_return b/tests/custom/99_bugs/36_vm_nested_call_return index 6a52b78..6a52b78 100644 --- a/tests/custom/04_bugs/36_vm_nested_call_return +++ b/tests/custom/99_bugs/36_vm_nested_call_return diff --git a/tests/custom/04_bugs/37_compiler_unexpected_unary_op b/tests/custom/99_bugs/37_compiler_unexpected_unary_op index e652319..e652319 100644 --- a/tests/custom/04_bugs/37_compiler_unexpected_unary_op +++ b/tests/custom/99_bugs/37_compiler_unexpected_unary_op diff --git a/tests/custom/04_bugs/38_index_segfault b/tests/custom/99_bugs/38_index_segfault index e29b99f..e29b99f 100644 --- a/tests/custom/04_bugs/38_index_segfault +++ b/tests/custom/99_bugs/38_index_segfault diff --git a/tests/custom/04_bugs/39_compiler_switch_continue_mismatch b/tests/custom/99_bugs/39_compiler_switch_continue_mismatch index c9b9ec6..c9b9ec6 100644 --- a/tests/custom/04_bugs/39_compiler_switch_continue_mismatch +++ b/tests/custom/99_bugs/39_compiler_switch_continue_mismatch diff --git a/tests/custom/04_bugs/40_lexer_bug_on_lstrip_off b/tests/custom/99_bugs/40_lexer_bug_on_lstrip_off index dc4f8dd..dc4f8dd 100644 --- a/tests/custom/04_bugs/40_lexer_bug_on_lstrip_off +++ b/tests/custom/99_bugs/40_lexer_bug_on_lstrip_off |