From 37b132821f6c1ecc7e6fb2cbd0ecd0a702526a38 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 19 Nov 2025 21:34:13 -0500 Subject: [PATCH] xo-interpreter: ObjectConverter + VirtualSchmatikaMachineFlyweight --- .../interpreter/VirtualSchematikaMachine.hpp | 11 +- .../interpreter/VirtualSchematikaMachine.cpp | 38 +++--- .../include/xo/object/ObjectConverter.hpp | 112 ++++++++++++++++++ xo-object/src/object/CMakeLists.txt | 1 + xo-object/src/object/ObjectConverter.cpp | 34 ++++++ .../include/xo/reflect/TypeDrivenMap.hpp | 11 +- 6 files changed, 187 insertions(+), 20 deletions(-) create mode 100644 xo-object/include/xo/object/ObjectConverter.hpp create mode 100644 xo-object/src/object/ObjectConverter.cpp diff --git a/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp b/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp index 069233a0..5ce33e29 100644 --- a/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp +++ b/xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp @@ -9,6 +9,12 @@ namespace xo { namespace scm { + /** @brief state that may be shared across VirtualSchematikaMachine instances **/ + struct VirtualSchematikaMachineFlyweight { + /** convert TaggedPtr->Object **/ + ObjectConverter object_converter_; + }; + /** @class VirtualSchematikaMachine * @brief Virtual machine implementing a Schematika interpreter * @@ -34,7 +40,7 @@ namespace xo { /** execute vsm instruction @p pc * Note: may possibly be able to replace with just opcode **/ - void execute_vsm(const VsmInstr * pc); + void execute_one(const VsmInstr * pc); /** implementation class; contains instruction implementations **/ friend class VsmOps; @@ -58,6 +64,9 @@ namespace xo { * (Perhaps replace with VsmInstr::Opcode ?) **/ const VsmInstr * cont_ = nullptr; + + /** possibly-shared data **/ + VirtualSchemtikaMachineFlyweight flyweight_; }; } /*namespace scm*/ diff --git a/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp b/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp index 4df7c4d5..a00eb988 100644 --- a/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp +++ b/xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp @@ -7,7 +7,7 @@ /** continue after completing a VSM instruction; * achieve by jumping to continuation. **/ -//#define VSM_CONTINUE() this->pc_ = this->cont_; return; +#define VSM_CONTINUE() this->pc_ = this->cont_; return; namespace xo { @@ -34,15 +34,28 @@ namespace xo { VirtualSchematikaMachine::VirtualSchematikaMachine() {} + std::pair, + SchematikaError> + VirtualSchematikaMachine::eval(bp expr) + { + this->pc_ = &VsmOps::eval_op; + this->expr_ = expr.promote(); + this->cont_ = &VsmOps::halt_op; + + this->run(); + + return std::make_pair(this->value_, this->error_); + } + void VirtualSchematikaMachine::run() { for (const VsmInstr * pc = pc_; pc; pc = pc_) - this->execute_vsm(pc); + this->execute_one(pc); } void - VirtualSchematikaMachine::execute_vsm(const VsmInstr * instr) + VirtualSchematikaMachine::execute_one(const VsmInstr * instr) { using Opcode = VsmInstr::Opcode; @@ -60,8 +73,11 @@ namespace xo { /* generally speaking: opcode will be 1:1 with extypes */ switch (expr_->extype()) { - case exprtype::invalid: case exprtype::constant: + this->constant_op(); + break; + + case exprtype::invalid: case exprtype::primitive: case exprtype::define: case exprtype::assign: @@ -88,20 +104,12 @@ namespace xo { } } - std::pair, - SchematikaError> - VirtualSchematikaMachine::eval(bp expr) + void + VirtualSchematikaMachine::constant_op() { - this->pc_ = &VsmOps::eval_op; - this->expr_ = expr.promote(); - this->cont_ = &VsmOps::halt_op; - - this->run(); - - return std::make_pair(this->value_, this->error_); + this->value_ = expr_->value_tp(); } - } /*namespace scm*/ } /*namespace xo*/ diff --git a/xo-object/include/xo/object/ObjectConverter.hpp b/xo-object/include/xo/object/ObjectConverter.hpp new file mode 100644 index 00000000..1ab2a2e5 --- /dev/null +++ b/xo-object/include/xo/object/ObjectConverter.hpp @@ -0,0 +1,112 @@ +/** @file ObjectConverter.hpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#pragma once + +#include "Object.hpp" +#include "xo/reflect/Reflect.hpp" +//#include "xo/reflect/TaggedPtr.hpp" +#include "xo/reflect/TypeDrivenMap.hpp" + +namespace xo { + namespace obj { + struct Converter { + using TaggedPtr = xo::reflect::TaggedPtr; + using ConvertToObjectFn = gp (*)(gc::IAlloc *, const TaggedPtr &); + + public: + explicit Converter(ConvertToObjectFn f) : cvt_to_object_{f} {} + + /** convert tagged pointer @p tp to new object, + * allocated via @p mm. + * + * Conversion will typically be for some specific type; + * see @ref ObjectConverter + **/ + ConvertToObjectFn cvt_to_object_; + }; + + /** @class ObjectConverter + * @brief Conversion to/from Object + * + * For some instance of type T: + * + * @code + * ObjectConverter & converters = ...; + * T x = ...; + * TaggedPtr tp = Reflect::make_tp(&x); + * TypeId tid = tp.td()->id(); + * + * const Converter * cvt = converters.cvt_.lookup(tid); + * + * if (cvt) { + * // cvt is a converter for T instances + * gp obj = (*(cvt->cvt_to_object_))(mm, + * @endcode + **/ + class ObjectConverter { + public: + using IAlloc = xo::gc::IAlloc; + + /** sets up standard conversions **/ + ObjectConverter(); + + /** establish conversion: use @p fn to convert values of type @tparam T. **/ + template + void establish_conversion(Converter::ConvertToObjectFn fn); + + /** convert @p x to object. + * return converted object; if allocated, using only memory from @p mm. + * return nullptr if no converter available, and @p throw_flag not set. + * throw exception if no converter available, and @p throw_flag set. + **/ + template + gp to_object(IAlloc * mm, const T & x, bool throw_flag); + + private: + /** expandable type-driven conversion table. + **/ + xo::reflect::TypeDrivenMap cvt_; + }; + + template + void + ObjectConverter::establish_conversion(Converter::ConvertToObjectFn fn) + { + using xo::reflect::TypeDescrW; + using xo::reflect::Reflect; + + TypeDescrW td = Reflect::require(); + Converter * cvt = cvt_.require(td); + + *cvt = Converter(fn); + } + + template + gp + ObjectConverter::to_object(IAlloc * mm, const T & x, bool throw_flag) + { + using xo::reflect::Reflect; + using xo::reflect::TaggedPtr; + + TaggedPtr x_tp = Reflect::make_tp(&x); + Converter * cvt = cvt_.lookup(x_tp.td()); + + if (cvt) { + return (cvt->cvt_to_object_)(mm, x_tp); + } else { + if (throw_flag) { + throw std::runtime_error(tostr("no object-converter available for instance of type", + xtag("id", x_tp.td()->id()), + xtag("name", x_tp.td()->short_name()))); + } + + return nullptr; + } + } + } +} + +/* end ObjectConverter.hpp */ diff --git a/xo-object/src/object/CMakeLists.txt b/xo-object/src/object/CMakeLists.txt index a76cf4c9..0924aa03 100644 --- a/xo-object/src/object/CMakeLists.txt +++ b/xo-object/src/object/CMakeLists.txt @@ -2,6 +2,7 @@ set(SELF_LIB xo_object) set(SELF_SRCS + ObjectConverter.cpp Boolean.cpp String.cpp List.cpp diff --git a/xo-object/src/object/ObjectConverter.cpp b/xo-object/src/object/ObjectConverter.cpp new file mode 100644 index 00000000..b6f4cf26 --- /dev/null +++ b/xo-object/src/object/ObjectConverter.cpp @@ -0,0 +1,34 @@ +/** @file ObjectConverter.cpp + * + * @author Roland Conybeare, Nov 2025 + **/ + +#include "ObjectConverter.hpp" +#include "Integer.hpp" + +namespace xo { + using xo::reflect::TaggedPtr; + using xo::gc::IAlloc; + + namespace obj { + namespace { + template + gp + int_to_object(IAlloc * mm, const TaggedPtr & src) + { + T * native = src.recover_native(); + + assert(native); + + return Integer::make(mm, *native); + } + } + + ObjectConverter::ObjectConverter() + { + this->establish_conversion(&int_to_object); + } + } +} + +/* end ObjectConverter.cpp */ diff --git a/xo-reflect/include/xo/reflect/TypeDrivenMap.hpp b/xo-reflect/include/xo/reflect/TypeDrivenMap.hpp index 3eb42660..d972780f 100644 --- a/xo-reflect/include/xo/reflect/TypeDrivenMap.hpp +++ b/xo-reflect/include/xo/reflect/TypeDrivenMap.hpp @@ -14,21 +14,24 @@ namespace xo { template class TypeDrivenMap { public: - Value const * lookup(TypeId id) const { return this->lookup_slot(id); } + TypeDrivenMap() = default; + + const Value * lookup(TypeId id) const { return this->lookup_slot(id); } + const Value * lookup(TypeDescr td) { return this->lookup_slot(td->id()); } Value * require(TypeId id) { return this->require_slot(id); } Value * require(TypeDescr td) { return this->require_slot(td->id()); } private: - Value const * lookup_slot(TypeId id) const { - if (this->contents_v_.size() <= id.id()) + const Value * lookup_slot(TypeId id) const { + if (contents_v_.size() <= id.id()) return nullptr; return &(this->contents_v_[id.id()]); } /*lookup_slot*/ Value * require_slot(TypeId id) { - if (this->contents_v_.size() <= id.id()) + if (contents_v_.size() <= id.id()) this->contents_v_.resize(id.id() + 1); return &(this->contents_v_[id.id()]);