diff --git a/Makefile b/Makefile index a7954369..5fc1c8db 100644 --- a/Makefile +++ b/Makefile @@ -19,12 +19,10 @@ GST_CORE_SOURCES=$(addprefix core/,\ compile.c disasm.c parse.c stl.c ids.c util.c\ value.c vm.c ds.c gc.c thread.c serialize.c) GST_CORE_OBJECTS=$(patsubst %.c,%.o,$(GST_CORE_SOURCES)) -$(GST_CORELIB): $(GST_CORE_OBJECTS) $(GST_HEADERS) - ar rcs $(GST_CORELIB) $(GST_CORE_OBJECTS) -############################## -##### The example client ##### -############################## +###################### +##### The client ##### +###################### GST_CLIENT_SOURCES=client/main.c GST_CLIENT_OBJECTS=$(patsubst %.c,%.o,$(GST_CLIENT_SOURCES)) $(GST_TARGET): $(GST_CLIENT_OBJECTS) $(GST_CORE_OBJECTS) @@ -50,4 +48,7 @@ clean: rm $(GST_CLIENT_OBJECTS) || true rm vgcore.* || true +test: $(GST_TARGET) + gsttests/basic.gst + .PHONY: clean install run debug valgrind diff --git a/client/main.c b/client/main.c index d29e1307..08fb124c 100644 --- a/client/main.c +++ b/client/main.c @@ -117,6 +117,8 @@ int debug_repl(Gst *vm) { break; if (!reader || *reader == '\0') { buffer = readline(">> "); + if (*buffer == '\0') + return 0; add_history(buffer); reader = buffer; } diff --git a/core/compile.c b/core/compile.c index 0d8d7340..7b07d77c 100644 --- a/core/compile.c +++ b/core/compile.c @@ -945,6 +945,7 @@ static SpecialFormHelper get_special(const GstValue *form) { return compile_apply; } } + break; case 'd': { if (gst_string_length(name) == 2 && @@ -989,6 +990,7 @@ static SpecialFormHelper get_special(const GstValue *form) { return compile_tran; } } + break; case 'w': { if (gst_string_length(name) == 5 && diff --git a/core/gc.c b/core/gc.c index 890bbf2c..6a1c3882 100644 --- a/core/gc.c +++ b/core/gc.c @@ -147,6 +147,8 @@ void gst_mark(Gst *vm, GstValueUnion x, GstType type) { frame = gst_mark_stackframe(vm, frame); if (thread->parent) gst_mark_value(vm, gst_wrap_thread(thread->parent)); + if (thread->errorParent) + gst_mark_value(vm, gst_wrap_thread(thread->errorParent)); } break; diff --git a/core/parse.c b/core/parse.c index dcd80e28..e4b7eec3 100644 --- a/core/parse.c +++ b/core/parse.c @@ -101,6 +101,8 @@ static void parser_push(GstParser *p, ParseType type, uint8_t character) { switch (type) { case PTYPE_STRING: top->buf.string.state = STRING_STATE_BASE; + top->buf.string.buffer = gst_buffer(p->vm, 10); + break; case PTYPE_TOKEN: top->buf.string.buffer = gst_buffer(p->vm, 10); break; @@ -458,6 +460,8 @@ static void dispatch_char(GstParser *p, uint8_t c) { */ int gst_parse_cstring(GstParser *p, const char *string) { int bytesRead = 0; + if (!string) + return 0; while ((p->status == GST_PARSER_PENDING || p->status == GST_PARSER_ROOT) && (string[bytesRead] != '\0')) { dispatch_char(p, string[bytesRead++]); @@ -468,6 +472,8 @@ int gst_parse_cstring(GstParser *p, const char *string) { /* Parse a gst string */ int gst_parse_string(GstParser *p, const uint8_t *string) { uint32_t i; + if (!string) + return 0; for (i = 0; i < gst_string_length(string); ++i) { if (p->status != GST_PARSER_PENDING && p->status != GST_PARSER_ROOT) break; dispatch_char(p, string[i]); diff --git a/core/serialize.c b/core/serialize.c index f27224e4..1a57431e 100644 --- a/core/serialize.c +++ b/core/serialize.c @@ -38,7 +38,7 @@ * Byte 207: Buffer - [u32 capacity][u32 length]*[u8... characters] * Byte 208: Array - [u32 length]*[value... elements] * Byte 209: Tuple - [u32 length]*[value... elements] - * Byte 210: Thread - [value parent][u8 state][u32 frames]*[[value callee][value env] + * Byte 210: Thread - [value parent][value errorParent][u8 state][u32 frames]*[[value callee][value env] * [u32 pcoffset][u32 ret][u32 args][u32 size]*[value ...stack]] * Byte 211: Table - [u32 length]*2*[value... kvs] * Byte 212: FuncDef - [u32 locals][u32 arity][u32 flags][u32 literallen]*[value... @@ -249,7 +249,16 @@ static const char *gst_deserialize_impl( } else if (ret.type == GST_THREAD) { t->parent = ret.data.thread; } else { - return "expected thread parent to thread"; + return "expected thread parent to be thread"; + } + err = gst_deserialize_impl(vm, data, end, &data, visited, &ret); + if (err != NULL) return err; + if (ret.type == GST_NIL) { + t->errorParent = NULL; + } else if (ret.type == GST_THREAD) { + t->errorParent = ret.data.thread; + } else { + return "expected thread error parent to be thread"; } deser_assert(data < end, UEB); statusbyte = *data++; @@ -520,10 +529,10 @@ const char *gst_serialize_impl( } /* Check tuples and structs before other reference types. - * They ae immutable, and thus cannot be referenced by other values + * They are immutable, and thus cannot be referenced by other values * until they are fully constructed. This creates some strange behavior * if they are treated like other reference types because they cannot - * be added to the visited table before recusring into serializing their + * be added to the visited table before recursing into serializing their * arguments */ if (x.type == GST_STRUCT || x.type == GST_TUPLE) { if (x.type == GST_STRUCT) { @@ -632,6 +641,11 @@ const char *gst_serialize_impl( err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_thread(t->parent)); else err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_nil()); + if (t->errorParent) + err = gst_serialize_impl(vm, buffer, visited, nextId, + gst_wrap_thread(t->errorParent)); + else + err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_nil()); if (err != NULL) return err; /* Write the status byte */ write_byte(t->status); diff --git a/core/stl.c b/core/stl.c index 58b3543e..d8b5b2f7 100644 --- a/core/stl.c +++ b/core/stl.c @@ -446,9 +446,21 @@ int gst_stl_string(Gst *vm) { int gst_stl_thread(Gst *vm) { GstThread *t; GstValue callee = gst_arg(vm, 0); + GstValue parent = gst_arg(vm, 1); + GstValue errorParent = gst_arg(vm, 2); + t = gst_thread(vm, callee, 10); if (callee.type != GST_FUNCTION && callee.type != GST_CFUNCTION) gst_c_throwc(vm, "expected function in thread constructor"); - t = gst_thread(vm, callee, 10); + if (parent.type == GST_THREAD) { + t->parent = parent.data.thread; + } else if (parent.type != GST_NIL) { + gst_c_throwc(vm, "expected thread/nil as parent"); + } + if (errorParent.type == GST_THREAD) { + t->errorParent = errorParent.data.thread; + } else if (errorParent.type != GST_NIL) { + gst_c_throwc(vm, "expected thread/nil as error parent"); + } t->parent = vm->thread; gst_c_return(vm, gst_wrap_thread(t)); } @@ -669,12 +681,13 @@ int gst_stl_namespace_set(Gst *vm) { /* Get the table or struct associated with a given namespace */ int gst_stl_namespace_get(Gst *vm) { - GstValue name = gst_arg(vm, 0); - GstValue check; - if (name.type != GST_STRING) - gst_c_throwc(vm, "expected string"); - check = gst_table_get(vm->modules, name); - gst_c_return(vm, check); + return gst_callc(vm, gst_stl_get, 2, gst_wrap_table(vm->modules), gst_arg(vm, 0)); + /*GstValue name = gst_arg(vm, 0);*/ + /*GstValue check;*/ + /*if (name.type != GST_STRING)*/ + /*gst_c_throwc(vm, "expected string");*/ + /*check = gst_table_get(vm->modules, name);*/ + /*gst_c_return(vm, check);*/ } /***/ @@ -796,7 +809,7 @@ int gst_stl_close(Gst *vm) { } /* Functions in the io module */ -static const GstModuleItem const io_dat[] = { +static const GstModuleItem io_dat[] = { {"open", gst_stl_open}, {"slurp", gst_stl_slurp}, {"read", gst_stl_read}, @@ -914,7 +927,7 @@ int gst_stl_debugp(Gst *vm) { /* Bootstraping */ /****/ -static const GstModuleItem const std_module[] = { +static const GstModuleItem std_module[] = { /* Arithmetic */ {"+", gst_stl_add}, {"*", gst_stl_mul}, diff --git a/core/thread.c b/core/thread.c index 1d942fa0..2cec03f1 100644 --- a/core/thread.c +++ b/core/thread.c @@ -42,6 +42,7 @@ GstThread *gst_thread(Gst *vm, GstValue callee, uint32_t capacity) { gst_frame_callee(stack) = callee; gst_thread_endframe(vm, thread); thread->parent = NULL; /* Need to set parent manually */ + thread->errorParent = NULL; return thread; } diff --git a/core/util.c b/core/util.c index 2a4b0b0a..c05523d6 100644 --- a/core/util.c +++ b/core/util.c @@ -237,3 +237,18 @@ GstInteger gst_endrange(GstInteger raw, uint32_t len) { return len + raw + 1; return raw; } + +int gst_callc(Gst *vm, GstCFunction fn, int numargs, ...) { + int result, i; + va_list args; + GstValue *stack; + va_start(args, numargs); + stack = gst_thread_beginframe(vm, vm->thread, gst_wrap_cfunction(fn), numargs); + for (i = 0; i < numargs; ++i) { + stack[i] = va_arg(args, GstValue); + } + va_end(args); + result = fn(vm); + gst_thread_popframe(vm, vm->thread); + return result; +} diff --git a/core/vm.c b/core/vm.c index 291ed755..b58387f0 100644 --- a/core/vm.c +++ b/core/vm.c @@ -394,9 +394,9 @@ int gst_continue(Gst *vm) { /* Handle errors from c functions and vm opcodes */ vm_error: vm->thread->status = GST_THREAD_ERROR; - if (vm->thread->parent == NULL) + if (vm->thread->errorParent == NULL) return GST_RETURN_ERROR; - vm->thread = vm->thread->parent; + vm->thread = vm->thread->errorParent; stack = vm->thread->data + vm->thread->count; stack[gst_frame_ret(stack)] = vm->ret; pc = gst_frame_pc(stack); diff --git a/gsttests/basic.gst b/gsttests/basic.gst index 96e699f9..291b2db4 100644 --- a/gsttests/basic.gst +++ b/gsttests/basic.gst @@ -1,11 +1,8 @@ -# Define assert +(do (: assert (fn [x e] (if x x (do (print e) (exit 1))))) - -# Basic Math -(assert (= 10 (+ 1 2 3 4), "addition") -(assert (= -8 (- 1 2 3 4), "subtraction") -(assert (= 24 (* 1 2 3 4), "multiplication") -(assert (= 0.1 (/ 1 10), "division") - -# All good +(assert (= 10 (+ 1 2 3 4)) "addition") +(assert (= -8 (- 1 2 3 4)) "subtraction") +(assert (= 24 (* 1 2 3 4)) "multiplication") +(assert (= 0.1 (/ 1.0 10)) "division") (exit 0) +) diff --git a/include/gst/gst.h b/include/gst/gst.h index 51fae5e4..982d0e5c 100644 --- a/include/gst/gst.h +++ b/include/gst/gst.h @@ -24,6 +24,7 @@ #define GST_H_defined #include +#include /* String utils */ #define gst_string_raw(s) ((uint32_t *)(s) - 2) @@ -206,6 +207,7 @@ struct GstThread { uint32_t capacity; GstValue *data; GstThread *parent; + GstThread *errorParent; enum { GST_THREAD_PENDING = 0, GST_THREAD_ALIVE, @@ -490,10 +492,13 @@ uint32_t gst_count_args(Gst *vm); /* C Api */ /****/ -void gst_module(Gst *vm, const char *packagename, const GstModuleItem *mod); -void gst_module_mutable(Gst *vm, const char *packagename, const GstModuleItem *mod); +void gst_module(Gst *vm, const char *name, const GstModuleItem *mod); +void gst_module_mutable(Gst *vm, const char *name, const GstModuleItem *mod); +void gst_module_put(Gst *vm, const char *packagename, const char *name, GstValue x); GstValue gst_module_get(Gst *vm, const char *packagename); -void gst_module_put(Gst *vm, const char *packagename, const char *name, GstValue v); +void gst_register_put(Gst *vm, const char *packagename, GstValue mod); +GstValue gst_register_get(Gst *vm, const char *name); +int gst_callc(Gst *vm, GstCFunction fn, int numargs, ...); /* Wrap data in GstValue */ GstValue gst_wrap_nil();