git.iko.soy/rowtype-yoga/purescript-native
on 9fd2ad0 help sign in
176 lines 6.2 kB history raw
1///////////////////////////////////////////////////////////////////////////////
2//
3// Module : purescript.h
4// Copyright : (c) Andy Arvanitis 2018
5// License : BSD
6//
7// Maintainer : Andy Arvanitis
8// Stability : experimental
9// Portability :
10//
11// Basic types and functions to support purescript-to-C++ rendering
12//
13///////////////////////////////////////////////////////////////////////////////
14//
15#ifndef purescript_H
16#define purescript_H
18#include <memory>
19#include <functional>
20#include <deque>
21#include <string>
22#include <limits>
23#include "string_literal_dict.h"
26namespace purescript {
28 using std::string;
30 class boxed : public std::shared_ptr<void> {
32 public:
33 using fn_t = std::function<boxed(const boxed&)>;
34 using eff_fn_t = std::function<boxed(void)>;
35 using dict_t = string_literal_dict_t<boxed>;
36 using array_t = std::deque<boxed>;
38 public:
39 using std::shared_ptr<void>::shared_ptr;
41 boxed() noexcept : std::shared_ptr<void>() {}
42 boxed(const std::nullptr_t) noexcept : std::shared_ptr<void>() {}
43 boxed(const int n) : std::shared_ptr<void>(std::make_shared<int>(n)) {}
45 boxed(const long n) : std::shared_ptr<void>(std::make_shared<int>(static_cast<int>(n))) {
46#if !defined(NDEBUG) // if debug build
47 if (n < std::numeric_limits<int>::min() || n > std::numeric_limits<int>::max()) {
48 throw std::runtime_error("integer out of range");
49 }
50#endif // !defined(NDEBUG)
51 }
53 boxed(const double n) : std::shared_ptr<void>(std::make_shared<double>(n)) {}
54 boxed(const bool b) : std::shared_ptr<void>(std::make_shared<bool>(b)) {}
55 boxed(const char s[]) : std::shared_ptr<void>(std::make_shared<string>(s)) {}
56 boxed(string&& s) : std::shared_ptr<void>(std::make_shared<string>(std::move(s))) {}
57 boxed(const string& s) : std::shared_ptr<void>(std::make_shared<string>(s)) {}
58 boxed(array_t&& l) : std::shared_ptr<void>(std::make_shared<array_t>(std::move(l))) {}
59 boxed(const array_t& l) : std::shared_ptr<void>(std::make_shared<array_t>(l)) {}
60 boxed(dict_t&& m) : std::shared_ptr<void>(std::make_shared<dict_t>(std::move(m))) {}
61 boxed(const dict_t& m) : std::shared_ptr<void>(std::make_shared<dict_t>(m)) {}
63 template <typename T,
64 typename = typename std::enable_if<!std::is_same<boxed,T>::value>::type>
65 boxed(const T& f,
66 typename std::enable_if<std::is_assignable<std::function<boxed(boxed)>,T>::value>::type* = 0)
67 : std::shared_ptr<void>(std::make_shared<fn_t>(f)) {
68 }
70 template <typename T,
71 typename = typename std::enable_if<!std::is_same<boxed,T>::value>::type>
72 boxed(const T& f,
73 typename std::enable_if<std::is_assignable<std::function<boxed(void)>,T>::value>::type* = 0)
74 : std::shared_ptr<void>(std::make_shared<eff_fn_t>(f)) {
75 }
77 template <typename T,
78 typename = typename std::enable_if<!std::is_same<boxed,T>::value &&
79 std::is_convertible<T,fn_t>::value>::type>
80 auto operator=(const T& right) -> boxed& {
81 if (std::shared_ptr<void>::operator bool()) {
82 auto& f = *static_cast<fn_t*>(get());
83 f = right;
84 } else {
85 reset(new fn_t(right));
86 }
87 return *this;
88 }
90 auto operator()(const boxed& arg) const -> boxed {
91 auto& f = *static_cast<fn_t*>(get());
92 return f(arg);
93 }
95 auto operator()() const -> boxed {
96 auto& f = *static_cast<eff_fn_t*>(get());
97 return f();
98 }
100 auto operator[](const char key[]) const -> const boxed& {
101 return (*static_cast<const dict_t*>(get()))[key];
102 }
104 auto operator[](const char key[]) -> boxed& {
105 return (*static_cast<dict_t*>(get()))[key];
106 }
108#if !defined(NDEBUG) // if debug build
109 auto operator[](const int index) const -> const boxed& {
110 return static_cast<const array_t*>(get())->at(index);
111 }
113 auto operator[](const int index) -> boxed& {
114 return static_cast<array_t*>(get())->at(index);
115 }
116#else // not debug build
117 auto operator[](const int index) const -> const boxed& {
118 return (*static_cast<const array_t*>(get()))[index];
119 }
121 auto operator[](const int index) -> boxed& {
122 return (*static_cast<array_t*>(get()))[index];
123 }
124#endif // !defined(NDEBUG)
126 }; // class boxed
128 template <typename T, typename... Args>
129 inline auto box(Args&&... args) -> boxed {
130 return std::make_shared<T>(std::forward<Args>(args)...);
131 }
133 template <typename T>
134 constexpr auto unbox(const boxed& b) -> const T& {
135 return *static_cast<const T*>(b.get());
136 }
138 template <typename T,
139 typename = typename std::enable_if<!std::is_same<T, const boxed&>::value>::type>
140 constexpr auto unbox(const T value) -> T {
141 return value;
142 }
144 template <typename T,
145 typename = typename std::enable_if<!std::is_same<T, const boxed&>::value &&
146 std::is_same<T, int>::value>::type>
147 constexpr auto unbox(const std::size_t value) -> long long {
148 return value;
149 }
151 template <typename T>
152 constexpr auto peek(boxed& b) -> T& {
153 return *static_cast<T*>(b.get());
154 }
156 inline auto array_length(const boxed& a) -> boxed::array_t::size_type {
157 return unbox<boxed::array_t>(a).size();
158 }
160 using fn_t = boxed::fn_t;
161 using eff_fn_t = boxed::eff_fn_t;
162 using dict_t = boxed::dict_t;
163 using array_t = boxed::array_t;
165 constexpr auto undefined = nullptr;
167} // namespace purescript
169#define FOREIGN_BEGIN(NS) namespace NS {\
170 using namespace purescript;\
171 auto foreign() -> dict_t&;\
172 static const auto& NS ## $foreign_init = []() {\
173 dict_t& exports = foreign();
174#define FOREIGN_END return exports; }(); }
176#endif // purescript_H