summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--compiler.c151
-rw-r--r--include/ucode/program.h2
-rw-r--r--include/ucode/types.h8
-rw-r--r--program.c26
-rw-r--r--tests/custom/04_modules/06_export_errors26
-rw-r--r--tests/custom/04_modules/07_import_default2
-rw-r--r--tests/custom/04_modules/08_import_list2
-rw-r--r--tests/custom/04_modules/12_import_immutability2
-rw-r--r--tests/custom/04_modules/14_circular_imports43
-rw-r--r--tests/custom/04_modules/15_complex_imports151
-rw-r--r--vm.c3
11 files changed, 348 insertions, 68 deletions
diff --git a/compiler.c b/compiler.c
index 4878be1..0042c15 100644
--- a/compiler.c
+++ b/compiler.c
@@ -169,10 +169,11 @@ uc_compiler_current_source(uc_compiler_t *compiler)
__attribute__((format(printf, 3, 0))) static void
uc_compiler_syntax_error(uc_compiler_t *compiler, size_t off, const char *fmt, ...)
{
+ uc_source_t *source = uc_compiler_current_source(compiler);
uc_stringbuf_t *buf = compiler->parser->error;
size_t line = 0, byte = 0, len = 0;
+ char *s, *p, *nl;
va_list ap;
- char *s;
if (compiler->parser->synchronizing)
return;
@@ -188,7 +189,7 @@ uc_compiler_syntax_error(uc_compiler_t *compiler, size_t off, const char *fmt, .
if (off) {
byte = off;
- line = uc_source_get_line(uc_compiler_current_source(compiler), &byte);
+ line = uc_source_get_line(source, &byte);
}
va_start(ap, fmt);
@@ -196,15 +197,53 @@ uc_compiler_syntax_error(uc_compiler_t *compiler, size_t off, const char *fmt, .
va_end(ap);
ucv_stringbuf_append(buf, "Syntax error: ");
- ucv_stringbuf_addstr(buf, s, len);
- ucv_stringbuf_append(buf, "\n");
+
+ p = strstr(s, "\nSyntax error: ");
+
+ if (!p) {
+ ucv_stringbuf_addstr(buf, s, len);
+ ucv_stringbuf_append(buf, "\n");
+ }
+ else {
+ ucv_stringbuf_printf(buf, "%.*s\n\n", (int)(p - s), s);
+
+ while (len > 0 && s[len-1] == '\n')
+ s[--len] = 0;
+
+ for (p++, nl = strchr(p, '\n'); p != NULL;
+ p = nl ? nl + 1 : NULL, nl = p ? strchr(p, '\n') : NULL)
+ {
+ if (!nl)
+ ucv_stringbuf_printf(buf, " | %s", p);
+ else if (nl != p)
+ ucv_stringbuf_printf(buf, " | %.*s\n", (int)(nl - p), p);
+ else
+ ucv_stringbuf_append(buf, " |\n");
+ }
+
+ ucv_stringbuf_append(buf, "\n\n");
+ }
free(s);
- if (line)
- ucv_stringbuf_printf(buf, "In line %zu, byte %zu:\n", line, byte);
+ if (line) {
+ ucv_stringbuf_append(buf, "In ");
+
+ if (compiler->program->sources.count > 1) {
+ len = strlen(source->filename);
+
+ if (len > 48)
+ ucv_stringbuf_printf(buf, "...%s", source->filename + len - 45);
+ else
+ ucv_stringbuf_addstr(buf, source->filename, len);
+
+ ucv_stringbuf_append(buf, ", ");
+ }
+
+ ucv_stringbuf_printf(buf, "line %zu, byte %zu:\n", line, byte);
+ }
- if (uc_error_context_format(buf, uc_compiler_current_source(compiler), NULL, off))
+ if (uc_error_context_format(buf, source, NULL, off))
ucv_stringbuf_append(buf, "\n\n");
}
@@ -593,6 +632,45 @@ uc_compiler_set_jmpaddr(uc_compiler_t *compiler, size_t off, uint32_t dest)
chunk->entries[off + 4] = addr % 0x100;
}
+static void
+uc_compiler_inc_exportnum(uc_compiler_t *compiler)
+{
+ uc_source_t *root = uc_program_function_source(uc_program_entry(compiler->program));
+ uint64_t u;
+
+ if (root->exports.count == 0) {
+ uc_vector_push(&root->exports, ucv_uint64_new(1));
+ }
+ else {
+ u = ucv_uint64_get(root->exports.entries[0]);
+
+ ucv_put(root->exports.entries[0]);
+
+ root->exports.entries[0] = ucv_uint64_new(u + 1);
+ }
+}
+
+static size_t
+uc_compiler_get_exportnum(uc_compiler_t *compiler)
+{
+ uc_source_t *root = uc_program_function_source(uc_program_entry(compiler->program));
+
+ return root->exports.count ? ucv_uint64_get(root->exports.entries[0]) : 0;
+}
+
+static void
+uc_compiler_emit_exports(uc_compiler_t *compiler) {
+ size_t i;
+
+ if (!compiler->patchlist || compiler->patchlist->token != TK_EXPORT)
+ return;
+
+ for (i = 0; i < compiler->patchlist->count; i++) {
+ uc_compiler_emit_insn(compiler, 0, I_EXPORT);
+ uc_compiler_emit_u32(compiler, 0, compiler->patchlist->entries[i]);
+ }
+}
+
static uc_function_t *
uc_compiler_finish(uc_compiler_t *compiler)
{
@@ -601,6 +679,9 @@ uc_compiler_finish(uc_compiler_t *compiler)
uc_upvals_t *upvals = &compiler->upvals;
size_t i;
+ if (compiler->function->module)
+ uc_compiler_emit_exports(compiler);
+
uc_compiler_emit_insn(compiler, 0, I_LNULL);
uc_compiler_emit_insn(compiler, 0, I_RETURN);
@@ -2782,7 +2863,7 @@ uc_compiler_compile_control(uc_compiler_t *compiler)
p = p->parent;
}
- if (!p) {
+ if (!p || p->token == TK_EXPORT) {
uc_compiler_syntax_error(compiler, pos,
(type == TK_BREAK)
? "break must be inside loop or switch"
@@ -2809,6 +2890,12 @@ uc_compiler_compile_return(uc_compiler_t *compiler)
uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
size_t off = chunk->count;
+ if (compiler->function->module) {
+ uc_compiler_syntax_error(compiler, 0, "return must be inside function body");
+
+ return;
+ }
+
uc_compiler_compile_expstmt(compiler);
/* if we compiled an empty expression statement (`;`), load implicit null */
@@ -2948,8 +3035,8 @@ uc_compiler_export_add(uc_compiler_t *compiler, uc_value_t *name, ssize_t slot)
"Duplicate default export for module '%s'", source->filename);
}
else {
- uc_compiler_emit_insn(compiler, 0, I_EXPORT);
- uc_compiler_emit_u32(compiler, 0, slot);
+ uc_vector_push(compiler->patchlist, slot);
+ uc_compiler_inc_exportnum(compiler);
}
}
@@ -3009,7 +3096,7 @@ uc_compiler_compile_export(uc_compiler_t *compiler)
uc_value_t *name;
ssize_t slot;
- if (compiler->program->sources.count == 1 || compiler->scope_depth) {
+ if (!compiler->function->module || compiler->scope_depth) {
uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
"Exports may only appear at top level of a module");
@@ -3072,6 +3159,10 @@ uc_compiler_compile_module_source(uc_compiler_t *compiler, uc_source_t *source,
uc_program_function_foreach(compiler->program, fn) {
if (uc_program_function_source(fn) == source) {
+ if (source->exports.offset == (size_t)-1)
+ uc_compiler_syntax_error(compiler, compiler->parser->prev.pos,
+ "Circular dependency");
+
loaded = true;
break;
}
@@ -3081,9 +3172,14 @@ uc_compiler_compile_module_source(uc_compiler_t *compiler, uc_source_t *source,
load_idx = uc_program_function_id(compiler->program,
uc_program_function_last(compiler->program)) + 1;
+ source->exports.offset = (size_t)-1;
+
if (!uc_compile_from_source(&config, source, compiler->program, errp))
return false;
+ source->exports.offset = uc_compiler_get_exportnum(compiler) - source->exports.count;
+ uc_compiler_current_source(compiler)->exports.offset += source->exports.count;
+
/* emit load, call & pop instructions */
uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_CLFN);
uc_compiler_emit_u32(compiler, 0, load_idx);
@@ -3097,20 +3193,17 @@ uc_compiler_compile_module_source(uc_compiler_t *compiler, uc_source_t *source,
/* 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) {
+ if (source->exports.offset > 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_insn(compiler, compiler->parser->prev.pos, 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);
+ uc_compiler_emit_u16(compiler, 0, source->exports.offset);
/* ... and constant indexes for all exported names */
for (load_idx = 0; load_idx < source->exports.count; load_idx++) {
@@ -3138,7 +3231,7 @@ uc_compiler_compile_module_source(uc_compiler_t *compiler, uc_source_t *source,
import = ucv_array_get(imports, i);
if (!ucv_boolean_get(import)) {
- slot = uc_program_export_lookup(compiler->program, source, import);
+ slot = uc_source_export_lookup(source, import);
if (slot == -1) {
if (import)
@@ -3153,8 +3246,9 @@ uc_compiler_compile_module_source(uc_compiler_t *compiler, uc_source_t *source,
"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));
+ uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_IMPORT);
+ uc_compiler_emit_u32(compiler, 0,
+ (source->exports.offset + slot) | ((compiler->upvals.count - n_imports + i) << 16));
}
}
}
@@ -3163,14 +3257,14 @@ uc_compiler_compile_module_source(uc_compiler_t *compiler, uc_source_t *source,
}
static char *
-uc_compiler_canonicalize_path(const char *path, const char *basedir)
+uc_compiler_canonicalize_path(const char *path, const char *runpath)
{
char *p, *resolved;
if (*path == '/')
xasprintf(&p, "%s", path);
- else if (basedir)
- xasprintf(&p, "%s/%s", basedir, path);
+ else if (runpath && (p = strrchr(runpath, '/')) != NULL)
+ xasprintf(&p, "%.*s/%s", (int)(p - runpath), runpath, path);
else
xasprintf(&p, "./%s", path);
@@ -3182,7 +3276,7 @@ uc_compiler_canonicalize_path(const char *path, const char *basedir)
}
static char *
-uc_compiler_expand_module_path(const char *name, const char *basedir, const char *template)
+uc_compiler_expand_module_path(const char *name, const char *runpath, const char *template)
{
int namelen, prefixlen;
char *path, *p;
@@ -3201,7 +3295,7 @@ uc_compiler_expand_module_path(const char *name, const char *basedir, const char
if (*p == '.')
*p = '/';
- p = uc_compiler_canonicalize_path(path, basedir);
+ p = uc_compiler_canonicalize_path(path, runpath);
free(path);
@@ -3464,6 +3558,7 @@ uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, uc_progra
return NULL;
#else
+ uc_patchlist_t exports = { .token = TK_EXPORT };
uc_exprstack_t expr = { .token = TK_EOF };
uc_parser_t parser = { .config = config };
uc_compiler_t compiler = { .parser = &parser, .exprstack = &expr };
@@ -3484,6 +3579,11 @@ uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, uc_progra
uc_compiler_init(&compiler, name, source, 0, progptr,
config && config->strict_declarations);
+ if (progptr == prog) {
+ compiler.patchlist = &exports;
+ compiler.function->module = true;
+ }
+
uc_compiler_parse_advance(&compiler);
while (!uc_compiler_parse_match(&compiler, TK_EOF))
@@ -3500,6 +3600,7 @@ uc_compile_from_source(uc_parse_config_t *config, uc_source_t *source, uc_progra
}
uc_lexer_free(&parser.lex);
+ uc_vector_clear(&exports);
if (!fn) {
if (progptr != prog)
diff --git a/include/ucode/program.h b/include/ucode/program.h
index 9014ae4..19c8bdf 100644
--- a/include/ucode/program.h
+++ b/include/ucode/program.h
@@ -55,8 +55,6 @@ __hidden uc_source_t *uc_program_function_source(uc_function_t *);
__hidden size_t uc_program_function_srcpos(uc_function_t *, size_t);
__hidden void uc_program_function_free(uc_function_t *);
-__hidden ssize_t uc_program_export_lookup(uc_program_t *, uc_source_t *, uc_value_t *);
-
__hidden uc_value_t *uc_program_get_constant(uc_program_t *, size_t);
__hidden ssize_t uc_program_add_constant(uc_program_t *, uc_value_t *);
diff --git a/include/ucode/types.h b/include/ucode/types.h
index 0b63501..636d6e4 100644
--- a/include/ucode/types.h
+++ b/include/ucode/types.h
@@ -65,7 +65,6 @@ typedef struct {
/* Source buffer defintions */
uc_declare_vector(uc_lineinfo_t, uint8_t);
-uc_declare_vector(uc_exports_t, uc_value_t *);
typedef struct {
uc_value_t header;
@@ -73,7 +72,10 @@ typedef struct {
FILE *fp;
size_t off;
uc_lineinfo_t lineinfo;
- uc_exports_t exports;
+ struct {
+ size_t count, offset;
+ uc_value_t **entries;
+ } exports;
} uc_source_t;
@@ -112,7 +114,7 @@ typedef struct uc_weakref {
typedef struct uc_function {
uc_weakref_t progref;
- bool arrow, vararg, strict;
+ bool arrow, vararg, strict, module;
size_t nargs;
size_t nupvals;
size_t srcidx;
diff --git a/program.c b/program.c
index f08e0cd..f347a35 100644
--- a/program.c
+++ b/program.c
@@ -228,6 +228,7 @@ enum {
UC_FUNCTION_F_HAS_NAME = (1 << 4),
UC_FUNCTION_F_HAS_VARDBG = (1 << 5),
UC_FUNCTION_F_HAS_OFFSETDBG = (1 << 6),
+ UC_FUNCTION_F_IS_MODULE = (1 << 7),
};
static void
@@ -288,6 +289,9 @@ write_function(uc_function_t *func, FILE *file, bool debug)
if (func->strict)
flags |= UC_FUNCTION_F_IS_STRICT;
+ if (func->module)
+ flags |= UC_FUNCTION_F_IS_MODULE;
+
if (func->chunk.ehranges.count)
flags |= UC_FUNCTION_F_HAS_EXCEPTIONS;
@@ -780,6 +784,7 @@ read_function(FILE *file, uc_program_t *program, size_t idx, char **errp)
func->arrow = (flags & UC_FUNCTION_F_IS_ARROW);
func->vararg = (flags & UC_FUNCTION_F_IS_VARARG);
func->strict = (flags & UC_FUNCTION_F_IS_STRICT);
+ func->module = (flags & UC_FUNCTION_F_IS_MODULE);
func->nargs = nargs;
func->nupvals = nupvals;
@@ -846,24 +851,3 @@ uc_program_entry(uc_program_t *program)
return (uc_function_t *)program->functions.prev;
}
-
-ssize_t
-uc_program_export_lookup(uc_program_t *program, uc_source_t *source, uc_value_t *name)
-{
- size_t i, off;
- ssize_t slot;
-
- for (i = 0, off = 0; i < program->sources.count; i++) {
- if (program->sources.entries[i] != source) {
- off += program->sources.entries[i]->exports.count;
- continue;
- }
-
- slot = uc_source_export_lookup(source, name);
-
- if (slot > -1)
- return off + slot;
- }
-
- return -1;
-}
diff --git a/tests/custom/04_modules/06_export_errors b/tests/custom/04_modules/06_export_errors
index c02a547..5c9f676 100644
--- a/tests/custom/04_modules/06_export_errors
+++ b/tests/custom/04_modules/06_export_errors
@@ -36,15 +36,14 @@ import "./files/test.uc";
-- 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
-
+ | Syntax error: Exports may only appear at top level of a module
+ | In ./files/test.uc, line 2, byte 2:
+ |
+ | ` export let x = 1;`
+ | ^-- Near here
-In line 1, byte 25:
+In [stdin], line 1, byte 25:
`import "./files/test.uc";`
Near here --------------^
@@ -72,15 +71,14 @@ export { y as x };
-- 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 ----^
-
+ | Syntax error: Duplicate export 'x' for module './files/test-duplicate.uc'
+ | In ./files/test-duplicate.uc, line 4, byte 15:
+ |
+ | `export { y as x };`
+ | Near here ----^
-In line 1, byte 35:
+In [stdin], line 1, byte 35:
`import "./files/test-duplicate.uc";`
Near here ------------------------^
diff --git a/tests/custom/04_modules/07_import_default b/tests/custom/04_modules/07_import_default
index 7190a22..d9d08b5 100644
--- a/tests/custom/04_modules/07_import_default
+++ b/tests/custom/04_modules/07_import_default
@@ -39,7 +39,7 @@ export const x = "This is a non-default export";
-- Expect stderr --
Syntax error: Module ./files/test2.uc has no default export
-In line 1, byte 20:
+In [stdin], line 1, byte 20:
`import defVal from "./files/test2.uc";`
Near here ---------^
diff --git a/tests/custom/04_modules/08_import_list b/tests/custom/04_modules/08_import_list
index 1a4f116..b55ddec 100644
--- a/tests/custom/04_modules/08_import_list
+++ b/tests/custom/04_modules/08_import_list
@@ -38,7 +38,7 @@ export const x = "This is a test";
-- Expect stderr --
Syntax error: Module ./files/test2.uc has no default export
-In line 1, byte 15:
+In [stdin], line 1, byte 15:
`import y from "./files/test2.uc";`
Near here ----^
diff --git a/tests/custom/04_modules/12_import_immutability b/tests/custom/04_modules/12_import_immutability
index 37c0bc6..48a7fe2 100644
--- a/tests/custom/04_modules/12_import_immutability
+++ b/tests/custom/04_modules/12_import_immutability
@@ -16,7 +16,7 @@ export let a = 1;
-- Expect stderr --
Syntax error: Invalid assignment to constant 'a'
-In line 3, byte 5:
+In [stdin], line 3, byte 5:
`a = 2;`
^-- Near here
diff --git a/tests/custom/04_modules/14_circular_imports b/tests/custom/04_modules/14_circular_imports
new file mode 100644
index 0000000..0b6070a
--- /dev/null
+++ b/tests/custom/04_modules/14_circular_imports
@@ -0,0 +1,43 @@
+Circular imports are not possible and will lead to a compilation error.
+
+-- Testcase --
+import a_val from "./files/a.uc";
+-- End --
+
+-- File a.uc --
+import b_val from "./b.uc";
+export default "a";
+-- End --
+
+-- File b.uc --
+import a_val from "./a.uc";
+export default "b";
+-- End --
+
+-- Args --
+-R
+-- End --
+
+-- Expect stderr --
+Syntax error: Unable to compile module './files/a.uc':
+
+ | Syntax error: Unable to compile module './files/b.uc':
+ |
+ | | Syntax error: Circular dependency
+ | | In ./files/b.uc, line 1, byte 19:
+ | |
+ | | `import a_val from "./a.uc";`
+ | | Near here --------^
+ |
+ | In ./files/a.uc, line 1, byte 27:
+ |
+ | `import b_val from "./b.uc";`
+ | Near here ----------------^
+
+In [stdin], line 1, byte 33:
+
+ `import a_val from "./files/a.uc";`
+ Near here ----------------------^
+
+
+-- End --
diff --git a/tests/custom/04_modules/15_complex_imports b/tests/custom/04_modules/15_complex_imports
new file mode 100644
index 0000000..f4dd588
--- /dev/null
+++ b/tests/custom/04_modules/15_complex_imports
@@ -0,0 +1,151 @@
+This testcase implements a somewhat complex dependency chain to stress
+test the compiler module resolving.
+
+The dependency tree is:
+
+root
+ + mod1
+ + mod4
+ + mod8
+ + mod2
+ + mod4
+ + mod6
+ + mod8
+ + mod9
+ + mod3
+ + mod4
+ + mod6
+ + mod4
+ + mod5
+ + mod1
+ + mod4
+ + mod8
+ + mod2
+ + mod4
+ + mod6
+ + mod8
+ + mod9
+ + mod4
+ + mod6
+ + mod8
+ + mod9
+ + mod4
+ + mod6
+ + mod6
+ + mod7
+ + mod5
+ + mod1
+ + mod4
+ + mod8
+ + mod2
+ + mod4
+ + mod6
+ + mod8
+ + mod9
+ + mod4
+ + mod6
+ + mod8
+ + mod9
+ + mod4
+ + mod6
+ + mod6
+ + mod8
+
+-- Testcase --
+import mod1 from 'mod1';
+import mod2 from 'mod2';
+import mod3 from 'mod3';
+import mod4 from 'mod4';
+import mod5 from 'mod5';
+import mod6 from 'mod6';
+import mod7 from 'mod7';
+import mod8 from 'mod8';
+
+print("root: ", [ mod1, mod2, mod3, mod4, mod5, mod6, mod7, mod8 ], "\n");
+-- End --
+
+-- File mod1.uc --
+import mod4 from 'mod4';
+import mod8 from 'mod8';
+
+print("mod1: ", [ mod4, mod8 ], "\n");
+
+export default 'mod1';
+-- End --
+
+-- File mod2.uc --
+import mod9 from 'mod9';
+import mod4 from 'mod4';
+import mod8 from 'mod8';
+import mod6 from 'mod6';
+
+print("mod2: ", [ mod4, mod6, mod8, mod9 ], "\n");
+
+export default 'mod2';
+-- End --
+
+-- File mod3.uc --
+import mod4 from 'mod4';
+import mod6 from 'mod6';
+
+print("mod3: ", [ mod4, mod6 ], "\n");
+
+export default 'mod3';
+-- End --
+
+-- File mod4.uc --
+export default 'mod4';
+-- End --
+
+-- File mod5.uc --
+import mod1 from 'mod1';
+import mod4 from 'mod4';
+import mod2 from 'mod2';
+import mod9 from 'mod9';
+import mod8 from 'mod8';
+import mod6 from 'mod6';
+
+print("mod5: ", [ mod1, mod2, mod4, mod6, mod8, mod9 ], "\n");
+
+export default 'mod5';
+-- End --
+
+-- File mod6.uc --
+export default 'mod6';
+-- End --
+
+-- File mod7.uc --
+import mod6 from 'mod6';
+import mod5 from 'mod5';
+
+print("mod7: ", [ mod5, mod6 ], "\n");
+
+export default 'mod7';
+-- End --
+
+-- File mod8.uc --
+export default 'mod8';
+-- End --
+
+-- File mod9.uc --
+import mod4 from 'mod4';
+import mod6 from 'mod6';
+
+print("mod9: ", [ mod4, mod6 ], "\n");
+
+export default 'mod9';
+-- End --
+
+-- Args --
+-R -L files/
+-- End --
+
+-- Expect stdout --
+mod1: [ "mod4", "mod8" ]
+mod9: [ "mod4", "mod6" ]
+mod2: [ "mod4", "mod6", "mod8", "mod9" ]
+mod3: [ "mod4", "mod6" ]
+mod5: [ "mod1", "mod2", "mod4", "mod6", "mod8", "mod9" ]
+mod7: [ "mod5", "mod6" ]
+root: [ "mod1", "mod2", "mod3", "mod4", "mod5", "mod6", "mod7", "mod8" ]
+-- End --
diff --git a/vm.c b/vm.c
index ad5cd44..3a6e39e 100644
--- a/vm.c
+++ b/vm.c
@@ -1179,6 +1179,9 @@ uc_vm_insn_load_closure(uc_vm_t *vm, uc_vm_insn_t insn)
uc_vm_stack_push(vm, &closure->header);
+ if (function->module)
+ return;
+
for (i = 0; i < function->nupvals; i++) {
uv = (
frame->ip[0] * 0x1000000 +