methods for integer + string, more list methods
authorcassowarii <2374677+cassowarii@users.noreply.github.com>
Wed, 8 Jul 2026 23:36:30 +0000 (16:36 -0700)
committercassowarii <2374677+cassowarii@users.noreply.github.com>
Wed, 8 Jul 2026 23:36:30 +0000 (16:36 -0700)
I need to restructure how methods are resolved, right now it is bad

src/data/integer.c
src/data/integer.h
src/data/list.c
src/data/list.h
src/data/methods.c [deleted file]
src/data/methods.h [deleted file]
src/data/string.c
src/data/string.h
src/vm/operations.c

index 337c853..94524c0 100644 (file)
@@ -1,5 +1,11 @@
 #include "integer.h"
 
+#include "vm/exec.h"
+#include "data/symbol.h"
+#include "data/string.h"
+
+#define METHOD_IS(name) (!sbstrncmp(method_name, name, sizeof(name)))
+
 /* reserve high bit for sign bit.
  * second-highest bit marks this as a handle to a bigint, which
  * means normally integers have to be less than +/- 2^62. */
@@ -97,6 +103,45 @@ hInteger sbInteger_floordiv(hInteger a, hInteger b) {
   PANIC("I haven't implemented this yet!");
 }
 
+void sbInteger_method(hVm vm) {
+  hV *target = sbVm_pop(vm);
+  if (target->type != IT_INTEGER) {
+    CHECK("can't call sbInteger_method on something that isn't an integer");
+  }
+  hV *argc = sbVm_pop(vm);
+  if (argc->type != IT_INTEGER) {
+    CHECK("argc of send should be integer!");
+  }
+
+  /* subtract 1 because the method name is itself a param */
+  usize num_params = argc->integer - 1;
+  hV *method_name_val = sbVm_peek(vm, num_params);
+  if (method_name_val->type != IT_SYMBOL) {
+    /* TODO this may become not true */
+    PANIC("method name for list must be symbol!");
+  }
+
+  const char *method_name = sbSymbol_name(method_name_val->symbol);
+  /* TODO: Need a better way of resolving these */
+  /* also TODO shouldn't be 'to_string' */
+  if (METHOD_IS("to_string")) {
+    sbVm_pop(vm); /* remove method name */
+    char stackbuf[1024];
+    char *buf = stackbuf;
+    usize length = snprintf(buf, 1024, "%lld", (long long)target->integer);
+    if (length + 1 >= sizeof(stackbuf)) {
+      buf = malloc(length + 1);
+      snprintf(buf, length, "%lld", (long long)target->integer);
+    }
+    sbVm_push_immediate(vm, &HVSTR(sbString_new(buf, length)));
+    if (buf != stackbuf) {
+      free(buf);
+    }
+  } else {
+    PANIC("unknown method name for integer");
+  }
+}
+
 /* --- */
 
 flag is_bigint(hInteger n) {
index 2d6225a..c279545 100644 (file)
@@ -16,3 +16,5 @@ hInteger sbInteger_diff(hInteger a, hInteger b);
 hInteger sbInteger_mul(hInteger a, hInteger b);
 
 hInteger sbInteger_floordiv(hInteger a, hInteger b);
+
+void sbInteger_method(hVm vm);
index 1c7cb02..e55875b 100644 (file)
@@ -1,8 +1,18 @@
 #include "data/list.h"
 
 #include "gc/gcinfo.h"
+#include "vm/exec.h"
+#include "data/symbol.h"
+#include "data/string.h"
 
 #define LIST_PER_BLOCK 256
+#define METHOD_IS(name) (!sbstrncmp(method_name, name, sizeof(name)))
+
+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);
 
 /* TODO etc etc */
 sbPool g_list_pool;
@@ -49,8 +59,299 @@ hV *sbList_index(hList list, usize index) {
   return item;
 }
 
