1///////////////////////////////////////////////////////////////////////////////
3// Module : purescript.hh
4// Copyright : (c) Andy Arvanitis 2015
7// Maintainer : Andy Arvanitis <andy.arvanitis@gmail.com>
8// Stability : experimental
11// Basic types and functions to support purescript-to-C++1x rendering
13///////////////////////////////////////////////////////////////////////////////
34#include <iso646.h> // mostly for MS Visual Studio compiler
35#include "PureScript_GC.hh"
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 {
46 runtime_error(const char message[]) : std::runtime_error(std::string(message)) {}
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.
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&;
98 virtual auto operator()(const any&) const -> any = 0;
102 template <typename T>
103 class _closure : public closure {
106 _closure(const T& l) noexcept : lambda(l) {}
107 auto operator()(const any& arg) const -> any override {
114 virtual auto operator()() const -> any = 0;
115 virtual ~eff_closure() {}
118 template <typename T>
119 class _eff_closure : public eff_closure {
122 _eff_closure(const T& l) noexcept : lambda(l) {}
123 auto operator()() const -> any override {
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)...);
148 mutable shared<std::string> s;
149 mutable shared<map> m;
150 mutable shared<data> v;
151 mutable shared<array> a;
152 mutable shared<closure> l;
153 mutable shared<eff_closure> k;
154 mutable shared<void> p;
159 any(const integer val) noexcept : type(Type::Integer), i(val) {}
160 any(const int val) noexcept : type(Type::Integer), i(val) {}
161 any(const unsigned int val) noexcept : type(Type::Integer), i(val) {}
162 any(const double val) noexcept : type(Type::Double), d(val) {}
163 any(const char val) noexcept : type(Type::Character), c(val) {}
165 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
166 any(const T val) noexcept : type(Type::Boolean), b(val) {}
169 any(const char (&val)[N]) noexcept : type(Type::StringLiteral), r(val) {}
170 any(char * val) : type(Type::String), s(make_shared<std::string>(val)) {}
172 any(const std::string& val) : type(Type::String), s(make_shared<std::string>(val)) {}
173 any(std::string&& val) noexcept : type(Type::String), s(make_shared<std::string>(std::move(val))) {}
175 any(const shared<std::string>& val) noexcept : type(Type::String), s(val) {}
176 any(shared<std::string>&& val) noexcept : type(Type::String), s(std::move(val)) {}
178 any(const map& val) : type(Type::Map), m(make_shared<map>(val)) {}
179 any(map&& val) noexcept : type(Type::Map), m(make_shared<map>(std::move(val))) {}
181 any(const data& val) : type(Type::Data), v(make_shared<data>(val)) {}
182 any(data&& val) noexcept : type(Type::Data), v(make_shared<data>(std::move(val))) {}
184 any(const array& val) : type(Type::Array), a(make_shared<array>(val)) {}
185 any(array&& val) noexcept : type(Type::Array), a(make_shared<array>(std::move(val))) {}
187 template <typename T>
188 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0) noexcept
189 : type(Type::Function), f(val) {}
191 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
192 !std::is_convertible<T,fn>::value>::type>
193 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
194 : type(Type::Closure), l(make_shared<_closure<T>>(val)) {}
196 template <typename T>
197 any(const T& val, typename std::enable_if<std::is_convertible<T,eff_fn>::value>::type* = 0) noexcept
198 : type(Type::EffFunction), e(val) {}
200 template <typename T,
201 typename = typename std::enable_if<!std::is_same<any,T>::value &&
202 !std::is_convertible<T,eff_fn>::value>::type>
203 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
204 : type(Type::EffClosure), k(make_shared<_eff_closure<T>>(val)) {}
206 template <typename T>
207 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0) noexcept
208 : type(Type::Thunk), t(val) {}
210 template <typename T,
211 typename = typename std::enable_if<std::is_class<typename std::remove_pointer<T>::type>::value>::type>
212 any(const T& val, typename std::enable_if<IS_POINTER_TYPE(T)::value>::type* = 0) noexcept
213 : type(Type::Pointer), p(val) {}
215 template <typename T>
216 any(T&& val, typename std::enable_if<std::is_assignable<shared<void>,T>::value>::type* = 0) noexcept
217 : type(Type::Pointer), p(std::move(val)) {}
219 // Explicit void* to raw pointer value
220 template <typename T>
221 any(const T& val, typename std::enable_if<std::is_same<T,void*>::value>::type* = 0) noexcept
222 : type(Type::RawPointer), u(val) {}
224 any(std::nullptr_t) noexcept : type(Type::Pointer), p(nullptr) {}
229 template <typename T,
231 typename = typename std::enable_if<!std::is_reference<T>::value>::type>
232 static constexpr auto move_if_rvalue(U&& u) noexcept -> U&& {
233 return static_cast<U&&>(u);
236 template <typename T,
238 typename = typename std::enable_if<std::is_reference<T>::value>::type>
239 static constexpr auto move_if_rvalue(U& u) noexcept -> U& {
240 return static_cast<U&>(u);
243 template <typename T>
244 auto assign(T&& other) const noexcept -> void {
245 switch (other.type) {
246 case Type::Thunk: t = other.t; break;
247 case Type::Integer: i = other.i; break;
248 case Type::Double: d = other.d; break;
249 case Type::Character: c = other.c; break;
250 case Type::Boolean: b = other.b; break;
251 case Type::StringLiteral: r = other.r; break;
252 case Type::Function: f = other.f; break;
253 case Type::EffFunction: e = other.e; break;
254 case Type::RawPointer: u = other.u; break;
256 case Type::String: new (&s) shared<std::string>(move_if_rvalue<T>(other.s)); break;
257 case Type::Map: new (&m) shared<map>(move_if_rvalue<T>(other.m)); break;
258 case Type::Data: new (&v) shared<data>(move_if_rvalue<T>(other.v)); break;
259 case Type::Array: new (&a) shared<array>(move_if_rvalue<T>(other.a)); break;
260 case Type::Closure: new (&l) shared<closure>(move_if_rvalue<T>(other.l)); break;
261 case Type::EffClosure: new (&k) shared<eff_closure>(move_if_rvalue<T>(other.k)); break;
262 case Type::Pointer: new (&p) shared<void>(move_if_rvalue<T>(other.p)); break;
264 default: assert(false && "Bad 'any' type"); break;
268 auto destruct() -> void {
270 case Type::String: s.~shared<std::string>(); break;
271 case Type::Map: m.~shared<map>(); break;
272 case Type::Data: v.~shared<data>(); break;
273 case Type::Array: a.~shared<array>(); break;
274 case Type::Closure: l.~shared<closure>(); break;
275 case Type::EffClosure: k.~shared<eff_closure>(); break;
276 case Type::Pointer: p.~shared<void>(); break;
283 any(const any& other) noexcept : type(other.type) {
287 any(any&& other) noexcept : type(other.type) {
288 assign(std::move(other));
291 auto operator=(const any& rhs) noexcept -> any& {
298 auto operator=(any&& rhs) noexcept -> any& {
301 assign(std::move(rhs));
308#endif // !defined(USE_GC)
313 auto operator()(const any&) const -> any;
314 auto operator()(const as_thunk) const -> const any&;
315 auto operator()() const -> any;
317 operator integer() const;
318 operator double() const;
319 operator bool() const;
320 operator char() const;
321 operator cstring() const;
322 operator const map&() const;
323 operator const data&() const;
324 operator const array&() const;
326 auto operator[](const char[]) const -> const any&;
327 auto operator[](const size_t) const -> const any&;
328 auto operator[](const any&) const -> const any&;
330 auto contains(const char[]) const -> bool;
332 auto extractPointer() const -> void*;
334 auto rawPointer() const -> void* {
335 const any& variant = unthunkVariant(*this);
336 assert(type == Type::RawPointer);
340 static auto unthunkVariant(const any&) -> const any&;
342 #define DEFINE_OPERATOR(op, ty, rty) \
343 inline friend auto operator op (const any& lhs, ty rhs) -> rty { \
344 return (ty)lhs op rhs; \
346 inline friend auto operator op (ty lhs, const any& rhs) -> rty { \
347 return lhs op (ty)rhs; \
350 #define DEFINE_INT_OPERATOR(op, rty) \
351 inline friend auto operator op (const any& lhs, int rhs) -> rty { \
352 return (integer)lhs op (integer)rhs; \
354 inline friend auto operator op (int lhs, const any& rhs) -> rty { \
355 return (integer)lhs op (integer)rhs; \
358 #define DECLARE_COMPARISON_OPERATOR(op) \
359 friend auto operator op (const any&, const any&) -> bool; \
360 DEFINE_OPERATOR(op, integer, bool) \
361 DEFINE_OPERATOR(op, double, bool) \
362 DEFINE_OPERATOR(op, char, bool) \
363 DEFINE_INT_OPERATOR(op, bool) \
364 friend auto operator op (const any&, const char * const) -> bool; \
365 friend auto operator op (const char * const, const any&) -> bool;
367 DECLARE_COMPARISON_OPERATOR(==)
368 DECLARE_COMPARISON_OPERATOR(!=)
369 DECLARE_COMPARISON_OPERATOR(<)
370 DECLARE_COMPARISON_OPERATOR(<=)
371 DECLARE_COMPARISON_OPERATOR(>)
372 DECLARE_COMPARISON_OPERATOR(>=)
374 friend auto operator+(const any&, const any&) -> any;
376 DEFINE_OPERATOR(+, integer, integer)
377 DEFINE_OPERATOR(+, double, double)
378 DEFINE_OPERATOR(+, char, char)
379 DEFINE_INT_OPERATOR(+, integer)
380 friend auto operator+(const any& lhs, const char * const rhs) -> std::string;
381 friend auto operator+(const char * const lhs, const any& rhs) -> std::string;
383 friend auto operator-(const any&, const any&) -> any;
385 DEFINE_OPERATOR(-, integer, integer)
386 DEFINE_OPERATOR(-, double, double)
387 DEFINE_OPERATOR(-, char, char)
388 DEFINE_INT_OPERATOR(-, integer)
390 friend auto operator*(const any&, const any&) -> any;
392 DEFINE_OPERATOR(*, integer, integer)
393 DEFINE_OPERATOR(*, double, double)
394 DEFINE_OPERATOR(*, char, char)
395 DEFINE_INT_OPERATOR(*, integer)
397 friend auto operator/(const any&, const any&) -> any;
399 DEFINE_OPERATOR(/, integer, integer)
400 DEFINE_OPERATOR(/, double, double)
401 DEFINE_OPERATOR(/, char, char)
402 DEFINE_INT_OPERATOR(/, integer)
404 friend auto operator%(const any&, const any&) -> any;
406 DEFINE_OPERATOR(%, integer, integer)
407 DEFINE_OPERATOR(%, char, char)
408 DEFINE_INT_OPERATOR(%, integer)
410 friend auto operator-(const any&) -> any; // unary negate
414inline auto cast(const any& a) ->
415 typename std::enable_if<std::is_arithmetic<T>::value ||
416 std::is_same<T,cstring>::value, T>::type {
421inline auto cast(const any& a) ->
422 typename std::enable_if<std::is_same<T, any::map>::value ||
423 std::is_same<T, any::data>::value ||
424 std::is_same<T, any::array>::value, const T&>::type {
428template <typename T, typename = typename std::enable_if<std::is_class<T>::value>::type>
429inline auto cast(const any& a) ->
430 typename std::enable_if<!std::is_same<T, any::map>::value &&
431 !std::is_same<T, any::data>::value &&
432 !std::is_same<T, any::array>::value, T&>::type {
433 return *static_cast<T*>(a.extractPointer());
437inline auto cast(const any& a) ->
438 typename std::enable_if<std::is_same<void*, T>::value, T>::type {
439 return a.rawPointer();
442} // namespace PureScript
447#undef IS_POINTER_TYPE
448#undef DEFINE_OPERATOR
449#undef DEFINE_INT_OPERATOR
450#undef DECLARE_COMPARISON_OPERATOR
452#endif // PureScript_HH
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list