git.iko.soy/rowtype-yoga/purescript-native
on cf43a16 help sign in
382 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
37#define DECLARE_OPERATOR(op, ty, rty) \
38 friend auto operator op (const any&, ty) -> rty; \
39 friend auto operator op (ty, const any&) -> rty;
41#define DECLARE_COMPARISON_OPERATOR(op) \
42 friend auto operator op (const any&, const any&) -> bool; \
43 DECLARE_OPERATOR(op, long, bool) \
44 DECLARE_OPERATOR(op, double, bool) \
45 DECLARE_OPERATOR(op, char, bool) \
46 DECLARE_OPERATOR(op, const char *, bool)
49namespace PureScript {
51using string = const char *;
52using nullptr_t = std::nullptr_t;
54// Workaround for missing C++11 version in gcc
55class runtime_error : public std::runtime_error {
56public:
57 runtime_error(const char message[]) : std::runtime_error(std::string(message)) {}
58};
60const bool undefined = false;
61const size_t constructor = 0;
63// A variant data class designed to provide some features of dynamic typing.
64//
65class any {
67 public:
68 enum class Type : int8_t {
69 Unknown,
70 Integer,
71 Double,
72 Character,
73 Boolean,
74 StringLiteral,
75 String,
76 Map,
77 Data,
78 Array,
79 Function,
80 Closure,
81 EffFunction,
82 Thunk,
83 Pointer
84 };
86 private:
87 mutable Type type;
88 mutable bool is_shared;
90 public:
91 struct as_thunk {
92 };
93 static constexpr as_thunk unthunk = as_thunk{};
95 using map = std::vector<std::pair<const char * const, const any>>;
96 using data = std::vector<any>;
97 using array = std::deque<any>;
98 using fn = auto (*)(const any&) -> any;
99 using thunk = auto (*)(const as_thunk) -> const any&;
101 private:
102 class closure {
103 public:
104 virtual auto operator()(const any&) const -> any = 0;
105 virtual ~closure() {}
106 };
108 template <typename T>
109 class _closure : public closure {
110 const T lambda;
111 public:
112 _closure(const T& l) noexcept : lambda(l) {}
113 auto operator()(const any& arg) const -> any {
114 return lambda(arg);
115 }
116 };
118 class eff_fn {
119 public:
120 virtual auto operator()() const -> any = 0;
121 };
123 template <typename T>
124 class _eff_fn : public eff_fn {
125 const T lambda;
126 public:
127 _eff_fn(const T& l) noexcept : lambda(l) {}
128 auto operator()() const -> any {
129 return lambda();
130 }
131 };
133 public:
134 template <typename T>
135 using shared = std::shared_ptr<T>;
137 template <typename T, typename... Args>
138 inline static auto make_shared(Args&&... args) -> decltype(std::make_shared<T>(std::forward<Args>(args)...)) {
139 return std::make_shared<T>(std::forward<Args>(args)...);
140 }
142 private:
143 union {
144 mutable long i;
145 mutable double d;
146 mutable char c;
147 mutable bool b;
148 mutable string r;
149 mutable shared<std::string> s;
150 mutable shared<map> m;
151 mutable shared<data> v;
152 mutable shared<array> a;
153 mutable fn f;
154 mutable shared<closure> l;
155 mutable shared<eff_fn> e;
156 mutable thunk t;
157 mutable shared<void> p;
158 };
160 public:
162 any(const long val) : type(Type::Integer), is_shared(false), i(val) {}
163 any(const int val) : type(Type::Integer), is_shared(false), i(val) {}
164 any(const unsigned int val) : type(Type::Integer), is_shared(false), i(val) {}
165 any(const double val) : type(Type::Double), is_shared(false), d(val) {}
166 any(const char val) : type(Type::Character), is_shared(false), c(val) {}
168 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
169 any(const T val) : type(Type::Boolean), is_shared(false), b(val) {}
171 template <size_t N>
172 any(const char (&val)[N]) : type(Type::StringLiteral), is_shared(false), r(val) {}
173 any(char * val) : type(Type::String), is_shared(true), s(make_shared<std::string>(val)) {}
175 any(const std::string& val) : type(Type::String), is_shared(true), s(make_shared<std::string>(val)) {}
176 any(std::string&& val) : type(Type::String), is_shared(true), s(make_shared<std::string>(std::move(val))) {}
178 any(const shared<std::string>& val) : type(Type::String), is_shared(true), s(val) {}
179 any(shared<std::string>&& val) noexcept : type(Type::String), is_shared(true), s(std::move(val)) {}
181 any(const map& val) : type(Type::Map), is_shared(true), m(make_shared<map>(val)) {}
182 any(map&& val) noexcept : type(Type::Map), is_shared(true), m(make_shared<map>(std::move(val))) {}
184 any(const data& val) : type(Type::Data), is_shared(true), v(make_shared<data>(val)) {}
185 any(data&& val) noexcept : type(Type::Data), is_shared(true), v(make_shared<data>(std::move(val))) {}
187 any(const array& val) : type(Type::Array), is_shared(true), a(make_shared<array>(val)) {}
188 any(array&& val) noexcept : type(Type::Array), is_shared(true), a(make_shared<array>(std::move(val))) {}
190 template <typename T>
191 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0)
192 : type(Type::Function), is_shared(false), f(val) {}
194 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
195 !std::is_convertible<T,fn>::value>::type>
196 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
197 : type(Type::Closure), is_shared(true), l(make_shared<_closure<T>>(val)) {}
199 template <typename T>
200 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
201 : type(Type::EffFunction), is_shared(true), e(make_shared<_eff_fn<T>>(val)) {}
203 template <typename T>
204 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0)
205 : type(Type::Thunk), is_shared(false), t(val) {}
207 template <typename T>
208 any(const T& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0)
209 : type(Type::Pointer), is_shared(true), p(val) {}
211 template <typename T>
212 any(T&& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0) noexcept
213 : type(Type::Pointer), is_shared(true), p(std::move(val)) {}
215 any(std::nullptr_t) : type(Type::Pointer), is_shared(true), p(nullptr) {}
217 private:
219 auto copy(const any& other) const -> void {
220 if (is_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 (is_shared) {
229 new (&p) shared<void>(std::move(other.p));
230 } else {
231 f = other.f;
232 }
233 }
235 auto destruct() noexcept -> void {
236 if (is_shared) {
237 p.~shared<void>();
238 }
239 }
241 public:
243 any(const any& other) : type(other.type), is_shared(other.is_shared) {
244 copy(other);
245 }
247 any(any&& other) noexcept : type(other.type), is_shared(other.is_shared) {
248 move(other);
249 }
251 auto operator=(const any& rhs) -> any& {
252 destruct();
253 type = rhs.type;
254 is_shared = rhs.is_shared;
255 copy(rhs);
256 return *this;
257 }
259 auto operator=(any&& rhs) noexcept -> any& {
260 destruct();
261 type = rhs.type;
262 is_shared = rhs.is_shared;
263 move(rhs);
264 return *this;
265 }
267 any() = delete;
269 ~any() {
270 destruct();
271 }
273 template <typename T>
274 auto cast() const -> typename std::enable_if<std::is_same<T, long>::value, T>::type;
276 template <typename T>
277 auto cast() const -> typename std::enable_if<std::is_same<T, double>::value, T>::type;
279 template <typename T>
280 auto cast() const -> typename std::enable_if<std::is_same<T, char>::value, T>::type;
282 template <typename T>
283 auto cast() const -> typename std::enable_if<std::is_same<T, bool>::value, T>::type;
285 template <typename T>
286 auto cast() const -> typename std::enable_if<std::is_same<T, string>::value, T>::type;
288 template <typename T>
289 auto cast() const -> typename std::enable_if<std::is_same<T, map>::value, const T&>::type;
291 template <typename T>
292 auto cast() const -> typename std::enable_if<std::is_same<T, data>::value, const T&>::type;
294 template <typename T>
295 auto cast() const -> typename std::enable_if<std::is_same<T, array>::value, const T&>::type;
297 template <typename T>
298 auto cast() const -> typename std::enable_if<std::is_assignable<shared<void>,T>::value, typename T::element_type*>::type {
299 return static_cast<typename T::element_type*>(extractPointer());
300 }
302 auto operator()(const any&) const -> any;
303 auto operator()(const as_thunk) const -> const any&;
304 auto operator()() const -> any;
306 operator long() const;
307 operator double() const;
308 operator bool() const;
310 operator string() const;
311 operator const map&() const;
312 operator const data&() const;
313 operator const array&() const;
315 auto operator[](const char[]) const -> const any&;
316 auto operator[](const size_t) const -> const any&;
317 auto operator[](const any&) const -> const any&;
319 auto contains(const char[]) const -> bool;
321 auto extractPointer() const -> void*;
323 static auto unthunkVariant(const any&) -> const any&;
325 DECLARE_COMPARISON_OPERATOR(==)
326 DECLARE_COMPARISON_OPERATOR(!=)
327 DECLARE_COMPARISON_OPERATOR(<)
328 DECLARE_COMPARISON_OPERATOR(<=)
329 DECLARE_COMPARISON_OPERATOR(>)
330 DECLARE_COMPARISON_OPERATOR(>=)
332 // For MS Visual Studio compiler: broken typed-enum workaround
333 DECLARE_OPERATOR(==, int, bool)
334 DECLARE_OPERATOR(!=, int, bool)
336 friend auto operator+(const any&, const any&) -> any;
338 DECLARE_OPERATOR(+, long, long)
339 DECLARE_OPERATOR(+, double, double)
340 DECLARE_OPERATOR(+, char, char)
341 DECLARE_OPERATOR(+, const char *, std::string)
343 friend auto operator-(const any&, const any&) -> any;
345 DECLARE_OPERATOR(-, long, long)
346 DECLARE_OPERATOR(-, double, double)
347 DECLARE_OPERATOR(-, char, char)
349 friend auto operator*(const any&, const any&) -> any;
351 DECLARE_OPERATOR(*, long, long)
352 DECLARE_OPERATOR(*, double, double)
353 DECLARE_OPERATOR(*, char, char)
355 friend auto operator/(const any&, const any&) -> any;
357 DECLARE_OPERATOR(/, long, long)
358 DECLARE_OPERATOR(/, double, double)
359 DECLARE_OPERATOR(/, char, char)
361 friend auto operator%(const any&, const any&) -> any;
363 DECLARE_OPERATOR(%, long, long)
364 DECLARE_OPERATOR(%, char, char)
366 friend auto operator-(const any&) -> any; // unary negate
367};
369// For MS Visual Studio compiler: broken typed-enum workaround
370inline auto operator==(const any& lhs, int rhs) -> bool {
371 return lhs == (long)rhs;
373inline auto operator!=(const any& lhs, int rhs) -> bool {
374 return lhs != (long)rhs;
377} // namespace PureScript
379#undef DECLARE_OPERATOR
380#undef DECLARE_COMPARISON_OPERATOR
382#endif // PureScript_HH