From 6c7216ed7d592bbbd17ef0ed06fc7fe7e6572ae3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 12 Mar 2026 20:26:08 -0500 Subject: [PATCH] xo-interpreter2 stack: refactor + bugfix operator expr --- cmake/xo_procedure2Config.cmake.in | 2 +- include/xo/procedure2/DPrimitive.hpp | 42 +++- include/xo/procedure2/PrimitiveRegistry.hpp | 89 ++++++++ .../procedure2_register_primitives.hpp | 18 ++ src/procedure2/CMakeLists.txt | 3 +- src/procedure2/PrimitiveRegistry.cpp | 49 +++++ src/procedure2/init_primitives.cpp | 192 ------------------ 7 files changed, 195 insertions(+), 200 deletions(-) create mode 100644 include/xo/procedure2/PrimitiveRegistry.hpp create mode 100644 include/xo/procedure2/procedure2_register_primitives.hpp create mode 100644 src/procedure2/PrimitiveRegistry.cpp diff --git a/cmake/xo_procedure2Config.cmake.in b/cmake/xo_procedure2Config.cmake.in index 96f11c9..250797d 100644 --- a/cmake/xo_procedure2Config.cmake.in +++ b/cmake/xo_procedure2Config.cmake.in @@ -6,8 +6,8 @@ include(CMakeFindDependencyMacro) # must coordinate with xo_dependency() calls # in CMakeLists.txt # +find_dependency(xo_type) find_dependency(xo_object2) -#find_dependency(xo_gc) find_dependency(subsys) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") diff --git a/include/xo/procedure2/DPrimitive.hpp b/include/xo/procedure2/DPrimitive.hpp index 17c1943..7735bf0 100644 --- a/include/xo/procedure2/DPrimitive.hpp +++ b/include/xo/procedure2/DPrimitive.hpp @@ -55,6 +55,18 @@ namespace xo { } /** @brief Schematika primitive with fixed number of arguments + * + * Distinction between type-constructor (@ref type_) and + * type-description (@ref fn_td_): type-constructor is narrower; + * it may lift into schematika type system some information about function + * behavior. For example + * @pre + * cons :: (T x list) -> list + * @endpre + * but implementation has signature: + * @pre + * (obj x obj) -> obj + * @endpre **/ template class Primitive { @@ -70,13 +82,28 @@ namespace xo { using ppindentinfo = xo::print::ppindentinfo; public: - Primitive(std::string_view name, Fn fn) : name_{name}, - fn_td_{Reflect::require()}, - fn_{fn} {} + /** @defgroup scm-primitive-ctors constructors **/ + ///@{ + + Primitive(std::string_view name, Fn fn) + : name_{name}, + fn_td_{Reflect::require()}, + fn_{fn} {} + + static Primitive * _make(obj mm, std::string_view name, Fn fn) { + void * mem = mm.alloc_for(); + + return new (mem) Primitive(name, fn); + } + + ///@} + /** @defgroup scm-primitive-methods general methods **/ + ///@{ TypeDescr fn_td() const noexcept { return fn_td_; } std::string_view name() const noexcept { return name_; } + static constexpr std::int32_t n_args() noexcept { return Traits::n_args; } bool is_nary() const noexcept { return false; } @@ -86,6 +113,7 @@ namespace xo { std::make_index_sequence{}); } + ///@} /** @defgroup scm-primitive-printable-facet **/ ///@{ @@ -166,8 +194,12 @@ namespace xo { template std::size_t - Primitive::forward_children(obj) noexcept { - // Primitive holds no GC refs (just string_view + function pointer) + Primitive::forward_children(obj gc) noexcept { + { + auto e = type_.to_facet(); // FacetRegistry dep + gc.forward_inplace(e.iface(), (void **)&(type_.data_)); + } + return this->shallow_size(); } diff --git a/include/xo/procedure2/PrimitiveRegistry.hpp b/include/xo/procedure2/PrimitiveRegistry.hpp new file mode 100644 index 0000000..6f1f67e --- /dev/null +++ b/include/xo/procedure2/PrimitiveRegistry.hpp @@ -0,0 +1,89 @@ +/** @file PrimitiveRegistry.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "Procedure.hpp" +#include +#include +#include + +namespace xo { + namespace scm { + /** partition primitives based on scope. + * Each primitive associates with exactly one flag value. + * Flags also operate as bitmasks when calling + * @ref PrimitiveRegistry::install_primitives() + **/ + enum class InstallFlags { + f_none = 0x0, + + /** mandatory primitives, necessary for operator support, + * e.g. _add needed to implement infix + + **/ + f_essential = 0x1, + f_generalpurpose = 0x2, + + /** all primitives **/ + f_all = f_essential | f_generalpurpose, + }; + + inline InstallFlags operator&(InstallFlags x, InstallFlags y) { + return InstallFlags(static_cast(x) & static_cast(y)); + } + + + + /** provided by VSM to receive created primitives. + * InstallSink(pm) adopts a primitive + **/ + using InstallSink = std::function pm, + InstallFlags flags)>; + + /** @class PrimitiveRegistry + * + * @brief Runtime registry for primitives + * + * Singleton to remember setup code for known primitives. + * Use to gather primitives for installation in global + * environment for a virtual schematika machine (VSM) + **/ + class PrimitiveRegistry { + public: + using AAllocator = xo::mm::AAllocator; + + /** provided by a subsystem that provides primitives. + * Allocates primitives using memory from mm, delivering them + * to InstallSink sink. + **/ + using InstallSource = std::function mm, + InstallSink sink, + InstallFlags flags)>; + + public: + /** singleton instance **/ + static PrimitiveRegistry & instance(); + + /** remember primitive-factory @p source_fn **/ + void register_primitives(InstallSource source_fn); + + /** create primitives using memory from @p mm, + * delivering each primitive to @p sink. + **/ + bool install_primitives(obj mm, + InstallSink sink, + InstallFlags flags); + + private: + /** a set of factories that create primitives **/ + std::vector init_seq_v_; + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end PrimitiveRegistry.hpp */ diff --git a/include/xo/procedure2/procedure2_register_primitives.hpp b/include/xo/procedure2/procedure2_register_primitives.hpp new file mode 100644 index 0000000..12e1db9 --- /dev/null +++ b/include/xo/procedure2/procedure2_register_primitives.hpp @@ -0,0 +1,18 @@ +/** @file procedure2_register_primitives.hpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#pragma once + +#include "PrimitiveRegistry.hpp" +#include + +namespace xo { + namespace scm { + /** Register gc-aware (AGCObject,DRepr) combinations with garbage collector @p gc **/ + bool procedure2_register_primitives(obj gc, InstallSink sink); + } +} + +/* end procedure2_register_primitives.hpp */ diff --git a/src/procedure2/CMakeLists.txt b/src/procedure2/CMakeLists.txt index b74b3e6..1a65a62 100644 --- a/src/procedure2/CMakeLists.txt +++ b/src/procedure2/CMakeLists.txt @@ -34,10 +34,9 @@ xo_install_include_tree3(include/xo/procedure2) # NOTE: dependency set here must be kept consistent with # xo-procedure2/cmake/xo_procedure2Config.cmake.in +xo_dependency(${SELF_LIB} xo_type) xo_dependency(${SELF_LIB} xo_object2) -#xo_dependency(${SELF_LIB} xo_gc) xo_dependency(${SELF_LIB} subsys) -#xo_dependency(${SELF_LIB} xo_indentlog) xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) diff --git a/src/procedure2/PrimitiveRegistry.cpp b/src/procedure2/PrimitiveRegistry.cpp new file mode 100644 index 0000000..0ce7aa6 --- /dev/null +++ b/src/procedure2/PrimitiveRegistry.cpp @@ -0,0 +1,49 @@ +/** @file PrimitiveRegistry.cpp + * + * @author Roland Conybeare, Mar 2026 + **/ + +#include "PrimitiveRegistry.hpp" +#include + +namespace xo { + namespace scm { + PrimitiveRegistry & + PrimitiveRegistry::instance() + { + static PrimitiveRegistry s_instance; + + return s_instance; + } + + void + PrimitiveRegistry::register_primitives(InstallSource factory) + { + scope log(XO_DEBUG(true)); + + init_seq_v_.push_back(factory); + } + + bool + PrimitiveRegistry::install_primitives(obj mm, + InstallSink sink, + InstallFlags flags) + { + scope log(XO_DEBUG(true)); + + bool ok = true; + + size_t i = 0; + size_t n = init_seq_v_.size(); + log && log("run n init steps", xtag("n", n)); + + for (const auto & fn : init_seq_v_) { + log && log("do install fn (", i+1, "/", n, ")"); + + ok = ok & fn(mm, sink, flags); + } + + return ok; + } + } +} /*namespace xo*/ diff --git a/src/procedure2/init_primitives.cpp b/src/procedure2/init_primitives.cpp index 142ad86..58b9d7a 100644 --- a/src/procedure2/init_primitives.cpp +++ b/src/procedure2/init_primitives.cpp @@ -37,187 +37,6 @@ namespace xo { } #endif -#ifdef OBSOLETE // see xo-numeric/xo/numeric/NumericPrimitives.cpp - obj - mul_gco_gco(obj rcx, - obj x_gco, - obj y_gco) - { - using xo::reflect::typeseq; - - obj mm = rcx.allocator(); - - // PLACEHOLDER - - // TODO: - // 1. move this to xo-numeric2/ when available - // 2. at that point will require polymorphic dispatch - // on argument representations, analogous to dispatch - // in FacetRegistry - - typeseq x_tseq = x_gco._typeseq(); - typeseq y_tseq = y_gco._typeseq(); - - // FOR NOW: just test runtime values - // - if (x_tseq == typeseq::id()) { - // i64 * .. - long x = GCObjectConversion::from_gco(mm, x_gco); - - if (y_tseq == typeseq::id()) { - // i64 * i64 - long y = GCObjectConversion::from_gco(mm, y_gco); - - return DInteger::box(mm, x * y); - } else if (y_tseq == typeseq::id()) { - // i64 * f64 - double y = GCObjectConversion::from_gco(mm, y_gco); - - return DFloat::box(mm, x * y); - } - } else if (x_tseq == typeseq::id()) { - if (y_tseq == typeseq::id()) { - // f64 * i64. - double x = GCObjectConversion::from_gco(mm, x_gco); - long y = GCObjectConversion::from_gco(mm, y_gco); - - return DFloat::box(mm, x * y); - } else if (y_tseq == typeseq::id()) { - // f64 * f64. - double x = GCObjectConversion::from_gco(mm, x_gco); - double y = GCObjectConversion::from_gco(mm, y_gco); - - return DFloat::box(mm, x * y); - } - } - - // here: error - throw std::runtime_error(tostr("mul_gco_gco: unexpected argument types xt,yt", - xtag("x.tseq", x_tseq), - xtag("y.tseq", y_tseq))); - return obj(); - } - - obj - sub_gco_gco(obj rcx, - obj x_gco, - obj y_gco) - { - using xo::reflect::typeseq; - - obj mm = rcx.allocator(); - - // PLACEHOLDER - - // TODO: - // 1. move this to xo-numeric2/ when available - // 2. at that point will require polymorphic dispatch - // on argument representations, analogous to dispatch - // in FacetRegistry - - typeseq x_tseq = x_gco._typeseq(); - typeseq y_tseq = y_gco._typeseq(); - - // FOR NOW: just test runtime values - // - if (x_tseq == typeseq::id()) { - // i64 * .. - long x = GCObjectConversion::from_gco(mm, x_gco); - - if (y_tseq == typeseq::id()) { - // i64 * i64 - long y = GCObjectConversion::from_gco(mm, y_gco); - - return DInteger::box(mm, x - y); - } else if (y_tseq == typeseq::id()) { - // i64 * f64 - double y = GCObjectConversion::from_gco(mm, y_gco); - - return DFloat::box(mm, x - y); - } - } else if (x_tseq == typeseq::id()) { - if (y_tseq == typeseq::id()) { - // f64 * i64. - double x = GCObjectConversion::from_gco(mm, x_gco); - long y = GCObjectConversion::from_gco(mm, y_gco); - - return DFloat::box(mm, x - y); - } else if (y_tseq == typeseq::id()) { - // f64 * f64. - double x = GCObjectConversion::from_gco(mm, x_gco); - double y = GCObjectConversion::from_gco(mm, y_gco); - - return DFloat::box(mm, x - y); - } - } - - // here: error - throw std::runtime_error(tostr("sub_gco_gco: unexpected argument types xt,yt", - xtag("x.tseq", x_tseq), - xtag("y.tseq", y_tseq))); - return obj(); - } - - obj - equal_gco_gco(obj rcx, - obj x_gco, - obj y_gco) - { - using xo::reflect::typeseq; - - obj mm = rcx.allocator(); - - // PLACEHOLDER - - // TODO - // 1. move this to xo-numeric2/ when available - // 2. at that point will require polymorphic dispatch on argument representations. - // - - typeseq x_tseq = x_gco._typeseq(); - typeseq y_tseq = y_gco._typeseq(); - - // FOR NOW: just test runtime values - // - if (x_tseq == typeseq::id()) { - // i64 * .. - long x = GCObjectConversion::from_gco(mm, x_gco); - - if (y_tseq == typeseq::id()) { - // i64 == i64 - long y = GCObjectConversion::from_gco(mm, y_gco); - - return DBoolean::box(mm, x == y); - } else if (y_tseq == typeseq::id()) { - // i64 == f64 - double y = GCObjectConversion::from_gco(mm, y_gco); - - return DFloat::box(mm, static_cast(x) == y); - } - } else if (x_tseq == typeseq::id()) { - if (y_tseq == typeseq::id()) { - // f64 == i64. - double x = GCObjectConversion::from_gco(mm, x_gco); - long y = GCObjectConversion::from_gco(mm, y_gco); - - return DFloat::box(mm, x == static_cast(y)); - } else if (y_tseq == typeseq::id()) { - // f64 * f64. - double x = GCObjectConversion::from_gco(mm, x_gco); - double y = GCObjectConversion::from_gco(mm, y_gco); - - return DFloat::box(mm, x == y); - } - } - - // here: error - throw std::runtime_error(tostr("mul_gco_gco: unexpected argument types xt,yt", - xtag("x.tseq", x_tseq), - xtag("y.tseq", y_tseq))); - return obj(); - } -#endif - #ifdef NOT_YET double mul_f64_f64(double x, double y) { @@ -255,17 +74,6 @@ namespace xo { } #endif -#ifdef OSOLETE - DPrimitive_gco_2_gco_gco - Primitives::s_mul_gco_gco_pm("_mul", &mul_gco_gco); - - DPrimitive_gco_2_gco_gco - Primitives::s_sub_gco_gco_pm("_sub", &sub_gco_gco); - - DPrimitive_gco_2_gco_gco - Primitives::s_equal_gco_gco_pm("_equal", &equal_gco_gco); -#endif - #ifdef NOT_YET Primitive_f64_1_f64 Primitives::s_neg_f64_pm("_neg_d",