/////////////////////////////////////////////////////////////////////////////// // // 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 #if !defined(NDEBUG) #include #endif #if !defined(PURESCRIPT_DISABLE_EXCEPTIONS) #include #endif #include "functions.h" #include "dictionary.h" #include "recursion.h" namespace purescript { using std::string; class boxed { public: std::shared_ptr shared; union { int _int_; double _double_; bool _bool_; }; public: using fn_t = _template_::fn_t; using eff_fn_t = _template_::eff_fn_t; using dict_t = _template_::dict_t; using array_t = std::vector; using weak = _template_::weak; using recur = _template_::recur; private: template using fn_T = _template_::fn_T; template using eff_fn_T = _template_::eff_fn_T; public: boxed() noexcept : shared() {} boxed(const std::nullptr_t) noexcept : shared() {} boxed(const weak& w) : shared(w.shared()) {} boxed(const recur& r) : shared(r.shared()) {} boxed(const recur::weak& w) : shared(w.shared()) {} template boxed(std::shared_ptr&& other) noexcept : shared(std::move(other)) {} template boxed(const std::shared_ptr& other) : shared(other) {} boxed(const int n) noexcept : _int_(n) {} boxed(const long n); boxed(const unsigned long n); boxed(const double n) noexcept : _double_(n) {} boxed(const bool b) noexcept : _bool_(b) {} boxed(const char s[]) : shared(std::make_shared(s)) {} boxed(string&& s) : shared(std::make_shared(std::move(s))) {} boxed(const string& s) : shared(std::make_shared(s)) {} boxed(array_t&& l) : shared(std::make_shared(std::move(l))) {} boxed(const array_t& l) : shared(std::make_shared(l)) {} boxed(dict_t&& m) : shared(std::make_shared(std::move(m))) {} boxed(const dict_t& m) : shared(std::make_shared(m)) {} template ::value>::type> boxed(T f, typename std::enable_if()(std::declval())), boxed>::value>::type* = 0) : shared(std::shared_ptr(std::make_shared>(std::move(f)))) { } template ::value>::type> boxed(T f, typename std::enable_if()()), boxed>::value>::type* = 0) : shared(std::shared_ptr(std::make_shared>(std::move(f)))) { } auto get() const noexcept -> void * { return shared.get(); } auto operator()(const boxed& arg) const -> boxed { return (*static_cast(shared.get()))(arg); } auto operator()() const -> boxed { return (*static_cast(shared.get()))(); } auto operator[](const char key[]) const -> const boxed& { return (*static_cast(shared.get()))[key]; } auto operator[](const char key[]) -> boxed& { return (*static_cast(shared.get()))[key]; } auto operator[](const int index) const -> const boxed&; auto operator[](const int index) -> boxed&; }; // class boxed extern template class _template_::fn_t; extern template class _template_::eff_fn_t; extern template class _template_::dict_t; extern template class _template_::weak; extern template class _template_::recur; extern const boxed undefined; 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; template ::value && !std::is_same::value && !std::is_same::value >::type> inline auto box(Args&&... args) -> boxed { return std::make_shared(std::forward(args)...); } template ::value, T>::type* = nullptr> inline auto box(T arg) noexcept -> boxed { return boxed(arg); } template ::value, T>::type* = nullptr> inline auto box(T arg) noexcept -> boxed { return boxed(arg); } template ::value, T>::type* = nullptr> inline auto box(T arg) noexcept -> boxed { return boxed(arg); } template ::value && !std::is_same::value && !std::is_same::value >::type> constexpr auto unbox(const boxed& b) -> const T& { return *static_cast(b.get()); } template ::value, T>::type* = nullptr> constexpr auto unbox(const boxed& b) noexcept -> T { return b._int_; } template ::value, T>::type* = nullptr> constexpr auto unbox(const boxed& b) noexcept -> T { return b._double_; } template ::value, T>::type* = nullptr> constexpr auto unbox(const boxed& b) noexcept -> T { return b._bool_; } template ::value && !std::is_same::value && !std::is_same::value >::type> constexpr auto unbox(boxed& b) -> T& { return *static_cast(b.get()); } template constexpr auto unbox(const T value) noexcept -> T { return value; } template ::value>::type> constexpr auto unbox(const std::size_t value) noexcept -> long long { return value; } inline auto array_length(const boxed& a) -> boxed::array_t::size_type { return unbox(a).size(); } } // namespace purescript #if !defined(PURESCRIPT_DISABLE_EXCEPTIONS) #define THROW_(e) throw std::runtime_error(s) #else #define THROW_(e) return undefined #endif #define DEFINE_FOREIGN_DICTIONARY_AND_ACCESSOR() \ inline auto foreign() -> dict_t& {\ static dict_t _;\ return _;\ } #define FOREIGN_BEGIN(NS) namespace NS {\ using namespace purescript;\ DEFINE_FOREIGN_DICTIONARY_AND_ACCESSOR()\ static const auto data = ([]() -> char {\ dict_t& exports = foreign(); #define FOREIGN_END return 0; }()); } #endif // purescript_H