git.iko.soy/rowtype-yoga/purescript-native
on ce67f6c help sign in
486 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 "PureScript.hh"
17namespace PureScript {
19#define COPY_DATA(src) \
20 switch (type) { \
21 case Type::Integer: i = src.i; break; \
22 case Type::Double: d = src.d; break; \
23 case Type::Character: c = src.c; break; \
24 case Type::Boolean: b = src.b; break; \
25 case Type::StringLiteral: r = src.r; break; \
26 case Type::String: new (&s) shared<std::string>(src.s); break; \
27 case Type::Map: new (&m) shared<map>(src.m); break; \
28 case Type::Vector: new (&v) shared<vector>(src.v); break; \
29 case Type::Function: f = src.f; break; \
30 case Type::Closure: new (&l) shared<closure>(src.l); break; \
31 case Type::EffFunction: new (&e) shared<eff_fn>(src.e); break; \
32 case Type::Thunk: t = src.t; break; \
33 case Type::Pointer: new (&p) shared<void>(src.p); break; \
34 \
35 default: assert(false && "Unsupported type in copy"); \
36 }
38#define MOVE_DATA(src) \
39 switch (type) { \
40 case Type::Integer: i = src.i; break; \
41 case Type::Double: d = src.d; break; \
42 case Type::Character: c = src.c; break; \
43 case Type::Boolean: b = src.b; break; \
44 case Type::StringLiteral: r = src.r; break; \
45 case Type::String: new (&s) shared<std::string>(std::move(src.s)); break; \
46 case Type::Map: new (&m) shared<map>(std::move(src.m)); break; \
47 case Type::Vector: new (&v) shared<vector>(std::move(src.v)); break; \
48 case Type::Function: f = src.f; break; \
49 case Type::Closure: new (&l) shared<closure>(std::move(src.l)); break; \
50 case Type::EffFunction: new (&e) shared<eff_fn>(std::move(src.e)); break; \
51 case Type::Thunk: t = src.t; break; \
52 case Type::Pointer: new (&p) shared<void>(std::move(src.p)); break; \
53 \
54 default: assert(false && "Unsupported type in move"); \
55 }
57any::any(const any& other) : type(other.type) {
58 COPY_DATA(other);
61any::any(any&& other) noexcept : type(other.type) {
62 MOVE_DATA(other);
65auto any::operator=(const any& rhs) -> any& {
66 type = rhs.type;
67 COPY_DATA(rhs);
68 return *this;
71// Takes ownership -- might need to reconsider this
72auto any::operator=(any& rhs) noexcept -> any& {
73 type = rhs.type;
74 MOVE_DATA(rhs);
75 return *this;
78auto any::operator=(any&& rhs) noexcept -> any& {
79 type = rhs.type;
80 MOVE_DATA(rhs);
81 return *this;
84any::~any() {
85 switch (type) {
86 case Type::Integer: ; break;
87 case Type::Double: ; break;
88 case Type::Character: ; break;
89 case Type::Boolean: ; break;
90 case Type::StringLiteral: ; break;
91 case Type::String: s.~shared<std::string>(); break;
92 case Type::Map: m.~shared<map>(); break;
93 case Type::Vector: v.~shared<vector>(); break;
94 case Type::Function: ; break;
95 case Type::Closure: l.~shared<closure>(); break;
96 case Type::EffFunction: e.~shared<eff_fn>(); break;
97 case Type::Thunk: ; break;
98 case Type::Pointer: p.~shared<void>(); break;
100 default: assert(false && "Unsupported type in destructor");
101 }
102};
104#define RETURN_VALUE(TYPE, VAL, FN) \
105 if (type == TYPE) { \
106 return FN(VAL); \
107 } \
108 const any* valuePtr = this; \
109 do { \
110 assert(valuePtr->type == Type::Thunk); \
111 const any& value = (*valuePtr->t)(unthunk); \
112 if (value.type == TYPE) { \
113 return FN(value.VAL); \
114 } \
115 valuePtr = &value; \
116 } while (valuePtr->type != Type::Unknown); \
117 assert(false && "Unknown value type"); \
118 return FN(VAL);
120template <typename T>
121auto any::cast() const -> typename std::enable_if<std::is_same<T, long>::value, T>::type {
122 RETURN_VALUE(Type::Integer, i,)
124template auto any::cast<long>() const -> long;
126template <typename T>
127auto any::cast() const -> typename std::enable_if<std::is_same<T, double>::value, T>::type {
128 RETURN_VALUE(Type::Double, d,)
130template auto any::cast<double>() const -> double;
132template <typename T>
133auto any::cast() const -> typename std::enable_if<std::is_same<T, char>::value, T>::type {
134 RETURN_VALUE(Type::Character, c,)
136template auto any::cast<char>() const -> char;
138template <typename T>
139auto any::cast() const -> typename std::enable_if<std::is_same<T, bool>::value, T>::type {
140 RETURN_VALUE(Type::Boolean, b,)
142template auto any::cast<bool>() const -> bool;
144template <typename T>
145auto any::cast() const -> typename std::enable_if<std::is_same<T, string>::value, T>::type {
146 const any& val = extractValue(*this);
147 if (val.type == Type::StringLiteral) {
148 return val.r;
149 }
150 assert(val.type == Type::String);
151 return val.s->c_str();
153template auto any::cast<string>() const -> string;
155template <typename T>
156auto any::cast() const -> typename std::enable_if<std::is_same<T, map>::value, const T&>::type {
157 RETURN_VALUE(Type::Map, m, *)
159template auto any::cast<any::map>() const -> const map&;
161template <typename T>
162auto any::cast() const -> typename std::enable_if<std::is_same<T, vector>::value, const T&>::type {
163 RETURN_VALUE(Type::Vector, v, *)
165template auto any::cast<any::vector>() const -> const vector&;
167auto any::operator()(const any& arg) const -> any {
168 if (type == Type::Function) {
169 return (*f)(arg);
170 }
171 if (type == Type::Closure) {
172 return (*l)(arg);
173 }
174 const any* valuePtr = this;
175 do {
176 assert(valuePtr->type == Type::Thunk);
177 const any& value = (*valuePtr->t)(unthunk);
178 if (value.type == Type::Function) {
179 return (*value.f)(arg);
180 }
181 if (value.type == Type::Closure) {
182 return (*value.l)(arg);
183 }
184 valuePtr = &value;
185 } while (valuePtr->type != Type::Unknown);
186 assert(false && "Unknown value type");
187 return nullptr;
190auto any::operator()(const as_thunk) const -> const any& {
191 assert(type == Type::Thunk);
192 return (*t)(unthunk);
195auto any::operator()() const -> any {
196 if (type == Type::EffFunction) {
197 return (*e)();
198 }
199 const any* valuePtr = this;
200 do {
201 assert(valuePtr->type == Type::Thunk);
202 const any& value = (*valuePtr->t)(unthunk);
203 if (value.type == Type::EffFunction) {
204 return (*value.e)();
205 }
206 valuePtr = &value;
207 } while (valuePtr->type != Type::Unknown);
208 assert(false && "Unknown value type");
209 return nullptr;
212any::operator long() const {
213 RETURN_VALUE(Type::Integer, i,)
216any::operator double() const {
217 RETURN_VALUE(Type::Double, d,)
220any::operator bool() const {
221 RETURN_VALUE(Type::Boolean, b,)
224any::operator string() const {
225 return cast<string>();
228any::operator const map&() const {
229 RETURN_VALUE(Type::Map, m, *)
232any::operator const vector&() const {
233 RETURN_VALUE(Type::Vector, v, *)
236auto any::extractPointer() const -> void* {
237 RETURN_VALUE(Type::Pointer, p.get(),)
240auto any::extractValue(const any& a) -> const any& {
241 if (a.type != Type::Thunk) {
242 return a;
243 }
244 const any* valuePtr = &a;
245 do {
246 const any& value = (*valuePtr->t)(unthunk);
247 if (value.type != Type::Thunk) {
248 return value;
249 }
250 valuePtr = &value;
251 } while (valuePtr->type != Type::Unknown);
252 assert(false && "Unknown value type");
253 return a;
256auto any::operator[](const char rhs[]) const -> const any& {
257 const any& val = extractValue(*this);
258 assert(val.type == Type::Map);
259 for (any::map::const_iterator it = val.m->begin(), end = val.m->end(); it != end; ++it) {
260 if (it->first == rhs || strcmp(it->first, rhs) == 0) {
261 return it->second;
262 }
263 }
264 throw runtime_error("map key not found");
267auto any::operator[](const vector::size_type rhs) const -> const any& {
268 const any& val = extractValue(*this);
269 assert(val.type == Type::Vector);
270 return (*val.v)[rhs];
273auto any::operator[](const any& rhs) const -> const any& {
274 const any& val = extractValue(*this);
275 assert(val.type == Type::Vector);
276 return (*val.v)[rhs.cast<long>()];
279auto any::contains(const char key[]) const -> bool {
280 const any& val = extractValue(*this);
281 assert(val.type == Type::Map);
282 for (any::map::const_iterator it = val.m->begin(), end = val.m->end(); it != end; ++it) {
283 if (it->first == key || strcmp(it->first, key) == 0) {
284 return true;
285 }
286 }
287 return false;
290//-----------------------------------------------------------------------------
291// Operator helper macros
292//-----------------------------------------------------------------------------
294#define DEFINE_OPERATOR(op, ty, rty) \
295auto operator op (const any& lhs, ty rhs) -> rty { \
296 return lhs.cast<typename std::remove_const<std::remove_reference<ty>::type>::type>() op rhs; \
297} \
298auto operator op (ty lhs, const any& rhs) -> rty { \
299 return lhs op rhs.cast<typename std::remove_const<std::remove_reference<ty>::type>::type>(); \
302#define DEFINE_CSTR_EQUALS_OPERATOR() \
303 auto operator==(const any& lhs_, const char * rhs) -> bool { \
304 const any& lhs = any::extractValue(lhs_); \
305 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
306 if (lhs.type == any::Type::StringLiteral) { \
307 return (lhs.r == rhs) || (strcmp(lhs.r, rhs) == 0); \
308 } \
309 return strcmp(lhs.s->c_str(), rhs) == 0; \
310 } \
311 auto operator==(const char * lhs, const any& rhs_) -> bool { \
312 const any& rhs = any::extractValue(rhs_); \
313 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
314 if (rhs.type == any::Type::StringLiteral) { \
315 return (lhs == rhs.r) || (strcmp(lhs, rhs) == 0); \
316 } \
317 return strcmp(lhs, rhs.s->c_str()) == 0; \
318 }
320#define DEFINE_CSTR_COMPARISON_OPERATOR(op) \
321 auto operator op (const any& lhs, const char * rhs) -> bool { \
322 return strcmp(lhs.cast<string>(), rhs) op 0; \
323 } \
324 auto operator op (const char * lhs, const any& rhs) -> bool { \
325 return strcmp(lhs, rhs.cast<string>()) op 0; \
326 }
328#define DEFINE_COMPARISON_OPERATOR(op) \
329 auto operator op (const any& lhs_, const any& rhs_) -> bool { \
330 const any& lhs = any::extractValue(lhs_); \
331 const any& rhs = any::extractValue(rhs_); \
332 switch (lhs.type) { \
333 case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i op rhs.i; \
334 case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d op rhs.d; \
335 case any::Type::Character: assert(lhs.type == any::Type::Character); return lhs.c op rhs.c; \
336 case any::Type::Boolean: assert(lhs.type == any::Type::Boolean); return lhs.b op rhs.b; \
337 case any::Type::StringLiteral: \
338 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
339 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
340 return strcmp(lhs.r, rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
341 case any::Type::String: \
342 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
343 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
344 return strcmp(lhs.s->c_str(), rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
345 case any::Type::Pointer: return lhs.p op rhs.p; \
346 default: assert(false && "Unsupported type for operator " #op); \
347 } \
348 return false; \
349 } \
350 DEFINE_OPERATOR(op, long, bool) \
351 DEFINE_OPERATOR(op, double, bool) \
352 DEFINE_OPERATOR(op, char, bool) \
353 DEFINE_OPERATOR(op, bool, bool) \
355//-----------------------------------------------------------------------------
356// Operator definitions
357//-----------------------------------------------------------------------------
359DEFINE_COMPARISON_OPERATOR(==)
360DEFINE_COMPARISON_OPERATOR(!=)
361DEFINE_COMPARISON_OPERATOR(<)
362DEFINE_COMPARISON_OPERATOR(<=)
363DEFINE_COMPARISON_OPERATOR(>)
364DEFINE_COMPARISON_OPERATOR(>=)
366DEFINE_CSTR_EQUALS_OPERATOR()
367DEFINE_CSTR_COMPARISON_OPERATOR(!=)
368DEFINE_CSTR_COMPARISON_OPERATOR(<)
369DEFINE_CSTR_COMPARISON_OPERATOR(<=)
370DEFINE_CSTR_COMPARISON_OPERATOR(>)
371DEFINE_CSTR_COMPARISON_OPERATOR(>=)
373auto operator+(const any& lhs_, const any& rhs_) -> any {
374 const any& lhs = any::extractValue(lhs_);
375 const any& rhs = any::extractValue(rhs_);
376 switch (lhs.type) {
377 case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i + rhs.i;
378 case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d + rhs.d;
379 case any::Type::Character: assert(lhs.type == any::Type::Character); return any(char(lhs.c + rhs.c));
380 case any::Type::StringLiteral:
381 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
382 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
383 return rhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs.r : lhs.r + *rhs.s;
384 case any::Type::String:
385 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
386 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
387 return rhs.type == any::Type::StringLiteral ? *lhs.s + rhs.r : *lhs.s + *rhs.s;
388 default: assert(false && "Unsupported type for '+' operator");
389 }
390 return nullptr;
393DEFINE_OPERATOR(+, long, long)
394DEFINE_OPERATOR(+, double, double)
395DEFINE_OPERATOR(+, char, char)
397auto operator+(const any& lhs_, const char * rhs) -> std::string {
398 const any& lhs = any::extractValue(lhs_);
399 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
400 return lhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs : *lhs.s + rhs;
403auto operator+(const char * lhs, const any& rhs_) -> std::string {
404 const any& rhs = any::extractValue(rhs_);
405 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
406 return rhs.type == any::Type::StringLiteral ? lhs + std::string(rhs.r) : lhs + *rhs.s;
409auto operator-(const any& lhs_, const any& rhs_) -> any {
410 const any& lhs = any::extractValue(lhs_);
411 const any& rhs = any::extractValue(rhs_);
412 assert(lhs.type == rhs.type);
413 switch (lhs.type) {
414 case any::Type::Integer: return lhs.i - rhs.i;
415 case any::Type::Double: return lhs.d - rhs.d;
416 case any::Type::Character: return any(char(lhs.c - rhs.c));
417 default: assert(false && "Unsupported type for '-' operator");
418 }
419 return nullptr;
422DEFINE_OPERATOR(-, long, long)
423DEFINE_OPERATOR(-, double, double)
424DEFINE_OPERATOR(-, char, char)
426auto operator*(const any& lhs_, const any& rhs_) -> any {
427 const any& lhs = any::extractValue(lhs_);
428 const any& rhs = any::extractValue(rhs_);
429 assert(lhs.type == rhs.type);
430 switch (lhs.type) {
431 case any::Type::Integer: return lhs.i * rhs.i;
432 case any::Type::Double: return lhs.d * rhs.d;
433 case any::Type::Character: return any(char(lhs.c * rhs.c));
434 default: assert(false && "Unsupported type for '*' operator");
435 }
436 return nullptr;
439DEFINE_OPERATOR(*, long, long)
440DEFINE_OPERATOR(*, double, double)
441DEFINE_OPERATOR(*, char, char)
443auto operator/(const any& lhs_, const any& rhs_) -> any {
444 const any& lhs = any::extractValue(lhs_);
445 const any& rhs = any::extractValue(rhs_);
446 assert(lhs.type == rhs.type);
447 switch (lhs.type) {
448 case any::Type::Integer: return lhs.i / rhs.i;
449 case any::Type::Double: return lhs.d / rhs.d;
450 case any::Type::Character: return any(char(lhs.c / rhs.c));
451 default: assert(false && "Unsupported type for '/' operator");
452 }
453 return nullptr;
456DEFINE_OPERATOR(/, long, long)
457DEFINE_OPERATOR(/, double, double)
458DEFINE_OPERATOR(/, char, char)
460auto operator%(const any& lhs_, const any& rhs_) -> any {
461 const any& lhs = any::extractValue(lhs_);
462 const any& rhs = any::extractValue(rhs_);
463 assert(lhs.type == rhs.type);
464 switch (lhs.type) {
465 case any::Type::Integer: return lhs.i % rhs.i;
466 case any::Type::Character: return any(char(lhs.c % rhs.c));
467 default: assert(false && "Unsupported type for '%' operator");
468 }
469 return nullptr;
472DEFINE_OPERATOR(%, long, long)
473DEFINE_OPERATOR(%, char, char)
475// unary negate
476auto operator-(const any& rhs_) -> any {
477 const any& rhs = any::extractValue(rhs_);
478 switch (rhs.type) {
479 case any::Type::Integer: return (- rhs.i);
480 case any::Type::Double: return (- rhs.d);
481 default: assert(false && "Unsupported type for unary '-' operator");
482 }
483 return nullptr;
486} // namespace PureScript