git.iko.soy/rowtype-yoga/purescript-native
on 12fdbae help sign in
386 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 <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 = Type::Unknown;
88 public:
89 struct as_thunk {
90 };
91 static constexpr as_thunk unthunk = as_thunk{};
93 using map = std::vector<std::pair<const char * const, const any>>;
94 using data = std::vector<any>;
95 using array = std::deque<any>;
96 using fn = auto (*)(const any&) -> any;
97 using thunk = auto (*)(const as_thunk) -> const any&;
99 private:
100 class closure {
101 public:
102 virtual auto operator()(const any&) const -> any = 0;
103 virtual auto operator()(const any&, const any&) const -> any = 0;
104 virtual auto operator()(const any&, const any&, const any&) const -> any = 0;
105 };
107 template <typename T>
108 class _closure : public closure {
109 const T lambda;
110 public:
111 _closure(const T& l) noexcept : lambda(l) {}
112 auto operator()(const any& arg) const -> any {
113 return lambda(arg);
114 }
115 auto operator()(const any& arg1, const any& arg2) const -> any {
116 return lambda(arg1)(arg2);
117 }
118 auto operator()(const any& arg1, const any& arg2, const any& arg3) const -> any {
119 return lambda(arg1)(arg2)(arg3);
120 }
121 };
123 template <typename T>
124 class _closure2 : public closure {
125 const T lambda;
126 public:
127 _closure2(const T& l) noexcept : lambda(l) {}
128 auto operator()(const any& arg1) const -> any {
129 return [=](const any& arg2) -> any {
130 return lambda(arg1, arg2);
131 };
132 }
133 auto operator()(const any& arg1, const any& arg2) const -> any {
134 return lambda(arg1, arg2);
135 }
136 auto operator()(const any& arg1, const any& arg2, const any& arg3) const -> any {
137 return lambda(arg1, arg2)(arg3);
138 }
139 };
141 template <typename T>
142 class _closure3 : public closure {
143 const T lambda;
144 public:
145 _closure3(const T& l) noexcept : lambda(l) {}
146 auto operator()(const any& arg1) const -> any {
147 return [=](const any& arg2) -> any {
148 return [=](const any& arg3) -> any {
149 return lambda(arg1, arg2, arg3);
150 };
151 };
152 }
153 auto operator()(const any& arg1, const any& arg2) const -> any {
154 return [=](const any& arg3) -> any {
155 return lambda(arg1, arg2, arg3);
156 };
157 }
158 auto operator()(const any& arg1, const any& arg2, const any& arg3) const -> any {
159 return lambda(arg1, arg2, arg3);
160 }
161 };
163 class eff_fn {
164 public:
165 virtual auto operator()() const -> any = 0;
166 };
168 template <typename T>
169 class _eff_fn : public eff_fn {
170 const T lambda;
171 public:
172 _eff_fn(const T& l) noexcept : lambda(l) {}
173 auto operator()() const -> any {
174 return lambda();
175 }
176 };
178 public:
179 template <typename T>
180 using shared = std::shared_ptr<T>;
182 template <typename T, typename... Args>
183 inline static auto make_shared(Args&&... args) -> decltype(std::make_shared<T>(std::forward<Args>(args)...)) {
184 return std::make_shared<T>(std::forward<Args>(args)...);
185 }
187 private:
188 union {
189 mutable long i;
190 mutable double d;
191 mutable char c;
192 mutable bool b;
193 mutable string r;
194 mutable shared<std::string> s;
195 mutable shared<map> m;
196 mutable shared<data> v;
197 mutable shared<array> a;
198 mutable fn f;
199 mutable shared<closure> l;
200 mutable shared<eff_fn> e;
201 mutable thunk t;
202 mutable shared<void> p;
203 };
205 public:
207 any(const long val) : type(Type::Integer), i(val) {}
208 any(const int val) : type(Type::Integer), i(val) {}
209 any(const unsigned int val) : type(Type::Integer), i(val) {}
210 any(const double val) : type(Type::Double), d(val) {}
211 any(const char val) : type(Type::Character), c(val) {}
213 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
214 any(const T val) : type(Type::Boolean), b(val) {}
216 template <size_t N>
217 any(const char (&val)[N]) : type(Type::StringLiteral), r(val) {}
218 any(char * val) : type(Type::String), s(make_shared<std::string>(val)) {}
220 any(const std::string& val) : type(Type::String), s(make_shared<std::string>(val)) {}
221 any(std::string&& val) : type(Type::String), s(make_shared<std::string>(std::move(val))) {}
223 any(const shared<std::string>& val) : type(Type::String), s(val) {}
224 any(shared<std::string>&& val) noexcept : type(Type::String), s(std::move(val)) {}
226 any(const map& val) : type(Type::Map), m(make_shared<map>(val)) {}
227 any(map&& val) noexcept : type(Type::Map), m(make_shared<map>(std::move(val))) {}
229 any(const data& val) : type(Type::Data), v(make_shared<data>(val)) {}
230 any(data&& val) noexcept : type(Type::Data), v(make_shared<data>(std::move(val))) {}
232 any(const array& val) : type(Type::Array), a(make_shared<array>(val)) {}
233 any(array&& val) noexcept : type(Type::Array), a(make_shared<array>(std::move(val))) {}
235 template <typename T>
236 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0)
237 : type(Type::Function), f(val) {}
239 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
240 !std::is_convertible<T,fn>::value>::type>
241 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
242 : type(Type::Closure), l(make_shared<_closure<T>>(val)) {}
244 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
245 !std::is_convertible<T,fn>::value>::type>
246 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&,
247 const any&)>,T>::value>::type* = 0)
248 : type(Type::Closure), l(make_shared<_closure2<T>>(val)) {}
250 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
251 !std::is_convertible<T,fn>::value>::type>
252 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&,
253 const any&,
254 const any&)>,T>::value>::type* = 0)
255 : type(Type::Closure), l(make_shared<_closure3<T>>(val)) {}
257 template <typename T>
258 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
259 : type(Type::EffFunction), e(make_shared<_eff_fn<T>>(val)) {}
261 template <typename T>
262 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0)
263 : type(Type::Thunk), t(val) {}
265 template <typename T>
266 any(const T& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0)
267 : type(Type::Pointer), p(val) {}
269 template <typename T>
270 any(T&& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0) noexcept
271 : type(Type::Pointer), p(std::move(val)) {}
273 any(std::nullptr_t) : type(Type::Pointer), p(nullptr) {}
275 any(const any&);
276 any(any&&) noexcept;
278 auto operator=(const any&) -> any&;
279 auto operator=(any&) noexcept -> any&;
280 auto operator=(any&&) noexcept -> any&;
282 any() = delete;
283 ~any();
285 template <typename T>
286 auto cast() const -> typename std::enable_if<std::is_same<T, long>::value, T>::type;
288 template <typename T>
289 auto cast() const -> typename std::enable_if<std::is_same<T, double>::value, T>::type;
291 template <typename T>
292 auto cast() const -> typename std::enable_if<std::is_same<T, char>::value, T>::type;
294 template <typename T>
295 auto cast() const -> typename std::enable_if<std::is_same<T, bool>::value, T>::type;
297 template <typename T>
298 auto cast() const -> typename std::enable_if<std::is_same<T, string>::value, T>::type;
300 template <typename T>
301 auto cast() const -> typename std::enable_if<std::is_same<T, map>::value, const T&>::type;
303 template <typename T>
304 auto cast() const -> typename std::enable_if<std::is_same<T, data>::value, const T&>::type;
306 template <typename T>
307 auto cast() const -> typename std::enable_if<std::is_same<T, array>::value, const T&>::type;
309 template <typename T>
310 auto cast() const -> typename std::enable_if<std::is_assignable<shared<void>,T>::value, typename T::element_type*>::type {
311 return static_cast<typename T::element_type*>(extractPointer());
312 }
314 auto operator()(const any&) const -> any;
315 auto operator()(const any&, const any&) const -> any;
316 auto operator()(const any&, const any&, const any&) const -> any;
318 auto operator()(const as_thunk) const -> const any&;
320 auto operator()() const -> any;
322 operator long() const;
323 operator double() const;
324 operator bool() const;
326 operator string() const;
327 operator const map&() const;
328 operator const data&() const;
329 operator const array&() const;
331 auto operator[](const char[]) const -> const any&;
332 auto operator[](const size_t) const -> const any&;
333 auto operator[](const any&) const -> const any&;
335 auto contains(const char[]) const -> bool;
337 auto extractPointer() const -> void*;
339 static auto unthunkVariant(const any&) -> const any&;
341 DECLARE_COMPARISON_OPERATOR(==)
342 DECLARE_COMPARISON_OPERATOR(!=)
343 DECLARE_COMPARISON_OPERATOR(<)
344 DECLARE_COMPARISON_OPERATOR(<=)
345 DECLARE_COMPARISON_OPERATOR(>)
346 DECLARE_COMPARISON_OPERATOR(>=)
348 friend auto operator+(const any&, const any&) -> any;
350 DECLARE_OPERATOR(+, long, long)
351 DECLARE_OPERATOR(+, double, double)
352 DECLARE_OPERATOR(+, char, char)
353 DECLARE_OPERATOR(+, const char *, std::string)
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(*, double, double)
365 DECLARE_OPERATOR(*, char, char)
367 friend auto operator/(const any&, const any&) -> any;
369 DECLARE_OPERATOR(/, long, long)
370 DECLARE_OPERATOR(/, double, double)
371 DECLARE_OPERATOR(/, char, char)
373 friend auto operator%(const any&, const any&) -> any;
375 DECLARE_OPERATOR(%, long, long)
376 DECLARE_OPERATOR(%, char, char)
378 friend auto operator-(const any&) -> any; // unary negate
379};
381} // namespace PureScript
383#undef DECLARE_OPERATOR
384#undef DECLARE_COMPARISON_OPERATOR
386#endif // PureScript_HH