git.iko.soy/rowtype-yoga/purescript-native
on 373bbf0 help sign in
403 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 integer = std::intptr_t;
40using cstring = const char *;
41using nullptr_t = std::nullptr_t;
43// Workaround for missing C++11 version in gcc
44class runtime_error : public std::runtime_error {
45public:
46 runtime_error(const char message[]) : std::runtime_error(std::string(message)) {}
47};
49const integer INTEGER_MIN = INTPTR_MIN;
50const integer INTEGER_MAX = INTPTR_MAX;
52const bool undefined = false;
53const size_t constructor = 0;
55// A variant data class designed to provide some features of dynamic typing.
56//
57class any {
59 public:
60 enum Type {
61 Thunk = 0x00,
62 Integer = 0x01,
63 Double = 0x02,
64 Character = 0x03,
65 Boolean = 0x04,
66 StringLiteral = 0x05,
67 Function = 0x06,
68 EffFunction = 0x07,
69 Shared = 0x08,
70 String = 0x08,
71 Map = 0x09,
72 Data = 0x0A,
73 Array = 0x0B,
74 Closure = 0x0C,
75 EffClosure = 0x0D,
76 Pointer = 0x0E
77 };
79 private:
80 mutable Type type;
82 public:
83 struct as_thunk {
84 };
85 static constexpr as_thunk unthunk = as_thunk{};
87 using map_pair = std::pair<const char * const, const any>;
88 using map = std::vector<map_pair WITH_ALLOCATOR(map_pair)>;
89 using data = std::vector<any WITH_ALLOCATOR(any)>;
90 using array = std::deque<any WITH_ALLOCATOR(any)>;
91 using fn = auto (*)(const any&) -> any;
92 using eff_fn = auto (*)() -> any;
93 using thunk = auto (*)(const as_thunk) -> const any&;
95 private:
96 class closure {
97 public:
98 virtual auto operator()(const any&) const -> any = 0;
99 virtual ~closure() {}
100 };
102 template <typename T>
103 class _closure : public closure {
104 const T lambda;
105 public:
106 _closure(const T& l) noexcept : lambda(l) {}
107 auto operator()(const any& arg) const -> any override {
108 return lambda(arg);
109 }
110 };
112 class eff_closure {
113 public:
114 virtual auto operator()() const -> any = 0;
115 virtual ~eff_closure() {}
116 };
118 template <typename T>
119 class _eff_closure : public eff_closure {
120 const T lambda;
121 public:
122 _eff_closure(const T& l) noexcept : lambda(l) {}
123 auto operator()() const -> any override {
124 return lambda();
125 }
126 };
128 public:
129 template <typename T>
130 using shared = SHARED_TYPE(T);
132 template <typename T, typename... Args>
133 inline static auto make_shared(Args&&... args) -> SHARED_TYPE(T) {
134 return MAKE_SHARED(T)(std::forward<Args>(args)...);
135 }
137 private:
138 union {
139 mutable thunk t;
140 mutable integer i;
141 mutable double d;
142 mutable char c;
143 mutable bool b;
144 mutable cstring r;
145 mutable fn f;
146 mutable eff_fn e;
147 mutable shared<std::string> s;
148 mutable shared<map> m;
149 mutable shared<data> v;
150 mutable shared<array> a;
151 mutable shared<closure> l;
152 mutable shared<eff_closure> el;
153 mutable shared<void> p;
154 };
156 public:
158 any(const integer val) noexcept : type(Type::Integer), i(val) {}
159 any(const int val) noexcept : type(Type::Integer), i(val) {}
160 any(const unsigned int val) noexcept : type(Type::Integer), i(val) {}
161 any(const double val) noexcept : type(Type::Double), d(val) {}
162 any(const char val) noexcept : type(Type::Character), c(val) {}
164 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
165 any(const T val) noexcept : type(Type::Boolean), b(val) {}
167 template <size_t N>
168 any(const char (&val)[N]) noexcept : type(Type::StringLiteral), r(val) {}
169 any(char * val) : type(Type::String), s(make_shared<std::string>(val)) {}
171 any(const std::string& val) : type(Type::String), s(make_shared<std::string>(val)) {}
172 any(std::string&& val) noexcept : type(Type::String), s(make_shared<std::string>(std::move(val))) {}
174 any(const shared<std::string>& val) noexcept : type(Type::String), s(val) {}
175 any(shared<std::string>&& val) noexcept : type(Type::String), s(std::move(val)) {}
177 any(const map& val) : type(Type::Map), m(make_shared<map>(val)) {}
178 any(map&& val) noexcept : type(Type::Map), m(make_shared<map>(std::move(val))) {}
180 any(const data& val) : type(Type::Data), v(make_shared<data>(val)) {}
181 any(data&& val) noexcept : type(Type::Data), v(make_shared<data>(std::move(val))) {}
183 any(const array& val) : type(Type::Array), a(make_shared<array>(val)) {}
184 any(array&& val) noexcept : type(Type::Array), a(make_shared<array>(std::move(val))) {}
186 template <typename T>
187 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0) noexcept
188 : type(Type::Function), f(val) {}
190 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
191 !std::is_convertible<T,fn>::value>::type>
192 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
193 : type(Type::Closure), l(make_shared<_closure<T>>(val)) {}
195 template <typename T>
196 any(const T& val, typename std::enable_if<std::is_convertible<T,eff_fn>::value>::type* = 0) noexcept
197 : type(Type::EffFunction), e(val) {}
199 template <typename T,
200 typename = typename std::enable_if<!std::is_same<any,T>::value &&
201 !std::is_convertible<T,eff_fn>::value>::type>
202 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
203 : type(Type::EffClosure), el(make_shared<_eff_closure<T>>(val)) {}
205 template <typename T>
206 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0) noexcept
207 : type(Type::Thunk), t(val) {}
209 template <typename T,
210 typename = typename std::enable_if<std::is_class<typename std::remove_pointer<T>::type>::value>::type>
211 any(const T& val, typename std::enable_if<IS_POINTER_TYPE(T)::value>::type* = 0) noexcept
212 : type(Type::Pointer), p(val) {}
214 template <typename T>
215 any(T&& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0) noexcept
216 : type(Type::Pointer), p(std::move(val)) {}
218 any(std::nullptr_t) noexcept : type(Type::Pointer), p(nullptr) {}
221#if !defined(USE_GC)
222 private:
223 auto copy(const any& other) const noexcept -> void {
224 if (type & Type::Shared) {
225 new (&p) shared<void>(other.p);
226 } else {
227 f = other.f;
228 }
229 }
231 auto move(any&& other) const noexcept -> void {
232 if (type & Type::Shared) {
233 new (&p) shared<void>(std::move(other.p));
234 } else {
235 f = other.f;
236 }
237 }
239 auto destruct() -> void {
240 if (type & Type::Shared) {
241 p.~shared<void>();
242 }
243 }
245 public:
246 any(const any& other) noexcept : type(other.type) {
247 copy(other);
248 }
250 any(any&& other) noexcept : type(other.type) {
251 move(std::move(other));
252 }
254 auto operator=(const any& rhs) noexcept -> any& {
255 destruct();
256 type = rhs.type;
257 copy(rhs);
258 return *this;
259 }
261 auto operator=(any&& rhs) noexcept -> any& {
262 destruct();
263 type = rhs.type;
264 move(std::move(rhs));
265 return *this;
266 }
268 ~any() {
269 destruct();
270 }
271#endif // !defined(USE_GC)
273 public:
274 any() = delete;
276 auto operator()(const any&) const -> any;
277 auto operator()(const as_thunk) const -> const any&;
278 auto operator()() const -> any;
280 operator integer() const;
281 operator double() const;
282 operator bool() const;
283 operator char() const;
284 operator cstring() const;
285 operator const map&() const;
286 operator const data&() const;
287 operator const array&() const;
289 auto operator[](const char[]) const -> const any&;
290 auto operator[](const size_t) const -> const any&;
291 auto operator[](const any&) const -> const any&;
293 auto contains(const char[]) const -> bool;
295 auto extractPointer() const -> void*;
297 static auto unthunkVariant(const any&) -> const any&;
299 #define DEFINE_OPERATOR(op, ty, rty) \
300 inline friend auto operator op (const any& lhs, ty rhs) -> rty { \
301 return (ty)lhs op rhs; \
302 } \
303 inline friend auto operator op (ty lhs, const any& rhs) -> rty { \
304 return lhs op (ty)rhs; \
305 } \
307 #define DEFINE_INT_OPERATOR(op, rty) \
308 inline friend auto operator op (const any& lhs, int rhs) -> rty { \
309 return (integer)lhs op (integer)rhs; \
310 } \
311 inline friend auto operator op (int lhs, const any& rhs) -> rty { \
312 return (integer)lhs op (integer)rhs; \
313 }
315 #define DECLARE_COMPARISON_OPERATOR(op) \
316 friend auto operator op (const any&, const any&) -> bool; \
317 DEFINE_OPERATOR(op, integer, bool) \
318 DEFINE_OPERATOR(op, double, bool) \
319 DEFINE_OPERATOR(op, char, bool) \
320 DEFINE_INT_OPERATOR(op, bool) \
321 friend auto operator op (const any&, const char * const) -> bool; \
322 friend auto operator op (const char * const, const any&) -> bool;
324 DECLARE_COMPARISON_OPERATOR(==)
325 DECLARE_COMPARISON_OPERATOR(!=)
326 DECLARE_COMPARISON_OPERATOR(<)
327 DECLARE_COMPARISON_OPERATOR(<=)
328 DECLARE_COMPARISON_OPERATOR(>)
329 DECLARE_COMPARISON_OPERATOR(>=)
331 friend auto operator+(const any&, const any&) -> any;
333 DEFINE_OPERATOR(+, integer, integer)
334 DEFINE_OPERATOR(+, double, double)
335 DEFINE_OPERATOR(+, char, char)
336 DEFINE_INT_OPERATOR(+, integer)
337 friend auto operator+(const any& lhs, const char * const rhs) -> std::string;
338 friend auto operator+(const char * const lhs, const any& rhs) -> std::string;
340 friend auto operator-(const any&, const any&) -> any;
342 DEFINE_OPERATOR(-, integer, integer)
343 DEFINE_OPERATOR(-, double, double)
344 DEFINE_OPERATOR(-, char, char)
345 DEFINE_INT_OPERATOR(-, integer)
347 friend auto operator*(const any&, const any&) -> any;
349 DEFINE_OPERATOR(*, integer, integer)
350 DEFINE_OPERATOR(*, double, double)
351 DEFINE_OPERATOR(*, char, char)
352 DEFINE_INT_OPERATOR(*, integer)
354 friend auto operator/(const any&, const any&) -> any;
356 DEFINE_OPERATOR(/, integer, integer)
357 DEFINE_OPERATOR(/, double, double)
358 DEFINE_OPERATOR(/, char, char)
359 DEFINE_INT_OPERATOR(/, integer)
361 friend auto operator%(const any&, const any&) -> any;
363 DEFINE_OPERATOR(%, integer, integer)
364 DEFINE_OPERATOR(%, char, char)
365 DEFINE_INT_OPERATOR(%, integer)
367 friend auto operator-(const any&) -> any; // unary negate
368};
370template <typename T>
371inline auto cast(const any& a) ->
372 typename std::enable_if<std::is_arithmetic<T>::value ||
373 std::is_same<T,cstring>::value, T>::type {
374 return a;
377template <typename T>
378inline auto cast(const any& a) ->
379 typename std::enable_if<std::is_same<T, any::map>::value ||
380 std::is_same<T, any::data>::value ||
381 std::is_same<T, any::array>::value, const T&>::type {
382 return a;
385template <typename T, typename = typename std::enable_if<std::is_class<T>::value>::type>
386inline auto cast(const any& a) ->
387 typename std::enable_if<!std::is_same<T, any::map>::value &&
388 !std::is_same<T, any::data>::value &&
389 !std::is_same<T, any::array>::value, T&>::type {
390 return *static_cast<T*>(a.extractPointer());
393} // namespace PureScript
395#undef WITH_ALLOCATOR
396#undef SHARED_TYPE
397#undef MAKE_SHARED
398#undef IS_POINTER_TYPE
399#undef DEFINE_OPERATOR
400#undef DEFINE_INT_OPERATOR
401#undef DECLARE_COMPARISON_OPERATOR
403#endif // PureScript_HH