+void sbList_method(hVm vm) {
+  hV *list = sbVm_pop(vm);
+  if (list->type != IT_LIST) {
+    CHECK("can't call sbList_method on something that isn't a list");
+  }
+  hV *argc = sbVm_pop(vm);
+  if (argc->type != IT_INTEGER) {
+    CHECK("argc of send should be integer!");
+  }
+  /* subtract 1 because the method name is itself a param */
+  usize num_params = argc->integer - 1;
+  hV *method_name_val = sbVm_peek(vm, num_params);
+  if (method_name_val->type != IT_SYMBOL) {
+    /* TODO this may become not true */
+    PANIC("method name for list must be symbol!");
+  }
+
+  const char *method_name = sbSymbol_name(method_name_val->symbol);
+  /* TODO: Need a better way of resolving these */
+  if (METHOD_IS("length")) {
+    if (num_params != 0) {
+      PANIC("list#length takes no arguments!");
+    }
+    sbVm_pop(vm); /* remove method name */
+    usize length;
+    sbList_get_value(list->list, &length);
+    sbVm_push_immediate(vm, &HVINT(length));
+  } else if (METHOD_IS("push")) {
+    if (num_params != 1) {
+      PANIC("list#push expects 1 argument!");
+    }
+    hV *to_append = sbVm_pop(vm);
+    sbVm_pop(vm); /* remove method name */
+    sbList_append(list->list, to_append);
+    sbVm_push_immediate(vm, &HVNIL);
+  } else if (METHOD_IS("each")) {
+    if (num_params != 1) {
+      PANIC("wrong number of arguments passed to list#each");
+    }
+    sbVm_push_immediate(vm, list);
+    sbVm_call_c_func(vm, list_each_cfunc);
+  } else if (METHOD_IS("map")) {
+    if (num_params != 1) {
+      PANIC("wrong number of arguments passed to list#map");
+    }
+    sbVm_push_immediate(vm, list);
+    sbVm_call_c_func(vm, list_map_cfunc);
+  } else if (METHOD_IS("filter")) {
+    if (num_params != 1) {
+      PANIC("wrong number of arguments passed to list#filter");
+    }
+    sbVm_push_immediate(vm, list);
+    sbVm_call_c_func(vm, list_filter_cfunc);
+  } else if (METHOD_IS("any?")) {
+    if (num_params != 1) {
+      PANIC("wrong number of arguments passed to list#any?");
+    }
+    sbVm_push_immediate(vm, list);
+    sbVm_call_c_func(vm, list_any_cfunc);
+  } else if (METHOD_IS("all?")) {
+    if (num_params != 1) {
+      PANIC("wrong number of arguments passed to list#any?");
+    }
+    sbVm_push_immediate(vm, list);
+    sbVm_call_c_func(vm, list_all_cfunc);
+  } else if (METHOD_IS("reverse")) {
+    if (num_params != 0) {
+      PANIC("list#reverse takes no arguments!");
+    }
+    /* TODO maybe mutate in place if no other refs */
+    sbVm_pop(vm); /* remove method name */
+    usize length;
+    hV *elems = sbList_get_value(list->list, &length);
+    hList new_list = sbList_new(length);
+    for (usize i = length - 1; ; i--) {
+      sbList_append(new_list, &elems[i]);
+      if (i == 0) break;
+    }
+    sbList_get_value(new_list, &length);
+    sbVm_push_immediate(vm, &HVLIST(new_list));
+  } else if (METHOD_IS("join")) {
+    if (num_params > 1) {
+      PANIC("list#join takes no arguments or 1 argument!");
+    }
+    flag join_with = FALSE;
+    hString delimiter;
+    if (num_params == 1) {
+      hV *delimiter_v = sbVm_pop(vm);
+      if (delimiter_v->type != IT_STRING) {
+        PANIC("list#join parameter should be string!");
+      }
+      join_with = TRUE;
+      delimiter = delimiter_v->string;
+    }
+    sbVm_pop(vm); /* remove method name */
+    usize length;
+    hV *elems = sbList_get_value(list->list, &length);
+    hString joined = sbString_new("", 0);
+    for (usize i = 0; i < length; i++) {
+      if (elems[i].type != IT_STRING) {
+        PANIC("need string to join");
+      }
+      joined = sbString_concat(joined, elems[i].string);
+      if (join_with && i < length - 1) {
+        joined = sbString_concat(joined, delimiter);
+      }
+    }
+    sbVm_push_immediate(vm, &HVSTR(joined));
+  } else {
+    PANIC("unknown method name for list");
+  }
+}
+
 /* --- */
 
 sbList *get_list_by_handle(hList handle) {
   return sbPool_get_entry(&g_list_pool, handle);
 }
