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!
39#include <unordered_map>
42#include <iso646.h> // mostly for MS Visual Studio compiler
43#include "purescript_memory.hh"
47using cstring = const char *;
50using std::runtime_error;
53 struct SymbolGeneratorAnchor {};
56 struct SymbolGenerator {
57 constexpr static SymbolGeneratorAnchor anchor = SymbolGeneratorAnchor{};
60 constexpr SymbolGeneratorAnchor SymbolGenerator<T>::anchor;
62 using Symbol = const SymbolGeneratorAnchor *;
65#define DEFINE_SYMBOL(S) namespace PureScript { \
72#define SYM(S) (&Private::SymbolGenerator<::PureScript::Private::Symbols::S_ ## S>::anchor)
74constexpr bool undefined = false;
76// TODO: Not a real limit, just used for simpler accessors
77static constexpr size_t unknown_size = 64;
79// A variant data class designed to provide some features of dynamic typing.
84 static constexpr auto _managed_ = 0x10;
111 inline static auto isManaged(const Tag tag) -> decltype(_managed_) {
112 return static_cast<decltype(_managed_)>(tag) & _managed_;
114 static_assert(static_cast<decltype(_managed_)>(Tag::Invalid) & _managed_, "outside of range");
119 static constexpr as_thunk unthunk = as_thunk{};
121 using dict_pair = std::pair<const Private::Symbol, const any>;
124 using dict = std::array<const dict_pair, N>;
127 using data = std::array<const any, N>;
129 using array = std::deque<any WITH_ALLOCATOR(any)>;
130 using record = std::unordered_map<std::string, any WITH_ALLOCATOR_PAIR(std::string, any)>;
132 using fn = auto (*)(const any&) -> any;
133 using eff_fn = auto (*)() -> any;
134 using thunk = auto (*)(const as_thunk) -> const any&;
139 virtual auto operator()(const any&) const -> any = 0;
143 template <typename T>
144 class Closure_ : public Closure {
147 Closure_(const T& l) noexcept : lambda(l) {}
148 auto operator()(const any& arg) const -> any override {
155 virtual auto operator()() const -> any = 0;
156 virtual ~EffClosure();
159 template <typename T>
160 class EffClosure_ : public EffClosure {
163 EffClosure_(const T& l) noexcept : lambda(l) {}
164 auto operator()() const -> any override {
180 mutable managed<void> p;
185 any(const int val) noexcept : tag(Tag::Integer), i(val) {}
186 any(const long val) noexcept : tag(Tag::Integer), i(static_cast<decltype(i)>(val)) {
187 assert(val >= std::numeric_limits<decltype(i)>::min() &&
188 val <= std::numeric_limits<decltype(i)>::max());
190 any(const double val) noexcept : tag(Tag::Double), d(val) {}
191 any(const char32_t val) noexcept : tag(Tag::Character), c(val) {}
192 any(const char val) noexcept : tag(Tag::Character), c(val) {}
194 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
195 any(const T val) noexcept : tag(Tag::Boolean), b(val) {}
197 any(const char * val) : tag(Tag::String), p(make_managed_and_finalized<string>(val)) {}
198 any(const string& val) : tag(Tag::String), p(make_managed_and_finalized<string>(val)) {}
199 any(string&& val) noexcept : tag(Tag::String), p(make_managed_and_finalized<string>(std::move(val))) {}
201 any(const managed<string>& val) noexcept : tag(Tag::String), p(val) {}
202 any(managed<string>&& val) noexcept : tag(Tag::String), p(std::move(val)) {}
205 any(dict<N>&& val) noexcept : tag(Tag::Dictionary), p(make_managed<dict<N>>(std::move(val))) {}
208 any(data<N>&& val) noexcept : tag(Tag::Data), p(make_managed<data<N>>(std::move(val))) {}
210 any(const array& val) : tag(Tag::Array), p(make_managed<array>(val)) {}
211 any(array&& val) noexcept : tag(Tag::Array), p(make_managed<array>(std::move(val))) {}
213 any(const record& val) : tag(Tag::Record), p(make_managed<record>(val)) {}
214 any(record&& val) noexcept : tag(Tag::Record), p(make_managed<record>(std::move(val))) {}
216 template <typename T>
217 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0) noexcept
218 : tag(Tag::Function), f(val) {}
220 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
221 !std::is_convertible<T,fn>::value>::type>
222 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
223 : tag(Tag::Closure), p(make_managed<Closure_<T>>(val)) {}
225 template <typename T>
226 any(const T& val, typename std::enable_if<std::is_convertible<T,eff_fn>::value>::type* = 0) noexcept
227 : tag(Tag::EffFunction), e(val) {}
229 template <typename T,
230 typename = typename std::enable_if<!std::is_same<any,T>::value &&
231 !std::is_convertible<T,eff_fn>::value>::type>
232 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
233 : tag(Tag::EffClosure), p(make_managed<EffClosure_<T>>(val)) {}
235 template <typename T>
236 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0) noexcept
237 : tag(Tag::Thunk), t(val) {}
239 template <typename T,
240 typename = typename std::enable_if<std::is_class<typename std::remove_pointer<T>::type>::value>::type>
241 any(const T& val, typename std::enable_if<IS_POINTER_TYPE(T)::value>::type* = 0) noexcept
242 : tag(Tag::Pointer), p(val) {}
244 template <typename T>
245 any(T&& val, typename std::enable_if<std::is_assignable<managed<void>,T>::value>::type* = 0) noexcept
246 : tag(Tag::Pointer), p(std::move(val)) {}
248 // Explicit void* to raw pointer value
249 template <typename T>
250 any(const T& val, typename std::enable_if<std::is_same<T,void*>::value>::type* = 0) noexcept
251 : tag(Tag::RawPointer), v(val) {}
253 any(nullptr_t) noexcept : tag(Tag::RawPointer), v(nullptr) {}
258 auto destruct() const noexcept -> void {
259 if (isManaged(tag)) {
264 static_assert(sizeof(u) >= sizeof(t), "size assumption");
265 static_assert(sizeof(u) >= sizeof(i), "size assumption");
266 static_assert(sizeof(u) >= sizeof(d), "size assumption");
267 static_assert(sizeof(u) >= sizeof(c), "size assumption");
268 static_assert(sizeof(u) >= sizeof(b), "size assumption");
269 static_assert(sizeof(u) >= sizeof(f), "size assumption");
270 static_assert(sizeof(u) >= sizeof(e), "size assumption");
271 static_assert(sizeof(u) >= sizeof(v), "size assumption");
273 auto copyAssign(const any& other) const noexcept -> void {
274 if (isManaged(other.tag)) {
275 new (&p) managed<void>(other.p);
280 auto moveAssign(any& other) const noexcept -> void {
281 if (isManaged(other.tag)) {
282 new (&p) managed<void>(std::move(other.p));
289 any(const any& other) noexcept : tag(other.tag) {
293 any(any&& other) noexcept : tag(other.tag) {
297 auto operator=(const any& rhs) noexcept -> any& {
304 auto operator=(any&& rhs) noexcept -> any& {
314#endif // !defined(USE_GC)
319 auto operator()(const any&) const -> any;
320 auto operator()(const as_thunk) const -> const any&;
321 auto operator()() const -> any;
323 operator int() const;
324 operator double() const;
325 operator bool() const;
326 operator char32_t() const;
327 operator char() const;
328 operator size_t() const;
329 operator const string&() const;
330 operator const char *() const;
331 operator const array&() const;
332 operator const record&() const;
334 auto operator[](const size_t) const -> const any&;
335 auto at(const std::string&) const -> const any&;
336 auto size() const -> size_t;
337 auto empty() const -> bool;
338 auto contains(const Private::Symbol) const -> bool;
340 auto extractPointer(IF_DEBUG(const Tag)) const -> void*;
342 auto rawPointer() const -> void* {
343 const any& variant = unthunkVariant(*this);
344 assert(tag == Tag::RawPointer);
348 static auto unthunkVariant(const any&) -> const any&;
350 #define DEFINE_OPERATOR(op) \
351 template <typename T, \
352 typename = typename std::enable_if<!std::is_same<T,any>::value && \
353 !std::is_same<T,const char *>::value>::type> \
354 inline friend auto operator op (const any& lhs, T rhs) -> T { \
355 return static_cast<typename std::add_lvalue_reference<typename std::add_const<T>::type >::type>(lhs) op rhs; \
357 template <typename T, \
358 typename = typename std::enable_if<!std::is_same<T,any>::value && \
359 !std::is_same<T,const char *>::value>::type> \
360 inline friend auto operator op (T lhs, const any& rhs) -> T { \
361 return lhs op static_cast<typename std::add_lvalue_reference<typename std::add_const<T>::type >::type>(rhs); \
363 friend auto operator op (const any&, const any&) -> any; \
365 #define DEFINE_COMPARISON_OPERATOR(op) \
366 template <typename T, \
367 typename = typename std::enable_if<!std::is_same<T,any>::value && \
368 !std::is_same<T,const char *>::value>::type> \
369 inline friend auto operator op (const any& lhs, T rhs) -> bool { \
370 return static_cast<typename std::add_lvalue_reference<typename std::add_const<T>::type >::type>(lhs) op rhs; \
372 template <typename T, \
373 typename = typename std::enable_if<!std::is_same<T,any>::value && \
374 !std::is_same<T,const char *>::value>::type> \
375 inline friend auto operator op (T lhs, const any& rhs) -> bool { \
376 return lhs op static_cast<typename std::add_lvalue_reference<typename std::add_const<T>::type >::type>(rhs); \
378 inline friend auto operator op (const any& lhs, const char * rhs) -> bool { \
379 return static_cast<const string&>(lhs) op rhs; \
381 inline friend auto operator op (const char * lhs, const any& rhs) -> bool { \
382 return lhs op static_cast<const string&>(rhs); \
384 friend auto operator op (const any&, const any&) -> bool; \
386 DEFINE_COMPARISON_OPERATOR(==)
387 DEFINE_COMPARISON_OPERATOR(!=)
388 DEFINE_COMPARISON_OPERATOR(<)
389 DEFINE_COMPARISON_OPERATOR(<=)
390 DEFINE_COMPARISON_OPERATOR(>)
391 DEFINE_COMPARISON_OPERATOR(>=)
399 inline friend auto operator+(const any& lhs, const char * rhs) -> string {
400 return static_cast<const string&>(lhs) + rhs;
402 inline friend auto operator+(const char * lhs, const any& rhs) -> string {
403 return lhs + static_cast<const string&>(rhs);
406 friend auto operator-(const any&) -> any; // unary negate
411 template <typename T, typename U=void>
415 struct TagHelper<any::dict<N>> {
416 static constexpr any::Tag tag = any::Tag::Dictionary;
420 struct TagHelper<any::data<N>> {
421 static constexpr any::Tag tag = any::Tag::Data;
424 template <typename T>
425 struct TagHelper<T> {
426 static constexpr any::Tag tag = any::Tag::Pointer;
432constexpr auto cast(const T& a) -> const T& {
437inline auto cast(const any& a) ->
438 typename std::enable_if<std::is_arithmetic<T>::value ||
439 std::is_same<T,const char *>::value, T>::type {
444 typename = typename std::enable_if<std::is_class<T>::value>::type>
445inline auto cast(const any& a) -> T& {
446 return *static_cast<T*>(a.extractPointer(IF_DEBUG(Private::TagHelper<T>::tag)));
450 typename = typename std::enable_if<std::is_pointer<T>::value &&
451 !std::is_same<T,void*>::value &&
452 !std::is_same<T,const char *>::value>::type>
453inline auto cast(const any& a) -> T {
454 return static_cast<T>(a.extractPointer(IF_DEBUG(Private::TagHelper<T>::tag)));
458inline auto cast(const any& a) ->
459 typename std::enable_if<std::is_same<void*, T>::value, T>::type {
460 return a.rawPointer();
464 template <size_t N, typename T>
465 inline auto get(const T& a) ->
466 typename std::enable_if<!std::is_same<any, T>::value, const any&>::type {
471 inline auto get(const any& a) -> const any& {
472 return cast<any::dict<N+1>>(a)[N].second;
476 inline auto get(const Private::Symbol key, const any::dict<N>& a) -> const any& {
477 static_assert(N > 0, "dict size must be greater than zero");
478 typename std::remove_reference<decltype(a)>::type::size_type i = 0;
480 if (a[i].first == key) {
483 } while (a[++i].first != nullptr);
484 assert(false && "dict key not found");
485 static const any invalid_key(nullptr);
489 inline auto get(const Private::Symbol key, const any& a) -> const any& {
490 return get(key, cast<any::dict<unknown_size>>(a));
493 #define P(N) any::dict_pair&& arg ## N
494 #define T(N) any::dict<N+1>
495 #define E(N) std::forward<decltype(arg ## N)>(arg ## N)
496 #define M(...) {{ __VA_ARGS__, { nullptr, nullptr } }}
498 inline auto make(P(1)) -> T(1) {
501 inline auto make(P(1), P(2)) -> T(2) {
502 return T(2) M(E(1), E(2));
504 inline auto make(P(1), P(2), P(3)) -> T(3) {
505 return T(3) M(E(1), E(2), E(3));
507 inline auto make(P(1), P(2), P(3), P(4)) -> T(4) {
508 return T(4) M(E(1), E(2), E(3), E(4));
510 inline auto make(P(1), P(2), P(3), P(4), P(5)) -> T(5) {
511 return T(5) M(E(1), E(2), E(3), E(4), E(5));
513 inline auto make(P(1), P(2), P(3), P(4), P(5), P(6)) -> T(6) {
514 return T(6) M(E(1), E(2), E(3), E(4), E(5), E(6));
516 inline auto make(P(1), P(2), P(3), P(4), P(5), P(6), P(7)) -> T(7) {
517 return T(7) M(E(1), E(2), E(3), E(4), E(5), E(6), E(7));
519 inline auto make(P(1), P(2), P(3), P(4), P(5), P(6), P(7), P(8)) -> T(8) {
520 return T(8) M(E(1), E(2), E(3), E(4), E(5), E(6), E(7), E(8));
530 template <size_t N, typename T>
531 inline auto get(const T& a) ->
532 typename std::enable_if<!std::is_same<any, T>::value, const any&>::type {
537 inline auto get(const any& a) -> const any& {
538 return cast<any::data<N+1>>(a)[N];
541 template <typename T>
542 inline auto ctor(const T& a) -> int {
547} // namespace PureScript
550#undef WITH_ALLOCATOR_PAIR
551#undef IS_POINTER_TYPE
552#undef DEFINE_OPERATOR
553#undef DEFINE_COMPARISON_OPERATOR
555#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