Skip to content

Commit b612f4e

Browse files
committed
exceptions :check:
1 parent 10674c3 commit b612f4e

File tree

8 files changed

+147
-18
lines changed

8 files changed

+147
-18
lines changed

vm/async.hpp

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,23 @@
1616
* tfw using functions instead of objects
1717
*/
1818

19+
// TODO should probably split into .hpp and .cpp
20+
1921
/// Resumes execution of frame after async result received
2022
class AsyncResultMsg : public RTMessage {
2123
public:
2224
Value ret;
2325
std::shared_ptr<SyncCallStack> stack_target;
26+
bool is_error;
2427

25-
AsyncResultMsg(std::shared_ptr<Value> ret, std::shared_ptr<SyncCallStack> stack_target):
26-
ret(*ret), stack_target(std::move(stack_target)) {}
28+
AsyncResultMsg(std::shared_ptr<Value> ret, std::shared_ptr<SyncCallStack> stack_target, bool is_error):
29+
ret(*ret), stack_target(std::move(stack_target)), is_error(is_error) {}
2730

2831
void action(Runtime& rt) override {
29-
stack_target->stack.back()->eval_stack.emplace_back(ret);
32+
if (!this->is_error)
33+
stack_target->stack.back()->eval_stack.emplace_back(ret);
34+
else
35+
stack_target->throw_error(ret);
3036

3137
// run it again bc should have been stopped when the Future was invoked
3238
rt.set_active(this->stack_target);
@@ -42,6 +48,9 @@ class AsyncReturnNativeFn : public NativeFunction {
4248
// store return value if frame_target not set
4349
std::shared_ptr<Value> ret{nullptr};
4450

51+
// does ret store an error?
52+
bool is_error{false};
53+
4554
// this gets set when user invokes the future functor
4655
std::shared_ptr<SyncCallStack> stack_target{nullptr}; //
4756

@@ -51,13 +60,15 @@ class AsyncReturnNativeFn : public NativeFunction {
5160

5261
void operator()(Frame& f) override {
5362
this->ret = std::make_shared<Value>(f.eval_stack.back());
63+
this->kill_thread(f);
64+
}
65+
void kill_thread(Frame& f) {
5466
f.rt->kill_running();
5567
if (this->stack_target == nullptr)
5668
return;
5769
this->stack_target->stack[0]->rt->recv_msg(
58-
new AsyncResultMsg(this->ret, this->stack_target));
70+
new AsyncResultMsg(this->ret, this->stack_target, is_error));
5971
}
60-
6172
void mark() override {
6273
if (ret)
6374
GC::mark(*ret);
@@ -74,7 +85,11 @@ class AsyncFutureNativeFn : public NativeFunction {
7485
void operator()(Frame& f) override {
7586
this->ofn->stack_target = f.rt->running;
7687
if (this->ofn->ret != nullptr) {
77-
f.eval_stack.emplace_back(*this->ofn->ret);
88+
if (this->ofn->is_error) {
89+
f.rt->running->throw_error(*this->ofn->ret);
90+
} else {
91+
f.eval_stack.emplace_back(*this->ofn->ret);
92+
}
7893
} else {
7994
f.rt->freeze_running();
8095
}
@@ -85,6 +100,37 @@ class AsyncFutureNativeFn : public NativeFunction {
85100
}
86101
};
87102

103+
// By default errors thrown in async tasks will
104+
class AsyncDefaultCatchFn : public NativeFunction {
105+
AsyncReturnNativeFn* ret;
106+
public:
107+
108+
explicit AsyncDefaultCatchFn(AsyncReturnNativeFn* ret): ret(ret) {}
109+
110+
void operator()(Frame& f) override {
111+
// Copy the error
112+
std::shared_ptr<Value> err = std::make_shared<Value>(f.eval_stack.back());
113+
// Print a message
114+
std::cout <<"WARNING: Uncaught Exception in async task:\n";
115+
116+
// Convert the error to a string and print it
117+
(*std::get<ValueTypes::n_fn_t>(get_global_id((int64_t) GlobalId::STR).v))(f);
118+
(*std::get<ValueTypes::n_fn_t>(get_global_id((int64_t) GlobalId::PRINT).v))(f);
119+
120+
// Put the error into the return closure and mark that it's an error
121+
// This way the future will throw
122+
this->ret->ret = err;
123+
this->ret->is_error = true;
124+
125+
// Transfer control
126+
this->ret->kill_thread(f);
127+
}
128+
129+
void mark() override {
130+
this->ret->mark();
131+
}
132+
};
133+
88134
/// typeof async(fn)
89135
class AsyncWrapperNativeFn : public NativeFunction {
90136
public:
@@ -119,6 +165,8 @@ class AsyncWrapperNativeFn : public NativeFunction {
119165
auto rcs = f.rt->running;
120166
f.rt->spawn_thread();
121167
f.rt->running->stack.emplace_back(std::make_shared<Frame>(f.rt, c));
168+
f.rt->running->stack.back()->error_handler = ::new(GC::alloc<Value>()) Value(
169+
(NativeFunction*)::new(GC::alloc<AsyncDefaultCatchFn>()) AsyncDefaultCatchFn(ofn));
122170
} else {
123171
std::cerr <<"async only accepts closures for now :/\n";
124172
// todo: typerror

vm/bc/fault_table.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "fault_table.hpp"
1010

11+
#ifdef SCL_DEBUG
1112
static inline void debug_fault_table(FaultTable& ft) {
1213
std::cout <<"\nRead Fault Table:\n- relocations: ";
1314
for (auto& p : ft.relocations)
@@ -23,6 +24,7 @@ static inline void debug_fault_table(FaultTable& ft) {
2324

2425
std::cout <<std::endl <<std::endl;
2526
}
27+
#endif
2628

2729

2830

vm/closure.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@
22
// Created by tate on 17-05-20.
33
//
44

5-
6-
#include "closure.hpp"
75
#include "value.hpp"
6+
#include "closure.hpp"

vm/error.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ class ErrorTrace {
6666
// ...
6767

6868
// For each item in the trace...
69-
for (auto& p : this->trace) {
69+
for (int i = this->trace.size() - 1; i >= 0; i--) {
70+
auto& p = this->trace[i];
7071
ret += "\tat ";
7172
auto macro_start_pos = get_macro_start_pos(vm.literals, p.second);
7273
auto pos = p.first + macro_start_pos;

vm/global_ids.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,19 @@ class IfFn : public NativeFunction {
9898
// Any -> Str
9999
class StrFn : public NativeFunction {
100100
void operator()(Frame& f) override {
101-
f.eval_stack.back() = Value(f.eval_stack.back().to_string());
101+
Value& v = f.eval_stack.back();
102+
103+
// if object has a __str method, call that
104+
if (v.type() == ValueTypes::VType::OBJ) {
105+
auto& o = *std::get<ValueTypes::obj_t*>(v.v);
106+
if (o.find("__str") != o.end()) {
107+
vm_util::invoke_value_sync(f, o["__str"], true);
108+
return;
109+
}
110+
}
111+
112+
// Otherwise convert it to a string manually
113+
f.eval_stack.back() = Value(v.to_string());
102114
}
103115

104116
void mark() override {}
@@ -257,7 +269,9 @@ class CopyFn : public NativeFunction {
257269
// Throw an error
258270
class ThrowFn : public NativeFunction {
259271
void operator()(Frame& f) override {
260-
272+
Value e = f.eval_stack.back();
273+
f.eval_stack.pop_back();
274+
f.rt->running->throw_error(e);
261275
}
262276
void mark() override {}
263277
};

vm/global_ids.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,24 @@
77

88
#include <cinttypes>
99

10+
11+
// Using these internally too
12+
enum class GlobalId : int64_t {
13+
EMPTY = 0,
14+
PRINT = 1,
15+
INPUT = 2,
16+
IF = 3,
17+
STR = 4,
18+
NUM = 5,
19+
VARS = 6,
20+
ASYNC = 7,
21+
IMPORT = 8,
22+
SIZE = 9,
23+
COPY = 10,
24+
ERROR = 11,
25+
THROW = 12,
26+
};
27+
1028
class Value;
1129
const Value& get_global_id(int64_t id);
1230
constexpr unsigned short global_ids_count = 12;

vm/vm.cpp

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,56 @@
1111
#include "value.hpp"
1212
#include "bc/exec_bc_instr.hpp"
1313
#include "global_ids.hpp"
14+
#include "operators/internal_tools.hpp"
15+
16+
17+
inline void fatal_exception(Frame& f) {
18+
std::cout <<"Fatal Exception:\n";
19+
(*std::get<ValueTypes::n_fn_t>(get_global_id((int64_t) GlobalId::STR).v))(f);
20+
(*std::get<ValueTypes::n_fn_t>(get_global_id((int64_t) GlobalId::PRINT).v))(f);
21+
exit(1);
22+
}
23+
1424

1525
void SyncCallStack::mark() {
1626
for (auto& f : this->stack)
1727
f->mark();
1828
}
1929

20-
class ExitProgramReturn : public virtual NativeFunction {
30+
void SyncCallStack::throw_error(Value thrown) {
31+
for (int i = this->stack.size() - 1; i >= 0; i--) {
32+
auto* h = this->stack[i]->error_handler;
33+
if (h != nullptr) {
34+
// Pop the stack back one level behind that of the handler
35+
// Replace the bad function call(stack) with the error handler
36+
// Note that this destroys back until the i-1-th frame
37+
// Note that the position of that frame will be the call that caused the error
38+
39+
std::shared_ptr<Frame> f;
40+
if (i != 0) {
41+
this->stack.resize(i);
42+
f = this->stack.back();
43+
} else {
44+
this->stack.resize(1);
45+
f = this->stack.back();
46+
// f->pos = f->closure.body->size();
47+
}
48+
49+
f->eval_stack.emplace_back(thrown);
50+
vm_util::invoke_value_sync(*f, *h, true);
51+
return;
52+
}
53+
}
54+
55+
// No handlers, die
56+
this->stack.back()->eval_stack.emplace_back(thrown);
57+
fatal_exception(*this->stack.back());
58+
}
59+
60+
class ExitProgramReturn : public NativeFunction {
2161
public:
2262

2363
void operator()(Frame& f) override {
24-
// TODO: convert stack.back() to int and return it
25-
// f.eval_stack.back();
2664
if (std::holds_alternative<Value::int_t>(f.eval_stack.back().v))
2765
exit(std::get<Value::int_t>(f.eval_stack.back().v));
2866
else
@@ -32,6 +70,12 @@ class ExitProgramReturn : public virtual NativeFunction {
3270
};
3371
static_assert(sizeof(ExitProgramReturn) == sizeof(NativeFunction), "Should be same size for convenience");
3472

73+
//class FatalExceptionHandler : public NativeFunction {
74+
//public:
75+
// void operator()(Frame& f) override {
76+
// fatal_exception(f, f.eval_stack.back());
77+
// }
78+
//};
3579

3680
VM::VM(std::vector<Literal> lit_header, const std::vector<std::string>& argv, std::istream& bytecode_source):
3781
bytecode_source(bytecode_source)
@@ -53,7 +97,6 @@ VM::VM(std::vector<Literal> lit_header, const std::vector<std::string>& argv, st
5397
// capture global variables
5498
for (const int64_t id : entry.capture_ids) {
5599
SCL_DEBUG_MSG("capture global id # " << id << std::endl);
56-
// std::cout <<"cid" <<id <<std::endl;
57100
main.vars[id] = ::new(GC::alloc<Value>()) Value(get_global_id(id));
58101
}
59102

@@ -68,9 +111,6 @@ VM::VM(std::vector<Literal> lit_header, const std::vector<std::string>& argv, st
68111
// TODO: capture command-line args
69112
Value argv_list{std::string("cmd args coming soon")};
70113
main.vars[main.i_id] = ::new(GC::alloc<Value>()) Value(argv_list);
71-
72-
// declare locals
73-
// main.declare_empty_locals(entry.decl_ids);
74114
}
75115

76116
void VM::run() {

vm/vm.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,14 @@ class RTMessage {
4040
class SyncCallStack {
4141
public:
4242
std::vector<std::shared_ptr<Frame>> stack;
43+
44+
SyncCallStack() {
45+
this->stack.reserve(32);
46+
}
47+
4348
void mark();
49+
50+
void throw_error(Value thrown);
4451
};
4552

4653

0 commit comments

Comments
 (0)