diff --git a/Makefile b/Makefile index ef54622f..457b0e5c 100644 --- a/Makefile +++ b/Makefile @@ -72,7 +72,7 @@ valgrind: $(DST_TARGET) @ valgrind --leak-check=full -v ./$(DST_TARGET) test: $(DST_TARGET) - @ ./$(DST_TARGET) dsttest/suite0.dst + @ ./$(DST_TARGET) --gcinterval=0 dsttest/suite0.dst valtest: $(DST_TARGET) valgrind --leak-check=full -v ./$(DST_TARGET) dsttests/basic.dst diff --git a/client/main.c b/client/main.c index 8a7192f6..1501b2cf 100644 --- a/client/main.c +++ b/client/main.c @@ -176,7 +176,7 @@ static void runfile(const uint8_t *src, int32_t len) { } int main(int argc, char **argv) { - int status = -1; + int status = 0; int i; int fileRead = 0; uint32_t gcinterval = 0x10000; diff --git a/core/compile_specials.c b/core/compile_specials.c index 037ba922..d54cdbd4 100644 --- a/core/compile_specials.c +++ b/core/compile_specials.c @@ -491,6 +491,9 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) { if (varargs) def->flags |= DST_FUNCDEF_FLAG_VARARG; defindex = dstc_addfuncdef(c, def); + /* Ensure enough slots for vararg function. */ + if (arity + varargs > def->slotcount) def->slotcount = arity + varargs; + /* Instantiate closure */ ret.flags = 0; ret.envindex = 0; diff --git a/core/fiber.c b/core/fiber.c index 7abe4932..1f501881 100644 --- a/core/fiber.c +++ b/core/fiber.c @@ -45,7 +45,7 @@ DstFiber *dst_fiber_reset(DstFiber *fiber) { fiber->frame = 0; fiber->stackstart = DST_FRAME_SIZE; fiber->stacktop = DST_FRAME_SIZE; - fiber->status = DST_FIBER_PENDING; + fiber->status = DST_FIBER_NEW; fiber->parent = NULL; return fiber; } diff --git a/core/stl.c b/core/stl.c index 30c1a710..07aa20b9 100644 --- a/core/stl.c +++ b/core/stl.c @@ -23,6 +23,15 @@ #include #include +int dst_stl_exit(int32_t argn, Dst *argv, Dst *ret) { + (void)ret; + int32_t exitcode = 0; + if (argn > 0) { + exitcode = dst_hash(argv[0]); + } + exit(exitcode); +} + int dst_stl_print(int32_t argn, Dst *argv, Dst *ret) { (void)ret; @@ -210,6 +219,37 @@ int dst_stl_get(int32_t argn, Dst *argv, Dst *ret) { return 0; } +int dst_stl_status(int32_t argn, Dst *argv, Dst *ret) { + const char *status; + if (argn != 1) { + *ret = dst_cstringv("expected 1 argument"); + return 1; + } + if (!dst_checktype(argv[0], DST_FIBER)) { + *ret = dst_cstringv("expected fiber"); + return 1; + } + switch(dst_unwrap_fiber(argv[0])->status) { + case DST_FIBER_PENDING: + status = "pending"; + break; + case DST_FIBER_NEW: + status = "new"; + break; + case DST_FIBER_ALIVE: + status = "alive"; + break; + case DST_FIBER_DEAD: + status = "dead"; + break; + case DST_FIBER_ERROR: + status = "error"; + break; + } + *ret = dst_cstringv(status); + return 0; +} + int dst_stl_put(int32_t argn, Dst *argv, Dst *ret) { Dst ds, key, value; if (argn < 3) { @@ -284,6 +324,7 @@ static DstReg stl[] = { {"tuple", dst_stl_tuple}, {"struct", dst_stl_struct}, {"fiber", dst_stl_fiber}, + {"status", dst_stl_status}, {"buffer", dst_stl_buffer}, {"gensym", dst_stl_gensym}, {"asm", dst_stl_asm}, @@ -325,7 +366,8 @@ static DstReg stl[] = { {"fopen", dst_stl_fileopen}, {"fclose", dst_stl_fileclose}, {"fwrite", dst_stl_filewrite}, - {"fread", dst_stl_fileread} + {"fread", dst_stl_fileread}, + {"exit!", dst_stl_exit} }; Dst dst_loadstl(int flags) { diff --git a/core/string.c b/core/string.c index 3a469aaa..c4749a8f 100644 --- a/core/string.c +++ b/core/string.c @@ -121,7 +121,7 @@ static const uint8_t *real_to_string(double x) { return dst_string(buf, real_to_string_impl(buf, x)); } -static int32_t integer_to_string_impl(uint8_t *buf, int64_t x) { +static int32_t integer_to_string_impl(uint8_t *buf, int32_t x) { int neg = 0; uint8_t *hi, *low; int32_t count = 0; @@ -151,12 +151,12 @@ static int32_t integer_to_string_impl(uint8_t *buf, int64_t x) { return count; } -static void integer_to_string_b(DstBuffer *buffer, int64_t x) { +static void integer_to_string_b(DstBuffer *buffer, int32_t x) { dst_buffer_extra(buffer, DST_BUFSIZE); buffer->count += integer_to_string_impl(buffer->data + buffer->count, x); } -static const uint8_t *integer_to_string(int64_t x) { +static const uint8_t *integer_to_string(int32_t x) { uint8_t buf[DST_BUFSIZE]; return dst_string(buf, integer_to_string_impl(buf, x)); } @@ -641,7 +641,7 @@ const uint8_t *dst_formatc(const char *format, ...) { real_to_string_b(bufp, va_arg(args, double)); break; case 'd': - integer_to_string_b(bufp, va_arg(args, int64_t)); + integer_to_string_b(bufp, va_arg(args, int32_t)); break; case 'S': { @@ -653,7 +653,7 @@ const uint8_t *dst_formatc(const char *format, ...) { dst_buffer_push_cstring(bufp, va_arg(args, const char *)); break; case 'c': - dst_buffer_push_u8(bufp, va_arg(args, int64_t)); + dst_buffer_push_u8(bufp, va_arg(args, long)); break; case 'v': { diff --git a/core/strtod.c b/core/strtod.c index 00630f48..bc7d7b6a 100644 --- a/core/strtod.c +++ b/core/strtod.c @@ -123,7 +123,8 @@ static double convert( : ldexp(mantissa, exponent2); } -/* Result of scanning a number source */ +/* Result of scanning a number source string. Will be further processed + * depending on the desired resultant type. */ struct DstScanRes { uint64_t mant; int32_t ex; diff --git a/core/value.c b/core/value.c index ff4d070c..9c69466f 100644 --- a/core/value.c +++ b/core/value.c @@ -67,9 +67,13 @@ int32_t dst_hash(Dst x) { int32_t hash = 0; switch (dst_type(x)) { case DST_NIL: + hash = 0; + break; case DST_FALSE: + hash = 1; + break; case DST_TRUE: - hash = dst_type(x); + hash = 2; break; case DST_STRING: case DST_SYMBOL: @@ -81,6 +85,8 @@ int32_t dst_hash(Dst x) { case DST_STRUCT: hash = dst_struct_hash(dst_unwrap_struct(x)); break; + case DST_INTEGER: + hash = dst_unwrap_integer(x); default: if (sizeof(double) == sizeof(void *)) { /* Assuming 8 byte pointer */ diff --git a/core/vm.c b/core/vm.c index 3cd67ced..f7ced1a0 100644 --- a/core/vm.c +++ b/core/vm.c @@ -532,6 +532,7 @@ static int dst_continue(Dst *returnreg) { case DOP_TRANSFER: { + int status; DstFiber *nextfiber; DstStackFrame *frame = dst_stack_frame(stack); Dst temp = stack[oparg(2, 0xFF)]; @@ -547,14 +548,31 @@ static int dst_continue(Dst *returnreg) { *returnreg = retreg; return 0; } - vm_assert(nextfiber->status == DST_FIBER_PENDING, "can only transfer to pending fiber"); + status = nextfiber->status; + vm_assert(status == DST_FIBER_PENDING || + status == DST_FIBER_NEW, "can only transfer to new or pending fiber"); frame->pc = pc; dst_vm_fiber->status = DST_FIBER_PENDING; dst_vm_fiber = nextfiber; vm_init_fiber_state(); - stack[oparg(1, 0xFF)] = retreg; - pc++; - vm_next(); + if (status == DST_FIBER_PENDING) { + /* The next fiber is currently on a transfer instruction. */ + stack[oparg(1, 0xFF)] = retreg; + pc++; + } else { + /* The next fiber is new and is on the first instruction */ + if ((func->def->flags & DST_FUNCDEF_FLAG_VARARG) && + !func->def->arity) { + /* Fully var arg function */ + Dst *tup = dst_tuple_begin(1); + tup[0] = retreg; + stack[0] = dst_wrap_tuple(dst_tuple_end(tup)); + } else if (func->def->arity) { + /* Non zero arity function */ + stack[0] = retreg; + } + } + vm_checkgc_next(); } case DOP_PUT: @@ -569,7 +587,7 @@ static int dst_continue(Dst *returnreg) { stack[oparg(2, 0xFF)], oparg(3, 0xFF)); ++pc; - vm_next(); + vm_checkgc_next(); case DOP_GET: stack[oparg(1, 0xFF)] = dst_get( diff --git a/dsttest/suite0.dst b/dsttest/suite0.dst index d0cc0d7e..699cc2a1 100644 --- a/dsttest/suite0.dst +++ b/dsttest/suite0.dst @@ -112,6 +112,13 @@ # Fiber tests +(def error (asm '{ + arity 1 + bytecode [ + (error 0) + ] +})) + (def afiber (fiber (fn [x] (error (string "hello, " x))))) @@ -124,10 +131,10 @@ (def t (fiber (fn [] (transfer nil 1) (transfer nil 2) 3))) -(assert (= 1 (transfer t)) "initial transfer to new thread") -(assert (= 2 (transfer t)) "second transfer to thread") -(assert (= 3 (transfer t)) "return from thread") -(assert (= (status t) "dead") "finished thread is dead") +(assert (= 1 (transfer t)) "initial transfer to new fiber") +(assert (= 2 (transfer t)) "second transfer to fiber") +(assert (= 3 (transfer t)) "return from fiber") +(assert (= (status t) "dead") "finished fiber is dead") # Var arg tests @@ -139,13 +146,6 @@ ] })) -(def error (asm '{ - arity 1 - bytecode [ - (error 0) - ] -})) - (def vargf (fn [more] (apply + more))) (assert (= 0 (vargf [])) "var arg no arguments") @@ -169,4 +169,4 @@ # report (print "\n" num-tests-passed " of " num-tests-run " tests passed\n") -(if (not (= num-tests-passed num-tests-run)) (exit! 1)) +(if (not= num-tests-passed num-tests-run) (exit! 1)) diff --git a/include/dst/dsttypes.h b/include/dst/dsttypes.h index acf2b44b..038bcc01 100644 --- a/include/dst/dsttypes.h +++ b/include/dst/dsttypes.h @@ -319,7 +319,8 @@ struct DstFiber { int32_t stacktop; /* Top of stack. Where values are pushed and popped from. */ int32_t capacity; enum { - DST_FIBER_PENDING = 0, + DST_FIBER_PENDING, + DST_FIBER_NEW, DST_FIBER_ALIVE, DST_FIBER_DEAD, DST_FIBER_ERROR