Steve Downey

@Sdowney
573 Followers
575 Following
3.6K Posts

Software engineer at Bloomberg LP

Views are my own

he/him

https://bsky.app/profile/sdowney.bsky.social

https://sdowney.org/

Emacs 31 pretest marked! 31.0.90

https://github.com/emacs-mirror/emacs/commit/4f4af26dd2ff7b2e5c7d35c6f8ffdabc5024d5b6

If you aren't already running it (😊) now is a good time to try it out with your config and help spot any problems.

Lots of good stuff with this one.

#emacs

Bump Emacs version to 31.0.90 · emacs-mirror/emacs@4f4af26

* README: * configure.ac: * exec/configure.ac: * java/AndroidManifest.xml.in (Version-code): * msdos/sed2v2.inp: * nt/README.W32: Bump Emacs version to 31.0.90.

GitHub
sandbox-expected/tests/beman/expected/CMakeLists.txt at main · steve-downey/sandbox-expected

An implementation of std::expected. Contribute to steve-downey/sandbox-expected development by creating an account on GitHub.

GitHub

I heard you like compilers so I wrote a compile time scheme compiler and put it in your C++26 compiler that compiles to Senders and reflection generates them into runtime aggregates.

Oh, and a C++ FFI, since that was almost free.

Y combinator Fib:
https://godbolt.org/z/hTTTvWaGc

https://github.com/steve-downey/compile-time-scheme/tree/main

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; }

A strange mix of fear and joy.

I just deliberately killed Chrome and when I restarted just closed the dialog box asking if I wanted to restore all my tabs.

I spent more than an hour because the string I was formatting is used by something else as format-spec, and it was HTML with lots of % and ".

Yay.

#emacs

I was wondering why I was seeing so many "Co-authored-by: Copilot" commits recently. It turns out VS Code added a "feature" that inserts that into your commits automatically, even if you're not using Copilot.

It looks like people complained about this, which went nowhere until this hit the front page of HN. After this was the top HN story Saturday, an MS engineer submitted a PR to switch this feature to default off an hour ago (midnight Redmond time).

What will they think of next?

"A question starts with Who, What, Where, When, Why, or How and goes up at the end."
"If it's more of a comment, hold that for a moment."

TFW each slide could be an entire talk, and there are a *lot* of slides.

F-algebras and type fixpoint in C++26 for recursive types like expression trees is almost a drive by example.

But, by Crom, I have Traversable, which is what Applicative is for. And open extension and retro-fit.

Off to see the wizard ...

Wait, no, that's me ...

Off to The Shire?

Off to C++Now '26!

#cppnow26

In the midst of what I'm really working on for C++Now, I noticed I have a typelevel fixpoint combinator for 0 overhead recursive data types, because std::indirect is a good Box.

Expression evaluators for free now.

Compiler Explorer https://godbolt.org/z/T1G4zzd1o via @compiler_explorer

Compiler Explorer - C++ (x86-64 gcc (trunk))

// Fixpoint Trees in C++: F-Algebras and Catamorphisms // Self-contained example — paste directly into Compiler Explorer. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // Box<A>: value-semantic wrapper for recursive positions. // Stands in for std::indirect (C++26) until it ships. template <typename A> using Box = std::indirect<A>; template <typename A, typename... Args> auto make_box(Args&&... args) -> Box<A> { return std::indirect<A>(std::forward<Args>(args)...); } // 1. The flat, non-recursive functor. No inheritance, no CRTP. template <typename A> struct Const { int val; }; template <typename A> struct Add { Box<A> left, right; }; template <typename A> struct Mul { Box<A> left, right; }; template <typename A> using ExprF = std::variant<Const<A>, Add<A>, Mul<A>>; // 2. The type-level fixed-point combinator. Pure composition (has-a). template <template <typename> class F> struct Fix { F<Fix<F>> inner; }; // 3. Zero-cost phantom operations (isorecursive boundaries) template <template <typename> class F> constexpr Fix<F> wrap(F<Fix<F>> f) { return Fix<F>{std::move(f)}; } template <template <typename> class F> constexpr const F<Fix<F>>& unwrap(const Fix<F>& f) { return f.inner; } // 4. Visitor helper and fmap template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>; template <typename A, typename B, typename Func> ExprF<B> fmap(Func&& f, const ExprF<A>& fa) { return std::visit( overloaded{ [](const Const<A>& c) -> ExprF<B> { return Const<B>{c.val}; }, [&f](const Add<A>& a) -> ExprF<B> { return Add<B>{make_box<B>(f(*a.left)), make_box<B>(f(*a.right))}; }, [&f](const Mul<A>& m) -> ExprF<B> { return Mul<B>{make_box<B>(f(*m.left)), make_box<B>(f(*m.right))}; }, }, fa); } // 5. Catamorphism (cata): the universal fold for fixpoint types. // The trailing return type breaks the recursive deduction cycle. // The algebra is applied via std::visit over the evaluated layer. template <template <typename> class F, typename Algebra> auto cata(const Algebra& alg, const Fix<F>& tree) -> decltype(std::visit(alg, std::declval<F<int>>())) { using Carrier = decltype(std::visit(alg, std::declval<F<int>>())); return std::visit(alg, fmap<Fix<F>, Carrier>( [&alg](const Fix<F>& child) -> Carrier { return cata<F>(alg, child); }, unwrap(tree))); } // 6. Smart constructors hide Fix wrapping and heap allocation. using ExprTree = Fix<ExprF>; ExprTree const_node(int v) { return wrap<ExprF>(Const<ExprTree>{v}); } ExprTree add_node(ExprTree l, ExprTree r) { return wrap<ExprF>(Add<ExprTree>{make_box<ExprTree>(std::move(l)), make_box<ExprTree>(std::move(r))}); } ExprTree mul_node(ExprTree l, ExprTree r) { return wrap<ExprF>(Mul<ExprTree>{make_box<ExprTree>(std::move(l)), make_box<ExprTree>(std::move(r))}); } // 7. Usage: building and evaluating an expression tree. // The algebra is entirely non-recursive — cata handles the recursion. int main() { // Build the tree: (2 * 3) + 4 ExprTree tree = add_node(mul_node(const_node(2), const_node(3)), const_node(4)); // Evaluate using a non-recursive algebra auto eval_algebra = overloaded{ [](const Const<int>& c) { return c.val; }, [](const Add<int>& a) { return *a.left + *a.right; }, [](const Mul<int>& m) { return *m.left * *m.right; }, }; std::cout << "Result: " << cata<ExprF>(eval_algebra, tree) << "\n"; return 0; }