git.iko.soy/rowtype-yoga/purescript-native
on 9ec7bf4 help sign in
189 lines 5.8 kB history raw
1///////////////////////////////////////////////////////////////////////////////
2//
3// Module : purescript.h
4// Copyright : (c) Andy Arvanitis 2018
5// License : BSD
6//
7// Maintainer : Andy Arvanitis
8// Stability : experimental
9// Portability :
10//
11// Basic types and functions to support purescript-to-C++ rendering
12//
13///////////////////////////////////////////////////////////////////////////////
14//
15#ifndef purescript_H
16#define purescript_H
18#include <memory>
19#include <functional>
20#include <deque>
21#include <map>
22#include <string>
23#include <limits>
25namespace purescript {
27 using std::string;
29 class boxed : public std::shared_ptr<void> {
31 public:
32 using fn_t = std::function<boxed(const boxed&)>;
33 using eff_fn_t = std::function<boxed(void)>;
34 using dict_t = std::map<const string, boxed>;
35 using array_t = std::deque<boxed>;
37 public:
38 using std::shared_ptr<void>::shared_ptr;
40 boxed() noexcept : std::shared_ptr<void>() {
41 }
43 boxed(const std::nullptr_t) noexcept : std::shared_ptr<void>() {
44 }
46 boxed(const int n) : std::shared_ptr<void>(std::make_shared<int>(n)) {
47 }
49 boxed(const long n) : std::shared_ptr<void>(std::make_shared<int>(static_cast<int>(n))) {
50#ifndef NDEBUG
51 if (n < std::numeric_limits<int>::min() || n > std::numeric_limits<int>::max()) {
52 throw std::runtime_error("integer out of range");
53 }
54#endif // !NDEBUG
55 }
57 boxed(const double n) : std::shared_ptr<void>(std::make_shared<double>(n)) {
58 }
60 boxed(const bool b) : std::shared_ptr<void>(std::make_shared<bool>(b)) {
61 }
63 boxed(const char s[]) : std::shared_ptr<void>(std::make_shared<string>(s)) {
64 }
66 boxed(string&& s) : std::shared_ptr<void>(std::make_shared<string>(std::move(s))) {
67 }
69 boxed(array_t&& l) : std::shared_ptr<void>(std::make_shared<array_t>(std::move(l))) {
70 }
72 boxed(dict_t&& m) : std::shared_ptr<void>(std::make_shared<dict_t>(std::move(m))) {
73 }
75 template <typename T,
76 typename = typename std::enable_if<!std::is_same<boxed,T>::value>::type>
77 boxed(const T& f,
78 typename std::enable_if<std::is_assignable<std::function<boxed(boxed)>,T>::value>::type* = 0) : std::shared_ptr<void>(std::make_shared<fn_t>(f)) {
79 }
81 template <typename T,
82 typename = typename std::enable_if<!std::is_same<boxed,T>::value>::type>
83 boxed(const T& f,
84 typename std::enable_if<std::is_assignable<std::function<boxed(void)>,T>::value>::type* = 0) : std::shared_ptr<void>(std::make_shared<eff_fn_t>(f)) {
85 }
87 template <typename T,
88 typename = typename std::enable_if<!std::is_same<boxed,T>::value &&
89 std::is_convertible<T,fn_t>::value>::type>
90 auto operator=(const T& right) -> boxed& {
91 if (std::shared_ptr<void>::operator bool()) {
92 auto& f = *static_cast<fn_t*>(get());
93 f = right;
94 } else {
95 reset(new fn_t(right));
96 }
97 return *this;
98 }
100 auto operator()(const boxed& arg) const -> boxed {
101 auto& f = *static_cast<fn_t*>(get());
102 return f(arg);
103 }
105 auto operator()() const -> boxed {
106 auto& f = *static_cast<eff_fn_t*>(get());
107 return f();
108 }
110 auto operator[](const string& key) const -> const boxed& {
111 const auto& dict = *static_cast<const dict_t*>(get());
112 return dict.at(key);
113 }
115 auto operator[](const string& key) -> boxed& {
116 auto& dict = *static_cast<dict_t*>(get());
117 return dict[key];
118 }
120#ifdef NDEBUG
121 auto operator[](const int index) const -> const boxed& {
122 const auto& array = *static_cast<const array_t*>(get());
123 return array[index];
124 }
126 auto operator[](const int index) -> boxed& {
127 auto& array = *static_cast<array_t*>(get());
128 return array[index];
129 }
130#else
131 auto operator[](const int index) const -> const boxed& {
132 const auto& array = *static_cast<const array_t*>(get());
133 return array.at(index);
134 }
136 auto operator[](const int index) -> boxed& {
137 auto& array = *static_cast<array_t*>(get());
138 return array.at(index);
139 }
141#endif // NDEBUG
143 }; // class boxed
145 template <typename T, typename... Args>
146 inline auto box(Args&&... args) -> boxed {
147 return std::make_shared<T>(std::forward<Args>(args)...);
148 }
150 template <typename T>
151 inline auto unbox(const boxed& b) -> const T& {
152 const auto& unboxed = *static_cast<const T*>(b.get());
153 return unboxed;
154 }
156 template <typename T,
157 typename = typename std::enable_if<!std::is_same<T, const boxed&>::value>::type>
158 constexpr auto unbox(const T value) -> T {
159 return value;
160 }
162 template <typename T>
163 inline auto peek(boxed& b) -> T& {
164 auto& unboxed = *static_cast<T*>(b.get());
165 return unboxed;
166 }
168 template <typename T>
169 inline auto copy(const boxed& b) -> boxed {
170 return box<T>(unbox<T>(b));
171 }
173 using fn_t = boxed::fn_t;
174 using eff_fn_t = boxed::eff_fn_t;
175 using dict_t = boxed::dict_t;
176 using array_t = boxed::array_t;
178 constexpr auto undefined = nullptr;
180} // namespace purescript
182#define FOREIGN_BEGIN(NS) namespace NS {\
183 using namespace purescript;\
184 auto foreign() -> dict_t&;\
185 static const auto& NS ## $foreign_init = []() {\
186 dict_t& exports = foreign();
187#define FOREIGN_END return exports; }(); }
189#endif // purescript_H