finally, global modules! we can print at long, sweet last
authorcassowarii <2374677+cassowarii@users.noreply.github.com>
Thu, 9 Jul 2026 20:23:53 +0000 (13:23 -0700)
committercassowarii <2374677+cassowarii@users.noreply.github.com>
Thu, 9 Jul 2026 20:23:53 +0000 (13:23 -0700)
19 files changed:
src/compile/emit.c
src/compile/emit.h
src/compile/ir.c
src/compile/ir.h
src/data/value.h
src/lib/lib.c
src/lib/lib.h
src/lib/method.h [new file with mode: 0644]
src/lib/method/integer.c
src/lib/method/list.c
src/lib/method/string.c
src/lib/module.h [new file with mode: 0644]
src/lib/module/global.c [new file with mode: 0644]
src/lib/table.h
src/main.c
src/vm/block.c
src/vm/block.h
src/vm/exec.c
src/vm/exec.h

index 9b341e5..b28b891 100644 (file)
@@ -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);
index f909625..279b268 100644 (file)
@@ -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);
index 1afa198..a7fb425 100644 (file)
@@ -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));
index e044b20..a27b2a1 100644 (file)
@@ -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;
 
index 236024e..f08c2df 100644 (file)
@@ -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;
index d40252b..ebfe0a1 100644 (file)
@@ -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));
+  }
+}
index 15ffdba..97697a6 100644 (file)
@@ -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 (file)
index 0000000..e7da22f
--- /dev/null
@@ -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();
index adeac1e..ea9f8a8 100644 (file)
@@ -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) {
index f830f75..d874be8 100644 (file)
@@ -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;
   }
 }
index 91beb69..37f03d6 100644 (file)
@@ -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 (file)
index 0000000..36bd9d8
--- /dev/null
@@ -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 (file)
index 0000000..cb5b752
--- /dev/null
@@ -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;
+  }
+}
index 2b73355..bde35ae 100644 (file)
@@ -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);
index 50031ab..06ddb7c 100644 (file)
@@ -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);
index fb6c834..16d76a2 100644 (file)
@@ -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);
index c80286b..069da4d 100644 (file)
@@ -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);
 
index 7d5c54b..6d49308 100644 (file)
@@ -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. */
index dadcc37..bdda0f6 100644 (file)
 
 /* 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);