summaryrefslogtreecommitdiffhomepage
path: root/lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib.c')
-rw-r--r--lib.c262
1 files changed, 213 insertions, 49 deletions
diff --git a/lib.c b/lib.c
index fcdd17b..37563c2 100644
--- a/lib.c
+++ b/lib.c
@@ -1638,71 +1638,44 @@ uc_require_so(uc_vm_t *vm, const char *path, uc_value_t **res)
return true;
}
+static uc_value_t *
+uc_loadfile(uc_vm_t *vm, size_t nargs);
+
+static uc_value_t *
+uc_callfunc(uc_vm_t *vm, size_t nargs);
+
static bool
uc_require_ucode(uc_vm_t *vm, const char *path, uc_value_t *scope, uc_value_t **res, bool raw_mode)
{
- uc_parse_config_t config = { 0 };
- uc_exception_type_t extype;
- uc_program_t *program;
- uc_value_t *prev_scope;
+ uc_parse_config_t config = *vm->config, *prev_config = vm->config;
uc_value_t *closure;
- uc_source_t *source;
struct stat st;
- bool prev_mode;
- char *err;
if (stat(path, &st))
return false;
- source = uc_source_new_file(path);
+ config.raw_mode = raw_mode;
+ vm->config = &config;
- if (!source) {
- uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
- "Unable to open file '%s': %s", path, strerror(errno));
+ uc_vm_stack_push(vm, ucv_string_new(path));
- return true;
- }
-
- if (!vm->config)
- vm->config = &config;
-
- prev_mode = vm->config->raw_mode;
- vm->config->raw_mode = raw_mode;
-
- program = uc_compile(vm->config, source, &err);
+ closure = uc_loadfile(vm, 1);
- uc_source_put(source);
-
- if (!program) {
- uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
- "Unable to compile module '%s':\n%s", path, err);
+ ucv_put(uc_vm_stack_pop(vm));
- free(err);
+ if (closure) {
+ uc_vm_stack_push(vm, closure);
+ uc_vm_stack_push(vm, NULL);
+ uc_vm_stack_push(vm, scope);
- vm->config->raw_mode = prev_mode;
+ *res = uc_callfunc(vm, 3);
- return true;
- }
-
- closure = ucv_closure_new(vm, uc_program_entry(program), false);
-
- uc_vm_stack_push(vm, closure);
- uc_program_put(program);
-
- if (scope) {
- prev_scope = ucv_get(uc_vm_scope_get(vm));
- uc_vm_scope_set(vm, ucv_get(scope));
+ uc_vm_stack_pop(vm);
+ uc_vm_stack_pop(vm);
+ uc_vm_stack_pop(vm);
}
- extype = uc_vm_call(vm, false, 0);
-
- if (scope)
- uc_vm_scope_set(vm, prev_scope);
-
- if (extype == EXCEPTION_NONE)
- *res = uc_vm_stack_pop(vm);
-
- vm->config->raw_mode = prev_mode;
+ vm->config = prev_config;
return true;
}
@@ -3589,6 +3562,194 @@ uc_gc(uc_vm_t *vm, size_t nargs)
return NULL;
}
+static void
+uc_compile_parse_config(uc_parse_config_t *config, uc_value_t *spec)
+{
+ uc_value_t *v, *p;
+ size_t i, j;
+ bool found;
+
+ struct {
+ const char *key;
+ bool *flag;
+ uc_search_path_t *path;
+ } fields[] = {
+ { "lstrip_blocks", &config->lstrip_blocks, NULL },
+ { "trim_blocks", &config->trim_blocks, NULL },
+ { "strict_declarations", &config->strict_declarations, NULL },
+ { "raw_mode", &config->raw_mode, NULL },
+ { "module_search_path", NULL, &config->module_search_path },
+ { "force_dynlink_list", NULL, &config->force_dynlink_list }
+ };
+
+ for (i = 0; i < ARRAY_SIZE(fields); i++) {
+ v = ucv_object_get(spec, fields[i].key, &found);
+
+ if (!found)
+ continue;
+
+ if (fields[i].flag) {
+ *fields[i].flag = ucv_is_truish(v);
+ }
+ else if (fields[i].path) {
+ fields[i].path->count = 0;
+ fields[i].path->entries = NULL;
+
+ for (j = 0; j < ucv_array_length(v); j++) {
+ p = ucv_array_get(v, j);
+
+ if (ucv_type(p) != UC_STRING)
+ continue;
+
+ uc_vector_push(fields[i].path, ucv_string_get(p));
+ }
+ }
+ }
+}
+
+static uc_value_t *
+uc_load_common(uc_vm_t *vm, size_t nargs, uc_source_t *source)
+{
+ uc_parse_config_t conf = *vm->config;
+ uc_program_t *program;
+ uc_value_t *closure;
+ char *err = NULL;
+
+ uc_compile_parse_config(&conf, uc_fn_arg(1));
+
+ program = uc_compile(&conf, source, &err);
+ closure = program ? ucv_closure_new(vm, uc_program_entry(program), false) : NULL;
+
+ uc_program_put(program);
+
+ if (!vm->config || conf.module_search_path.entries != vm->config->module_search_path.entries)
+ uc_vector_clear(&conf.module_search_path);
+
+ if (!vm->config || conf.force_dynlink_list.entries != vm->config->force_dynlink_list.entries)
+ uc_vector_clear(&conf.force_dynlink_list);
+
+ if (!closure) {
+ uc_error_message_indent(&err);
+
+ if (source->buffer)
+ uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
+ "Unable to compile source string:\n\n%s", err);
+ else
+ uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
+ "Unable to compile source file '%s':\n\n%s", source->filename, err);
+ }
+
+ uc_source_put(source);
+ free(err);
+
+ return closure;
+}
+
+static uc_value_t *
+uc_loadstring(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *code = uc_fn_arg(0);
+ uc_source_t *source;
+ size_t len;
+ char *s;
+
+ if (ucv_type(code) == UC_STRING) {
+ len = ucv_string_length(code);
+ s = xalloc(len);
+ memcpy(s, ucv_string_get(code), len);
+ }
+ else {
+ s = ucv_to_string(vm, code);
+ len = strlen(s);
+ }
+
+ source = uc_source_new_buffer("[loadstring argument]", s, len);
+
+ if (!source) {
+ uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
+ "Unable to allocate source buffer: %s",
+ strerror(errno));
+
+ return NULL;
+ }
+
+ return uc_load_common(vm, nargs, source);
+}
+
+static uc_value_t *
+uc_loadfile(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *path = uc_fn_arg(0);
+ uc_source_t *source;
+
+ if (ucv_type(path) != UC_STRING)
+ return NULL;
+
+ source = uc_source_new_file(ucv_string_get(path));
+
+ if (!source) {
+ uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
+ "Unable to open source file %s: %s",
+ ucv_string_get(path), strerror(errno));
+
+ return NULL;
+ }
+
+ return uc_load_common(vm, nargs, source);
+}
+
+static uc_value_t *
+uc_callfunc(uc_vm_t *vm, size_t nargs)
+{
+ size_t argoff = vm->stack.count - nargs, i;
+ uc_value_t *fn_scope, *prev_scope, *res;
+ uc_value_t *fn = uc_fn_arg(0);
+ uc_value_t *this = uc_fn_arg(1);
+ uc_value_t *scope = uc_fn_arg(2);
+
+ if (!ucv_is_callable(fn))
+ return NULL;
+
+ if (scope && ucv_type(scope) != UC_OBJECT)
+ return NULL;
+
+ if (ucv_prototype_get(scope)) {
+ fn_scope = ucv_get(scope);
+ }
+ else if (scope) {
+ fn_scope = ucv_object_new(vm);
+
+ ucv_object_foreach(scope, k, v)
+ ucv_object_add(fn_scope, k, ucv_get(v));
+
+ ucv_prototype_set(fn_scope, ucv_get(uc_vm_scope_get(vm)));
+ }
+ else {
+ fn_scope = NULL;
+ }
+
+ uc_vm_stack_push(vm, ucv_get(this));
+ uc_vm_stack_push(vm, ucv_get(fn));
+
+ for (i = 3; i < nargs; i++)
+ uc_vm_stack_push(vm, ucv_get(vm->stack.entries[3 + argoff++]));
+
+ if (fn_scope) {
+ prev_scope = ucv_get(uc_vm_scope_get(vm));
+ uc_vm_scope_set(vm, fn_scope);
+ }
+
+ if (uc_vm_call(vm, true, i - 3) == EXCEPTION_NONE)
+ res = uc_vm_stack_pop(vm);
+ else
+ res = NULL;
+
+ if (fn_scope)
+ uc_vm_scope_set(vm, prev_scope);
+
+ return res;
+}
+
const uc_function_list_t uc_stdlib_functions[] = {
{ "chr", uc_chr },
@@ -3656,7 +3817,10 @@ const uc_function_list_t uc_stdlib_functions[] = {
{ "clock", uc_clock },
{ "hexdec", uc_hexdec },
{ "hexenc", uc_hexenc },
- { "gc", uc_gc }
+ { "gc", uc_gc },
+ { "loadstring", uc_loadstring },
+ { "loadfile", uc_loadfile },
+ { "call", uc_callfunc },
};