From 42d85e14d9754fcf6eb09a007e5696ddc04cab2f Mon Sep 17 00:00:00 2001 From: cassowarii <2374677+cassowarii@users.noreply.github.com> Date: Wed, 8 Jul 2026 16:36:30 -0700 Subject: [PATCH] methods for integer + string, more list methods I need to restructure how methods are resolved, right now it is bad --- src/data/integer.c | 45 ++++++++ src/data/integer.h | 2 + src/data/list.c | 301 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/data/list.h | 2 + src/data/methods.c | 258 -------------------------------------------- src/data/methods.h | 3 - src/data/string.c | 36 +++++++ src/data/string.h | 2 + src/vm/operations.c | 8 +- 9 files changed, 395 insertions(+), 262 deletions(-) delete mode 100644 src/data/methods.c delete mode 100644 src/data/methods.h diff --git a/src/data/integer.c b/src/data/integer.c index 337c853..94524c0 100644 --- a/src/data/integer.c +++ b/src/data/integer.c @@ -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) { diff --git a/src/data/integer.h b/src/data/integer.h index 2d6225a..c279545 100644 --- a/src/data/integer.h +++ b/src/data/integer.h @@ -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); diff --git a/src/data/list.c b/src/data/list.c index 1c7cb02..e55875b 100644 --- a/src/data/list.c +++ b/src/data/list.c @@ -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)); + } +} diff --git a/src/data/list.h b/src/data/list.h index 65e6a1e..36b32a0 100644 --- a/src/data/list.h +++ b/src/data/list.h @@ -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 index dbe6e6e..0000000 --- a/src/data/methods.c +++ /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 index 1a4ce1b..0000000 --- a/src/data/methods.h +++ /dev/null @@ -1,3 +0,0 @@ -#include "common.h" - -void sbList_method(hVm vm); diff --git a/src/data/string.c b/src/data/string.c index c9da7d2..13fc006 100644 --- a/src/data/string.c +++ b/src/data/string.c @@ -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) { diff --git a/src/data/string.h b/src/data/string.h index 2406c2c..8d574c0 100644 --- a/src/data/string.h +++ b/src/data/string.h @@ -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(); diff --git a/src/vm/operations.c b/src/vm/operations.c index fdf10d6..6d89274 100644 --- a/src/vm/operations.c +++ b/src/vm/operations.c @@ -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!"); -- 1.8.3.1