Implement a map function that works on lists

This commit is contained in:
Konstantin Nazarov 2024-09-15 16:21:58 +01:00
parent 06149c3d61
commit 049aeef62f
Signed by: knazarov
GPG key ID: 4CFE0A42FA409C22
3 changed files with 56 additions and 1 deletions

View file

@ -161,6 +161,60 @@ Result<StackFrame> stdlib_size(const StackFrame& stack) {
return res.ret(0); return res.ret(0);
} }
Result<StackFrame> stdlib_map(const StackFrame& stack_param) {
auto stack = TRY(stack_param.copy());
auto params = TRY(stack.get(0));
auto stack_size = TRY(stack.size());
auto fun = TRY(params.get(1));
if (stack_size == 1) {
// This is the first call, need to set up arguments on the stack
auto collection = TRY(params.get(0));
auto num_params = TRY(params.size());
if (num_params != 2) return ERROR(ArgumentCountMismatch);
if (!collection.is<Pair>()) return ERROR(TypeMismatch);
// Result accumulator will contain nil value initially
auto nil = Value(TRY(Nil::create()));
stack = TRY(stack.set(1, nil));
// Remaining elements in the collection
stack = TRY(stack.set(2, TRY(collection.rest())));
stack = TRY(stack.set(3, fun));
stack = TRY(stack.set(4, TRY(collection.first())));
return TRY(stack.call(fun, 3, 5));
}
auto accumulator = TRY(stack.get(1));
auto remaining = TRY(stack.get(2));
auto fun_result = TRY(stack.get(3));
accumulator = Value(TRY(Pair::create(fun_result, accumulator)));
stack = TRY(stack.set(1, accumulator));
if (!remaining.is<Nil>()) {
stack = TRY(stack.set(2, TRY(remaining.rest())));
stack = TRY(stack.set(3, fun));
stack = TRY(stack.set(4, TRY(remaining.first())));
return TRY(stack.call(fun, 3, 5));
}
accumulator = TRY(reverse(accumulator));
auto res = TRY(stack.set(0, accumulator));
res = TRY(res.ret(0));
res = TRY(res.incpc());
return res;
}
#define STDLIB_FUNCTION(name, id) \ #define STDLIB_FUNCTION(name, id) \
[(uint64_t)StdlibFunctionId::id] = {#name, StdlibFunctionId::id, \ [(uint64_t)StdlibFunctionId::id] = {#name, StdlibFunctionId::id, \
stdlib_##name} stdlib_##name}
@ -177,6 +231,7 @@ static StdlibFunctionEntry function_entries[] = {
STDLIB_FUNCTION(get, Get), STDLIB_FUNCTION(get, Get),
STDLIB_FUNCTION(srcloc, SrcLoc), STDLIB_FUNCTION(srcloc, SrcLoc),
STDLIB_FUNCTION(size, Size), STDLIB_FUNCTION(size, Size),
STDLIB_FUNCTION(map, Map),
[(uint64_t)StdlibFunctionId::Max] = {0, StdlibFunctionId::Max, [(uint64_t)StdlibFunctionId::Max] = {0, StdlibFunctionId::Max,
stdlib_unknown}, stdlib_unknown},
}; };

View file

@ -16,6 +16,7 @@ enum class StdlibFunctionId : uint64_t {
Get, Get,
SrcLoc, SrcLoc,
Size, Size,
Map,
Max, Max,
}; };

View file

@ -283,7 +283,6 @@ Result<void> VM::step_native() {
auto fun_id = fun.to<StdlibFunction>()->fun_id(); auto fun_id = fun.to<StdlibFunction>()->fun_id();
_stack = TRY(call_stdlib_function(fun_id, _stack)); _stack = TRY(call_stdlib_function(fun_id, _stack));
_stack = TRY(_stack.incpc());
return Result<void>(); return Result<void>();
} }