From 0378b505e780bfe7d8d8f3619df58dc7d32ba9e7 Mon Sep 17 00:00:00 2001 From: cassowarii Date: Sun, 12 Jul 2026 15:42:29 -0700 Subject: [PATCH] add reduce, max, project euler #7, some other euler updates --- sample/project_euler/pe01.sa | 15 ++++---------- sample/project_euler/pe03.sa | 15 ++++---------- sample/project_euler/pe04.sa | 3 +-- sample/project_euler/pe05.sa | 10 +-------- sample/project_euler/pe06.sa | 6 +----- sample/project_euler/pe07.sa | 24 ++++++++++++++++++++++ src/lib/method/list.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ src/lib/module/math.c | 15 ++++++++++++++ src/vm/exec.c | 7 ++++++- 9 files changed, 104 insertions(+), 39 deletions(-) create mode 100644 sample/project_euler/pe07.sa diff --git a/sample/project_euler/pe01.sa b/sample/project_euler/pe01.sa index 4b26267..96d3c0f 100644 --- a/sample/project_euler/pe01.sa +++ b/sample/project_euler/pe01.sa @@ -1,11 +1,4 @@ -def sum list { - let s = 0 - list.each => elem { - s = s + elem - } - s -} - -println sum list::iota(1000).filter => num { - [3, 5].any? => factor { num %% factor } -} +list::iota(1000) + | _.filter => num { [3, 5].any? => factor { num %% factor } } + | _.reduce 0, => a, b { a + b } + | println diff --git a/sample/project_euler/pe03.sa b/sample/project_euler/pe03.sa index 295bdfc..9336183 100644 --- a/sample/project_euler/pe03.sa +++ b/sample/project_euler/pe03.sa @@ -1,13 +1,3 @@ -def max_positive list { - let result = 0 - - list.each => element { - result = element if element > result - } - - result -} - def factors num { let list = [] let candidate = 2 @@ -23,4 +13,7 @@ def prime? num { factors(num).length() == 0 } -println max_positive factors(600851475143).filter => num { prime? num } +factors 600851475143 + | _.filter(prime?) + | _.reduce(0, math::max) + | println diff --git a/sample/project_euler/pe04.sa b/sample/project_euler/pe04.sa index 48bd320..5e7b242 100644 --- a/sample/project_euler/pe04.sa +++ b/sample/project_euler/pe04.sa @@ -1,6 +1,5 @@ def is_palindrome num { - let string_num = num | string::from - string_num == string_num.split().reverse().join() + string::from num | _ == _.split().reverse().join() } let max = 0 diff --git a/sample/project_euler/pe05.sa b/sample/project_euler/pe05.sa index b5aed85..eabaf89 100644 --- a/sample/project_euler/pe05.sa +++ b/sample/project_euler/pe05.sa @@ -7,12 +7,4 @@ def gcd a, b { } } -def lcm nums { - let result = 1 - nums.each => num { - result = result * num // gcd(result, num) - } - result -} - -println lcm list::iota 1, 21 +println list::iota(1, 21).reduce(1, => a, b { a * b // gcd(a, b) }) diff --git a/sample/project_euler/pe06.sa b/sample/project_euler/pe06.sa index 8e2715c..b361aa9 100644 --- a/sample/project_euler/pe06.sa +++ b/sample/project_euler/pe06.sa @@ -1,9 +1,5 @@ def sum list { - let acc = 0 - list.each => elem { - acc = acc + elem - } - acc + list.reduce(0, => a, b { a + b }) } def square num { diff --git a/sample/project_euler/pe07.sa b/sample/project_euler/pe07.sa new file mode 100644 index 0000000..2defd66 --- /dev/null +++ b/sample/project_euler/pe07.sa @@ -0,0 +1,24 @@ +# See Project Euler #3 +def factors num { + let list = [] + let candidate = 2 + let max = math::sqrt num + while candidate <= max { + list.push candidate if num %% candidate + candidate = candidate + 1 + } + list +} + +def prime? num { + factors(num).length() == 0 +} + +let seen = 0 +let num = 1 +while seen < 10001 { + num = num + 1 + seen = seen + 1 if prime? num +} + +println num diff --git a/src/lib/method/list.c b/src/lib/method/list.c index b9197a6..c55feca 100644 --- a/src/lib/method/list.c +++ b/src/lib/method/list.c @@ -9,6 +9,7 @@ sbCFuncStatus list_each_cfunc(hVm vm, flag init); sbCFuncStatus list_map_cfunc(hVm vm, flag init); sbCFuncStatus list_filter_cfunc(hVm vm, flag init); +sbCFuncStatus list_reduce_cfunc(hVm vm, flag init); sbCFuncStatus list_any_cfunc(hVm vm, flag init); sbCFuncStatus list_all_cfunc(hVm vm, flag init); @@ -101,6 +102,14 @@ static void filter(hVm vm, hV *list, usize num_params) { sbVm_call_c_func(vm, list_filter_cfunc); } +static void reduce(hVm vm, hV *list, usize num_params) { + if (num_params != 2) { + PANIC("wrong number of arguments passed to list#reduce"); + } + sbVm_push_immediate(vm, list); + sbVm_call_c_func(vm, list_reduce_cfunc); +} + static void any_p(hVm vm, hV *list, usize num_params) { if (num_params != 1) { PANIC("wrong number of arguments passed to list#any?"); @@ -126,6 +135,7 @@ void sbList_create_methods(void) { REGISTER_METHOD(&g_list_methods, "each", each); REGISTER_METHOD(&g_list_methods, "map", map); REGISTER_METHOD(&g_list_methods, "filter", filter); + REGISTER_METHOD(&g_list_methods, "reduce", reduce); REGISTER_METHOD(&g_list_methods, "any?", any_p); REGISTER_METHOD(&g_list_methods, "all?", all_p); } @@ -239,6 +249,44 @@ sbCFuncStatus list_filter_cfunc(hVm vm, flag init) { } } +sbCFuncStatus list_reduce_cfunc(hVm vm, flag init) { + if (init) { + /* state: list being reduced, index, callback, result */ + sbVm_request_var_space(vm, 4); + hV *iterating_list = sbVm_pop(vm); + hV *result = sbVm_pop(vm); + hV *reduce_func = sbVm_pop(vm); + usize length; + sbList_get_value(iterating_list->list, &length); + hV index = HVINT(0); + + vm->fp->locals[0] = *iterating_list; + vm->fp->locals[1] = index; + vm->fp->locals[2] = *reduce_func; + vm->fp->locals[3] = *result; + } else { + /* get result of reduce function */ + hV *result = sbVm_pop(vm); + vm->fp->locals[3] = *result; + } + + 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 result and new value on stack, then call callback function */ + sbVm_push(vm, &vm->fp->locals[3]); + sbVm_push(vm, &iter_values[current_index]); + sbVm_push_immediate(vm, &HVINT(2)); + sbVm_call_func(vm, &vm->fp->locals[2]); + return CFUNC_NEXT; + } else { + /* return result */ + sbVm_push_immediate(vm, &vm->fp->locals[3]); + return CFUNC_END; + } +} + sbCFuncStatus list_any_cfunc(hVm vm, flag init) { if (init) { /* state: list being filtered, index, callback */ diff --git a/src/lib/module/math.c b/src/lib/module/math.c index c04e32c..b9f5599 100644 --- a/src/lib/module/math.c +++ b/src/lib/module/math.c @@ -5,6 +5,7 @@ #include "data/string.h" #include "data/symbol.h" #include "data/integer.h" +#include "vm/operations.h" #include "vm/exec.h" #include @@ -29,7 +30,21 @@ static void sbsqrt(hVm vm, usize argc) { sbVm_push_immediate(vm, &HVFLOAT(sqrt(original_value))); } +static void sbmax(hVm vm, usize argc) { + hV *result = &HVNIL; + while (argc > 0) { + argc --; + hV *val = sbVm_pop(vm); + if (result->type == IT_NIL || sbV_le(result, val).boolean) { + result = val; + } + } + + sbVm_push_immediate(vm, result); +} + void sbLib_loadmodule_math() { sbLibTable_initialize(&g_math_module, 16, FALSE); REGISTER_VALUE(&g_math_module, "sqrt", &HVBUILTIN(sbsqrt)); + REGISTER_VALUE(&g_math_module, "max", &HVBUILTIN(sbmax)); } diff --git a/src/vm/exec.c b/src/vm/exec.c index 9f8639a..9b8ac03 100644 --- a/src/vm/exec.c +++ b/src/vm/exec.c @@ -7,6 +7,7 @@ #include "lib/lib.h" void call_block(hVm vm, usize block_id, hClosure closure); +void call_builtin(hVm vm, hV *to_call); void return_from_block(hVm vm); void execute_instruction(hVm vm); void push_stack(hVm vm, hV *value); @@ -79,7 +80,11 @@ void sbVm_swap(hVm vm) { } void sbVm_call_func(hVm vm, hV *func) { - call_block(vm, func->type, func->closure); + if (func->type == IT_BUILTIN) { + call_builtin(vm, func); + } else { + call_block(vm, func->type, func->closure); + } } void sbVm_transfer_to_func(hVm vm, hV *func) { -- 1.8.3.1