Skip to content

Instantly share code, notes, and snippets.

@ajnsit
Last active August 26, 2023 08:18
Show Gist options
  • Save ajnsit/c7d5fb74312afd22753c991ab5d0328e to your computer and use it in GitHub Desktop.
Save ajnsit/c7d5fb74312afd22753c991ab5d0328e to your computer and use it in GitHub Desktop.
Purescript to C++ compiler runtime from - https://github.com/andyarvanitis/purescript-native/
///////////////////////////////////////////////////////////////////////////////
//
// 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
///////////////////////////////////////////////////////////////////////////////
//
// 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
///////////////////////////////////////////////////////////////////////////////
//
// 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
///////////////////////////////////////////////////////////////////////////////
//
// 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
///////////////////////////////////////////////////////////////////////////////
//
// 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