diff --git a/src/error.cpp b/src/error.cpp index e2ae8c5..3efd9fb 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -63,6 +63,8 @@ const char* errname(ErrorCode errcode) { return "runtime-error"; case ErrorCode::Raise: return "raise"; + case ErrorCode::Reraise: + return "reraise"; case ErrorCode::TaskFailed: return "task-failed"; } diff --git a/src/error.hpp b/src/error.hpp index 65d8b85..931a3b3 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -23,6 +23,7 @@ enum class ErrorCode { SyntaxError, RuntimeError, Raise, + Reraise, TaskFailed, }; diff --git a/src/stdlib.cpp b/src/stdlib.cpp index 7616f61..3fb5978 100644 --- a/src/stdlib.cpp +++ b/src/stdlib.cpp @@ -417,48 +417,9 @@ Result stdlib_reraise(const StackFrame& stack) { if (!cont_val.is()) return ERROR(TypeMismatch); - Continuation& cont = *cont_val.to(); - StackFrame cont_stack = TRY(cont.frame()); + auto new_cont = Value(TRY(Continuation::create(cont_val, stack))); - StackFrame cur = TRY(stack.copy()); - - uint64_t depth = 0; - - while (true) { - if (cur.guard()) { - auto state = TRY(cur.get(1)); - if (!state.is()) return ERROR(TypeMismatch); - auto state_int = state.to()->value(); - - if (state_int > 1) { - auto val = TRY(cont.value()); - auto remaining_stack = TRY(stack.detach(depth - 1)); - - Value fun = TRY(params.get(0)); - cur = TRY(cur.set(1, Value(TRY(Int64::create((int64_t)0))))); - cur = TRY(cur.set(2, Value(std::move(fun)))); - cur = TRY(cur.settop(3)); - - cur = TRY(remaining_stack.attach(cur)); - cur = TRY(cont_stack.attach(cur)); - - uint64_t start_from = depth + TRY(cont_stack.depth()) + 1; - - auto res = TRY(cur.unwind(val, start_from)); - if (res.is()) - return res.to()->copy(); - else - break; - } - } - - auto parent = TRY(cur.parent()); - if (parent.is()) break; - - cur = TRY(parent.to()->copy()); - ++depth; - } - return ERROR_OBJ(Raise, cont_val); + return ERROR_OBJ(Reraise, new_cont); } Result stdlib_task(const StackFrame& stack) { diff --git a/src/vm.cpp b/src/vm.cpp index 3d3518c..ee525d1 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -302,17 +302,16 @@ Result VM::step_bytecode() { return Result(); } -Result VM::unwind(const Continuation& cont) { +Result VM::unwind(const Continuation& cont, uint64_t start_from) { auto val = TRY(cont.value()); auto cont_stack = TRY(cont.frame()); - return cont_stack.unwind(val); + return cont_stack.unwind(val, start_from); } -Result VM::handle_raise(const Continuation& cont) { - // TODO: this should do proper stack unwinding - - auto unwind_res = TRY(unwind(cont)); +Result VM::handle_raise(const Continuation& cont, + uint64_t start_from) { + auto unwind_res = TRY(unwind(cont, start_from)); if (!unwind_res.is()) { auto new_stack = TRY(unwind_res.to()->copy()); @@ -358,6 +357,59 @@ Result VM::handle_raise(const Continuation& cont) { return ERROR(TypeMismatch); } +Result VM::handle_reraise(const Continuation& parent_cont) { + auto stack = TRY(parent_cont.frame()); + auto cont_val = TRY(parent_cont.value()); + + if (!cont_val.is()) return ERROR(TypeMismatch); + + Continuation& cont = *cont_val.to(); + StackFrame cont_stack = TRY(cont.frame()); + + StackFrame cur = TRY(stack.copy()); + + uint64_t depth = 0; + + while (true) { + if (cur.guard()) { + auto state = TRY(cur.get(1)); + if (!state.is()) return ERROR(TypeMismatch); + auto state_int = state.to()->value(); + + if (state_int > 1) { + auto val = TRY(cont.value()); + auto remaining_stack = TRY(stack.detach(depth - 1)); + + auto params = TRY(cur.get(0)); + Value fun = TRY(params.get(0)); + cur = TRY(cur.set(1, Value(TRY(Int64::create((int64_t)0))))); + cur = TRY(cur.settop(2)); + + cur = TRY(cont_stack.attach(cur)); + + uint64_t start_from = TRY(cont_stack.depth()) + 1; + + auto res = TRY(cur.unwind(val, start_from)); + if (res.is()) { + return res.to()->copy(); + } else { + auto new_cont = TRY(Continuation::create(val, cur)); + return handle_raise(new_cont, start_from); + } + } + } + + auto parent = TRY(cur.parent()); + if (parent.is()) break; + + cur = TRY(parent.to()->copy()); + ++depth; + } + + auto new_cont = TRY(Continuation::create(TRY(cont.value()), stack)); + return handle_raise(new_cont, 0); +} + Result VM::step_native() { auto fun = TRY(_stack.fun()); if (!fun.is()) return ERROR(TypeMismatch); @@ -392,6 +444,12 @@ Result VM::step() { return Result(); } } + if (res.error() == ErrorCode::Reraise) { + if (obj.is()) { + _stack = TRY(handle_reraise(*obj.to())); + return Result(); + } + } auto cont = TRY(Continuation::create(obj, _stack)); _stack = TRY(handle_raise(cont)); diff --git a/src/vm.hpp b/src/vm.hpp index fec214a..e4fd1dd 100644 --- a/src/vm.hpp +++ b/src/vm.hpp @@ -63,8 +63,10 @@ class VM { Result vm_global_load(Opcode& oc); Result vm_global_store(Opcode& oc); - Result unwind(const Continuation& cont); - Result handle_raise(const Continuation& cont); + Result unwind(const Continuation& cont, uint64_t start_from = 0); + Result handle_raise(const Continuation& cont, + uint64_t start_from = 0); + Result handle_reraise(const Continuation& cont); Result get(bool is_const, uint64_t idx); Result getconst(uint64_t idx);