Implement a map function that works on lists
This commit is contained in:
parent
06149c3d61
commit
049aeef62f
3 changed files with 56 additions and 1 deletions
|
@ -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},
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,6 +16,7 @@ enum class StdlibFunctionId : uint64_t {
|
||||||
Get,
|
Get,
|
||||||
SrcLoc,
|
SrcLoc,
|
||||||
Size,
|
Size,
|
||||||
|
Map,
|
||||||
Max,
|
Max,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue