diff --git a/client/main.c b/client/main.c index 05338763..98e7d076 100644 --- a/client/main.c +++ b/client/main.c @@ -42,6 +42,10 @@ int debug_compile_and_run(Gst *vm, GstValue ast, GstValue env) { printf("Compiler error: %s\n", c.error); return 1; } + /* Print disasm */ + printf("%c[31m===== Begin Disassembly =====\n", 27); + gst_dasm_function(stdout, func.data.function); + printf("===== End Disassembly =====%c[0m\n", 27); /* Execute function */ if (gst_run(vm, func)) { if (vm->crash) { @@ -132,7 +136,7 @@ int debug_repl(Gst *vm) { /* Add _ to environemt */ st = gst_struct_begin(vm, 1); gst_struct_put(st, gst_string_cv(vm, "_"), vm->ret); - if (0 == debug_compile_and_run(vm, gst_parse_consume(&p), gst_wrap_struct(gst_struct_end(vm, st)))) { + if (!debug_compile_and_run(vm, gst_parse_consume(&p), gst_wrap_struct(gst_struct_end(vm, st)))) { printf("%s\n", gst_to_string(vm, vm->ret)); } } diff --git a/core/compile.c b/core/compile.c index 7c6e71e0..c1e50083 100644 --- a/core/compile.c +++ b/core/compile.c @@ -684,71 +684,6 @@ static Slot compile_if(GstCompiler *c, FormOptions opts, const GstValue *form) { return condition; } -/* Try catch special */ -static Slot compile_try(GstCompiler *c, FormOptions opts, const GstValue *form) { - GstScope *scope = c->tail; - GstBuffer *buffer = c->buffer; - Slot body; - uint16_t errorIndex; - uint32_t countAtTry, countTemp, countAtJump; - countAtJump = 0; - /* Check argument count */ - if (gst_tuple_length(form) < 3 || gst_tuple_length(form) > 4) - c_error(c, "try takes either 2 or 3 arguments"); - /* Check for symbol to bind error to */ - if (form[1].type != GST_STRING) - c_error(c, "expected string at start of try"); - /* Add subscope for error variable */ - GstScope *subScope = compiler_push_scope(c, 1); - errorIndex = compiler_declare_symbol(c, subScope, form[1]); - /* Leave space for try instruction */ - countAtTry = buffer->count; - buffer->count += sizeof(uint32_t) + 2 * sizeof(uint16_t); - /* Compile the body */ - body = compile_value(c, opts, form[2]); - if (opts.isTail) { - compiler_return(c, body); - } else { - /* If we need to jump over the catch, do so */ - if (gst_tuple_length(form) == 4) { - countAtJump = buffer->count; - buffer->count += sizeof(int32_t) + sizeof(uint16_t); - } - } - /* Reinsert try jump with correct index */ - countTemp = buffer->count; - buffer->count = countAtTry; - gst_buffer_push_u16(c->vm, buffer, GST_OP_TRY); - gst_buffer_push_u16(c->vm, buffer, errorIndex); - gst_buffer_push_i32(c->vm, buffer, (countTemp - countAtTry) / 2); - buffer->count = countTemp; - /* Compile catch path */ - if (gst_tuple_length(form) == 4) { - Slot catch; - countAtJump = buffer->count; - catch = compile_value(c, opts, form[3]); - if (opts.isTail) compiler_return(c, catch); - compiler_drop_slot(c, scope, catch); - } else if (opts.isTail) { - compiler_return(c, nil_slot()); - } - /* Reset the second jump length */ - if (!opts.isTail && gst_tuple_length(form) == 4) { - countTemp = buffer->count; - buffer->count = countAtJump; - gst_buffer_push_u16(c->vm, buffer, GST_OP_JMP); - gst_buffer_push_i32(c->vm, buffer, (countTemp - countAtJump) / 2); - buffer->count = countTemp; - } - /* Untry */ - gst_buffer_push_u16(c->vm, buffer, GST_OP_UTY); - /* Pop the error scope */ - compiler_pop_scope(c); - if (opts.isTail) - body.hasReturned = 1; - return body; -} - /* While special */ static Slot compile_while(GstCompiler *c, FormOptions opts, const GstValue *form) { Slot cond; @@ -885,14 +820,6 @@ static SpecialFormHelper get_special(const GstValue *form) { } } break; - case 't': - { - if (gst_string_length(name) == 3 && - name[1] == 'r' && - name[2] == 'y') { - return compile_try; - } - } case 'w': { if (gst_string_length(name) == 5 && @@ -991,11 +918,15 @@ static Slot compile_form(GstCompiler *c, FormOptions opts, const GstValue *form) /* Free up some slots */ compiler_drop_slot(c, scope, callee); compiler_tracker_free(c, scope, &tracker); + /* Prepare next stack frame */ + gst_buffer_push_u16(c->vm, buffer, GST_OP_PSK); + gst_buffer_push_u16(c->vm, buffer, gst_tuple_length(form) - 1); + /* Write the location of all of the arguments */ + compiler_tracker_write(c, &tracker, 0); /* If this is in tail position do a tail call. */ if (opts.isTail) { gst_buffer_push_u16(c->vm, buffer, GST_OP_TCL); gst_buffer_push_u16(c->vm, buffer, callee.index); - gst_buffer_push_u16(c->vm, buffer, gst_tuple_length(form) - 1); ret.hasReturned = 1; ret.isNil = 1; } else { @@ -1003,10 +934,7 @@ static Slot compile_form(GstCompiler *c, FormOptions opts, const GstValue *form) gst_buffer_push_u16(c->vm, buffer, GST_OP_CAL); gst_buffer_push_u16(c->vm, buffer, callee.index); gst_buffer_push_u16(c->vm, buffer, ret.index); - gst_buffer_push_u16(c->vm, buffer, gst_tuple_length(form) - 1); } - /* Write the location of all of the arguments */ - compiler_tracker_write(c, &tracker, 0); return ret; } } diff --git a/core/disasm.c b/core/disasm.c index 85353fe3..623d7239 100644 --- a/core/disasm.c +++ b/core/disasm.c @@ -191,29 +191,23 @@ void gst_dasm(FILE * out, uint16_t *byteCode, uint32_t len) { case GST_OP_TUP: current += dasm_varg_op(out, current, "tuple", 1); break; - case GST_OP_ERR: - current += dasm_fixed_op(out, current, "error", 1); - break; - case GST_OP_TRY: - dasm_print_arg(out, "try"); - dasm_print_slot(out, current[1]); - dasm_print_i32(out, *(int32_t *)(current + 2)); - current += 4; - break; - case GST_OP_UTY: - current += dasm_fixed_op(out, current, "untry", 0); - break; case GST_OP_RET: current += dasm_fixed_op(out, current, "return", 1); break; case GST_OP_RTN: current += dasm_fixed_op(out, current, "returnNil", 0); break; + case GST_OP_PSK: + current += dasm_varg_op(out, current, "pushArgs", 0); + break; + case GST_OP_PAR: + current += dasm_fixed_op(out, current, "pushSeq", 1); + break; case GST_OP_CAL: - current += dasm_varg_op(out, current, "call", 2); + current += dasm_fixed_op(out, current, "call", 2); break; case GST_OP_TCL: - current += dasm_varg_op(out, current, "tailCall", 1); + current += dasm_fixed_op(out, current, "tailCall", 1); break; } fprintf(out, "\n"); diff --git a/core/gc.c b/core/gc.c index dea231a9..f66acf0e 100644 --- a/core/gc.c +++ b/core/gc.c @@ -267,8 +267,10 @@ void gst_collect(Gst *vm) { /* Thread can be null */ if (vm->thread) gst_mark_value(vm, gst_wrap_thread(vm->thread)); - gst_mark_value(vm, gst_wrap_object(vm->modules)); - gst_mark_value(vm, gst_wrap_object(vm->registry)); + if (vm->modules) + gst_mark_value(vm, gst_wrap_object(vm->modules)); + if (vm->registry) + gst_mark_value(vm, gst_wrap_object(vm->registry)); gst_mark_value(vm, vm->ret); if (vm->scratch) gc_header(vm->scratch)->color = vm->black; diff --git a/core/serialize.c b/core/serialize.c index 4bb29c47..4e6a357d 100644 --- a/core/serialize.c +++ b/core/serialize.c @@ -39,7 +39,7 @@ * Byte 208: Array - [u32 length]*[value... elements] * Byte 209: Tuple - [u32 length]*[value... elements] * Byte 210: Thread - [u8 state][u32 frames]*[[value callee][value env] - * [u32 pcoffset][u32 erroffset][u16 ret][u16 errloc][u16 size]*[value ...stack] + * [u32 pcoffset][u16 ret][u16 args][u16 size]*[value ...stack] * Byte 211: Object - [value parent][u32 length]*2*[value... kvs] * Byte 212: FuncDef - [u32 locals][u32 arity][u32 flags][u32 literallen]*[value... * literals][u32 bytecodelen]*[u16... bytecode] @@ -242,8 +242,8 @@ static const char *gst_deserialize_impl( /* Add frames */ for (i = 0; i < length; ++i) { GstValue callee, env; - uint32_t pcoffset, erroffset; - uint16_t ret, errloc, size, j; + uint32_t pcoffset; + uint16_t ret, args, size, j; /* Create a new frame */ if (i > 0) gst_thread_beginframe(vm, t, nil, 0); @@ -253,20 +253,18 @@ static const char *gst_deserialize_impl( err = gst_deserialize_impl(vm, data, end, &data, visited, &env); if (err != NULL) return err; read_u32(pcoffset); - read_u32(erroffset); read_u16(ret); - read_u16(errloc); + read_u16(args); read_u16(size); /* Set up the stack */ stack = gst_thread_stack(t); if (callee.type == GST_FUNCTION) { gst_frame_pc(stack) = callee.data.function->def->byteCode + pcoffset; - gst_frame_errjmp(stack) = callee.data.function->def->byteCode + erroffset; if (env.type == GST_FUNCENV) gst_frame_env(stack) = env.data.env; } gst_frame_ret(stack) = ret; - gst_frame_errloc(stack) = errloc; + gst_frame_args(stack) = args; gst_frame_size(stack) = size; gst_frame_prevsize(stack) = prevsize; prevsize = size; diff --git a/core/stl.c b/core/stl.c index d6df5300..e36f6015 100644 --- a/core/stl.c +++ b/core/stl.c @@ -249,7 +249,7 @@ int gst_stl_object(Gst *vm) { GstObject *object; if (count % 2 != 0) gst_c_throwc(vm, "expected even number of arguments"); - object = gst_object(vm, count * 2); + object = gst_object(vm, 4 * count); for (i = 0; i < count; i += 2) gst_object_put(vm, object, gst_arg(vm, i), gst_arg(vm, i + 1)); gst_c_return(vm, gst_wrap_object(object)); @@ -457,6 +457,7 @@ static const GstModuleItem const std_module[] = { {"exit", gst_stl_exit}, {"rawget", gst_stl_rawget}, {"rawset", gst_stl_rawset}, + {"next", gst_stl_next}, {"error", gst_stl_error}, {"serialize", gst_stl_serialize}, {"open", gst_stl_open}, diff --git a/core/thread.c b/core/thread.c index 1c5c6e7d..f7551873 100644 --- a/core/thread.c +++ b/core/thread.c @@ -36,10 +36,9 @@ GstThread *gst_thread(Gst *vm, GstValue callee, uint32_t capacity) { gst_frame_size(stack) = 0; gst_frame_prevsize(stack) = 0; gst_frame_ret(stack) = 0; - gst_frame_errloc(stack) = 0; + gst_frame_args(stack) = 0; gst_frame_pc(stack) = NULL; gst_frame_env(stack) = NULL; - gst_frame_errjmp(stack) = NULL; gst_frame_callee(stack) = callee; gst_thread_endframe(vm, thread); thread->parent = NULL; @@ -115,7 +114,6 @@ GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uin newStack = oldStack + frameOffset; gst_frame_prevsize(newStack) = gst_frame_size(oldStack); gst_frame_env(newStack) = NULL; - gst_frame_errjmp(newStack) = NULL; gst_frame_size(newStack) = 0; gst_frame_callee(newStack) = callee; thread->count += frameOffset; @@ -144,6 +142,8 @@ void gst_thread_endframe(Gst *vm, GstThread *thread) { gst_thread_pushnil(vm, thread, locals - gst_frame_size(stack)); } } + stack = thread->data + thread->count; + gst_frame_args(stack) = gst_frame_size(stack) + GST_FRAME_SIZE; } } @@ -173,44 +173,3 @@ GstValue *gst_thread_popframe(Gst *vm, GstThread *thread) { else return NULL; } - -/* Move the current stack frame over its parent stack frame, allowing - * for primitive tail calls. */ -GstValue *gst_thread_tail(Gst *vm, GstThread *thread) { - GstFuncEnv *env; - GstValue *stack = thread->data + thread->count; - GstValue *nextStack = gst_thread_popframe(vm, thread); - uint32_t i; - - if (nextStack == NULL) return NULL; - env = gst_frame_env(nextStack); - - /* Check for old closures */ - if (env != NULL) { - uint32_t size = gst_frame_size(stack); - env->thread = NULL; - env->stackOffset = size; - env->values = gst_alloc(vm, sizeof(GstValue) * size); - gst_memcpy(env->values, stack, sizeof(GstValue) * size); - } - - /* Modify new closure */ - env = gst_frame_env(stack); - if (env != NULL) { - env->stackOffset = thread->count; - } - - /* Copy over (some of) stack frame. Leave ret and prevsize untouched. */ - gst_frame_env(nextStack) = env; - gst_frame_size(nextStack) = gst_frame_size(stack); - gst_frame_pc(nextStack) = gst_frame_pc(stack); - gst_frame_errjmp(nextStack) = gst_frame_errjmp(stack); - gst_frame_errloc(nextStack) = gst_frame_errloc(stack); - gst_frame_callee(nextStack) = gst_frame_callee(stack); - - /* Copy stack arguments */ - for (i = 0; i < gst_frame_size(nextStack); ++i) - nextStack[i] = stack[i]; - - return nextStack; -} diff --git a/core/vm.c b/core/vm.c index a14a2726..a3c4b54b 100644 --- a/core/vm.c +++ b/core/vm.c @@ -22,33 +22,23 @@ #include -/* Macros for errors in the vm */ - -/* Exit from the VM normally */ -#define gst_exit(vm, r) return ((vm)->ret = (r), GST_RETURN_OK) - -/* Bail from the VM with an error string. */ -#define gst_error(vm, e) do { (vm)->ret = gst_string_cv((vm), (e)); goto vm_error; } while (0) - -/* Crash. Not catchable, unlike error. */ -#define gst_crash(vm, e) return ((vm)->crash = (e), GST_RETURN_CRASH) - -/* Error if the condition is false */ -#define gst_assert(vm, cond, e) do {if (!(cond)){gst_error((vm), (e));}} while (0) - static const char GST_NO_UPVALUE[] = "no upvalue"; static const char GST_EXPECTED_FUNCTION[] = "expected function"; static const char GST_EXPECTED_NUMBER_ROP[] = "expected right operand to be number"; static const char GST_EXPECTED_NUMBER_LOP[] = "expected left operand to be number"; -/* Start running the VM from where it left off. Continue running - * until the stack size is smaller than minStackSize. */ -static int gst_continue_size(Gst *vm, uint32_t stackBase) { +/* Start running the VM from where it left off. */ +int gst_continue(Gst *vm) { /* VM state */ GstValue *stack; GstValue temp, v1, v2; uint16_t *pc; +#define gst_exit(vm, r) return ((vm)->ret = (r), GST_RETURN_OK) +#define gst_error(vm, e) do { (vm)->ret = gst_string_cv((vm), (e)); goto vm_error; } while (0) +#define gst_crash(vm, e) return ((vm)->crash = (e), GST_RETURN_CRASH) +#define gst_assert(vm, cond, e) do {if (!(cond)){gst_error((vm), (e));}} while (0) + /* Intialize local state */ stack = vm->thread->data + vm->thread->count; pc = gst_frame_pc(stack); @@ -188,20 +178,9 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) { } break; - case GST_OP_TRY: /* Begin try block */ - gst_frame_errloc(stack) = pc[1]; - gst_frame_errjmp(stack) = pc + *(uint32_t *)(pc + 2); - pc += 4; - continue; - - case GST_OP_UTY: /* End try block */ - gst_frame_errjmp(stack) = NULL; - pc++; - continue; - case GST_OP_RTN: /* Return nil */ stack = gst_thread_popframe(vm, vm->thread); - if (vm->thread->count < stackBase) { + if (vm->thread->count < GST_FRAME_SIZE) { vm->ret.type = GST_NIL; return GST_RETURN_OK; } @@ -212,7 +191,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) { case GST_OP_RET: /* Return */ temp = stack[pc[1]]; stack = gst_thread_popframe(vm, vm->thread); - if (vm->thread->count < stackBase) { + if (vm->thread->count < GST_FRAME_SIZE) { vm->ret = temp; return GST_RETURN_OK; } @@ -220,71 +199,132 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) { stack[gst_frame_ret(stack)] = temp; continue; - case GST_OP_CAL: /* Call */ - case GST_OP_TCL: /* Tail call */ + case GST_OP_PSK: /* Push stack */ { - GstValue *oldStack; - temp = stack[pc[1]]; - int isTCall = *pc == GST_OP_TCL; - uint32_t i, arity, offset, size; - uint16_t ret = pc[2]; - offset = isTCall ? 3 : 4; - arity = pc[offset - 1]; - /* Push new frame */ - if (temp.type != GST_FUNCTION && temp.type != GST_CFUNCTION) - gst_error(vm, GST_EXPECTED_FUNCTION); - stack = gst_thread_beginframe(vm, vm->thread, temp, arity); - oldStack = stack - GST_FRAME_SIZE - gst_frame_prevsize(stack); + uint16_t arity = pc[1]; + uint16_t i; + uint16_t newBase = gst_frame_size(stack) + GST_FRAME_SIZE; + gst_frame_args(stack) = newBase; + gst_thread_ensure_extra(vm, vm->thread, GST_FRAME_SIZE + arity); + stack = gst_thread_stack(vm->thread); + gst_frame_size(stack) += GST_FRAME_SIZE + arity; + /* Nil stuff */ + for (i = 0; i < GST_FRAME_SIZE; ++i) + stack[newBase + i - GST_FRAME_SIZE].type = GST_NIL; /* Write arguments */ - size = gst_frame_size(stack); for (i = 0; i < arity; ++i) - stack[i + size - arity] = oldStack[pc[offset + i]]; - /* Finish new frame */ - gst_thread_endframe(vm, vm->thread); - /* Check tail call - if so, replace frame. */ - if (isTCall) { - stack = gst_thread_tail(vm, vm->thread); - } else { - gst_frame_ret(oldStack) = ret; - } - /* Call function */ - temp = gst_frame_callee(stack); - if (temp.type == GST_FUNCTION) { - /* Save pc and set new pc */ - if (!isTCall) - gst_frame_pc(oldStack) = pc + offset + arity; - pc = temp.data.function->def->byteCode; - } else { - int status; - gst_frame_pc(stack) = pc; - vm->ret.type = GST_NIL; - status = temp.data.cfunction(vm); - stack = gst_thread_popframe(vm, vm->thread); - if (status == GST_RETURN_OK) { - if (vm->thread->count < stackBase) { - return status; - } else { - stack[gst_frame_ret(stack)] = vm->ret; - if (isTCall) - pc = gst_frame_pc(stack); - else - pc += offset + arity; - } - } else { - goto vm_error; - } - } + stack[newBase + i] = stack[pc[2 + i]]; + pc += 2 + arity; } break; + case GST_OP_PAR: /* Push array or tuple */ + { + uint32_t count, i, oldsize; + const GstValue *data; + temp = stack[pc[1]]; + if (temp.type == GST_TUPLE) { + count = gst_tuple_length(temp.data.tuple); + data = temp.data.tuple; + } else if (temp.type == GST_ARRAY){ + count = temp.data.array->count; + data = temp.data.array->data; + } else { + gst_error(vm, "expected array or tuple"); + } + oldsize = gst_frame_size(stack); + gst_thread_pushnil(vm, vm->thread, count); + stack = gst_thread_stack(vm->thread); + for (i = 0; i < count; ++i) + stack[oldsize + i] = data[i]; + pc += 2; + } + break; + + case GST_OP_CAL: /* Call */ + { + uint16_t newStackIndex = gst_frame_args(stack); + uint16_t size = gst_frame_size(stack); + temp = stack[pc[1]]; + gst_frame_ret(stack) = pc[2]; + gst_frame_pc(stack) = pc + 3; + if (newStackIndex < GST_FRAME_SIZE) + gst_error(vm, "invalid call instruction"); + vm->thread->count += newStackIndex; + stack = gst_thread_stack(vm->thread); + gst_frame_size(stack) = size - newStackIndex; + gst_frame_prevsize(stack) = newStackIndex; + gst_frame_callee(stack) = temp; + } + goto common_function_call; + + case GST_OP_TCL: /* Tail call */ + { + uint16_t newStackIndex = gst_frame_args(stack); + uint16_t size = gst_frame_size(stack); + uint16_t i; + temp = stack[pc[1]]; + /* Check for closures */ + if (gst_frame_env(stack)) { + GstFuncEnv *env = gst_frame_env(stack); + env->thread = NULL; + env->stackOffset = size; + env->values = gst_alloc(vm, sizeof(GstValue) * size); + gst_memcpy(env->values, stack, sizeof(GstValue) * size); + } + if (newStackIndex) + for (i = 0; i < size - newStackIndex; ++i) + stack[i] = stack[newStackIndex + i]; + gst_frame_size(stack) = size - newStackIndex; + gst_frame_callee(stack) = temp; + } + goto common_function_call; + + /* Code common to all function calls */ + common_function_call: + gst_frame_args(stack) = 0; + gst_frame_env(stack) = NULL; + gst_thread_endframe(vm, vm->thread); + stack = vm->thread->data + vm->thread->count; + gst_frame_args(stack) = 0; + temp = gst_frame_callee(stack); + if (temp.type == GST_FUNCTION) { + pc = temp.data.function->def->byteCode; + } else if (temp.type == GST_CFUNCTION) { + int status; + vm->ret.type = GST_NIL; + status = temp.data.cfunction(vm); + stack = gst_thread_popframe(vm, vm->thread); + if (status == GST_RETURN_OK) { + if (vm->thread->count < GST_FRAME_SIZE) { + return status; + } else { + stack[gst_frame_ret(stack)] = vm->ret; + pc = gst_frame_pc(stack); + } + } else { + goto vm_error; + } + } else { + gst_error(vm, GST_EXPECTED_FUNCTION); + } + break; + + case GST_OP_YLD: /* Yield to new thread */ + temp = stack[pc[1]]; + v1 = stack[pc[2]]; + gst_assert(vm, v1.type == GST_THREAD, "expected thread"); + gst_assert(vm, v1.data.thread->status != GST_THREAD_DEAD, "cannot rejoin dead thread"); + gst_frame_pc(stack) = pc + 3; + vm->thread = v1.data.thread; + stack = vm->thread->data + vm->thread->count; + pc = gst_frame_pc(stack); + continue; + /* Faster implementations of standard functions * These opcodes are nto strictlyre required and can * be reimplemented with stanard library functions */ - case GST_OP_ERR: /* Throw error */ - vm->ret = stack[pc[1]]; - goto vm_error; - #define OP_BINARY_MATH(op) \ v1 = stack[pc[2]]; \ v2 = stack[pc[3]]; \ @@ -375,7 +415,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) { { uint32_t i = 3; uint32_t kvs = pc[2]; - GstObject *o = gst_object(vm, 2 * kvs + 2); + GstObject *o = gst_object(vm, 2 * kvs); kvs = kvs + 3; while (i < kvs) { v1 = stack[pc[i++]]; @@ -403,30 +443,16 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) { } break; - case GST_OP_YLD: /* Yield from function */ - temp = stack[pc[1]]; - if (vm->thread->parent == NULL) { - vm->ret = temp; - return GST_RETURN_OK; - } - gst_frame_pc(stack) = pc + 2; - vm->thread = vm->thread->parent; - stack = vm->thread->data + vm->thread->count; - pc = gst_frame_pc(stack); - break; /* Handle errors from c functions and vm opcodes */ vm_error: - if (stack == NULL) + if (stack == NULL || vm->thread->parent == NULL) return GST_RETURN_ERROR; - while (gst_frame_errjmp(stack) == NULL) { - stack = gst_thread_popframe(vm, vm->thread); - if (vm->thread->count < stackBase) - return GST_RETURN_ERROR; - } - pc = gst_frame_errjmp(stack); - stack[gst_frame_errloc(stack)] = vm->ret; - break; + vm->thread->status = GST_THREAD_DEAD; + vm->thread = vm->thread->parent; + stack = vm->thread->data + vm->thread->count; + pc = gst_frame_pc(stack); + continue; } /* end switch */ @@ -439,11 +465,6 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) { } -/* Continue running the VM after it has stopped */ -int gst_continue(Gst *vm) { - return gst_continue_size(vm, vm->thread->count); -} - /* Run the vm with a given function. This function is * called to start the vm. */ int gst_run(Gst *vm, GstValue callee) { diff --git a/include/gst/gst.h b/include/gst/gst.h index 439ae53a..4bbad92a 100644 --- a/include/gst/gst.h +++ b/include/gst/gst.h @@ -79,17 +79,16 @@ /* Stack frame manipulation */ /* Size of stack frame in number of values */ -#define GST_FRAME_SIZE 5 +#define GST_FRAME_SIZE 4 /* Macros for referencing a stack frame given a stack */ #define gst_frame_callee(s) (*(s - 1)) #define gst_frame_size(s) ((s - 2)->data.hws[0]) #define gst_frame_prevsize(s) ((s - 2)->data.hws[1]) -#define gst_frame_errloc(s) ((s - 2)->data.hws[2]) +#define gst_frame_args(s) ((s - 2)->data.hws[2]) #define gst_frame_ret(s) ((s - 2)->data.hws[3]) #define gst_frame_pc(s) ((s - 3)->data.u16p) -#define gst_frame_errjmp(s) ((s - 4)->data.u16p) -#define gst_frame_env(s) ((s - 5)->data.env) +#define gst_frame_env(s) ((s - 4)->data.env) /* C function helpers */ @@ -109,7 +108,7 @@ #ifndef GST_OUT_OF_MEMORY #include #include -#define GST_OUT_OF_MEMORY do { printf("out of memory.\n"); exit(1); } while (0) +#define GST_OUT_OF_MEMORY do { printf("out of memory\n"); exit(1); } while (0) #endif /* Max search depth for classes. */ @@ -196,7 +195,7 @@ struct GstValue { }; /* A lightweight thread in gst. Does not correspond to - * operating system threads. Used in coroutines. */ + * operating system threads. Used in coroutines and continuations. */ struct GstThread { uint32_t count; uint32_t capacity; @@ -292,7 +291,7 @@ struct Gst { GstObject *registry; /* Return state */ const char *crash; - GstValue ret; /* Returned value from gst_start. Also holds errors. */ + GstValue ret; /* Returned value from gst_start. */ }; /* Bytecode */ @@ -323,11 +322,10 @@ enum GstOpCode { GST_OP_ARR, /* Create array */ GST_OP_DIC, /* Create object */ GST_OP_TUP, /* Create tuple */ - GST_OP_ERR, /* Throw error */ - GST_OP_TRY, /* Begin try block */ - GST_OP_UTY, /* End try block */ GST_OP_RET, /* Return from function */ GST_OP_RTN, /* Return nil */ + GST_OP_PSK, /* Push stack */ + GST_OP_PAR, /* Push array or tuple */ GST_OP_CAL, /* Call function */ GST_OP_TCL, /* Tail call */ GST_OP_YLD /* Yield from function */ @@ -419,8 +417,6 @@ void gst_thread_tuplepack(Gst *vm, GstThread *thread, uint32_t n); GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity); void gst_thread_endframe(Gst *vm, GstThread *thread); GstValue *gst_thread_popframe(Gst *vm, GstThread *thread); -GstValue *gst_thread_tail(Gst *vm, GstThread *thread); - /****/ /* Value manipulation */ diff --git a/libs/pp.gst b/libs/pp.gst new file mode 100644 index 00000000..ed3a2503 --- /dev/null +++ b/libs/pp.gst @@ -0,0 +1,20 @@ +# Pretty print + +# Reindent a function to be more deeply indented +(: reindent (fn [x] x)) + +(: handler { + "number" tostring + "nil" tostring + "boolean" tostring + "userdata" tostring + "cfunction" tostring + "function" tostring + "string" tostring # change to unquote string + "buffer" tostring + "array" tostring + "tuple" tostring + "object" tostring + "struct" tostring + "thread" tostring + })