From 385f34e46571c4f87bdebbc83529d26d72ab27a6 Mon Sep 17 00:00:00 2001 From: cassowarii Date: Tue, 7 Jul 2026 11:55:26 -0700 Subject: [PATCH] "any?" and "all?" methods for lists --- src/data/methods.c | 122 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 105 insertions(+), 17 deletions(-) diff --git a/src/data/methods.c b/src/data/methods.c index 653f309..dbe6e6e 100644 --- a/src/data/methods.c +++ b/src/data/methods.c @@ -9,6 +9,8 @@ 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); @@ -25,40 +27,52 @@ void sbList_method(hVm vm) { 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("each")) { + 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!"); + 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!"); + 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!"); + 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("length")) { - if (num_params != 0) { - PANIC("list#length takes no arguments!"); + } else if (METHOD_IS("any?")) { + if (num_params != 1) { + PANIC("wrong number of arguments passed to list#any?"); } - 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")) { + sbVm_push_immediate(vm, list); + sbVm_call_c_func(vm, list_any_cfunc); + } else if (METHOD_IS("all?")) { if (num_params != 1) { - PANIC("list#push expects 1 argument!"); + PANIC("wrong number of arguments passed to list#any?"); } - hV *to_append = sbVm_pop(vm); - sbVm_pop(vm); /* remove method name */ - sbList_append(list->list, to_append); - sbVm_push_immediate(vm, &HVNIL); + 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); @@ -168,3 +182,77 @@ void list_filter_cfunc(hVm vm, flag init) { 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)); + } +} -- 1.8.3.1