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///////////////////////////////////////////////////////////////////////////////
37#include <iso646.h> // mostly for MS Visual Studio compiler
38#include "purescript_memory.hh"
42using cstring = const char *;
45struct symbol_generator_anchor {};
46using symbol_t = const symbol_generator_anchor *;
49struct symbol_generator {
50 constexpr static symbol_generator_anchor anchor = symbol_generator_anchor{};
53constexpr symbol_generator_anchor symbol_generator<T>::anchor;
55#define SYMBOL(S) &symbol_generator<symbol::S>::anchor
57// Workaround for missing C++11 version in gcc
58class runtime_error : public std::runtime_error {
60 runtime_error(const char message[]) : std::runtime_error(std::string(message)) {}
63constexpr bool undefined = false;
64constexpr size_t constructor = 0;
66// Not a real limit, just used for simpler accessors
67static constexpr size_t unknown_size = 64;
69// A variant data class designed to provide some features of dynamic typing.
99 static constexpr as_thunk unthunk = as_thunk{};
101 using map_pair = std::pair<const symbol_t, const any>;
104 using map = std::array<const map_pair, N>;
107 using data = std::array<const any, N>;
109 using array = std::deque<any WITH_ALLOCATOR(any)>;
110 using fn = auto (*)(const any&) -> any;
111 using eff_fn = auto (*)() -> any;
112 using thunk = auto (*)(const as_thunk) -> const any&;
117 virtual auto operator()(const any&) const -> any = 0;
118 virtual ~closure() {}
121 template <typename T>
122 class _closure : public closure {
125 _closure(const T& l) noexcept : lambda(l) {}
126 auto operator()(const any& arg) const -> any override {
133 virtual auto operator()() const -> any = 0;
134 virtual ~eff_closure() {}
137 template <typename T>
138 class _eff_closure : public eff_closure {
141 _eff_closure(const T& l) noexcept : lambda(l) {}
142 auto operator()() const -> any override {
158 mutable managed<std::string> s;
159 mutable managed<array> a;
160 mutable managed<closure> l;
161 mutable managed<eff_closure> k;
162 mutable managed<void> p;
167 any(const int val) noexcept : type(Type::Integer), i(val) {}
168 any(const long int_value) noexcept : type(Type::Integer), i(int_value) {
169 assert(int_value >= INT_MIN && int_value <= INT_MAX);
172 any(const double val) noexcept : type(Type::Double), d(val) {}
173 any(const char val) noexcept : type(Type::Character), c(val) {}
175 template <typename T, typename = typename std::enable_if<std::is_same<bool,T>::value>::type>
176 any(const T val) noexcept : type(Type::Boolean), b(val) {}
179 any(const char (&val)[N]) noexcept : type(Type::StringLiteral), r(val) {}
180 any(char * val) : type(Type::String), s(make_managed<std::string>(val)) {}
182 any(const std::string& val) : type(Type::String), s(make_managed<std::string>(val)) {}
183 any(std::string&& val) noexcept : type(Type::String), s(make_managed<std::string>(std::move(val))) {}
185 any(const managed<std::string>& val) noexcept : type(Type::String), s(val) {}
186 any(managed<std::string>&& val) noexcept : type(Type::String), s(std::move(val)) {}
189 any(map<N>&& val) noexcept : type(Type::Map), p(make_managed<map<N>>(std::move(val))) {}
192 any(data<N>&& val) noexcept : type(Type::Data), p(make_managed<data<N>>(std::move(val))) {}
194 any(const array& val) : type(Type::Array), a(make_managed<array>(val)) {}
195 any(array&& val) noexcept : type(Type::Array), a(make_managed<array>(std::move(val))) {}
197 template <typename T>
198 any(const T& val, typename std::enable_if<std::is_convertible<T,fn>::value>::type* = 0) noexcept
199 : type(Type::Function), f(val) {}
201 template <typename T, typename = typename std::enable_if<!std::is_same<any,T>::value &&
202 !std::is_convertible<T,fn>::value>::type>
203 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any(const any&)>,T>::value>::type* = 0)
204 : type(Type::Closure), l(make_managed<_closure<T>>(val)) {}
206 template <typename T>
207 any(const T& val, typename std::enable_if<std::is_convertible<T,eff_fn>::value>::type* = 0) noexcept
208 : type(Type::EffFunction), e(val) {}
210 template <typename T,
211 typename = typename std::enable_if<!std::is_same<any,T>::value &&
212 !std::is_convertible<T,eff_fn>::value>::type>
213 any(const T& val, typename std::enable_if<std::is_assignable<std::function<any()>,T>::value>::type* = 0)
214 : type(Type::EffClosure), k(make_managed<_eff_closure<T>>(val)) {}
216 template <typename T>
217 any(const T& val, typename std::enable_if<std::is_convertible<T,thunk>::value>::type* = 0) noexcept
218 : type(Type::Thunk), t(val) {}
220 template <typename T,
221 typename = typename std::enable_if<std::is_class<typename std::remove_pointer<T>::type>::value>::type>
222 any(const T& val, typename std::enable_if<IS_POINTER_TYPE(T)::value>::type* = 0) noexcept
223 : type(Type::Pointer), p(val) {}
225 template <typename T>
226 any(T&& val, typename std::enable_if<std::is_assignable<managed<void>,T>::value>::type* = 0) noexcept
227 : type(Type::Pointer), p(std::move(val)) {}
229 // Explicit void* to raw pointer value
230 template <typename T>
231 any(const T& val, typename std::enable_if<std::is_same<T,void*>::value>::type* = 0) noexcept
232 : type(Type::RawPointer), u(val) {}
234 any(nullptr_t) noexcept : type(Type::RawPointer), u(nullptr) {}
239 template <typename T,
241 typename = typename std::enable_if<!std::is_reference<T>::value>::type>
242 static constexpr auto move_if_rvalue(U&& u) noexcept -> U&& {
243 return static_cast<U&&>(u);
246 template <typename T,
248 typename = typename std::enable_if<std::is_reference<T>::value>::type>
249 static constexpr auto move_if_rvalue(U& u) noexcept -> U& {
250 return static_cast<U&>(u);
253 template <typename T>
254 auto assign(T&& other) const noexcept -> void {
255 switch (other.type) {
256 case Type::Thunk: t = other.t; break;
257 case Type::Integer: i = other.i; break;
258 case Type::Double: d = other.d; break;
259 case Type::Character: c = other.c; break;
260 case Type::Boolean: b = other.b; break;
261 case Type::StringLiteral: r = other.r; break;
262 case Type::Function: f = other.f; break;
263 case Type::EffFunction: e = other.e; break;
264 case Type::RawPointer: u = other.u; break;
266 case Type::String: new (&s) managed<std::string>(move_if_rvalue<T>(other.s)); break;
267 case Type::Array: new (&a) managed<array>(move_if_rvalue<T>(other.a)); break;
268 case Type::Closure: new (&l) managed<closure>(move_if_rvalue<T>(other.l)); break;
269 case Type::EffClosure: new (&k) managed<eff_closure>(move_if_rvalue<T>(other.k)); break;
272 case Type::Pointer: new (&p) managed<void>(move_if_rvalue<T>(other.p)); break;
274 default: assert(false && "Bad 'any' type"); break;
278 auto destruct() -> void {
280 case Type::String: s.~managed<std::string>(); break;
281 case Type::Array: a.~managed<array>(); break;
282 case Type::Closure: l.~managed<closure>(); break;
283 case Type::EffClosure: k.~managed<eff_closure>(); break;
286 case Type::Pointer: p.~managed<void>(); break;
293 any(const any& other) noexcept : type(other.type) {
297 any(any&& other) noexcept : type(other.type) {
298 assign(std::move(other));
301 auto operator=(const any& rhs) noexcept -> any& {
308 auto operator=(any&& rhs) noexcept -> any& {
311 assign(std::move(rhs));
318#endif // !defined(USE_GC)
323 auto operator()(const any&) const -> any;
324 auto operator()(const as_thunk) const -> const any&;
325 auto operator()() const -> any;
327 operator int() const;
328 operator double() const;
329 operator bool() const;
330 operator char() const;
331 operator cstring() const;
332 operator const array&() const;
334 auto operator[](const symbol_t) const -> const any&;
335 auto operator[](const size_t) const -> const any&;
336 auto operator[](const any&) const -> const any&;
338 auto contains(const symbol_t) const -> bool;
340 auto extractPointer(IF_DEBUG(const Type)) const -> void*;
342 auto rawPointer() const -> void* {
343 const any& variant = unthunkVariant(*this);
344 assert(type == Type::RawPointer);
348 static auto unthunkVariant(const any&) -> const any&;
350 #define DEFINE_OPERATOR(op, ty, rty) \
351 inline friend auto operator op (const any& lhs, ty rhs) -> rty { \
352 return (ty)lhs op rhs; \
354 inline friend auto operator op (ty lhs, const any& rhs) -> rty { \
355 return lhs op (ty)rhs; \
358 #define DECLARE_COMPARISON_OPERATOR(op) \
359 friend auto operator op (const any&, const any&) -> bool; \
360 DEFINE_OPERATOR(op, int, bool) \
361 DEFINE_OPERATOR(op, double, bool) \
362 DEFINE_OPERATOR(op, char, bool) \
363 DEFINE_OPERATOR(op, bool, 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(+, int, int)
377 DEFINE_OPERATOR(+, double, double)
378 DEFINE_OPERATOR(+, char, char)
379 friend auto operator+(const any& lhs, const char * const rhs) -> std::string;
380 friend auto operator+(const char * const lhs, const any& rhs) -> std::string;
382 friend auto operator-(const any&, const any&) -> any;
384 DEFINE_OPERATOR(-, int, int)
385 DEFINE_OPERATOR(-, double, double)
386 DEFINE_OPERATOR(-, char, char)
388 friend auto operator*(const any&, const any&) -> any;
390 DEFINE_OPERATOR(*, int, int)
391 DEFINE_OPERATOR(*, double, double)
392 DEFINE_OPERATOR(*, char, char)
394 friend auto operator/(const any&, const any&) -> any;
396 DEFINE_OPERATOR(/, int, int)
397 DEFINE_OPERATOR(/, double, double)
398 DEFINE_OPERATOR(/, char, char)
400 friend auto operator%(const any&, const any&) -> any;
402 DEFINE_OPERATOR(%, int, int)
403 DEFINE_OPERATOR(%, char, char)
405 friend auto operator-(const any&) -> any; // unary negate
409template <typename T, typename U=void>
413struct tag_helper<any::map<N>> {
414 static constexpr any::Type tag = any::Type::Map;
418struct tag_helper<any::data<N>> {
419 static constexpr any::Type tag = any::Type::Data;
423struct tag_helper<T> {
424 static constexpr any::Type tag = any::Type::Pointer;
428inline auto cast(const any& a) ->
429 typename std::enable_if<std::is_arithmetic<T>::value ||
430 std::is_same<T,cstring>::value, T>::type {
435inline auto cast(const any& a) ->
436 typename std::enable_if<std::is_same<T, any::array>::value, const T&>::type {
440template <typename T, typename = typename std::enable_if<std::is_class<T>::value>::type>
441inline auto cast(const any& a) ->
442 typename std::enable_if<!std::is_same<T, any::array>::value, T&>::type {
443 return *static_cast<T*>(a.extractPointer(IF_DEBUG(tag_helper<T>::tag)));
447inline auto cast(const any& a) ->
448 typename std::enable_if<std::is_same<void*, T>::value, T>::type {
449 return a.rawPointer();
452} // namespace PureScript
455#undef IS_POINTER_TYPE
456#undef DEFINE_OPERATOR
457#undef DECLARE_COMPARISON_OPERATOR
459#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