git.iko.soy/rowtype-yoga/purescript-native
on b18eb12 help sign in
201 lines 6.7 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(const int n) : std::shared_ptr<void>(std::make_shared<int>(n)) {}
42 boxed(const long n) : std::shared_ptr<void>(std::make_shared<int>(static_cast<int>(n))) {
43#if !defined(NDEBUG) // if debug build
44 if (n < std::numeric_limits<int>::min() || n > std::numeric_limits<int>::max()) {
45 throw std::runtime_error("integer out of range");
46 }
47#endif // !defined(NDEBUG)
48 }
50 boxed(const unsigned long n) : std::shared_ptr<void>(std::make_shared<int>(static_cast<int>(n))) {
51#if !defined(NDEBUG) // if debug build
52 if (n > std::numeric_limits<int>::max()) {
53 throw std::runtime_error("integer out of range");
54 }
55#endif // !defined(NDEBUG)
56 }
58 boxed(const double n) : std::shared_ptr<void>(std::make_shared<double>(n)) {}
59 boxed(const bool b) : std::shared_ptr<void>(std::make_shared<bool>(b)) {}
60 boxed(const char s[]) : std::shared_ptr<void>(std::make_shared<string>(s)) {}
61 boxed(string&& s) : std::shared_ptr<void>(std::make_shared<string>(std::move(s))) {}
62 boxed(const string& s) : std::shared_ptr<void>(std::make_shared<string>(s)) {}
63 boxed(array_t&& l) : std::shared_ptr<void>(std::make_shared<array_t>(std::move(l))) {}
64 boxed(const array_t& l) : std::shared_ptr<void>(std::make_shared<array_t>(l)) {}
65 boxed(dict_t&& m) : std::shared_ptr<void>(std::make_shared<dict_t>(std::move(m))) {}
66 boxed(const dict_t& m) : std::shared_ptr<void>(std::make_shared<dict_t>(m)) {}
68 template <typename T,
69 typename = typename std::enable_if<!std::is_same<boxed,T>::value>::type>
70 boxed(const T& f,
71 typename std::enable_if<std::is_assignable<std::function<boxed(boxed)>,T>::value>::type* = 0)
72 : std::shared_ptr<void>(std::make_shared<fn_t>(f)) {
73 }
75 template <typename T,
76 typename = typename std::enable_if<!std::is_same<boxed,T>::value>::type>
77 boxed(const T& f,
78 typename std::enable_if<std::is_assignable<std::function<boxed(void)>,T>::value>::type* = 0)
79 : std::shared_ptr<void>(std::make_shared<eff_fn_t>(f)) {
80 }
82 auto operator()(const boxed& arg) const -> boxed {
83 auto& f = *static_cast<fn_t*>(get());
84 return f(arg);
85 }
87 auto operator()() const -> boxed {
88 auto& f = *static_cast<eff_fn_t*>(get());
89 return f();
90 }
92 auto operator[](const char key[]) const -> const boxed& {
93 return (*static_cast<const dict_t*>(get()))[key];
94 }
96 auto operator[](const char key[]) -> boxed& {
97 return (*static_cast<dict_t*>(get()))[key];
98 }
100#if !defined(NDEBUG) // if debug build
101 auto operator[](const int index) const -> const boxed& {
102 return static_cast<const array_t*>(get())->at(index);
103 }
105 auto operator[](const int index) -> boxed& {
106 return static_cast<array_t*>(get())->at(index);
107 }
108#else // not debug build
109 auto operator[](const int index) const -> const boxed& {
110 return (*static_cast<const array_t*>(get()))[index];
111 }
113 auto operator[](const int index) -> boxed& {
114 return (*static_cast<array_t*>(get()))[index];
115 }
116#endif // !defined(NDEBUG)
118 }; // class boxed
120 using fn_t = boxed::fn_t;
121 using eff_fn_t = boxed::eff_fn_t;
122 using dict_t = boxed::dict_t;
123 using array_t = boxed::array_t;
125 class boxed_r : private std::shared_ptr<void> {
126 public:
127 boxed_r() : std::shared_ptr<void>(std::make_shared<boxed>()) {}
129 operator const boxed&() const {
130 return *static_cast<const boxed*>(get());
131 }
133 auto operator()(const boxed& arg) const -> boxed {
134 auto& b = *static_cast<boxed*>(get());
135 auto& f = *static_cast<fn_t*>(b.get());
136 return f(arg);
137 }
139 auto operator()() const -> boxed {
140 auto& b = *static_cast<boxed*>(get());
141 auto& f = *static_cast<eff_fn_t*>(b.get());
142 return f();
143 }
145 template <typename T>
146 auto operator=(T&& right) -> boxed_r& {
147 auto& b = *static_cast<boxed*>(get());
148 b = std::forward<T>(right);
149 return *this;
150 }
152 }; // class boxed_r
154 template <typename T, typename... Args>
155 inline auto box(Args&&... args) -> boxed {
156 return std::make_shared<T>(std::forward<Args>(args)...);
157 }
159 template <typename T>
160 constexpr auto unbox(const boxed& b) -> const T& {
161 return *static_cast<const T*>(b.get());
162 }
164 template <typename T>
165 constexpr auto unbox(boxed& b) -> T& {
166 return *static_cast<T*>(b.get());
167 }
169 template <typename T>
170 constexpr auto unbox(const T value) -> T {
171 return value;
172 }
174 template <typename T,
175 typename = typename std::enable_if<std::is_same<T, int>::value>::type>
176 constexpr auto unbox(const std::size_t value) -> long long {
177 return value;
178 }
180 inline auto array_length(const boxed& a) -> boxed::array_t::size_type {
181 return unbox<boxed::array_t>(a).size();
182 }
184 constexpr auto undefined = nullptr;
186} // namespace purescript
188#define DEFINE_FOREIGN_DICTIONARY_AND_ACCESSOR() \
189 inline auto foreign() -> dict_t& {\
190 static dict_t $dict$;\
191 return $dict$;\
192 }
194#define FOREIGN_BEGIN(NS) namespace NS {\
195 using namespace purescript;\
196 DEFINE_FOREIGN_DICTIONARY_AND_ACCESSOR()\
197 static const auto $foreign_exports_init$ = ([]() -> char {\
198 dict_t& exports = foreign();
199#define FOREIGN_END return 0; }()); }
201#endif // purescript_H