git.iko.soy/rowtype-yoga/purescript-native
on 82ca705 help sign in
390 lines 12 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 EffFunction = 0x07,
65 Shared = 0x08,
66 String = 0x08,
67 Map = 0x09,
68 Data = 0x0A,
69 Array = 0x0B,
70 Closure = 0x0C,
71 EffClosure = 0x0D,
72 Pointer = 0x0E
73 };
75 private:
76 mutable Type type;
78 public:
79 struct as_thunk {
80 };
81 static constexpr as_thunk unthunk = as_thunk{};
83 using map = std::vector<std::pair<const char * const, const any>>;
84 using data = std::vector<any>;
85 using array = std::deque<any>;
86 using fn = auto (*)(const any&) -> any;
87 using eff_fn = auto (*)() -> any;
88 using thunk = auto (*)(const as_thunk) -> const any&;
90 private:
91 class closure {
92 public:
93 virtual auto operator()(const any&) const -> any = 0;
94 virtual ~closure() {}
95 };
97 template <typename T>
98 class _closure : public closure {
99 const T lambda;
100 public:
101 _closure(const T& l) noexcept : lambda(l) {}
102 auto operator()(const any& arg) const -> any {
103 return lambda(arg);
104 }
105 };
107 class eff_closure {
108 public:
109 virtual auto operator()() const -> any = 0;
110 };
112 template <typename T>
113 class _eff_closure : public eff_closure {
114 const T lambda;
115 public:
116 _eff_closure(const T& l) noexcept : lambda(l) {}
117 auto operator()() const -> any {
118 return lambda();
119 }
120 };
122 public:
123 template <typename T>
124 using shared = std::shared_ptr<T>;
126 template <typename T, typename... Args>
127 inline static auto make_shared(Args&&... args) -> decltype(std::make_shared<T>(std::forward<Args>(args)...)) {
128 return std::make_shared<T>(std::forward<Args>(args)...);
129 }
131 private:
132 union {
133 mutable thunk t;
134 mutable long i;
135 mutable double d;
136 mutable char c;
137 mutable bool b;
138 mutable cstring r;
139 mutable fn f;
140 mutable eff_fn e;
141 mutable shared<std::string> s;
142 mutable shared<map> m;
143 mutable shared<data> v;
144 mutable shared<array> a;
145 mutable shared<closure> l;
146 mutable shared<eff_closure> el;
147 mutable shared<void> p;
148 };
150 public:
152 any(const long val) noexcept : type(Type::Integer), i(val) {}
153 any(const int val) noexcept : type(Type::Integer), i(val) {}
154 any(const unsigned int val) noexcept : type(Type::Integer), i(val) {}
155 any(const double val) noexcept : type(Type::Double), d(val) {}
156 any(const char val) noexcept : type(Type::Character), c(val) {}
158 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
159 any(const T val) noexcept : type(Type::Boolean), b(val) {}
161 template <size_t N>
162 any(const char (&val)[N]) noexcept : type(Type::StringLiteral), r(val) {}
163 any(char * val) : type(Type::String), s(make_shared<std::string>(val)) {}
165 any(const std::string& val) : type(Type::String), s(make_shared<std::string>(val)) {}
166 any(std::string&& val) noexcept : type(Type::String), s(make_shared<std::string>(std::move(val))) {}
168 any(const shared<std::string>& val) noexcept : type(Type::String), s(val) {}
169 any(shared<std::string>&& val) noexcept : type(Type::String), s(std::move(val)) {}
171 any(const map& val) : type(Type::Map), m(make_shared<map>(val)) {}
172 any(map&& val) noexcept : type(Type::Map), m(make_shared<map>(std::move(val))) {}
174 any(const data& val) : type(Type::Data), v(make_shared<data>(val)) {}
175 any(data&& val) noexcept : type(Type::Data), v(make_shared<data>(std::move(val))) {}
177 any(const array& val) : type(Type::Array), a(make_shared<array>(val)) {}
178 any(array&& val) noexcept : type(Type::Array), a(make_shared<array>(std::move(val))) {}
180 template <typename T>
181 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0) noexcept
182 : type(Type::Function), f(val) {}
184 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
185 !std::is_convertible<T,fn>::value>::type>
186 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
187 : type(Type::Closure), l(make_shared<_closure<T>>(val)) {}
189 template <typename T>
190 any(const T& val, typename std::enable_if<std::is_convertible<T,eff_fn>::value>::type* = 0) noexcept
191 : type(Type::EffFunction), e(val) {}
193 template <typename T,
194 typename = typename std::enable_if<!std::is_same<any,T>::value &&
195 !std::is_convertible<T,eff_fn>::value>::type>
196 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
197 : type(Type::EffClosure), el(make_shared<_eff_closure<T>>(val)) {}
199 template <typename T>
200 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0) noexcept
201 : type(Type::Thunk), t(val) {}
203 template <typename T>
204 any(const T& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0) noexcept
205 : type(Type::Pointer), p(val) {}
207 template <typename T>
208 any(T&& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0) noexcept
209 : type(Type::Pointer), p(std::move(val)) {}
211 any(std::nullptr_t) noexcept : type(Type::Pointer), p(nullptr) {}
213 private:
215 auto copy(const any& other) const noexcept -> void {
216 if (type & Type::Shared) {
217 new (&p) shared<void>(other.p);
218 } else {
219 f = other.f;
220 }
221 }
223 auto move(any&& other) const noexcept -> void {
224 if (type & Type::Shared) {
225 new (&p) shared<void>(std::move(other.p));
226 } else {
227 f = other.f;
228 }
229 }
231 auto destruct() -> void {
232 if (type & Type::Shared) {
233 p.~shared<void>();
234 }
235 }
237 public:
239 any(const any& other) noexcept : type(other.type) {
240 copy(other);
241 }
243 any(any&& other) noexcept : type(other.type) {
244 move(std::move(other));
245 }
247 auto operator=(const any& rhs) noexcept -> any& {
248 destruct();
249 type = rhs.type;
250 copy(rhs);
251 return *this;
252 }
254 auto operator=(any&& rhs) noexcept -> any& {
255 destruct();
256 type = rhs.type;
257 move(std::move(rhs));
258 return *this;
259 }
261 any() = delete;
263 ~any() {
264 destruct();
265 }
267 auto operator()(const any&) const -> any;
268 auto operator()(const as_thunk) const -> const any&;
269 auto operator()() const -> any;
271 operator long() const;
272 operator double() const;
273 operator bool() const;
274 operator char() const;
275 operator cstring() const;
276 operator const map&() const;
277 operator const data&() const;
278 operator const array&() const;
280 auto operator[](const char[]) const -> const any&;
281 auto operator[](const size_t) const -> const any&;
282 auto operator[](const any&) const -> const any&;
284 auto contains(const char[]) const -> bool;
286 auto extractPointer() const -> void*;
288 static auto unthunkVariant(const any&) -> const any&;
290 #define DEFINE_OPERATOR(op, ty, rty) \
291 inline friend auto operator op (const any& lhs, ty rhs) -> rty { \
292 return (ty)lhs op rhs; \
293 } \
294 inline friend auto operator op (ty lhs, const any& rhs) -> rty { \
295 return lhs op (ty)rhs; \
296 } \
298 #define DEFINE_INT_OPERATOR(op, rty) \
299 inline friend auto operator op (const any& lhs, int rhs) -> rty { \
300 return (long)lhs op (long)rhs; \
301 } \
302 inline friend auto operator op (int lhs, const any& rhs) -> rty { \
303 return (long)lhs op (long)rhs; \
304 }
306 #define DECLARE_COMPARISON_OPERATOR(op) \
307 friend auto operator op (const any&, const any&) -> bool; \
308 DEFINE_OPERATOR(op, long, bool) \
309 DEFINE_OPERATOR(op, double, bool) \
310 DEFINE_OPERATOR(op, char, bool) \
311 DEFINE_INT_OPERATOR(op, bool) \
312 friend auto operator op (const any&, const char * const) -> bool; \
313 friend auto operator op (const char * const, const any&) -> bool;
315 DECLARE_COMPARISON_OPERATOR(==)
316 DECLARE_COMPARISON_OPERATOR(!=)
317 DECLARE_COMPARISON_OPERATOR(<)
318 DECLARE_COMPARISON_OPERATOR(<=)
319 DECLARE_COMPARISON_OPERATOR(>)
320 DECLARE_COMPARISON_OPERATOR(>=)
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)
328 friend auto operator+(const any& lhs, const char * const rhs) -> std::string;
329 friend auto operator+(const char * const lhs, const any& rhs) -> std::string;
331 friend auto operator-(const any&, const any&) -> any;
333 DEFINE_OPERATOR(-, long, long)
334 DEFINE_OPERATOR(-, double, double)
335 DEFINE_OPERATOR(-, char, char)
336 DEFINE_INT_OPERATOR(-, long)
338 friend auto operator*(const any&, const any&) -> any;
340 DEFINE_OPERATOR(*, long, long)
341 DEFINE_OPERATOR(*, double, double)
342 DEFINE_OPERATOR(*, char, char)
343 DEFINE_INT_OPERATOR(*, long)
345 friend auto operator/(const any&, const any&) -> any;
347 DEFINE_OPERATOR(/, long, long)
348 DEFINE_OPERATOR(/, double, double)
349 DEFINE_OPERATOR(/, char, char)
350 DEFINE_INT_OPERATOR(/, long)
352 friend auto operator%(const any&, const any&) -> any;
354 DEFINE_OPERATOR(%, long, long)
355 DEFINE_OPERATOR(%, char, char)
356 DEFINE_INT_OPERATOR(%, long)
358 friend auto operator-(const any&) -> any; // unary negate
359};
361template <typename T>
362inline auto cast(const any& a) ->
363 typename std::enable_if<std::is_arithmetic<T>::value ||
364 std::is_same<T,cstring>::value, T>::type {
365 return a;
368template <typename T>
369inline auto cast(const any& a) ->
370 typename std::enable_if<std::is_same<T, any::map>::value ||
371 std::is_same<T, any::data>::value ||
372 std::is_same<T, any::array>::value, const T&>::type {
373 return a;
376template <typename T, typename = typename std::enable_if<std::is_class<T>::value>::type>
377inline auto cast(const any& a) ->
378 typename std::enable_if<!std::is_same<T, any::map>::value &&
379 !std::is_same<T, any::data>::value &&
380 !std::is_same<T, any::array>::value, T&>::type {
381 return *static_cast<T*>(a.extractPointer());
384} // namespace PureScript
386#undef DEFINE_OPERATOR
387#undef DEFINE_INT_OPERATOR
388#undef DECLARE_COMPARISON_OPERATOR
390#endif // PureScript_HH