forward jumps! now if and while work
authorcassowarii <cassowary@cassowary.me>
Tue, 30 Jun 2026 05:08:56 +0000 (22:08 -0700)
committercassowarii <cassowary@cassowary.me>
Tue, 30 Jun 2026 05:08:56 +0000 (22:08 -0700)
src/compile/emit.c
src/data/operations.c
src/data/value.h
src/vm/block.c
src/vm/block.h
src/vm/exec.c

index 209c8c0..e37f528 100644 (file)
@@ -35,7 +35,7 @@ void sbEmit_compile_program(sbVmProgram *vp, sbIrProgram *ir) {
 void emit_arg(sbVmCompiler *cm, usize number) {
   printf("    arg %zu\n", number);
   u8 buf[9];
-  if (number < 256) {
+  if (number < 253) {
     buf[0] = number;
     sbVmCompiler_write_code(cm, buf, 1);
   } else if (number < 65536) {
@@ -79,11 +79,29 @@ void compile_chunk(sbVmCompiler *cm, sbIrChunk *chunk) {
     EMIT(BC_NUMARG);
     EARG(chunk->num_args);
   }
+
+  EMIT(BC_ALLOC_VARS);
+  EARG(chunk->variable_count);
+
   for (int i = 0; i < nstmts; i++) {
     sbIrStmt *stmt = ((sbIrStmt**)chunk->stmts.data)[i];
-
     compile_stmt(cm, stmt);
   }
+
+  /* Go back and fill in locations for forward jumps, whose
+   * positions we now know. */
+  usize nlabelpos = cm->label_positions.size / sizeof(struct labelpos);
+  for (int i = 0; i < nlabelpos; i++) {
+    struct labelpos lp = ((struct labelpos*)cm->label_positions.data)[i];
+    u8 location_bytes[4];
+    u32 position = lp.label->block_position;
+    printf("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;
+    location_bytes[3] = (position >>  0) & 0xFF;
+    sbVmCompiler_overwrite_code_at(cm, lp.offset, location_bytes, 4);
+  }
 }
 
 /* when compiling one line at a time, we don't know the position
@@ -91,6 +109,8 @@ void compile_chunk(sbVmCompiler *cm, sbIrChunk *chunk) {
  * address, and say "please put the address of this label here later!" */
 void record_labelpos(sbVmCompiler *cm, sbIrLabel *label, u32 offset) {
   struct labelpos lp = {
+    .label = label,
+    .offset = offset,
   };
 
   sbBuffer_append(&cm->label_positions, &lp, sizeof(struct labelpos));
@@ -104,20 +124,28 @@ void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt) {
       EMIT(BC_POP);
       break;
     case IR_S_JUMP:
-      if (stmt->jump.label->found_yet) {
-        if (stmt->jump.condition == NULL) {
-          EMIT(BC_JMP);
+      if (stmt->jump.condition == NULL) {
+        EMIT(BC_JMP);
+      } else {
+        compile_expr(cm, stmt->jump.condition);
+        printf("%3zu ", sbVmCompiler_get_position(cm));
+        if (stmt->jump.inverted) {
+          EMIT(BC_JF);
         } else {
-          compile_expr(cm, stmt->jump.condition);
-          if (stmt->jump.inverted) {
-            EMIT(BC_JF);
-          } else {
-            EMIT(BC_JT);
-          }
+          EMIT(BC_JT);
         }
+      }
+      if (stmt->jump.label->found_yet) {
         EARG(stmt->jump.label->block_position);
       } else {
-        printf("haven't implemented forward jump yet!\n");
+        printf("<forward jump>\n");
+        EMIT(BC_VLONG_NUM);
+        /* we have to remember to come back and fill in the address later when we
+         * know where this label is! */
+        record_labelpos(cm, stmt->jump.label, sbVmCompiler_get_position(cm));
+        /* leave behind four zeroes at this offset that we can later put the
+         * address into */
+        EMIT(0, 0, 0, 0);
       }
       break;
     case IR_S_LABEL:
index ed117b9..4ca5827 100644 (file)
@@ -14,7 +14,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");
+    PANIC("todo (subtract type %llu minus %llu)", a->type, b->type);
   }
 }
 
index 5cd07e1..b6bc921 100644 (file)
@@ -7,6 +7,7 @@
 #define HVSTR(s) ((hV) { .type = IT_STRING, .string = OBJSL(s) })
 #define HVBOOL(b) ((hV) { .type = IT_BOOLEAN, .boolean = b })
 #define HVFUNC(i) ((hV) { .type = IT_FUNCTION, .data = i })
+#define HVNIL ((hV) { .type = IT_NIL })
 
 typedef u64 hHash;
 typedef u64 hString;
index 804f476..202b09f 100644 (file)
@@ -25,6 +25,11 @@ void sbVmCompiler_write_code(sbVmCompiler *cm, const u8 *data, usize length) {
   sbBuffer_append(&cm->bytecode, data, length);
 }
 
+void sbVmCompiler_overwrite_code_at(sbVmCompiler *cm, usize offset, const u8 *data, usize length) {
+  if (offset + length > cm->bytecode.size) PANIC("buffer overflow with overwrite_code_at!");
+  memcpy(&cm->bytecode.data[offset], data, length);
+}
+
 usize sbVmCompiler_get_position(sbVmCompiler *cm) {
   return cm->bytecode.size;
 }
index 2e63326..c3e3745 100644 (file)
@@ -43,6 +43,8 @@ void sbVmCompiler_deinitialize(sbVmCompiler *pb);
 
 void sbVmCompiler_write_code(sbVmCompiler *pb, const u8 *data, usize length);
 
+void sbVmCompiler_overwrite_code_at(sbVmCompiler *cm, usize offset, const u8 *data, usize length);
+
 usize sbVmCompiler_get_position(sbVmCompiler *cm);
 
 void sbVmCompiler_add_constant(sbVmCompiler *pb, hV *constant);
index ea50f2b..6491a0c 100644 (file)
@@ -165,7 +165,7 @@ u64 get_param(hVm vm) {
 /* execute one instruction! wow! */
 void execute_instruction(hVm vm) {
   sbOpcode op = get_opcode(vm);
-  u32 param;
+  u64 param;
   hV *v, *w, res;
 
   switch (op) {
@@ -195,6 +195,9 @@ void execute_instruction(hVm vm) {
       param = get_param(vm);
       push_stack(vm, &HVFUNC(param));
       return;
+    case BC_LD_NIL:
+      push_stack(vm, &HVNIL);
+      return;
     case BC_ST_VAR:
       param = get_param(vm);
       v = peek_stack(vm, 0);