Skip to content

Commit

Permalink
Merge pull request #98 from jow-/dynlink-support
Browse files Browse the repository at this point in the history
Add import statement support for dynamic extensions
  • Loading branch information
jow- authored Aug 6, 2022
2 parents f1e3938 + fcc49e6 commit d0ae910
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 22 deletions.
76 changes: 70 additions & 6 deletions compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,8 @@ uc_compiler_syntax_error(uc_compiler_t *compiler, size_t off, const char *fmt, .
off = uc_program_function_srcpos(compiler->function,
uc_compiler_current_chunk(compiler)->count);

if (off) {
byte = off;
line = uc_source_get_line(source, &byte);
}
byte = off;
line = uc_source_get_line(source, &byte);

va_start(ap, fmt);
len = xvasprintf(&s, fmt, ap);
Expand Down Expand Up @@ -3331,6 +3329,68 @@ uc_compiler_acquire_source(uc_compiler_t *compiler, const char *path)
return uc_source_new_file(path);
}

static bool
uc_compiler_compile_dynload(uc_compiler_t *compiler, const char *name, uc_value_t *imports)
{
uc_value_t *modname = ucv_string_new(name);
size_t i, n_imports;
uc_value_t *import;

for (i = 0, n_imports = 0; i < ucv_array_length(imports); i++) {
import = ucv_array_get(imports, i);

if (ucv_boolean_get(import)) {
uc_compiler_emit_insn(compiler, 0, I_DYNLOAD);
uc_compiler_emit_u32(compiler, 0, 0);
uc_compiler_emit_constant_index(compiler, 0, modname);
}
else {
n_imports++;
}
}

if (n_imports > 0) {
uc_compiler_emit_insn(compiler, 0, I_DYNLOAD);
uc_compiler_emit_u32(compiler, 0, n_imports | ((compiler->upvals.count - n_imports) << 16));
uc_compiler_emit_constant_index(compiler, 0, modname);

for (i = 0; i < ucv_array_length(imports); i++) {
import = ucv_get(ucv_array_get(imports, i));

if (!import)
import = ucv_string_new("default");

if (!ucv_boolean_get(import))
uc_compiler_emit_constant_index(compiler, 0, import);

ucv_put(import);
}
}

ucv_put(modname);

return true;
}

static bool
uc_compiler_is_dynlink_module(uc_compiler_t *compiler, const char *name, const char *path)
{
uc_search_path_t *dynlink_list = &compiler->parser->config->force_dynlink_list;
size_t i;
char *p;

for (i = 0; i < dynlink_list->count; i++)
if (!strcmp(dynlink_list->entries[i], name))
return true;

if (!path)
return false;

p = strrchr(path, '.');

return (p && !strcmp(p, ".so"));
}

