From a3f010f60791f2c9c551a5f96d959642ae2b90f1 Mon Sep 17 00:00:00 2001 From: cassowarii <2374677+cassowarii@users.noreply.github.com> Date: Sun, 5 Jul 2026 15:05:57 -0700 Subject: [PATCH] more portable printing; callbacks from native code to script --- src/compile/emit.c | 2 +- src/compile/print_ir.c | 2 +- src/data/closure.c | 2 +- src/data/hashtable.c | 2 +- src/data/methods.c | 52 +++++++++++++++++++++------------ src/data/string.c | 4 +-- src/data/symbol.c | 2 +- src/vm/exec.c | 78 ++++++++++++++++++++++++++++++++++++-------------- src/vm/exec.h | 16 +++++++++-- src/vm/operations.c | 10 +++---- 10 files changed, 116 insertions(+), 54 deletions(-) diff --git a/src/compile/emit.c b/src/compile/emit.c index acab122..ffee6d2 100644 --- a/src/compile/emit.c +++ b/src/compile/emit.c @@ -33,7 +33,7 @@ void sbEmit_compile_program(sbVmProgram *vp, sbIrProgram *ir) { /* --- */ void emit_arg(sbVmCompiler *cm, i64 actual_number) { - debug(" arg %lld\n", actual_number); + debug(" arg %lld\n", (long long)actual_number); u8 buf[9]; u64 number = actual_number; if (0 <= actual_number && actual_number < 253) { diff --git a/src/compile/print_ir.c b/src/compile/print_ir.c index ab71f23..8643d0a 100644 --- a/src/compile/print_ir.c +++ b/src/compile/print_ir.c @@ -57,7 +57,7 @@ static void print_expr(sbIrExpr *e) { if (e->value.type == IT_NIL) { debug("nil"); } else if (e->value.type == IT_INTEGER) { - debug("%lld", e->value.integer); + debug("%lld", (long long)e->value.integer); } else { debug("some value"); } diff --git a/src/data/closure.c b/src/data/closure.c index e89942c..4207a30 100644 --- a/src/data/closure.c +++ b/src/data/closure.c @@ -85,5 +85,5 @@ hV sbClosure_get_ref(hClosure which, usize index) { static sbClosure *find_closure_by_handle(hRef handle) { if (!(handle & FLAG_REAL)) PANIC("null closure"); - return sbPool_get_entry(&g_closure_pool, handle); + return sbPool_get_entry(&g_closure_pool, handle & ~FLAG_REAL); } diff --git a/src/data/hashtable.c b/src/data/hashtable.c index b18fa8b..3a9b1cf 100644 --- a/src/data/hashtable.c +++ b/src/data/hashtable.c @@ -73,7 +73,7 @@ sbHashValue sbHash_hash_obj(hV *obj) { const char *strval = sbString_get_value(obj->string, scratch, &length); return sbHash_hash_bytes(strval, length); } else { - PANIC("don't know how to hash object of type %lld", obj->type); + PANIC("don't know how to hash object of type %lld", (long long)obj->type); } } diff --git a/src/data/methods.c b/src/data/methods.c index dc8bd0a..d554db3 100644 --- a/src/data/methods.c +++ b/src/data/methods.c @@ -6,6 +6,9 @@ #define METHOD_IS(name) (!sbstrncmp(method_name, name, sizeof(name))) +void list_each_cfunc(hVm vm, flag init); +void list_map_cfunc(hVm vm, flag init); + void sbList_method(hV list, hVm vm) { if (list.type != IT_LIST) { CHECK("can't call sbList_method on something that isn't a list"); @@ -24,26 +27,39 @@ void sbList_method(hV list, hVm vm) { if (num_params != 1) { PANIC("wrong number of arguments passed to list#each!"); } - hV loop_func = sbVm_pop(vm); - sbVm_pop(vm); /* remove method name */ - usize length; - hV *iter_values = sbList_get_value(list.list, &length); - for (usize i = 0; i < length; i++) { - /* TODO : This doesn't work! It almost works, but when we call the - * callback func, we need to, like, pause this function and run more - * VM instructions, then come back to this one. How do? :thinking emoji: */ - printf("index %zu\n", i); - sbVm_push(vm, iter_values[i]); - sbVm_push(vm, HVINT(1)); - printf("call loop-func\n"); - sbVm_call_func(vm, loop_func); - /* remove result of loop_func */ - printf("loop-func done\n"); - sbVm_pop(vm); - } + sbVm_push(vm, list); + sbVm_call_c_func(vm, list_each_cfunc); } } else { - PANIC("method name to list is not symbol! (%lld)", method_name_val->type); + PANIC("method name to list is not symbol! (%ld)", method_name_val->type); } } +void list_each_cfunc(hVm vm, flag init) { + if (init) { + /* store three state variables: the list we're iterating, the index into it, and the callback function */ + sbVm_request_var_space(vm, 3); + hV iterating_list = sbVm_pop(vm); + hV loop_func = sbVm_pop(vm); + sbVm_pop(vm); /* remove method name */ + hV index = HVINT(0); + vm->fp->locals[0] = iterating_list; + vm->fp->locals[1] = index; + vm->fp->locals[2] = loop_func; + } else { + /* loop func must have finished, so remove its result */ + sbVm_pop(vm); + } + + usize current_index = vm->fp->locals[1].integer++; + usize length; + hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length); + if (current_index < length) { + sbVm_push(vm, iter_values[current_index]); + sbVm_push(vm, HVINT(1)); + sbVm_call_func(vm, vm->fp->locals[2]); + } else { + /* if index was past the end, callback function won't be called, and we'll exit. return nil */ + sbVm_push(vm, HVNIL); + } +} diff --git a/src/data/string.c b/src/data/string.c index 38796df..c9da7d2 100644 --- a/src/data/string.c +++ b/src/data/string.c @@ -325,13 +325,13 @@ static char *get_mutable_ptr_of_entry(strentry *e, usize length, hString *handle static void tinystr_into_buffer(char *buffer, hString handle, usize max_length) { /* we have max_length because we may need to cut off early in some corner cases, * like getting a mutable ptr of length 3 for a tinystr of length 6 */ - if (!is_tinystr(handle)) PANIC("%llx is not a tinystr! can't parse!", handle); + if (!is_tinystr(handle)) PANIC("%llx is not a tinystr! can't parse!", (long long)handle); usize index = 0; usize tinylength = tinystr_length(handle); hString handle_to_eat = handle; - if (tinylength >= REQ_ALLOC_LENGTH) PANIC("%llx has improper tinylength %zu", handle, tinylength); + if (tinylength >= REQ_ALLOC_LENGTH) PANIC("%llx has improper tinylength %zu", (long long)handle, tinylength); /* string is stored backwards because it's easiest to just get the low byte */ while (index < tinylength && index < max_length) { diff --git a/src/data/symbol.c b/src/data/symbol.c index d4838d7..de7006c 100644 --- a/src/data/symbol.c +++ b/src/data/symbol.c @@ -33,7 +33,7 @@ hSymbol sbSymbol_from_bytes(const char *text, usize length) { /* return already existing symbol */ return result.symbol; } else { - PANIC("Only symbol values are allowed in the symbol table! (%lld)", result.type); + PANIC("Only symbol values are allowed in the symbol table! (%lld)", (long long)result.type); } } diff --git a/src/vm/exec.c b/src/vm/exec.c index 42ff4f9..8be69e4 100644 --- a/src/vm/exec.c +++ b/src/vm/exec.c @@ -6,6 +6,7 @@ #include "data/closure.h" void call_block(hVm vm, usize block_id, hClosure closure); +void return_from_block(hVm vm); void execute_instruction(hVm vm); void push_stack(hVm vm, const hV *value); hV pop_stack(hVm vm); @@ -70,6 +71,34 @@ void sbVm_call_func(hVm vm, hV func) { call_block(vm, func.type, func.closure); } +void sbVm_call_c_func(hVm vm, sbRuntimeCFunc func) { + sbVmStackFrame frame = { + .return_addr = vm->ip, + .last_fp = vm->fp, + .last_rp = vm->rp, + .is_c_func = TRUE, + .c_func = func, + }; + *(sbVmStackFrame*)vm->rp = frame; + vm->fp = (sbVmStackFrame*)vm->rp; + vm->rp += sizeof(sbVmStackFrame); + + func(vm, TRUE); + + if (vm->fp->is_c_func) { + /* if c_func didn't call another callback, return from it */ + return_from_block(vm); + } +} + +void sbVm_request_var_space(hVm vm, usize amount) { + /* have to set new rstack space to 0 so we don't accidentally decrement + * the ref count of variables from a previous stack frame (or of just garbage) */ + memset(vm->rp, 0, amount * sizeof(hV)); + vm->rp += amount * sizeof(hV); + vm->fp->num_locals += amount; +} + /* --- */ void call_block(hVm vm, usize block_id, hClosure closure) { @@ -79,8 +108,8 @@ void call_block(hVm vm, usize block_id, hClosure closure) { .return_addr = vm->ip, .last_fp = vm->fp, .last_rp = vm->rp, - .block = blk, - .closure = closure, + .block_func.block = blk, + .block_func.closure = closure, }; *(sbVmStackFrame*)vm->rp = frame; vm->fp = (sbVmStackFrame*)vm->rp; @@ -102,11 +131,21 @@ void return_from_block(hVm vm) { vm->fp = frame->last_fp; vm->rp = frame->last_rp; vm->ip = frame->return_addr; + + if (vm->fp->is_c_func) { + /* if we returned into a c-function call frame, go back to the c-function */ + vm->fp->c_func(vm, FALSE); + + if (vm->fp->is_c_func) { + /* c-function didn't make a callback, so is done */ + return_from_block(vm); + } + } } } void debug_print_hv(const hV *value) { - debug("%016llx %016llx\n", *(u64*)value, *((u64*)value+1)); + debug("%016llx %016llx\n", *(long long*)value, *((long long*)value+1)); } void store_local(hVm vm, usize local_index, const hV *value) { @@ -141,7 +180,7 @@ hV *peek_stack(hVm vm, usize offset) { } sbOpcode get_opcode(hVm vm) { - if (vm->ip >= vm->fp->block->bytecode_end) PANIC("execution outside defined code area"); + if (vm->ip >= vm->fp->block_func.block->bytecode_end) PANIC("execution outside defined code area"); return *(vm->ip++); } @@ -160,7 +199,7 @@ void next_byte(hVm vm, u64 *result) { * in big-endian format */ i64 get_param(hVm vm) { u64 result = *((u8*)vm->ip++); - if (vm->debugmode) debug("%02llX ", result); + if (vm->debugmode) debug("%02llX ", (long long)result); i64 signed_result = result; if (result == BC_LONG_NUM) { @@ -214,7 +253,7 @@ void execute_instruction(hVm vm) { break; case BC_LD_CONST: param = get_param(vm); - push_stack(vm, &vm->fp->block->constants[param]); + push_stack(vm, &vm->fp->block_func.block->constants[param]); break; case BC_LD_CTX: PANIC("todo"); @@ -235,12 +274,12 @@ void execute_instruction(hVm vm) { case BC_LD_UPVAL: /* Hey, was there upval in there? */ param = get_param(vm); - v = sbClosure_get_var(vm->fp->closure, param); + v = sbClosure_get_var(vm->fp->block_func.closure, param); push_stack(vm, v); break; case BC_LD_UPREF: param = get_param(vm); - res = sbClosure_get_ref(vm->fp->closure, param); + res = sbClosure_get_ref(vm->fp->block_func.closure, param); push_stack(vm, &res); break; case BC_LD_BLK: @@ -251,7 +290,7 @@ void execute_instruction(hVm vm) { param = get_param(vm); v = &vm->fp->locals[param]; if (v->type != IT_REF) { - CHECK("indirect variables should be of type reference! (%lld)", v->type); + CHECK("indirect variables should be of type reference! (%lld)", (long long)v->type); } w = sbRef_deref(v->ref); push_stack(vm, w); @@ -268,7 +307,7 @@ void execute_instruction(hVm vm) { case BC_ST_UPVAL: param = get_param(vm); vv = pop_stack(vm); - sbClosure_set_var(vm->fp->closure, param, &vv); + sbClosure_set_var(vm->fp->block_func.closure, param, &vv); break; case BC_ST_IND: param = get_param(vm); @@ -280,7 +319,7 @@ void execute_instruction(hVm vm) { } else if (v->type == IT_REF) { sbRef_set_ref(v->ref, w); } else { - CHECK("indirect variables should be of type reference! (%lld)", v->type); + CHECK("indirect variables should be of type reference! (%lld)", (long long)v->type); } pop_stack(vm); break; @@ -316,7 +355,7 @@ void execute_instruction(hVm vm) { } else if (v->type == IT_REF) { sbRef_set_ref(v->ref, w); } else { - CHECK("indirect variables should be of type reference! (%lld)", v->type); + CHECK("indirect variables should be of type reference! (%lld)", (long long)v->type); } pop_stack(vm); xx.integer --; @@ -368,20 +407,20 @@ void execute_instruction(hVm vm) { break; case BC_JMP: param = get_param(vm); - vm->ip = &vm->fp->block->bytecode[param]; + vm->ip = &vm->fp->block_func.block->bytecode[param]; break; case BC_JT: param = get_param(vm); vv = pop_stack(vm); if (!sbV_c_falsy(&vv)) { - vm->ip = &vm->fp->block->bytecode[param]; + vm->ip = &vm->fp->block_func.block->bytecode[param]; } break; case BC_JF: param = get_param(vm); vv = pop_stack(vm); if (sbV_c_falsy(&vv)) { - vm->ip = &vm->fp->block->bytecode[param]; + vm->ip = &vm->fp->block_func.block->bytecode[param]; } break; case BC_RET: @@ -481,12 +520,7 @@ void execute_instruction(hVm vm) { case BC_ALLOC_VARS: /* TODO check for overflow */ param = get_param(vm); - /* have to set new rstack space to 0 so we don't accidentally decrement - * the ref count of variables from a previous stack frame (or of just garbage) */ - memset(vm->rp, 0, param * sizeof(hV)); - /* we allocate one more variable at 0 for internal use */ - vm->rp += (param + 1) * sizeof(hV); - vm->fp->num_locals += param; + sbVm_request_var_space(vm, param); break; case BC_CLOSURE: param = get_param(vm); @@ -501,7 +535,7 @@ void execute_instruction(hVm vm) { * have previously been being manipulated using the IND instructions */ w = peek_stack(vm, 0); if (w->type != IT_REF) { - CHECK("internal violation: closure should receive a set of reference variables (got %lld)", w->type); + CHECK("internal violation: closure should receive a set of reference variables (got %lld)", (long long)w->type); } sbClosure_set_ref(c, param, w); pop_stack(vm); diff --git a/src/vm/exec.h b/src/vm/exec.h index ebcb8bf..e110e19 100644 --- a/src/vm/exec.h +++ b/src/vm/exec.h @@ -36,6 +36,8 @@ /* Also these stacks grow upwards in memory, from low to high addresses. */ +typedef void (*sbRuntimeCFunc)(hVm, flag init); + typedef enum sbVmStatus { VM_STAT_UNKNOWN, VM_STAT_SUCCESS, @@ -46,8 +48,14 @@ typedef struct sbVmStackFrame { const u8 *return_addr; struct sbVmStackFrame *last_fp; u8 *last_rp; - const sbVmBlock *block; - hClosure closure; + flag is_c_func; + union { + struct { + const sbVmBlock *block; + hClosure closure; + } block_func; + sbRuntimeCFunc c_func; + }; usize num_locals; hV locals[]; } sbVmStackFrame; @@ -82,3 +90,7 @@ hV sbVm_pop(hVm vm); hV *sbVm_peek(hVm vm, usize where); void sbVm_call_func(hVm vm, hV func); + +void sbVm_call_c_func(hVm vm, sbRuntimeCFunc func); + +void sbVm_request_var_space(hVm vm, usize amount); diff --git a/src/vm/operations.c b/src/vm/operations.c index 15e9f47..1b73140 100644 --- a/src/vm/operations.c +++ b/src/vm/operations.c @@ -31,7 +31,7 @@ hV sbV_add(const hV *a, const hV *b) { if (a->type == IT_INTEGER && b->type == IT_INTEGER) { return sbV_int(sbInteger_sum(a->integer, b->integer)); } else { - PANIC("todo (add type %llu and type %llu)", a->type, b->type); + PANIC("todo (add type %llu and type %llu)", (long long)a->type, (long long)b->type); } } @@ -39,7 +39,7 @@ hV sbV_sub(const hV *a, const hV *b) { if (a->type == IT_INTEGER && b->type == IT_INTEGER) { return sbV_int(sbInteger_diff(a->integer, b->integer)); } else { - PANIC("todo (subtract type %llu minus %llu)", a->type, b->type); + PANIC("todo (subtract type %llu minus %llu)", (long long)a->type, (long long)b->type); } } @@ -120,7 +120,7 @@ hV sbV_index(hV *a, hV *b) { if (a->type == IT_LIST && b->type == IT_INTEGER) { return sbList_index(a->list, b->integer); } else { - PANIC("todo %lld %lld", a->type, b->type); + PANIC("todo %lld %lld", (long long)a->type, (long long)b->type); } } @@ -128,7 +128,7 @@ hV sbV_scope_get(hV *obj, hV *key) { if (obj->type == IT_HASH) { return sbHash_find(obj->hash, key); } else { - PANIC("todo %lld", obj->type); + PANIC("todo %lld", (long long)obj->type); } } @@ -136,6 +136,6 @@ void sbV_scope_set(hV *obj, hV *key, hV *value) { if (obj->type == IT_HASH) { sbHash_insert(obj->hash, key, value); } else { - PANIC("todo %lld", obj->type); + PANIC("todo %lld", (long long)obj->type); } } -- 1.8.3.1