Compiler Explorer - C++ (x86-64 gcc (trunk))
// src/examples/advanced_sender_ffi.cpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// --- Begin inlined: smd/schemepoc/schemepoc.hpp ---
// 44cc988c-7353-43aa-a7d3-8840f92371a6
// --- Begin inlined: smd/schemepoc/closure_backend.hpp ---
// --- Begin inlined: smd/schemepoc/cps.hpp ---
// --- Begin inlined: smd/schemepoc/elaborator.hpp ---
// --- Begin inlined: smd/schemepoc/elaborator_core.hpp ---
// --- Begin inlined: smd/schemepoc/datum_tree.hpp ---
// --- Begin inlined: smd/schemepoc/arena_box.hpp ---
// --- Begin inlined: smd/schemepoc/static_vector.hpp ---
namespace smd::schemepoc {
template <class T, int Capacity>
class static_vector {
public:
constexpr static_vector() = default;
constexpr auto push_back(T value) -> void;
[[nodiscard]] constexpr auto size() const -> int;
[[nodiscard]] constexpr auto empty() const -> bool;
[[nodiscard]] constexpr auto operator[](int index) -> T &;
[[nodiscard]] constexpr auto operator[](int index) const -> T const &;
constexpr auto begin() -> T * { return storage_.data(); }
constexpr auto begin() const -> const T * { return storage_.data(); }
constexpr auto end() -> T * { return storage_.data() + size_; }
constexpr auto end() const -> const T * { return storage_.data() + size_; }
private:
std::array<T, Capacity> storage_{};
int size_{};
};
template <class T, int Capacity>
constexpr auto static_vector<T, Capacity>::push_back(T value) -> void {
assert(size_ < Capacity);
storage_[size_] = std::move(value);
++size_;
}
template <class T, int Capacity>
constexpr auto static_vector<T, Capacity>::size() const -> int {
return size_;
}
template <class T, int Capacity>
constexpr auto static_vector<T, Capacity>::empty() const -> bool {
return size_ == 0;
}
template <class T, int Capacity>
constexpr auto static_vector<T, Capacity>::operator[](int index) -> T & {
assert(index >= 0 && index < size_);
return storage_[index];
}
template <class T, int Capacity>
constexpr auto static_vector<T, Capacity>::operator[](int index) const
-> T const & {
assert(index >= 0 && index < size_);
return storage_[index];
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/static_vector.hpp ---
namespace smd::schemepoc {
template <typename T, int MaxNodes = 1024>
struct arena_box {
int id_{-1};
constexpr arena_box() = default;
constexpr explicit arena_box(int id) : id_(id) {}
constexpr explicit operator bool() const { return id_ != -1; }
};
template <typename T, int MaxNodes>
struct tree_arena {
static_vector<T, MaxNodes> data{};
constexpr tree_arena() = default;
constexpr auto allocate(T value) -> int {
int id = data.size();
data.push_back(std::move(value));
return id;
}
constexpr auto get(int id) -> T & { return data[id]; }
constexpr auto get(int id) const -> const T & { return data[id]; }
constexpr auto get(arena_box<T, MaxNodes> b) -> T & { return data[b.id_]; }
constexpr auto get(arena_box<T, MaxNodes> b) const -> const T & {
return data[b.id_];
}
};
template <typename T, int MaxNodes, typename... Args>
constexpr auto make_arena_box(tree_arena<T, MaxNodes> &arena, Args &&...args)
-> arena_box<T, MaxNodes> {
return arena_box<T, MaxNodes>(
arena.allocate(T(std::forward<Args>(args)...)));
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/arena_box.hpp ---
// --- Begin inlined: smd/schemepoc/fix.hpp ---
// --- Begin inlined: smd/schemepoc/functor.hpp ---
namespace smd::schemepoc {
template <class Impl>
struct Functor : protected Impl {
using Impl::fmap;
template <class T, class U>
constexpr auto replace(this auto &&self, T &&value, U &&replacement) {
return self.fmap([replacement = std::forward<U>(replacement)](
const auto &) { return replacement; },
std::forward<T>(value));
}
};
template <class T>
inline constexpr auto functor_typeclass = std::false_type{};
struct fmap_fn {
template <class F, class T,
const auto &TC = functor_typeclass<std::remove_cvref_t<T>>>
constexpr auto operator()(F &&f, T &&value) const {
using tc_type = std::remove_cvref_t<decltype(TC)>;
return tc_type{}.fmap(std::forward<F>(f), std::forward<T>(value));
}
};
inline constexpr fmap_fn fmap{};
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/functor.hpp ---
namespace smd::schemepoc {
template <template <class> class F>
struct fix {
F<fix<F>> inner;
constexpr fix() = default;
constexpr explicit fix(F<fix<F>> layer) : inner(std::move(layer)) {}
};
// fold_fix recursively folds a fix<F> tree using a carrier-algebra.
// R is the carrier type (return type of algebra).
// fmap is invoked via the CPO smd::schemepoc::fmap, which delegates to
// functor_typeclass.
template <class R, template <class> class F, class Algebra>
constexpr auto fold_fix(fix<F> const &tree, Algebra algebra) -> R {
auto mapped = fmap(tree.inner, [&](auto const &child) -> R {
return fold_fix<R>(child, algebra);
});
return algebra(mapped);
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/fix.hpp ---
// --- Begin inlined: smd/schemepoc/static_vector.hpp ---
// --- End inlined: smd/schemepoc/static_vector.hpp ---
namespace smd::schemepoc {
struct datum_integer {
int value{};
};
struct datum_symbol {
std::string_view name{};
};
struct datum_boolean {
bool value{};
};
template <typename R, int MaxNodes, int MaxList>
struct datum_list {
static_vector<arena_box<R, MaxNodes>, MaxList> elements{};
};
template <typename R, int MaxNodes>
struct datum_quote {
arena_box<R, MaxNodes> quoted{};
};
template <int MaxNodes, int MaxList>
struct datum_f_factory {
template <typename R>
using type = std::variant<datum_integer, datum_symbol, datum_boolean,
datum_list<R, MaxNodes, MaxList>,
datum_quote<R, MaxNodes>>;
};
template <int MaxNodes, int MaxList>
using datum_type = fix<datum_f_factory<MaxNodes, MaxList>::template type>;
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/datum_tree.hpp ---
// --- Begin inlined: smd/schemepoc/fix.hpp ---
// --- End inlined: smd/schemepoc/fix.hpp ---
namespace smd::schemepoc {
struct core_integer {
int value;
};
struct core_boolean {
bool value;
};
struct core_symbol {
std::string_view name;
};
struct core_quote {
std::variant<int, bool, std::string_view> atom;
};
template <typename R, int MaxNodes>
struct core_if {
arena_box<R, MaxNodes> condition;
arena_box<R, MaxNodes> consequent;
arena_box<R, MaxNodes> alternative;
};
template <typename R, int MaxNodes, int MaxList>
struct core_lambda {
static_vector<std::string_view, MaxList> params;
arena_box<R, MaxNodes> body;
};
template <typename R, int MaxNodes, int MaxList>
struct core_application {
arena_box<R, MaxNodes> func;
static_vector<arena_box<R, MaxNodes>, MaxList> args;
};
template <typename R, int MaxNodes>
struct core_define {
std::string_view name;
arena_box<R, MaxNodes> value;
};
template <int MaxNodes, int MaxList>
struct core_f_factory {
template <typename R>
using type =
std::variant<core_integer, core_boolean, core_symbol, core_quote,
core_if<R, MaxNodes>, core_lambda<R, MaxNodes, MaxList>,
core_application<R, MaxNodes, MaxList>,
core_define<R, MaxNodes>>;
};
template <int MaxNodes, int MaxList>
using core_type = fix<core_f_factory<MaxNodes, MaxList>::template type>;
template <int MaxNodes, int MaxList>
struct elaborated_core {
using core = core_type<MaxNodes, MaxList>;
tree_arena<core, MaxNodes> arena;
core root;
};
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/elaborator_core.hpp ---
// --- Begin inlined: smd/schemepoc/reader.hpp ---
// --- Begin inlined: smd/schemepoc/datum_tree.hpp ---
// --- End inlined: smd/schemepoc/datum_tree.hpp ---
// --- Begin inlined: smd/schemepoc/parser.hpp ---
// --- Begin inlined: smd/schemepoc/reader_cursor.hpp ---
// --- Begin inlined: smd/schemepoc/source.hpp ---
namespace smd::schemepoc {
struct source_pos {
int offset{};
int line{1};
int column{1};
friend constexpr auto operator==(source_pos, source_pos) -> bool = default;
};
struct source_span {
source_pos first{};
source_pos last{};
friend constexpr auto operator==(source_span, source_span)
-> bool = default;
};
struct parse_error {
source_pos where{};
char const *message{};
friend constexpr auto operator==(parse_error const &lhs,
parse_error const &rhs) -> bool {
if (!(lhs.where == rhs.where)) {
return false;
}
if (lhs.message == rhs.message) {
return true;
}
if (lhs.message == nullptr || rhs.message == nullptr) {
return false;
}
auto const *a = lhs.message;
auto const *b = rhs.message;
while (*a != '\0' && *b != '\0') {
if (*a != *b) {
return false;
}
++a;
++b;
}
return *a == *b;
}
};
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/source.hpp ---
namespace smd::schemepoc {
class cursor {
std::string_view input_{};
source_pos pos_{};
public:
constexpr explicit cursor(std::string_view input) : input_{input} {}
constexpr auto empty() const -> bool { return input_.empty(); }
constexpr auto peek() const -> char { return input_.front(); }
constexpr auto bump() const -> cursor {
cursor next{*this};
if (!input_.empty()) {
char c = input_.front();
next.input_.remove_prefix(1);
++next.pos_.offset;
if (c == '\n') {
++next.pos_.line;
next.pos_.column = 1;
} else {
++next.pos_.column;
}
}
return next;
}
constexpr auto position() const -> source_pos { return pos_; }
constexpr auto remaining() const -> std::string_view { return input_; }
};
constexpr auto is_space(char c) -> bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r';
}
constexpr auto is_initial_symbol_char(char c) -> bool {
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
return true;
}
return c == '+' || c == '-' || c == '*' || c == '/' || c == '=' ||
c == '<' || c == '>' || c == '!' || c == '?';
}
constexpr auto is_symbol_char(char c) -> bool {
return is_initial_symbol_char(c) || (c >= '0' && c <= '9');
}
constexpr auto is_delimiter(char c) -> bool {
return is_space(c) || c == '(' || c == ')' || c == '\'';
}
constexpr auto skip_intertoken_space(cursor cur) -> cursor {
while (!cur.empty() && is_space(cur.peek())) {
cur = cur.bump();
}
return cur;
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/reader_cursor.hpp ---
// --- Begin inlined: smd/schemepoc/result.hpp ---
// --- Begin inlined: smd/schemepoc/source.hpp ---
// --- End inlined: smd/schemepoc/source.hpp ---
namespace smd::schemepoc {
template <class T>
class result {
public:
constexpr result(T value);
constexpr result(parse_error error);
[[nodiscard]] constexpr auto has_value() const -> bool;
[[nodiscard]] constexpr auto value() const -> T const &;
[[nodiscard]] constexpr auto error() const -> parse_error const &;
private:
std::variant<T, parse_error> data_;
};
template <class T>
constexpr result<T>::result(T value) : data_{std::move(value)} {}
template <class T>
constexpr result<T>::result(parse_error error) : data_{error} {}
template <class T>
constexpr auto result<T>::has_value() const -> bool {
return std::holds_alternative<T>(data_);
}
template <class T>
constexpr auto result<T>::value() const -> T const & {
return std::get<T>(data_);
}
template <class T>
constexpr auto result<T>::error() const -> parse_error const & {
return std::get<parse_error>(data_);
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/result.hpp ---
namespace smd::schemepoc {
template <class P>
concept parser_like = requires(P p, cursor c) { p(c); };
template <class T>
struct parse_state {
T value;
cursor rest;
};
template <class T>
using parse_result = result<parse_state<T>>;
template <class F>
class parser {
public:
constexpr explicit parser(F f) : f_{f} {}
constexpr auto operator()(cursor cur) const { return f_(cur); }
private:
F f_;
};
template <class F>
parser(F) -> parser<F>;
template <class T>
[[nodiscard]] constexpr auto pure(T value) {
return parser{[v = value](cursor cur) -> parse_result<T> {
return parse_state<T>{v, cur};
}};
}
[[nodiscard]] constexpr auto satisfy(auto pred, char const *expected) {
return parser{[pred, expected](cursor cur) -> parse_result<char> {
if (!cur.empty() && pred(cur.peek())) {
return parse_state<char>{cur.peek(), cur.bump()};
}
return parse_error{cur.position(), expected};
}};
}
[[nodiscard]] constexpr auto char_p(char expected) {
return satisfy([expected](char c) { return c == expected; },
"expected char");
}
template <parser_like PA, class F>
[[nodiscard]] constexpr auto map(PA pa, F f) {
return parser{[pa, f](cursor cur) {
auto r = pa(cur);
if (!r.has_value()) {
using R = decltype(f(r.value().value));
return parse_result<R>{r.error()};
}
using R = decltype(f(r.value().value));
return parse_result<R>{
parse_state<R>{f(r.value().value), r.value().rest}};
}};
}
template <parser_like PA, parser_like PB, class F>
[[nodiscard]] constexpr auto lift2(PA pa, PB pb, F f) {
return parser{[pa, pb, f](cursor cur) {
auto ra = pa(cur);
if (!ra.has_value()) {
using V = decltype(f(ra.value().value, pb(cur).value().value));
return parse_result<V>{ra.error()};
}
auto rb = pb(ra.value().rest);
if (!rb.has_value()) {
using V = decltype(f(ra.value().value, rb.value().value));
return parse_result<V>{rb.error()};
}
using V = decltype(f(ra.value().value, rb.value().value));
return parse_result<V>{parse_state<V>{
f(ra.value().value, rb.value().value), rb.value().rest}};
}};
}
template <parser_like PA, parser_like PB>
[[nodiscard]] constexpr auto sequence_left(PA pa, PB pb) {
return lift2(pa, pb, [](auto a, auto) { return a; });
}
template <parser_like PA, parser_like PB>
[[nodiscard]] constexpr auto sequence_right(PA pa, PB pb) {
return lift2(pa, pb, [](auto, auto b) { return b; });
}
template <parser_like PA, parser_like PB>
[[nodiscard]] constexpr auto operator|(PA pa, PB pb) {
return parser{[pa, pb](cursor cur) {
auto start = cur.position().offset;
auto ra = pa(cur);
if (ra.has_value())
return ra;
if (ra.error().where.offset != start)
return ra;
return pb(cur);
}};
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/parser.hpp ---
// --- Begin inlined: smd/schemepoc/reader_atom.hpp ---
// --- Begin inlined: smd/schemepoc/parser.hpp ---
// --- End inlined: smd/schemepoc/parser.hpp ---
// --- Begin inlined: smd/schemepoc/parser_alternative.hpp ---
// --- Begin inlined: smd/schemepoc/parser.hpp ---
// --- End inlined: smd/schemepoc/parser.hpp ---
// --- Begin inlined: smd/schemepoc/reader_cursor.hpp ---
// --- End inlined: smd/schemepoc/reader_cursor.hpp ---
// --- Begin inlined: smd/schemepoc/static_vector.hpp ---
// --- End inlined: smd/schemepoc/static_vector.hpp ---
namespace smd::schemepoc {
template <parser_like PA, parser_like PB>
[[nodiscard]] constexpr auto alt(PA pa, PB pb) {
return pa | pb;
}
template <int Capacity, parser_like P>
[[nodiscard]] constexpr auto many(P p) {
return parser{[p](cursor cur) {
using V = decltype(p(cur).value().value);
static_vector<V, Capacity> result{};
while (result.size() < Capacity) {
auto r = p(cur);
if (!r.has_value())
break;
result.push_back(r.value().value);
cur = r.value().rest;
}
return parse_result<static_vector<V, Capacity>>{
parse_state<static_vector<V, Capacity>>{result, cur}};
}};
}
template <int Capacity, parser_like P>
[[nodiscard]] constexpr auto some(P p) {
return parser{[p](cursor cur) {
using V = decltype(p(cur).value().value);
auto first = p(cur);
if (!first.has_value()) {
return parse_result<static_vector<V, Capacity>>{first.error()};
}
static_vector<V, Capacity> result{};
result.push_back(first.value().value);
cur = first.value().rest;
while (result.size() < Capacity) {
auto r = p(cur);
if (!r.has_value())
break;
result.push_back(r.value().value);
cur = r.value().rest;
}
return parse_result<static_vector<V, Capacity>>{
parse_state<static_vector<V, Capacity>>{result, cur}};
}};
}
template <parser_like P>
[[nodiscard]] constexpr auto optional(P p) {
return parser{[p](cursor cur) {
using V = decltype(p(cur).value().value);
auto r = p(cur);
if (r.has_value()) {
return parse_result<std::optional<V>>{
parse_state<std::optional<V>>{r.value().value, r.value().rest}};
}
return parse_result<std::optional<V>>{
parse_state<std::optional<V>>{std::optional<V>{}, cur}};
}};
}
template <parser_like P>
[[nodiscard]] constexpr auto lexeme(P p) {
return parser{[p](cursor cur) {
auto start = skip_intertoken_space(cur);
auto r = p(start);
if (!r.has_value())
return r;
auto rest = skip_intertoken_space(r.value().rest);
using V = decltype(r.value().value);
return parse_result<V>{parse_state<V>{r.value().value, rest}};
}};
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/parser_alternative.hpp ---
// --- Begin inlined: smd/schemepoc/reader_cursor.hpp ---
// --- End inlined: smd/schemepoc/reader_cursor.hpp ---
namespace smd::schemepoc {
struct atom_integer {
int value;
};
struct atom_symbol {
std::string_view name;
};
using atom = std::variant<atom_integer, atom_symbol>;
[[nodiscard]] constexpr auto integer_p() {
return parser{[](cursor cur) -> parse_result<atom_integer> {
auto sign_r = optional(char_p('-'))(cur);
bool negative = sign_r.value().value.has_value();
auto after_sign = sign_r.value().rest;
auto digits = some<20>(satisfy(
[](char c) { return c >= '0' && c <= '9'; }, "digit"))(after_sign);
if (!digits.has_value()) {
return parse_result<atom_integer>{digits.error()};
}
auto &d = digits.value().value;
auto rest = digits.value().rest;
int sign = negative ? -1 : 1;
int n = 0;
for (int i = 0; i < d.size(); ++i)
n = n * 10 + (d[i] - '0');
return parse_result<atom_integer>{
parse_state<atom_integer>{atom_integer{sign * n}, rest}};
}};
}
[[nodiscard]] constexpr auto symbol_p() {
return parser{[](cursor cur) -> parse_result<atom_symbol> {
auto start = cur;
auto first = satisfy(is_initial_symbol_char, "symbol")(cur);
if (!first.has_value())
return parse_result<atom_symbol>{first.error()};
auto rest_cur = first.value().rest;
auto tail = many<64>(satisfy(is_symbol_char, "symbol char"))(rest_cur);
auto end_cur = tail.value().rest;
int len = end_cur.position().offset - start.position().offset;
auto name = start.remaining().substr(0, len);
return parse_result<atom_symbol>{
parse_state<atom_symbol>{atom_symbol{name}, end_cur}};
}};
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/reader_atom.hpp ---
// --- Begin inlined: smd/schemepoc/reader_cursor.hpp ---
// --- End inlined: smd/schemepoc/reader_cursor.hpp ---
namespace smd::schemepoc {
namespace detail {
template <int MaxNodes, int MaxList>
constexpr auto
read_datum_node(cursor cur,
tree_arena<datum_type<MaxNodes, MaxList>, MaxNodes> &arena)
-> parse_result<datum_type<MaxNodes, MaxList>> {
using datum = datum_type<MaxNodes, MaxList>;
using datum_f =
typename datum_f_factory<MaxNodes, MaxList>::template type<datum>;
cur = skip_intertoken_space(cur);
if (cur.empty())
return parse_error{cur.position(), "unexpected end of input"};
char c = cur.peek();
if (c == '#') {
cursor after = cur.bump();
if (!after.empty()) {
char b = after.peek();
if (b == 't' || b == 'f') {
cursor after_bool = after.bump();
if (after_bool.empty() || is_delimiter(after_bool.peek())) {
datum d{datum_f{datum_boolean{b == 't'}}};
return parse_state<datum>{d, after_bool};
}
}
}
return parse_error{cur.position(), "boolean"};
}
if (c == '\'') {
cursor after = cur.bump();
auto inner = read_datum_node<MaxNodes, MaxList>(after, arena);
if (!inner.has_value())
return inner;
datum d{datum_f{datum_quote<datum, MaxNodes>{
make_arena_box(arena, inner.value().value)}}};
return parse_state<datum>{d, inner.value().rest};
}
if (c == '(') {
cursor after = cur.bump();
datum_list<datum, MaxNodes, MaxList> list{};
while (true) {
after = skip_intertoken_space(after);
if (after.empty())
return parse_error{after.position(), "expected ')'"};
if (after.peek() == ')') {
datum d{datum_f{list}};
return parse_state<datum>{d, after.bump()};
}
auto elem = read_datum_node<MaxNodes, MaxList>(after, arena);
if (!elem.has_value())
return elem;
list.elements.push_back(make_arena_box(arena, elem.value().value));
after = elem.value().rest;
}
}
{
auto int_r = integer_p()(cur);
if (int_r.has_value()) {
datum d{datum_f{datum_integer{int_r.value().value.value}}};
return parse_state<datum>{d, int_r.value().rest};
}
}
{
auto sym_r = symbol_p()(cur);
if (sym_r.has_value()) {
datum d{datum_f{datum_symbol{sym_r.value().value.name}}};
return parse_state<datum>{d, sym_r.value().rest};
}
}
return parse_error{cur.position(), "expected datum"};
}
} // namespace detail
template <int MaxNodes, int MaxList>
[[nodiscard]] constexpr auto
read_datum(cursor cur,
tree_arena<datum_type<MaxNodes, MaxList>, MaxNodes> &arena)
-> result<parse_state<datum_type<MaxNodes, MaxList>>> {
auto r = detail::read_datum_node<MaxNodes, MaxList>(cur, arena);
if (!r.has_value())
return r.error();
return r.value();
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/reader.hpp ---
// --- Begin inlined: smd/schemepoc/result.hpp ---
// --- End inlined: smd/schemepoc/result.hpp ---
namespace smd::schemepoc {
namespace detail {
template <int MaxNodes, int MaxList>
constexpr auto elaborate_quote(
datum_type<MaxNodes, MaxList> const &d,
const tree_arena<datum_type<MaxNodes, MaxList>, MaxNodes> & /*arena*/)
-> result<std::variant<int, bool, std::string_view>> {
if (std::holds_alternative<datum_integer>(d.inner)) {
return std::variant<int, bool, std::string_view>{
std::get<datum_integer>(d.inner).value};
}
if (std::holds_alternative<datum_boolean>(d.inner)) {
return std::variant<int, bool, std::string_view>{
std::get<datum_boolean>(d.inner).value};
}
if (std::holds_alternative<datum_symbol>(d.inner)) {
return std::variant<int, bool, std::string_view>{
std::get<datum_symbol>(d.inner).name};
}
return parse_error{{}, "quote: lists/nested quotes not yet supported"};
}
template <int MaxNodes, int MaxList>
constexpr auto elaborate_node(
datum_type<MaxNodes, MaxList> const &d,
const tree_arena<datum_type<MaxNodes, MaxList>, MaxNodes> &datum_arena,
tree_arena<core_type<MaxNodes, MaxList>, MaxNodes> &core_arena)
-> result<core_type<MaxNodes, MaxList>>;
template <int MaxNodes, int MaxList>
constexpr auto elaborate_list(
datum_list<datum_type<MaxNodes, MaxList>, MaxNodes, MaxList> const &lst,
const tree_arena<datum_type<MaxNodes, MaxList>, MaxNodes> &datum_arena,
tree_arena<core_type<MaxNodes, MaxList>, MaxNodes> &core_arena)
-> result<core_type<MaxNodes, MaxList>> {
using core = core_type<MaxNodes, MaxList>;
using core_f =
typename core_f_factory<MaxNodes, MaxList>::template type<core>;
if (lst.elements.empty()) {
return parse_error{{}, "empty application"};
}
auto const &first = datum_arena.get(lst.elements[0]);
if (std::holds_alternative<datum_symbol>(first.inner)) {
auto name = std::get<datum_symbol>(first.inner).name;
if (name == "if") {
if (lst.elements.size() != 4)
return parse_error{{}, "if: expected 3 arguments"};
auto cond_r = elaborate_node<MaxNodes, MaxList>(
datum_arena.get(lst.elements[1]), datum_arena, core_arena);
if (!cond_r.has_value())
return cond_r;
auto cons_r = elaborate_node<MaxNodes, MaxList>(
datum_arena.get(lst.elements[2]), datum_arena, core_arena);
if (!cons_r.has_value())
return cons_r;
auto alt_r = elaborate_node<MaxNodes, MaxList>(
datum_arena.get(lst.elements[3]), datum_arena, core_arena);
if (!alt_r.has_value())
return alt_r;
return core{core_f{core_if<core, MaxNodes>{
make_arena_box(core_arena, std::move(cond_r.value())),
make_arena_box(core_arena, std::move(cons_r.value())),
make_arena_box(core_arena, std::move(alt_r.value()))}}};
}
if (name == "quote") {
if (lst.elements.size() != 2)
return parse_error{{}, "quote: expected 1 argument"};
auto atom_r = elaborate_quote<MaxNodes, MaxList>(
datum_arena.get(lst.elements[1]), datum_arena);
if (!atom_r.has_value())
return parse_error{{}, atom_r.error().message};
return core{core_f{core_quote{atom_r.value()}}};
}
if (name == "define") {
if (lst.elements.size() != 3)
return parse_error{{}, "define: expected name and value"};
auto const &name_node = datum_arena.get(lst.elements[1]);
if (!std::holds_alternative<datum_symbol>(name_node.inner))
return parse_error{{}, "define: name must be a symbol"};
auto val_r = elaborate_node<MaxNodes, MaxList>(
datum_arena.get(lst.elements[2]), datum_arena, core_arena);
if (!val_r.has_value())
return val_r;
return core{core_f{core_define<core, MaxNodes>{
std::get<datum_symbol>(name_node.inner).name,
make_arena_box(core_arena, std::move(val_r.value()))}}};
}
if (name == "lambda") {
if (lst.elements.size() != 3)
return parse_error{{},
"lambda: expected formals and body (only 1 "
"expr body supported)"};
auto const &formals_node = datum_arena.get(lst.elements[1]);
if (!std::holds_alternative<datum_list<
datum_type<MaxNodes, MaxList>, MaxNodes, MaxList>>(
formals_node.inner))
return parse_error{{}, "lambda: formals must be a list"};
core_lambda<core, MaxNodes, MaxList> lam{};
auto const &formals = std::get<
datum_list<datum_type<MaxNodes, MaxList>, MaxNodes, MaxList>>(
formals_node.inner);
for (int i = 0; i < formals.elements.size(); ++i) {
auto const &p = datum_arena.get(formals.elements[i]);
if (!std::holds_alternative<datum_symbol>(p.inner))
return parse_error{{}, "lambda: formal must be a symbol"};
auto p_name = std::get<datum_symbol>(p.inner).name;
for (auto const &existing : lam.params) {
if (existing == p_name)
return parse_error{{}, "duplicate parameter"};
}
lam.params.push_back(p_name);
}
auto body_r = elaborate_node<MaxNodes, MaxList>(
datum_arena.get(lst.elements[2]), datum_arena, core_arena);
if (!body_r.has_value())
return body_r;
lam.body = make_arena_box(core_arena, std::move(body_r.value()));
return core{core_f{std::move(lam)}};
}
}
// Regular application
auto func_r =
elaborate_node<MaxNodes, MaxList>(first, datum_arena, core_arena);
if (!func_r.has_value())
return func_r;
core_application<core, MaxNodes, MaxList> app{};
app.func = make_arena_box(core_arena, std::move(func_r.value()));
for (int i = 1; i < lst.elements.size(); ++i) {
auto arg_r = elaborate_node<MaxNodes, MaxList>(
datum_arena.get(lst.elements[i]), datum_arena, core_arena);
if (!arg_r.has_value())
return arg_r;
app.args.push_back(
make_arena_box(core_arena, std::move(arg_r.value())));
}
return core{core_f{std::move(app)}};
}
template <int MaxNodes, int MaxList>
constexpr auto elaborate_node(
datum_type<MaxNodes, MaxList> const &d,
const tree_arena<datum_type<MaxNodes, MaxList>, MaxNodes> &datum_arena,
tree_arena<core_type<MaxNodes, MaxList>, MaxNodes> &core_arena)
-> result<core_type<MaxNodes, MaxList>> {
using core = core_type<MaxNodes, MaxList>;
using core_f =
typename core_f_factory<MaxNodes, MaxList>::template type<core>;
if (std::holds_alternative<datum_integer>(d.inner)) {
return core{
core_f{core_integer{std::get<datum_integer>(d.inner).value}}};
}
if (std::holds_alternative<datum_boolean>(d.inner)) {
return core{
core_f{core_boolean{std::get<datum_boolean>(d.inner).value}}};
}
if (std::holds_alternative<datum_symbol>(d.inner)) {
return core{core_f{core_symbol{std::get<datum_symbol>(d.inner).name}}};
}
if (std::holds_alternative<
datum_quote<datum_type<MaxNodes, MaxList>, MaxNodes>>(d.inner)) {
auto const &q =
std::get<datum_quote<datum_type<MaxNodes, MaxList>, MaxNodes>>(
d.inner);
auto atom_r = elaborate_quote<MaxNodes, MaxList>(
datum_arena.get(q.quoted), datum_arena);
if (!atom_r.has_value())
return atom_r.error();
return core{core_f{core_quote{atom_r.value()}}};
}
if (std::holds_alternative<
datum_list<datum_type<MaxNodes, MaxList>, MaxNodes, MaxList>>(
d.inner)) {
return elaborate_list<MaxNodes, MaxList>(
std::get<
datum_list<datum_type<MaxNodes, MaxList>, MaxNodes, MaxList>>(
d.inner),
datum_arena, core_arena);
}
return parse_error{{}, "elaborator: unsupported node type"};
}
} // namespace detail
template <int MaxNodes, int MaxList>
constexpr auto elaborate(
datum_type<MaxNodes, MaxList> const &pd,
const tree_arena<datum_type<MaxNodes, MaxList>, MaxNodes> &datum_arena,
tree_arena<core_type<MaxNodes, MaxList>, MaxNodes> &core_arena)
-> result<core_type<MaxNodes, MaxList>> {
auto r =
detail::elaborate_node<MaxNodes, MaxList>(pd, datum_arena, core_arena);
if (!r.has_value())
return r.error();
return r.value();
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/elaborator.hpp ---
// --- Begin inlined: smd/schemepoc/result.hpp ---
// --- End inlined: smd/schemepoc/result.hpp ---
// --- Begin inlined: smd/schemepoc/value.hpp ---
// --- Begin inlined: smd/schemepoc/datum_tree.hpp ---
// --- End inlined: smd/schemepoc/datum_tree.hpp ---
// --- Begin inlined: smd/schemepoc/result.hpp ---
// --- End inlined: smd/schemepoc/result.hpp ---
// --- Begin inlined: smd/schemepoc/static_vector.hpp ---
// --- End inlined: smd/schemepoc/static_vector.hpp ---
namespace smd::schemepoc {
enum class builtin_op { add, multiply };
struct builtin {
builtin_op op;
friend constexpr auto operator==(builtin, builtin) -> bool = default;
};
// Forward declaration of env to resolve circular dependency
template <typename Core, int MaxBindings>
class env;
// A custom copyable constexpr unique pointer to avoid escaping allocations
// and allow value/closure to be copied naturally in constexpr.
template <class T>
struct constexpr_box {
T *ptr = nullptr;
constexpr constexpr_box() = default;
constexpr explicit constexpr_box(T *p) : ptr(p) {}
constexpr constexpr_box(constexpr_box const &other) {
if (other.ptr)
ptr = new T(*other.ptr);
}
constexpr constexpr_box(constexpr_box &&other) noexcept {
ptr = other.ptr;
other.ptr = nullptr;
}
constexpr auto operator=(constexpr_box const &other) -> constexpr_box & {
if (this == &other)
return *this;
delete ptr;
if (other.ptr)
ptr = new T(*other.ptr);
else
ptr = nullptr;
return *this;
}
constexpr auto operator=(constexpr_box &&other) noexcept
-> constexpr_box & {
delete ptr;
ptr = other.ptr;
other.ptr = nullptr;
return *this;
}
constexpr ~constexpr_box() { delete ptr; }
constexpr auto operator*() const -> T & { return *ptr; }
constexpr auto operator->() const -> T * { return ptr; }
constexpr explicit operator bool() const { return ptr != nullptr; }
constexpr auto get() const -> T * { return ptr; }
};
template <typename Core>
struct closure {
Core const *node;
constexpr_box<env<Core, 16>> captured; // capture env<16> directly
friend constexpr auto operator==(closure<Core> const &lhs,
closure<Core> const &rhs) -> bool {
// Simple structural equality for test purposes.
return lhs.node == rhs.node;
}
};
struct symbol {
std::string_view name;
friend constexpr auto operator==(symbol const &lhs, symbol const &rhs)
-> bool {
return lhs.name == rhs.name;
}
};
template <typename Core>
struct foreign_function {
using val_t = std::variant<int, bool, builtin, closure<Core>, symbol,
foreign_function>;
using sig_t = result<val_t> (*)(std::span<val_t const>);
sig_t fn;
friend constexpr auto operator==(foreign_function const &lhs,
foreign_function const &rhs) -> bool {
return lhs.fn == rhs.fn;
}
};
template <typename Core>
using value = std::variant<int, bool, builtin, closure<Core>, symbol,
foreign_function<Core>>;
template <typename Core, int MaxBindings>
class env {
public:
constexpr auto define(std::string_view name, value<Core> val) -> void;
[[nodiscard]] constexpr auto lookup(std::string_view name) const
-> result<value<Core>>;
private:
struct binding {
std::string_view name;
value<Core> val;
};
static_vector<binding, MaxBindings> bindings_{};
};
template <typename Core, int MaxBindings>
constexpr auto env<Core, MaxBindings>::define(std::string_view name,
value<Core> val) -> void {
bindings_.push_back(binding{name, val});
}
template <typename Core, int MaxBindings>
constexpr auto env<Core, MaxBindings>::lookup(std::string_view name) const
-> result<value<Core>> {
for (int i = bindings_.size() - 1; i >= 0; --i) {
if (bindings_[i].name == name)
return bindings_[i].val;
}
return parse_error{{}, "unbound variable"};
}
template <typename Core, int MaxBindings>
[[nodiscard]] constexpr auto default_env() -> env<Core, MaxBindings> {
env<Core, MaxBindings> e{};
e.define("+", value<Core>{builtin{builtin_op::add}});
e.define("*", value<Core>{builtin{builtin_op::multiply}});
return e;
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/value.hpp ---
namespace smd::schemepoc {
template <class F>
struct cps_code {
F f;
template <class Env, class K>
constexpr auto operator()(Env const &env, K k) const {
return f(env, k);
}
};
template <class F>
cps_code(F) -> cps_code<F>;
namespace detail {
template <class Core>
struct identity_k {
constexpr auto operator()(value<Core> v) const -> result<value<Core>> {
return v;
}
};
template <int MaxNodes, int MaxList, class Cont, class Env, class K>
constexpr auto
cps_dispatch(core_type<MaxNodes, MaxList> const &node,
const tree_arena<core_type<MaxNodes, MaxList>, MaxNodes> &arena,
Cont const &cont, Env const &env, K const &k)
-> result<value<core_type<MaxNodes, MaxList>>> {
using Core = core_type<MaxNodes, MaxList>;
if (std::holds_alternative<core_integer>(node.inner)) {
auto r = cont(value<Core>{std::get<core_integer>(node.inner).value});
if (!r.has_value())
return r;
return k(r.value());
}
if (std::holds_alternative<core_boolean>(node.inner)) {
auto r = cont(value<Core>{std::get<core_boolean>(node.inner).value});
if (!r.has_value())
return r;
return k(r.value());
}
if (std::holds_alternative<core_symbol>(node.inner)) {
auto lr = env.lookup(std::get<core_symbol>(node.inner).name);
if (!lr.has_value())
return result<value<Core>>{lr.error()};
auto r = cont(lr.value());
if (!r.has_value())
return r;
return k(r.value());
}
if (std::holds_alternative<core_if<Core, MaxNodes>>(node.inner)) {
auto const &cif = std::get<core_if<Core, MaxNodes>>(node.inner);
auto cond_r = cps_dispatch<MaxNodes, MaxList>(arena.get(cif.condition),
arena, identity_k<Core>{},
env, identity_k<Core>{});
if (!cond_r.has_value())
return cond_r;
bool taken = !std::holds_alternative<bool>(cond_r.value()) ||
std::get<bool>(cond_r.value());
auto const &branch = taken ? cif.consequent : cif.alternative;
return cps_dispatch<MaxNodes, MaxList>(arena.get(branch), arena, cont,
env, k);
}
if (std::holds_alternative<core_quote>(node.inner)) {
auto const &cq = std::get<core_quote>(node.inner);
value<Core> v;
if (std::holds_alternative<int>(cq.atom))
v = value<Core>{std::get<int>(cq.atom)};
else if (std::holds_alternative<bool>(cq.atom))
v = value<Core>{std::get<bool>(cq.atom)};
else
v = value<Core>{symbol{std::get<std::string_view>(cq.atom)}};
auto r = cont(v);
if (!r.has_value())
return r;
return k(r.value());
}
if (std::holds_alternative<core_lambda<Core, MaxNodes, MaxList>>(
node.inner)) {
value<Core> v{
closure<Core>{&node, constexpr_box<schemepoc::env<Core, 16>>{
new schemepoc::env<Core, 16>{env}}}};
auto r = cont(v);
if (!r.has_value())
return r;
return k(r.value());
}
if (std::holds_alternative<core_application<Core, MaxNodes, MaxList>>(
node.inner)) {
auto const &app =
std::get<core_application<Core, MaxNodes, MaxList>>(node.inner);
auto func_r = cps_dispatch<MaxNodes, MaxList>(arena.get(app.func),
arena, identity_k<Core>{},
env, identity_k<Core>{});
if (!func_r.has_value())
return func_r;
if (std::holds_alternative<builtin>(func_r.value())) {
auto const &bi = std::get<builtin>(func_r.value());
if (app.args.size() != 2)
return result<value<Core>>{parse_error{{}, "arity mismatch"}};
auto arg0_r = cps_dispatch<MaxNodes, MaxList>(
arena.get(app.args[0]), arena, identity_k<Core>{}, env,
identity_k<Core>{});
if (!arg0_r.has_value())
return arg0_r;
if (!std::holds_alternative<int>(arg0_r.value()))
return result<value<Core>>{parse_error{{}, "type error"}};
int a = std::get<int>(arg0_r.value());
auto arg1_r = cps_dispatch<MaxNodes, MaxList>(
arena.get(app.args[1]), arena, identity_k<Core>{}, env,
identity_k<Core>{});
if (!arg1_r.has_value())
return arg1_r;
if (!std::holds_alternative<int>(arg1_r.value()))
return result<value<Core>>{parse_error{{}, "type error"}};
int b = std::get<int>(arg1_r.value());
value<Core> app_val;
if (bi.op == builtin_op::add)
app_val = value<Core>{a + b};
else
app_val = value<Core>{a * b};
auto r = cont(app_val);
if (!r.has_value())
return r;
return k(r.value());
}
if (std::holds_alternative<closure<Core>>(func_r.value())) {
auto const &clo = std::get<closure<Core>>(func_r.value());
auto const &lam_node = *clo.node;
if (!std::holds_alternative<core_lambda<Core, MaxNodes, MaxList>>(
lam_node.inner))
return result<value<Core>>{parse_error{{}, "type error"}};
auto const &lam =
std::get<core_lambda<Core, MaxNodes, MaxList>>(lam_node.inner);
if (app.args.size() != lam.params.size())
return result<value<Core>>{parse_error{{}, "arity mismatch"}};
auto new_env = clo.captured ? *clo.captured : env;
for (int i = 0; i < app.args.size(); ++i) {
auto arg_r = cps_dispatch<MaxNodes, MaxList>(
arena.get(app.args[i]), arena, identity_k<Core>{}, env,
identity_k<Core>{});
if (!arg_r.has_value())
return arg_r;
new_env.define(lam.params[i], arg_r.value());
}
return cps_dispatch<MaxNodes, MaxList>(arena.get(lam.body), arena,
cont, new_env, k);
}
if (std::holds_alternative<foreign_function<Core>>(func_r.value())) {
auto const &ff = std::get<foreign_function<Core>>(func_r.value());
static_vector<value<Core>, MaxNodes> evaluated_args;
for (auto const &arg_id : app.args) {
auto arg_r = cps_dispatch<MaxNodes, MaxList>(
arena.get(arg_id), arena, identity_k<Core>{}, env,
identity_k<Core>{});
if (!arg_r.has_value())
return arg_r;
evaluated_args.push_back(arg_r.value());
}
auto ff_r = ff.fn(std::span<value<Core> const>(
evaluated_args.begin(), evaluated_args.end()));
if (!ff_r.has_value())
return result<value<Core>>{ff_r.error()};
auto r = cont(ff_r.value());
if (!r.has_value())
return r;
return k(r.value());
}
return result<value<Core>>{
parse_error{{}, "attempted to call non-function"}};
}
return result<value<Core>>{
parse_error{{}, "cps_dispatch: unsupported form"}};
}
} // namespace detail
template <int MaxNodes, int MaxList, class Cont>
[[nodiscard]] constexpr auto
cps_of(core_type<MaxNodes, MaxList> const &node,
tree_arena<core_type<MaxNodes, MaxList>, MaxNodes> arena, Cont cont) {
return cps_code{[node, arena, cont](auto const &env, auto k) constexpr {
return detail::cps_dispatch<MaxNodes, MaxList>(node, arena, cont, env,
k);
}};
}
template <int MaxNodes, int MaxList>
[[nodiscard]] constexpr auto
compile_cps(core_type<MaxNodes, MaxList> const &node,
tree_arena<core_type<MaxNodes, MaxList>, MaxNodes> arena) {
using Core = core_type<MaxNodes, MaxList>;
return cps_of<MaxNodes, MaxList>(node, arena, detail::identity_k<Core>{});
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/cps.hpp ---
// --- Begin inlined: smd/schemepoc/elaborator.hpp ---
// --- End inlined: smd/schemepoc/elaborator.hpp ---
// --- Begin inlined: smd/schemepoc/reader.hpp ---
// --- End inlined: smd/schemepoc/reader.hpp ---
// --- Begin inlined: smd/schemepoc/result.hpp ---
// --- End inlined: smd/schemepoc/result.hpp ---
// --- Begin inlined: smd/schemepoc/value.hpp ---
// --- End inlined: smd/schemepoc/value.hpp ---
namespace smd::schemepoc {
// closure_program: a callable compiled object.
// Wraps a cps_code so it can be invoked with just an environment,
// using the identity as the outermost continuation.
template <int MaxNodes, int MaxList, class CpsCode>
struct closure_program {
using Core = core_type<MaxNodes, MaxList>;
CpsCode code;
template <int MaxBindings>
constexpr auto operator()(env<Core, MaxBindings> const &environment) const
-> result<value<Core>> {
return code(environment, detail::identity_k<Core>{});
}
};
// compile_to_closure: full pipeline from source string to callable closure.
// Chains read -> elaborate -> compile_cps<MaxNodes, MaxList>.
// Returns result<closure_program<...>>; error propagates from any stage.
template <int MaxNodes = 32, int MaxList = 16>
[[nodiscard]] constexpr auto compile_to_closure(std::string_view src) {
using Core = core_type<MaxNodes, MaxList>;
using CpsCodeT = decltype(compile_cps<MaxNodes, MaxList>(
std::declval<Core const &>(),
std::declval<tree_arena<Core, MaxNodes> const &>()));
using ProgramT = closure_program<MaxNodes, MaxList, CpsCodeT>;
tree_arena<datum_type<MaxNodes, MaxList>, MaxNodes> arena_dr;
auto dr = read_datum<MaxNodes, MaxList>(cursor{src}, arena_dr);
if (!dr.has_value())
return result<ProgramT>{dr.error()};
tree_arena<Core, MaxNodes> core_arena;
auto er =
elaborate<MaxNodes, MaxList>(dr.value().value, arena_dr, core_arena);
if (!er.has_value())
return result<ProgramT>{er.error()};
auto const &ct_root = er.value();
return result<ProgramT>{
ProgramT{compile_cps<MaxNodes, MaxList>(ct_root, core_arena)}};
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/closure_backend.hpp ---
namespace smd::schemepoc {
template <std::size_t N>
struct source_literal {
char text[N]{};
constexpr source_literal(char const (&input)[N]) {
std::copy_n(input, N, text);
}
[[nodiscard]] constexpr auto view() const -> std::string_view {
return {text, N - 1};
}
};
template <source_literal Source>
inline constexpr auto compiled_closure =
compile_to_closure(Source.view()).value();
} // namespace smd::schemepoc
// 44cc988c-7353-43aa-a7d3-8840f92371a6 end
// --- End inlined: smd/schemepoc/schemepoc.hpp ---
// --- Begin inlined: smd/schemepoc/reflection_reify.hpp ---
namespace smd::schemepoc {
// A compile-time description of a captured environment variable
struct capture_desc {
std::meta::info type;
std::string_view name;
};
// Target template for generating environment aggregate shapes.
// `Tag` allows creating uniquely named aggregate structures per invocation context.
template <typename Tag>
struct reified_environment;
// Inject fields into `reified_environment<Tag>` based on descriptor
// This generates an ordinary aggregate type that doesn't cross into evaluation runtime limits.
template <typename Tag>
consteval void compile_environment(std::vector<capture_desc> captures) {
std::vector<std::meta::info> members;
for (auto c : captures) {
members.push_back(std::meta::data_member_spec(c.type, {.name = c.name}));
}
std::meta::define_aggregate(^^reified_environment<Tag>, members);
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/reflection_reify.hpp ---
// --- Begin inlined: smd/schemepoc/sender_backend.hpp ---
// --- Begin inlined: smd/schemepoc/elaborator.hpp ---
// --- End inlined: smd/schemepoc/elaborator.hpp ---
// --- Begin inlined: smd/schemepoc/elaborator_core.hpp ---
// --- End inlined: smd/schemepoc/elaborator_core.hpp ---
// --- Begin inlined: smd/schemepoc/reader.hpp ---
// --- End inlined: smd/schemepoc/reader.hpp ---
// --- Begin inlined: smd/schemepoc/result.hpp ---
// --- End inlined: smd/schemepoc/result.hpp ---
// --- Begin inlined: smd/schemepoc/sender_adapter.hpp ---
namespace smd::schemepoc::sender_v {
using beman::execution26::just;
using beman::execution26::let_value;
using beman::execution26::sync_wait;
using beman::execution26::then;
using beman::execution26::when_all;
template <typename T>
using task = beman::execution::task<T>;
} // namespace smd::schemepoc::sender_v
// --- End inlined: smd/schemepoc/sender_adapter.hpp ---
// --- Begin inlined: smd/schemepoc/value.hpp ---
// --- End inlined: smd/schemepoc/value.hpp ---
namespace smd::schemepoc {
namespace sender_backend {
// NOTE: Creating a fully dynamic sender graph from a runtime AST without
// type erasure (std::any/any_sender) or coroutines (Beman Task) hits
// C++ structural typing limits, as `when_all` and `then` have distinct types.
// We use `beman::task::task` as an asynchronous sender factory which
// type-erases the graph structures into a common coroutine state machine type.
template <int MaxNodes, int MaxList, int MaxBindings>
sender_v::task<result<value<core_type<MaxNodes, MaxList>>>>
compile_node(core_type<MaxNodes, MaxList> const& node,
tree_arena<core_type<MaxNodes, MaxList>, MaxNodes> const &arena,
env<core_type<MaxNodes, MaxList>, MaxBindings> environment);
template <int MaxNodes, int MaxList, int MaxBindings>
sender_v::task<result<value<core_type<MaxNodes, MaxList>>>>
compile_node(core_type<MaxNodes, MaxList> const& node,
tree_arena<core_type<MaxNodes, MaxList>, MaxNodes> const &arena,
env<core_type<MaxNodes, MaxList>, MaxBindings> environment) {
using Core = core_type<MaxNodes, MaxList>;
// Literal evaluations
if (std::holds_alternative<core_integer>(node.inner))
co_return value<Core>{std::get<core_integer>(node.inner).value};
if (std::holds_alternative<core_boolean>(node.inner))
co_return value<Core>{std::get<core_boolean>(node.inner).value};
if (std::holds_alternative<core_symbol>(node.inner))
co_return environment.lookup(std::get<core_symbol>(node.inner).name);
if (std::holds_alternative<core_quote>(node.inner)) {
auto const &cq = std::get<core_quote>(node.inner);
if (std::holds_alternative<int>(cq.atom))
co_return value<Core>{std::get<int>(cq.atom)};
if (std::holds_alternative<bool>(cq.atom))
co_return value<Core>{std::get<bool>(cq.atom)};
co_return value<Core>{symbol{std::get<std::string_view>(cq.atom)}};
}
if (std::holds_alternative<core_if<Core, MaxNodes>>(node.inner)) {
auto const &cif = std::get<core_if<Core, MaxNodes>>(node.inner);
auto cond_r = co_await compile_node<MaxNodes, MaxList, MaxBindings>(
arena.get(cif.condition), arena, environment);
if (!cond_r.has_value())
co_return cond_r.error();
auto const &cond_val = cond_r.value();
if (std::holds_alternative<bool>(cond_val) &&
!std::get<bool>(cond_val)) {
co_return co_await compile_node<MaxNodes, MaxList, MaxBindings>(
arena.get(cif.alternative), arena, environment);
}
co_return co_await compile_node<MaxNodes, MaxList, MaxBindings>(
arena.get(cif.consequent), arena, environment);
}
if (std::holds_alternative<core_lambda<Core, MaxNodes, MaxList>>(
node.inner)) {
co_return value<Core>{closure<Core>{
&node,
constexpr_box<env<Core, 16>>{new env<Core, 16>{environment}}}};
}
if (std::holds_alternative<core_application<Core, MaxNodes, MaxList>>(
node.inner)) {
auto const &app =
std::get<core_application<Core, MaxNodes, MaxList>>(node.inner);
auto func_r = co_await compile_node<MaxNodes, MaxList, MaxBindings>(
arena.get(app.func), arena, environment);
if (!func_r.has_value())
co_return func_r.error();
if (std::holds_alternative<builtin>(func_r.value())) {
auto const &bi = std::get<builtin>(func_r.value());
if (app.args.size() != 2)
co_return parse_error{{}, "arity mismatch"};
auto arg0_r = co_await compile_node<MaxNodes, MaxList, MaxBindings>(
arena.get(app.args[0]), arena, environment);
if (!arg0_r.has_value())
co_return arg0_r.error();
if (!std::holds_alternative<int>(arg0_r.value()))
co_return parse_error{{}, "type error"};
auto arg1_r = co_await compile_node<MaxNodes, MaxList, MaxBindings>(
arena.get(app.args[1]), arena, environment);
if (!arg1_r.has_value())
co_return arg1_r.error();
if (!std::holds_alternative<int>(arg1_r.value()))
co_return parse_error{{}, "type error"};
int a = std::get<int>(arg0_r.value());
int b = std::get<int>(arg1_r.value());
if (bi.op == builtin_op::add)
co_return value<Core>{a + b};
co_return value<Core>{a * b};
}
if (std::holds_alternative<closure<Core>>(func_r.value())) {
auto const &clo = std::get<closure<Core>>(func_r.value());
auto const &lam_node = *clo.node;
if (!std::holds_alternative<core_lambda<Core, MaxNodes, MaxList>>(
lam_node.inner))
co_return parse_error{{}, "type error"};
auto const &lam =
std::get<core_lambda<Core, MaxNodes, MaxList>>(lam_node.inner);
if (app.args.size() != lam.params.size())
co_return parse_error{{}, "arity mismatch"};
auto new_env = clo.captured ? *clo.captured : environment;
for (int i = 0; i < app.args.size(); ++i) {
auto arg_r =
co_await compile_node<MaxNodes, MaxList, MaxBindings>(
arena.get(app.args[i]), arena, environment);
if (!arg_r.has_value())
co_return arg_r.error();
new_env.define(lam.params[i], arg_r.value());
}
co_return co_await compile_node<MaxNodes, MaxList, MaxBindings>(
arena.get(lam.body), arena, new_env);
}
if (std::holds_alternative<foreign_function<Core>>(func_r.value())) {
auto const &ff = std::get<foreign_function<Core>>(func_r.value());
static_vector<value<Core>, MaxNodes> evaluated_args;
for (auto const &arg_id : app.args) {
auto arg_r =
co_await compile_node<MaxNodes, MaxList, MaxBindings>(
arena.get(arg_id), arena, environment);
if (!arg_r.has_value())
co_return arg_r.error();
evaluated_args.push_back(arg_r.value());
}
co_return ff.fn(std::span<value<Core> const>(evaluated_args.begin(),
evaluated_args.end()));
}
co_return parse_error{{}, "attempted to call non-function"};
}
co_return parse_error{{}, "compile_node: unsupported form"};
}
} // namespace sender_backend
template <int MaxNodes, int MaxList>
struct sender_program {
using Core = core_type<MaxNodes, MaxList>;
Core root;
tree_arena<Core, MaxNodes> arena;
template <int MaxBindings>
auto operator()(env<Core, MaxBindings> environment) const
-> sender_v::task<result<value<Core>>> {
return sender_backend::compile_node<MaxNodes, MaxList, MaxBindings>(
root, arena, std::move(environment));
}
};
template <int MaxNodes = 32, int MaxList = 16>
[[nodiscard]] constexpr auto compile_to_sender(std::string_view src) {
using Core = core_type<MaxNodes, MaxList>;
using ProgramT = sender_program<MaxNodes, MaxList>;
tree_arena<datum_type<MaxNodes, MaxList>, MaxNodes> arena_dr;
auto dr = read_datum<MaxNodes, MaxList>(cursor{src}, arena_dr);
if (!dr.has_value())
return result<ProgramT>{dr.error()};
tree_arena<Core, MaxNodes> core_arena;
auto er =
elaborate<MaxNodes, MaxList>(dr.value().value, arena_dr, core_arena);
if (!er.has_value())
return result<ProgramT>{er.error()};
auto const &ct_root = er.value();
return result<ProgramT>{ProgramT{ct_root, core_arena}};
}
} // namespace smd::schemepoc
// --- End inlined: smd/schemepoc/sender_backend.hpp ---
// --- Begin inlined: smd/schemepoc/sender_adapter.hpp ---
// --- End inlined: smd/schemepoc/sender_adapter.hpp ---
namespace scm = smd::schemepoc;
using Core = scm::core_type<512, 16>;
// 2. Foreign Function Interfaces (FFIs) mapped manually.
constexpr auto ffi_eq(std::span<scm::value<Core> const> args)
-> scm::result<scm::value<Core>> {
if (args.size() != 2) return scm::parse_error{{}, "arity eq?"};
if (!std::holds_alternative<int>(args[0]) || !std::holds_alternative<int>(args[1]))
return scm::parse_error{{}, "type err eq?"};
return scm::value<Core>{std::get<int>(args[0]) == std::get<int>(args[1])};
}
constexpr auto ffi_print_and_return(std::span<scm::value<Core> const> args)
-> scm::result<scm::value<Core>> {
if (args.size() != 2) return scm::parse_error{{}, "arity print-and-return"};
if (!std::holds_alternative<int>(args[0]))
return scm::parse_error{{}, "type err print-and-return"};
if (!std::is_constant_evaluated()) {
std::println("Scheme executing evaluation step for n = {}", std::get<int>(args[0]));
}
return args[1];
}
// 3. Compile-time generation of the Runtime State Aggregates using Reflection.
// This creates a physical C++ `struct` natively from the descriptor list.
struct RuntimeStateTag {};
consteval {
scm::compile_environment<RuntimeStateTag>({
{^^int, "eval_result"},
{^^bool, "successful_run"}
});
}
// 1. Non-trivial Scheme program compiled to heavily optimized CPS form strictly
// at compile-time.
// This is the Y-combinator executing Fibonacci recursively.
constexpr auto scheme_source = R"(
((lambda (fib)
(fib fib 5))
(lambda (self n)
(print-and-return n
(if (eq? n 0)
0
(if (eq? n 1)
1
(+ (self self (+ n -1))
(self self (+ n -2))))))))
)";
constexpr auto program = scm::compile_to_sender<512, 16>(scheme_source).value();
int main() {
std::println("==== Compile-Time Scheme -> Sender Runtime Execution ====");
auto env = scm::default_env<Core, 16>();
env.define("eq?", scm::value<Core>{scm::foreign_function<Core>{ffi_eq}});
env.define("print-and-return", scm::value<Core>{scm::foreign_function<Core>{ffi_print_and_return}});
std::println("Running pre-compiled Scheme application via Senders...");
auto s = program(env);
auto res_opt = scm::sender_v::sync_wait(std::move(s));
scm::reified_environment<RuntimeStateTag> state{};
if (res_opt.has_value()) {
auto result = std::get<0>(res_opt.value());
if (result.has_value()) {
state.successful_run = true;
state.eval_result = std::get<int>(result.value());
std::println("Final Scheme Result Output: {}", state.eval_result);
} else {
state.successful_run = false;
std::println(stderr, "Error evaluating Scheme: {}", result.error().message);
return 1;
}
} else {
std::println(stderr, "Sender sync_wait returned empty optional.");
return 1;
}
return 0;
}