static bool
uc_compiler_compile_module(uc_compiler_t *compiler, const char *name, uc_value_t *imports)
{
Expand All @@ -3343,7 +3403,10 @@ uc_compiler_compile_module(uc_compiler_t *compiler, const char *name, uc_value_t

path = uc_compiler_resolve_module_path(compiler, name);

if (path) {
if (uc_compiler_is_dynlink_module(compiler, name, path)) {
res = uc_compiler_compile_dynload(compiler, name, imports);
}
else if (path) {
source = uc_compiler_acquire_source(compiler, path);

if (source) {
Expand All @@ -3363,6 +3426,8 @@ uc_compiler_compile_module(uc_compiler_t *compiler, const char *name, uc_value_t

res = false;
}

uc_source_put(source);
}
else {
uc_compiler_syntax_error(compiler, compiler->parser->curr.pos,
Expand All @@ -3371,7 +3436,6 @@ uc_compiler_compile_module(uc_compiler_t *compiler, const char *name, uc_value_t
return false;
}

uc_source_put(source);
free(path);

return res;
Expand Down
1 change: 1 addition & 0 deletions include/ucode/lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ uc_cfn_ptr_t uc_stdlib_function(const char *name);
__hidden bool uc_source_context_format(uc_stringbuf_t *buf, uc_source_t *src, size_t off, bool compact);
__hidden bool uc_error_context_format(uc_stringbuf_t *buf, uc_source_t *src, uc_value_t *stacktrace, size_t off);

__hidden uc_value_t *uc_require_library(uc_vm_t *vm, uc_value_t *nameval, bool so_only);

/* vm helper */

Expand Down
1 change: 1 addition & 0 deletions include/ucode/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ typedef struct {
bool strict_declarations;
bool raw_mode;
uc_search_path_t module_search_path;
uc_search_path_t force_dynlink_list;
} uc_parse_config_t;

extern uc_parse_config_t uc_default_parse_config;
Expand Down
3 changes: 2 additions & 1 deletion include/ucode/vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ __insn(NEXTK) \
__insn(NEXTKV) \
__insn(DELETE) \
__insn(IMPORT) \
__insn(EXPORT)
__insn(EXPORT) \
__insn(DYNLOAD)


#undef __insn
Expand Down
21 changes: 13 additions & 8 deletions lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1674,7 +1674,7 @@ uc_require_ucode(uc_vm_t *vm, const char *path, uc_value_t *scope, uc_value_t **
}

static bool
uc_require_path(uc_vm_t *vm, const char *path_template, const char *name, uc_value_t **res)
uc_require_path(uc_vm_t *vm, const char *path_template, const char *name, uc_value_t **res, bool so_only)
{
uc_stringbuf_t *buf = xprintbuf_new();
const char *p, *q, *last;
Expand Down Expand Up @@ -1715,7 +1715,7 @@ uc_require_path(uc_vm_t *vm, const char *path_template, const char *name, uc_val

if (!strcmp(p + 1, ".so"))
rv = uc_require_so(vm, buf->buf, res);
else if (!strcmp(p + 1, ".uc"))
else if (!strcmp(p + 1, ".uc") && !so_only)
rv = uc_require_ucode(vm, buf->buf, NULL, res, true);

if (rv)
Expand All @@ -1727,18 +1727,17 @@ uc_require_path(uc_vm_t *vm, const char *path_template, const char *name, uc_val
return rv;
}

static uc_value_t *
uc_require(uc_vm_t *vm, size_t nargs)
uc_value_t *
uc_require_library(uc_vm_t *vm, uc_value_t *nameval, bool so_only)
{
uc_value_t *val = uc_fn_arg(0);
uc_value_t *search, *se, *res;
size_t arridx, arrlen;
const char *name;

if (ucv_type(val) != UC_STRING)
if (ucv_type(nameval) != UC_STRING)
return NULL;

name = ucv_string_get(val);
name = ucv_string_get(nameval);
search = ucv_property_get(uc_vm_scope_get(vm), "REQUIRE_SEARCH_PATH");

if (ucv_type(search) != UC_ARRAY) {
Expand All @@ -1754,7 +1753,7 @@ uc_require(uc_vm_t *vm, size_t nargs)
if (ucv_type(se) != UC_STRING)
continue;

if (uc_require_path(vm, ucv_string_get(se), name, &res))
if (uc_require_path(vm, ucv_string_get(se), name, &res, so_only))
return res;
}

Expand All @@ -1764,6 +1763,12 @@ uc_require(uc_vm_t *vm, size_t nargs)
return NULL;
}

static uc_value_t *
uc_require(uc_vm_t *vm, size_t nargs)
{
return uc_require_library(vm, uc_fn_arg(0), false);
}

static uc_value_t *
uc_iptoarr(uc_vm_t *vm, size_t nargs)
{
Expand Down
14 changes: 11 additions & 3 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ print_usage(const char *app)
"-c[flag,flag,...]\n"
" Compile the given source file(s) to bytecode instead of executing them.\n"
" Supported flags: no-interp (omit interpreter line), interp=... (over-\n"
" ride interpreter line with ...)\n\n"
" ride interpreter line with ...), dynlink=... (force import from ... to\n"
" be treated as shared extensions loaded at runtime).\n\n"

"-o path\n"
" Output file path when compiling. If omitted, the compiled byte code\n"
Expand Down Expand Up @@ -204,7 +205,7 @@ parse_template_modeflags(char *opt, uc_parse_config_t *config)
}

static void
parse_compile_flags(char *opt, char **interp)
parse_compile_flags(char *opt, char **interp, uc_search_path_t *dynlink_list)
{
char *p, *k, *v;

Expand All @@ -230,6 +231,12 @@ parse_compile_flags(char *opt, char **interp)
else
*interp = v;
}
else if (!strcmp(k, "dynlink")) {
if (!v)
fprintf(stderr, "Compile flag \"%s\" requires a value, ignoring\n", k);
else
uc_vector_push(dynlink_list, v);
}
else {
fprintf(stderr, "Unrecognized -c flag \"%s\", ignoring\n", k);
}
Expand Down Expand Up @@ -577,7 +584,7 @@ main(int argc, char **argv)

case 'c':
outfile = "./uc.out";
parse_compile_flags(optarg, &interp);
parse_compile_flags(optarg, &interp, &config.force_dynlink_list);
break;

case 's':
Expand Down Expand Up @@ -640,6 +647,7 @@ main(int argc, char **argv)

out:
uc_search_path_free(&config.module_search_path);
uc_vector_clear(&config.force_dynlink_list);

uc_source_put(source);

Expand Down
3 changes: 2 additions & 1 deletion tests/cram/test_basic.t
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ check that ucode provides exepected help:
-c[flag,flag,...]
Compile the given source file(s) to bytecode instead of executing them.
Supported flags: no-interp (omit interpreter line), interp=... (over-
ride interpreter line with ...)
ride interpreter line with ...), dynlink=... (force import from ... to
be treated as shared extensions loaded at runtime).

-o path
Output file path when compiling. If omitted, the compiled byte code
Expand Down
1 change: 1 addition & 0 deletions tests/custom/04_modules/06_export_errors
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export let x = 1;

-- Expect stderr --
Syntax error: Exports may only appear at top level of a module
In line 1, byte 1:

`export let x = 1;`
^-- Near here
Expand Down
Loading

0 comments on commit d0ae910

Please sign in to comment.