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///////////////////////////////////////////////////////////////////////////////
18#if !defined(__cplusplus)
19#error This is a C++ file!
41#include <iso646.h> // mostly for MS Visual Studio compiler
42#include "purescript_memory.hh"
46using cstring = const char *;
49using std::runtime_error;
52 struct SymbolGeneratorAnchor {};
55 struct SymbolGenerator {
56 constexpr static SymbolGeneratorAnchor anchor = SymbolGeneratorAnchor{};
59 constexpr SymbolGeneratorAnchor SymbolGenerator<T>::anchor;
61 using Symbol = const SymbolGeneratorAnchor *;
64#define define_symbol(S) namespace PureScript { \
71#define symbol(S) (&Private::SymbolGenerator<::PureScript::Private::Symbols::S_ ## S>::anchor)
73constexpr bool undefined = false;
75// TODO: Not a real limit, just used for simpler accessors
76static constexpr size_t unknown_size = 64;
78// A variant data class designed to provide some features of dynamic typing.
108 static constexpr as_thunk unthunk = as_thunk{};
110 using map_pair = std::pair<const Private::Symbol, const any>;
113 using map = std::array<const map_pair, N>;
116 using data = std::array<const any, N>;
118 using array = std::deque<any WITH_ALLOCATOR(any)>;
119 using fn = auto (*)(const any&) -> any;
120 using eff_fn = auto (*)() -> any;
121 using thunk = auto (*)(const as_thunk) -> const any&;
126 virtual auto operator()(const any&) const -> any = 0;
130 template <typename T>
131 class Closure_ : public Closure {
134 Closure_(const T& l) noexcept : lambda(l) {}
135 auto operator()(const any& arg) const -> any override {
142 virtual auto operator()() const -> any = 0;
143 virtual ~EffClosure();
146 template <typename T>
147 class EffClosure_ : public EffClosure {
150 EffClosure_(const T& l) noexcept : lambda(l) {}
151 auto operator()() const -> any override {
167 mutable managed<string> s;
168 mutable managed<array> a;
169 mutable managed<Closure> l;
170 mutable managed<EffClosure> k;
171 mutable managed<void> p;
176 any(const int val) noexcept : tag(Tag::Integer), i(val) {}
177 any(const long val) noexcept : tag(Tag::Integer), i(static_cast<decltype(i)>(val)) {
178 assert(val >= std::numeric_limits<decltype(i)>::min() &&
179 val <= std::numeric_limits<decltype(i)>::max());
182 any(const double val) noexcept : tag(Tag::Double), d(val) {}
183 any(const char val) noexcept : tag(Tag::Character), c(val) {}
185 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
186 any(const T val) noexcept : tag(Tag::Boolean), b(val) {}
189 any(const char (&val)[N]) noexcept : tag(Tag::StringLiteral), r(val) {}
190 any(char * val) : tag(Tag::String), s(make_managed<string>(val)) {}
192 any(const string& val) : tag(Tag::String), s(make_managed<string>(val)) {}
193 any(string&& val) noexcept : tag(Tag::String), s(make_managed<string>(std::move(val))) {}
195 any(const managed<string>& val) noexcept : tag(Tag::String), s(val) {}
196 any(managed<string>&& val) noexcept : tag(Tag::String), s(std::move(val)) {}
199 any(map<N>&& val) noexcept : tag(Tag::Map), p(make_managed<map<N>>(std::move(val))) {}
202 any(data<N>&& val) noexcept : tag(Tag::Data), p(make_managed<data<N>>(std::move(val))) {}
204 any(const array& val) : tag(Tag::Array), a(make_managed<array>(val)) {}
205 any(array&& val) noexcept : tag(Tag::Array), a(make_managed<array>(std::move(val))) {}
207 template <typename T>
208 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0) noexcept
209 : tag(Tag::Function), f(val) {}
211 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
212 !std::is_convertible<T,fn>::value>::type>
213 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
214 : tag(Tag::Closure), l(make_managed<Closure_<T>>(val)) {}
216 template <typename T>
217 any(const T& val, typename std::enable_if<std::is_convertible<T,eff_fn>::value>::type* = 0) noexcept
218 : tag(Tag::EffFunction), e(val) {}
220 template <typename T,
221 typename = typename std::enable_if<!std::is_same<any,T>::value &&
222 !std::is_convertible<T,eff_fn>::value>::type>
223 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
224 : tag(Tag::EffClosure), k(make_managed<EffClosure_<T>>(val)) {}
226 template <typename T>
227 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0) noexcept
228 : tag(Tag::Thunk), t(val) {}
230 template <typename T,
231 typename = typename std::enable_if<std::is_class<typename std::remove_pointer<T>::type>::value>::type>
232 any(const T& val, typename std::enable_if<IS_POINTER_TYPE(T)::value>::type* = 0) noexcept
233 : tag(Tag::Pointer), p(val) {}
235 template <typename T>
236 any(T&& val, typename std::enable_if<std::is_assignable<managed<void>,T>::value>::type* = 0) noexcept
237 : tag(Tag::Pointer), p(std::move(val)) {}
239 // Explicit void* to raw pointer value
240 template <typename T>
241 any(const T& val, typename std::enable_if<std::is_same<T,void*>::value>::type* = 0) noexcept
242 : tag(Tag::RawPointer), u(val) {}
244 any(nullptr_t) noexcept : tag(Tag::RawPointer), u(nullptr) {}
249 template <typename T,
251 typename = typename std::enable_if<!std::is_reference<T>::value>::type>
252 static constexpr auto move_if_rvalue(U&& u) noexcept -> U&& {
253 return static_cast<U&&>(u);
256 template <typename T,
258 typename = typename std::enable_if<std::is_reference<T>::value>::type>
259 static constexpr auto move_if_rvalue(U& u) noexcept -> U& {
260 return static_cast<U&>(u);
263 template <typename T>
264 auto assign(T&& other) const noexcept -> void {
266 case Tag::Thunk: t = other.t; break;
267 case Tag::Integer: i = other.i; break;
268 case Tag::Double: d = other.d; break;
269 case Tag::Character: c = other.c; break;
270 case Tag::Boolean: b = other.b; break;
271 case Tag::StringLiteral: r = other.r; break;
272 case Tag::Function: f = other.f; break;
273 case Tag::EffFunction: e = other.e; break;
274 case Tag::RawPointer: u = other.u; break;
276 case Tag::String: new (&s) managed<string>(move_if_rvalue<T>(other.s)); break;
277 case Tag::Array: new (&a) managed<array>(move_if_rvalue<T>(other.a)); break;
278 case Tag::Closure: new (&l) managed<Closure>(move_if_rvalue<T>(other.l)); break;
279 case Tag::EffClosure: new (&k) managed<EffClosure>(move_if_rvalue<T>(other.k)); break;
282 case Tag::Pointer: new (&p) managed<void>(move_if_rvalue<T>(other.p)); break;
284 default: assert(false && "Bad 'any' tag"); break;
288 auto destruct() -> void {
290 case Tag::String: s.~managed<string>(); break;
291 case Tag::Array: a.~managed<array>(); break;
292 case Tag::Closure: l.~managed<Closure>(); break;
293 case Tag::EffClosure: k.~managed<EffClosure>(); break;
296 case Tag::Pointer: p.~managed<void>(); break;
303 any(const any& other) noexcept : tag(other.tag) {
307 any(any&& other) noexcept : tag(other.tag) {
308 assign(std::move(other));
311 auto operator=(const any& rhs) noexcept -> any& {
318 auto operator=(any&& rhs) noexcept -> any& {
321 assign(std::move(rhs));
328#endif // !defined(USE_GC)
333 auto operator()(const any&) const -> any;
334 auto operator()(const as_thunk) const -> const any&;
335 auto operator()() const -> any;
337 operator int() const;
338 operator double() const;
339 operator bool() const;
340 operator char() const;
341 operator size_t() const;
342 operator cstring() const;
343 operator const array&() const;
345 auto operator[](const size_t) const -> const any&;
347 auto size() const -> size_t;
348 auto empty() const -> bool;
349 auto contains(const Private::Symbol) const -> bool;
351 auto extractPointer(IF_DEBUG(const Tag)) const -> void*;
353 auto rawPointer() const -> void* {
354 const any& variant = unthunkVariant(*this);
355 assert(tag == Tag::RawPointer);
359 static auto unthunkVariant(const any&) -> const any&;
361 #define DEFINE_OPERATOR(op, ty, rty) \
362 inline friend auto operator op (const any& lhs, ty rhs) -> rty { \
363 return (ty)lhs op rhs; \
365 inline friend auto operator op (ty lhs, const any& rhs) -> rty { \
366 return lhs op (ty)rhs; \
369 #define DECLARE_COMPARISON_OPERATOR(op) \
370 friend auto operator op (const any&, const any&) -> bool; \
371 DEFINE_OPERATOR(op, int, bool) \
372 DEFINE_OPERATOR(op, double, bool) \
373 DEFINE_OPERATOR(op, char, bool) \
374 DEFINE_OPERATOR(op, bool, bool) \
375 friend auto operator op (const any&, const char * const) -> bool; \
376 friend auto operator op (const char * const, const any&) -> bool;
378 DECLARE_COMPARISON_OPERATOR(==)
379 DECLARE_COMPARISON_OPERATOR(!=)
380 DECLARE_COMPARISON_OPERATOR(<)
381 DECLARE_COMPARISON_OPERATOR(<=)
382 DECLARE_COMPARISON_OPERATOR(>)
383 DECLARE_COMPARISON_OPERATOR(>=)
385 friend auto operator+(const any&, const any&) -> any;
387 DEFINE_OPERATOR(+, int, int)
388 DEFINE_OPERATOR(+, double, double)
389 DEFINE_OPERATOR(+, char, char)
390 friend auto operator+(const any& lhs, const char * const rhs) -> string;
391 friend auto operator+(const char * const lhs, const any& rhs) -> string;
393 friend auto operator-(const any&, const any&) -> any;
395 DEFINE_OPERATOR(-, int, int)
396 DEFINE_OPERATOR(-, double, double)
397 DEFINE_OPERATOR(-, char, char)
399 friend auto operator*(const any&, const any&) -> any;
401 DEFINE_OPERATOR(*, int, int)
402 DEFINE_OPERATOR(*, double, double)
403 DEFINE_OPERATOR(*, char, char)
405 friend auto operator/(const any&, const any&) -> any;
407 DEFINE_OPERATOR(/, int, int)
408 DEFINE_OPERATOR(/, double, double)
409 DEFINE_OPERATOR(/, char, char)
411 friend auto operator%(const any&, const any&) -> any;
413 DEFINE_OPERATOR(%, int, int)
414 DEFINE_OPERATOR(%, char, char)
416 friend auto operator-(const any&) -> any; // unary negate
421 template <typename T, typename U=void>
425 struct TagHelper<any::map<N>> {
426 static constexpr any::Tag tag = any::Tag::Map;
430 struct TagHelper<any::data<N>> {
431 static constexpr any::Tag tag = any::Tag::Data;
434 template <typename T>
435 struct TagHelper<T> {
436 static constexpr any::Tag tag = any::Tag::Pointer;
442constexpr auto cast(const T& a) -> const T& {
447inline auto cast(const any& a) ->
448 typename std::enable_if<std::is_arithmetic<T>::value ||
449 std::is_same<T,cstring>::value, T>::type {
454inline auto cast(const any& a) ->
455 typename std::enable_if<std::is_same<T, any::array>::value, const T&>::type {
459template <typename T, typename = typename std::enable_if<std::is_class<T>::value>::type>
460inline auto cast(const any& a) ->
461 typename std::enable_if<!std::is_same<T, any::array>::value, T&>::type {
462 return *static_cast<T*>(a.extractPointer(IF_DEBUG(Private::TagHelper<T>::tag)));
466 typename = typename std::enable_if<std::is_pointer<T>::value &&
467 !std::is_same<T,void*>::value &&
468 !std::is_same<T,cstring>::value>::type>
469inline auto cast(const any& a) -> T {
470 return static_cast<T>(a.extractPointer(IF_DEBUG(Private::TagHelper<T>::tag)));
474inline auto cast(const any& a) ->
475 typename std::enable_if<std::is_same<void*, T>::value, T>::type {
476 return a.rawPointer();
480 template <size_t N, typename T>
481 inline auto get(const T& a) ->
482 typename std::enable_if<!std::is_same<any, T>::value, const any&>::type {
487 inline auto get(const any& a) -> const any& {
488 return cast<any::map<N+1>>(a)[N].second;
492 inline auto get(const Private::Symbol key, const any::map<N>& a) -> const any& {
493 static_assert(N > 0, "map size must be greater than zero");
494 typename std::remove_reference<decltype(a)>::type::size_type i = 0;
496 if (a[i].first == key) {
499 } while (a[++i].first != nullptr);
500 assert(false && "map key not found");
501 static const any invalid_key(nullptr);
505 inline auto get(const Private::Symbol key, const any& a) -> const any& {
506 return get(key, cast<any::map<unknown_size>>(a));
509 #define P(N) any::map_pair&& arg ## N
510 #define T(N) any::map<N+1>
511 #define E(N) std::forward<decltype(arg ## N)>(arg ## N)
512 #define M(...) {{ __VA_ARGS__, { nullptr, nullptr } }}
514 inline auto make(P(1)) -> T(1) {
517 inline auto make(P(1), P(2)) -> T(2) {
518 return T(2) M(E(1), E(2));
520 inline auto make(P(1), P(2), P(3)) -> T(3) {
521 return T(3) M(E(1), E(2), E(3));
523 inline auto make(P(1), P(2), P(3), P(4)) -> T(4) {
524 return T(4) M(E(1), E(2), E(3), E(4));
526 inline auto make(P(1), P(2), P(3), P(4), P(5)) -> T(5) {
527 return T(5) M(E(1), E(2), E(3), E(4), E(5));
529 inline auto make(P(1), P(2), P(3), P(4), P(5), P(6)) -> T(6) {
530 return T(6) M(E(1), E(2), E(3), E(4), E(5), E(6));
532 inline auto make(P(1), P(2), P(3), P(4), P(5), P(6), P(7)) -> T(7) {
533 return T(7) M(E(1), E(2), E(3), E(4), E(5), E(6), E(7));
535 inline auto make(P(1), P(2), P(3), P(4), P(5), P(6), P(7), P(8)) -> T(8) {
536 return T(8) M(E(1), E(2), E(3), E(4), E(5), E(6), E(7), E(8));
545namespace record = map;
548 template <size_t N, typename T>
549 inline auto get(const T& a) ->
550 typename std::enable_if<!std::is_same<any, T>::value, const any&>::type {
555 inline auto get(const any& a) -> const any& {
556 return cast<any::data<N+1>>(a)[N];
559 template <typename T>
560 inline auto ctor(const T& a) -> int {
565} // namespace PureScript
568#undef IS_POINTER_TYPE
569#undef DEFINE_OPERATOR
570#undef DECLARE_COMPARISON_OPERATOR
572#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