bound methods for intrinsic types
authorcassowarii <cassowary@cassowary.me>
Mon, 13 Jul 2026 02:34:09 +0000 (19:34 -0700)
committercassowarii <cassowary@cassowary.me>
Mon, 13 Jul 2026 02:34:09 +0000 (19:34 -0700)
src/data/value.h
src/lib/lib.c
src/vm/exec.c

index 804eb13..6aa6a63 100644 (file)
@@ -3,7 +3,7 @@
 
 #include "global.h"
 
-#define FLAG_SQUIGGLY (1ULL << 62)
+#define IT_FLAG_BOUND_METHOD (1ULL << 62)
 
 #define HVINT(n) ((hV) { .type = IT_INTEGER, .integer = n })
 #define HVFLOAT(f) ((hV) { .type = IT_FLOAT, .float_val = f })
@@ -15,8 +15,8 @@
 #define HVNIL ((hV) { .type = IT_NIL })
 #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 })
+#define HVBOUNDMETHOD(m, t) ((hV) { .type = m | IT_FLAG_BOUND_METHOD, .ref = t })
 #define HVMODULE(m) ((hV) { .type = IT_MODULE, .module = m })
 
 struct sbVm;
index 11dcc28..c0dea9d 100644 (file)
@@ -1,7 +1,9 @@
 #include "common.h"
-#include "data/symbol.h"
 #include "vm/exec.h"
 
+#include "data/symbol.h"
+#include "data/reference.h"
+
 #include "lib/table.h"
 #include "lib/sentinel.h"
 #include "lib/method.h"
@@ -96,8 +98,6 @@ void sbLib_resolve_method(hVm vm) {
  * (non-intrinsic types are always functions, so they can be resolved just by
  *  calling them)*/
 void sbLib_resolve_property(hVm vm) {
-  printf("Resolving property\n");
-  sbVm_print_stack(vm);
   hV *target = sbVm_pop(vm);
   hV *argc = sbVm_pop(vm);
   if (argc->type != IT_INTEGER) {
@@ -132,7 +132,8 @@ void sbLib_resolve_property(hVm vm) {
       } else {
         /* it is a method, but it is being called without parameters.
          * annoyingly, we need to construct a bound version of this method. */
-        PANIC("I haven't done this yet!");
+        hRef ref = sbRef_create(target);
+        sbVm_push_immediate(vm, &HVBOUNDMETHOD(method_name_val->symbol, ref));
       }
     } else {
       PANIC("invalid method name for type %lld: %s", (long long)target->type, sbSymbol_name(method_name_val->symbol));
index f4dd780..2d2ee7c 100644 (file)
@@ -8,6 +8,7 @@
 
 void call_block(hVm vm, usize block_id, hClosure closure);
 void call_builtin(hVm vm, hV *to_call);
+void call_bound_method(hVm vm, hV *to_call);
 void return_from_block(hVm vm);
 void execute_instruction(hVm vm);
 void push_stack(hVm vm, hV *value);
@@ -82,6 +83,12 @@ void sbVm_swap(hVm vm) {
 void sbVm_call_func(hVm vm, hV *func) {
   if (func->type == IT_BUILTIN) {
     call_builtin(vm, func);
+  } else if (func->type <= 0) {
+    /* intrinsic type: resolve a property on it */
+    push_stack(vm, func);
+    sbLib_resolve_property(vm);
+  } else if (func->type & IT_FLAG_BOUND_METHOD) {
+    call_bound_method(vm, func);
   } else {
     call_block(vm, func->type, func->closure);
   }
@@ -164,6 +171,27 @@ void call_block(hVm vm, usize block_id, hClosure closure) {
   vm->ip = &blk->bytecode[0];
 }
 
+void call_bound_method(hVm vm, hV *to_call) {
+  if (!(to_call->type & IT_FLAG_BOUND_METHOD)) {
+    CHECK("call_bound_method can only call bound methods!");
+  }
+
+  /* bound method is just a symbol + a closure containing one variable */
+  hSymbol sym = (hSymbol)(to_call->type & ~IT_FLAG_BOUND_METHOD);
+  hRef ref = (to_call->ref);
+
+  /* we should already have parameters, so we just need to line it back up
+   * on the stack and call the method again */
+  push_stack_immediate(vm, &HVSYM(sym));
+  swap_stack_top(vm);
+  if (peek_stack(vm, 0)->type != IT_INTEGER) {
+    CHECK("bound method call should receive an integer arg count!");
+  }
+  peek_stack(vm, 0)->integer ++;
+  push_stack(vm, sbRef_deref(ref));
+  sbLib_resolve_method(vm);
+}
+
 void return_from_block(hVm vm) {
   for (usize i = 0; i < vm->fp->num_locals; i++) {
     sbV_release(&vm->fp->locals[i]);
@@ -483,15 +511,7 @@ void execute_instruction(hVm vm) {
       break;
     case BC_CALL:
       v = pop_stack(vm);
-      if (v->type == IT_BUILTIN) {
-        call_builtin(vm, v);
-      } else if (v->type <= 0) {
-        /* intrinsic type: resolve a property on it */
-        push_stack(vm, v);
-        sbLib_resolve_property(vm);
-      } else {
-        call_block(vm, v->type, v->closure);
-      }
+      sbVm_call_func(vm, v);
       break;
     case BC_SEND:
       sbLib_resolve_method(vm);