git.iko.soy/rowtype-yoga/purescript-native
on b64dad8 help sign in
382 lines 13 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); \
25template <typename T>
26auto any::cast() const -> typename std::enable_if<std::is_same<T, long>::value, T>::type {
27 RETURN_VALUE(Type::Integer, i,)
29template auto any::cast<long>() const -> long;
31template <typename T>
32auto any::cast() const -> typename std::enable_if<std::is_same<T, double>::value, T>::type {
33 RETURN_VALUE(Type::Double, d,)
35template auto any::cast<double>() const -> double;
37template <typename T>
38auto any::cast() const -> typename std::enable_if<std::is_same<T, char>::value, T>::type {
39 RETURN_VALUE(Type::Character, c,)
41template auto any::cast<char>() const -> char;
43template <typename T>
44auto any::cast() const -> typename std::enable_if<std::is_same<T, bool>::value, T>::type {
45 RETURN_VALUE(Type::Boolean, b,)
47template auto any::cast<bool>() const -> bool;
49template <typename T>
50auto any::cast() const -> typename std::enable_if<std::is_same<T, string>::value, T>::type {
51 const any& variant = unthunkVariant(*this);
52 if (variant.type == Type::StringLiteral) {
53 return variant.r;
54 }
55 assert(variant.type == Type::String);
56 return variant.s->c_str();
58template auto any::cast<string>() const -> string;
60template <typename T>
61auto any::cast() const -> typename std::enable_if<std::is_same<T, map>::value, const T&>::type {
62 RETURN_VALUE(Type::Map, m, *)
64template auto any::cast<any::map>() const -> const map&;
66template <typename T>
67auto any::cast() const -> typename std::enable_if<std::is_same<T, data>::value, const T&>::type {
68 RETURN_VALUE(Type::Data, v, *)
70template auto any::cast<any::data>() const -> const data&;
72template <typename T>
73auto any::cast() const -> typename std::enable_if<std::is_same<T, array>::value, const T&>::type {
74 RETURN_VALUE(Type::Array, a, *)
76template auto any::cast<any::array>() const -> const array&;
78auto any::operator()(const any& arg) const -> any {
79 const any& variant = unthunkVariant(*this);
80 if (variant.type == Type::Closure) {
81 return (*variant.l)(arg);
82 }
83 assert(variant.type == Type::Function);
84 return (*variant.f)(arg);
87auto any::operator()(const as_thunk) const -> const any& {
88 assert(type == Type::Thunk);
89 return (*t)(unthunk);
92auto any::operator()() const -> any {
93 const any& variant = unthunkVariant(*this);
94 assert(variant.type == Type::EffFunction);
95 return (*variant.e)();
98any::operator long() const {
99 return cast<long>();
102any::operator double() const {
103 return cast<double>();
106any::operator bool() const {
107 return cast<bool>();
110any::operator string() const {
111 return cast<string>();
114any::operator const map&() const {
115 return cast<map>();
118any::operator const data&() const {
119 return cast<data>();
122any::operator const array&() const {
123 return cast<array>();
126auto any::extractPointer() const -> void* {
127 RETURN_VALUE(Type::Pointer, p.get(),)
130auto any::unthunkVariant(const any& a) -> const any& {
131 const any * variant = &a;
132 while (variant->type == Type::Thunk) {
133 variant = &((*variant->t)(unthunk));
134 }
135 return *variant;
138auto any::operator[](const char rhs[]) const -> const any& {
139 const any& variant = unthunkVariant(*this);
140 assert(variant.type == Type::Map);
141 const auto begin = variant.m->cbegin();
142 const auto end = variant.m->cend();
143 for (auto it = begin; it != end; ++it) {
144 if (it->first == rhs) {
145 return it->second;
146 }
147 }
148 for (auto it = begin; it != end; ++it) {
149 if (strcmp(it->first, rhs) == 0) {
150 return it->second;
151 }
152 }
153 throw runtime_error("map key not found");
156auto any::operator[](const size_t rhs) const -> const any& {
157 const any& variant = unthunkVariant(*this);
158 assert(variant.type == Type::Array);
159 return (*variant.a)[rhs];
162auto any::operator[](const any& rhs) const -> const any& {
163 const any& variant = unthunkVariant(*this);
164 assert(variant.type == Type::Array);
165 return (*variant.a)[rhs.cast<long>()];
168auto any::contains(const char key[]) const -> bool {
169 const any& variant = unthunkVariant(*this);
170 assert(variant.type == Type::Map);
171 const auto begin = variant.m->cbegin();
172 const auto end = variant.m->cend();
173 for (auto it = begin; it != end; ++it) {
174 if (it->first == key) {
175 return true;
176 }
177 }
178 for (auto it = begin; it != end; ++it) {
179 if (strcmp(it->first, key) == 0) {
180 return true;
181 }
182 }
183 return false;
186//-----------------------------------------------------------------------------
187// Operator helper macros
188//-----------------------------------------------------------------------------
190#define DEFINE_OPERATOR(op, ty, rty) \
191auto operator op (const any& lhs, ty rhs) -> rty { \
192 return lhs.cast<typename std::remove_const<std::remove_reference<ty>::type>::type>() op rhs; \
193} \
194auto operator op (ty lhs, const any& rhs) -> rty { \
195 return lhs op rhs.cast<typename std::remove_const<std::remove_reference<ty>::type>::type>(); \
198#define DEFINE_CSTR_EQUALS_OPERATOR() \
199 auto operator==(const any& lhs_, const char * rhs) -> bool { \
200 const any& lhs = any::unthunkVariant(lhs_); \
201 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
202 if (lhs.type == any::Type::StringLiteral) { \
203 return (lhs.r == rhs) || (strcmp(lhs.r, rhs) == 0); \
204 } \
205 return strcmp(lhs.s->c_str(), rhs) == 0; \
206 } \
207 auto operator==(const char * lhs, const any& rhs_) -> bool { \
208 const any& rhs = any::unthunkVariant(rhs_); \
209 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
210 if (rhs.type == any::Type::StringLiteral) { \
211 return (lhs == rhs.r) || (strcmp(lhs, rhs) == 0); \
212 } \
213 return strcmp(lhs, rhs.s->c_str()) == 0; \
214 }
216#define DEFINE_CSTR_COMPARISON_OPERATOR(op) \
217 auto operator op (const any& lhs, const char * rhs) -> bool { \
218 return strcmp(lhs.cast<string>(), rhs) op 0; \
219 } \
220 auto operator op (const char * lhs, const any& rhs) -> bool { \
221 return strcmp(lhs, rhs.cast<string>()) op 0; \
222 }
224#define DEFINE_COMPARISON_OPERATOR(op) \
225 auto operator op (const any& lhs_, const any& rhs_) -> bool { \
226 const any& lhs = any::unthunkVariant(lhs_); \
227 const any& rhs = any::unthunkVariant(rhs_); \
228 switch (lhs.type) { \
229 case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i op rhs.i; \
230 case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d op rhs.d; \
231 case any::Type::Character: assert(lhs.type == any::Type::Character); return lhs.c op rhs.c; \
232 case any::Type::Boolean: assert(lhs.type == any::Type::Boolean); return lhs.b op rhs.b; \
233 case any::Type::StringLiteral: \
234 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
235 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
236 return strcmp(lhs.r, rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
237 case any::Type::String: \
238 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String); \
239 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String); \
240 return strcmp(lhs.s->c_str(), rhs.type == any::Type::StringLiteral ? rhs.r : rhs.s->c_str()) op 0; \
241 case any::Type::Pointer: return lhs.p op rhs.p; \
242 default: assert(false && "Unsupported type for operator " #op); \
243 } \
244 return false; \
245 } \
246 DEFINE_OPERATOR(op, long, bool) \
247 DEFINE_OPERATOR(op, double, bool) \
248 DEFINE_OPERATOR(op, char, bool) \
249 DEFINE_OPERATOR(op, bool, bool) \
251//-----------------------------------------------------------------------------
252// Operator definitions
253//-----------------------------------------------------------------------------
255DEFINE_COMPARISON_OPERATOR(==)
256DEFINE_COMPARISON_OPERATOR(!=)
257DEFINE_COMPARISON_OPERATOR(<)
258DEFINE_COMPARISON_OPERATOR(<=)
259DEFINE_COMPARISON_OPERATOR(>)
260DEFINE_COMPARISON_OPERATOR(>=)
262DEFINE_CSTR_EQUALS_OPERATOR()
263DEFINE_CSTR_COMPARISON_OPERATOR(!=)
264DEFINE_CSTR_COMPARISON_OPERATOR(<)
265DEFINE_CSTR_COMPARISON_OPERATOR(<=)
266DEFINE_CSTR_COMPARISON_OPERATOR(>)
267DEFINE_CSTR_COMPARISON_OPERATOR(>=)
269auto operator+(const any& lhs_, const any& rhs_) -> any {
270 const any& lhs = any::unthunkVariant(lhs_);
271 const any& rhs = any::unthunkVariant(rhs_);
272 switch (lhs.type) {
273 case any::Type::Integer: assert(lhs.type == any::Type::Integer); return lhs.i + rhs.i;
274 case any::Type::Double: assert(lhs.type == any::Type::Double); return lhs.d + rhs.d;
275 case any::Type::Character: assert(lhs.type == any::Type::Character); return any(char(lhs.c + rhs.c));
276 case any::Type::StringLiteral:
277 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
278 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
279 return rhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs.r : lhs.r + *rhs.s;
280 case any::Type::String:
281 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
282 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
283 return rhs.type == any::Type::StringLiteral ? *lhs.s + rhs.r : *lhs.s + *rhs.s;
284 default: assert(false && "Unsupported type for '+' operator");
285 }
286 return nullptr;
289DEFINE_OPERATOR(+, long, long)
290DEFINE_OPERATOR(+, double, double)
291DEFINE_OPERATOR(+, char, char)
293auto operator+(const any& lhs_, const char * rhs) -> std::string {
294 const any& lhs = any::unthunkVariant(lhs_);
295 assert(lhs.type == any::Type::StringLiteral || lhs.type == any::Type::String);
296 return lhs.type == any::Type::StringLiteral ? std::string(lhs.r) + rhs : *lhs.s + rhs;
299auto operator+(const char * lhs, const any& rhs_) -> std::string {
300 const any& rhs = any::unthunkVariant(rhs_);
301 assert(rhs.type == any::Type::StringLiteral || rhs.type == any::Type::String);
302 return rhs.type == any::Type::StringLiteral ? lhs + std::string(rhs.r) : lhs + *rhs.s;
305auto operator-(const any& lhs_, const any& rhs_) -> any {
306 const any& lhs = any::unthunkVariant(lhs_);
307 const any& rhs = any::unthunkVariant(rhs_);
308 assert(lhs.type == rhs.type);
309 switch (lhs.type) {
310 case any::Type::Integer: return lhs.i - rhs.i;
311 case any::Type::Double: return lhs.d - rhs.d;
312 case any::Type::Character: return any(char(lhs.c - rhs.c));
313 default: assert(false && "Unsupported type for '-' operator");
314 }
315 return nullptr;
318DEFINE_OPERATOR(-, long, long)
319DEFINE_OPERATOR(-, double, double)
320DEFINE_OPERATOR(-, char, char)
322auto operator*(const any& lhs_, const any& rhs_) -> any {
323 const any& lhs = any::unthunkVariant(lhs_);
324 const any& rhs = any::unthunkVariant(rhs_);
325 assert(lhs.type == rhs.type);
326 switch (lhs.type) {
327 case any::Type::Integer: return lhs.i * rhs.i;
328 case any::Type::Double: return lhs.d * rhs.d;
329 case any::Type::Character: return any(char(lhs.c * rhs.c));
330 default: assert(false && "Unsupported type for '*' operator");
331 }
332 return nullptr;
335DEFINE_OPERATOR(*, long, long)
336DEFINE_OPERATOR(*, double, double)
337DEFINE_OPERATOR(*, char, char)
339auto operator/(const any& lhs_, const any& rhs_) -> any {
340 const any& lhs = any::unthunkVariant(lhs_);
341 const any& rhs = any::unthunkVariant(rhs_);
342 assert(lhs.type == rhs.type);
343 switch (lhs.type) {
344 case any::Type::Integer: return lhs.i / rhs.i;
345 case any::Type::Double: return lhs.d / rhs.d;
346 case any::Type::Character: return any(char(lhs.c / rhs.c));
347 default: assert(false && "Unsupported type for '/' operator");
348 }
349 return nullptr;
352DEFINE_OPERATOR(/, long, long)
353DEFINE_OPERATOR(/, double, double)
354DEFINE_OPERATOR(/, char, char)
356auto operator%(const any& lhs_, const any& rhs_) -> any {
357 const any& lhs = any::unthunkVariant(lhs_);
358 const any& rhs = any::unthunkVariant(rhs_);
359 assert(lhs.type == rhs.type);
360 switch (lhs.type) {
361 case any::Type::Integer: return lhs.i % rhs.i;
362 case any::Type::Character: return any(char(lhs.c % rhs.c));
363 default: assert(false && "Unsupported type for '%' operator");
364 }
365 return nullptr;
368DEFINE_OPERATOR(%, long, long)
369DEFINE_OPERATOR(%, char, char)
371// unary negate
372auto operator-(const any& rhs_) -> any {
373 const any& rhs = any::unthunkVariant(rhs_);
374 switch (rhs.type) {
375 case any::Type::Integer: return (- rhs.i);
376 case any::Type::Double: return (- rhs.d);
377 default: assert(false && "Unsupported type for unary '-' operator");
378 }
379 return nullptr;
382} // namespace PureScript