From: cassowarii <2374677+cassowarii@users.noreply.github.com> Date: Thu, 9 Jul 2026 20:23:53 +0000 (-0700) Subject: finally, global modules! we can print at long, sweet last X-Git-Url: https://git.cassowary.me/gitweb.cgi?a=commitdiff_plain;h=edc828704837544ce68da662795728c64258dbbb;p=sarabande.git finally, global modules! we can print at long, sweet last --- diff --git a/src/compile/emit.c b/src/compile/emit.c index 9b341e5..b28b891 100644 --- a/src/compile/emit.c +++ b/src/compile/emit.c @@ -2,7 +2,10 @@ #define STRING1(...) #__VA_ARGS__ #define STRING2(...) STRING1(__VA_ARGS__) -#define EMIT(...) do { debug(STRING2(__VA_ARGS__) "\n"); sbVmCompiler_write_code(cm, (u8[]) { __VA_ARGS__ }, sizeof((u8[]) { __VA_ARGS__ })); } while (0) +#define EMIT(...) do { \ + if (cm->debugmode) debug(STRING2(__VA_ARGS__) "\n"); \ + sbVmCompiler_write_code(cm, (u8[]) { __VA_ARGS__ }, sizeof((u8[]) { __VA_ARGS__ })); \ +} while (0) #define EARG(x) (emit_arg(cm, x)) struct labelpos { @@ -14,8 +17,8 @@ void compile_chunk(sbVmCompiler *cm, sbIrChunk *chunk); void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt); void compile_expr(sbVmCompiler *cm, sbIrExpr *expr); -void sbEmit_compile_program(sbVmProgram *vp, sbIrProgram *ir) { - sbVmCompiler cm = sbVmCompiler_create(4096, 4096); +void sbEmit_compile_program(sbVmProgram *vp, sbIrProgram *ir, flag debugmode) { + sbVmCompiler cm = sbVmCompiler_create(4096, 4096, debugmode); int nchunks = ir->chunks.size / sizeof(sbIrChunk*); for (int i = 0; i < nchunks; i++) { @@ -33,7 +36,8 @@ void sbEmit_compile_program(sbVmProgram *vp, sbIrProgram *ir) { /* --- */ void emit_arg(sbVmCompiler *cm, i64 actual_number) { - debug(" arg %lld\n", (long long)actual_number); + if (cm->debugmode) debug(" arg %lld\n", (long long)actual_number); + u8 buf[9]; u64 number = actual_number; if (0 <= actual_number && actual_number < 253) { @@ -74,7 +78,7 @@ void emit_arg(sbVmCompiler *cm, i64 actual_number) { void compile_chunk(sbVmCompiler *cm, sbIrChunk *chunk) { - debug("\n--block %d--\n", chunk->id); + if (cm->debugmode) debug("\n--block %d--\n", chunk->id); int nstmts = chunk->stmts.size / sizeof(sbIrStmt*); if (chunk->id > 0) { @@ -108,7 +112,7 @@ void compile_chunk(sbVmCompiler *cm, sbIrChunk *chunk) { struct labelpos lp = ((struct labelpos*)cm->label_positions.data)[i]; u8 location_bytes[4]; u32 position = lp.label->block_position; - debug("now we know that the jump at %d should go to %d\n", lp.offset - 2, position); + if (cm->debugmode) debug("now we know that the jump at %d should go to %d\n", lp.offset - 2, position); location_bytes[0] = (position >> 24) & 0xFF; location_bytes[1] = (position >> 16) & 0xFF; location_bytes[2] = (position >> 8) & 0xFF; @@ -133,7 +137,7 @@ void record_labelpos(sbVmCompiler *cm, sbIrLabel *label, u32 offset) { void compile_list(sbVmCompiler *cm, sbIrExpr *expr); void compile_bind_list(sbVmCompiler *cm, sbIrBindList *list); void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt) { - debug("%3zu ", sbVmCompiler_get_position(cm)); + if (cm->debugmode) debug("%3zu ", sbVmCompiler_get_position(cm)); switch (stmt->type) { case IR_S_EXPR: compile_expr(cm, stmt->expr); @@ -333,6 +337,10 @@ void compile_expr(sbVmCompiler *cm, sbIrExpr *expr) { compile_expr(cm, expr->send.target); EMIT(BC_SEND); break; + case IR_E_CONTEXT: + EMIT(BC_LD_CTX); + EARG(expr->symbol); + break; case IR_E_VAR: if (expr->var->is_upvalue) { EMIT(BC_LD_UPVAL); diff --git a/src/compile/emit.h b/src/compile/emit.h index f909625..279b268 100644 --- a/src/compile/emit.h +++ b/src/compile/emit.h @@ -20,4 +20,4 @@ * have to essentially convert the tree to "reverse polish * notation." */ -void sbEmit_compile_program(sbVmProgram *vp, sbIrProgram *ir); +void sbEmit_compile_program(sbVmProgram *vp, sbIrProgram *ir, flag debugmode); diff --git a/src/compile/ir.c b/src/compile/ir.c index 1afa198..a7fb425 100644 --- a/src/compile/ir.c +++ b/src/compile/ir.c @@ -38,6 +38,7 @@ void sbIrProgram_deinitialize(hIrProgram ir) { sbBuffer_deinitialize(&ir->chunks); sbBuffer_deinitialize(&ir->varmapping); + sbBuffer_deinitialize(&ir->context_vars); BUFFER_ITER(ir->buffers, sbBuffer*, buf) { sbBuffer_deinitialize(*buf); } @@ -195,11 +196,9 @@ static sbIrVariable *var_name(hIrChunk ck, const char *name, usize name_len) { sbIrVariable *v = existing_var(ck, name, name_len, &index); if (v == NO_VAR) { - /* TODO do a different thing here */ - chunk_error(ck, "unknown variable name! '%s'\n", name); - } - - if (index >= ck->lowest_var_id) { + /* not a lexical variable */ + return NULL; + } else if (index >= ck->lowest_var_id) { /* normal variable in inner function scope */ return v; } else { @@ -210,8 +209,6 @@ static sbIrVariable *var_name(hIrChunk ck, const char *name, usize name_len) { /* we can introduce new variables into a scope using LET */ static sbIrVariable *create_var(hIrChunk ck, const char *name, usize name_len) { - sbIrVariable *new_var = sbArena_alloc(&ck->program->arena, sizeof(sbIrVariable)); - sbIrVariable *already_existing = existing_var(ck, name, name_len, NULL); if (already_existing != NO_VAR) { // TODO this should probably just be a warning @@ -219,6 +216,8 @@ static sbIrVariable *create_var(hIrChunk ck, const char *name, usize name_len) { return NO_VAR; } + sbIrVariable *new_var = sbArena_alloc(&ck->program->arena, sizeof(sbIrVariable)); + usize nvars = ck->program->varmapping.size / sizeof(varmapentry); *new_var = (sbIrVariable) {0}; @@ -269,6 +268,13 @@ static sbIrExpr *expr_var(hIrChunk ck, sbIrVariable *var) { }); } +static sbIrExpr *expr_context(hIrChunk ck, hSymbol symbol) { + return new_expr(ck, &(sbIrExpr) { + .type = IR_E_CONTEXT, + .symbol = symbol, + }); +} + static sbIrExpr *expr_value(hIrChunk ck, hV *value) { return new_expr(ck, &(sbIrExpr) { .type = IR_E_VALUE, @@ -675,7 +681,7 @@ static void compile_ast_stmt(hIrChunk ck, sbAst node, flag implicit_return) { * RETURN a * linearizes to: * RETURN a - * + * * OK, this one's pretty simple. */ if (node->seq.left == NO_NODE) { @@ -855,6 +861,7 @@ static void compile_ast_stmt(hIrChunk ck, sbAst node, flag implicit_return) { static sbIrVariable *compile_ast_var(hIrChunk ck, sbAst node) { if (node->type == AST_NODE_NAME) { + /* TODO I don't want to use strlen. symbols should know their length */ return var_name(ck, sbSymbol_name(node->symb), strlen(sbSymbol_name(node->symb))); } else { /* TODO make errors not bad */ @@ -1009,9 +1016,11 @@ static sbIrExpr *compile_ast_expr(hIrChunk ck, sbAst node, flag list_context) { } else if (node->type == AST_VAL_NIL) { return expr_value(ck, &HVNIL); } else if (node->type == AST_NODE_NAME) { - /* TODO: I don't want to use strlen. Can we remember the lengths of symbols? */ sbIrVariable *var = compile_ast_var(ck, node); - if (var->introduced) { + if (!var) { + /* it is not a variable that was introduced anywhere. assume it is a context value */ + return expr_context(ck, node->symb); + } else if (var->introduced) { return expr_var(ck, var); } else { chunk_error(ck, "Variable '%s' has not been declared here!\n", sbSymbol_name(node->symb)); diff --git a/src/compile/ir.h b/src/compile/ir.h index e044b20..a27b2a1 100644 --- a/src/compile/ir.h +++ b/src/compile/ir.h @@ -44,6 +44,7 @@ typedef enum sbIrExprType { IR_E_VALUE, IR_E_OP, IR_E_VAR, + IR_E_CONTEXT, IR_E_FUNC, IR_E_CALL, IR_E_SEND, @@ -56,6 +57,7 @@ typedef enum sbIrNameIntroduceType { BY_DEF, BY_LET, BY_PARAM, + BY_CONTEXT, } sbIrNameIntroduceType; typedef struct sbIrLabel { @@ -84,6 +86,7 @@ typedef struct sbIrExpr { union { hV value; sbIrVariable *var; + hSymbol symbol; struct { struct sbIrChunk *chunk; sbBuffer bound; @@ -154,6 +157,7 @@ typedef struct sbIrProgram { sbBuffer varmapping; sbBuffer chunks; sbBuffer buffers; + sbBuffer context_vars; i32 error_count; } sbIrProgram; diff --git a/src/data/value.h b/src/data/value.h index 236024e..f08c2df 100644 --- a/src/data/value.h +++ b/src/data/value.h @@ -15,6 +15,9 @@ #define HVNOTHING ((hV) {0}) #define HVFUNC(i, c) ((hV) { .type = i, .closure = c }) #define HVFUNC2(i, c) ((hV) { .type = i | FLAG_SQUIGGLY, .closure = c }) +#define HVBUILTIN(b) ((hV) { .type = IT_BUILTIN, .builtin = b }) + +struct sbVm; typedef u64 hHash; typedef u64 hString; @@ -23,6 +26,7 @@ typedef i64 hInteger; typedef u64 hList; typedef u64 hRef; typedef u64 hClosure; +typedef void (*sbBuiltinFunc)(struct sbVm*, usize); enum intrinsic_type { IT_NOTHING, // sentinel for "no value here" @@ -52,6 +56,7 @@ typedef struct hV { hRef ref; u64 boolean; double float_val; + sbBuiltinFunc builtin; u64 data; }; } hV; diff --git a/src/lib/lib.c b/src/lib/lib.c index d40252b..ebfe0a1 100644 --- a/src/lib/lib.c +++ b/src/lib/lib.c @@ -1,13 +1,16 @@ #include "common.h" -#include "lib/table.h" #include "data/symbol.h" #include "vm/exec.h" -extern void sbList_create_methods(); -extern void sbString_create_methods(); -extern void sbInteger_create_methods(); +#include "lib/table.h" +#include "lib/method.h" +#include "lib/module.h" void sbLib_sys_init() { + sbLibTable_initialize(&g_global_module, 16, FALSE); + + sbLib_loadmodule_global(); + sbLibTable_initialize(&g_list_methods, 16, TRUE); sbLibTable_initialize(&g_string_methods, 16, TRUE); sbLibTable_initialize(&g_integer_methods, 16, TRUE); @@ -21,6 +24,8 @@ void sbLib_sys_deinit() { sbLibTable_deinitialize(&g_list_methods); sbLibTable_deinitialize(&g_string_methods); sbLibTable_deinitialize(&g_integer_methods); + + sbLibTable_deinitialize(&g_global_module); } void sbLib_resolve_method(hVm vm) { @@ -59,3 +64,16 @@ void sbLib_resolve_method(hVm vm) { PANIC("invalid method name for type %lld: %s", (long long)target->type, sbSymbol_name(method_name_val->symbol)); } } + +void sbLib_resolve_global(hVm vm) { + hV *target = sbVm_pop(vm); + if (target->type != IT_SYMBOL) { + CHECK("global lookup must be symbol!"); + } + hV *v = sbLibTable_find_value(&g_global_module, target->symbol); + if (v) { + sbVm_push_immediate(vm, v); + } else { + PANIC("name '%s' is not defined", sbSymbol_name(target->symbol)); + } +} diff --git a/src/lib/lib.h b/src/lib/lib.h index 15ffdba..97697a6 100644 --- a/src/lib/lib.h +++ b/src/lib/lib.h @@ -5,6 +5,8 @@ typedef void (*sbLibMethod)(hVm, hV*, usize); void sbLib_resolve_method(hVm vm); +void sbLib_resolve_global(hVm vm); + void sbLib_sys_init(); void sbLib_sys_deinit(); diff --git a/src/lib/method.h b/src/lib/method.h new file mode 100644 index 0000000..e7da22f --- /dev/null +++ b/src/lib/method.h @@ -0,0 +1,7 @@ +extern sbLibTable g_list_methods; +extern sbLibTable g_string_methods; +extern sbLibTable g_integer_methods; + +void sbList_create_methods(); +void sbString_create_methods(); +void sbInteger_create_methods(); diff --git a/src/lib/method/integer.c b/src/lib/method/integer.c index adeac1e..ea9f8a8 100644 --- a/src/lib/method/integer.c +++ b/src/lib/method/integer.c @@ -5,12 +5,6 @@ #include "data/string.h" #include "vm/exec.h" -void list_each_cfunc(hVm vm, flag init); -void list_map_cfunc(hVm vm, flag init); -void list_filter_cfunc(hVm vm, flag init); -void list_any_cfunc(hVm vm, flag init); -void list_all_cfunc(hVm vm, flag init); - sbLibTable g_integer_methods; static void to_string(hVm vm, hV *target, usize num_params) { diff --git a/src/lib/method/list.c b/src/lib/method/list.c index f830f75..d874be8 100644 --- a/src/lib/method/list.c +++ b/src/lib/method/list.c @@ -5,11 +5,11 @@ #include "data/string.h" #include "vm/exec.h" -void list_each_cfunc(hVm vm, flag init); -void list_map_cfunc(hVm vm, flag init); -void list_filter_cfunc(hVm vm, flag init); -void list_any_cfunc(hVm vm, flag init); -void list_all_cfunc(hVm vm, flag init); +sbCFuncStatus list_each_cfunc(hVm vm, flag init); +sbCFuncStatus list_map_cfunc(hVm vm, flag init); +sbCFuncStatus list_filter_cfunc(hVm vm, flag init); +sbCFuncStatus list_any_cfunc(hVm vm, flag init); +sbCFuncStatus list_all_cfunc(hVm vm, flag init); sbLibTable g_list_methods; @@ -134,7 +134,7 @@ void sbList_create_methods(void) { /* --- */ -void list_each_cfunc(hVm vm, flag init) { +sbCFuncStatus 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); @@ -157,13 +157,15 @@ void list_each_cfunc(hVm vm, flag init) { sbVm_push(vm, &iter_values[current_index]); sbVm_push_immediate(vm, &HVINT(1)); sbVm_call_func(vm, &vm->fp->locals[2]); + return CFUNC_NEXT; } else { /* if index was past the end, callback function won't be called, and we'll exit. return nil */ sbVm_push_immediate(vm, &HVNIL); + return CFUNC_END; } } -void list_map_cfunc(hVm vm, flag init) { +sbCFuncStatus list_map_cfunc(hVm vm, flag init) { if (init) { /* state: list being mapped, index, callback, result */ sbVm_request_var_space(vm, 4); @@ -192,13 +194,15 @@ void list_map_cfunc(hVm vm, flag init) { sbVm_push(vm, &iter_values[current_index]); sbVm_push_immediate(vm, &HVINT(1)); sbVm_call_func(vm, &vm->fp->locals[2]); + return CFUNC_NEXT; } else { /* return result list */ sbVm_push_immediate(vm, &vm->fp->locals[3]); + return CFUNC_END; } } -void list_filter_cfunc(hVm vm, flag init) { +sbCFuncStatus list_filter_cfunc(hVm vm, flag init) { if (init) { /* state: list being filtered, index, callback, result */ sbVm_request_var_space(vm, 4); @@ -232,13 +236,15 @@ void list_filter_cfunc(hVm vm, flag init) { sbVm_push(vm, &iter_values[current_index]); sbVm_push_immediate(vm, &HVINT(1)); sbVm_call_func(vm, &vm->fp->locals[2]); + return CFUNC_NEXT; } else { /* return result list */ sbVm_push_immediate(vm, &vm->fp->locals[3]); + return CFUNC_END; } } -void list_any_cfunc(hVm vm, flag init) { +sbCFuncStatus list_any_cfunc(hVm vm, flag init) { if (init) { /* state: list being filtered, index, callback */ sbVm_request_var_space(vm, 3); @@ -256,7 +262,7 @@ void list_any_cfunc(hVm vm, flag init) { if (!sbV_c_falsy(mapped)) { /* one was true! return true */ sbVm_push_immediate(vm, &HVBOOL(TRUE)); - return; + return CFUNC_END; } } @@ -269,13 +275,15 @@ void list_any_cfunc(hVm vm, flag init) { sbVm_push(vm, &iter_values[current_index]); sbVm_push_immediate(vm, &HVINT(1)); sbVm_call_func(vm, &vm->fp->locals[2]); + return CFUNC_NEXT; } else { /* no result found */ sbVm_push_immediate(vm, &HVBOOL(FALSE)); + return CFUNC_END; } } -void list_all_cfunc(hVm vm, flag init) { +sbCFuncStatus list_all_cfunc(hVm vm, flag init) { if (init) { /* state: list being filtered, index, callback */ sbVm_request_var_space(vm, 3); @@ -293,7 +301,7 @@ void list_all_cfunc(hVm vm, flag init) { if (sbV_c_falsy(mapped)) { /* one was false; return false */ sbVm_push_immediate(vm, &HVBOOL(FALSE)); - return; + return CFUNC_END; } } @@ -306,8 +314,10 @@ void list_all_cfunc(hVm vm, flag init) { sbVm_push(vm, &iter_values[current_index]); sbVm_push_immediate(vm, &HVINT(1)); sbVm_call_func(vm, &vm->fp->locals[2]); + return CFUNC_NEXT; } else { /* all passed */ sbVm_push_immediate(vm, &HVBOOL(TRUE)); + return CFUNC_END; } } diff --git a/src/lib/method/string.c b/src/lib/method/string.c index 91beb69..37f03d6 100644 --- a/src/lib/method/string.c +++ b/src/lib/method/string.c @@ -25,6 +25,17 @@ static void split(hVm vm, hV *target, usize num_params) { sbVm_push_immediate(vm, &HVLIST(l)); } +static void to_string(hVm vm, hV *target, usize num_params) { + if (num_params != 0) { + PANIC("to_string takes no parameters"); + } + sbVm_pop(vm); /* remove method name */ + + /* to_string for a string just returns itself */ + sbVm_push_immediate(vm, target); +} + void sbString_create_methods(void) { REGISTER_METHOD(&g_string_methods, "split", split); + REGISTER_METHOD(&g_string_methods, "to_string", to_string); } diff --git a/src/lib/module.h b/src/lib/module.h new file mode 100644 index 0000000..36bd9d8 --- /dev/null +++ b/src/lib/module.h @@ -0,0 +1,3 @@ +extern sbLibTable g_global_module; + +void sbLib_loadmodule_global(); diff --git a/src/lib/module/global.c b/src/lib/module/global.c new file mode 100644 index 0000000..cb5b752 --- /dev/null +++ b/src/lib/module/global.c @@ -0,0 +1,81 @@ +#include "common.h" + +#include "lib/table.h" +#include "data/list.h" +#include "data/string.h" +#include "data/symbol.h" +#include "vm/exec.h" + +sbCFuncStatus print_cfunc(hVm vm, flag init); +sbCFuncStatus println_cfunc(hVm vm, flag init); + +sbLibTable g_global_module; + +static void print(hVm vm, usize argc) { + sbVm_push_immediate(vm, &HVINT(argc)); + sbVm_call_c_func(vm, print_cfunc); +} + +static void println(hVm vm, usize argc) { + sbVm_push_immediate(vm, &HVINT(argc)); + sbVm_call_c_func(vm, println_cfunc); +} + +void sbLib_loadmodule_global() { + REGISTER_VALUE(&g_global_module, "print", &HVBUILTIN(print)); + REGISTER_VALUE(&g_global_module, "println", &HVBUILTIN(println)); +} + +/* --- */ + +sbCFuncStatus print_cfunc(hVm vm, flag init) { + hV *args_left; + + if (!init) { + /* get value of previous to_string */ + hV *value = sbVm_pop(vm); + /* TODO: We should probably have some kind of 'implicit convert to string' + * thing that checks that it's really a string and throws if not, that we + * can call from multiple places */ + if (value->type != IT_STRING) { + PANIC("to_string needs to return a string"); + } + + char scratch[8]; + const char *strdata = sbString_get_value(value->string, scratch, NULL); + printf("%s", strdata); + args_left = sbVm_pop(vm); + } else { + args_left = sbVm_pop(vm); + if (args_left->type != IT_INTEGER) { + CHECK("argc to function needs to be integer!"); + } + } + + /* TODO: Built-in symbols like 'to_string' should be saved globally, so we don't have to do this + * hashing at runtime. */ + if (args_left->integer > 0) { + args_left->integer --; + sbVm_push_immediate(vm, args_left); /* ... param args_left */ + sbVm_swap(vm); /* ... args_left param */ + sbVm_push_immediate(vm, &HVSYM(sbSymbol_from_bytes("to_string", 9))); /* ... args_left param :to_string */ + sbVm_swap(vm); /* ... args_left :to_string param */ + sbVm_push_immediate(vm, &HVINT(1)); /* ... args_left :to_string param 1 */ + sbVm_swap(vm); /* ... args_left :to_string 1 param */ + sbLib_resolve_method(vm); /* call method */ + return CFUNC_NEXT; + } else { + sbVm_push_immediate(vm, &HVNIL); + return CFUNC_END; + } +} + +sbCFuncStatus println_cfunc(hVm vm, flag init) { + if (init) { + sbVm_call_c_func(vm, print_cfunc); + return CFUNC_NEXT; + } else { + printf("\n"); + return CFUNC_END; + } +} diff --git a/src/lib/table.h b/src/lib/table.h index 2b73355..bde35ae 100644 --- a/src/lib/table.h +++ b/src/lib/table.h @@ -16,10 +16,6 @@ typedef struct sbLibTable { typedef sbLibTable *hLibTable; -extern sbLibTable g_list_methods; -extern sbLibTable g_string_methods; -extern sbLibTable g_integer_methods; - void sbLibTable_initialize(hLibTable t, usize capacity, flag method_table); void sbLibTable_deinitialize(hLibTable t); diff --git a/src/main.c b/src/main.c index 50031ab..06ddb7c 100644 --- a/src/main.c +++ b/src/main.c @@ -62,7 +62,7 @@ int main(int argc, char **argv) { sbVmProgram pm; sbVmProgram_initialize(&pm, 65536); - sbEmit_compile_program(&pm, &ir); + sbEmit_compile_program(&pm, &ir, debugmode); sbIrProgram_deinitialize(&ir); @@ -71,11 +71,13 @@ int main(int argc, char **argv) { sbVm_execute(&vm, &pm); - printf("Stack result: "); - for (hV **p = (hV**)vm.vstack; p < (hV**)vm.vsp; p++) { - printf("%16llx %16llx ", (long long)(*p)->type, (long long)(*p)->data); + if (vm.debugmode) { + printf("Stack result: "); + for (hV **p = (hV**)vm.vstack; p < (hV**)vm.vsp; p++) { + printf("%16llx %16llx ", (long long)(*p)->type, (long long)(*p)->data); + } + printf("\n"); } - printf("\n"); sbVmProgram_deinitialize(&pm); sbVm_deinitialize(&vm); diff --git a/src/vm/block.c b/src/vm/block.c index fb6c834..16d76a2 100644 --- a/src/vm/block.c +++ b/src/vm/block.c @@ -2,8 +2,9 @@ #define INITIAL_PROGRAM_BLOCK_SIZE 32 -sbVmCompiler sbVmCompiler_create(usize initial_bytecode_size, usize initial_constant_size) { +sbVmCompiler sbVmCompiler_create(usize initial_bytecode_size, usize initial_constant_size, flag debugmode) { sbVmCompiler cm = {0}; + cm.debugmode = debugmode; sbBuffer_initialize(&cm.bytecode, initial_bytecode_size); sbBuffer_initialize(&cm.constants, initial_constant_size); sbBuffer_initialize(&cm.label_positions, 1024); diff --git a/src/vm/block.h b/src/vm/block.h index c80286b..069da4d 100644 --- a/src/vm/block.h +++ b/src/vm/block.h @@ -13,6 +13,7 @@ /* dynamic sized block that we can more easily add * things to while compiling */ typedef struct sbVmCompiler { + flag debugmode; sbBuffer bytecode; sbBuffer constants; sbBuffer label_positions; @@ -35,7 +36,7 @@ typedef struct sbVmProgram { typedef usize sbBlockId; -sbVmCompiler sbVmCompiler_create(usize initial_bytecode_size, usize initial_constant_size); +sbVmCompiler sbVmCompiler_create(usize initial_bytecode_size, usize initial_constant_size, flag debugmode); void sbVmCompiler_reset(sbVmCompiler *pb); diff --git a/src/vm/exec.c b/src/vm/exec.c index 7d5c54b..6d49308 100644 --- a/src/vm/exec.c +++ b/src/vm/exec.c @@ -14,6 +14,7 @@ void push_stack_immediate(hVm vm, const hV *value); hV *pop_stack(hVm vm); hV *npop_stack(hVm vm, usize count); hV *peek_stack(hVm vm, isize offset); +void swap_stack_top(hVm vm); void print_stack(hVm vm); void sbVm_initialize(hVm vm, usize stacksize, usize rstacksize, flag debugmode) { @@ -73,6 +74,10 @@ hV *sbVm_peek(hVm vm, usize where) { return peek_stack(vm, where); } +void sbVm_swap(hVm vm) { + swap_stack_top(vm); +} + void sbVm_call_func(hVm vm, hV *func) { call_block(vm, func->type, func->closure); } @@ -89,10 +94,11 @@ void sbVm_call_c_func(hVm vm, sbRuntimeCFunc func) { vm->fp = (sbVmStackFrame*)vm->rsp; vm->rsp += sizeof(sbVmStackFrame); - func(vm, TRUE); + sbCFuncStatus result = func(vm, TRUE); - if (vm->fp->is_c_func) { + if (result == CFUNC_END) { /* if c_func didn't call another callback, return from it */ + printf("returning\n"); return_from_block(vm); } } @@ -119,6 +125,19 @@ void print_stack(hVm vm) { debug("\n"); } +void call_builtin(hVm vm, hV *to_call) { + if (to_call->type != IT_BUILTIN) { + CHECK("call_builtin can only call builtins!"); + } + + hV *argc = sbVm_pop(vm); + if (argc->type != IT_INTEGER) { + CHECK("argc to builtin needs to be integer!"); + } + + to_call->builtin(vm, argc->integer); +} + void call_block(hVm vm, usize block_id, hClosure closure) { sbVmBlock *blk = &vm->program->blocks[block_id]; @@ -149,16 +168,6 @@ void return_from_block(hVm vm) { vm->fp = frame->last_fp; vm->rsp = 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); - } - } } } @@ -286,6 +295,18 @@ i64 get_param(hVm vm) { /* execute one instruction! wow! */ void execute_instruction(hVm vm) { + if (vm->fp->is_c_func) { + /* if still in c func, do that instead of instruction */ + sbCFuncStatus result = vm->fp->c_func(vm, FALSE); + + if (result == CFUNC_END) { + /* c-function is done */ + return_from_block(vm); + } + + return; + } + sbOpcode op = get_opcode(vm); if (vm->debugmode) debug("op %02X ", op); u64 param; @@ -307,7 +328,10 @@ void execute_instruction(hVm vm) { push_stack_immediate(vm, &vm->fp->block_func.block->constants[param]); break; case BC_LD_CTX: - PANIC("todo"); + param = get_param(vm); + push_stack_immediate(vm, &HVSYM((hSymbol)param)); + sbLib_resolve_global(vm); + break; case BC_LD_VAR: param = get_param(vm); push_stack(vm, &vm->fp->locals[param]); @@ -434,6 +458,7 @@ void execute_instruction(hVm vm) { case BC_CALL: v = pop_stack(vm); if (v->type == IT_BUILTIN) { + call_builtin(vm, v); } else if (v->type <= 0) { /* We need to figure out exception support or some such. * User error should not panic. */ diff --git a/src/vm/exec.h b/src/vm/exec.h index dadcc37..bdda0f6 100644 --- a/src/vm/exec.h +++ b/src/vm/exec.h @@ -36,7 +36,12 @@ /* Also these stacks grow upwards in memory, from low to high addresses. */ -typedef void (*sbRuntimeCFunc)(hVm, flag init); +typedef enum { + CFUNC_END, + CFUNC_NEXT, +} sbCFuncStatus; + +typedef sbCFuncStatus (*sbRuntimeCFunc)(hVm, flag init); typedef enum sbVmStatus { VM_STAT_UNKNOWN, @@ -93,6 +98,8 @@ hV *sbVm_pop(hVm vm); hV *sbVm_peek(hVm vm, usize where); +void sbVm_swap(hVm vm); + void sbVm_call_func(hVm vm, hV *func); void sbVm_call_c_func(hVm vm, sbRuntimeCFunc func);