git.iko.soy/rowtype-yoga/purescript-native
on fa9c565 help sign in
307 lines 11 kB history raw
1///////////////////////////////////////////////////////////////////////////////
2//
3// Module : purescript.cc
4// Copyright : (c) Andy Arvanitis 2015
5// License : MIT
6//
7// Maintainer : Andy Arvanitis <andy.arvanitis@gmail.com>
8// Stability : experimental
9// Portability :
10//
11// Basic types and functions to support purescript-to-C++1x rendering
12//
13///////////////////////////////////////////////////////////////////////////////
14//
15#include <cstring>
16#include "PureScript.hh"
18namespace PureScript {
20#define RETURN_VALUE(TYPE, ACCESSOR, INDIRECTION) \
21 const any& variant = unthunkVariant(*this); \
22 assert(variant.type == TYPE); \
23 return INDIRECTION(variant.ACCESSOR); \
25auto any::operator()(const any& arg) const -> any {
26 const any& variant = unthunkVariant(*this);
27 if (variant.type == Type::Closure) {
28 return (*variant.l)(arg);
29 }
30 assert(variant.type == Type::Function);
31 return (*variant.f)(arg);
34auto any::operator()(const as_thunk) const -> const any& {
35 assert(type == Type::Thunk);
36 return (*t)(unthunk);
39auto any::operator()() const -> any {
40 const any& variant = unthunkVariant(*this);
41 assert(variant.type == Type::EffFunction);
42 return (*variant.e)();
45any::operator long() const {
46 RETURN_VALUE(Type::Integer, i,)
49any::operator double() const {
50 RETURN_VALUE(Type::Double, d,)
53any::operator bool() const {
54 RETURN_VALUE(Type::Boolean, b,)
57any::operator char() const {
58 RETURN_VALUE(Type::Character, c,)
61any::operator cstring() const {
62 const any& variant = unthunkVariant(*this);
63 if (variant.type == Type::StringLiteral) {
64 return variant.r;
65 }
66 assert(variant.type == Type::String);
67 return variant.s->c_str();
70any::operator const map&() const {
71 RETURN_VALUE(Type::Map, m, *)
74any::operator const data&() const {
75 RETURN_VALUE(Type::Data, v, *)
78any::operator const array&() const {
79 RETURN_VALUE(Type::Array, a, *)
82auto any::extractPointer() const -> void* {
83 RETURN_VALUE(Type::Pointer, p.get(),)
86auto any::unthunkVariant(const any& a) -> const any& {
87 const any * variant = &a;
88 while (variant->type == Type::Thunk) {
89 variant = &((*variant->t)(unthunk));
90 }
91 return *variant;
94auto any::operator[](const char rhs[]) const -> const any& {
95 const any& variant = unthunkVariant(*this);
96 assert(variant.type == Type::Map);
97 const auto begin = variant.m->cbegin();
98 const auto end = variant.m->cend();
99 for (auto it = begin; it != end; ++it) {
100 if (it->first == rhs) {
101 return it->second;
102 }
103 }
104 for (auto it = begin; it != end; ++it) {
105 if (strcmp(it->first, rhs) == 0) {
106 return it->second;
107 }
108 }
109 throw runtime_error("map key not found");
112auto any::operator[](const size_t rhs) const -> const any& {
113 const any& variant = unthunkVariant(*this);
114 assert(variant.type == Type::Array);
115 return (*variant.a)[rhs];
118auto any::operator[](const any& rhs) const -> const any& {
119 const any& variant = unthunkVariant(*this);
120 assert(variant.type == Type::Array);
121 return (*variant.a)[cast<long>(rhs)];
124auto any::contains(const char key[]) const -> bool {
125 const any& variant = unthunkVariant(*this);
126 assert(variant.type == Type::Map);
127 const auto begin = variant.m->cbegin();
128 const auto end = variant.m->cend();
129 for (auto it = begin; it != end; ++it) {
130 if (it->first == key) {
131 return true;
132 }
133 }
134 for (auto it = begin; it != end; ++it) {
135 if (strcmp(it->first, key) == 0) {
136 return true;
137 }
138 }
139 return false;
142//-----------------------------------------------------------------------------
143// Operator helper macros
144//-----------------------------------------------------------------------------
146#define DEFINE_CSTR_EQUALS_OPERATOR() \
147 auto operator==(const any& lhs_, const char * rhs) -> bool { \
148 const any& lhs = any::unthunkVariant(lhs_); \
149 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
150 if (lhs.type == any::Type::StringLiteral) { \
151 return (lhs.r == rhs) || (strcmp(lhs.r, rhs) == 0); \
152 } \
153 return strcmp(lhs.s->c_str(), rhs) == 0; \
154 } \
155 auto operator==(const char * lhs, const any& rhs_) -> bool { \
156 const any& rhs = any::unthunkVariant(rhs_); \
157 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
158 if (rhs.type == any::Type::StringLiteral) { \
159 return (lhs == rhs.r) || (strcmp(lhs, rhs) == 0); \
160 } \
161 return strcmp(lhs, rhs.s->c_str()) == 0; \
162 }
164#define DEFINE_CSTR_COMPARISON_OPERATOR(op) \
165 auto operator op (const any& lhs, const char * rhs) -> bool { \
166 return strcmp(cast<cstring>(lhs), rhs) op 0; \
167 } \
168 auto operator op (const char * lhs, const any& rhs) -> bool { \
169 return strcmp(lhs, cast<cstring>(rhs)) op 0; \
170 }
172#define DEFINE_COMPARISON_OPERATOR(op) \
173 auto operator op (const any& lhs_, const any& rhs_) -> bool { \
174 const any& lhs = any::unthunkVariant(lhs_); \
175 const any& rhs = any::unthunkVariant(rhs_); \
176 switch (lhs.type) { \
177 case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i op rhs.i; \
178 case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d op rhs.d; \
179 case any::Type::Character: assert(lhs.type == any::Type::Character); return lhs.c op rhs.c; \
180 case any::Type::Boolean: assert(lhs.type == any::Type::Boolean); return lhs.b op rhs.b; \
181 case any::Type::StringLiteral: \
182 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
183 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
184 return strcmp(lhs.r, rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
185 case any::Type::String: \
186 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
187 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
188 return strcmp(lhs.s->c_str(), rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
189 case any::Type::Pointer: return lhs.p op rhs.p; \
190 default: assert(false && "Unsupported type for operator " #op); \
191 } \
192 return false; \
193 }
195//-----------------------------------------------------------------------------
196// Operator definitions
197//-----------------------------------------------------------------------------
199DEFINE_COMPARISON_OPERATOR(==)
200DEFINE_COMPARISON_OPERATOR(!=)
201DEFINE_COMPARISON_OPERATOR(<)
202DEFINE_COMPARISON_OPERATOR(<=)
203DEFINE_COMPARISON_OPERATOR(>)
204DEFINE_COMPARISON_OPERATOR(>=)
206DEFINE_CSTR_EQUALS_OPERATOR()
207DEFINE_CSTR_COMPARISON_OPERATOR(!=)
208DEFINE_CSTR_COMPARISON_OPERATOR(<)
209DEFINE_CSTR_COMPARISON_OPERATOR(<=)
210DEFINE_CSTR_COMPARISON_OPERATOR(>)
211DEFINE_CSTR_COMPARISON_OPERATOR(>=)
213auto operator+(const any& lhs_, const any& rhs_) -> any {
214 const any& lhs = any::unthunkVariant(lhs_);
215 const any& rhs = any::unthunkVariant(rhs_);
216 switch (lhs.type) {
217 case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i + rhs.i;
218 case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d + rhs.d;
219 case any::Type::Character: assert(lhs.type == any::Type::Character); return any(char(lhs.c + rhs.c));
220 case any::Type::StringLiteral:
221 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
222 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
223 return rhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs.r : lhs.r + *rhs.s;
224 case any::Type::String:
225 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
226 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
227 return rhs.type == any::Type::StringLiteral ? *lhs.s + rhs.r : *lhs.s + *rhs.s;
228 default: assert(false && "Unsupported type for '+' operator");
229 }
230 return nullptr;
233auto operator+(const any& lhs_, const char * rhs) -> std::string {
234 const any& lhs = any::unthunkVariant(lhs_);
235 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
236 return lhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs : *lhs.s + rhs;
239auto operator+(const char * lhs, const any& rhs_) -> std::string {
240 const any& rhs = any::unthunkVariant(rhs_);
241 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
242 return rhs.type == any::Type::StringLiteral ? lhs + std::string(rhs.r) : lhs + *rhs.s;
245auto operator-(const any& lhs_, const any& rhs_) -> any {
246 const any& lhs = any::unthunkVariant(lhs_);
247 const any& rhs = any::unthunkVariant(rhs_);
248 assert(lhs.type == rhs.type);
249 switch (lhs.type) {
250 case any::Type::Integer: return lhs.i - rhs.i;
251 case any::Type::Double: return lhs.d - rhs.d;
252 case any::Type::Character: return any(char(lhs.c - rhs.c));
253 default: assert(false && "Unsupported type for '-' operator");
254 }
255 return nullptr;
258auto operator*(const any& lhs_, const any& rhs_) -> any {
259 const any& lhs = any::unthunkVariant(lhs_);
260 const any& rhs = any::unthunkVariant(rhs_);
261 assert(lhs.type == rhs.type);
262 switch (lhs.type) {
263 case any::Type::Integer: return lhs.i * rhs.i;
264 case any::Type::Double: return lhs.d * rhs.d;
265 case any::Type::Character: return any(char(lhs.c * rhs.c));
266 default: assert(false && "Unsupported type for '*' operator");
267 }
268 return nullptr;
271auto operator/(const any& lhs_, const any& rhs_) -> any {
272 const any& lhs = any::unthunkVariant(lhs_);
273 const any& rhs = any::unthunkVariant(rhs_);
274 assert(lhs.type == rhs.type);
275 switch (lhs.type) {
276 case any::Type::Integer: return lhs.i / rhs.i;
277 case any::Type::Double: return lhs.d / rhs.d;
278 case any::Type::Character: return any(char(lhs.c / rhs.c));
279 default: assert(false && "Unsupported type for '/' operator");
280 }
281 return nullptr;
284auto operator%(const any& lhs_, const any& rhs_) -> any {
285 const any& lhs = any::unthunkVariant(lhs_);
286 const any& rhs = any::unthunkVariant(rhs_);
287 assert(lhs.type == rhs.type);
288 switch (lhs.type) {
289 case any::Type::Integer: return lhs.i % rhs.i;
290 case any::Type::Character: return any(char(lhs.c % rhs.c));
291 default: assert(false && "Unsupported type for '%' operator");
292 }
293 return nullptr;
296// unary negate
297auto operator-(const any& rhs_) -> any {
298 const any& rhs = any::unthunkVariant(rhs_);
299 switch (rhs.type) {
300 case any::Type::Integer: return (- rhs.i);
301 case any::Type::Double: return (- rhs.d);
302 default: assert(false && "Unsupported type for unary '-' operator");
303 }
304 return nullptr;
307} // namespace PureScript