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!
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>;
123 using dict = std::array<const dict_pair, N>;
126 using data = std::array<const any, N>;
128 using array = std::deque<any WITH_ALLOCATOR(any)>;
131 auto operator ()(const char *, const char *) const -> bool;
133 using record = std::map<const char *,
136 WITH_ALLOCATOR_PAIR(char * const, any)>;
138 using fn = auto (*)(const any&) -> any;
139 using eff_fn = auto (*)() -> any;
140 using thunk = auto (*)(const as_thunk) -> const any&;
145 virtual auto operator()(const any&) const -> any = 0;
149 template <typename T>
150 class Closure_ : public Closure {
153 Closure_(const T& l) noexcept : lambda(l) {}
154 auto operator()(const any& arg) const -> any override {
161 virtual auto operator()() const -> any = 0;
162 virtual ~EffClosure();
165 template <typename T>
166 class EffClosure_ : public EffClosure {
169 EffClosure_(const T& l) noexcept : lambda(l) {}
170 auto operator()() const -> any override {
186 mutable managed<void> p;
191 any(const int val) noexcept : tag(Tag::Integer), i(val) {}
192 any(const long val) noexcept : tag(Tag::Integer), i(static_cast<decltype(i)>(val)) {
193 assert(val >= std::numeric_limits<decltype(i)>::min() &&
194 val <= std::numeric_limits<decltype(i)>::max());
196 any(const double val) noexcept : tag(Tag::Double), d(val) {}
197 any(const char32_t val) noexcept : tag(Tag::Character), c(val) {}
198 any(const char val) noexcept : tag(Tag::Character), c(val) {}
200 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
201 any(const T val) noexcept : tag(Tag::Boolean), b(val) {}
203 any(const char * val) : tag(Tag::String), p(make_managed_and_finalized<string>(val)) {}
204 any(const string& val) : tag(Tag::String), p(make_managed_and_finalized<string>(val)) {}
205 any(string&& val) noexcept : tag(Tag::String), p(make_managed_and_finalized<string>(std::move(val))) {}
207 any(const managed<string>& val) noexcept : tag(Tag::String), p(val) {}
208 any(managed<string>&& val) noexcept : tag(Tag::String), p(std::move(val)) {}
211 any(dict<N>&& val) noexcept : tag(Tag::Dictionary), p(make_managed<dict<N>>(std::move(val))) {}
214 any(data<N>&& val) noexcept : tag(Tag::Data), p(make_managed<data<N>>(std::move(val))) {}
216 any(const array& val) : tag(Tag::Array), p(make_managed<array>(val)) {}
217 any(array&& val) noexcept : tag(Tag::Array), p(make_managed<array>(std::move(val))) {}
219 any(const record& val) : tag(Tag::Record), p(make_managed<record>(val)) {}
220 any(record&& val) noexcept : tag(Tag::Record), p(make_managed<record>(std::move(val))) {}
222 template <typename T>
223 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0) noexcept
224 : tag(Tag::Function), f(val) {}
226 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
227 !std::is_convertible<T,fn>::value>::type>
228 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
229 : tag(Tag::Closure), p(make_managed<Closure_<T>>(val)) {}
231 template <typename T>
232 any(const T& val, typename std::enable_if<std::is_convertible<T,eff_fn>::value>::type* = 0) noexcept
233 : tag(Tag::EffFunction), e(val) {}
235 template <typename T,
236 typename = typename std::enable_if<!std::is_same<any,T>::value &&
237 !std::is_convertible<T,eff_fn>::value>::type>
238 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
239 : tag(Tag::EffClosure), p(make_managed<EffClosure_<T>>(val)) {}
241 template <typename T>
242 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0) noexcept
243 : tag(Tag::Thunk), t(val) {}
245 template <typename T,
246 typename = typename std::enable_if<std::is_class<typename std::remove_pointer<T>::type>::value>::type>
247 any(const T& val, typename std::enable_if<IS_POINTER_TYPE(T)::value>::type* = 0) noexcept
248 : tag(Tag::Pointer), p(val) {}
250 template <typename T>
251 any(T&& val, typename std::enable_if<std::is_assignable<managed<void>,T>::value>::type* = 0) noexcept
252 : tag(Tag::Pointer), p(std::move(val)) {}
254 // Explicit void* to raw pointer value
255 template <typename T>
256 any(const T& val, typename std::enable_if<std::is_same<T,void*>::value>::type* = 0) noexcept
257 : tag(Tag::RawPointer), v(val) {}
259 any(nullptr_t) noexcept : tag(Tag::RawPointer), v(nullptr) {}
264 auto destruct() const noexcept -> void {
265 if (isManaged(tag)) {
270 static_assert(sizeof(u) >= sizeof(t), "size assumption");
271 static_assert(sizeof(u) >= sizeof(i), "size assumption");
272 static_assert(sizeof(u) >= sizeof(d), "size assumption");
273 static_assert(sizeof(u) >= sizeof(c), "size assumption");
274 static_assert(sizeof(u) >= sizeof(b), "size assumption");
275 static_assert(sizeof(u) >= sizeof(f), "size assumption");
276 static_assert(sizeof(u) >= sizeof(e), "size assumption");
277 static_assert(sizeof(u) >= sizeof(v), "size assumption");
279 auto copyAssign(const any& other) const noexcept -> void {
280 if (isManaged(other.tag)) {
281 new (&p) managed<void>(other.p);
286 auto moveAssign(any& other) const noexcept -> void {
287 if (isManaged(other.tag)) {
288 new (&p) managed<void>(std::move(other.p));
295 any(const any& other) noexcept : tag(other.tag) {
299 any(any&& other) noexcept : tag(other.tag) {
303 auto operator=(const any& rhs) noexcept -> any& {
310 auto operator=(any&& rhs) noexcept -> any& {
320#endif // !defined(USE_GC)
325 auto operator()(const any&) const -> any;
326 auto operator()(const as_thunk) const -> const any&;
327 auto operator()() const -> any;
329 operator int() const;
330 operator double() const;
331 operator bool() const;
332 operator char32_t() const;
333 operator char() const;
334 operator size_t() const;
335 operator const string&() const;
336 operator const char *() const;
337 operator const array&() const;
338 operator const record&() const;
340 auto operator[](const size_t) const -> const any&;
341 auto at(const char *) const -> const any&;
342 auto size() const -> size_t;
343 auto empty() const -> bool;
344 auto contains(const Private::Symbol) const -> bool;
346 auto extractPointer(IF_DEBUG(const Tag)) const -> void*;
348 auto rawPointer() const -> void* {
349 const any& variant = unthunkVariant(*this);
350 assert(tag == Tag::RawPointer);
354 static auto unthunkVariant(const any&) -> const any&;
356 #define DEFINE_OPERATOR(op) \
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 (const any& lhs, T rhs) -> T { \
361 return static_cast<typename std::add_lvalue_reference<typename std::add_const<T>::type >::type>(lhs) op rhs; \
363 template <typename T, \
364 typename = typename std::enable_if<!std::is_same<T,any>::value && \
365 !std::is_same<T,const char *>::value>::type> \
366 inline friend auto operator op (T lhs, const any& rhs) -> T { \
367 return lhs op static_cast<typename std::add_lvalue_reference<typename std::add_const<T>::type >::type>(rhs); \
369 friend auto operator op (const any&, const any&) -> any; \
371 #define DEFINE_COMPARISON_OPERATOR(op) \
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 (const any& lhs, T rhs) -> bool { \
376 return static_cast<typename std::add_lvalue_reference<typename std::add_const<T>::type >::type>(lhs) op rhs; \
378 template <typename T, \
379 typename = typename std::enable_if<!std::is_same<T,any>::value && \
380 !std::is_same<T,const char *>::value>::type> \
381 inline friend auto operator op (T lhs, const any& rhs) -> bool { \
382 return lhs op static_cast<typename std::add_lvalue_reference<typename std::add_const<T>::type >::type>(rhs); \
384 inline friend auto operator op (const any& lhs, const char * rhs) -> bool { \
385 return static_cast<const string&>(lhs) op rhs; \
387 inline friend auto operator op (const char * lhs, const any& rhs) -> bool { \
388 return lhs op static_cast<const string&>(rhs); \
390 friend auto operator op (const any&, const any&) -> bool; \
392 DEFINE_COMPARISON_OPERATOR(==)
393 DEFINE_COMPARISON_OPERATOR(!=)
394 DEFINE_COMPARISON_OPERATOR(<)
395 DEFINE_COMPARISON_OPERATOR(<=)
396 DEFINE_COMPARISON_OPERATOR(>)
397 DEFINE_COMPARISON_OPERATOR(>=)
405 inline friend auto operator+(const any& lhs, const char * rhs) -> string {
406 return static_cast<const string&>(lhs) + rhs;
408 inline friend auto operator+(const char * lhs, const any& rhs) -> string {
409 return lhs + static_cast<const string&>(rhs);
412 friend auto operator-(const any&) -> any; // unary negate
417 template <typename T, typename U=void>
421 struct TagHelper<string> {
422 static constexpr any::Tag tag = any::Tag::String;
426 struct TagHelper<const char *> {
427 static constexpr any::Tag tag = any::Tag::String;
431 struct TagHelper<any::dict<N>> {
432 static constexpr any::Tag tag = any::Tag::Dictionary;
436 struct TagHelper<any::data<N>> {
437 static constexpr any::Tag tag = any::Tag::Data;
441 struct TagHelper<any::array> {
442 static constexpr any::Tag tag = any::Tag::Array;
446 struct TagHelper<any::record> {
447 static constexpr any::Tag tag = any::Tag::Record;
450 template <typename T>
451 struct TagHelper<T> {
452 static constexpr any::Tag tag = any::Tag::Pointer;
458constexpr auto cast(const T& a) -> const T& {
463inline auto cast(const any& a) ->
464 typename std::enable_if<std::is_arithmetic<T>::value ||
465 std::is_same<T,const char *>::value, T>::type {
470 typename = typename std::enable_if<std::is_class<T>::value>::type>
471inline auto cast(const any& a) -> T& {
472 return *static_cast<T*>(a.extractPointer(IF_DEBUG(Private::TagHelper<T>::tag)));
476 typename = typename std::enable_if<std::is_pointer<T>::value &&
477 !std::is_same<T,void*>::value &&
478 !std::is_same<T,const char *>::value>::type>
479inline auto cast(const any& a) -> T {
480 return static_cast<T>(a.extractPointer(IF_DEBUG(Private::TagHelper<T>::tag)));
484inline auto cast(const any& a) ->
485 typename std::enable_if<std::is_same<void*, T>::value, T>::type {
486 return a.rawPointer();
490 template <size_t N, typename T>
491 inline auto get(const T& a) ->
492 typename std::enable_if<!std::is_same<any, T>::value, const any&>::type {
497 inline auto get(const any& a) -> const any& {
498 return cast<any::dict<N+1>>(a)[N].second;
502 inline auto get(const Private::Symbol key, const any::dict<N>& a) -> const any& {
503 static_assert(N > 0, "dict size must be greater than zero");
504 typename std::remove_reference<decltype(a)>::type::size_type i = 0;
506 if (a[i].first == key) {
509 } while (a[++i].first != nullptr);
510 assert(false && "dict key not found");
511 static const any invalid_key(nullptr);
515 inline auto get(const Private::Symbol key, const any& a) -> const any& {
516 return get(key, cast<any::dict<unknown_size>>(a));
519 #define P(N) any::dict_pair&& arg ## N
520 #define T(N) any::dict<N+1>
521 #define E(N) std::forward<decltype(arg ## N)>(arg ## N)
522 #define M(...) {{ __VA_ARGS__, { nullptr, nullptr } }}
524 inline auto make(P(1)) -> T(1) {
527 inline auto make(P(1), P(2)) -> T(2) {
528 return T(2) M(E(1), E(2));
530 inline auto make(P(1), P(2), P(3)) -> T(3) {
531 return T(3) M(E(1), E(2), E(3));
533 inline auto make(P(1), P(2), P(3), P(4)) -> T(4) {
534 return T(4) M(E(1), E(2), E(3), E(4));
536 inline auto make(P(1), P(2), P(3), P(4), P(5)) -> T(5) {
537 return T(5) M(E(1), E(2), E(3), E(4), E(5));
539 inline auto make(P(1), P(2), P(3), P(4), P(5), P(6)) -> T(6) {
540 return T(6) M(E(1), E(2), E(3), E(4), E(5), E(6));
542 inline auto make(P(1), P(2), P(3), P(4), P(5), P(6), P(7)) -> T(7) {
543 return T(7) M(E(1), E(2), E(3), E(4), E(5), E(6), E(7));
545 inline auto make(P(1), P(2), P(3), P(4), P(5), P(6), P(7), P(8)) -> T(8) {
546 return T(8) M(E(1), E(2), E(3), E(4), E(5), E(6), E(7), E(8));
556 template <size_t N, typename T>
557 inline auto get(const T& a) ->
558 typename std::enable_if<!std::is_same<any, T>::value, const any&>::type {
563 inline auto get(const any& a) -> const any& {
564 return cast<any::data<N+1>>(a)[N];
567 template <typename T>
568 inline auto ctor(const T& a) -> int {
573} // namespace PureScript
576#undef WITH_ALLOCATOR_PAIR
577#undef IS_POINTER_TYPE
578#undef DEFINE_OPERATOR
579#undef DEFINE_COMPARISON_OPERATOR
581#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