/////////////////////////////////////////////////////////////////////////////// // // 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 "string_literal_dict.h" 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 = string_literal_dict_t; 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))) { #if !defined(NDEBUG) // if debug build if (n < std::numeric_limits::min() || n > std::numeric_limits::max()) { throw std::runtime_error("integer out of range"); } #endif // !defined(NDEBUG) } boxed(const unsigned long n) : std::shared_ptr(std::make_shared(static_cast(n))) { #if !defined(NDEBUG) // if debug build if (n > std::numeric_limits::max()) { throw std::runtime_error("integer out of range"); } #endif // !defined(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 string& s) : std::shared_ptr(std::make_shared(s)) {} boxed(array_t&& l) : std::shared_ptr(std::make_shared(std::move(l))) {} boxed(const array_t& l) : std::shared_ptr(std::make_shared(l)) {} boxed(dict_t&& m) : std::shared_ptr(std::make_shared(std::move(m))) {} boxed(const dict_t& m) : std::shared_ptr(std::make_shared(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)) { } 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 char key[]) const -> const boxed& { return (*static_cast(get()))[key]; } auto operator[](const char key[]) -> boxed& { return (*static_cast(get()))[key]; } #if !defined(NDEBUG) // if debug build auto operator[](const int index) const -> const boxed& { return static_cast(get())->at(index); } auto operator[](const int index) -> boxed& { return static_cast(get())->at(index); } #else // not debug build auto operator[](const int index) const -> const boxed& { return (*static_cast(get()))[index]; } auto operator[](const int index) -> boxed& { return (*static_cast(get()))[index]; } #endif // !defined(NDEBUG) }; // class boxed 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; class boxed_r : private std::shared_ptr { public: boxed_r() : std::shared_ptr(std::make_shared()) {} operator const boxed&() const { return *static_cast(get()); } auto operator()(const boxed& arg) const -> boxed { auto& b = *static_cast(get()); auto& f = *static_cast(b.get()); return f(arg); } auto operator()() const -> boxed { auto& b = *static_cast(get()); auto& f = *static_cast(b.get()); return f(); } template auto operator=(T&& right) -> boxed_r& { auto& b = *static_cast(get()); b = std::forward(right); return *this; } }; // class boxed_r template inline auto box(Args&&... args) -> boxed { return std::make_shared(std::forward(args)...); } template constexpr auto unbox(const boxed& b) -> const T& { return *static_cast(b.get()); } template constexpr auto unbox(boxed& b) -> T& { return *static_cast(b.get()); } template constexpr auto unbox(const T value) -> T { return value; } template ::value>::type> constexpr auto unbox(const std::size_t value) -> long long { return value; } inline auto array_length(const boxed& a) -> boxed::array_t::size_type { return unbox(a).size(); } constexpr auto undefined = nullptr; } // namespace purescript #define DEFINE_FOREIGN_DICTIONARY_AND_ACCESSOR() \ inline auto foreign() -> dict_t& {\ static dict_t $dict$;\ return $dict$;\ } #define FOREIGN_BEGIN(NS) namespace NS {\ using namespace purescript;\ DEFINE_FOREIGN_DICTIONARY_AND_ACCESSOR()\ static const auto $foreign_exports_init$ = ([]() -> char {\ dict_t& exports = foreign(); #define FOREIGN_END return 0; }()); } #endif // purescript_H