git.iko.soy/rowtype-yoga/purescript-native
on 1ff046b help sign in
422 lines 13 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 RawPointer = 0x08,
70 Shared = 0x10,
71 String = 0x10,
72 Map = 0x11,
73 Data = 0x12,
74 Array = 0x13,
75 Closure = 0x14,
76 EffClosure = 0x15,
77 Pointer = 0x16
78 };
80 private:
81 mutable Type type;
83 public:
84 struct as_thunk {
85 };
86 static constexpr as_thunk unthunk = as_thunk{};
88 using map_pair = std::pair<const char * const, const any>;
89 using map = std::vector<map_pair WITH_ALLOCATOR(map_pair)>;
90 using data = std::vector<any WITH_ALLOCATOR(any)>;
91 using array = std::deque<any WITH_ALLOCATOR(any)>;
92 using fn = auto (*)(const any&) -> any;
93 using eff_fn = auto (*)() -> any;
94 using thunk = auto (*)(const as_thunk) -> const any&;
96 private:
97 class closure {
98 public:
99 virtual auto operator()(const any&) const -> any = 0;
100 virtual ~closure() {}
101 };
103 template <typename T>
104 class _closure : public closure {
105 const T lambda;
106 public:
107 _closure(const T& l) noexcept : lambda(l) {}
108 auto operator()(const any& arg) const -> any override {
109 return lambda(arg);
110 }
111 };
113 class eff_closure {
114 public:
115 virtual auto operator()() const -> any = 0;
116 virtual ~eff_closure() {}
117 };
119 template <typename T>
120 class _eff_closure : public eff_closure {
121 const T lambda;
122 public:
123 _eff_closure(const T& l) noexcept : lambda(l) {}
124 auto operator()() const -> any override {
125 return lambda();
126 }
127 };
129 public:
130 template <typename T>
131 using shared = SHARED_TYPE(T);
133 template <typename T, typename... Args>
134 inline static auto make_shared(Args&&... args) -> SHARED_TYPE(T) {
135 return MAKE_SHARED(T)(std::forward<Args>(args)...);
136 }
138 private:
139 union {
140 mutable thunk t;
141 mutable integer i;
142 mutable double d;
143 mutable char c;
144 mutable bool b;
145 mutable cstring r;
146 mutable fn f;
147 mutable eff_fn e;
148 mutable void * u;
149 mutable shared<std::string> s;
150 mutable shared<map> m;
151 mutable shared<data> v;
152 mutable shared<array> a;
153 mutable shared<closure> l;
154 mutable shared<eff_closure> el;
155 mutable shared<void> p;
156 };
158 public:
160 any(const integer val) noexcept : type(Type::Integer), i(val) {}
161 any(const int val) noexcept : type(Type::Integer), i(val) {}
162 any(const unsigned int val) noexcept : type(Type::Integer), i(val) {}
163 any(const double val) noexcept : type(Type::Double), d(val) {}
164 any(const char val) noexcept : type(Type::Character), c(val) {}
166 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
167 any(const T val) noexcept : type(Type::Boolean), b(val) {}
169 template <size_t N>
170 any(const char (&val)[N]) noexcept : type(Type::StringLiteral), r(val) {}
171 any(char * val) : type(Type::String), s(make_shared<std::string>(val)) {}
173 any(const std::string& val) : type(Type::String), s(make_shared<std::string>(val)) {}
174 any(std::string&& val) noexcept : type(Type::String), s(make_shared<std::string>(std::move(val))) {}
176 any(const shared<std::string>& val) noexcept : type(Type::String), s(val) {}
177 any(shared<std::string>&& val) noexcept : type(Type::String), s(std::move(val)) {}
179 any(const map& val) : type(Type::Map), m(make_shared<map>(val)) {}
180 any(map&& val) noexcept : type(Type::Map), m(make_shared<map>(std::move(val))) {}
182 any(const data& val) : type(Type::Data), v(make_shared<data>(val)) {}
183 any(data&& val) noexcept : type(Type::Data), v(make_shared<data>(std::move(val))) {}
185 any(const array& val) : type(Type::Array), a(make_shared<array>(val)) {}
186 any(array&& val) noexcept : type(Type::Array), a(make_shared<array>(std::move(val))) {}
188 template <typename T>
189 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0) noexcept
190 : type(Type::Function), f(val) {}
192 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
193 !std::is_convertible<T,fn>::value>::type>
194 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
195 : type(Type::Closure), l(make_shared<_closure<T>>(val)) {}
197 template <typename T>
198 any(const T& val, typename std::enable_if<std::is_convertible<T,eff_fn>::value>::type* = 0) noexcept
199 : type(Type::EffFunction), e(val) {}
201 template <typename T,
202 typename = typename std::enable_if<!std::is_same<any,T>::value &&
203 !std::is_convertible<T,eff_fn>::value>::type>
204 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
205 : type(Type::EffClosure), el(make_shared<_eff_closure<T>>(val)) {}
207 template <typename T>
208 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0) noexcept
209 : type(Type::Thunk), t(val) {}
211 template <typename T,
212 typename = typename std::enable_if<std::is_class<typename std::remove_pointer<T>::type>::value>::type>
213 any(const T& val, typename std::enable_if<IS_POINTER_TYPE(T)::value>::type* = 0) noexcept
214 : type(Type::Pointer), p(val) {}
216 template <typename T>
217 any(T&& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0) noexcept
218 : type(Type::Pointer), p(std::move(val)) {}
220 // Explicit void* to raw pointer value
221 template <typename T>
222 any(const T& val, typename std::enable_if<std::is_same<T,void*>::value>::type* = 0) noexcept
223 : type(Type::RawPointer), u(val) {}
225 any(std::nullptr_t) noexcept : type(Type::Pointer), p(nullptr) {}
228#if !defined(USE_GC)
229 private:
230 auto copy(const any& other) const noexcept -> void {
231 if (type & Type::Shared) {
232 new (&p) shared<void>(other.p);
233 } else {
234 f = other.f;
235 }
236 }
238 auto move(any&& other) const noexcept -> void {
239 if (type & Type::Shared) {
240 new (&p) shared<void>(std::move(other.p));
241 } else {
242 f = other.f;
243 }
244 }
246 auto destruct() -> void {
247 if (type & Type::Shared) {
248 p.~shared<void>();
249 }
250 }
252 public:
253 any(const any& other) noexcept : type(other.type) {
254 copy(other);
255 }
257 any(any&& other) noexcept : type(other.type) {
258 move(std::move(other));
259 }
261 auto operator=(const any& rhs) noexcept -> any& {
262 destruct();
263 type = rhs.type;
264 copy(rhs);
265 return *this;
266 }
268 auto operator=(any&& rhs) noexcept -> any& {
269 destruct();
270 type = rhs.type;
271 move(std::move(rhs));
272 return *this;
273 }
275 ~any() {
276 destruct();
277 }
278#endif // !defined(USE_GC)
280 public:
281 any() = delete;
283 auto operator()(const any&) const -> any;
284 auto operator()(const as_thunk) const -> const any&;
285 auto operator()() const -> any;
287 operator integer() const;
288 operator double() const;
289 operator bool() const;
290 operator char() const;
291 operator cstring() const;
292 operator const map&() const;
293 operator const data&() const;
294 operator const array&() const;
296 auto operator[](const char[]) const -> const any&;
297 auto operator[](const size_t) const -> const any&;
298 auto operator[](const any&) const -> const any&;
300 auto contains(const char[]) const -> bool;
302 auto extractPointer() const -> void*;
304 auto rawPointer() const -> void* {
305 const any& variant = unthunkVariant(*this);
306 assert(type == Type::RawPointer);
307 return variant.u;
308 }
310 static auto unthunkVariant(const any&) -> const any&;
312 #define DEFINE_OPERATOR(op, ty, rty) \
313 inline friend auto operator op (const any& lhs, ty rhs) -> rty { \
314 return (ty)lhs op rhs; \
315 } \
316 inline friend auto operator op (ty lhs, const any& rhs) -> rty { \
317 return lhs op (ty)rhs; \
318 } \
320 #define DEFINE_INT_OPERATOR(op, rty) \
321 inline friend auto operator op (const any& lhs, int rhs) -> rty { \
322 return (integer)lhs op (integer)rhs; \
323 } \
324 inline friend auto operator op (int lhs, const any& rhs) -> rty { \
325 return (integer)lhs op (integer)rhs; \
326 }
328 #define DECLARE_COMPARISON_OPERATOR(op) \
329 friend auto operator op (const any&, const any&) -> bool; \
330 DEFINE_OPERATOR(op, integer, bool) \
331 DEFINE_OPERATOR(op, double, bool) \
332 DEFINE_OPERATOR(op, char, bool) \
333 DEFINE_INT_OPERATOR(op, bool) \
334 friend auto operator op (const any&, const char * const) -> bool; \
335 friend auto operator op (const char * const, const any&) -> bool;
337 DECLARE_COMPARISON_OPERATOR(==)
338 DECLARE_COMPARISON_OPERATOR(!=)
339 DECLARE_COMPARISON_OPERATOR(<)
340 DECLARE_COMPARISON_OPERATOR(<=)
341 DECLARE_COMPARISON_OPERATOR(>)
342 DECLARE_COMPARISON_OPERATOR(>=)
344 friend auto operator+(const any&, const any&) -> any;
346 DEFINE_OPERATOR(+, integer, integer)
347 DEFINE_OPERATOR(+, double, double)
348 DEFINE_OPERATOR(+, char, char)
349 DEFINE_INT_OPERATOR(+, integer)
350 friend auto operator+(const any& lhs, const char * const rhs) -> std::string;
351 friend auto operator+(const char * const lhs, const any& rhs) -> std::string;
353 friend auto operator-(const any&, const any&) -> any;
355 DEFINE_OPERATOR(-, integer, integer)
356 DEFINE_OPERATOR(-, double, double)
357 DEFINE_OPERATOR(-, char, char)
358 DEFINE_INT_OPERATOR(-, integer)
360 friend auto operator*(const any&, const any&) -> any;
362 DEFINE_OPERATOR(*, integer, integer)
363 DEFINE_OPERATOR(*, double, double)
364 DEFINE_OPERATOR(*, char, char)
365 DEFINE_INT_OPERATOR(*, integer)
367 friend auto operator/(const any&, const any&) -> any;
369 DEFINE_OPERATOR(/, integer, integer)
370 DEFINE_OPERATOR(/, double, double)
371 DEFINE_OPERATOR(/, char, char)
372 DEFINE_INT_OPERATOR(/, integer)
374 friend auto operator%(const any&, const any&) -> any;
376 DEFINE_OPERATOR(%, integer, integer)
377 DEFINE_OPERATOR(%, char, char)
378 DEFINE_INT_OPERATOR(%, integer)
380 friend auto operator-(const any&) -> any; // unary negate
381};
383template <typename T>
384inline auto cast(const any& a) ->
385 typename std::enable_if<std::is_arithmetic<T>::value ||
386 std::is_same<T,cstring>::value, T>::type {
387 return a;
390template <typename T>
391inline auto cast(const any& a) ->
392 typename std::enable_if<std::is_same<T, any::map>::value ||
393 std::is_same<T, any::data>::value ||
394 std::is_same<T, any::array>::value, const T&>::type {
395 return a;
398template <typename T, typename = typename std::enable_if<std::is_class<T>::value>::type>
399inline auto cast(const any& a) ->
400 typename std::enable_if<!std::is_same<T, any::map>::value &&
401 !std::is_same<T, any::data>::value &&
402 !std::is_same<T, any::array>::value, T&>::type {
403 return *static_cast<T*>(a.extractPointer());
406template <typename T>
407inline auto cast(const any& a) ->
408 typename std::enable_if<std::is_same<void*, T>::value, T>::type {
409 return a.rawPointer();
412} // namespace PureScript
414#undef WITH_ALLOCATOR
415#undef SHARED_TYPE
416#undef MAKE_SHARED
417#undef IS_POINTER_TYPE
418#undef DEFINE_OPERATOR
419#undef DEFINE_INT_OPERATOR
420#undef DECLARE_COMPARISON_OPERATOR
422#endif // PureScript_HH