list assignment (and such) works!
authorcassowarii <2374677+cassowarii@users.noreply.github.com>
Thu, 23 Jul 2026 02:28:14 +0000 (19:28 -0700)
committercassowarii <2374677+cassowarii@users.noreply.github.com>
Thu, 23 Jul 2026 02:28:14 +0000 (19:28 -0700)
the only thing i think not currently working is something mysterious in
generator, and list.length right now because it doesn't return a
reference. i'll fix this later, i'm tired and it's too WARM, i need to
remove some of my horrible comments too

sample/generator.sbd
src/compile/emit.c
src/compile/print_ir.c
src/lib/lib.c
src/lib/table.c
src/lib/table.h
src/vm/bytecode.h
src/vm/exec.c
src/vm/operations.c
src/vm/operations.h

index f06aa0b..7ef6f0d 100644 (file)
@@ -153,12 +153,16 @@ let generator = (=> {
     }
   }
 
+  def get_classmethod m {
+    &class_methods[m]
+  }
+
   => f {
     if f == op::index {
-      class_methods(op::index)
+      get_classmethod
     } else {
       => method {
-        instance_methods[method](f)
+        &(instance_methods[method](f))
       }
     }
   }
index bfe0728..d2eef01 100644 (file)
@@ -136,6 +136,12 @@ void record_labelpos(sbVmCompiler *cm, sbIrLabel *label, u32 offset) {
   sbBuffer_append(&cm->label_positions, &lp, sizeof(struct labelpos));
 }
 
