From: cassowarii Date: Tue, 7 Jul 2026 18:43:53 +0000 (-0700) Subject: map and filter methods for lists X-Git-Url: https://git.cassowary.me/gitweb.cgi?a=commitdiff_plain;h=122b4f221902b41242a795b3b935b8b5ded978da;p=sarabande.git map and filter methods for lists --- diff --git a/src/data/methods.c b/src/data/methods.c index dbd57e4..653f309 100644 --- a/src/data/methods.c +++ b/src/data/methods.c @@ -8,6 +8,7 @@ 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 sbList_method(hVm vm) { hV *list = sbVm_pop(vm); @@ -23,30 +24,41 @@ void sbList_method(hVm vm) { 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("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("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("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("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 { PANIC("method name to list is not symbol! (%lld)", (long long)method_name_val->type); @@ -81,3 +93,78 @@ void list_each_cfunc(hVm vm, flag init) { 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]); + } +}