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
2022class AsyncResultMsg : public RTMessage {
2123public:
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)
89135class AsyncWrapperNativeFn : public NativeFunction {
90136public:
@@ -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
0 commit comments