/////////////////////////////////////////////////////////////////////////////// // // Module : purescript.h // Copyright : (c) Andy Arvanitis 2018 // License : BSD // // Maintainer : Andy Arvanitis // Stability : experimental // Portability : // // Basic types and functions to support purescript-to-C++ rendering // /////////////////////////////////////////////////////////////////////////////// // #ifndef purescript_H #define purescript_H #include #include #include #include #include #include namespace purescript { using std::string; class boxed : public std::shared_ptr { public: using fn_t = std::function; using eff_fn_t = std::function; using dict_t = std::map; using array_t = std::deque; public: using std::shared_ptr::shared_ptr; boxed(const int n) : std::shared_ptr(std::make_shared(n)) { } boxed(const long n) : std::shared_ptr(std::make_shared(static_cast(n))) { #ifndef NDEBUG if (n < std::numeric_limits::min() || n > std::numeric_limits::max()) { throw std::runtime_error("integer out of range"); } #endif // !NDEBUG } boxed(const double n) : std::shared_ptr(std::make_shared(n)) { } boxed(const bool b) : std::shared_ptr(std::make_shared(b)) { } boxed(const char s[]) : std::shared_ptr(std::make_shared(s)) { } boxed(string&& s) : std::shared_ptr(std::make_shared(std::move(s))) { } boxed(const std::nullptr_t) : std::shared_ptr() { } boxed(array_t&& l) : std::shared_ptr(std::make_shared(std::move(l))) { } boxed(dict_t&& m) : std::shared_ptr(std::make_shared(std::move(m))) { } template ::value>::type> boxed(const T& f, typename std::enable_if,T>::value>::type* = 0) : std::shared_ptr(std::make_shared(f)) { } template ::value>::type> boxed(const T& f, typename std::enable_if,T>::value>::type* = 0) : std::shared_ptr(std::make_shared(f)) { } template ::value && std::is_convertible::value>::type> auto operator=(const T& right) -> boxed& { if (std::shared_ptr::operator bool()) { auto& f = *static_cast(get()); f = right; } else { reset(new fn_t(right)); } return *this; } auto operator()(const boxed& arg) const -> boxed { auto& f = *static_cast(get()); return f(arg); } auto operator()() const -> boxed { auto& f = *static_cast(get()); return f(); } auto operator[](const string& key) const -> const boxed& { const auto& dict = *static_cast(get()); return dict.at(key); } auto operator[](const string& key) -> boxed& { auto& dict = *static_cast(get()); return dict[key]; } #ifdef NDEBUG auto operator[](const int index) const -> const boxed& { const auto& array = *static_cast(get()); return array[index]; } auto operator[](const int index) -> boxed& { auto& array = *static_cast(get()); return array[index]; } #else auto operator[](const int index) const -> const boxed& { const auto& array = *static_cast(get()); return array.at(index); } auto operator[](const int index) -> boxed& { auto& array = *static_cast(get()); return array.at(index); } #endif // NDEBUG }; // class boxed template inline auto box(Args&&... args) -> boxed { return std::make_shared(std::forward(args)...); } template inline auto unbox(const boxed& b) -> const T& { const auto& unboxed = *static_cast(b.get()); return unboxed; } template ::value>::type> constexpr auto unbox(const T value) -> T { return value; } template inline auto peek(boxed& b) -> T& { auto& unboxed = *static_cast(b.get()); return unboxed; } template inline auto copy(const boxed& b) -> boxed { return box(unbox(b)); } using fn_t = boxed::fn_t; using eff_fn_t = boxed::eff_fn_t; using dict_t = boxed::dict_t; using array_t = boxed::array_t; constexpr auto undefined = nullptr; } // namespace purescript #define FOREIGN_BEGIN(NS) namespace NS {\ using namespace purescript;\ auto _foreign_() -> dict_t&;\ static const auto& NS ## _foreign_init = []() {\ dict_t& exports = _foreign_(); #define FOREIGN_END return exports; }(); } #endif // purescript_H