git.iko.soy/rowtype-yoga/purescript-native
on e655652 help sign in
434 lines 14 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>
36#define DECLARE_OPERATOR(op, ty, rty) \
37 friend auto operator op (const any&, ty) -> rty; \
38 friend auto operator op (ty, const any&) -> rty;
40#define DECLARE_COMPARISON_OPERATOR(op) \
41 friend auto operator op (const any&, const any&) -> bool; \
42 DECLARE_OPERATOR(op, long, bool) \
43 DECLARE_OPERATOR(op, double, bool) \
44 DECLARE_OPERATOR(op, char, bool) \
45 DECLARE_OPERATOR(op, const char *, bool)
48namespace PureScript {
50using string = const char *;
51using nullptr_t = std::nullptr_t;
53// Workaround for missing C++11 version in gcc
54class runtime_error : public std::runtime_error {
55public:
56 runtime_error(const char message[]) : std::runtime_error(std::string(message)) {}
57};
59const bool undefined = false;
60const size_t constructor = 0;
62// A variant data class designed to provide some features of dynamic typing.
63//
64class any {
66 public:
67 enum class Type : int8_t {
68 Unknown,
69 Integer,
70 Double,
71 Character,
72 Boolean,
73 StringLiteral,
74 String,
75 Map,
76 Data,
77 Array,
78 Function,
79 Closure,
80 EffFunction,
81 Thunk,
82 Pointer
83 };
85 private:
86 mutable Type type;
87 mutable bool is_shared;
89 public:
90 struct as_thunk {
91 };
92 static constexpr as_thunk unthunk = as_thunk{};
94 using map = std::vector<std::pair<const char * const, const any>>;
95 using data = std::vector<any>;
96 using array = std::deque<any>;
97 using fn = auto (*)(const any&) -> any;
98 using thunk = auto (*)(const as_thunk) -> const any&;
100 private:
101 class closure {
102 public:
103 virtual auto operator()(const any&) const -> any = 0;
104 virtual auto operator()(const any&, const any&) const -> any = 0;
105 virtual auto operator()(const any&, const any&, const any&) const -> any = 0;
106 virtual ~closure() {}
107 };
109 template <typename T>
110 class _closure : public closure {
111 const T lambda;
112 public:
113 _closure(const T& l) noexcept : lambda(l) {}
114 auto operator()(const any& arg) const -> any {
115 return lambda(arg);
116 }
117 auto operator()(const any& arg1, const any& arg2) const -> any {
118 return lambda(arg1)(arg2);
119 }
120 auto operator()(const any& arg1, const any& arg2, const any& arg3) const -> any {
121 return lambda(arg1)(arg2)(arg3);
122 }
123 };
125 template <typename T>
126 class _closure2 : public closure {
127 const T lambda;
128 public:
129 _closure2(const T& l) noexcept : lambda(l) {}
130 auto operator()(const any& arg1) const -> any {
131 return [=](const any& arg2) -> any {
132 return lambda(arg1, arg2);
133 };
134 }
135 auto operator()(const any& arg1, const any& arg2) const -> any {
136 return lambda(arg1, arg2);
137 }
138 auto operator()(const any& arg1, const any& arg2, const any& arg3) const -> any {
139 return lambda(arg1, arg2)(arg3);
140 }
141 };
143 template <typename T>
144 class _closure3 : public closure {
145 const T lambda;
146 public:
147 _closure3(const T& l) noexcept : lambda(l) {}
148 auto operator()(const any& arg1) const -> any {
149 return [=](const any& arg2) -> any {
150 return [=](const any& arg3) -> any {
151 return lambda(arg1, arg2, arg3);
152 };
153 };
154 }
155 auto operator()(const any& arg1, const any& arg2) const -> any {
156 return [=](const any& arg3) -> any {
157 return lambda(arg1, arg2, arg3);
158 };
159 }
160 auto operator()(const any& arg1, const any& arg2, const any& arg3) const -> any {
161 return lambda(arg1, arg2, arg3);
162 }
163 };
165 class eff_fn {
166 public:
167 virtual auto operator()() const -> any = 0;
168 };
170 template <typename T>
171 class _eff_fn : public eff_fn {
172 const T lambda;
173 public:
174 _eff_fn(const T& l) noexcept : lambda(l) {}
175 auto operator()() const -> any {
176 return lambda();
177 }
178 };
180 public:
181 template <typename T>
182 using shared = std::shared_ptr<T>;
184 template <typename T, typename... Args>
185 inline static auto make_shared(Args&&... args) -> decltype(std::make_shared<T>(std::forward<Args>(args)...)) {
186 return std::make_shared<T>(std::forward<Args>(args)...);
187 }
189 private:
190 union {
191 mutable long i;
192 mutable double d;
193 mutable char c;
194 mutable bool b;
195 mutable string r;
196 mutable shared<std::string> s;
197 mutable shared<map> m;
198 mutable shared<data> v;
199 mutable shared<array> a;
200 mutable fn f;
201 mutable shared<closure> l;
202 mutable shared<eff_fn> e;
203 mutable thunk t;
204 mutable shared<void> p;
205 };
207 public:
209 any(const long val) : type(Type::Integer), is_shared(false), i(val) {}
210 any(const int val) : type(Type::Integer), is_shared(false), i(val) {}
211 any(const unsigned int val) : type(Type::Integer), is_shared(false), i(val) {}
212 any(const double val) : type(Type::Double), is_shared(false), d(val) {}
213 any(const char val) : type(Type::Character), is_shared(false), c(val) {}
215 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
216 any(const T val) : type(Type::Boolean), is_shared(false), b(val) {}
218 template <size_t N>
219 any(const char (&val)[N]) : type(Type::StringLiteral), is_shared(false), r(val) {}
220 any(char * val) : type(Type::String), is_shared(true), s(make_shared<std::string>(val)) {}
222 any(const std::string& val) : type(Type::String), is_shared(true), s(make_shared<std::string>(val)) {}
223 any(std::string&& val) : type(Type::String), is_shared(true), s(make_shared<std::string>(std::move(val))) {}
225 any(const shared<std::string>& val) : type(Type::String), is_shared(true), s(val) {}
226 any(shared<std::string>&& val) noexcept : type(Type::String), is_shared(true), s(std::move(val)) {}
228 any(const map& val) : type(Type::Map), is_shared(true), m(make_shared<map>(val)) {}
229 any(map&& val) noexcept : type(Type::Map), is_shared(true), m(make_shared<map>(std::move(val))) {}
231 any(const data& val) : type(Type::Data), is_shared(true), v(make_shared<data>(val)) {}
232 any(data&& val) noexcept : type(Type::Data), is_shared(true), v(make_shared<data>(std::move(val))) {}
234 any(const array& val) : type(Type::Array), is_shared(true), a(make_shared<array>(val)) {}
235 any(array&& val) noexcept : type(Type::Array), is_shared(true), a(make_shared<array>(std::move(val))) {}
237 template <typename T>
238 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0)
239 : type(Type::Function), is_shared(false), f(val) {}
241 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
242 !std::is_convertible<T,fn>::value>::type>
243 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
244 : type(Type::Closure), is_shared(true), l(make_shared<_closure<T>>(val)) {}
246 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
247 !std::is_convertible<T,fn>::value>::type>
248 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&,
249 const any&)>,T>::value>::type* = 0)
250 : type(Type::Closure), is_shared(true), l(make_shared<_closure2<T>>(val)) {}
252 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
253 !std::is_convertible<T,fn>::value>::type>
254 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&,
255 const any&,
256 const any&)>,T>::value>::type* = 0)
257 : type(Type::Closure), is_shared(true), l(make_shared<_closure3<T>>(val)) {}
259 template <typename T>
260 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
261 : type(Type::EffFunction), is_shared(true), e(make_shared<_eff_fn<T>>(val)) {}
263 template <typename T>
264 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0)
265 : type(Type::Thunk), is_shared(false), t(val) {}
267 template <typename T>
268 any(const T& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0)
269 : type(Type::Pointer), is_shared(true), p(val) {}
271 template <typename T>
272 any(T&& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0) noexcept
273 : type(Type::Pointer), is_shared(true), p(std::move(val)) {}
275 any(std::nullptr_t) : type(Type::Pointer), is_shared(true), p(nullptr) {}
277 private:
279 auto copy(const any& other) const -> void {
280 if (is_shared) {
281 new (&p) shared<void>(other.p);
282 } else {
283 f = other.f;
284 }
285 }
287 auto move(any& other) const noexcept -> void {
288 if (is_shared) {
289 new (&p) shared<void>(std::move(other.p));
290 } else {
291 f = other.f;
292 }
293 }
295 auto del() noexcept -> void {
296 if (is_shared) {
297 p.~shared<void>();
298 }
299 }
301 public:
303 any(const any& other) : type(other.type), is_shared(other.is_shared) {
304 copy(other);
305 }
307 any(any&& other) noexcept : type(other.type), is_shared(other.is_shared) {
308 move(other);
309 }
311 auto operator=(const any& rhs) -> any& {
312 del();
313 type = rhs.type;
314 is_shared = rhs.is_shared;
315 copy(rhs);
316 return *this;
317 }
319 auto operator=(any&& rhs) noexcept -> any& {
320 del();
321 type = rhs.type;
322 is_shared = rhs.is_shared;
323 move(rhs);
324 return *this;
325 }
327 any() = delete;
329 ~any() {
330 del();
331 }
333 template <typename T>
334 auto cast() const -> typename std::enable_if<std::is_same<T, long>::value, T>::type;
336 template <typename T>
337 auto cast() const -> typename std::enable_if<std::is_same<T, double>::value, T>::type;
339 template <typename T>
340 auto cast() const -> typename std::enable_if<std::is_same<T, char>::value, T>::type;
342 template <typename T>
343 auto cast() const -> typename std::enable_if<std::is_same<T, bool>::value, T>::type;
345 template <typename T>
346 auto cast() const -> typename std::enable_if<std::is_same<T, string>::value, T>::type;
348 template <typename T>
349 auto cast() const -> typename std::enable_if<std::is_same<T, map>::value, const T&>::type;
351 template <typename T>
352 auto cast() const -> typename std::enable_if<std::is_same<T, data>::value, const T&>::type;
354 template <typename T>
355 auto cast() const -> typename std::enable_if<std::is_same<T, array>::value, const T&>::type;
357 template <typename T>
358 auto cast() const -> typename std::enable_if<std::is_assignable<shared<void>,T>::value, typename T::element_type*>::type {
359 return static_cast<typename T::element_type*>(extractPointer());
360 }
362 auto operator()(const any&) const -> any;
363 auto operator()(const any&, const any&) const -> any;
364 auto operator()(const any&, const any&, const any&) const -> any;
366 auto operator()(const as_thunk) const -> const any&;
368 auto operator()() const -> any;
370 operator long() const;
371 operator double() const;
372 operator bool() const;
374 operator string() const;
375 operator const map&() const;
376 operator const data&() const;
377 operator const array&() const;
379 auto operator[](const char[]) const -> const any&;
380 auto operator[](const size_t) const -> const any&;
381 auto operator[](const any&) const -> const any&;
383 auto contains(const char[]) const -> bool;
385 auto extractPointer() const -> void*;
387 static auto unthunkVariant(const any&) -> const any&;
389 DECLARE_COMPARISON_OPERATOR(==)
390 DECLARE_COMPARISON_OPERATOR(!=)
391 DECLARE_COMPARISON_OPERATOR(<)
392 DECLARE_COMPARISON_OPERATOR(<=)
393 DECLARE_COMPARISON_OPERATOR(>)
394 DECLARE_COMPARISON_OPERATOR(>=)
396 friend auto operator+(const any&, const any&) -> any;
398 DECLARE_OPERATOR(+, long, long)
399 DECLARE_OPERATOR(+, double, double)
400 DECLARE_OPERATOR(+, char, char)
401 DECLARE_OPERATOR(+, const char *, std::string)
403 friend auto operator-(const any&, const any&) -> any;
405 DECLARE_OPERATOR(-, long, long)
406 DECLARE_OPERATOR(-, double, double)
407 DECLARE_OPERATOR(-, char, char)
409 friend auto operator*(const any&, const any&) -> any;
411 DECLARE_OPERATOR(*, long, long)
412 DECLARE_OPERATOR(*, double, double)
413 DECLARE_OPERATOR(*, char, char)
415 friend auto operator/(const any&, const any&) -> any;
417 DECLARE_OPERATOR(/, long, long)
418 DECLARE_OPERATOR(/, double, double)
419 DECLARE_OPERATOR(/, char, char)
421 friend auto operator%(const any&, const any&) -> any;
423 DECLARE_OPERATOR(%, long, long)
424 DECLARE_OPERATOR(%, char, char)
426 friend auto operator-(const any&) -> any; // unary negate
427};
429} // namespace PureScript
431#undef DECLARE_OPERATOR
432#undef DECLARE_COMPARISON_OPERATOR
434#endif // PureScript_HH