Implement exception reraising from the guard handler
This commit is contained in:
parent
999cd062f0
commit
b9fa84ba0e
5 changed files with 107 additions and 28 deletions
|
@ -702,6 +702,50 @@ Result<StackFrame> StackFrame::attach(const StackFrame& frame) const {
|
|||
return StackFrame(TRY(MkGcRoot(pod)));
|
||||
}
|
||||
|
||||
Result<Value> StackFrame::unwind(const Value& val, uint64_t start_from) const {
|
||||
StackFrame cur = TRY(copy());
|
||||
|
||||
uint64_t depth = 0;
|
||||
while (true) {
|
||||
if (cur.guard() && depth >= start_from) {
|
||||
auto state = TRY(cur.get(1));
|
||||
if (!state.is<Int64>()) return ERROR(TypeMismatch);
|
||||
auto state_int = state.to<Int64>()->value();
|
||||
|
||||
if (state_int <= 1) {
|
||||
auto detached_stack = TRY(detach(depth - 1));
|
||||
|
||||
auto new_cont = TRY(Continuation::create(val, detached_stack));
|
||||
|
||||
cur = TRY(cur.set(1, Value(TRY(Int64::create((int64_t)1)))));
|
||||
cur = TRY(cur.set(2, Value(std::move(new_cont))));
|
||||
return Value(std::move(cur));
|
||||
}
|
||||
}
|
||||
|
||||
auto parent = TRY(cur.parent());
|
||||
if (parent.is<Nil>()) break;
|
||||
|
||||
cur = TRY(parent.to<StackFrame>()->copy());
|
||||
++depth;
|
||||
}
|
||||
return Value(TRY(Nil::create()));
|
||||
}
|
||||
|
||||
Result<uint64_t> StackFrame::depth() const {
|
||||
StackFrame cur = TRY(copy());
|
||||
|
||||
uint64_t depth = 1;
|
||||
while (true) {
|
||||
auto parent = TRY(cur.parent());
|
||||
if (parent.is<Nil>()) break;
|
||||
|
||||
cur = TRY(parent.to<StackFrame>()->copy());
|
||||
++depth;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
Result<StackFrame> StackFrame::set_guard(bool guard) const {
|
||||
uint64_t size = _value->size;
|
||||
auto pod = TRY(arena_alloc<PodStackFrame>(sizeof(OffPtr<PodObject>) * size));
|
||||
|
|
|
@ -1168,6 +1168,9 @@ class StackFrame : public Object {
|
|||
Result<StackFrame> detach(uint64_t depth) const;
|
||||
Result<StackFrame> attach(const StackFrame& frame) const;
|
||||
|
||||
Result<Value> unwind(const Value& val, uint64_t start_from = 0) const;
|
||||
Result<uint64_t> depth() const;
|
||||
|
||||
Result<StackFrame> set_guard(bool guard = true) const;
|
||||
|
||||
virtual Result<Value> copy_value() const final;
|
||||
|
|
|
@ -406,6 +406,61 @@ Result<StackFrame> stdlib_raise(const StackFrame& stack) {
|
|||
return ERROR_OBJ(Raise, cont);
|
||||
}
|
||||
|
||||
Result<StackFrame> stdlib_reraise(const StackFrame& stack) {
|
||||
auto stack_size = TRY(stack.size());
|
||||
|
||||
auto params = TRY(stack.get(0));
|
||||
auto size = TRY(params.size());
|
||||
if (size != 1) return ERROR(ArgumentCountMismatch);
|
||||
|
||||
auto cont_val = TRY(params.get(0));
|
||||
|
||||
if (!cont_val.is<Continuation>()) return ERROR(TypeMismatch);
|
||||
|
||||
Continuation& cont = *cont_val.to<Continuation>();
|
||||
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<Int64>()) return ERROR(TypeMismatch);
|
||||
auto state_int = state.to<Int64>()->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<StackFrame>())
|
||||
return res.to<StackFrame>()->copy();
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto parent = TRY(cur.parent());
|
||||
if (parent.is<Nil>()) break;
|
||||
|
||||
cur = TRY(parent.to<StackFrame>()->copy());
|
||||
++depth;
|
||||
}
|
||||
return ERROR_OBJ(Raise, cont_val);
|
||||
}
|
||||
|
||||
Result<StackFrame> stdlib_task(const StackFrame& stack) {
|
||||
auto params = TRY(stack.get(0));
|
||||
Array& params_array = *params.to<Array>();
|
||||
|
@ -588,6 +643,7 @@ static StdlibFunctionEntry function_entries[] = {
|
|||
STDLIB_FUNCTION(map, Map),
|
||||
STDLIB_FUNCTION(error, Error),
|
||||
STDLIB_FUNCTION(raise, Raise),
|
||||
STDLIB_FUNCTION(reraise, Reraise),
|
||||
STDLIB_FUNCTION(task, Task),
|
||||
STDLIB_FUNCTION(guard, Guard),
|
||||
STDLIB_FUNCTION(serialize, Serialize),
|
||||
|
|
|
@ -22,6 +22,7 @@ enum class StdlibFunctionId : uint64_t {
|
|||
Map,
|
||||
Error,
|
||||
Raise,
|
||||
Reraise,
|
||||
Task,
|
||||
Guard,
|
||||
Serialize,
|
||||
|
|
31
src/vm.cpp
31
src/vm.cpp
|
@ -303,35 +303,10 @@ Result<void> VM::step_bytecode() {
|
|||
}
|
||||
|
||||
Result<Value> VM::unwind(const Continuation& cont) {
|
||||
StackFrame cur = TRY(cont.frame());
|
||||
auto val = TRY(cont.value());
|
||||
auto cont_stack = TRY(cont.frame());
|
||||
|
||||
uint64_t depth = 0;
|
||||
while (true) {
|
||||
if (cur.guard()) {
|
||||
auto state = TRY(cur.get(1));
|
||||
if (!state.is<Int64>()) return ERROR(TypeMismatch);
|
||||
auto state_int = state.to<Int64>()->value();
|
||||
|
||||
if (state_int <= 1) {
|
||||
auto val = TRY(cont.value());
|
||||
auto cont_stack = TRY(cont.frame());
|
||||
cont_stack = TRY(cont_stack.detach(depth - 1));
|
||||
|
||||
auto new_cont = TRY(Continuation::create(val, cont_stack));
|
||||
|
||||
cur = TRY(cur.set(1, Value(TRY(Int64::create((int64_t)1)))));
|
||||
cur = TRY(cur.set(2, Value(std::move(new_cont))));
|
||||
return Value(std::move(cur));
|
||||
}
|
||||
}
|
||||
|
||||
auto parent = TRY(cur.parent());
|
||||
if (parent.is<Nil>()) break;
|
||||
|
||||
cur = TRY(parent.to<StackFrame>()->copy());
|
||||
++depth;
|
||||
}
|
||||
return Value(TRY(Nil::create()));
|
||||
return cont_stack.unwind(val);
|
||||
}
|
||||
|
||||
Result<StackFrame> VM::handle_raise(const Continuation& cont) {
|
||||
|
|
Loading…
Reference in a new issue