summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Weiner <hannes@cmpxchg.org>2010-05-12 19:37:33 +0200
committerJohannes Weiner <hannes@cmpxchg.org>2010-05-12 19:37:33 +0200
commitd0a2089e2bbaf5195748646c21a637e0dacee4f0 (patch)
treeb49739e2a44b6c6f77597fbece148679021fb8bb
parent4787400cf01b0c40de11c401e4f8b72e000a7cc4 (diff)
vm: runtime error reporting facility
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
-rw-r--r--include/sheep/vm.h5
-rw-r--r--sheep/eval.c10
-rw-r--r--sheep/function.c3
-rw-r--r--sheep/module.c12
-rw-r--r--sheep/number.c6
-rw-r--r--sheep/sequence.c2
-rw-r--r--sheep/string.c2
-rw-r--r--sheep/type.c4
-rw-r--r--sheep/unpack.c18
-rw-r--r--sheep/vm.c42
10 files changed, 76 insertions, 28 deletions
diff --git a/include/sheep/vm.h b/include/sheep/vm.h
index 19925bb..f2fe1db 100644
--- a/include/sheep/vm.h
+++ b/include/sheep/vm.h
@@ -12,6 +12,7 @@
#include <sheep/vector.h>
#include <sheep/alien.h>
#include <sheep/map.h>
+#include <stdarg.h>
struct sheep_vm {
/* Object management */
@@ -32,8 +33,12 @@ struct sheep_vm {
struct sheep_indirect *pending;
struct sheep_vector stack;
struct sheep_vector calls; /* [lastpc lastbasep lastfunction] */
+ char *error;
};
+void sheep_error(struct sheep_vm *, const char *, ...);
+void sheep_report_error(struct sheep_vm *, sheep_t);
+
unsigned int sheep_vm_key(struct sheep_vm *, const char *);
void sheep_vm_mark(struct sheep_vm *);
diff --git a/sheep/eval.c b/sheep/eval.c
index 06cb281..c6ddd1b 100644
--- a/sheep/eval.c
+++ b/sheep/eval.c
@@ -54,7 +54,7 @@ static sheep_t hash(struct sheep_vm *vm, sheep_t container,
return slots[(unsigned long)entry];
err:
obj = sheep_repr(container);
- fprintf(stderr, "can not find %s in %s\n", key, obj);
+ sheep_error(vm, "can not find `%s' in `%s'", key, obj);
sheep_free(obj);
return NULL;
}
@@ -82,8 +82,7 @@ static enum sheep_call precall(struct sheep_vm *vm, sheep_t callable,
type = sheep_type(callable);
if (!type->call) {
- fprintf(stderr, "can not call object of type %s\n",
- type->name);
+ sheep_error(vm, "can not call `%s'", type->name);
return SHEEP_CALL_FAIL;
}
return type->call(vm, callable, nr_args, valuep);
@@ -121,6 +120,7 @@ sheep_t sheep_eval(struct sheep_vm *vm, sheep_t function)
struct sheep_function *current;
unsigned long basep, *codep;
unsigned int nesting = 0;
+ sheep_t problem = NULL;
sheep_protect(vm, function);
@@ -209,6 +209,7 @@ sheep_t sheep_eval(struct sheep_vm *vm, sheep_t function)
done = precall(vm, tmp, arg, &tmp);
switch (done) {
case SHEEP_CALL_FAIL:
+ problem = tmp;
goto err;
case SHEEP_CALL_DONE:
sheep_vector_push(&vm->stack, tmp);
@@ -233,6 +234,7 @@ sheep_t sheep_eval(struct sheep_vm *vm, sheep_t function)
done = precall(vm, tmp, arg, &tmp);
switch (done) {
case SHEEP_CALL_FAIL:
+ problem = tmp;
goto err;
case SHEEP_CALL_DONE:
sheep_vector_push(&vm->stack, tmp);
@@ -308,6 +310,8 @@ out:
err:
vm->stack.nr_items = 0;
vm->calls.nr_items -= 3 * nesting;
+ if (!vm->calls.nr_items)
+ sheep_report_error(vm, problem);
sheep_unprotect(vm, function);
return NULL;
}
diff --git a/sheep/function.c b/sheep/function.c
index f3a6808..706fadc 100644
--- a/sheep/function.c
+++ b/sheep/function.c
@@ -44,8 +44,7 @@ static enum sheep_call function_call(struct sheep_vm *vm, sheep_t callable,
function = sheep_function(callable);
if (function->nr_parms != nr_args) {
- fprintf(stderr, "%s: too %s arguments\n",
- function->name,
+ sheep_error(vm, "too %s arguments",
function->nr_parms < nr_args ? "many" : "few");
return SHEEP_CALL_FAIL;
}
diff --git a/sheep/module.c b/sheep/module.c
index f1aa23f..8f7f8b1 100644
--- a/sheep/module.c
+++ b/sheep/module.c
@@ -65,13 +65,13 @@ static unsigned int load_so(struct sheep_vm *vm, const char *path,
handle = dlopen(path, RTLD_NOW);
if (!handle) {
- fprintf(stderr, "load: dlopen(%s) failed: %s\n", path, dlerror());
+ sheep_error(vm, "dlopen(%s) failed: %s", path, dlerror());
goto err;
}
init = dlsym(handle, "init");
if (!init) {
- fprintf(stderr, "load: %s has no init()\n", path);
+ sheep_error(vm, "%s has no init()", path);
goto err_handle;
}
@@ -154,7 +154,7 @@ sheep_t sheep_module_load(struct sheep_vm *vm, const char *name)
paths_ = vm->globals.items[load_path];
if (sheep_type(paths_) != &sheep_list_type) {
- fprintf(stderr, "load: load-path is not a list\n");
+ sheep_error(vm, "`load-path' is not a list");
goto err;
}
@@ -163,7 +163,7 @@ sheep_t sheep_module_load(struct sheep_vm *vm, const char *name)
const char *path;
if (sheep_type(paths->head) != &sheep_string_type) {
- fprintf(stderr, "load: bogus load-path contents\n");
+ sheep_error(vm, "bogus paths in `load-path'");
goto err;
}
@@ -179,8 +179,8 @@ sheep_t sheep_module_load(struct sheep_vm *vm, const char *name)
}
}
- fprintf(stderr, "load: %s not found\n", name);
-err:
+ sheep_error(vm, "module `%s' not found", name);
+err:
free_module(mod);
return NULL;
found:
diff --git a/sheep/number.c b/sheep/number.c
index f61037a..2fd819d 100644
--- a/sheep/number.c
+++ b/sheep/number.c
@@ -77,14 +77,12 @@ static sheep_t builtin_number(struct sheep_vm *vm, unsigned int nr_args)
case 0:
return number;
default:
- fprintf(stderr, "number: can not convert \"%s\"\n",
- str);
+ sheep_error(vm, "can not convert \"%s\"", str);
return NULL;
}
}
- fprintf(stderr, "number: can not convert %s\n",
- sheep_type(sheep)->name);
+ sheep_error(vm, "can not convert `%s'", sheep_type(sheep)->name);
return NULL;
}
diff --git a/sheep/sequence.c b/sheep/sequence.c
index f8cd7a2..136ab4b 100644
--- a/sheep/sequence.c
+++ b/sheep/sequence.c
@@ -30,7 +30,7 @@ static sheep_t builtin_concat(struct sheep_vm *vm, unsigned int nr_args)
sheep_t object;
if (!nr_args) {
- fprintf(stderr, "concat: too few arguments\n");
+ sheep_error(vm, "too few arguments\n");
return NULL;
}
diff --git a/sheep/string.c b/sheep/string.c
index 4a6a1de..e994f78 100644
--- a/sheep/string.c
+++ b/sheep/string.c
@@ -116,7 +116,7 @@ static sheep_t string_position(struct sheep_vm *vm, sheep_t item, sheep_t sheep)
const char *str, *pos;
if (sheep_type(item) != &sheep_string_type) {
- fprintf(stderr, "position: string can not contain %s\n",
+ sheep_error(vm, "string can not contain `%s'",
sheep_type(item)->name);
return NULL;
}
diff --git a/sheep/type.c b/sheep/type.c
index a2cae7b..bbcda07 100644
--- a/sheep/type.c
+++ b/sheep/type.c
@@ -72,8 +72,8 @@ static enum sheep_call typeclass_call(struct sheep_vm *vm, sheep_t callable,
class = sheep_data(callable);
if (nr_args != class->nr_slots) {
- fprintf(stderr, "%s has %d slots, %d values given\n",
- class->name, class->nr_slots, nr_args);
+ sheep_error(vm, "type has %d slots, %d values given",
+ class->nr_slots, nr_args);
return SHEEP_CALL_FAIL;
}
diff --git a/sheep/unpack.c b/sheep/unpack.c
index a7cbbb7..7c1e91d 100644
--- a/sheep/unpack.c
+++ b/sheep/unpack.c
@@ -106,8 +106,8 @@ int sheep_unpack(const char *caller, struct sheep_vm *vm,
wanted = unpack(item, object, itemp, &next);
if (wanted) {
- fprintf(stderr, "%s: expected %s, got %s\n",
- caller, wanted, sheep_type(object)->name);
+ sheep_error(vm, "expected %s, got %s",
+ wanted, sheep_type(object)->name);
va_end(ap);
return -1;
}
@@ -144,8 +144,8 @@ int sheep_unpack_list(const char *caller, struct sheep_vm *vm,
wanted = unpack(*items, list->head, itemp, &next);
if (wanted) {
- fprintf(stderr, "%s: expected %s, got %s\n",
- caller, wanted, sheep_type(list->head)->name);
+ sheep_error(vm, "expected %s, got %s",
+ wanted, sheep_type(list->head)->name);
va_end(ap);
return -1;
}
@@ -161,8 +161,8 @@ int sheep_unpack_list(const char *caller, struct sheep_vm *vm,
if (!*items && !list->head)
return 0;
- fprintf(stderr, "%s: too %s arguments\n",
- caller, !!*items - !!list->head > 0 ? "few" : "many");
+ sheep_error(vm, "too %s arguments",
+ !!*items - !!list->head > 0 ? "few" : "many");
return -1;
}
@@ -173,7 +173,7 @@ int sheep_unpack_stack(const char *caller, struct sheep_vm *vm,
va_list ap;
if (strlen(items) != nr_args) {
- fprintf(stderr, "%s: too %s arguments\n", caller,
+ sheep_error(vm, "too %s arguments",
strlen(items) > nr_args ? "few" : "many");
return -1;
}
@@ -192,8 +192,8 @@ int sheep_unpack_stack(const char *caller, struct sheep_vm *vm,
wanted = unpack(*items, object, itemp, &next);
if (wanted) {
- fprintf(stderr, "%s: expected %s, got %s\n",
- caller, wanted, sheep_type(object)->name);
+ sheep_error(vm, "expected %s, got %s",
+ wanted, sheep_type(object)->name);
va_end(ap);
return -1;
}
diff --git a/sheep/vm.c b/sheep/vm.c
index 75fca23..97e9d2b 100644
--- a/sheep/vm.c
+++ b/sheep/vm.c
@@ -13,12 +13,54 @@
#include <sheep/core.h>
#include <sheep/eval.h>
#include <sheep/list.h>
+#include <sheep/type.h>
#include <sheep/util.h>
#include <sheep/gc.h>
+#include <stdarg.h>
#include <string.h>
+#include <stdio.h>
#include <sheep/vm.h>
+#define DEFAULT_ERRBUF 128
+
+void sheep_error(struct sheep_vm *vm, const char *fmt, ...)
+{
+ va_list ap;
+ size_t len;
+
+ sheep_bug_on(vm->error);
+ vm->error = sheep_malloc(DEFAULT_ERRBUF);
+
+ va_start(ap, fmt);
+ len = vsnprintf(vm->error, DEFAULT_ERRBUF, fmt, ap);
+ va_end(ap);
+
+ if (len >= DEFAULT_ERRBUF) {
+ vm->error = sheep_realloc(vm->error, len + 1);
+ va_start(ap, fmt);
+ vsprintf(vm->error, fmt, ap);
+ va_end(ap);
+ }
+}
+
+void sheep_report_error(struct sheep_vm *vm, sheep_t sheep)
+{
+ sheep_bug_on(!vm->error);
+
+ if (sheep) {
+ char *context;
+
+ context = sheep_format(sheep);
+ fprintf(stderr, "%s: ", context);
+ sheep_free(context);
+ }
+ fprintf(stderr, "%s\n", vm->error);
+
+ sheep_free(vm->error);
+ vm->error = NULL;
+}
+
unsigned int sheep_vm_key(struct sheep_vm *vm, const char *key)
{
unsigned int slot = 0;