fix a couple bugs w/ pointers + like half of index assignment
authorcassowarii <2374677+cassowarii@users.noreply.github.com>
Mon, 20 Jul 2026 07:16:39 +0000 (00:16 -0700)
committercassowarii <2374677+cassowarii@users.noreply.github.com>
Mon, 20 Jul 2026 07:16:39 +0000 (00:16 -0700)
src/compile/emit.c
src/vm/exec.c

index fb38ba6..2c61541 100644 (file)
@@ -16,6 +16,8 @@ struct labelpos {
 void compile_chunk(sbVmCompiler *cm, sbIrChunk *chunk);
 void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt);
 void compile_expr(sbVmCompiler *cm, sbIrExpr *expr);
+void compile_ref(sbVmCompiler *cm, sbIrExpr *expr, flag is_lref);
+void compile_op(sbVmCompiler *cm, sbAstOp op);
 
 void sbEmit_compile_program(sbVmProgram *vp, sbIrProgram *ir, flag debugmode) {
   sbVmCompiler cm = sbVmCompiler_create(4096, 4096, debugmode);
@@ -202,9 +204,21 @@ void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt) {
         compile_expr(cm, stmt->assign.where->op.left);
         /* this should leave us with a pointer to expr on top of stack */
         EMIT(BC_REF_PUT);
+      } else if (stmt->assign.where->type == IR_E_OP && stmt->assign.where->op.type == AST_OP_INDEX) {
+        /* a[b] = whatever, a::b = whatever */
+        /* there is an IMPLICIT DEREFERENCE that occurs here. op::refindex returns an LREF,
+         * then we assign through the reference we receive, i.e.
+         *    a[b] = c
+         * really means
+         *    *(a{op::refindex}(b)) = c
+         * The reason for this has to do with assigning through nested data structures.
+         * Doing it this way just makes the whole semantics feel more natural. It's similar
+         * to returning a reference from indexing in C++, I guess. */
+        compile_ref(cm, stmt->assign.where->op.left, TRUE); /* thing we are indexing into */
+        compile_expr(cm, stmt->assign.where->op.right);     /* index we are using */
+        EMIT(BC_OP_INDEXLREF);
+        EMIT(BC_REF_PUT);
       } else {
-        /* TODO: Now we can support stuff like index-assignment also if we want to.
-         * Probably do this next */
         PANIC("This type of assignment operation is not supported!");
       }
       break;
@@ -345,13 +359,11 @@ void compile_bind_list(sbVmCompiler *cm, sbIrBindList *list) {
   }
 }
 
-void compile_ref(sbVmCompiler *cm, sbIrExpr *expr);
-void compile_op(sbVmCompiler *cm, sbAstOp op);
 void compile_expr(sbVmCompiler *cm, sbIrExpr *expr) {
   switch(expr->type) {
     case IR_E_OP:
       if (expr->op.type == AST_OP_REF) {
-        compile_ref(cm, expr->op.left);
+        compile_ref(cm, expr->op.left, FALSE);
       } else {
         compile_expr(cm, expr->op.left);
         if (expr->op.right) {
@@ -442,18 +454,30 @@ void compile_expr(sbVmCompiler *cm, sbIrExpr *expr) {
   }
 }
 
-/* compiling the left hand side of an assignment (that isn't straightforwardly
- * a variable) to return some kind of reference */
-void compile_assign_left(sbVmCompiler *cm, sbIrExpr *expr) {
-}
-
 /* when we see an expression of the form '&expr', we have to
  * handle this specially depending on what 'expr' is (and sometimes
- * we just aren't allowed to do it) */
-void compile_ref(sbVmCompiler *cm, sbIrExpr *expr) {
+ * we just aren't allowed to do it). this is also used for compiling
+ * certain indexing structures on the left side of assignment operators */
+void compile_ref(sbVmCompiler *cm, sbIrExpr *expr, flag is_lref) {
   if (expr->type == IR_E_VAR) {
-    EMIT(BC_LD_RREF);
+    if (expr->var->is_upvalue) {
+      EMIT(BC_LD_UPREF);
+    } else if (is_lref) {
+      EMIT(BC_LD_LREF);
+    } else {
+      EMIT(BC_LD_RREF);
+    }
     EARG(expr->var->slot_id);
+  } else if (expr->type == IR_E_OP && expr->op.type == AST_OP_INDEX) {
+    compile_ref(cm, expr->op.left, is_lref);  /* thing we are indexing into */
+    compile_expr(cm, expr->op.right);         /* index we are using */
+    if (is_lref) {
+      /* a[0] = ? / a::b = ? */
+      EMIT(BC_OP_INDEXLREF);
+    } else {
+      /* &a[0] / &a::b */
+      EMIT(BC_OP_INDEXRREF);
+    }
   } else {
     PANIC("cannot & non-variable-name! (todo)");
   }
index da484a4..abdeafc 100644 (file)
@@ -3,6 +3,7 @@
 #include "vm/operations.h"
 #include "data/list.h"
 #include "data/closure.h"
+#include "data/symbol.h"
 #include "lib/lib.h"
 #include "lib/sentinel.h"
 
@@ -137,10 +138,41 @@ void sbVm_print_stack(hVm vm) {
 
 /* --- */
 
+void print_val(hVal *p) {
+  if (p->type == IT_NIL) {
+    debug("nil");
+  } else if (p->type == IT_BOOLEAN && p->boolean) {
+    debug("true");
+  } else if (p->type == IT_BOOLEAN) {
+    debug("false");
+  } else if (p->type == IT_REF) {
+    debug("&(");
+    print_val(sbVar_get_value_ptr(sbVar_deref(p)));
+    debug(")");
+  } else if (p->type == IT_SYMBOL) {
+    debug(":%s", sbSymbol_name(p->symbol));
+  } else if (p->type == IT_INTEGER) {
+    debug("%lld", (long long)p->integer);
+  } else if (p->type == IT_LIST) {
+    debug("[...]");
+  } else if (p->type == IT_HASH) {
+    debug("{...}");
+  } else if (p->type > 0 && (p->type & IT_FLAG_BOUND_METHOD)) {
+    debug("(bound method #%lld:%lld)", (long long)p->type, (long long)(p->closure & ~0x80000000000000));
+  } else if (p->type > 0 && p->closure > 0) {
+    debug("(closure #%lld:%lld)", (long long)p->type, (long long)(p->closure & ~0x8000000000000000));
+  } else if (p->type > 0) {
+    debug("(block #%lld)", (long long)p->type);
+  } else {
+    debug("%16llx %16llx", (long long)p->type, (long long)p->data);
+  }
+}
+
 void print_stack(hVm vm) {
   debug("Stack: ");
   for (hVal *p = (hVal*)vm->vstack; p < (hVal*)vm->vsp; p++) {
-    debug("%16llx %16llx ", (long long)p->type, (long long)p->data);
+    print_val(p);
+    debug(" ");
   }
   debug("\n");
 }