diff --git a/CMakeLists.txt b/CMakeLists.txt index d319ad93..8ae5fd91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,11 +99,11 @@ add_subdirectory(xo-callback) add_subdirectory(xo-printable2) # experiment w/ facet object model add_subdirectory(xo-alloc) add_subdirectory(xo-alloc2) # experiment w/ facet object model -add_subdirectory(xo-numeric) # experiment w/ facet object model add_subdirectory(xo-gc) add_subdirectory(xo-object) add_subdirectory(xo-object2) # experiment w/ facet object model add_subdirectory(xo-procedure2) # schematika procedure abstraction + runtime context (fomo) +add_subdirectory(xo-numeric) # experiment w/ facet object model add_subdirectory(xo-ordinaltree) # add_subdirectory(xo-tokenizer2) # schematika tokenizer (fomo) diff --git a/xo-facet/include/xo/facet/FacetRegistry.hpp b/xo-facet/include/xo/facet/FacetRegistry.hpp index 2beb99b2..eda22f5d 100644 --- a/xo-facet/include/xo/facet/FacetRegistry.hpp +++ b/xo-facet/include/xo/facet/FacetRegistry.hpp @@ -50,7 +50,8 @@ namespace xo { // combine the two seqno values std::size_t h1 = std::hash{}(k.first.seqno()); std::size_t h2 = std::hash{}(k.second.seqno()); - return h1 ^ (h2 << 1); + + return h1 ^ (h2 << 3); } }; diff --git a/xo-interpreter2/src/skrepl/skreplxx.cpp b/xo-interpreter2/src/skrepl/skreplxx.cpp index df6be29d..6d68fb32 100644 --- a/xo-interpreter2/src/skrepl/skreplxx.cpp +++ b/xo-interpreter2/src/skrepl/skreplxx.cpp @@ -9,6 +9,9 @@ #include #include #include +#ifdef __APPLE__ +#include // for STDIN_FILENO on OSX +#endif namespace xo { using xo::scm::VirtualSchematikaMachine; @@ -85,7 +88,7 @@ namespace xo { AppConfig(const ReplConfig & repl_cfg = ReplConfig(), const ArenaConfig & app_arena_cfg = ArenaConfig().with_name("skreplxx").with_size(16 * 1024), - const VsmConfig & vsm_cfg = VsmConfig()) + const VsmConfig & vsm_cfg = VsmConfig()) : repl_config_{repl_cfg}, app_arena_config_{app_arena_cfg}, vsm_config_{vsm_cfg} { //rdr_config_.reader_debug_flag_ = true; @@ -239,4 +242,3 @@ main (int argc, char * argv[]) } /*main*/ /* end skreplxx.cpp */ - diff --git a/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp b/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp index 77b3a30b..75726b72 100644 --- a/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp +++ b/xo-interpreter2/utest/VirtualSchematikaMachine.test.cpp @@ -73,8 +73,8 @@ namespace xo { }; aux_mm_.arena_.visit_pools(visitor); - FacetRegistry::instance().visit_pools(visitor); TypeRegistry::instance().visit_pools(visitor); + FacetRegistry::instance().visit_pools(visitor); vsm_.visit_pools(visitor); return true; @@ -189,6 +189,37 @@ namespace xo { log && vsm_fixture.log_memory_layout(&log); } + TEST_CASE("VirtualSchematikaMachine-arith2", "[interpreter2][VSM]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + VsmFixture vsm_fixture(testname, c_debug_flag); + auto & vsm = vsm_fixture.vsm_; + + bool eof_flag = false; + + vsm.begin_interactive_session(); + VsmResultExt res = vsm.read_eval_print(span_type::from_cstr("3.14159265 / 0.5;"), eof_flag); + + REQUIRE(res.is_value()); + REQUIRE(res.value()); + + log && log(xtag("res.tseq", res.value()->_typeseq())); + + auto x = obj::from(*res.value()); + + REQUIRE(x); + REQUIRE(x.data()->value() == 6.2831853); + + REQUIRE(res.remaining_.size() == 1); + REQUIRE(*res.remaining_.lo() == '\n'); + + log && vsm_fixture.log_memory_layout(&log); + } + TEST_CASE("VirtualSchematikaMachine-cmp1", "[interpreter2][VSM]") { const auto & testname = Catch::getResultCapture().getCurrentTestName(); diff --git a/xo-numeric/CMakeLists.txt b/xo-numeric/CMakeLists.txt index c762fbfa..92d4b9e7 100644 --- a/xo-numeric/CMakeLists.txt +++ b/xo-numeric/CMakeLists.txt @@ -29,14 +29,32 @@ xo_add_genfacet( # ---------------------------------------------------------------- +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-numeric-facetimpl-numeric-float + FACET_PKG xo_numeric + FACET Numeric + REPR Float + INPUT idl/INumeric_DFloat.json5 +) + +# note: manual target; generated code committed to git +xo_add_genfacetimpl( + TARGET xo-numeric-facetimpl-numeric-integer + FACET_PKG xo_numeric + FACET Numeric + REPR Integer + INPUT idl/INumeric_DInteger.json5 +) + +# ---------------------------------------------------------------- + xo_add_genfacet_all(xo-numeric-genfacet-all) # ---------------------------------------------------------------- -#add_subdirectory(src/numeric) # NOTE: will need cmake export here -#add_subdirectory(utest) +add_subdirectory(src/numeric) +add_subdirectory(utest) # ---------------------------------------------------------------- # cmake export - - diff --git a/xo-numeric/NumericDispatch.hpp b/xo-numeric/NumericDispatch.hpp deleted file mode 100644 index a312c1c1..00000000 --- a/xo-numeric/NumericDispatch.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/** @file NumericDispatch.hpp - * - * @author Roland Conybeare, Feb 2026 - **/ - -#pragma once - -//#include // probably will need this at some point? -#include -#include - -namespace xo { - namespace scm { - - /** type-erased arithmetic dispatch. - **/ - struct NumericOps { - obj - }; - - class NumericDispatch { - public: - using KeyType = std::pair; - using MapType = xo::map::DArenaHashMap - - /** combine two typeseq's to get hash value **/ - struct KeyHash { - std::size_t operator()(const key_type & k) const noexcept { - // combine the two seqno values - std::size_t h1 = std::hash{}(k.first.seqno()); - std::size_t h2 = std::hash{}(k.second.seqno()); - return h1 ^ (h2 << 1); - } - }; - - - }; - - } /*namespace scm*/ -} /*namespace xo*/ - -/* end NumericDispqatch.hpp */ - - diff --git a/xo-numeric/cmake/xo_numericConfig.cmake.in b/xo-numeric/cmake/xo_numericConfig.cmake.in index 4155d92e..a38ab389 100644 --- a/xo-numeric/cmake/xo_numericConfig.cmake.in +++ b/xo-numeric/cmake/xo_numericConfig.cmake.in @@ -7,7 +7,7 @@ include(CMakeFindDependencyMacro) # in CMakeLists.txt # #find_dependency(xo_gc) -find_dependency(xo_facet) +find_dependency(xo_procedure2) find_dependency(subsys) #find_dependency(indentlog) diff --git a/xo-numeric/idl/INumeric_DFloat.json5 b/xo-numeric/idl/INumeric_DFloat.json5 new file mode 100644 index 00000000..6b269c6d --- /dev/null +++ b/xo-numeric/idl/INumeric_DFloat.json5 @@ -0,0 +1,18 @@ +{ + mode: "implementation", + output_cpp_dir: "src/numeric", + output_hpp_dir: "include/xo/numeric", + output_impl_subdir: "float", + includes: [ +// "", +// "" + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Numeric.json5", + brief: "provide ANumeric interface for DFloat", + using_doxygen: true, + repr: "DFloat", + doc: [ "implement ANumeric for DFloat" ], +} diff --git a/xo-numeric/idl/INumeric_DInteger.json5 b/xo-numeric/idl/INumeric_DInteger.json5 new file mode 100644 index 00000000..5c478c12 --- /dev/null +++ b/xo-numeric/idl/INumeric_DInteger.json5 @@ -0,0 +1,18 @@ +{ + mode: "implementation", + output_cpp_dir: "src/numeric", + output_hpp_dir: "include/xo/numeric", + output_impl_subdir: "integer", + includes: [ +// "", +// "" + ], + local_types: [ ], + namespace1: "xo", + namespace2: "scm", + facet_idl: "idl/Numeric.json5", + brief: "provide ANumeric interface for DInteger", + using_doxygen: true, + repr: "DInteger", + doc: [ "implement ANumeric for DInteger" ], +} diff --git a/xo-numeric/include/xo/numeric/FloatIntegerOps.hpp b/xo-numeric/include/xo/numeric/FloatIntegerOps.hpp new file mode 100644 index 00000000..97a2c3f6 --- /dev/null +++ b/xo-numeric/include/xo/numeric/FloatIntegerOps.hpp @@ -0,0 +1,42 @@ +/** @file FloatIntegerOps.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "Numeric.hpp" +#include +#include +#include + + +namespace xo { + namespace scm { + + class FloatIntegerOps { + public: + using AGCObject = xo::mm::AGCObject; + + public: + static obj multiply(obj rcx, + DFloat * x, DInteger * y); + static obj divide(obj rcx, + DFloat * x, DInteger * y); + }; + + class IntegerFloatOps { + public: + using AGCObject = xo::mm::AGCObject; + + public: + static obj multiply(obj rcx, + DInteger * x, DFloat * y); + static obj divide(obj rcx, + DInteger * x, DFloat * y); + }; + + } +} + +/* end FloatIntegerOps.hpp */ diff --git a/xo-numeric/include/xo/numeric/FloatOps.hpp b/xo-numeric/include/xo/numeric/FloatOps.hpp new file mode 100644 index 00000000..c3a2c288 --- /dev/null +++ b/xo-numeric/include/xo/numeric/FloatOps.hpp @@ -0,0 +1,30 @@ +/** @file FloatOps.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "Numeric.hpp" +#include +#include + + +namespace xo { + namespace scm { + + class FloatOps { + public: + using AGCObject = xo::mm::AGCObject; + + public: + static obj multiply(obj rcx, + DFloat * x, DFloat * y); + static obj divide(obj rcx, + DFloat * x, DFloat * y); + }; + + } +} + +/* end FloatOps.hpp */ diff --git a/xo-numeric/include/xo/numeric/IntegerOps.hpp b/xo-numeric/include/xo/numeric/IntegerOps.hpp new file mode 100644 index 00000000..4f9138de --- /dev/null +++ b/xo-numeric/include/xo/numeric/IntegerOps.hpp @@ -0,0 +1,31 @@ +/** @file IntegerOps.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include "Numeric.hpp" +#include +#include + +namespace xo { + namespace scm { + + class IntegerOps { + public: + using AGCObject = xo::mm::AGCObject; + + public: + static obj multiply(obj rcx, + DInteger * x, DInteger * y); + + static obj divide(obj rcx, + DInteger * x, DInteger * y); + + }; + + } +} + +/* end IntegerOps.hpp */ diff --git a/xo-numeric/include/xo/numeric/NumericDispatch.hpp b/xo-numeric/include/xo/numeric/NumericDispatch.hpp index 45f12a75..5174430e 100644 --- a/xo-numeric/include/xo/numeric/NumericDispatch.hpp +++ b/xo-numeric/include/xo/numeric/NumericDispatch.hpp @@ -5,13 +5,93 @@ #pragma once +#include "NumericOps.hpp" +#include +#include +#include +#include + namespace xo { namespace scm { + /** Runtime polymoprhic multimethod dispatch. + * Hash on argument types to get function table + **/ class NumericDispatch { public: + //using AAllocator = xo::mm::AAllocator; + using AGCObject = xo::mm::AGCObject; + using MemorySizeVisitor = xo::mm::MemorySizeVisitor; + using typeseq = xo::reflect::typeseq; + using KeyType = std::pair; + using MappedType = AnonymizedNumericOps; - + /** hash function for key_type **/ + struct KeyHash { + + std::size_t operator()(const KeyType & k) const noexcept { + // combine the two seqno values + std::size_t h1 = std::hash{}(k.first.seqno()); + std::size_t h2 = std::hash{}(k.second.seqno()); + + return h1 ^ (h2 << 7); + } + + }; + + using MapType = xo::map::DArenaHashMap>; + + public: + NumericDispatch(uint32_t hint_max_capacity) + : dispatch_{"numeric-dispatch", + hint_max_capacity, + false /*!debug_flag*/} {} + + /** @p hint_max_capacity only honored the first time instance() + * is called. + **/ + static NumericDispatch & instance(uint32_t hint_max_capacity = 64) { + static NumericDispatch s_instance(hint_max_capacity); + return s_instance; + } + + /** multiply w/ runtime polymorphism (double-dispatch) + **/ + static obj multiply(obj rcx, + obj x, + obj y); + + /** divide w/ runtime polymorphism (double-dispatch) + **/ + static obj divide(obj rcx, + obj x, + obj y); + + /** report memory use for owned arenas to @p visitor **/ + void visit_pools(const MemorySizeVisitor & visitor); + + /** Use: + * Need to have overload + * multiply(obj, DRepr1, DRepr2) -> obj + * available + **/ + template + void register_impl(typename NumericOps::BinaryOp_Impl mul_fn, + typename NumericOps::BinaryOp_Impl div_fn) { + + KeyType key(typeseq::id().seqno(), + typeseq::id().seqno()); + + // note: copying op table so they're in proximity + this->dispatch_[key] = NumericOps::make(mul_fn, div_fn); + } + + private: + /** 2d dispatch for arithmetic **/ + MapType dispatch_; }; } /*namespace scm*/ diff --git a/xo-numeric/include/xo/numeric/NumericOps.hpp b/xo-numeric/include/xo/numeric/NumericOps.hpp index 720d65db..4e900534 100644 --- a/xo-numeric/include/xo/numeric/NumericOps.hpp +++ b/xo-numeric/include/xo/numeric/NumericOps.hpp @@ -1,44 +1,52 @@ /** @file NumericOps.hpp -* + * * @author Roland Conybeare, Feb 2026 **/ #pragma once -#include "Numeric.hpp" +#include +#include +#include +#include namespace xo { namespace scm { - - class INumericOps { + class AnonymizedNumericOps { public: - using BinaryOp1 = obj (*)(obj mm, void * x, void * y); + using ARuntimeContext = xo::scm::ARuntimeContext; + using AGCObject = xo::mm::AGCObject; + using BinaryOp = obj (*)(obj mm, void * x, void * y); public: - explicit INumericOp9s(BinaryOp1 multiply) : multiply_{multiply} {} + /** note: null ctor load-bearing for membership in DArenaHashTable **/ + AnonymizedNumericOps() = default; + /** @p multiply to multiply (x,y); allocate from mm **/ + explicit AnonymizedNumericOps(BinaryOp multiply, + BinaryOp divide) + : multiply_{multiply}, divide_{divide} {} - /** multiply (x,y); allocate from mm **/ - BinaryOp1 multiply_; + BinaryOp multiply_ = nullptr; + BinaryOp divide_ = nullptr; }; - /** Convenience template. To use, provide implementation - * for - * _multiply() ... - * - **/ template - class NumericOps : public INumericOps { + class NumericOps { public: - using BinaryOp1_Impl = obj (*)(obj mm, DRepr1 * x, DRepr2 * y); + using ARuntimeContext = xo::scm::ARuntimeContext; + using AGCObject = xo::mm::AGCObject; + using BinaryOp_Impl = obj (*)(obj rcx, DRepr1 * x, DRepr2 * y); + using BinaryOp_Anon = AnonymizedNumericOps::BinaryOp; public: - explicit NumericOps(BinaryOp1_Impl multiply) - : INumericOps(reinterpret_cast(multiply)) - {} + static AnonymizedNumericOps make(BinaryOp_Impl multiply, + BinaryOp_Impl divide) { + return AnonymizedNumericOps(reinterpret_cast(multiply), + reinterpret_cast(divide)); + } }; } /*namespace scm*/ } /*namespace xo*/ /* end NumericOps.hpp */ - diff --git a/xo-numeric/include/xo/numeric/NumericPrimitives.hpp b/xo-numeric/include/xo/numeric/NumericPrimitives.hpp new file mode 100644 index 00000000..376f94b9 --- /dev/null +++ b/xo-numeric/include/xo/numeric/NumericPrimitives.hpp @@ -0,0 +1,23 @@ +/** @file NumericDispatch.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include + +namespace xo { + namespace scm { + + /** @brief primitives using multidispatch + **/ + class NumericPrimitives { + public: + /** poly divide **/ + static DPrimitive_gco_2_gco_gco s_div_gco_gco_pm; + }; + } +} + +/* end NumericDispatch.hpp */ diff --git a/xo-numeric/include/xo/numeric/float/INumeric_DFloat.hpp b/xo-numeric/include/xo/numeric/float/INumeric_DFloat.hpp new file mode 100644 index 00000000..8e88438e --- /dev/null +++ b/xo-numeric/include/xo/numeric/float/INumeric_DFloat.hpp @@ -0,0 +1,56 @@ +/** @file INumeric_DFloat.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/INumeric_DFloat.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/INumeric_DFloat.json5] + **/ + +#pragma once + +#include "Numeric.hpp" +#include "DFloat.hpp" + +namespace xo { namespace scm { class INumeric_DFloat; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::INumeric_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class INumeric_DFloat + **/ + class INumeric_DFloat { + public: + /** @defgroup scm-numeric-dfloat-type-traits **/ + ///@{ + using Copaque = xo::scm::ANumeric::Copaque; + using Opaque = xo::scm::ANumeric::Opaque; + ///@} + /** @defgroup scm-numeric-dfloat-methods **/ + ///@{ + // const methods + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-numeric/include/xo/numeric/init_numeric.hpp b/xo-numeric/include/xo/numeric/init_numeric.hpp new file mode 100644 index 00000000..c3f1cf19 --- /dev/null +++ b/xo-numeric/include/xo/numeric/init_numeric.hpp @@ -0,0 +1,21 @@ +/** @file init_numeric.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +#include + +namespace xo { + /* tag to represent the xo-numeric/ subsystem within ordered initialization */ + enum S_numeric_tag {}; + + template <> + struct InitSubsys { + static void init(); + static InitEvidence require(); + }; +} + +/* end init_numeric.hpp */ diff --git a/xo-numeric/include/xo/numeric/integer/INumeric_DInteger.hpp b/xo-numeric/include/xo/numeric/integer/INumeric_DInteger.hpp new file mode 100644 index 00000000..ca530949 --- /dev/null +++ b/xo-numeric/include/xo/numeric/integer/INumeric_DInteger.hpp @@ -0,0 +1,56 @@ +/** @file INumeric_DInteger.hpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/INumeric_DInteger.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_repr.hpp.j2] + * 3. idl for facet methods + * [idl/INumeric_DInteger.json5] + **/ + +#pragma once + +#include "Numeric.hpp" +#include "DInteger.hpp" + +namespace xo { namespace scm { class INumeric_DInteger; } } + +namespace xo { + namespace facet { + template <> + struct FacetImplementation + { + using ImplType = xo::scm::INumeric_Xfer + ; + }; + } +} + +namespace xo { + namespace scm { + /** @class INumeric_DInteger + **/ + class INumeric_DInteger { + public: + /** @defgroup scm-numeric-dinteger-type-traits **/ + ///@{ + using Copaque = xo::scm::ANumeric::Copaque; + using Opaque = xo::scm::ANumeric::Opaque; + ///@} + /** @defgroup scm-numeric-dinteger-methods **/ + ///@{ + // const methods + + // non-const methods + ///@} + }; + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end */ \ No newline at end of file diff --git a/xo-numeric/include/xo/numeric/numeric_register_facets.hpp b/xo-numeric/include/xo/numeric/numeric_register_facets.hpp new file mode 100644 index 00000000..7beeb10e --- /dev/null +++ b/xo-numeric/include/xo/numeric/numeric_register_facets.hpp @@ -0,0 +1,16 @@ +/** @file numeric_register_facets.hpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#pragma once + +namespace xo { + namespace scm { + /** Setup numeric facet dispatch **/ + bool numeric_register_facets(); + + } +} + +/* end numeric_register_facets.hpp */ diff --git a/xo-numeric/src/numeric/CMakeLists.txt b/xo-numeric/src/numeric/CMakeLists.txt new file mode 100644 index 00000000..4d2b4345 --- /dev/null +++ b/xo-numeric/src/numeric/CMakeLists.txt @@ -0,0 +1,25 @@ +# numeric/CMakeLists.txt + +set(SELF_LIB xo_numeric) +set(SELF_SRCS + init_numeric.cpp + numeric_register_facets.cpp + NumericPrimitives.cpp + NumericDispatch.cpp + INumeric_Any.cpp + FloatIntegerOps.cpp + FloatOps.cpp + IntegerOps.cpp +) + +xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) +xo_dependency(${SELF_LIB} xo_procedure2) +xo_dependency(${SELF_LIB} subsys) + +xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) + +# ---------------------------------------------------------------- +# docs targets depend on other library/utest/exec targets above, +# --> must come after them. +# +#add_subdirectory(docs) diff --git a/xo-numeric/src/numeric/FloatIntegerOps.cpp b/xo-numeric/src/numeric/FloatIntegerOps.cpp new file mode 100644 index 00000000..65a106ab --- /dev/null +++ b/xo-numeric/src/numeric/FloatIntegerOps.cpp @@ -0,0 +1,48 @@ +/** @file FloatIntegerOps.cp + * + * @author Roland Conybeare, Feb 2206 + **/ + +#include "FloatIntegerOps.hpp" +#include "float/INumeric_DFloat.hpp" + +namespace xo { + using xo::mm::AGCObject; + + namespace scm { + + // ----- Float op Integer ----- + + obj + FloatIntegerOps::multiply(obj rcx, + DFloat * x, DInteger * y) + { + return DFloat::box(rcx.allocator(), x->value() * y->value()); + } + + obj + FloatIntegerOps::divide(obj rcx, + DFloat * x, DInteger * y) + { + return DFloat::box(rcx.allocator(), x->value() / y->value()); + } + + // ----- Integer op Float ----- + + obj + IntegerFloatOps::multiply(obj rcx, + DInteger * x, DFloat * y) + { + return DFloat::box(rcx.allocator(), x->value() * y->value()); + } + + obj + IntegerFloatOps::divide(obj rcx, + DInteger * x, DFloat * y) + { + return DFloat::box(rcx.allocator(), x->value() / y->value()); + } + } +} + +/* end FloatIntegerOps.cpp */ diff --git a/xo-numeric/src/numeric/FloatOps.cpp b/xo-numeric/src/numeric/FloatOps.cpp new file mode 100644 index 00000000..9db149b9 --- /dev/null +++ b/xo-numeric/src/numeric/FloatOps.cpp @@ -0,0 +1,31 @@ +/** @file FloatOps.cp + * + * @author Roland Conybeare, Feb 2206 + **/ + +#include "FloatOps.hpp" +#include "float/INumeric_DFloat.hpp" + +namespace xo { + using xo::mm::AGCObject; + + namespace scm { + + obj + FloatOps::multiply(obj rcx, + DFloat * x, DFloat * y) + { + return DFloat::box(rcx.allocator(), x->value() * y->value()); + } + + obj + FloatOps::divide(obj rcx, + DFloat * x, DFloat * y) + { + return DFloat::box(rcx.allocator(), x->value() / y->value()); + } + + } +} + +/* end FloatOps.cpp */ diff --git a/xo-numeric/src/numeric/INumeric_DFloat.cpp b/xo-numeric/src/numeric/INumeric_DFloat.cpp new file mode 100644 index 00000000..4024dc04 --- /dev/null +++ b/xo-numeric/src/numeric/INumeric_DFloat.cpp @@ -0,0 +1,22 @@ +/** @file INumeric_DFloat.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/INumeric_DFloat.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/INumeric_DFloat.json5] +**/ + +#include "float/INumeric_DFloat.hpp" + +namespace xo { + namespace scm { + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end INumeric_DFloat.cpp */ diff --git a/xo-numeric/src/numeric/INumeric_DInteger.cpp b/xo-numeric/src/numeric/INumeric_DInteger.cpp new file mode 100644 index 00000000..a4ae6a12 --- /dev/null +++ b/xo-numeric/src/numeric/INumeric_DInteger.cpp @@ -0,0 +1,22 @@ +/** @file INumeric_DInteger.cpp + * + * Generated automagically from ingredients: + * 1. code generator: + * [xo-facet/codegen/genfacet] + * arguments: + * --input [idl/INumeric_DInteger.json5] + * 2. jinja2 template for abstract facet .hpp file: + * [iface_facet_any.hpp.j2] + * 3. idl for facet methods + * [idl/INumeric_DInteger.json5] +**/ + +#include "integer/INumeric_DInteger.hpp" + +namespace xo { + namespace scm { + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end INumeric_DInteger.cpp */ diff --git a/xo-numeric/src/numeric/IntegerOps.cpp b/xo-numeric/src/numeric/IntegerOps.cpp new file mode 100644 index 00000000..c8322266 --- /dev/null +++ b/xo-numeric/src/numeric/IntegerOps.cpp @@ -0,0 +1,31 @@ +/** @file IntegerOps.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "IntegerOps.hpp" +#include "integer/INumeric_DInteger.hpp" + +namespace xo { + using xo::mm::AGCObject; + + namespace scm { + + obj + IntegerOps::multiply(obj rcx, + DInteger * x, DInteger * y) + { + return DInteger::box(rcx.allocator(), x->value() * y->value()); + } + + obj + IntegerOps::divide(obj rcx, + DInteger * x, DInteger * y) + { + return DInteger::box(rcx.allocator(), x->value() / y->value()); + } + + } +} + +/* end IntegerOps.cpp */ diff --git a/xo-numeric/src/numeric/NumericDispatch.cpp b/xo-numeric/src/numeric/NumericDispatch.cpp new file mode 100644 index 00000000..bfc65586 --- /dev/null +++ b/xo-numeric/src/numeric/NumericDispatch.cpp @@ -0,0 +1,59 @@ +/** @file NumericDispatch.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "NumericDispatch.hpp" +#include + +namespace xo { + using xo::mm::AGCObject; + + namespace scm { + + void + NumericDispatch::visit_pools(const MemorySizeVisitor & visitor) + { + dispatch_.visit_pools(visitor); + } + + obj + NumericDispatch::multiply(obj rcx, + obj x, + obj y) + { + KeyType key(x._typeseq(), y._typeseq()); + + auto target_fn + = NumericDispatch::instance().dispatch_[key].multiply_; + + return (*target_fn)(rcx, x.data(), y.data()); + } + + obj + NumericDispatch::divide(obj rcx, + obj x, + obj y) + { + scope log(XO_DEBUG(true)); + + KeyType key(x._typeseq(), y._typeseq()); + + log && log(xtag("x.tseq", x._typeseq().seqno()), + xtag("y.tseq", y._typeseq().seqno())); + + auto target_fn + = NumericDispatch::instance().dispatch_[key].divide_; + + log && log(xtag("target_fn", target_fn)); + + assert(target_fn); + + return (*target_fn)(rcx, x.data(), y.data()); + } + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end NumericDispatch.cpp **/ diff --git a/xo-numeric/src/numeric/NumericPrimitives.cpp b/xo-numeric/src/numeric/NumericPrimitives.cpp new file mode 100644 index 00000000..5666a751 --- /dev/null +++ b/xo-numeric/src/numeric/NumericPrimitives.cpp @@ -0,0 +1,22 @@ +/** @file NumericPrimitives.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "NumericPrimitives.hpp" +#include "NumericDispatch.hpp" + +namespace xo { + using xo::mm::AGCObject; + + namespace scm { + + DPrimitive_gco_2_gco_gco + NumericPrimitives::s_div_gco_gco_pm("_div", + &NumericDispatch::divide); + + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end NumericDispatch.cpp */ diff --git a/xo-numeric/src/numeric/init_numeric.cpp b/xo-numeric/src/numeric/init_numeric.cpp new file mode 100644 index 00000000..1b205585 --- /dev/null +++ b/xo-numeric/src/numeric/init_numeric.cpp @@ -0,0 +1,36 @@ +/** @file init_numeric.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "init_numeric.hpp" +#include +#include "Subsystem.hpp" +#include "numeric_register_facets.hpp" + +namespace xo { + using xo::scm::numeric_register_facets; + + void + InitSubsys::init() + { + numeric_register_facets(); + } + + InitEvidence + InitSubsys::require() + { + InitEvidence retval; + + /* direct subsystem deps for xo-numeric/ */ + retval ^= InitSubsys::require(); + + /* xo-numeric/'s own initialization code */ + retval ^= Subsystem::provide("numeric", &init); + + return retval; + } + +} /*namespace xo*/ + +/* end init_numeric.cpp */ diff --git a/xo-numeric/src/numeric/numeric_register_facets.cpp b/xo-numeric/src/numeric/numeric_register_facets.cpp new file mode 100644 index 00000000..3e2d94a5 --- /dev/null +++ b/xo-numeric/src/numeric/numeric_register_facets.cpp @@ -0,0 +1,61 @@ +/** @file numeric_register_facets.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "numeric_register_facets.hpp" +#include "NumericDispatch.hpp" +#include "Numeric.hpp" + +#include "FloatIntegerOps.hpp" +#include "FloatOps.hpp" +#include "float/INumeric_DFloat.hpp" + +#include "IntegerOps.hpp" +#include "integer/INumeric_DInteger.hpp" + +#include +#include + +#include +#include +#include + +namespace xo { + using xo::facet::FacetRegistry; + using xo::reflect::typeseq; + + namespace scm { + + bool + numeric_register_facets() + { + scope log(XO_DEBUG(true)); + + FacetRegistry::register_impl(); + + NumericDispatch::instance().register_impl + (&FloatOps::multiply, + &FloatOps::divide); + + NumericDispatch::instance().register_impl + (&FloatIntegerOps::multiply, + &FloatIntegerOps::divide); + + NumericDispatch::instance().register_impl + (&IntegerFloatOps::multiply, + &IntegerFloatOps::divide); + + NumericDispatch::instance().register_impl + (&IntegerOps::multiply, + &IntegerOps::divide); + + log && log(xtag("ANumeric.tseq", typeseq::id())); + + return true; + } + + } /*namespace scm*/ +} /*namespace xo*/ + +/* end numeric_register_facets.cpp */ diff --git a/xo-numeric/utest/CMakeLists.txt b/xo-numeric/utest/CMakeLists.txt new file mode 100644 index 00000000..8b714e4a --- /dev/null +++ b/xo-numeric/utest/CMakeLists.txt @@ -0,0 +1,12 @@ +# built unittest xo-numeric/utest + +set(UTEST_EXE utest.numeric) +set(UTEST_SRCS + numeric_utest_main.cpp + Numeric.test.cpp +) + +xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS}) +xo_self_dependency(${UTEST_EXE} xo_numeric) +#xo_dependency(${UTEST_EXE} randomgen) +xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2) diff --git a/xo-numeric/utest/Numeric.test.cpp b/xo-numeric/utest/Numeric.test.cpp new file mode 100644 index 00000000..53a44058 --- /dev/null +++ b/xo-numeric/utest/Numeric.test.cpp @@ -0,0 +1,76 @@ +/** @file Numeric.test.cpp + * + * @author Roland Conybeare, Feb 2026 + **/ + +#include "init_numeric.hpp" +#include "NumericDispatch.hpp" +#include +#include +#include + +namespace xo { + using xo::scm::NumericDispatch; + //using xo::mm::AAllocator; + using xo::mm::DArena; + using xo::mm::ArenaConfig;; + using xo::mm::MemorySizeInfo; + using xo::facet::FacetRegistry; + using xo::facet::TypeRegistry; + //using xo::facet::with_facet; + //using xo::facet::obj; + + namespace ut { + + namespace { + struct Fixture { + explicit Fixture(const std::string & testname, + std::size_t aux_arena_size = 16 * 1024) + : aux_arena_( + ArenaConfig().with_name(testname).with_size(aux_arena_size)) + {} + + + bool log_memory_layout(scope * p_log) { + auto visitor = [p_log](const MemorySizeInfo & info) { + *p_log && (*p_log)(xtag("resource", info.resource_name_), + xtag("used", info.used_), + xtag("alloc", info.allocated_), + xtag("commit", info.committed_), + xtag("resv", info.reserved_)); + }; + + aux_arena_.visit_pools(visitor); + TypeRegistry::instance().visit_pools(visitor); + FacetRegistry::instance().visit_pools(visitor); + NumericDispatch::instance().visit_pools(visitor); + + return true; + } + + DArena aux_arena_; + }; + } /*namespace*/ + + static InitEvidence s_init = (InitSubsys::require()); + + TEST_CASE("Numeric-init" "[numeric]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = true; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + Fixture fixture(testname); + { + // real purpose: ensure s_init sutvives static linking + REQUIRE(s_init.evidence()); + } + + log && fixture.log_memory_layout(&log); + } + + } /*namespace ut*/ +} /*namespace xo*/ + +/* end Numeric.test.cpp */ diff --git a/xo-numeric/utest/numeric_utest_main.cpp b/xo-numeric/utest/numeric_utest_main.cpp new file mode 100644 index 00000000..96d5d0b6 --- /dev/null +++ b/xo-numeric/utest/numeric_utest_main.cpp @@ -0,0 +1,24 @@ +/* file numeric_utest_main.cpp */ + +#include + +#define CATCH_CONFIG_RUNNER +#include "catch2/catch.hpp" + +int +main(int argc, char* argv[]) +{ + using xo::Subsystem; + + // Your custom initialization code here + Subsystem::initialize_all(); + + // Run Catch2's test session + int result = Catch::Session().run(argc, argv); + + // cleanup here, if any + + return result; +} + +/* end numeric_utest_main.cpp */ diff --git a/xo-reader2/cmake/xo_reader2Config.cmake.in b/xo-reader2/cmake/xo_reader2Config.cmake.in index ed161c20..06d291b4 100644 --- a/xo-reader2/cmake/xo_reader2Config.cmake.in +++ b/xo-reader2/cmake/xo_reader2Config.cmake.in @@ -6,6 +6,7 @@ include(CMakeFindDependencyMacro) # must coordinate with xo_dependency() calls # in CMakeLists.txt # +find_dependency(xo_numeric) find_dependency(xo_procedure2) find_dependency(xo_gc) find_dependency(xo_tokenizer2) diff --git a/xo-reader2/src/reader2/CMakeLists.txt b/xo-reader2/src/reader2/CMakeLists.txt index 6ad71cdf..f9c6511c 100644 --- a/xo-reader2/src/reader2/CMakeLists.txt +++ b/xo-reader2/src/reader2/CMakeLists.txt @@ -73,6 +73,7 @@ set(SELF_SRCS xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) # note: deps here must also appear in cmake/xo_expression2Config.cmake.in +xo_dependency(${SELF_LIB} xo_numeric) xo_dependency(${SELF_LIB} xo_procedure2) xo_dependency(${SELF_LIB} xo_gc) xo_dependency(${SELF_LIB} xo_tokenizer2) diff --git a/xo-reader2/src/reader2/DProgressSsm.cpp b/xo-reader2/src/reader2/DProgressSsm.cpp index 72ec3e93..eafe88b8 100644 --- a/xo-reader2/src/reader2/DProgressSsm.cpp +++ b/xo-reader2/src/reader2/DProgressSsm.cpp @@ -12,6 +12,8 @@ #include "ApplySsm.hpp" #include "ParenSsm.hpp" +#include + #include #include @@ -118,15 +120,15 @@ namespace xo { switch (tktype) { case tokentype::tk_assign: return optype::op_assign; - case tokentype::tk_plus: + case tokentype::tk_plus: // [+] return optype::op_add; - case tokentype::tk_minus: + case tokentype::tk_minus: // [-] return optype::op_subtract; - case tokentype::tk_star: + case tokentype::tk_star: // [*] return optype::op_multiply; - case tokentype::tk_slash: + case tokentype::tk_slash: // [/] return optype::op_divide; - case tokentype::tk_cmpeq: + case tokentype::tk_cmpeq: // [==] return optype::op_equal; case tokentype::tk_cmpne: return optype::op_not_equal; @@ -297,12 +299,12 @@ namespace xo { break; case tokentype::tk_star: + case tokentype::tk_slash: case tokentype::tk_minus: case tokentype::tk_cmpeq: this->on_operator_token(tk, p_psm); return; - case tokentype::tk_slash: case tokentype::tk_cmpne: case tokentype::tk_type: case tokentype::tk_lambda: @@ -1283,9 +1285,40 @@ namespace xo { break; case optype::op_divide: - // TODO: implement binary operator expression assembly - assert(false); + { + auto pm_obj = (with_facet::mkobj + (&NumericPrimitives::s_div_gco_gco_pm)); + auto fn_expr = (DConstant::make + (p_psm->expr_alloc(), pm_obj)); + + /* note: + * 1. don't assume we know lhs_ / rhs_ value types yet. + * perhaps have expression like + * f(..) * g(..) + * where f is the function that contains current ssm. + * + * 2. consequence: we need representation for + * polymorphic multiply on unknown numeric arguments. + * + * 3. TypeRef::dwim(..) is a placeholder. + * Plan to later provide abstract interpreter + * (ie compiler pass :) to drive type inference/unification + * + * 4. Alternatively could supply type-annotation syntax + * so human can assist inference; context here is we want + * to automate the boring stuff + */ + + TypeRef tref = TypeRef::dwim + (TypeRef::prefix_type::from_chars("_div_gco"), + nullptr); + + return DApplyExpr::make2(p_psm->expr_alloc(), + tref, fn_expr, lhs_, rhs_); + } + break; + case optype::op_subtract: /* editor bait: op_minus */ { auto pm_obj = (with_facet::mkobj diff --git a/xo-reader2/src/reader2/init_reader2.cpp b/xo-reader2/src/reader2/init_reader2.cpp index aa7e291c..a6e1a7b0 100644 --- a/xo-reader2/src/reader2/init_reader2.cpp +++ b/xo-reader2/src/reader2/init_reader2.cpp @@ -8,6 +8,7 @@ #include "reader2_register_types.hpp" #include +#include #include namespace xo { @@ -30,6 +31,7 @@ namespace xo { /* direct subsystem deps for xo-reader2/ */ retval ^= InitSubsys::require(); + retval ^= InitSubsys::require(); /* xo-reader2/'s own initialization code */ retval ^= Subsystem::provide("reader2", &init); diff --git a/xo-reader2/utest/SchematikaParser.test.cpp b/xo-reader2/utest/SchematikaParser.test.cpp index 2b92161a..b6934f18 100644 --- a/xo-reader2/utest/SchematikaParser.test.cpp +++ b/xo-reader2/utest/SchematikaParser.test.cpp @@ -578,6 +578,67 @@ namespace xo { log && fixture.log_memory_layout(&log); } + TEST_CASE("SchematikaParser-interactive-arith2", "[reader2][SchematikaParser]") + { + const auto & testname = Catch::getResultCapture().getCurrentTestName(); + + constexpr bool c_debug_flag = false; + scope log(XO_DEBUG(c_debug_flag), xtag("test", testname)); + + ParserFixture fixture(testname, c_debug_flag); + auto & parser = *(fixture.parser_); + + parser.begin_interactive_session(); + + /** Walkthrough parsing input equivalent to: + * + * 3.14159265 / 10.0 ; + * + **/ + + std::vector tk_v{ + Token::f64_token("3.14159265"), + Token::slash_token(), + Token::f64_token("10.0"), + Token::semicolon_token(), + }; + + INFO(testname); + + utest_tokenizer_loop(&parser, tk_v, c_debug_flag); + + const auto & result = parser.result(); + { + auto expr = obj::from(result.result_expr()); + REQUIRE(expr); + + REQUIRE(expr->n_args() == 2); + + auto fn = obj::from(expr->fn()); + REQUIRE(fn); + + auto pm = obj::from(fn->value()); + REQUIRE(pm); + REQUIRE(pm->name() == "_div"); + + auto lhs = obj::from(expr->arg(0)); + REQUIRE(lhs); + + auto lhs_f64 = obj::from(lhs->value()); + REQUIRE(lhs_f64); + REQUIRE(lhs_f64->value() == 3.14159265); + + auto rhs = obj::from(expr->arg(1)); + REQUIRE(rhs); + + auto rhs_f64 = obj::from(rhs->value()); + REQUIRE(rhs_f64); + REQUIRE(rhs_f64->value() == 10.0); + } + + log && fixture.log_memory_layout(&log); + } + TEST_CASE("SchematikaParser-interactive-cmp", "[reader2][SchematikaParser]") { const auto & testname = Catch::getResultCapture().getCurrentTestName();