git.iko.soy/rowtype-yoga/purescript-native
on a5bc8dc help sign in
399 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 <functional>
29#include <string>
30#include <vector>
31#include <deque>
32#include <utility>
33#include <stdexcept>
34#include <iso646.h> // mostly for MS Visual Studio compiler
35#include "PureScript_GC.hh"
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_pair = std::pair<const char * const, const any>;
84 using map = std::vector<map_pair WITH_ALLOCATOR(map_pair)>;
85 using data = std::vector<any WITH_ALLOCATOR(any)>;
86 using array = std::deque<any WITH_ALLOCATOR(any)>;
87 using fn = auto (*)(const any&) -> any;
88 using eff_fn = auto (*)() -> any;
89 using thunk = auto (*)(const as_thunk) -> const any&;
91 private:
92 class closure {
93 public:
94 virtual auto operator()(const any&) const -> any = 0;
95 virtual ~closure() {}
96 };
98 template <typename T>
99 class _closure : public closure {
100 const T lambda;
101 public:
102 _closure(const T& l) noexcept : lambda(l) {}
103 auto operator()(const any& arg) const -> any override {
104 return lambda(arg);
105 }
106 };
108 class eff_closure {
109 public:
110 virtual auto operator()() const -> any = 0;
111 virtual ~eff_closure() {}
112 };
114 template <typename T>
115 class _eff_closure : public eff_closure {
116 const T lambda;
117 public:
118 _eff_closure(const T& l) noexcept : lambda(l) {}
119 auto operator()() const -> any override {
120 return lambda();
121 }
122 };
124 public:
125 template <typename T>
126 using shared = SHARED_TYPE(T);
128 template <typename T, typename... Args>
129 inline static auto make_shared(Args&&... args) -> SHARED_TYPE(T) {
130 return MAKE_SHARED(T)(std::forward<Args>(args)...);
131 }
133 private:
134 union {
135 mutable thunk t;
136 mutable long i;
137 mutable double d;
138 mutable char c;
139 mutable bool b;
140 mutable cstring r;
141 mutable fn f;
142 mutable eff_fn e;
143 mutable shared<std::string> s;
144 mutable shared<map> m;
145 mutable shared<data> v;
146 mutable shared<array> a;
147 mutable shared<closure> l;
148 mutable shared<eff_closure> el;
149 mutable shared<void> p;
150 };
152 public:
154 any(const long val) noexcept : type(Type::Integer), i(val) {}
155 any(const int val) noexcept : type(Type::Integer), i(val) {}
156 any(const unsigned int val) noexcept : type(Type::Integer), i(val) {}
157 any(const double val) noexcept : type(Type::Double), d(val) {}
158 any(const char val) noexcept : type(Type::Character), c(val) {}
160 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
161 any(const T val) noexcept : type(Type::Boolean), b(val) {}
163 template <size_t N>
164 any(const char (&val)[N]) noexcept : type(Type::StringLiteral), r(val) {}
165 any(char * val) : type(Type::String), s(make_shared<std::string>(val)) {}
167 any(const std::string& val) : type(Type::String), s(make_shared<std::string>(val)) {}
168 any(std::string&& val) noexcept : type(Type::String), s(make_shared<std::string>(std::move(val))) {}
170 any(const shared<std::string>& val) noexcept : type(Type::String), s(val) {}
171 any(shared<std::string>&& val) noexcept : type(Type::String), s(std::move(val)) {}
173 any(const map& val) : type(Type::Map), m(make_shared<map>(val)) {}
174 any(map&& val) noexcept : type(Type::Map), m(make_shared<map>(std::move(val))) {}
176 any(const data& val) : type(Type::Data), v(make_shared<data>(val)) {}
177 any(data&& val) noexcept : type(Type::Data), v(make_shared<data>(std::move(val))) {}
179 any(const array& val) : type(Type::Array), a(make_shared<array>(val)) {}
180 any(array&& val) noexcept : type(Type::Array), a(make_shared<array>(std::move(val))) {}
182 template <typename T>
183 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0) noexcept
184 : type(Type::Function), f(val) {}
186 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
187 !std::is_convertible<T,fn>::value>::type>
188 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
189 : type(Type::Closure), l(make_shared<_closure<T>>(val)) {}
191 template <typename T>
192 any(const T& val, typename std::enable_if<std::is_convertible<T,eff_fn>::value>::type* = 0) noexcept
193 : type(Type::EffFunction), e(val) {}
195 template <typename T,
196 typename = typename std::enable_if<!std::is_same<any,T>::value &&
197 !std::is_convertible<T,eff_fn>::value>::type>
198 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
199 : type(Type::EffClosure), el(make_shared<_eff_closure<T>>(val)) {}
201 template <typename T>
202 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0) noexcept
203 : type(Type::Thunk), t(val) {}
205 template <typename T,
206 typename = typename std::enable_if<std::is_class<typename std::remove_pointer<T>::type>::value>::type>
207 any(const T& val, typename std::enable_if<IS_POINTER_TYPE(T)::value>::type* = 0) noexcept
208 : type(Type::Pointer), p(val) {}
210 template <typename T>
211 any(T&& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0) noexcept
212 : type(Type::Pointer), p(std::move(val)) {}
214 any(std::nullptr_t) noexcept : type(Type::Pointer), p(nullptr) {}
217#if !defined(USE_GC)
218 private:
219 auto copy(const any& other) const noexcept -> void {
220 if (type & Type::Shared) {
221 new (&p) shared<void>(other.p);
222 } else {
223 f = other.f;
224 }
225 }
227 auto move(any&& other) const noexcept -> void {
228 if (type & Type::Shared) {
229 new (&p) shared<void>(std::move(other.p));
230 } else {
231 f = other.f;
232 }
233 }
235 auto destruct() -> void {
236 if (type & Type::Shared) {
237 p.~shared<void>();
238 }
239 }
241 public:
242 any(const any& other) noexcept : type(other.type) {
243 copy(other);
244 }
246 any(any&& other) noexcept : type(other.type) {
247 move(std::move(other));
248 }
250 auto operator=(const any& rhs) noexcept -> any& {
251 destruct();
252 type = rhs.type;
253 copy(rhs);
254 return *this;
255 }
257 auto operator=(any&& rhs) noexcept -> any& {
258 destruct();
259 type = rhs.type;
260 move(std::move(rhs));
261 return *this;
262 }
264 ~any() {
265 destruct();
266 }
267#endif // !defined(USE_GC)
269 public:
270 any() = delete;
272 auto operator()(const any&) const -> any;
273 auto operator()(const as_thunk) const -> const any&;
274 auto operator()() const -> any;
276 operator long() const;
277 operator double() const;
278 operator bool() const;
279 operator char() const;
280 operator cstring() const;
281 operator const map&() const;
282 operator const data&() const;
283 operator const array&() const;
285 auto operator[](const char[]) const -> const any&;
286 auto operator[](const size_t) const -> const any&;
287 auto operator[](const any&) const -> const any&;
289 auto contains(const char[]) const -> bool;
291 auto extractPointer() const -> void*;
293 static auto unthunkVariant(const any&) -> const any&;
295 #define DEFINE_OPERATOR(op, ty, rty) \
296 inline friend auto operator op (const any& lhs, ty rhs) -> rty { \
297 return (ty)lhs op rhs; \
298 } \
299 inline friend auto operator op (ty lhs, const any& rhs) -> rty { \
300 return lhs op (ty)rhs; \
301 } \
303 #define DEFINE_INT_OPERATOR(op, rty) \
304 inline friend auto operator op (const any& lhs, int rhs) -> rty { \
305 return (long)lhs op (long)rhs; \
306 } \
307 inline friend auto operator op (int lhs, const any& rhs) -> rty { \
308 return (long)lhs op (long)rhs; \
309 }
311 #define DECLARE_COMPARISON_OPERATOR(op) \
312 friend auto operator op (const any&, const any&) -> bool; \
313 DEFINE_OPERATOR(op, long, bool) \
314 DEFINE_OPERATOR(op, double, bool) \
315 DEFINE_OPERATOR(op, char, bool) \
316 DEFINE_INT_OPERATOR(op, bool) \
317 friend auto operator op (const any&, const char * const) -> bool; \
318 friend auto operator op (const char * const, const any&) -> bool;
320 DECLARE_COMPARISON_OPERATOR(==)
321 DECLARE_COMPARISON_OPERATOR(!=)
322 DECLARE_COMPARISON_OPERATOR(<)
323 DECLARE_COMPARISON_OPERATOR(<=)
324 DECLARE_COMPARISON_OPERATOR(>)
325 DECLARE_COMPARISON_OPERATOR(>=)
327 friend auto operator+(const any&, const any&) -> any;
329 DEFINE_OPERATOR(+, long, long)
330 DEFINE_OPERATOR(+, double, double)
331 DEFINE_OPERATOR(+, char, char)
332 DEFINE_INT_OPERATOR(+, long)
333 friend auto operator+(const any& lhs, const char * const rhs) -> std::string;
334 friend auto operator+(const char * const lhs, const any& rhs) -> std::string;
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(*, double, double)
347 DEFINE_OPERATOR(*, char, char)
348 DEFINE_INT_OPERATOR(*, long)
350 friend auto operator/(const any&, const any&) -> any;
352 DEFINE_OPERATOR(/, long, long)
353 DEFINE_OPERATOR(/, double, double)
354 DEFINE_OPERATOR(/, char, char)
355 DEFINE_INT_OPERATOR(/, long)
357 friend auto operator%(const any&, const any&) -> any;
359 DEFINE_OPERATOR(%, long, long)
360 DEFINE_OPERATOR(%, char, char)
361 DEFINE_INT_OPERATOR(%, long)
363 friend auto operator-(const any&) -> any; // unary negate
364};
366template <typename T>
367inline auto cast(const any& a) ->
368 typename std::enable_if<std::is_arithmetic<T>::value ||
369 std::is_same<T,cstring>::value, T>::type {
370 return a;
373template <typename T>
374inline auto cast(const any& a) ->
375 typename std::enable_if<std::is_same<T, any::map>::value ||
376 std::is_same<T, any::data>::value ||
377 std::is_same<T, any::array>::value, const T&>::type {
378 return a;
381template <typename T, typename = typename std::enable_if<std::is_class<T>::value>::type>
382inline auto cast(const any& a) ->
383 typename std::enable_if<!std::is_same<T, any::map>::value &&
384 !std::is_same<T, any::data>::value &&
385 !std::is_same<T, any::array>::value, T&>::type {
386 return *static_cast<T*>(a.extractPointer());
389} // namespace PureScript
391#undef WITH_ALLOCATOR
392#undef SHARED_TYPE
393#undef MAKE_SHARED
394#undef IS_POINTER_TYPE
395#undef DEFINE_OPERATOR
396#undef DEFINE_INT_OPERATOR
397#undef DECLARE_COMPARISON_OPERATOR
399#endif // PureScript_HH