+
+void 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);
+    hV *iterating_list = sbVm_pop(vm);
+    hV *loop_func = sbVm_pop(vm);
+    sbVm_pop(vm); /* remove method name */
+    hV index = HVINT(0);
+    vm->fp->locals[0] = *iterating_list;
+    vm->fp->locals[1] = index;
+    vm->fp->locals[2] = *loop_func;
+  } else {
+    /* loop func must have finished, so remove its result */
+    sbVm_pop(vm);
+  }
+
+  usize current_index = vm->fp->locals[1].integer++;
+  usize length;
+  hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
+  if (current_index < length) {
+    sbVm_push(vm, &iter_values[current_index]);
+    sbVm_push_immediate(vm, &HVINT(1));
+    sbVm_call_func(vm, &vm->fp->locals[2]);
+  } else {
+    /* if index was past the end, callback function won't be called, and we'll exit. return nil */
+    sbVm_push_immediate(vm, &HVNIL);
+  }
+}
+
+void list_map_cfunc(hVm vm, flag init) {
+  if (init) {
+    /* state: list being mapped, index, callback, result */
+    sbVm_request_var_space(vm, 4);
+    hV *iterating_list = sbVm_pop(vm);
+    hV *map_func = sbVm_pop(vm);
+    sbVm_pop(vm); /* remove method name */
+    usize length;
+    sbList_get_value(iterating_list->list, &length);
+    hV index = HVINT(0);
+    hV result = sbV_empty_list(length);
+
+    vm->fp->locals[0] = *iterating_list;
+    vm->fp->locals[1] = index;
+    vm->fp->locals[2] = *map_func;
+    vm->fp->locals[3] = result;
+  } else {
+    /* get result of map function and append its result to result list */
+    hV *mapped = sbVm_pop(vm);
+    sbList_append(vm->fp->locals[3].list, mapped);
+  }
+
+  usize current_index = vm->fp->locals[1].integer++;
+  usize length;
+  hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
+  if (current_index < length) {
+    sbVm_push(vm, &iter_values[current_index]);
+    sbVm_push_immediate(vm, &HVINT(1));
+    sbVm_call_func(vm, &vm->fp->locals[2]);
+  } else {
+    /* return result list */
+    sbVm_push_immediate(vm, &vm->fp->locals[3]);
+  }
+}
+
+void list_filter_cfunc(hVm vm, flag init) {
+  if (init) {
+    /* state: list being filtered, index, callback, result */
+    sbVm_request_var_space(vm, 4);
+    hV *iterating_list = sbVm_pop(vm);
+    hV *filter_func = sbVm_pop(vm);
+    sbVm_pop(vm); /* remove method name */
+    usize length;
+    sbList_get_value(iterating_list->list, &length);
+    hV index = HVINT(0);
+    hV result = sbV_empty_list(length);
+
+    vm->fp->locals[0] = *iterating_list;
+    vm->fp->locals[1] = index;
+    vm->fp->locals[2] = *filter_func;
+    vm->fp->locals[3] = result;
+  } else {
+    /* get result of filter function and append element to result if true */
+    hV *mapped = sbVm_pop(vm);
+    hV *element = sbVm_pop(vm);
+    if (!sbV_c_falsy(mapped)) {
+      sbList_append(vm->fp->locals[3].list, element);
+    }
+  }
+
+  usize current_index = vm->fp->locals[1].integer++;
+  usize length;
+  hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
+  if (current_index < length) {
+    /* put current value on stack twice: once as parameter for function, once to save for ourselves */
+    sbVm_push(vm, &iter_values[current_index]);
+    sbVm_push(vm, &iter_values[current_index]);
+    sbVm_push_immediate(vm, &HVINT(1));
+    sbVm_call_func(vm, &vm->fp->locals[2]);
+  } else {
+    /* return result list */
+    sbVm_push_immediate(vm, &vm->fp->locals[3]);
+  }
+}
+
+void list_any_cfunc(hVm vm, flag init) {
+  if (init) {
+    /* state: list being filtered, index, callback */
+    sbVm_request_var_space(vm, 3);
+    hV *iterating_list = sbVm_pop(vm);
+    hV *pred_func = sbVm_pop(vm);
+    sbVm_pop(vm); /* remove method name */
+    hV index = HVINT(0);
+
+    vm->fp->locals[0] = *iterating_list;
+    vm->fp->locals[1] = index;
+    vm->fp->locals[2] = *pred_func;
+  } else {
+    /* get result of predicate function */
+    hV *mapped = sbVm_pop(vm);
+    if (!sbV_c_falsy(mapped)) {
+      /* one was true! return true */
+      sbVm_push_immediate(vm, &HVBOOL(TRUE));
+      return;
+    }
+  }
+
+  /* haven't found any yet... */
+  usize current_index = vm->fp->locals[1].integer++;
+  usize length;
+  hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
+  if (current_index < length) {
+    /* try next element */
+    sbVm_push(vm, &iter_values[current_index]);
+    sbVm_push_immediate(vm, &HVINT(1));
+    sbVm_call_func(vm, &vm->fp->locals[2]);
+  } else {
+    /* no result found */
+    sbVm_push_immediate(vm, &HVBOOL(FALSE));
+  }
+}
+
+void list_all_cfunc(hVm vm, flag init) {
+  if (init) {
+    /* state: list being filtered, index, callback */
+    sbVm_request_var_space(vm, 3);
+    hV *iterating_list = sbVm_pop(vm);
+    hV *pred_func = sbVm_pop(vm);
+    sbVm_pop(vm); /* remove method name */
+    hV index = HVINT(0);
+
+    vm->fp->locals[0] = *iterating_list;
+    vm->fp->locals[1] = index;
+    vm->fp->locals[2] = *pred_func;
+  } else {
+    /* get result of predicate function */
+    hV *mapped = sbVm_pop(vm);
+    if (sbV_c_falsy(mapped)) {
+      /* one was false; return false */
+      sbVm_push_immediate(vm, &HVBOOL(FALSE));
+      return;
+    }
+  }
+
+  /* all true so far */
+  usize current_index = vm->fp->locals[1].integer++;
+  usize length;
+  hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
+  if (current_index < length) {
+    /* try next element */
+    sbVm_push(vm, &iter_values[current_index]);
+    sbVm_push_immediate(vm, &HVINT(1));
+    sbVm_call_func(vm, &vm->fp->locals[2]);
+  } else {
+    /* all passed */
+    sbVm_push_immediate(vm, &HVBOOL(TRUE));
+  }
+}
index 65e6a1e..36b32a0 100644 (file)
@@ -11,3 +11,5 @@ void sbList_append(hList list, hV *item);
 hV *sbList_get_value(hList list, usize *length);
 
 hV *sbList_index(hList list, usize index);