+/* things that implicitly dereference when used in a value context but
+ * can be assigned to on the left side of an = */
+flag is_implicit_ref(sbIrExpr *expr) {
+  return expr->type == IR_E_VAR || expr->type == IR_E_DOT || (expr->type == IR_E_OP && expr->op.type == AST_OP_INDEX);
+}
+
 void compile_list(sbVmCompiler *cm, sbIrExpr *expr);
 void compile_bind_list(sbVmCompiler *cm, sbIrBindList *list);
 void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt) {
@@ -214,18 +220,32 @@ void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt) {
          * 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 */
+        if (is_implicit_ref(stmt->assign.where->op.left)) {
+          compile_ref(cm, stmt->assign.where->op.left, TRUE);
+        } else {
+          compile_expr(cm, stmt->assign.where->op.left);
+        }
         compile_expr(cm, stmt->assign.where->op.right);     /* index we are using */
-        EMIT(BC_OP_INDEXLREF);
+        if (is_implicit_ref(stmt->assign.where->op.left)) {
+          EMIT(BC_OP_INDEXLREF_IND);
+        } else {
+          /* THE PROLIFERATION OF THESE!!!!!!!!!! I DO NOT LIKE!!!! */
+          EMIT(BC_OP_INDEXLREF);
+        }
         EMIT(BC_REF_PUT);
       } else if (stmt->assign.where->type == IR_E_DOT) {
         /* same as op::index, essentially. the dot returns a reference to the inside of the
          * thing, then we can assign to that reference */
-        compile_expr(cm, stmt->assign.where->op.right);
+        compile_expr(cm, stmt->assign.where->dot.param);
         EMIT(BC_LD_IMM);
         EARG(1);
-        compile_ref(cm, stmt->assign.where->op.left, TRUE);
-        EMIT(BC_CALL_IND);
+        if (is_implicit_ref(stmt->assign.where->dot.target)) {
+          compile_ref(cm, stmt->assign.where->dot.target, TRUE);
+          EMIT(BC_DOT_IND);
+        } else {
+          compile_expr(cm, stmt->assign.where->dot.target);
+          EMIT(BC_DOT);
+        }
         EMIT(BC_REF_PUT);
       } else {
         PANIC("This type of assignment operation is not supported!");
@@ -369,6 +389,11 @@ void compile_bind_list(sbVmCompiler *cm, sbIrBindList *list) {
 }
 
 void compile_expr(sbVmCompiler *cm, sbIrExpr *expr) {
+  if (cm->debugmode) {
+    sbIr_print_expr(expr);
+    debug("\n");
+  }
+
   switch(expr->type) {
     case IR_E_OP:
       if (expr->op.type == AST_OP_REF) {
@@ -386,8 +411,7 @@ void compile_expr(sbVmCompiler *cm, sbIrExpr *expr) {
     case IR_E_CALL:
       /* calling convention: store argument count on stack */
       compile_list(cm, expr->call.param);
-      if (expr->call.func->type == IR_E_DOT
-            || (expr->call.func->type == IR_E_OP && expr->call.func->op.type == AST_OP_INDEX)) {
+      if (is_implicit_ref(expr->call.func)) {
         /* for expressions with reference type, call 'through' the reference */
         compile_ref(cm, expr->call.func, TRUE);
         EMIT(BC_CALL_IND);
@@ -497,23 +521,43 @@ void compile_ref(sbVmCompiler *cm, sbIrExpr *expr, flag is_lref) {
     }
     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 */
+    /* TODO: Oh my god, it's 90F with no air conditioning, but can we PLEASE figure out
+     * a better way to structure this??!!?!?!?! */
+    if (is_implicit_ref(expr->op.left)) {
+      compile_ref(cm, expr->op.left, is_lref);  /* thing we are indexing into */
+    } else {
+      compile_expr(cm, expr->op.left);  /* 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);
+      if (is_implicit_ref(expr->op.left)) {
+        /* THIS SUCKS!!! */
+        EMIT(BC_OP_INDEXLREF_IND);
+      } else {
+        EMIT(BC_OP_INDEXLREF);
+      }
     } else {
       /* &a[0] / &a::b */
-      EMIT(BC_OP_INDEXRREF);
+      if (is_implicit_ref(expr->op.left)) {
+        EMIT(BC_OP_INDEXRREF_IND);
+      } else {
+        EMIT(BC_OP_INDEXRREF);
+      }
     }
   } else if (expr->type == IR_E_DOT) {
     compile_expr(cm, expr->dot.param);
     EMIT(BC_LD_IMM);
     EARG(1);
-    compile_ref(cm, expr->dot.target, is_lref);
-    EMIT(BC_DOT);
+    if (is_implicit_ref(expr->dot.target)) {
+      compile_ref(cm, expr->dot.target, is_lref);
+      EMIT(BC_DOT_IND);
+    } else {
+      compile_expr(cm, expr->dot.target);
+      EMIT(BC_DOT);
+    }
   } else {
-    PANIC("cannot & non-variable-name! (todo)");
+    PANIC("This type of reference operation is not supported!");
   }
 }
 
index 070b0c1..21a3d0a 100644 (file)
@@ -82,9 +82,9 @@ static void print_expr(sbIrExpr *e) {
       debug(")");
       break;
     case IR_E_CALL:
-      debug("CALL: ");
+      debug("(CALL: ");
       print_expr(e->call.func);
-      debug(" with params (");
+      debug(" with params ");
       if (e->call.param) {
         print_expr(e->call.param);
       }
index 64c6b4e..002945d 100644 (file)
@@ -183,19 +183,22 @@ static sbLibTable *find_method_table(hVal *target) {
 /* resolve_method should have set us up so we can just call in twice */
 static sbCFuncStatus please_call_again(hVm vm, flag init) {
   hVal *target = sbVm_pop(vm);
-  if (target->type <= 0) {
+  if (init && target->type <= 0) {
     PANIC("i have not implemented partial methods for builtin types yet! i'll get to it");
+  } else if (!init && target->type != IT_REF) {
+    PANIC("object illegally did not return a reference!");
   }
 
   if (init) {
     /* first time around: call to dispatch method */
     sbVm_call_func(vm, target);
 
-    /* please call us again if you have any questions*/
+    /* please call us again if you have any questions */
     return CFUNC_NEXT;
   } else {
     /* second time around: call method on its parameters */
-    sbVm_transfer_to_func(vm, target);
+    hVal *bound_method_ptr = sbVar_get_value_ptr(sbVar_deref(target));
+    sbVm_transfer_to_func(vm, bound_method_ptr);
 
     /* please forget we ever existed */
     return CFUNC_TAILCALL;
index 85cd49b..9c60df9 100644 (file)
@@ -12,13 +12,13 @@ typedef sbLibTable {
   hSymbol *keys;
   union {
     sbLibMethod *methods;
-    hVal *values;
+    sbVar *values;
   };
 } sbLibTable;
 */
 
 static void insert_method(hSymbol *keys, sbLibMethod *methods, usize capacity, hSymbol key, sbLibMethod *method);
-static void insert_value(hSymbol *keys, hVal *values, usize capacity, hSymbol key, hVal *value);
+static void insert_value(hSymbol *keys, sbVar *values, usize capacity, hSymbol key, hVal *value);
 static void check_grow_table(hLibTable t);
 
 void sbLibTable_initialize(hLibTable t, usize capacity, flag method_table) {
@@ -74,12 +74,30 @@ hVal *sbLibTable_find_value(hLibTable t, hSymbol key) {
   }
 
   if (t->keys[index]) {
-    return &t->values[index];
+    return sbVar_get_value_ptr(&t->values[index]);
   } else {
     return NULL;
   }
 }
 
+hVal sbLibTable_find_ref(hLibTable t, hSymbol key) {
+  if (t->method_table) CHECK("cannot find value in method table");
+
+  sbHashValue hash = sbHash_hash_bytes((const char*)&key, sizeof(hSymbol));
+  usize index = hash % t->capacity;
+  while (t->keys[index] && t->keys[index] != key) {
+    index ++;
+    index %= t->capacity;
+  }
+
+  if (t->keys[index]) {
+    /* lvalue ref always safe because these never get deallocated */
+    return sbVar_get_lvalue_ref(&t->values[index]);
+  } else {
+    return HVNIL;
+  }
+}
+
 void sbLibTable_register_method_sym(hLibTable t, hSymbol key, sbLibMethod *method) {
   if (!t->method_table) CHECK("cannot put method in non-method table");
 
@@ -123,7 +141,7 @@ static void insert_method(hSymbol *keys, sbLibMethod *methods, usize capacity, h
   methods[index] = *method;
 }
 
-static void insert_value(hSymbol *keys, hVal *values, usize capacity, hSymbol key, hVal *value) {
+static void insert_value(hSymbol *keys, sbVar *values, usize capacity, hSymbol key, hVal *value) {
   sbHashValue hash = sbHash_hash_bytes((const char*)&key, sizeof(hSymbol));
   usize index = hash % capacity;
 
@@ -133,7 +151,7 @@ static void insert_value(hSymbol *keys, hVal *values, usize capacity, hSymbol ke
   }
 
   keys[index] = key;
-  values[index] = *value;
+  sbVar_set_value(&values[index], value);
 }
 
 static void check_grow_table(hLibTable t) {
@@ -154,11 +172,11 @@ static void check_grow_table(hLibTable t) {
       free(t->methods);
       t->methods = new_methods;
     } else {
-      hVal *new_values = calloc(new_capacity, sizeof(hVal));
+      sbVar *new_values = calloc(new_capacity, sizeof(hVal));
 
       for (usize i = 0; i < t->capacity; i++) {
         if (t->keys[i] != 0) {
-          insert_value(new_keys, new_values, new_capacity, t->keys[i], &t->values[i]);
+          insert_value(new_keys, new_values, new_capacity, t->keys[i], sbVar_get_value_ptr(&t->values[i]));
         }
       }
 
index bcf2add..72649bb 100644 (file)
@@ -13,7 +13,7 @@ typedef struct sbLibTable {
   flag method_table;
   union {
       sbLibMethod *methods;
-      hVal *values;
+      sbVar *values;
   };
 } sbLibTable;
 
@@ -27,6 +27,8 @@ sbLibMethod *sbLibTable_find_method(hLibTable t, hSymbol key);
 
 hVal *sbLibTable_find_value(hLibTable t, hSymbol key);
 
+hVal sbLibTable_find_ref(hLibTable t, hSymbol key);
+
 void sbLibTable_register_method(hLibTable t, const char *method_name, usize method_name_length, sbLibMethod *method);
 
 void sbLibTable_register_method_sym(hLibTable t, hSymbol key, sbLibMethod *method);
index c246edd..e96e17e 100644 (file)
@@ -25,7 +25,8 @@ typedef enum sbOpcode {
   BC_SWAP,              // swap top two values on stack
   BC_CALL,              // push return address and jump to new block
   BC_CALL_IND,          // 'a->(...)' indirect call that can return a value
-  BC_DOT,               // 'a.b' indirect call that should return a reference
+  BC_DOT,               // 'a.b' call that should return a reference
+  BC_DOT_IND,           // 'a.b' indirect call that should return a reference
   BC_RET,               // return to calling block
   BC_NUMARG,            // check number of function arguments = this
   BC_MINARG,            // check number of function arguments > this
@@ -53,7 +54,9 @@ typedef enum sbOpcode {
   BC_OP_OR,             // logical or
   BC_OP_INDEXVAL,       // a[...]
   BC_OP_INDEXLREF,      // a[...] = ...
+  BC_OP_INDEXLREF_IND,  // a[...] = ...
   BC_OP_INDEXRREF,      // &a[...]
+  BC_OP_INDEXRREF_IND,  // &a[...]
   BC_OP_RANGEINDEX,     // index [a..b]
   BC_ALLOC_VARS,        // create space in rstack for local variables
   BC_CLOSURE,           // create closure from top elements of stack
index f68f119..24d93d0 100644 (file)
@@ -458,17 +458,22 @@ void execute_instruction(hVm vm) {
       swap_stack_top(vm);
       break;
     case BC_CALL:
+    case BC_DOT:
       v = pop_stack(vm);
       sbVm_call_func(vm, v);
       break;
-    case BC_DOT:
+    case BC_DOT_IND:
     case BC_CALL_IND:
       v = pop_stack(vm);
-      if (v->type != IT_REF) {
+      if (v->type == IT_REF) {
+        vars = sbVar_deref(v);
+        w = sbVar_get_value_ptr(vars);
+        sbVm_call_func(vm, w);
+      } else if (v->type & IT_FLAG_BOUND_METHOD) {
+        sbVm_call_func(vm, v);
+      } else {
         PANIC("object illegally returned non-reference value");
       }
-      vars = sbVar_deref(v);
-      sbVm_call_func(vm, sbVar_get_value_ptr(vars));
       break;
     case BC_SEND:
       sbLib_resolve_method(vm);
@@ -608,10 +613,16 @@ void execute_instruction(hVm vm) {
       sbV_index_value(vm);
       break;
     case BC_OP_INDEXLREF:
-      sbV_index_lref(vm);
+      sbV_index_ref(vm, TRUE, FALSE);
+      break;
+    case BC_OP_INDEXLREF_IND:
+      sbV_index_ref(vm, TRUE, TRUE);
       break;
     case BC_OP_INDEXRREF:
-      sbV_index_rref(vm);
+      sbV_index_ref(vm, FALSE, FALSE);
+      break;
+    case BC_OP_INDEXRREF_IND:
+      sbV_index_ref(vm, FALSE, TRUE);
       break;
     case BC_OP_RANGEINDEX:
       v = peek_stack(vm, 2);
index fcd4e33..d1ad06f 100644 (file)
@@ -148,52 +148,39 @@ void sbV_index_value(hVm vm) {
   }
 }
 
-void sbV_index_lref(hVm vm) {
+void sbV_index_ref(hVm vm, flag is_lref, flag is_indirect) {
   hVal *a = sbVm_peek(vm, 1);
   hVal *b = sbVm_peek(vm, 0);
-  if (a->type != IT_REF) {
-    PANIC("Object illegally returned non-reference!");
+
+  if (is_indirect) {
+    if (a->type != IT_REF) {
+      PANIC("Object illegally returned non-reference!");
+    }
+    a = sbVar_get_value_ptr(sbVar_deref(a));
   }
-  a = sbVar_get_value_ptr(sbVar_deref(a));
 
   if (a->type == IT_LIST && b->type == IT_INTEGER) {
     sbVm_npop(vm, 2);
-    hVal result = sbList_index_lvalue_ref(a->list, b->integer);
+    hVal result;
+    if (is_lref) {
+      result = sbList_index_lvalue_ref(a->list, b->integer);
+    } else {
+      result = sbList_index_rvalue_ref(a->list, b->integer);
+    }
     sbVm_push(vm, &result);
   } else if (a->type == IT_HASH) {
     sbVm_npop(vm, 2);
-    hVal result = sbHash_find_lvalue_ref(a->hash, b);
+    hVal result;
+    if (is_lref) {
+      result = sbHash_find_lvalue_ref(a->hash, b);
+    } else {
+      result = sbHash_find_rvalue_ref(a->hash, b);
+    }
     sbVm_push(vm, &result);
   } else if (a->type == IT_MODULE && b->type == IT_SYMBOL) {
-    PANIC("TODO");
-  } else {
-    sbVm_swap(vm);                                      /* b a */
-    sbVm_push_immediate(vm, &HVSYM(S_OP_INDEX));        /* b a op::index */
-    sbVm_swap(vm);                                      /* b op::index a */
-    sbVm_push_immediate(vm, &HVINT(2));                 /* b op::index a 2 */
-    sbVm_swap(vm);                                      /* b op::index 2 a */
-    sbLib_resolve_method(vm);
-  }
-}
-
-void sbV_index_rref(hVm vm) {
-  hVal *a = sbVm_peek(vm, 1);
-  hVal *b = sbVm_peek(vm, 0);
-  if (a->type != IT_REF) {
-    PANIC("Object illegally returned non-reference!");
-  }
-  a = sbVar_get_value_ptr(sbVar_deref(a));
-
-  if (a->type == IT_LIST && b->type == IT_INTEGER) {
-    sbVm_npop(vm, 2);
-    hVal result = sbList_index_rvalue_ref(a->list, b->integer);
-    sbVm_push(vm, &result);
-  } else if (a->type == IT_HASH) {
     sbVm_npop(vm, 2);
-    hVal result = sbHash_find_rvalue_ref(a->hash, b);
+    hVal result = sbLibTable_find_ref(a->module, b->symbol);
     sbVm_push(vm, &result);
-  } else if (a->type == IT_MODULE && b->type == IT_SYMBOL) {
-    PANIC("TODO");
   } else {
     sbVm_swap(vm);                                      /* b a */
     sbVm_push_immediate(vm, &HVSYM(S_OP_INDEX));        /* b a op::index */
index 12270e9..7c9844c 100644 (file)
@@ -26,9 +26,7 @@ hVal sbV_append(hVal *a, hVal *b);
 
 void sbV_index_value(hVm vm);
 
-void sbV_index_lref(hVm vm);
-
-void sbV_index_rref(hVm vm);
+void sbV_index_ref(hVm vm, flag is_lref, flag is_indirect);
 
 hVal sbV_rangeindex(hVal *a, hVal *b, hVal *c);