Port print and println to use tasks/continuations

This commit is contained in:
Konstantin Nazarov 2024-09-28 19:43:17 +01:00
parent cf9aa08aea
commit 52eae6b3e3
Signed by: knazarov
GPG key ID: 4CFE0A42FA409C22
2 changed files with 70 additions and 36 deletions

View file

@ -22,14 +22,48 @@ struct StdlibTaskEntry {
StdlibTaskIdPtr task_ptr;
};
Result<StackFrame> raise_task(const StackFrame& stack, StdlibTaskId task_id,
const Array& params) {
auto val = Value(TRY(Task::create((uint64_t)task_id, params)));
auto cont = Value(TRY(Continuation::create(val, stack)));
return ERROR_OBJ(Raise, cont);
}
Result<StackFrame> raise_task(const StackFrame& stack, StdlibTaskId task_id,
const Value& param) {
Array params = TRY(Array::create());
params = TRY(params.append(param));
auto val = Value(TRY(Task::create((uint64_t)task_id, params)));
auto cont = Value(TRY(Continuation::create(val, stack)));
return ERROR_OBJ(Raise, cont);
}
Result<StackFrame> task_return(const StackFrame& stack, uint64_t idx) {
auto result = TRY(stack.get(idx));
if (!result.is<TaskResult>()) return ERROR(TypeMismatch);
const auto& task_result = *result.to<TaskResult>();
auto error = TRY(task_result.error());
if (!error.is<Nil>()) {
return ERROR_OBJ(TaskFailed, error);
}
auto res = TRY(stack.set(0, TRY(task_result.result())));
res = TRY(res.ret(0));
return res;
}
Result<StackFrame> stdlib_unknown(const StackFrame& stack) {
return ERROR(NotImplemented);
}
Result<StackFrame> stdlib_print(const StackFrame& stack) {
auto params = TRY(stack.get(0));
Result<String> tostring(const Value& params, bool newline = false) {
auto size = TRY(params.size());
String str = TRY(String::create(""));
for (uint64_t i = 0; i < size; i++) {
@ -46,21 +80,36 @@ Result<StackFrame> stdlib_print(const StackFrame& stack) {
}
}
TRY(print_string(str));
if (newline) {
str = TRY(str.concat("\n"));
}
auto nil = Value(TRY(Nil::create()));
auto res = TRY(stack.set(0, nil));
return str;
}
res = TRY(res.ret(0));
Result<StackFrame> stdlib_print(const StackFrame& stack) {
auto params = TRY(stack.get(0));
auto stack_size = TRY(stack.size());
return res;
if (stack_size > 1) {
return task_return(stack, 1);
}
auto str = Value(TRY(tostring(params)));
return raise_task(stack, StdlibTaskId::Print, str);
}
Result<StackFrame> stdlib_println(const StackFrame& stack) {
auto res = TRY(stdlib_print(stack));
std::cout << "\n";
auto params = TRY(stack.get(0));
auto stack_size = TRY(stack.size());
return res;
if (stack_size > 1) {
return task_return(stack, 1);
}
auto str = Value(TRY(tostring(params, true)));
return raise_task(stack, StdlibTaskId::Print, str);
}
Result<StackFrame> stdlib_prn(const StackFrame& stack) {
@ -307,21 +356,7 @@ Result<StackFrame> stdlib_raise(const StackFrame& stack) {
auto stack_size = TRY(stack.size());
if (stack_size > 1) {
auto result = TRY(stack.get(1));
if (!result.is<TaskResult>()) return ERROR(TypeMismatch);
const auto& task_result = *result.to<TaskResult>();
auto error = TRY(task_result.error());
if (!error.is<Nil>()) {
return ERROR_OBJ(TaskFailed, error);
}
auto res = TRY(stack.set(0, TRY(task_result.result())));
res = TRY(res.ret(0));
return res;
return task_return(stack, 1);
}
auto params = TRY(stack.get(0));
@ -347,7 +382,8 @@ Result<StackFrame> stdlib_task(const StackFrame& stack) {
Value task_params = TRY(params_array.slice(1, size));
auto val = Value(TRY(Task::create((uint64_t)task_id.to<Int64>()->value(), *task_params.to<Array>())));
auto val = Value(TRY(Task::create((uint64_t)task_id.to<Int64>()->value(),
*task_params.to<Array>())));
auto res = TRY(stack.set(0, val));
@ -389,7 +425,8 @@ Result<Value> stdlib_task_print(const Array& params) {
auto size = TRY(params.size());
if (size != 1) {
auto err = Value(TRY(Error::create("argument-count-mismatch", "Argument count mismatch")));
auto err = Value(TRY(
Error::create("argument-count-mismatch", "Argument count mismatch")));
return ERROR_OBJ(ArgumentCountMismatch, err);
}
@ -404,15 +441,13 @@ Result<Value> stdlib_task_print(const Array& params) {
return Value(TRY(Nil::create()));
}
#define STDLIB_TASK(name, id) \
[(uint64_t)StdlibTaskId::id] = {#name, StdlibTaskId::id, \
stdlib_task_##name}
#define STDLIB_TASK(name, id) \
[(uint64_t)StdlibTaskId::id] = {#name, StdlibTaskId::id, stdlib_task_##name}
static StdlibTaskEntry task_entries[] = {
STDLIB_TASK(unknown, Unknown),
STDLIB_TASK(print, Print),
[(uint64_t)StdlibTaskId::Max] = {0, StdlibTaskId::Max,
stdlib_task_unknown},
[(uint64_t)StdlibTaskId::Max] = {0, StdlibTaskId::Max, stdlib_task_unknown},
};
// TODO: this just scans through the array of functions linearly every time.
@ -466,7 +501,6 @@ Result<const char*> get_stdlib_function_name(StdlibFunctionId fun_id) {
return function_entries[(uint64_t)fun_id].name;
}
StdlibTaskEntry get_task_entry(const char* name) {
for (uint64_t i = 1; i < (uint64_t)StdlibTaskId::Max; i++) {
if (strcmp(task_entries[i].name, name) == 0) {
@ -497,8 +531,7 @@ Result<StdlibTaskId> get_stdlib_task(const Symbol& name) {
return task_id;
}
Result<Value> call_stdlib_task(StdlibTaskId fun_id,
const Array& params) {
Result<Value> call_stdlib_task(StdlibTaskId fun_id, const Array& params) {
if (fun_id == StdlibTaskId(0) || fun_id >= StdlibTaskId::Max) {
return ERROR(KeyError);
}

View file

@ -103,6 +103,7 @@ Result<void> run_repl() {
auto backtrace = TRY(vm.backtrace(2));
print_error(maybe_res, backtrace);
}
std::cout << std::flush;
}
return Result<void>();