+
+void sbList_method(hVm vm);
diff --git a/src/data/methods.c b/src/data/methods.c
deleted file mode 100644 (file)
index dbe6e6e..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-#include "data/methods.h"
-
-#include "vm/exec.h"
-#include "data/symbol.h"
-#include "data/list.h"
-
-#define METHOD_IS(name) (!sbstrncmp(method_name, name, sizeof(name)))
-
-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);
-
-void sbList_method(hVm vm) {
-  hV *list = sbVm_pop(vm);
-  if (list->type != IT_LIST) {
-    CHECK("can't call sbList_method on something that isn't a list");
-  }
-  hV *argc = sbVm_pop(vm);
-  if (argc->type != IT_INTEGER) {
-    CHECK("argc of send should be integer!");
-  }
-  /* subtract 1 because the method name is itself a param */
-  usize num_params = argc->integer - 1;
-  hV *method_name_val = sbVm_peek(vm, num_params);
-  if (method_name_val->type == IT_SYMBOL) {
-    const char *method_name = sbSymbol_name(method_name_val->symbol);
-    /* TODO: Need a better way of resolving these */
-    if (METHOD_IS("length")) {
-      if (num_params != 0) {
-        PANIC("list#length takes no arguments!");
-      }
-      sbVm_pop(vm); /* remove method name */
-      usize length;
-      sbList_get_value(list->list, &length);
-      sbVm_push_immediate(vm, &HVINT(length));
-    } else if (METHOD_IS("push")) {
-      if (num_params != 1) {
-        PANIC("list#push expects 1 argument!");
-      }
-      hV *to_append = sbVm_pop(vm);
-      sbVm_pop(vm); /* remove method name */
-      sbList_append(list->list, to_append);
-      sbVm_push_immediate(vm, &HVNIL);
-    } else if (METHOD_IS("each")) {
-      if (num_params != 1) {
-        PANIC("wrong number of arguments passed to list#each");
-      }
-      sbVm_push_immediate(vm, list);
-      sbVm_call_c_func(vm, list_each_cfunc);
-    } else if (METHOD_IS("map")) {
-      if (num_params != 1) {
-        PANIC("wrong number of arguments passed to list#map");
-      }
-      sbVm_push_immediate(vm, list);
-      sbVm_call_c_func(vm, list_map_cfunc);
-    } else if (METHOD_IS("filter")) {
-      if (num_params != 1) {
-        PANIC("wrong number of arguments passed to list#filter");
-      }
-      sbVm_push_immediate(vm, list);
-      sbVm_call_c_func(vm, list_filter_cfunc);
-    } else if (METHOD_IS("any?")) {
-      if (num_params != 1) {
-        PANIC("wrong number of arguments passed to list#any?");
-      }
-      sbVm_push_immediate(vm, list);
-      sbVm_call_c_func(vm, list_any_cfunc);
-    } else if (METHOD_IS("all?")) {
-      if (num_params != 1) {
-        PANIC("wrong number of arguments passed to list#any?");
-      }
-      sbVm_push_immediate(vm, list);
-      sbVm_call_c_func(vm, list_all_cfunc);
-    }
-  } else {
-    PANIC("method name to list is not symbol! (%lld)", (long long)method_name_val->type);
-  }
-}
-
-void 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);
-    hV *iterating_list = sbVm_pop(vm);
-    hV *loop_func = sbVm_pop(vm);
-    sbVm_pop(vm); /* remove method name */
-    hV index = HVINT(0);
-    vm->fp->locals[0] = *iterating_list;
-    vm->fp->locals[1] = index;
-    vm->fp->locals[2] = *loop_func;
-  } else {
-    /* loop func must have finished, so remove its result */
-    sbVm_pop(vm);
-  }
-
-  usize current_index = vm->fp->locals[1].integer++;
-  usize length;
-  hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
-  if (current_index < length) {
-    sbVm_push(vm, &iter_values[current_index]);
-    sbVm_push_immediate(vm, &HVINT(1));
-    sbVm_call_func(vm, &vm->fp->locals[2]);
-  } else {
-    /* if index was past the end, callback function won't be called, and we'll exit. return nil */
-    sbVm_push_immediate(vm, &HVNIL);
-  }
-}
-
-void list_map_cfunc(hVm vm, flag init) {
-  if (init) {
-    /* state: list being mapped, index, callback, result */
-    sbVm_request_var_space(vm, 4);
-    hV *iterating_list = sbVm_pop(vm);
-    hV *map_func = sbVm_pop(vm);
-    sbVm_pop(vm); /* remove method name */
-    usize length;
-    sbList_get_value(iterating_list->list, &length);
-    hV index = HVINT(0);
-    hV result = sbV_empty_list(length);
-
-    vm->fp->locals[0] = *iterating_list;
-    vm->fp->locals[1] = index;
-    vm->fp->locals[2] = *map_func;
-    vm->fp->locals[3] = result;
-  } else {
-    /* get result of map function and append its result to result list */
-    hV *mapped = sbVm_pop(vm);
-    sbList_append(vm->fp->locals[3].list, mapped);
-  }
-
-  usize current_index = vm->fp->locals[1].integer++;
-  usize length;
-  hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
-  if (current_index < length) {
-    sbVm_push(vm, &iter_values[current_index]);
-    sbVm_push_immediate(vm, &HVINT(1));
-    sbVm_call_func(vm, &vm->fp->locals[2]);
-  } else {
-    /* return result list */
-    sbVm_push_immediate(vm, &vm->fp->locals[3]);
-  }
-}
-
-void list_filter_cfunc(hVm vm, flag init) {
-  if (init) {
-    /* state: list being filtered, index, callback, result */
-    sbVm_request_var_space(vm, 4);
-    hV *iterating_list = sbVm_pop(vm);
-    hV *filter_func = sbVm_pop(vm);
-    sbVm_pop(vm); /* remove method name */
-    usize length;
-    sbList_get_value(iterating_list->list, &length);
-    hV index = HVINT(0);
-    hV result = sbV_empty_list(length);
-
-    vm->fp->locals[0] = *iterating_list;
-    vm->fp->locals[1] = index;
-    vm->fp->locals[2] = *filter_func;
-    vm->fp->locals[3] = result;
-  } else {
-    /* get result of filter function and append element to result if true */
-    hV *mapped = sbVm_pop(vm);
-    hV *element = sbVm_pop(vm);
-    if (!sbV_c_falsy(mapped)) {
-      sbList_append(vm->fp->locals[3].list, element);
-    }
-  }
-
-  usize current_index = vm->fp->locals[1].integer++;
-  usize length;
-  hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
-  if (current_index < length) {
-    /* put current value on stack twice: once as parameter for function, once to save for ourselves */
-    sbVm_push(vm, &iter_values[current_index]);
-    sbVm_push(vm, &iter_values[current_index]);
-    sbVm_push_immediate(vm, &HVINT(1));
-    sbVm_call_func(vm, &vm->fp->locals[2]);
-  } else {
-    /* return result list */
-    sbVm_push_immediate(vm, &vm->fp->locals[3]);
-  }
-}
-
-void list_any_cfunc(hVm vm, flag init) {
-  if (init) {
-    /* state: list being filtered, index, callback */
-    sbVm_request_var_space(vm, 3);
-    hV *iterating_list = sbVm_pop(vm);
-    hV *pred_func = sbVm_pop(vm);
-    sbVm_pop(vm); /* remove method name */
-    hV index = HVINT(0);
-
-    vm->fp->locals[0] = *iterating_list;
-    vm->fp->locals[1] = index;
-    vm->fp->locals[2] = *pred_func;
-  } else {
-    /* get result of predicate function */
-    hV *mapped = sbVm_pop(vm);
-    if (!sbV_c_falsy(mapped)) {
-      /* one was true! return true */
-      sbVm_push_immediate(vm, &HVBOOL(TRUE));
-      return;
-    }
-  }
-
-  /* haven't found any yet... */
-  usize current_index = vm->fp->locals[1].integer++;
-  usize length;
-  hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
-  if (current_index < length) {
-    /* try next element */
-    sbVm_push(vm, &iter_values[current_index]);
-    sbVm_push_immediate(vm, &HVINT(1));
-    sbVm_call_func(vm, &vm->fp->locals[2]);
-  } else {
-    /* no result found */
-    sbVm_push_immediate(vm, &HVBOOL(FALSE));
-  }
-}
-
-void list_all_cfunc(hVm vm, flag init) {
-  if (init) {
-    /* state: list being filtered, index, callback */
-    sbVm_request_var_space(vm, 3);
-    hV *iterating_list = sbVm_pop(vm);
-    hV *pred_func = sbVm_pop(vm);
-    sbVm_pop(vm); /* remove method name */
-    hV index = HVINT(0);
-
-    vm->fp->locals[0] = *iterating_list;
-    vm->fp->locals[1] = index;
-    vm->fp->locals[2] = *pred_func;
-  } else {
-    /* get result of predicate function */
-    hV *mapped = sbVm_pop(vm);
-    if (sbV_c_falsy(mapped)) {
-      /* one was false; return false */
-      sbVm_push_immediate(vm, &HVBOOL(FALSE));
-      return;
-    }
-  }
-
-  /* all true so far */
-  usize current_index = vm->fp->locals[1].integer++;
-  usize length;
-  hV *iter_values = sbList_get_value(vm->fp->locals[0].list, &length);
-  if (current_index < length) {
-    /* try next element */
-    sbVm_push(vm, &iter_values[current_index]);
-    sbVm_push_immediate(vm, &HVINT(1));
-    sbVm_call_func(vm, &vm->fp->locals[2]);
-  } else {
-    /* all passed */
-    sbVm_push_immediate(vm, &HVBOOL(TRUE));
-  }
-}
diff --git a/src/data/methods.h b/src/data/methods.h
deleted file mode 100644 (file)
index 1a4ce1b..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "common.h"
-
-void sbList_method(hVm vm);
index c9da7d2..13fc006 100644 (file)
@@ -2,9 +2,13 @@
 
 #include "gc/gcinfo.h"
 #include "gc/rc.h"
