summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Weiner <hannes@cmpxchg.org>2010-03-17 15:04:38 +0100
committerJohannes Weiner <hannes@cmpxchg.org>2010-03-17 15:05:10 +0100
commitb485d31f858bc8fcc64badd574c2525489c5e97b (patch)
treebafeeaf3a3b7f36dfc1fa2312719f0fee6feff6c
parent7cc6869ff9b12265f66dc06918ab8eec8fa5160a (diff)
runtime module loading
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
-rw-r--r--include/sheep/code.h30
-rw-r--r--include/sheep/vm.h7
-rw-r--r--sheep/code.c10
-rw-r--r--sheep/compile.c77
-rw-r--r--sheep/core.c36
-rw-r--r--sheep/eval.c56
-rw-r--r--sheep/vm.c32
7 files changed, 162 insertions, 86 deletions
diff --git a/include/sheep/code.h b/include/sheep/code.h
index db7e721..3bc4ac2 100644
--- a/include/sheep/code.h
+++ b/include/sheep/code.h
@@ -15,19 +15,23 @@ struct sheep_vm;
enum sheep_opcode {
/* 0*/SHEEP_DROP,
- /* 1*/SHEEP_LOCAL,
- /* 2*/SHEEP_SET_LOCAL,
- /* 3*/SHEEP_FOREIGN,
- /* 4*/SHEEP_SET_FOREIGN,
- /* 5*/SHEEP_GLOBAL,
- /* 6*/SHEEP_SET_GLOBAL,
- /* 7*/SHEEP_CLOSURE,
- /* 8*/SHEEP_CALL,
- /* 9*/SHEEP_TAILCALL,
- /*10*/SHEEP_RET,
- /*11*/SHEEP_BRT,
- /*12*/SHEEP_BRF,
- /*13*/SHEEP_BR,
+ /* 1*/SHEEP_DUP,
+ /* 2*/SHEEP_LOCAL,
+ /* 3*/SHEEP_SET_LOCAL,
+ /* 4*/SHEEP_FOREIGN,
+ /* 5*/SHEEP_SET_FOREIGN,
+ /* 6*/SHEEP_GLOBAL,
+ /* 7*/SHEEP_SET_GLOBAL,
+ /* 8*/SHEEP_HASH,
+ /* 9*/SHEEP_SET_HASH,
+ /*10*/SHEEP_CLOSURE,
+ /*11*/SHEEP_CALL,
+ /*12*/SHEEP_TAILCALL,
+ /*13*/SHEEP_RET,
+ /*14*/SHEEP_BRT,
+ /*15*/SHEEP_BRF,
+ /*16*/SHEEP_BR,
+ /*17*/SHEEP_LOAD,
};
#define SHEEP_OPCODE_BITS 5
diff --git a/include/sheep/vm.h b/include/sheep/vm.h
index 0384be9..bb771f5 100644
--- a/include/sheep/vm.h
+++ b/include/sheep/vm.h
@@ -20,6 +20,7 @@ struct sheep_vm {
struct sheep_vector protected;
int gc_disabled;
+ char **keys;
struct sheep_vector globals;
/* Compiler */
@@ -33,6 +34,10 @@ struct sheep_vm {
struct sheep_vector calls; /* [lastpc lastbasep lastfunction] */
};
+unsigned int sheep_vm_key(struct sheep_vm *, const char *);
+
+void sheep_vm_mark(struct sheep_vm *);
+
static inline unsigned int sheep_vm_constant(struct sheep_vm *vm, sheep_t sheep)
{
return sheep_vector_push(&vm->globals, sheep);
@@ -49,6 +54,4 @@ void sheep_vm_function(struct sheep_vm *, const char *, sheep_alien_t);
void sheep_vm_init(struct sheep_vm *, int, char **);
void sheep_vm_exit(struct sheep_vm *);
-void sheep_vm_mark(struct sheep_vm *);
-
#endif /* _SHEEP_VM_H */
diff --git a/sheep/code.c b/sheep/code.c
index b5f4e87..384fb02 100644
--- a/sheep/code.c
+++ b/sheep/code.c
@@ -48,9 +48,11 @@ void sheep_code_finalize(struct sheep_code *code)
}
static const char *opnames[] = {
- "DROP", "LOCAL", "SET_LOCAL", "FOREIGN", "SET_FOREIGN",
- "GLOBAL", "SET_GLOBAL", "CLOSURE", "CALL", "TAILCALL", "RET",
+ "DROP", "DUP", "LOCAL", "SET_LOCAL", "FOREIGN", "SET_FOREIGN",
+ "GLOBAL", "SET_GLOBAL", "HASH", "SET_HASH",
+ "CLOSURE", "CALL", "TAILCALL", "RET",
"BRT", "BRF", "BR",
+ "LOAD",
};
void sheep_code_dump(struct sheep_vm *vm, struct sheep_function *function,
@@ -77,6 +79,10 @@ void sheep_code_dump(struct sheep_vm *vm, struct sheep_function *function,
case SHEEP_CLOSURE:
sheep = vm->globals.items[arg];
break;
+ case SHEEP_HASH:
+ case SHEEP_SET_HASH:
+ printf("; %s\n", vm->keys[arg]);
+ return;
default:
puts("");
return;
diff --git a/sheep/compile.c b/sheep/compile.c
index 02dcd4b..61ca62a 100644
--- a/sheep/compile.c
+++ b/sheep/compile.c
@@ -96,79 +96,60 @@ static enum env_level lookup_env(struct sheep_compile *compile,
return ENV_FOREIGN;
}
-static int compile_simple_name(struct sheep_compile *compile,
+static int compile_name(struct sheep_compile *compile,
struct sheep_function *function,
struct sheep_context *context,
sheep_t sheep, int set)
{
- unsigned int dist, slot;
- const char *name;
+ unsigned int dist, slot, i = 0;
+ struct sheep_name *name;
- name = sheep_name(sheep)->parts[0];
+ if (set)
+ sheep_emit(&function->code, SHEEP_DUP, 0);
- switch (lookup_env(compile, context, name, &dist, &slot)) {
+ name = sheep_name(sheep);
+ switch (lookup_env(compile, context, name->parts[0], &dist, &slot)) {
case ENV_NONE:
sheep_parser_error(compile, sheep, "unbound name");
return -1;
case ENV_LOCAL:
- if (set)
+ if (set && name->nr_parts == 1)
sheep_emit(&function->code, SHEEP_SET_LOCAL, slot);
- sheep_emit(&function->code, SHEEP_LOCAL, slot);
+ else
+ sheep_emit(&function->code, SHEEP_LOCAL, slot);
break;
case ENV_GLOBAL:
- if (set)
+ if (set && name->nr_parts == 1)
sheep_emit(&function->code, SHEEP_SET_GLOBAL, slot);
- sheep_emit(&function->code, SHEEP_GLOBAL, slot);
+ else
+ sheep_emit(&function->code, SHEEP_GLOBAL, slot);
break;
case ENV_FOREIGN:
slot = sheep_foreign_slot(function, dist, slot);
- if (set)
+ if (set && name->nr_parts == 1)
sheep_emit(&function->code, SHEEP_SET_FOREIGN, slot);
- sheep_emit(&function->code, SHEEP_FOREIGN, slot);
+ else
+ sheep_emit(&function->code, SHEEP_FOREIGN, slot);
break;
}
- return 0;
-}
-static int compile_name(struct sheep_compile *compile,
- struct sheep_function *function,
- struct sheep_context *context,
- sheep_t sheep, int set)
-{
- struct sheep_module *mod;
- struct sheep_name *name;
- unsigned int i = 0;
- void *entry;
-
- name = sheep_name(sheep);
- if (name->nr_parts == 1)
- return compile_simple_name(compile, function,
- context, sheep, set);
+ for (i = name->nr_parts - 1; i; i--) {
+ enum sheep_opcode opcode;
+ unsigned int key_slot;
+ const char *key;
- mod = compile->module;
- do {
- sheep_t m;
+ key = name->parts[name->nr_parts - i];
+ key_slot = sheep_vm_key(compile->vm, key);
- if (sheep_map_get(&mod->env, name->parts[i], &entry))
- goto err;
+ if (set && i == 1)
+ opcode = SHEEP_SET_HASH;
+ else
+ opcode = SHEEP_HASH;
- m = compile->vm->globals.items[(unsigned long)entry];
- if (sheep_type(m) != &sheep_module_type)
- goto err;
- mod = sheep_data(m);
- } while (++i < name->nr_parts - 1);
-
- if (sheep_map_get(&mod->env, name->parts[i], &entry))
- goto err;
-
- if (set)
- sheep_emit(&function->code, SHEEP_SET_GLOBAL,
- (unsigned long)entry);
- sheep_emit(&function->code, SHEEP_GLOBAL, (unsigned long)entry);
+ sheep_emit(&function->code, opcode, key_slot);
+ }
+
return 0;
-err:
- sheep_parser_error(compile, sheep, "unbound");
- return -1;
}
int sheep_compile_name(struct sheep_compile *compile,
diff --git a/sheep/core.c b/sheep/core.c
index 52c7c74..2239285 100644
--- a/sheep/core.c
+++ b/sheep/core.c
@@ -167,14 +167,14 @@ static int compile_variable(struct sheep_compile *compile,
if (sheep_compile_object(compile, function, context, value))
return -1;
+ sheep_emit(&function->code, SHEEP_DUP, 0);
+
if (context->parent) {
slot = sheep_function_local(function);
sheep_emit(&function->code, SHEEP_SET_LOCAL, slot);
- sheep_emit(&function->code, SHEEP_LOCAL, slot);
} else {
slot = sheep_vm_global(compile->vm);
sheep_emit(&function->code, SHEEP_SET_GLOBAL, slot);
- sheep_emit(&function->code, SHEEP_GLOBAL, slot);
}
sheep_map_set(context->env, name, (void *)(unsigned long)slot);
return 0;
@@ -232,14 +232,14 @@ static int compile_function(struct sheep_compile *compile,
if (name) {
unsigned int slot;
+ sheep_emit(&function->code, SHEEP_DUP, 0);
+
if (context->parent) {
slot = sheep_function_local(function);
sheep_emit(&function->code, SHEEP_SET_LOCAL, slot);
- sheep_emit(&function->code, SHEEP_LOCAL, slot);
} else {
slot = sheep_vm_global(compile->vm);
sheep_emit(&function->code, SHEEP_SET_GLOBAL, slot);
- sheep_emit(&function->code, SHEEP_GLOBAL, slot);
}
sheep_map_set(context->env, name, (void *)(unsigned long)slot);
}
@@ -400,30 +400,24 @@ static int compile_load(struct sheep_compile *compile,
{
unsigned int slot;
const char *name;
- int ret = -1;
- sheep_t mod;
-
- if (context->parent) {
- sheep_parser_error(compile, args->head, "non-toplevel");
- return -1;
- }
if (sheep_parse(compile, args, "s", &name))
return -1;
- sheep_protect(compile->vm, sheep_list(args->tail)->head);
+ slot = sheep_vm_key(compile->vm, name);
+ sheep_emit(&function->code, SHEEP_LOAD, slot);
- mod = sheep_module_load(compile->vm, name);
- if (!mod)
- goto out;
+ sheep_emit(&function->code, SHEEP_DUP, 0);
- slot = sheep_vm_constant(compile->vm, mod);
- sheep_emit(&function->code, SHEEP_GLOBAL, slot);
+ if (context->parent) {
+ slot = sheep_function_local(function);
+ sheep_emit(&function->code, SHEEP_SET_LOCAL, slot);
+ } else {
+ slot = sheep_vm_global(compile->vm);
+ sheep_emit(&function->code, SHEEP_SET_GLOBAL, slot);
+ }
sheep_map_set(context->env, name, (void *)(unsigned long)slot);
- ret = 0;
-out:
- sheep_unprotect(compile->vm, sheep_list(args->tail)->head);
- return ret;
+ return 0;
}
void sheep_core_init(struct sheep_vm *vm)
diff --git a/sheep/eval.c b/sheep/eval.c
index 2b3e2ca..5d6e48a 100644
--- a/sheep/eval.c
+++ b/sheep/eval.c
@@ -6,9 +6,11 @@
#include <sheep/function.h>
#include <sheep/foreign.h>
#include <sheep/object.h>
+#include <sheep/string.h>
#include <sheep/alien.h>
#include <sheep/bool.h>
#include <sheep/code.h>
+#include <sheep/name.h>
#include <sheep/util.h>
#include <sheep/map.h>
#include <sheep/gc.h>
@@ -19,6 +21,38 @@
#include <sheep/eval.h>
+static sheep_t hash(struct sheep_vm *vm, sheep_t container,
+ unsigned int key_slot, sheep_t value)
+{
+ struct sheep_vector *slots;
+ const char *key, *obj;
+ struct sheep_map *map;
+ void *entry;
+
+ key = vm->keys[key_slot];
+
+ if (sheep_type(container) == &sheep_module_type) {
+ struct sheep_module *mod = sheep_data(container);
+
+ slots = &vm->globals;
+ map = &mod->env;
+ } else
+ goto err;
+
+ if (sheep_map_get(map, key, &entry))
+ goto err;
+
+ if (value)
+ slots->items[(unsigned int)entry] = value;
+
+ return slots->items[(unsigned int)entry];
+err:
+ obj = sheep_repr(container);
+ fprintf(stderr, "can not find %s in %s\n", key, obj);
+ sheep_free(obj);
+ return NULL;
+}
+
static sheep_t closure(struct sheep_vm *vm, unsigned long basep,
struct sheep_function *parent, sheep_t sheep)
{
@@ -118,6 +152,10 @@ sheep_t sheep_eval(struct sheep_vm *vm, sheep_t function)
case SHEEP_DROP:
sheep_vector_pop(&vm->stack);
break;
+ case SHEEP_DUP:
+ tmp = vm->stack.items[vm->stack.nr_items - 1];
+ sheep_vector_push(&vm->stack, tmp);
+ break;
case SHEEP_LOCAL:
tmp = vm->stack.items[basep + arg];
sheep_vector_push(&vm->stack, tmp);
@@ -158,6 +196,18 @@ sheep_t sheep_eval(struct sheep_vm *vm, sheep_t function)
tmp = sheep_vector_pop(&vm->stack);
vm->globals.items[arg] = tmp;
break;
+ case SHEEP_HASH:
+ tmp = sheep_vector_pop(&vm->stack);
+ tmp = hash(vm, tmp, arg, NULL);
+ if (!tmp)
+ goto err;
+ sheep_vector_push(&vm->stack, tmp);
+ break;
+ case SHEEP_SET_HASH:
+ tmp = sheep_vector_pop(&vm->stack);
+ if (!hash(vm, tmp, arg, sheep_vector_pop(&vm->stack)))
+ goto err;
+ break;
case SHEEP_CLOSURE:
tmp = vm->globals.items[arg];
tmp = closure(vm, basep, current, tmp);
@@ -252,6 +302,12 @@ sheep_t sheep_eval(struct sheep_vm *vm, sheep_t function)
case SHEEP_BR:
codep += arg;
continue;
+ case SHEEP_LOAD:
+ tmp = sheep_module_load(vm, vm->keys[arg]);
+ if (!tmp)
+ goto err;
+ sheep_vector_push(&vm->stack, tmp);
+ break;
default:
abort();
}
diff --git a/sheep/vm.c b/sheep/vm.c
index 268c34a..75fca23 100644
--- a/sheep/vm.c
+++ b/sheep/vm.c
@@ -19,6 +19,37 @@
#include <sheep/vm.h>
+unsigned int sheep_vm_key(struct sheep_vm *vm, const char *key)
+{
+ unsigned int slot = 0;
+
+ if (vm->keys) {
+ while (vm->keys[slot]) {
+ if (!strcmp(vm->keys[slot], key))
+ return slot;
+ slot++;
+ }
+ }
+
+ vm->keys = sheep_realloc(vm->keys, sizeof(char *) * (slot + 2));
+ vm->keys[slot] = sheep_strdup(key);
+ vm->keys[slot + 1] = NULL;
+ return slot;
+}
+
+static void drain_keys(struct sheep_vm *vm)
+{
+ unsigned int slot;
+
+ if (!vm->keys)
+ return;
+
+ for (slot = 0; vm->keys[slot]; slot++)
+ sheep_free(vm->keys[slot]);
+
+ sheep_free(vm->keys);
+}
+
void sheep_vm_mark(struct sheep_vm *vm)
{
unsigned int i;
@@ -91,5 +122,6 @@ void sheep_vm_exit(struct sheep_vm *vm)
sheep_core_exit(vm);
sheep_evaluator_exit(vm);
sheep_free(vm->globals.items);
+ drain_keys(vm);
sheep_gc_exit(vm);
}