Last active
August 26, 2023 08:18
-
-
Save ajnsit/c7d5fb74312afd22753c991ab5d0328e to your computer and use it in GitHub Desktop.
Purescript to C++ compiler runtime from - https://github.com/andyarvanitis/purescript-native/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// Module : dictionary.h | |
// Copyright : (c) Andy Arvanitis 2018 | |
// License : BSD | |
// | |
// Maintainer : Andy Arvanitis | |
// Stability : experimental | |
// Portability : | |
// | |
// A simple dictionary optimized for this runtime's particular use – | |
// *not* intended for general use or as a replacement for containers | |
// such as std::map or std::unordered_map. It relies on the following | |
// assumptions: | |
// | |
// 1) Keys are C-type string literals. No copying or (memory management) | |
// of the keys occurs | |
// 2) The number of elements in the container is generally small – say, | |
// under 20. There is no sorting and a linear search is used to | |
// locate elements | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
#ifndef purescript_dictionary_H | |
#define purescript_dictionary_H | |
#include <cstring> | |
#include <vector> | |
#include <utility> | |
#if !defined(NDEBUG) | |
#include <string> | |
#endif | |
namespace purescript { | |
namespace _template_ { | |
template <typename T> | |
class dict_t : public std::vector<std::pair<const char *, T>> { | |
static auto null() -> const T& { | |
static const T value; | |
return value; | |
} | |
public: | |
using std::vector<std::pair<const char *, T>>::vector; | |
auto operator[](const char key[]) const -> const T& { | |
for (auto it = this->cbegin(), end=this->cend(); it != end; it++) { | |
const auto& elem_key = it->first; | |
if (elem_key == key || !std::strcmp(elem_key, key)) { | |
return it->second; | |
} | |
} | |
#if !defined(NDEBUG) && !defined(PURESCRIPT_DISABLE_EXCEPTIONS) | |
throw std::runtime_error("dictionary key \"" + std::string(key) + "\" not found"); | |
#endif | |
return null(); | |
} | |
auto at(const char key[]) const -> const T& { | |
return (*this)[key]; | |
} | |
auto operator[](const char key[]) -> T& { | |
const auto end = this->end(); | |
for (auto it = this->begin(); it != end; it++) { | |
const auto& elem_key = it->first; | |
if (elem_key == key || !std::strcmp(elem_key, key)) { | |
return it->second; | |
} | |
} | |
return this->emplace(end, key, T())->second; | |
} | |
auto contains(const char key[]) const -> bool { | |
for (auto it = this->cbegin(), end=this->cend(); it != end; it++) { | |
const auto& elem_key = it->first; | |
if (elem_key == key || !std::strcmp(elem_key, key)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
}; | |
} // namespace _template_ | |
} // namespace purescript | |
#endif // purescript_dictionary_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// Module : functions.h | |
// Copyright : (c) Andy Arvanitis 2019 | |
// License : BSD | |
// | |
// Maintainer : Andy Arvanitis | |
// Stability : experimental | |
// Portability : | |
// | |
// Runtime function types (for regular functions and lambdas) | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
#ifndef purescript_functions_H | |
#define purescript_functions_H | |
namespace purescript { | |
namespace _template_ { | |
template <typename T> | |
class fn_t { | |
public: | |
virtual ~fn_t() {} | |
virtual auto operator ()(const T&) const -> T = 0; | |
}; | |
template <typename T, typename U> | |
class fn_T : public fn_t<T> { | |
U fn; | |
public: | |
fn_T(U&& f) noexcept : fn(std::move(f)) {} | |
auto operator ()(const T& arg) const -> T override { | |
return fn(arg); | |
} | |
}; | |
template <typename T> | |
class eff_fn_t { | |
public: | |
virtual ~eff_fn_t() {} | |
virtual auto operator ()() const -> T = 0; | |
}; | |
template <typename T, typename U> | |
class eff_fn_T : public eff_fn_t<T> { | |
U fn; | |
public: | |
eff_fn_T(U&& f) noexcept : fn(std::move(f)) {} | |
auto operator ()() const -> T override { | |
return fn(); | |
} | |
}; | |
} // namespace _template_ | |
} // namespace purescript | |
#endif // purescript_functions_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// Module : purescript.cpp | |
// Copyright : (c) Andy Arvanitis 2019 | |
// License : BSD | |
// | |
// Maintainer : Andy Arvanitis | |
// Stability : experimental | |
// Portability : | |
// | |
// Basic types and functions to support purescript-to-C++ rendering | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
#include "purescript.h" | |
namespace purescript { | |
template class _template_::fn_t<boxed>; | |
template class _template_::eff_fn_t<boxed>; | |
template class _template_::dict_t<boxed>; | |
template class _template_::weak<boxed>; | |
template class _template_::recur<boxed>; | |
boxed::boxed(const long n) : _int_(static_cast<int>(n)) { | |
#if !defined(NDEBUG) && !defined(PURESCRIPT_DISABLE_EXCEPTIONS) | |
if (n < std::numeric_limits<int>::min() || n > std::numeric_limits<int>::max()) { | |
throw std::runtime_error("integer out of range"); | |
} | |
#endif | |
} | |
boxed::boxed(const unsigned long n) : _int_(static_cast<int>(n)) { | |
#if !defined(NDEBUG) && !defined(PURESCRIPT_DISABLE_EXCEPTIONS) | |
if (n > std::numeric_limits<int>::max()) { | |
throw std::runtime_error("integer out of range"); | |
} | |
#endif | |
} | |
auto boxed::operator[](const int index) const -> const boxed& { | |
#if !defined(NDEBUG) | |
return static_cast<const array_t*>(shared.get())->at(index); | |
#else | |
return (*static_cast<const array_t*>(shared.get()))[index]; | |
#endif | |
} | |
auto boxed::operator[](const int index) -> boxed& { | |
#if !defined(NDEBUG) | |
return static_cast<array_t*>(shared.get())->at(index); | |
#else | |
return (*static_cast<array_t*>(shared.get()))[index]; | |
#endif | |
} | |
const boxed undefined; | |
} // namespace purescript |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// Module : purescript.h | |
// Copyright : (c) Andy Arvanitis 2018 | |
// License : BSD | |
// | |
// Maintainer : Andy Arvanitis | |
// Stability : experimental | |
// Portability : | |
// | |
// Basic types and functions to support purescript-to-C++ rendering | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
#ifndef purescript_H | |
#define purescript_H | |
#include <memory> | |
#include <vector> | |
#include <string> | |
#include <utility> | |
#if !defined(NDEBUG) | |
#include <limits> | |
#endif | |
#if !defined(PURESCRIPT_DISABLE_EXCEPTIONS) | |
#include <stdexcept> | |
#endif | |
#include "functions.h" | |
#include "dictionary.h" | |
#include "recursion.h" | |
namespace purescript { | |
using std::string; | |
class boxed { | |
public: | |
std::shared_ptr<void> shared; | |
union { | |
int _int_; | |
double _double_; | |
bool _bool_; | |
}; | |
public: | |
using fn_t = _template_::fn_t<boxed>; | |
using eff_fn_t = _template_::eff_fn_t<boxed>; | |
using dict_t = _template_::dict_t<boxed>; | |
using array_t = std::vector<boxed>; | |
using weak = _template_::weak<boxed>; | |
using recur = _template_::recur<boxed>; | |
private: | |
template <typename T> | |
using fn_T = _template_::fn_T<boxed, T>; | |
template <typename T> | |
using eff_fn_T = _template_::eff_fn_T<boxed, T>; | |
public: | |
boxed() noexcept : shared() {} | |
boxed(const std::nullptr_t) noexcept : shared() {} | |
boxed(const weak& w) : shared(w.shared()) {} | |
boxed(const recur& r) : shared(r.shared()) {} | |
boxed(const recur::weak& w) : shared(w.shared()) {} | |
template <typename T> | |
boxed(std::shared_ptr<T>&& other) noexcept : shared(std::move(other)) {} | |
template <typename T> | |
boxed(const std::shared_ptr<T>& other) : shared(other) {} | |
boxed(const int n) noexcept : _int_(n) {} | |
boxed(const long n); | |
boxed(const unsigned long n); | |
boxed(const double n) noexcept : _double_(n) {} | |
boxed(const bool b) noexcept : _bool_(b) {} | |
boxed(const char s[]) : shared(std::make_shared<string>(s)) {} | |
boxed(string&& s) : shared(std::make_shared<string>(std::move(s))) {} | |
boxed(const string& s) : shared(std::make_shared<string>(s)) {} | |
boxed(array_t&& l) : shared(std::make_shared<array_t>(std::move(l))) {} | |
boxed(const array_t& l) : shared(std::make_shared<array_t>(l)) {} | |
boxed(dict_t&& m) : shared(std::make_shared<dict_t>(std::move(m))) {} | |
boxed(const dict_t& m) : shared(std::make_shared<dict_t>(m)) {} | |
template <typename T, | |
typename U = typename std::remove_reference<T>::type, | |
typename V = typename std::remove_const<U>::type, | |
typename = typename std::enable_if<!std::is_same<boxed,V>::value && !std::is_same<recur,V>::value>::type> | |
boxed(T&& f, | |
typename std::enable_if<std::is_same<decltype(std::declval<U>()(std::declval<boxed>())), boxed>::value>::type* = 0) | |
: shared(std::shared_ptr<fn_t>(std::make_shared<fn_T<T>>(std::forward<T>(f)))) { | |
} | |
template <typename T, | |
typename U = typename std::remove_reference<T>::type, | |
typename V = typename std::remove_const<U>::type, | |
typename = typename std::enable_if<!std::is_same<boxed,V>::value && !std::is_same<recur,V>::value>::type> | |
boxed(T&& f, | |
typename std::enable_if<std::is_same<decltype(std::declval<U>()()), boxed>::value>::type* = 0) | |
: shared(std::shared_ptr<eff_fn_t>(std::make_shared<eff_fn_T<T>>(std::forward<T>(f)))) { | |
} | |
auto get() const noexcept -> void * { | |
return shared.get(); | |
} | |
auto operator()(const boxed& arg) const -> boxed { | |
return (*static_cast<fn_t*>(shared.get()))(arg); | |
} | |
auto operator()() const -> boxed { | |
return (*static_cast<eff_fn_t*>(shared.get()))(); | |
} | |
auto operator[](const char key[]) const -> const boxed& { | |
return (*static_cast<const dict_t*>(shared.get()))[key]; | |
} | |
auto operator[](const char key[]) -> boxed& { | |
return (*static_cast<dict_t*>(shared.get()))[key]; | |
} | |
auto operator[](const int index) const -> const boxed&; | |
auto operator[](const int index) -> boxed&; | |
}; // class boxed | |
extern template class _template_::fn_t<boxed>; | |
extern template class _template_::eff_fn_t<boxed>; | |
extern template class _template_::dict_t<boxed>; | |
extern template class _template_::weak<boxed>; | |
extern template class _template_::recur<boxed>; | |
extern const boxed undefined; | |
using fn_t = boxed::fn_t; | |
using eff_fn_t = boxed::eff_fn_t; | |
using dict_t = boxed::dict_t; | |
using array_t = boxed::array_t; | |
template <typename T, typename... Args, | |
typename = typename std::enable_if<!std::is_same<T, int>::value && | |
!std::is_same<T, double>::value && | |
!std::is_same<T, bool>::value | |
>::type> | |
inline auto box(Args&&... args) -> boxed { | |
return std::make_shared<T>(std::forward<Args>(args)...); | |
} | |
template <typename T, | |
typename std::enable_if<std::is_same<T, int>::value, T>::type* = nullptr> | |
inline auto box(T arg) noexcept -> boxed { | |
return boxed(arg); | |
} | |
template <typename T, | |
typename std::enable_if<std::is_same<T, double>::value, T>::type* = nullptr> | |
inline auto box(T arg) noexcept -> boxed { | |
return boxed(arg); | |
} | |
template <typename T, | |
typename std::enable_if<std::is_same<T, bool>::value, T>::type* = nullptr> | |
inline auto box(T arg) noexcept -> boxed { | |
return boxed(arg); | |
} | |
template <typename T, | |
typename = typename std::enable_if<!std::is_same<T, int>::value && | |
!std::is_same<T, double>::value && | |
!std::is_same<T, bool>::value | |
>::type> | |
constexpr auto unbox(const boxed& b) -> const T& { | |
return *static_cast<const T*>(b.get()); | |
} | |
template <typename T, | |
typename std::enable_if<std::is_same<T, int>::value, T>::type* = nullptr> | |
constexpr auto unbox(const boxed& b) noexcept -> T { | |
return b._int_; | |
} | |
template <typename T, | |
typename std::enable_if<std::is_same<T, double>::value, T>::type* = nullptr> | |
constexpr auto unbox(const boxed& b) noexcept -> T { | |
return b._double_; | |
} | |
template <typename T, | |
typename std::enable_if<std::is_same<T, bool>::value, T>::type* = nullptr> | |
constexpr auto unbox(const boxed& b) noexcept -> T { | |
return b._bool_; | |
} | |
template <typename T, | |
typename = typename std::enable_if<!std::is_same<T, int>::value && | |
!std::is_same<T, double>::value && | |
!std::is_same<T, bool>::value | |
>::type> | |
constexpr auto unbox(boxed& b) -> T& { | |
return *static_cast<T*>(b.get()); | |
} | |
template <typename T> | |
constexpr auto unbox(const T value) noexcept -> T { | |
return value; | |
} | |
template <typename T, | |
typename = typename std::enable_if<std::is_same<T, int>::value>::type> | |
constexpr auto unbox(const std::size_t value) noexcept -> long long { | |
return value; | |
} | |
inline auto array_length(const boxed& a) -> boxed::array_t::size_type { | |
return unbox<boxed::array_t>(a).size(); | |
} | |
} // namespace purescript | |
#if !defined(PURESCRIPT_DISABLE_EXCEPTIONS) | |
#define THROW_(s) throw std::runtime_error(s) | |
#else | |
#define THROW_(_) return undefined | |
#endif | |
#define DEFINE_FOREIGN_DICTIONARY_AND_ACCESSOR() \ | |
inline auto foreign() -> dict_t& {\ | |
static dict_t _;\ | |
return _;\ | |
} | |
#define FOREIGN_BEGIN(NS) namespace NS {\ | |
using namespace purescript;\ | |
DEFINE_FOREIGN_DICTIONARY_AND_ACCESSOR()\ | |
static const auto data = ([]() -> char {\ | |
dict_t& exports = foreign(); | |
#define FOREIGN_END return 0; }()); } | |
#endif // purescript_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// Module : recursion.h | |
// Copyright : (c) Andy Arvanitis 2019 | |
// License : BSD | |
// | |
// Maintainer : Andy Arvanitis | |
// Stability : experimental | |
// Portability : | |
// | |
// Runtime types to support recursion | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
#ifndef purescript_recursion_H | |
#define purescript_recursion_H | |
#include <memory> | |
namespace purescript { | |
namespace _template_ { | |
template <typename T> | |
class weak { | |
std::weak_ptr<void> wptr; | |
public: | |
weak() = delete; | |
weak(T& b) : wptr(b.shared) {} | |
auto shared() const -> std::shared_ptr<void> { | |
#if defined(NDEBUG) | |
return wptr.lock(); | |
#else | |
return static_cast<std::shared_ptr<void>>(wptr); | |
#endif | |
} | |
}; // class weak | |
template <typename T> | |
class recur { | |
std::shared_ptr<T> sptr; | |
std::shared_ptr<typename T::weak> wptr; | |
public: | |
recur() : sptr(std::make_shared<T>()) | |
, wptr(std::make_shared<typename T::weak>(*sptr)) {} | |
auto shared() const -> std::shared_ptr<void> { | |
return sptr->shared; | |
} | |
auto operator()() const -> T { | |
return (*sptr)(); | |
} | |
auto operator()(const T& arg) const -> T { | |
return (*sptr)(arg); | |
} | |
template <typename U> | |
auto operator=(U&& right) -> recur& { | |
*sptr = std::forward<U>(right); | |
*wptr = *sptr; | |
return *this; | |
} | |
class weak { | |
std::shared_ptr<typename T::weak> wptr; | |
public: | |
weak(const recur& r) : wptr(r.wptr) {} | |
auto shared() const -> std::shared_ptr<void> { | |
return wptr->shared(); | |
} | |
auto operator()() const -> T { | |
return static_cast<T>(*wptr)(); | |
} | |
auto operator()(const T& arg) const -> T { | |
return static_cast<T>(*wptr)(arg); | |
} | |
}; // class recur::weak | |
}; // class recur | |
} // namespace _template_ | |
} // namespace purescript | |
#endif // purescript_recursion_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment