git.iko.soy/rowtype-yoga/purescript-native
on 1e55cc3 help sign in
494 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::Vector: new (&v) shared<vector>(src.v); break; \
30 case Type::Function: f = src.f; break; \
31 case Type::Closure: new (&l) shared<closure>(src.l); break; \
32 case Type::EffFunction: new (&e) shared<eff_fn>(src.e); break; \
33 case Type::Thunk: t = src.t; break; \
34 case Type::Pointer: new (&p) shared<void>(src.p); break; \
35 \
36 default: assert(false && "Unsupported type in copy"); \
37 }
39#define MOVE_DATA(src) \
40 switch (type) { \
41 case Type::Integer: i = src.i; break; \
42 case Type::Double: d = src.d; break; \
43 case Type::Character: c = src.c; break; \
44 case Type::Boolean: b = src.b; break; \
45 case Type::StringLiteral: r = src.r; break; \
46 case Type::String: new (&s) shared<std::string>(std::move(src.s)); break; \
47 case Type::Map: new (&m) shared<map>(std::move(src.m)); break; \
48 case Type::Vector: new (&v) shared<vector>(std::move(src.v)); break; \
49 case Type::Function: f = src.f; break; \
50 case Type::Closure: new (&l) shared<closure>(std::move(src.l)); break; \
51 case Type::EffFunction: new (&e) shared<eff_fn>(std::move(src.e)); break; \
52 case Type::Thunk: t = src.t; break; \
53 case Type::Pointer: new (&p) shared<void>(std::move(src.p)); break; \
54 \
55 default: assert(false && "Unsupported type in move"); \
56 }
58any::any(const any& other) : type(other.type) {
59 COPY_DATA(other);
62any::any(any&& other) noexcept : type(other.type) {
63 MOVE_DATA(other);
66auto any::operator=(const any& rhs) -> any& {
67 type = rhs.type;
68 COPY_DATA(rhs);
69 return *this;
72// Takes ownership -- might need to reconsider this
73auto any::operator=(any& rhs) noexcept -> any& {
74 type = rhs.type;
75 MOVE_DATA(rhs);
76 return *this;
79auto any::operator=(any&& rhs) noexcept -> any& {
80 type = rhs.type;
81 MOVE_DATA(rhs);
82 return *this;
85any::~any() {
86 switch (type) {
87 case Type::Integer: ; break;
88 case Type::Double: ; break;
89 case Type::Character: ; break;
90 case Type::Boolean: ; break;
91 case Type::StringLiteral: ; break;
92 case Type::String: s.~shared<std::string>(); break;
93 case Type::Map: m.~shared<map>(); break;
94 case Type::Vector: v.~shared<vector>(); break;
95 case Type::Function: ; break;
96 case Type::Closure: l.~shared<closure>(); break;
97 case Type::EffFunction: e.~shared<eff_fn>(); break;
98 case Type::Thunk: ; break;
99 case Type::Pointer: p.~shared<void>(); break;
101 default: assert(false && "Unsupported type in destructor");
102 }
103};
105#define RETURN_VALUE(TYPE, VAL, FN) \
106 if (type == TYPE) { \
107 return FN(VAL); \
108 } \
109 const any* valuePtr = this; \
110 do { \
111 assert(valuePtr->type == Type::Thunk); \
112 const any& value = (*valuePtr->t)(unthunk); \
113 if (value.type == TYPE) { \
114 return FN(value.VAL); \
115 } \
116 valuePtr = &value; \
117 } while (valuePtr->type != Type::Unknown); \
118 assert(false && "Unknown value type"); \
119 return FN(VAL);
121template <typename T>
122auto any::cast() const -> typename std::enable_if<std::is_same<T, long>::value, T>::type {
123 RETURN_VALUE(Type::Integer, i,)
125template auto any::cast<long>() const -> long;
127template <typename T>
128auto any::cast() const -> typename std::enable_if<std::is_same<T, double>::value, T>::type {
129 RETURN_VALUE(Type::Double, d,)
131template auto any::cast<double>() const -> double;
133template <typename T>
134auto any::cast() const -> typename std::enable_if<std::is_same<T, char>::value, T>::type {
135 RETURN_VALUE(Type::Character, c,)
137template auto any::cast<char>() const -> char;
139template <typename T>
140auto any::cast() const -> typename std::enable_if<std::is_same<T, bool>::value, T>::type {
141 RETURN_VALUE(Type::Boolean, b,)
143template auto any::cast<bool>() const -> bool;
145template <typename T>
146auto any::cast() const -> typename std::enable_if<std::is_same<T, string>::value, T>::type {
147 const any& val = extractValue(*this);
148 if (val.type == Type::StringLiteral) {
149 return val.r;
150 }
151 assert(val.type == Type::String);
152 return val.s->c_str();
154template auto any::cast<string>() const -> string;
156template <typename T>
157auto any::cast() const -> typename std::enable_if<std::is_same<T, map>::value, const T&>::type {
158 RETURN_VALUE(Type::Map, m, *)
160template auto any::cast<any::map>() const -> const map&;
162template <typename T>
163auto any::cast() const -> typename std::enable_if<std::is_same<T, vector>::value, const T&>::type {
164 RETURN_VALUE(Type::Vector, v, *)
166template auto any::cast<any::vector>() const -> const vector&;
168auto any::operator()(const any& arg) const -> any {
169 if (type == Type::Function) {
170 return (*f)(arg);
171 }
172 if (type == Type::Closure) {
173 return (*l)(arg);
174 }
175 const any* valuePtr = this;
176 do {
177 assert(valuePtr->type == Type::Thunk);
178 const any& value = (*valuePtr->t)(unthunk);
179 if (value.type == Type::Function) {
180 return (*value.f)(arg);
181 }
182 if (value.type == Type::Closure) {
183 return (*value.l)(arg);
184 }
185 valuePtr = &value;
186 } while (valuePtr->type != Type::Unknown);
187 assert(false && "Unknown value type");
188 return nullptr;
191auto any::operator()(const as_thunk) const -> const any& {
192 assert(type == Type::Thunk);
193 return (*t)(unthunk);
196auto any::operator()() const -> any {
197 if (type == Type::EffFunction) {
198 return (*e)();
199 }
200 const any* valuePtr = this;
201 do {
202 assert(valuePtr->type == Type::Thunk);
203 const any& value = (*valuePtr->t)(unthunk);
204 if (value.type == Type::EffFunction) {
205 return (*value.e)();
206 }
207 valuePtr = &value;
208 } while (valuePtr->type != Type::Unknown);
209 assert(false && "Unknown value type");
210 return nullptr;
213any::operator long() const {
214 RETURN_VALUE(Type::Integer, i,)
217any::operator double() const {
218 RETURN_VALUE(Type::Double, d,)
221any::operator bool() const {
222 RETURN_VALUE(Type::Boolean, b,)
225any::operator string() const {
226 return cast<string>();
229any::operator const map&() const {
230 RETURN_VALUE(Type::Map, m, *)
233any::operator const vector&() const {
234 RETURN_VALUE(Type::Vector, v, *)
237auto any::extractPointer() const -> void* {
238 RETURN_VALUE(Type::Pointer, p.get(),)
241auto any::extractValue(const any& a) -> const any& {
242 if (a.type != Type::Thunk) {
243 return a;
244 }
245 const any* valuePtr = &a;
246 do {
247 const any& value = (*valuePtr->t)(unthunk);
248 if (value.type != Type::Thunk) {
249 return value;
250 }
251 valuePtr = &value;
252 } while (valuePtr->type != Type::Unknown);
253 assert(false && "Unknown value type");
254 return a;
257auto any::operator[](const char rhs[]) const -> const any& {
258 const any& val = extractValue(*this);
259 assert(val.type == Type::Map);
260 const any::map::const_iterator begin = val.m->begin();
261 const any::map::const_iterator end = val.m->end();
262 for (any::map::const_iterator it = begin; it != end; ++it) {
263 if (it->first == rhs) {
264 return it->second;
265 }
266 }
267 for (any::map::const_iterator it = begin; it != end; ++it) {
268 if (strcmp(it->first, rhs) == 0) {
269 return it->second;
270 }
271 }
272 throw runtime_error("map key not found");
275auto any::operator[](const vector::size_type rhs) const -> const any& {
276 const any& val = extractValue(*this);
277 assert(val.type == Type::Vector);
278 return (*val.v)[rhs];
281auto any::operator[](const any& rhs) const -> const any& {
282 const any& val = extractValue(*this);
283 assert(val.type == Type::Vector);
284 return (*val.v)[rhs.cast<long>()];
287auto any::contains(const char key[]) const -> bool {
288 const any& val = extractValue(*this);
289 assert(val.type == Type::Map);
290 for (any::map::const_iterator it = val.m->begin(), end = val.m->end(); it != end; ++it) {
291 if (it->first == key || strcmp(it->first, key) == 0) {
292 return true;
293 }
294 }
295 return false;
298//-----------------------------------------------------------------------------
299// Operator helper macros
300//-----------------------------------------------------------------------------
302#define DEFINE_OPERATOR(op, ty, rty) \
303auto operator op (const any& lhs, ty rhs) -> rty { \
304 return lhs.cast<typename std::remove_const<std::remove_reference<ty>::type>::type>() op rhs; \
305} \
306auto operator op (ty lhs, const any& rhs) -> rty { \
307 return lhs op rhs.cast<typename std::remove_const<std::remove_reference<ty>::type>::type>(); \
310#define DEFINE_CSTR_EQUALS_OPERATOR() \
311 auto operator==(const any& lhs_, const char * rhs) -> bool { \
312 const any& lhs = any::extractValue(lhs_); \
313 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
314 if (lhs.type == any::Type::StringLiteral) { \
315 return (lhs.r == rhs) || (strcmp(lhs.r, rhs) == 0); \
316 } \
317 return strcmp(lhs.s->c_str(), rhs) == 0; \
318 } \
319 auto operator==(const char * lhs, const any& rhs_) -> bool { \
320 const any& rhs = any::extractValue(rhs_); \
321 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
322 if (rhs.type == any::Type::StringLiteral) { \
323 return (lhs == rhs.r) || (strcmp(lhs, rhs) == 0); \
324 } \
325 return strcmp(lhs, rhs.s->c_str()) == 0; \
326 }
328#define DEFINE_CSTR_COMPARISON_OPERATOR(op) \
329 auto operator op (const any& lhs, const char * rhs) -> bool { \
330 return strcmp(lhs.cast<string>(), rhs) op 0; \
331 } \
332 auto operator op (const char * lhs, const any& rhs) -> bool { \
333 return strcmp(lhs, rhs.cast<string>()) op 0; \
334 }
336#define DEFINE_COMPARISON_OPERATOR(op) \
337 auto operator op (const any& lhs_, const any& rhs_) -> bool { \
338 const any& lhs = any::extractValue(lhs_); \
339 const any& rhs = any::extractValue(rhs_); \
340 switch (lhs.type) { \
341 case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i op rhs.i; \
342 case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d op rhs.d; \
343 case any::Type::Character: assert(lhs.type == any::Type::Character); return lhs.c op rhs.c; \
344 case any::Type::Boolean: assert(lhs.type == any::Type::Boolean); return lhs.b op rhs.b; \
345 case any::Type::StringLiteral: \
346 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
347 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
348 return strcmp(lhs.r, rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
349 case any::Type::String: \
350 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
351 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
352 return strcmp(lhs.s->c_str(), rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
353 case any::Type::Pointer: return lhs.p op rhs.p; \
354 default: assert(false && "Unsupported type for operator " #op); \
355 } \
356 return false; \
357 } \
358 DEFINE_OPERATOR(op, long, bool) \
359 DEFINE_OPERATOR(op, double, bool) \
360 DEFINE_OPERATOR(op, char, bool) \
361 DEFINE_OPERATOR(op, bool, bool) \
363//-----------------------------------------------------------------------------
364// Operator definitions
365//-----------------------------------------------------------------------------
367DEFINE_COMPARISON_OPERATOR(==)
368DEFINE_COMPARISON_OPERATOR(!=)
369DEFINE_COMPARISON_OPERATOR(<)
370DEFINE_COMPARISON_OPERATOR(<=)
371DEFINE_COMPARISON_OPERATOR(>)
372DEFINE_COMPARISON_OPERATOR(>=)
374DEFINE_CSTR_EQUALS_OPERATOR()
375DEFINE_CSTR_COMPARISON_OPERATOR(!=)
376DEFINE_CSTR_COMPARISON_OPERATOR(<)
377DEFINE_CSTR_COMPARISON_OPERATOR(<=)
378DEFINE_CSTR_COMPARISON_OPERATOR(>)
379DEFINE_CSTR_COMPARISON_OPERATOR(>=)
381auto operator+(const any& lhs_, const any& rhs_) -> any {
382 const any& lhs = any::extractValue(lhs_);
383 const any& rhs = any::extractValue(rhs_);
384 switch (lhs.type) {
385 case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i + rhs.i;
386 case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d + rhs.d;
387 case any::Type::Character: assert(lhs.type == any::Type::Character); return any(char(lhs.c + rhs.c));
388 case any::Type::StringLiteral:
389 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
390 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
391 return rhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs.r : lhs.r + *rhs.s;
392 case any::Type::String:
393 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
394 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
395 return rhs.type == any::Type::StringLiteral ? *lhs.s + rhs.r : *lhs.s + *rhs.s;
396 default: assert(false && "Unsupported type for '+' operator");
397 }
398 return nullptr;
401DEFINE_OPERATOR(+, long, long)
402DEFINE_OPERATOR(+, double, double)
403DEFINE_OPERATOR(+, char, char)
405auto operator+(const any& lhs_, const char * rhs) -> std::string {
406 const any& lhs = any::extractValue(lhs_);
407 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
408 return lhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs : *lhs.s + rhs;
411auto operator+(const char * lhs, const any& rhs_) -> std::string {
412 const any& rhs = any::extractValue(rhs_);
413 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
414 return rhs.type == any::Type::StringLiteral ? lhs + std::string(rhs.r) : lhs + *rhs.s;
417auto operator-(const any& lhs_, const any& rhs_) -> any {
418 const any& lhs = any::extractValue(lhs_);
419 const any& rhs = any::extractValue(rhs_);
420 assert(lhs.type == rhs.type);
421 switch (lhs.type) {
422 case any::Type::Integer: return lhs.i - rhs.i;
423 case any::Type::Double: return lhs.d - rhs.d;
424 case any::Type::Character: return any(char(lhs.c - rhs.c));
425 default: assert(false && "Unsupported type for '-' operator");
426 }
427 return nullptr;
430DEFINE_OPERATOR(-, long, long)
431DEFINE_OPERATOR(-, double, double)
432DEFINE_OPERATOR(-, char, char)
434auto operator*(const any& lhs_, const any& rhs_) -> any {
435 const any& lhs = any::extractValue(lhs_);
436 const any& rhs = any::extractValue(rhs_);
437 assert(lhs.type == rhs.type);
438 switch (lhs.type) {
439 case any::Type::Integer: return lhs.i * rhs.i;
440 case any::Type::Double: return lhs.d * rhs.d;
441 case any::Type::Character: return any(char(lhs.c * rhs.c));
442 default: assert(false && "Unsupported type for '*' operator");
443 }
444 return nullptr;
447DEFINE_OPERATOR(*, long, long)
448DEFINE_OPERATOR(*, double, double)
449DEFINE_OPERATOR(*, char, char)
451auto operator/(const any& lhs_, const any& rhs_) -> any {
452 const any& lhs = any::extractValue(lhs_);
453 const any& rhs = any::extractValue(rhs_);
454 assert(lhs.type == rhs.type);
455 switch (lhs.type) {
456 case any::Type::Integer: return lhs.i / rhs.i;
457 case any::Type::Double: return lhs.d / rhs.d;
458 case any::Type::Character: return any(char(lhs.c / rhs.c));
459 default: assert(false && "Unsupported type for '/' operator");
460 }
461 return nullptr;
464DEFINE_OPERATOR(/, long, long)
465DEFINE_OPERATOR(/, double, double)
466DEFINE_OPERATOR(/, char, char)
468auto operator%(const any& lhs_, const any& rhs_) -> any {
469 const any& lhs = any::extractValue(lhs_);
470 const any& rhs = any::extractValue(rhs_);
471 assert(lhs.type == rhs.type);
472 switch (lhs.type) {
473 case any::Type::Integer: return lhs.i % rhs.i;
474 case any::Type::Character: return any(char(lhs.c % rhs.c));
475 default: assert(false && "Unsupported type for '%' operator");
476 }
477 return nullptr;
480DEFINE_OPERATOR(%, long, long)
481DEFINE_OPERATOR(%, char, char)
483// unary negate
484auto operator-(const any& rhs_) -> any {
485 const any& rhs = any::extractValue(rhs_);
486 switch (rhs.type) {
487 case any::Type::Integer: return (- rhs.i);
488 case any::Type::Double: return (- rhs.d);
489 default: assert(false && "Unsupported type for unary '-' operator");
490 }
491 return nullptr;
494} // namespace PureScript