+#include "vm/exec.h"
+#include "data/list.h"
+#include "data/symbol.h"
 
 #define INLINE_BUFFER_SIZE 256
 #define STRINGS_PER_BLOCK 256
+#define METHOD_IS(name) (!sbstrncmp(method_name, name, sizeof(name)))
 
 /* highest bit unset on handle value means it is a tinystr. this is
  * so that 0x0000_0000_0000_0000 represents an empty string */
@@ -231,6 +235,38 @@ usize sbString_get_length(hString handle) {
   }
 }
 
+void sbString_method(hVm vm) {
+  hV *target = sbVm_pop(vm);
+  if (target->type != IT_STRING) {
+    CHECK("can't call sbString_method on something that isn't a string");
+  }
+  hV *argc = sbVm_pop(vm);
+  if (argc->type != IT_INTEGER) {
+    CHECK("argc of send should be integer!");
+  }
+  /* subtract 1 because the method name is itself a param */
+  usize num_params = argc->integer - 1;
+  hV *method_name_val = sbVm_peek(vm, num_params);
+  if (method_name_val->type != IT_SYMBOL) {
+    /* TODO this may become not true */
+    PANIC("method name for string must be symbol!");
+  }
+
+  const char *method_name = sbSymbol_name(method_name_val->symbol);
+  /* TODO: Need a better way of resolving these */
+  if (METHOD_IS("split")) {
+    sbVm_pop(vm); /* remove method name */
+    usize length;
+    char scratch[8];
+    const char *buf = sbString_get_value(target->string, scratch, &length);
+    hList l = sbList_new(length);
+    for (usize i = 0; i < length; i++) {
+      sbList_append(l, &HVSTR(sbString_new(&buf[i], 1)));
+    }
+    sbVm_push_immediate(vm, &HVLIST(l));
+  }
+}
+
 /* --- */
 
 static flag is_tinystr(hString handle) {
index 2406c2c..8d574c0 100644 (file)
@@ -73,5 +73,7 @@ int sbString_eq(hString a, hString b);
 int sbString_cmp(hString a, hString b);
 hString sbString_concat(hString a, hString b);
 
+void sbString_method(hVm vm);
+
 void sbString_sys_init();
 void sbString_sys_deinit();
index fdf10d6..6d89274 100644 (file)
@@ -4,7 +4,7 @@
 #include "data/integer.h"
 #include "data/list.h"
 #include "data/hashtable.h"
-#include "data/methods.h"
+#include "data/string.h"
 
 void sbV_message_handler(hVm vm) {
   hV *target = sbVm_peek(vm, 0);
@@ -12,6 +12,12 @@ void sbV_message_handler(hVm vm) {
     case IT_LIST:
       sbList_method(vm);
       break;
+    case IT_INTEGER:
+      sbInteger_method(vm);
+      break;
+    case IT_STRING:
+      sbString_method(vm);
+      break;
     default:
       if (target->type < 0) {
         PANIC("haven't implemented method calling for this intrinsic type!");