git.iko.soy/rowtype-yoga/purescript-native
on ecb97a7 help sign in
225 lines 7.3 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 {
20any::Closure::~Closure() {}
21any::EffClosure::~EffClosure() {}
23#define RETURN_VALUE(TAG, ACCESSOR, INDIRECTION) \
24 const any& variant = unthunkVariant(*this); \
25 assert(variant.tag == TAG); \
26 return INDIRECTION(variant.ACCESSOR); \
28auto any::operator()(const any& arg) const -> any {
29 const any& variant = unthunkVariant(*this);
30 if (variant.tag == Tag::Closure) {
31 return (*variant.l)(arg);
32 }
33 assert(variant.tag == Tag::Function);
34 return (*variant.f)(arg);
37auto any::operator()(const as_thunk) const -> const any& {
38 assert(tag == Tag::Thunk);
39 return (*t)(unthunk);
42auto any::operator()() const -> any {
43 const any& variant = unthunkVariant(*this);
44 if (variant.tag == Tag::EffClosure) {
45 return (*variant.k)();
46 }
47 assert(variant.tag == Tag::EffFunction);
48 return (*variant.e)();
51any::operator int() const {
52 RETURN_VALUE(Tag::Integer, i,)
55any::operator double() const {
56 RETURN_VALUE(Tag::Double, d,)
59any::operator bool() const {
60 RETURN_VALUE(Tag::Boolean, b,)
63any::operator char32_t() const {
64 RETURN_VALUE(Tag::Character, c,)
67any::operator char() const {
68 const auto val = static_cast<decltype(c)>(*this);
69 assert(val <= std::numeric_limits<char>::max());
70 return static_cast<char>(val);
73any::operator size_t() const {
74 const auto val = static_cast<decltype(i)>(*this);
75 assert(val >= 0);
76 return static_cast<size_t>(val);
79any::operator const string&() const {
80 RETURN_VALUE(Tag::String, s, *)
83any::operator const char *() const {
84 RETURN_VALUE(Tag::String, s->c_str(),)
87any::operator const array&() const {
88 RETURN_VALUE(Tag::Array, a, *)
91auto any::extractPointer(IF_DEBUG(const any::Tag t)) const -> void* {
92 RETURN_VALUE(t, POINTER_FROM_MEMBER(p),)
95auto any::unthunkVariant(const any& a) -> const any& {
96 const any * variant = &a;
97 while (variant->tag == Tag::Thunk) {
98 variant = &((*variant->t)(unthunk));
99 }
100 return *variant;
103auto any::operator[](const size_t rhs) const -> const any& {
104 const auto& xs = static_cast<const array&>(*this);
105 return xs[rhs];
108auto any::size() const -> size_t {
109 return static_cast<const array&>(*this).size();
112auto any::empty() const -> bool {
113 return static_cast<const array&>(*this).empty();
116auto any::contains(const Private::Symbol key) const -> bool {
117 // TODO: assumes at least one element -- safe assumption?
118 const auto& m = cast<map<unknown_size>>(*this);
119 std::remove_reference<decltype(m)>::type::size_type i = 0;
120 do {
121 if (m[i].first == key) {
122 return true;
123 }
124 } while (m[++i].first != nullptr);
125 return false;
128//-----------------------------------------------------------------------------
129// Operator helper macros
130//-----------------------------------------------------------------------------
132#define DEFINE_COMPARISON_OPERATOR(op) \
133 auto operator op (const any& lhs_, const any& rhs) -> bool { \
134 const any& lhs = any::unthunkVariant(lhs_); \
135 switch (lhs.tag) { \
136 case any::Tag::Integer: return lhs.i op static_cast<decltype(any::i)>(rhs); \
137 case any::Tag::Double: return lhs.d op static_cast<decltype(any::d)>(rhs); \
138 case any::Tag::Character: return lhs.c op static_cast<decltype(any::c)>(rhs); \
139 case any::Tag::Boolean: return lhs.b op static_cast<decltype(any::b)>(rhs); \
140 case any::Tag::String: return *lhs.s op static_cast<const string&>(rhs); \
141 case any::Tag::RawPointer: return lhs.v op cast<decltype(any::v)>(rhs); \
142 case any::Tag::Pointer: return lhs.p op any::unthunkVariant(rhs).p; \
143 default: assert(false && "Unsupported tag for operator " #op); \
144 } \
145 return false; \
146 }
148//-----------------------------------------------------------------------------
149// Operator definitions
150//-----------------------------------------------------------------------------
152DEFINE_COMPARISON_OPERATOR(==)
153DEFINE_COMPARISON_OPERATOR(!=)
154DEFINE_COMPARISON_OPERATOR(<)
155DEFINE_COMPARISON_OPERATOR(<=)
156DEFINE_COMPARISON_OPERATOR(>)
157DEFINE_COMPARISON_OPERATOR(>=)
159auto operator+(const any& lhs_, const any& rhs) -> any {
160 const any& lhs = any::unthunkVariant(lhs_);
161 switch (lhs.tag) {
162 case any::Tag::Integer: return lhs.i + static_cast<decltype(any::i)>(rhs);
163 case any::Tag::Double: return lhs.d + static_cast<decltype(any::d)>(rhs);
164 case any::Tag::Character: return decltype(any::c){lhs.c + static_cast<decltype(any::c)>(rhs)};
165 case any::Tag::String: return *lhs.s + static_cast<const string&>(rhs);
166 default: assert(false && "Unsupported tag for '+' operator");
167 }
168 return nullptr;
171auto operator-(const any& lhs_, const any& rhs) -> any {
172 const any& lhs = any::unthunkVariant(lhs_);
173 switch (lhs.tag) {
174 case any::Tag::Integer: return lhs.i - static_cast<decltype(any::i)>(rhs);
175 case any::Tag::Double: return lhs.d - static_cast<decltype(any::d)>(rhs);
176 case any::Tag::Character: return decltype(any::c){lhs.c - static_cast<decltype(any::c)>(rhs)};
177 default: assert(false && "Unsupported tag for '-' operator");
178 }
179 return nullptr;
182auto operator*(const any& lhs_, const any& rhs) -> any {
183 const any& lhs = any::unthunkVariant(lhs_);
184 switch (lhs.tag) {
185 case any::Tag::Integer: return lhs.i * static_cast<decltype(any::i)>(rhs);
186 case any::Tag::Double: return lhs.d * static_cast<decltype(any::d)>(rhs);
187 case any::Tag::Character: return decltype(lhs.c){lhs.c - static_cast<decltype(any::c)>(rhs)};
188 default: assert(false && "Unsupported tag for '*' operator");
189 }
190 return nullptr;
193auto operator/(const any& lhs_, const any& rhs) -> any {
194 const any& lhs = any::unthunkVariant(lhs_);
195 switch (lhs.tag) {
196 case any::Tag::Integer: return lhs.i / static_cast<decltype(any::i)>(rhs);
197 case any::Tag::Double: return lhs.d / static_cast<decltype(any::d)>(rhs);
198 case any::Tag::Character: return decltype(any::c){lhs.c / static_cast<decltype(any::c)>(rhs)};
199 default: assert(false && "Unsupported tag for '/' operator");
200 }
201 return nullptr;
204auto operator%(const any& lhs_, const any& rhs) -> any {
205 const any& lhs = any::unthunkVariant(lhs_);
206 switch (lhs.tag) {
207 case any::Tag::Integer: return lhs.i % static_cast<decltype(any::i)>(rhs);
208 case any::Tag::Character: return decltype(any::c){lhs.c % static_cast<decltype(any::c)>(rhs)};
209 default: assert(false && "Unsupported tag for '%' operator");
210 }
211 return nullptr;
214// unary negate
215auto operator-(const any& rhs_) -> any {
216 const any& rhs = any::unthunkVariant(rhs_);
217 switch (rhs.tag) {
218 case any::Tag::Integer: return (- rhs.i);
219 case any::Tag::Double: return (- rhs.d);
220 default: assert(false && "Unsupported tag for unary '-' operator");
221 }
222 return nullptr;
225} // namespace PureScript