Created
August 2, 2020 16:56
-
-
Save long-long-float/1e3a591c6f968377730b8409e65cfa4d to your computer and use it in GitHub Desktop.
A PoC of JEff (https://dl.acm.org/doi/abs/10.1145/3276954.3276955)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include <memory> | |
#include <functional> | |
#include <vector> | |
#include <algorithm> | |
#include <list> | |
using namespace std; | |
class Object { | |
public: | |
virtual ~Object() = default; | |
}; | |
class Unit : public Object {}; | |
class Context { | |
vector<shared_ptr<Object>> handlers; | |
public: | |
void push_handler(shared_ptr<Object> handler) { handlers.push_back(handler); } | |
template <class T> | |
shared_ptr<T> _ () { | |
for (auto h : handlers) { | |
if (auto hh = dynamic_pointer_cast<T>(h)) { | |
return hh; | |
} | |
} | |
return nullptr; | |
} | |
template <class T> | |
T resume(T x, Object* this_, shared_ptr<Object> h) { | |
handlers.erase(remove_if(handlers.begin(), handlers.end(), | |
[this_](auto &elem) { return elem.get() == this_; }), handlers.end()); | |
handlers.push_back(h); | |
return x; | |
} | |
}; | |
template <class Out, class In> | |
class Handler : public Object { | |
public: | |
shared_ptr<Context> ctx; | |
virtual Out return_(In in) = 0; | |
}; | |
template <class T, class Out, class In> | |
class Resume : public Object { | |
virtual Out resume(T x, Handler<Out, In> h) = 0; | |
}; | |
template <class T, class In> | |
T with(shared_ptr<Handler<T, In>> handler, std::function<In(shared_ptr<Context>)> f) { | |
auto ctx = make_shared<Context>(); | |
ctx->push_handler(handler); | |
handler->ctx = ctx; | |
try { | |
auto result = f(ctx); | |
return ctx->_<Handler<T, In>>()->return_(result); | |
} | |
catch(T t) { | |
return t; | |
} | |
} | |
class Raise : public Object { | |
public: | |
virtual void raise(string s) = 0; | |
}; | |
template <class T> | |
class DefaultRaise : public Raise, public Handler<T, T> { | |
T x; | |
public: | |
DefaultRaise(T x) : x(x) {} | |
T return_(T in) { return in; } | |
void raise(string s) { throw this->x; } | |
}; | |
int devide(shared_ptr<Context> ctx, int x, int y) { | |
if (y != 0) | |
return x / y; | |
else { | |
ctx->_<Raise>()->raise("Devision by zero"); | |
return 0; | |
} | |
} | |
void devide_main() { | |
shared_ptr<Handler<int, int>> dh = make_shared<DefaultRaise<int>>(-1); | |
int res1 = with<int, int>(dh, [](shared_ptr<Context> ctx) { | |
return devide(ctx, 4, 2) + 10; | |
}); | |
cout << "res1 = " << res1 << endl; | |
int res2 = with<int, int>(dh, [](shared_ptr<Context> ctx) { | |
return devide(ctx, 4, 0) + 10; | |
}); | |
cout << "res2 = " << res2 << endl; | |
shared_ptr<Handler<int, int>> h2 = make_shared<DefaultRaise<int>>(42); | |
int res3 = with<int, int>(h2, [](shared_ptr<Context> ctx) { | |
return devide(ctx, 4, 0) + 10; | |
}); | |
cout << "res3 = " << res3 << endl; | |
} | |
template <class T> | |
class State { | |
public: | |
virtual T get() = 0; | |
virtual Unit put(T x) = 0; | |
}; | |
template <class T, class U> | |
class TupleState : public State<T>, public Handler<tuple<T, U>, U> { | |
T s; | |
public: | |
TupleState(T s) : s(s) {} | |
T get() { | |
auto h = make_shared<TupleState<T, U>>(s); | |
h->ctx = this->ctx; | |
return this->ctx->resume(this->s, this, h); | |
} | |
Unit put(T x) { | |
auto h = make_shared<TupleState<T, U>>(x); | |
h->ctx = this->ctx; | |
return this->ctx->resume(Unit(), this, h); | |
} | |
tuple<T, U> return_(U x) { | |
return make_tuple(this->s, x); | |
} | |
}; | |
template <class T, class U> | |
class LogState : public State<T>, public Handler<tuple<list<T>, U>, U> { | |
list<T> log; | |
public: | |
LogState(list<T> log) : log(log) {} | |
T get() { | |
auto h = make_shared<LogState<T, U>>(log); | |
h->ctx = this->ctx; | |
return this->ctx->resume(this->log.back(), this, h); | |
} | |
Unit put(T x) { | |
list<T> new_log(log); | |
new_log.push_back(x); | |
auto h = make_shared<LogState<T, U>>(new_log); | |
h->ctx = this->ctx; | |
return this->ctx->resume(Unit(), this, h); | |
} | |
tuple<list<T>, U> return_(U x) { | |
return make_tuple(this->log, x); | |
} | |
}; | |
Unit count_down(shared_ptr<Context> ctx) { | |
int i = ctx->_<State<int>>()->get(); | |
if (i > 0) { | |
ctx->_<State<int>>()->put(i - 1); | |
return count_down(ctx); | |
} | |
else { | |
return Unit(); | |
} | |
} | |
void count_down_main() { | |
shared_ptr<Handler<tuple<int, Unit>, Unit>> h1 = make_shared<TupleState<int, Unit>>(2); | |
auto res1 = with<tuple<int, Unit>, Unit>(h1, [](shared_ptr<Context> ctx) { | |
return count_down(ctx); | |
}); | |
cout << "res1 = " << get<0>(res1) << endl; | |
shared_ptr<Handler<tuple<list<int>, Unit>, Unit>> h2(new LogState<int, Unit>({2})); | |
auto res2 = with<tuple<list<int>, Unit>, Unit>(h2, [](shared_ptr<Context> ctx) { | |
return count_down(ctx); | |
}); | |
cout << "res2 = "; | |
for (auto e : get<0>(res2)) { | |
cout << e << ", "; | |
} | |
cout << endl; | |
} | |
int main() { | |
cout << "devide" << endl; | |
devide_main(); | |
cout << "count down" << endl; | |
count_down_main(); | |
return 0; | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
devide | |
res1 = 12 | |
res2 = -1 | |
res3 = 42 | |
count down | |
res1 = 0 | |
res2 = 2, 1, 0, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment