git.iko.soy/rowtype-yoga/purescript-native
on fa9c565 help sign in
381 lines 11 kB history raw
1///////////////////////////////////////////////////////////////////////////////
2//
3// Module : purescript.hh
4// Copyright : (c) Andy Arvanitis 2015
5// License : MIT
6//
7// Maintainer : Andy Arvanitis <andy.arvanitis@gmail.com>
8// Stability : experimental
9// Portability :
10//
11// Basic types and functions to support purescript-to-C++1x rendering
12//
13///////////////////////////////////////////////////////////////////////////////
14//
15#ifndef PureScript_HH
16#define PureScript_HH
18// Standard includes
20#if defined(DEBUG)
21 #include <cassert>
22#else
23 #define NDEBUG
24 #undef assert
25 #define assert(x)
26#endif
28#include <memory>
29#include <functional>
30#include <string>
31#include <vector>
32#include <deque>
33#include <utility>
34#include <stdexcept>
35#include <iso646.h> // mostly for MS Visual Studio compiler
37namespace PureScript {
39using cstring = const char *;
40using nullptr_t = std::nullptr_t;
42// Workaround for missing C++11 version in gcc
43class runtime_error : public std::runtime_error {
44public:
45 runtime_error(const char message[]) : std::runtime_error(std::string(message)) {}
46};
48const bool undefined = false;
49const size_t constructor = 0;
51// A variant data class designed to provide some features of dynamic typing.
52//
53class any {
55 public:
56 enum Type {
57 Thunk = 0x00,
58 Integer = 0x01,
59 Double = 0x02,
60 Character = 0x03,
61 Boolean = 0x04,
62 StringLiteral = 0x05,
63 Function = 0x06,
64 Shared = 0x08,
65 String = 0x08,
66 Map = 0x09,
67 Data = 0x0A,
68 Array = 0x0B,
69 Closure = 0x0C,
70 EffFunction = 0x0D,
71 Pointer = 0x0E
72 };
74 private:
75 mutable Type type;
77 public:
78 struct as_thunk {
79 };
80 static constexpr as_thunk unthunk = as_thunk{};
82 using map = std::vector<std::pair<const char * const, const any>>;
83 using data = std::vector<any>;
84 using array = std::deque<any>;
85 using fn = auto (*)(const any&) -> any;
86 using thunk = auto (*)(const as_thunk) -> const any&;
88 private:
89 class closure {
90 public:
91 virtual auto operator()(const any&) const -> any = 0;
92 virtual ~closure() {}
93 };
95 template <typename T>
96 class _closure : public closure {
97 const T lambda;
98 public:
99 _closure(const T& l) noexcept : lambda(l) {}
100 auto operator()(const any& arg) const -> any {
101 return lambda(arg);
102 }
103 };
105 class eff_fn {
106 public:
107 virtual auto operator()() const -> any = 0;
108 };
110 template <typename T>
111 class _eff_fn : public eff_fn {
112 const T lambda;
113 public:
114 _eff_fn(const T& l) noexcept : lambda(l) {}
115 auto operator()() const -> any {
116 return lambda();
117 }
118 };
120 public:
121 template <typename T>
122 using shared = std::shared_ptr<T>;
124 template <typename T, typename... Args>
125 inline static auto make_shared(Args&&... args) -> decltype(std::make_shared<T>(std::forward<Args>(args)...)) {
126 return std::make_shared<T>(std::forward<Args>(args)...);
127 }
129 private:
130 union {
131 mutable thunk t;
132 mutable long i;
133 mutable double d;
134 mutable char c;
135 mutable bool b;
136 mutable cstring r;
137 mutable fn f;
138 mutable shared<std::string> s;
139 mutable shared<map> m;
140 mutable shared<data> v;
141 mutable shared<array> a;
142 mutable shared<closure> l;
143 mutable shared<eff_fn> e;
144 mutable shared<void> p;
145 };
147 public:
149 any(const long val) noexcept : type(Type::Integer), i(val) {}
150 any(const int val) noexcept : type(Type::Integer), i(val) {}
151 any(const unsigned int val) noexcept : type(Type::Integer), i(val) {}
152 any(const double val) noexcept : type(Type::Double), d(val) {}
153 any(const char val) noexcept : type(Type::Character), c(val) {}
155 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
156 any(const T val) noexcept : type(Type::Boolean), b(val) {}
158 template <size_t N>
159 any(const char (&val)[N]) noexcept : type(Type::StringLiteral), r(val) {}
160 any(char * val) : type(Type::String), s(make_shared<std::string>(val)) {}
162 any(const std::string& val) : type(Type::String), s(make_shared<std::string>(val)) {}
163 any(std::string&& val) noexcept : type(Type::String), s(make_shared<std::string>(std::move(val))) {}
165 any(const shared<std::string>& val) noexcept : type(Type::String), s(val) {}
166 any(shared<std::string>&& val) noexcept : type(Type::String), s(std::move(val)) {}
168 any(const map& val) : type(Type::Map), m(make_shared<map>(val)) {}
169 any(map&& val) noexcept : type(Type::Map), m(make_shared<map>(std::move(val))) {}
171 any(const data& val) : type(Type::Data), v(make_shared<data>(val)) {}
172 any(data&& val) noexcept : type(Type::Data), v(make_shared<data>(std::move(val))) {}
174 any(const array& val) : type(Type::Array), a(make_shared<array>(val)) {}
175 any(array&& val) noexcept : type(Type::Array), a(make_shared<array>(std::move(val))) {}
177 template <typename T>
178 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0) noexcept
179 : type(Type::Function), f(val) {}
181 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
182 !std::is_convertible<T,fn>::value>::type>
183 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
184 : type(Type::Closure), l(make_shared<_closure<T>>(val)) {}
186 template <typename T>
187 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
188 : type(Type::EffFunction), e(make_shared<_eff_fn<T>>(val)) {}
190 template <typename T>
191 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0) noexcept
192 : type(Type::Thunk), t(val) {}
194 template <typename T>
195 any(const T& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0) noexcept
196 : type(Type::Pointer), p(val) {}
198 template <typename T>
199 any(T&& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0) noexcept
200 : type(Type::Pointer), p(std::move(val)) {}
202 any(std::nullptr_t) noexcept : type(Type::Pointer), p(nullptr) {}
204 private:
206 auto copy(const any& other) const noexcept -> void {
207 if (type & Type::Shared) {
208 new (&p) shared<void>(other.p);
209 } else {
210 f = other.f;
211 }
212 }
214 auto move(any&& other) const noexcept -> void {
215 if (type & Type::Shared) {
216 new (&p) shared<void>(std::move(other.p));
217 } else {
218 f = other.f;
219 }
220 }
222 auto destruct() -> void {
223 if (type & Type::Shared) {
224 p.~shared<void>();
225 }
226 }
228 public:
230 any(const any& other) noexcept : type(other.type) {
231 copy(other);
232 }
234 any(any&& other) noexcept : type(other.type) {
235 move(std::move(other));
236 }
238 auto operator=(const any& rhs) noexcept -> any& {
239 destruct();
240 type = rhs.type;
241 copy(rhs);
242 return *this;
243 }
245 auto operator=(any&& rhs) noexcept -> any& {
246 destruct();
247 type = rhs.type;
248 move(std::move(rhs));
249 return *this;
250 }
252 any() = delete;
254 ~any() {
255 destruct();
256 }
258 auto operator()(const any&) const -> any;
259 auto operator()(const as_thunk) const -> const any&;
260 auto operator()() const -> any;
262 operator long() const;
263 operator double() const;
264 operator bool() const;
265 operator char() const;
266 operator cstring() const;
267 operator const map&() const;
268 operator const data&() const;
269 operator const array&() const;
271 auto operator[](const char[]) const -> const any&;
272 auto operator[](const size_t) const -> const any&;
273 auto operator[](const any&) const -> const any&;
275 auto contains(const char[]) const -> bool;
277 auto extractPointer() const -> void*;
279 static auto unthunkVariant(const any&) -> const any&;
281 #define DEFINE_OPERATOR(op, ty, rty) \
282 inline friend auto operator op (const any& lhs, ty rhs) -> rty { \
283 return (ty)lhs op rhs; \
284 } \
285 inline friend auto operator op (ty lhs, const any& rhs) -> rty { \
286 return lhs op (ty)rhs; \
287 } \
289 #define DEFINE_INT_OPERATOR(op, rty) \
290 inline friend auto operator op (const any& lhs, int rhs) -> rty { \
291 return (long)lhs op (long)rhs; \
292 } \
293 inline friend auto operator op (int lhs, const any& rhs) -> rty { \
294 return (long)lhs op (long)rhs; \
295 }
297 #define DECLARE_COMPARISON_OPERATOR(op) \
298 friend auto operator op (const any&, const any&) -> bool; \
299 DEFINE_OPERATOR(op, long, bool) \
300 DEFINE_OPERATOR(op, double, bool) \
301 DEFINE_OPERATOR(op, char, bool) \
302 DEFINE_INT_OPERATOR(op, bool) \
303 friend auto operator op (const any&, const char * const) -> bool; \
304 friend auto operator op (const char * const, const any&) -> bool;
306 DECLARE_COMPARISON_OPERATOR(==)
307 DECLARE_COMPARISON_OPERATOR(!=)
308 DECLARE_COMPARISON_OPERATOR(<)
309 DECLARE_COMPARISON_OPERATOR(<=)
310 DECLARE_COMPARISON_OPERATOR(>)
311 DECLARE_COMPARISON_OPERATOR(>=)
313 friend auto operator+(const any&, const any&) -> any;
315 DEFINE_OPERATOR(+, long, long)
316 DEFINE_OPERATOR(+, double, double)
317 DEFINE_OPERATOR(+, char, char)
318 DEFINE_INT_OPERATOR(+, long)
319 friend auto operator+(const any& lhs, const char * const rhs) -> std::string;
320 friend auto operator+(const char * const lhs, const any& rhs) -> std::string;
322 friend auto operator-(const any&, const any&) -> any;
324 DEFINE_OPERATOR(-, long, long)
325 DEFINE_OPERATOR(-, double, double)
326 DEFINE_OPERATOR(-, char, char)
327 DEFINE_INT_OPERATOR(-, long)
329 friend auto operator*(const any&, const any&) -> any;
331 DEFINE_OPERATOR(*, long, long)
332 DEFINE_OPERATOR(*, double, double)
333 DEFINE_OPERATOR(*, char, char)
334 DEFINE_INT_OPERATOR(*, long)
336 friend auto operator/(const any&, const any&) -> any;
338 DEFINE_OPERATOR(/, long, long)
339 DEFINE_OPERATOR(/, double, double)
340 DEFINE_OPERATOR(/, char, char)
341 DEFINE_INT_OPERATOR(/, long)
343 friend auto operator%(const any&, const any&) -> any;
345 DEFINE_OPERATOR(%, long, long)
346 DEFINE_OPERATOR(%, char, char)
347 DEFINE_INT_OPERATOR(%, long)
349 friend auto operator-(const any&) -> any; // unary negate
350};
352template <typename T>
353inline auto cast(const any& a) ->
354 typename std::enable_if<std::is_arithmetic<T>::value ||
355 std::is_same<T,cstring>::value, T>::type {
356 return a;
359template <typename T>
360inline auto cast(const any& a) ->
361 typename std::enable_if<std::is_same<T, any::map>::value ||
362 std::is_same<T, any::data>::value ||
363 std::is_same<T, any::array>::value, const T&>::type {
364 return a;
367template <typename T, typename = typename std::enable_if<std::is_class<T>::value>::type>
368inline auto cast(const any& a) ->
369 typename std::enable_if<!std::is_same<T, any::map>::value &&
370 !std::is_same<T, any::data>::value &&
371 !std::is_same<T, any::array>::value, T&>::type {
372 return *static_cast<T*>(a.extractPointer());
375} // namespace PureScript
377#undef DEFINE_OPERATOR
378#undef DEFINE_INT_OPERATOR
379#undef DECLARE_COMPARISON_OPERATOR
381#endif // PureScript_HH