git.iko.soy/rowtype-yoga/purescript-native
on f93d365 help sign in
463 lines 17 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::Vector: new (&v) shared<vector>(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::Vector: new (&v) shared<vector>(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;
74// Takes ownership -- might need to reconsider this
75auto any::operator=(any& rhs) noexcept -> any& {
76 type = rhs.type;
77 MOVE_DATA(rhs);
78 return *this;
81auto any::operator=(any&& rhs) noexcept -> any& {
82 type = rhs.type;
83 MOVE_DATA(rhs);
84 return *this;
87any::~any() {
88 switch (type) {
89 case Type::Integer: ; break;
90 case Type::Double: ; break;
91 case Type::Character: ; break;
92 case Type::Boolean: ; break;
93 case Type::StringLiteral: ; break;
94 case Type::String: s.~shared<std::string>(); break;
95 case Type::Map: m.~shared<map>(); break;
96 case Type::Vector: v.~shared<vector>(); break;
97 case Type::Array: a.~shared<array>(); break;
98 case Type::Function: ; break;
99 case Type::Closure: l.~shared<closure>(); break;
100 case Type::EffFunction: e.~shared<eff_fn>(); break;
101 case Type::Thunk: ; break;
102 case Type::Pointer: p.~shared<void>(); break;
104 default: assert(false && "Unsupported type in destructor");
105 }
106};
108#define RETURN_VALUE(TYPE, ACCESSOR, INDIRECTION) \
109 const any& variant = unthunkVariant(*this); \
110 assert(variant.type == TYPE); \
111 return INDIRECTION(variant.ACCESSOR); \
113template <typename T>
114auto any::cast() const -> typename std::enable_if<std::is_same<T, long>::value, T>::type {
115 RETURN_VALUE(Type::Integer, i,)
117template auto any::cast<long>() const -> long;
119template <typename T>
120auto any::cast() const -> typename std::enable_if<std::is_same<T, double>::value, T>::type {
121 RETURN_VALUE(Type::Double, d,)
123template auto any::cast<double>() const -> double;
125template <typename T>
126auto any::cast() const -> typename std::enable_if<std::is_same<T, char>::value, T>::type {
127 RETURN_VALUE(Type::Character, c,)
129template auto any::cast<char>() const -> char;
131template <typename T>
132auto any::cast() const -> typename std::enable_if<std::is_same<T, bool>::value, T>::type {
133 RETURN_VALUE(Type::Boolean, b,)
135template auto any::cast<bool>() const -> bool;
137template <typename T>
138auto any::cast() const -> typename std::enable_if<std::is_same<T, string>::value, T>::type {
139 const any& variant = unthunkVariant(*this);
140 if (variant.type == Type::StringLiteral) {
141 return variant.r;
142 }
143 assert(variant.type == Type::String);
144 return variant.s->c_str();
146template auto any::cast<string>() const -> string;
148template <typename T>
149auto any::cast() const -> typename std::enable_if<std::is_same<T, map>::value, const T&>::type {
150 RETURN_VALUE(Type::Map, m, *)
152template auto any::cast<any::map>() const -> const map&;
154template <typename T>
155auto any::cast() const -> typename std::enable_if<std::is_same<T, vector>::value, const T&>::type {
156 RETURN_VALUE(Type::Vector, v, *)
158template auto any::cast<any::vector>() const -> const vector&;
160template <typename T>
161auto any::cast() const -> typename std::enable_if<std::is_same<T, array>::value, const T&>::type {
162 RETURN_VALUE(Type::Array, a, *)
164template auto any::cast<any::array>() const -> const array&;
166auto any::operator()(const any& arg) const -> any {
167 const any& variant = unthunkVariant(*this);
168 if (variant.type == Type::Closure) {
169 return (*variant.l)(arg);
170 }
171 assert(variant.type == Type::Function);
172 return (*variant.f)(arg);
175auto any::operator()(const as_thunk) const -> const any& {
176 assert(type == Type::Thunk);
177 return (*t)(unthunk);
180auto any::operator()() const -> any {
181 const any& variant = unthunkVariant(*this);
182 assert(variant.type == Type::EffFunction);
183 return (*variant.e)();
186any::operator long() const {
187 return cast<long>();
190any::operator double() const {
191 return cast<double>();
194any::operator bool() const {
195 return cast<bool>();
198any::operator string() const {
199 return cast<string>();
202any::operator const map&() const {
203 return cast<map>();
206any::operator const vector&() const {
207 return cast<vector>();
210any::operator const array&() const {
211 return cast<array>();
214auto any::extractPointer() const -> void* {
215 RETURN_VALUE(Type::Pointer, p.get(),)
218auto any::unthunkVariant(const any& a) -> const any& {
219 const any * variant = &a;
220 while (variant->type == Type::Thunk) {
221 variant = &((*variant->t)(unthunk));
222 }
223 return *variant;
226auto any::operator[](const char rhs[]) const -> const any& {
227 const any& variant = unthunkVariant(*this);
228 assert(variant.type == Type::Map);
229 const any::map::const_iterator begin = variant.m->begin();
230 const any::map::const_iterator end = variant.m->end();
231 for (any::map::const_iterator it = begin; it != end; ++it) {
232 if (it->first == rhs) {
233 return it->second;
234 }
235 }
236 for (any::map::const_iterator it = begin; it != end; ++it) {
237 if (strcmp(it->first, rhs) == 0) {
238 return it->second;
239 }
240 }
241 throw runtime_error("map key not found");
244auto any::operator[](const size_t rhs) const -> const any& {
245 const any& variant = unthunkVariant(*this);
246 assert(variant.type == Type::Array);
247 return (*variant.a)[rhs];
250auto any::operator[](const any& rhs) const -> const any& {
251 const any& variant = unthunkVariant(*this);
252 assert(variant.type == Type::Array);
253 return (*variant.a)[rhs.cast<long>()];
256auto any::contains(const char key[]) const -> bool {
257 const any& variant = unthunkVariant(*this);
258 assert(variant.type == Type::Map);
259 for (any::map::const_iterator it = variant.m->begin(), end = variant.m->end(); it != end; ++it) {
260 if (it->first == key || strcmp(it->first, key) == 0) {
261 return true;
262 }
263 }
264 return false;
267//-----------------------------------------------------------------------------
268// Operator helper macros
269//-----------------------------------------------------------------------------
271#define DEFINE_OPERATOR(op, ty, rty) \
272auto operator op (const any& lhs, ty rhs) -> rty { \
273 return lhs.cast<typename std::remove_const<std::remove_reference<ty>::type>::type>() op rhs; \
274} \
275auto operator op (ty lhs, const any& rhs) -> rty { \
276 return lhs op rhs.cast<typename std::remove_const<std::remove_reference<ty>::type>::type>(); \
279#define DEFINE_CSTR_EQUALS_OPERATOR() \
280 auto operator==(const any& lhs_, const char * rhs) -> bool { \
281 const any& lhs = any::unthunkVariant(lhs_); \
282 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
283 if (lhs.type == any::Type::StringLiteral) { \
284 return (lhs.r == rhs) || (strcmp(lhs.r, rhs) == 0); \
285 } \
286 return strcmp(lhs.s->c_str(), rhs) == 0; \
287 } \
288 auto operator==(const char * lhs, const any& rhs_) -> bool { \
289 const any& rhs = any::unthunkVariant(rhs_); \
290 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
291 if (rhs.type == any::Type::StringLiteral) { \
292 return (lhs == rhs.r) || (strcmp(lhs, rhs) == 0); \
293 } \
294 return strcmp(lhs, rhs.s->c_str()) == 0; \
295 }
297#define DEFINE_CSTR_COMPARISON_OPERATOR(op) \
298 auto operator op (const any& lhs, const char * rhs) -> bool { \
299 return strcmp(lhs.cast<string>(), rhs) op 0; \
300 } \
301 auto operator op (const char * lhs, const any& rhs) -> bool { \
302 return strcmp(lhs, rhs.cast<string>()) op 0; \
303 }
305#define DEFINE_COMPARISON_OPERATOR(op) \
306 auto operator op (const any& lhs_, const any& rhs_) -> bool { \
307 const any& lhs = any::unthunkVariant(lhs_); \
308 const any& rhs = any::unthunkVariant(rhs_); \
309 switch (lhs.type) { \
310 case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i op rhs.i; \
311 case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d op rhs.d; \
312 case any::Type::Character: assert(lhs.type == any::Type::Character); return lhs.c op rhs.c; \
313 case any::Type::Boolean: assert(lhs.type == any::Type::Boolean); return lhs.b op rhs.b; \
314 case any::Type::StringLiteral: \
315 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
316 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
317 return strcmp(lhs.r, rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
318 case any::Type::String: \
319 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
320 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
321 return strcmp(lhs.s->c_str(), rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
322 case any::Type::Pointer: return lhs.p op rhs.p; \
323 default: assert(false && "Unsupported type for operator " #op); \
324 } \
325 return false; \
326 } \
327 DEFINE_OPERATOR(op, long, bool) \
328 DEFINE_OPERATOR(op, double, bool) \
329 DEFINE_OPERATOR(op, char, bool) \
330 DEFINE_OPERATOR(op, bool, bool) \
332//-----------------------------------------------------------------------------
333// Operator definitions
334//-----------------------------------------------------------------------------
336DEFINE_COMPARISON_OPERATOR(==)
337DEFINE_COMPARISON_OPERATOR(!=)
338DEFINE_COMPARISON_OPERATOR(<)
339DEFINE_COMPARISON_OPERATOR(<=)
340DEFINE_COMPARISON_OPERATOR(>)
341DEFINE_COMPARISON_OPERATOR(>=)
343DEFINE_CSTR_EQUALS_OPERATOR()
344DEFINE_CSTR_COMPARISON_OPERATOR(!=)
345DEFINE_CSTR_COMPARISON_OPERATOR(<)
346DEFINE_CSTR_COMPARISON_OPERATOR(<=)
347DEFINE_CSTR_COMPARISON_OPERATOR(>)
348DEFINE_CSTR_COMPARISON_OPERATOR(>=)
350auto operator+(const any& lhs_, const any& rhs_) -> any {
351 const any& lhs = any::unthunkVariant(lhs_);
352 const any& rhs = any::unthunkVariant(rhs_);
353 switch (lhs.type) {
354 case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i + rhs.i;
355 case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d + rhs.d;
356 case any::Type::Character: assert(lhs.type == any::Type::Character); return any(char(lhs.c + rhs.c));
357 case any::Type::StringLiteral:
358 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
359 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
360 return rhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs.r : lhs.r + *rhs.s;
361 case any::Type::String:
362 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
363 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
364 return rhs.type == any::Type::StringLiteral ? *lhs.s + rhs.r : *lhs.s + *rhs.s;
365 default: assert(false && "Unsupported type for '+' operator");
366 }
367 return nullptr;
370DEFINE_OPERATOR(+, long, long)
371DEFINE_OPERATOR(+, double, double)
372DEFINE_OPERATOR(+, char, char)
374auto operator+(const any& lhs_, const char * rhs) -> std::string {
375 const any& lhs = any::unthunkVariant(lhs_);
376 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
377 return lhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs : *lhs.s + rhs;
380auto operator+(const char * lhs, const any& rhs_) -> std::string {
381 const any& rhs = any::unthunkVariant(rhs_);
382 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
383 return rhs.type == any::Type::StringLiteral ? lhs + std::string(rhs.r) : lhs + *rhs.s;
386auto operator-(const any& lhs_, const any& rhs_) -> any {
387 const any& lhs = any::unthunkVariant(lhs_);
388 const any& rhs = any::unthunkVariant(rhs_);
389 assert(lhs.type == rhs.type);
390 switch (lhs.type) {
391 case any::Type::Integer: return lhs.i - rhs.i;
392 case any::Type::Double: return lhs.d - rhs.d;
393 case any::Type::Character: return any(char(lhs.c - rhs.c));
394 default: assert(false && "Unsupported type for '-' operator");
395 }
396 return nullptr;
399DEFINE_OPERATOR(-, long, long)
400DEFINE_OPERATOR(-, double, double)
401DEFINE_OPERATOR(-, char, char)
403auto operator*(const any& lhs_, const any& rhs_) -> any {
404 const any& lhs = any::unthunkVariant(lhs_);
405 const any& rhs = any::unthunkVariant(rhs_);
406 assert(lhs.type == rhs.type);
407 switch (lhs.type) {
408 case any::Type::Integer: return lhs.i * rhs.i;
409 case any::Type::Double: return lhs.d * rhs.d;
410 case any::Type::Character: return any(char(lhs.c * rhs.c));
411 default: assert(false && "Unsupported type for '*' operator");
412 }
413 return nullptr;
416DEFINE_OPERATOR(*, long, long)
417DEFINE_OPERATOR(*, double, double)
418DEFINE_OPERATOR(*, char, char)
420auto operator/(const any& lhs_, const any& rhs_) -> any {
421 const any& lhs = any::unthunkVariant(lhs_);
422 const any& rhs = any::unthunkVariant(rhs_);
423 assert(lhs.type == rhs.type);
424 switch (lhs.type) {
425 case any::Type::Integer: return lhs.i / rhs.i;
426 case any::Type::Double: return lhs.d / rhs.d;
427 case any::Type::Character: return any(char(lhs.c / rhs.c));
428 default: assert(false && "Unsupported type for '/' operator");
429 }
430 return nullptr;
433DEFINE_OPERATOR(/, long, long)
434DEFINE_OPERATOR(/, double, double)
435DEFINE_OPERATOR(/, char, char)
437auto operator%(const any& lhs_, const any& rhs_) -> any {
438 const any& lhs = any::unthunkVariant(lhs_);
439 const any& rhs = any::unthunkVariant(rhs_);
440 assert(lhs.type == rhs.type);
441 switch (lhs.type) {
442 case any::Type::Integer: return lhs.i % rhs.i;
443 case any::Type::Character: return any(char(lhs.c % rhs.c));
444 default: assert(false && "Unsupported type for '%' operator");
445 }
446 return nullptr;
449DEFINE_OPERATOR(%, long, long)
450DEFINE_OPERATOR(%, char, char)
452// unary negate
453auto operator-(const any& rhs_) -> any {
454 const any& rhs = any::unthunkVariant(rhs_);
455 switch (rhs.type) {
456 case any::Type::Integer: return (- rhs.i);
457 case any::Type::Double: return (- rhs.d);
458 default: assert(false && "Unsupported type for unary '-' operator");
459 }
460 return nullptr;
463} // namespace PureScript