git.iko.soy/rowtype-yoga/purescript-native
on 7591176 help sign in
487 lines 18 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 COPY_DATA(src) \
21 switch (type) { \
22 case Type::Integer: i = src.i; break; \
23 case Type::Double: d = src.d; break; \
24 case Type::Character: c = src.c; break; \
25 case Type::Boolean: b = src.b; break; \
26 case Type::StringLiteral: r = src.r; break; \
27 case Type::String: new (&s) shared<std::string>(src.s); break; \
28 case Type::Map: new (&m) shared<map>(src.m); break; \
29 case Type::Data: new (&v) shared<data>(src.v); break; \
30 case Type::Array: new (&a) shared<array>(src.a); break; \
31 case Type::Function: f = src.f; break; \
32 case Type::Closure: new (&l) shared<closure>(src.l); break; \
33 case Type::EffFunction: new (&e) shared<eff_fn>(src.e); break; \
34 case Type::Thunk: t = src.t; break; \
35 case Type::Pointer: new (&p) shared<void>(src.p); break; \
36 \
37 default: assert(false && "Unsupported type in copy"); \
38 }
40#define MOVE_DATA(src) \
41 switch (type) { \
42 case Type::Integer: i = src.i; break; \
43 case Type::Double: d = src.d; break; \
44 case Type::Character: c = src.c; break; \
45 case Type::Boolean: b = src.b; break; \
46 case Type::StringLiteral: r = src.r; break; \
47 case Type::String: new (&s) shared<std::string>(std::move(src.s)); break; \
48 case Type::Map: new (&m) shared<map>(std::move(src.m)); break; \
49 case Type::Data: new (&v) shared<data>(std::move(src.v)); break; \
50 case Type::Array: new (&a) shared<array>(std::move(src.a)); break; \
51 case Type::Function: f = src.f; break; \
52 case Type::Closure: new (&l) shared<closure>(std::move(src.l)); break; \
53 case Type::EffFunction: new (&e) shared<eff_fn>(std::move(src.e)); break; \
54 case Type::Thunk: t = src.t; break; \
55 case Type::Pointer: new (&p) shared<void>(std::move(src.p)); break; \
56 \
57 default: assert(false && "Unsupported type in move"); \
58 }
60any::any(const any& other) : type(other.type) {
61 COPY_DATA(other);
64any::any(any&& other) noexcept : type(other.type) {
65 MOVE_DATA(other);
68auto any::operator=(const any& rhs) -> any& {
69 type = rhs.type;
70 COPY_DATA(rhs);
71 return *this;
74auto any::operator=(any& rhs) noexcept -> any& {
75 type = rhs.type;
76 COPY_DATA(rhs);
77 return *this;
80auto any::operator=(any&& rhs) noexcept -> any& {
81 type = rhs.type;
82 MOVE_DATA(rhs);
83 return *this;
86any::~any() {
87 switch (type) {
88 case Type::Integer: ; break;
89 case Type::Double: ; break;
90 case Type::Character: ; break;
91 case Type::Boolean: ; break;
92 case Type::StringLiteral: ; break;
93 case Type::String: s.~shared<std::string>(); break;
94 case Type::Map: m.~shared<map>(); break;
95 case Type::Data: v.~shared<data>(); break;
96 case Type::Array: a.~shared<array>(); break;
97 case Type::Function: ; break;
98 case Type::Closure: l.~shared<closure>(); break;
99 case Type::EffFunction: e.~shared<eff_fn>(); break;
100 case Type::Thunk: ; break;
101 case Type::Pointer: p.~shared<void>(); break;
103 default: assert(false && "Unsupported type in destructor");
104 }
105};
107#define RETURN_VALUE(TYPE, ACCESSOR, INDIRECTION) \
108 const any& variant = unthunkVariant(*this); \
109 assert(variant.type == TYPE); \
110 return INDIRECTION(variant.ACCESSOR); \
112template <typename T>
113auto any::cast() const -> typename std::enable_if<std::is_same<T, long>::value, T>::type {
114 RETURN_VALUE(Type::Integer, i,)
116template auto any::cast<long>() const -> long;
118template <typename T>
119auto any::cast() const -> typename std::enable_if<std::is_same<T, double>::value, T>::type {
120 RETURN_VALUE(Type::Double, d,)
122template auto any::cast<double>() const -> double;
124template <typename T>
125auto any::cast() const -> typename std::enable_if<std::is_same<T, char>::value, T>::type {
126 RETURN_VALUE(Type::Character, c,)
128template auto any::cast<char>() const -> char;
130template <typename T>
131auto any::cast() const -> typename std::enable_if<std::is_same<T, bool>::value, T>::type {
132 RETURN_VALUE(Type::Boolean, b,)
134template auto any::cast<bool>() const -> bool;
136template <typename T>
137auto any::cast() const -> typename std::enable_if<std::is_same<T, string>::value, T>::type {
138 const any& variant = unthunkVariant(*this);
139 if (variant.type == Type::StringLiteral) {
140 return variant.r;
141 }
142 assert(variant.type == Type::String);
143 return variant.s->c_str();
145template auto any::cast<string>() const -> string;
147template <typename T>
148auto any::cast() const -> typename std::enable_if<std::is_same<T, map>::value, const T&>::type {
149 RETURN_VALUE(Type::Map, m, *)
151template auto any::cast<any::map>() const -> const map&;
153template <typename T>
154auto any::cast() const -> typename std::enable_if<std::is_same<T, data>::value, const T&>::type {
155 RETURN_VALUE(Type::Data, v, *)
157template auto any::cast<any::data>() const -> const data&;
159template <typename T>
160auto any::cast() const -> typename std::enable_if<std::is_same<T, array>::value, const T&>::type {
161 RETURN_VALUE(Type::Array, a, *)
163template auto any::cast<any::array>() const -> const array&;
165auto any::operator()(const any& arg) const -> any {
166 const any& variant = unthunkVariant(*this);
167 if (variant.type == Type::Closure) {
168 return (*variant.l)(arg);
169 }
170 assert(variant.type == Type::Function);
171 return (*variant.f)(arg);
174auto any::operator()(const any& arg1, const any& arg2) const -> any {
175 const any& variant = unthunkVariant(*this);
176 if (variant.type == Type::Closure) {
177 return (*variant.l)(arg1, arg2);
178 }
179 assert(variant.type == Type::Function);
180 return (*variant.f)(arg1)(arg2);
183auto any::operator()(const any& arg1, const any& arg2, const any& arg3) const -> any {
184 const any& variant = unthunkVariant(*this);
185 if (variant.type == Type::Closure) {
186 return (*variant.l)(arg1, arg2, arg3);
187 }
188 assert(variant.type == Type::Function);
189 return (*variant.f)(arg1)(arg2)(arg3);
192auto any::operator()(const as_thunk) const -> const any& {
193 assert(type == Type::Thunk);
194 return (*t)(unthunk);
197auto any::operator()() const -> any {
198 const any& variant = unthunkVariant(*this);
199 assert(variant.type == Type::EffFunction);
200 return (*variant.e)();
203any::operator long() const {
204 return cast<long>();
207any::operator double() const {
208 return cast<double>();
211any::operator bool() const {
212 return cast<bool>();
215any::operator string() const {
216 return cast<string>();
219any::operator const map&() const {
220 return cast<map>();
223any::operator const data&() const {
224 return cast<data>();
227any::operator const array&() const {
228 return cast<array>();
231auto any::extractPointer() const -> void* {
232 RETURN_VALUE(Type::Pointer, p.get(),)
235auto any::unthunkVariant(const any& a) -> const any& {
236 const any * variant = &a;
237 while (variant->type == Type::Thunk) {
238 variant = &((*variant->t)(unthunk));
239 }
240 return *variant;
243auto any::operator[](const char rhs[]) const -> const any& {
244 const any& variant = unthunkVariant(*this);
245 assert(variant.type == Type::Map);
246 const auto begin = variant.m->cbegin();
247 const auto end = variant.m->cend();
248 for (auto it = begin; it != end; ++it) {
249 if (it->first == rhs) {
250 return it->second;
251 }
252 }
253 for (auto it = begin; it != end; ++it) {
254 if (strcmp(it->first, rhs) == 0) {
255 return it->second;
256 }
257 }
258 throw runtime_error("map key not found");
261auto any::operator[](const size_t rhs) const -> const any& {
262 const any& variant = unthunkVariant(*this);
263 assert(variant.type == Type::Array);
264 return (*variant.a)[rhs];
267auto any::operator[](const any& rhs) const -> const any& {
268 const any& variant = unthunkVariant(*this);
269 assert(variant.type == Type::Array);
270 return (*variant.a)[rhs.cast<long>()];
273auto any::contains(const char key[]) const -> bool {
274 const any& variant = unthunkVariant(*this);
275 assert(variant.type == Type::Map);
276 const auto begin = variant.m->cbegin();
277 const auto end = variant.m->cend();
278 for (auto it = begin; it != end; ++it) {
279 if (it->first == key) {
280 return true;
281 }
282 }
283 for (auto it = begin; it != end; ++it) {
284 if (strcmp(it->first, key) == 0) {
285 return true;
286 }
287 }
288 return false;
291//-----------------------------------------------------------------------------
292// Operator helper macros
293//-----------------------------------------------------------------------------
295#define DEFINE_OPERATOR(op, ty, rty) \
296auto operator op (const any& lhs, ty rhs) -> rty { \
297 return lhs.cast<typename std::remove_const<std::remove_reference<ty>::type>::type>() op rhs; \
298} \
299auto operator op (ty lhs, const any& rhs) -> rty { \
300 return lhs op rhs.cast<typename std::remove_const<std::remove_reference<ty>::type>::type>(); \
303#define DEFINE_CSTR_EQUALS_OPERATOR() \
304 auto operator==(const any& lhs_, const char * rhs) -> bool { \
305 const any& lhs = any::unthunkVariant(lhs_); \
306 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
307 if (lhs.type == any::Type::StringLiteral) { \
308 return (lhs.r == rhs) || (strcmp(lhs.r, rhs) == 0); \
309 } \
310 return strcmp(lhs.s->c_str(), rhs) == 0; \
311 } \
312 auto operator==(const char * lhs, const any& rhs_) -> bool { \
313 const any& rhs = any::unthunkVariant(rhs_); \
314 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
315 if (rhs.type == any::Type::StringLiteral) { \
316 return (lhs == rhs.r) || (strcmp(lhs, rhs) == 0); \
317 } \
318 return strcmp(lhs, rhs.s->c_str()) == 0; \
319 }
321#define DEFINE_CSTR_COMPARISON_OPERATOR(op) \
322 auto operator op (const any& lhs, const char * rhs) -> bool { \
323 return strcmp(lhs.cast<string>(), rhs) op 0; \
324 } \
325 auto operator op (const char * lhs, const any& rhs) -> bool { \
326 return strcmp(lhs, rhs.cast<string>()) op 0; \
327 }
329#define DEFINE_COMPARISON_OPERATOR(op) \
330 auto operator op (const any& lhs_, const any& rhs_) -> bool { \
331 const any& lhs = any::unthunkVariant(lhs_); \
332 const any& rhs = any::unthunkVariant(rhs_); \
333 switch (lhs.type) { \
334 case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i op rhs.i; \
335 case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d op rhs.d; \
336 case any::Type::Character: assert(lhs.type == any::Type::Character); return lhs.c op rhs.c; \
337 case any::Type::Boolean: assert(lhs.type == any::Type::Boolean); return lhs.b op rhs.b; \
338 case any::Type::StringLiteral: \
339 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
340 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
341 return strcmp(lhs.r, rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
342 case any::Type::String: \
343 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
344 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
345 return strcmp(lhs.s->c_str(), rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
346 case any::Type::Pointer: return lhs.p op rhs.p; \
347 default: assert(false && "Unsupported type for operator " #op); \
348 } \
349 return false; \
350 } \
351 DEFINE_OPERATOR(op, long, bool) \
352 DEFINE_OPERATOR(op, double, bool) \
353 DEFINE_OPERATOR(op, char, bool) \
354 DEFINE_OPERATOR(op, bool, bool) \
356//-----------------------------------------------------------------------------
357// Operator definitions
358//-----------------------------------------------------------------------------
360DEFINE_COMPARISON_OPERATOR(==)
361DEFINE_COMPARISON_OPERATOR(!=)
362DEFINE_COMPARISON_OPERATOR(<)
363DEFINE_COMPARISON_OPERATOR(<=)
364DEFINE_COMPARISON_OPERATOR(>)
365DEFINE_COMPARISON_OPERATOR(>=)
367DEFINE_CSTR_EQUALS_OPERATOR()
368DEFINE_CSTR_COMPARISON_OPERATOR(!=)
369DEFINE_CSTR_COMPARISON_OPERATOR(<)
370DEFINE_CSTR_COMPARISON_OPERATOR(<=)
371DEFINE_CSTR_COMPARISON_OPERATOR(>)
372DEFINE_CSTR_COMPARISON_OPERATOR(>=)
374auto operator+(const any& lhs_, const any& rhs_) -> any {
375 const any& lhs = any::unthunkVariant(lhs_);
376 const any& rhs = any::unthunkVariant(rhs_);
377 switch (lhs.type) {
378 case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i + rhs.i;
379 case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d + rhs.d;
380 case any::Type::Character: assert(lhs.type == any::Type::Character); return any(char(lhs.c + rhs.c));
381 case any::Type::StringLiteral:
382 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
383 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
384 return rhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs.r : lhs.r + *rhs.s;
385 case any::Type::String:
386 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
387 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
388 return rhs.type == any::Type::StringLiteral ? *lhs.s + rhs.r : *lhs.s + *rhs.s;
389 default: assert(false && "Unsupported type for '+' operator");
390 }
391 return nullptr;
394DEFINE_OPERATOR(+, long, long)
395DEFINE_OPERATOR(+, double, double)
396DEFINE_OPERATOR(+, char, char)
398auto operator+(const any& lhs_, const char * rhs) -> std::string {
399 const any& lhs = any::unthunkVariant(lhs_);
400 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
401 return lhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs : *lhs.s + rhs;
404auto operator+(const char * lhs, const any& rhs_) -> std::string {
405 const any& rhs = any::unthunkVariant(rhs_);
406 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
407 return rhs.type == any::Type::StringLiteral ? lhs + std::string(rhs.r) : lhs + *rhs.s;
410auto operator-(const any& lhs_, const any& rhs_) -> any {
411 const any& lhs = any::unthunkVariant(lhs_);
412 const any& rhs = any::unthunkVariant(rhs_);
413 assert(lhs.type == rhs.type);
414 switch (lhs.type) {
415 case any::Type::Integer: return lhs.i - rhs.i;
416 case any::Type::Double: return lhs.d - rhs.d;
417 case any::Type::Character: return any(char(lhs.c - rhs.c));
418 default: assert(false && "Unsupported type for '-' operator");
419 }
420 return nullptr;
423DEFINE_OPERATOR(-, long, long)
424DEFINE_OPERATOR(-, double, double)
425DEFINE_OPERATOR(-, char, char)
427auto operator*(const any& lhs_, const any& rhs_) -> any {
428 const any& lhs = any::unthunkVariant(lhs_);
429 const any& rhs = any::unthunkVariant(rhs_);
430 assert(lhs.type == rhs.type);
431 switch (lhs.type) {
432 case any::Type::Integer: return lhs.i * rhs.i;
433 case any::Type::Double: return lhs.d * rhs.d;
434 case any::Type::Character: return any(char(lhs.c * rhs.c));
435 default: assert(false && "Unsupported type for '*' operator");
436 }
437 return nullptr;
440DEFINE_OPERATOR(*, long, long)
441DEFINE_OPERATOR(*, double, double)
442DEFINE_OPERATOR(*, char, char)
444auto operator/(const any& lhs_, const any& rhs_) -> any {
445 const any& lhs = any::unthunkVariant(lhs_);
446 const any& rhs = any::unthunkVariant(rhs_);
447 assert(lhs.type == rhs.type);
448 switch (lhs.type) {
449 case any::Type::Integer: return lhs.i / rhs.i;
450 case any::Type::Double: return lhs.d / rhs.d;
451 case any::Type::Character: return any(char(lhs.c / rhs.c));
452 default: assert(false && "Unsupported type for '/' operator");
453 }
454 return nullptr;
457DEFINE_OPERATOR(/, long, long)
458DEFINE_OPERATOR(/, double, double)
459DEFINE_OPERATOR(/, char, char)
461auto operator%(const any& lhs_, const any& rhs_) -> any {
462 const any& lhs = any::unthunkVariant(lhs_);
463 const any& rhs = any::unthunkVariant(rhs_);
464 assert(lhs.type == rhs.type);
465 switch (lhs.type) {
466 case any::Type::Integer: return lhs.i % rhs.i;
467 case any::Type::Character: return any(char(lhs.c % rhs.c));
468 default: assert(false && "Unsupported type for '%' operator");
469 }
470 return nullptr;
473DEFINE_OPERATOR(%, long, long)
474DEFINE_OPERATOR(%, char, char)
476// unary negate
477auto operator-(const any& rhs_) -> any {
478 const any& rhs = any::unthunkVariant(rhs_);
479 switch (rhs.type) {
480 case any::Type::Integer: return (- rhs.i);
481 case any::Type::Double: return (- rhs.d);
482 default: assert(false && "Unsupported type for unary '-' operator");
483 }
484 return nullptr;
487} // namespace PureScript