xo-interpreter2: work towards utest w/ vsm+reader [WIP]

This commit is contained in:
Roland Conybeare 2026-02-01 22:12:28 -05:00
commit 756e8a94cf
26 changed files with 503 additions and 270 deletions

View file

@ -62,6 +62,10 @@ namespace xo {
/** RTTI: unique id# for actual runtime data representation **/
virtual typeseq _typeseq() const noexcept = 0;
/** destroy instance @p d. Calls c++ destructor for actual runtime type.
* does not recover memory.
**/
virtual void _drop(Opaque d) const noexcept = 0;
/** optional name for allocator @p d .
* Allows labeling allocators, for diagnostics/instrumentation.
**/
@ -142,10 +146,12 @@ namespace xo {
virtual value_type alloc_copy(Opaque d, value_type src) const = 0;
/** reset allocator @p d to empty state. **/
virtual void clear(Opaque d) const = 0;
#ifdef OBSOLETE
/** Destruct allocator @p d.
* Releases allocator memory to operating system.
**/
virtual void destruct_data(Opaque d) const = 0;
#endif
///@}
}; /*AAllocator*/

View file

@ -32,7 +32,10 @@ namespace xo {
const AAllocator * iface() const { return std::launder(this); }
// from AAllocator
// builtin methods
typeseq _typeseq() const noexcept override { return s_typeseq; }
void _drop(Opaque) const noexcept override { _fatal(); }
// const methods
[[noreturn]] std::string_view name(Copaque) const noexcept override { _fatal(); }
@ -55,7 +58,6 @@ namespace xo {
[[noreturn]] value_type sub_alloc(Opaque, std::size_t, bool) const override { _fatal(); }
[[noreturn]] value_type alloc_copy(Opaque, value_type) const override { _fatal(); }
[[noreturn]] void clear(Opaque) const override { _fatal(); }
[[noreturn]] void destruct_data(Opaque) const override { _fatal(); }
private:
[[noreturn]] static void _fatal();

View file

@ -36,10 +36,14 @@ namespace xo {
// from AAllocator
// const methods
// builtin methods
/** return typeseq for @tparam DRepr **/
typeseq _typeseq() const noexcept override { return s_typeseq; }
/** invoke native c++ dtor **/
void _drop(Opaque d) const noexcept override { _dcast(d).~DRepr(); }
// const methods
std::string_view name(Copaque d) const noexcept override { return I::name(_dcast(d)); }
size_type reserved(Copaque d) const noexcept override { return I::reserved(_dcast(d)); }
size_type size(Copaque d) const noexcept override { return I::size(_dcast(d)); }
@ -73,7 +77,6 @@ namespace xo {
value_type alloc_copy(Opaque d,
value_type src) const override { return I::alloc_copy(_dcast(d), src); }
void clear(Opaque d) const override { return I::clear(_dcast(d)); }
void destruct_data(Opaque d) const override { return I::destruct_data(_dcast(d)); }
///@}
private:

View file

@ -29,6 +29,7 @@ namespace xo {
RAllocator(Object::DataPtr data) : Object{std::move(data)} {}
typeseq _typeseq() const noexcept { return O::iface()->_typeseq(); }
void _drop() const noexcept { O::iface()->_drop(O::data()); }
std::string_view name() const noexcept { return O::iface()->name(O::data()); }
size_type reserved() const noexcept { return O::iface()->reserved(O::data()); }
size_type size() const noexcept { return O::iface()->size(O::data()); }

View file

@ -39,7 +39,7 @@ namespace ut {
using xo::mm::ACollector;
using xo::mm::AGCObject;
using xo::mm::DX1Collector;
using xo::mm::CollectorConfig;
using xo::mm::X1CollectorConfig;
using xo::mm::ArenaConfig;
using xo::facet::with_facet;
using xo::facet::typeseq;
@ -54,14 +54,13 @@ namespace ut {
REQUIRE(s_init.evidence());
// Create collector
CollectorConfig cfg{
.name_ = "x1_duniquestring_test",
.arena_config_ = ArenaConfig{
.size_ = 8192,
.store_header_flag_ = true},
.object_types_z_ = 16384,
.gc_trigger_v_{{1024, 1024}},
.debug_flag_ = false,
X1CollectorConfig cfg{ .name_ = "x1_duniquestring_test",
.arena_config_ = ArenaConfig{
.size_ = 8192,
.store_header_flag_ = true},
.object_types_z_ = 16384,
.gc_trigger_v_{{1024, 1024}},
.debug_flag_ = false,
};
DX1Collector gc(cfg);

View file

@ -1,74 +0,0 @@
/** @file OUniqueBox.hpp
*
* @author Roland Conybeare, Dec 2025
**/
namespace xo {
namespace facet {
/**
* Uniquely-owned instance with runtime polymorphism.
*
* Reminder that in the facet object model we expect
* objects to be transient.
*
*
* Unlike OUniqueBox<AInterface, ..> can use for variant data
* without additional overhead. Tradeoff is that avoiding such
* overhead excludes std::unique_ptr.
*
* We're going to instead rely on AInterface providing a destruct_data() method,
* so in practice get the deleter from interface state.
*
* Possibly means we need all abstract interfaces to share a common base
*
* Remarks:
* - when @tparam Data is supplied
**/
template <typename AInterface, typename Data = DOpaquePlaceholder>
struct OUniqueBox {
using AbstractInterface = AInterface;
using ISpecific = ISpecificFor<AInterface, Data>::ImplType;
/* note: Data can be void here */
using DataType = Data;
using DataBox = Data*;
explicit OUniqueBox() {}
/* unsatisfactory b/c doesn't enforce that @p d is heap-allocated */
explicit OUniqueBox(DataBox d) : data_{std::move(d)} {}
~OUniqueBox() {
if (data_ != nullptr) {
this->iface()->destruct_data(data_);
delete data_;
this->data_ = nullptr;
}
}
const AInterface * iface() const
requires std::is_same_v<Data, DOpaquePlaceholder>
{
return std::launder(&iface_);
}
const AInterface * iface() const
requires (!std::is_same_v<Data, DOpaquePlaceholder>)
{
return &iface_;
}
/** note: would prefer this to be constexpr, but not simple asof gcc 14.3 **/
static bool _valid;
/** note: load-bearing for routing classes such as RComplex<OUniqueBox> **/
Data * data() const { return data_; }
ISpecific iface_;
DataBox data_ = nullptr;
};
}
} /*namespace xo*/
/* end OUniqueBox.hpp */

View file

@ -0,0 +1,83 @@
/** @file box.hpp
*
* @author Roland Conybeare, Jan 2026
**/
#pragma once
#include "obj.hpp"
namespace xo {
namespace facet {
/** object with owned state
* - with default DRepr argument:
* type-erased container (runtime polymorphism).
* - with sepcific DRepr argument:
* typed container (comptime polymorphism).
**/
template <typename AFacet, typename DRepr = DVariantPlaceholder>
struct box : public RoutingType<AFacet, OObject<AFacet, DRepr>> {
using Super = RoutingType<AFacet, OObject<AFacet, DRepr>>;
box() : Super() {}
/** box takes ownership of data @p *d;
* will destroy when box goes out of scope.
*
* Note this is not useful when DRepr=DVariablePlaceholder
**/
explicit box(Super::DataPtr d) : Super(d) {}
/** Adopt instance that has interface @p iface and (type-erased here)
* representation @p data
**/
box(const AFacet * iface, void * data)
requires std::is_same_v<DRepr, DVariantPlaceholder>
: Super(iface, data)
{}
/** (copy ctor not supported -- ownership is unique) **/
// --------------------------------
/** Move constructor **/
template <typename DOther>
box(box<AFacet, DOther> && other)
requires (std::is_same_v<DRepr, DVariantPlaceholder>
|| std::is_same_v<DRepr, DOther>)
: obj<AFacet,DRepr>()
{
/* replacing .iface_ along w/ .data_ */
this->from_obj(other);
other.reset_opaque(nullptr);
}
/** explicit conversion to obj<AFacet,DRepr> **/
obj<AFacet, DRepr> to_op() const noexcept { return obj<AFacet, DRepr>(this->iface(), this->data()); }
/** Take ownership from unowned object **/
template <typename DOther>
box & adopt(const obj<AFacet, DOther> & other)
requires (std::is_same_v<DRepr, DVariantPlaceholder>
|| std::is_same_v<DRepr, DOther>)
{
/* replace .iface_ along w/ .data_ */
this->from_obj(other);
return *this;
}
~box() {
auto p = this->data();
this->_drop();
::operator delete(p);
}
};
} /*namespace facet*/
using facet::box;
} /*namespace xo*/
/* end box.hpp */

View file

@ -12,9 +12,9 @@
namespace xo {
namespace facet {
/** object with borrowed state pointer
* - With default Data argument:
* - With default DRepr argument:
* type-erased polymorphic container
* - with specific Data argument:
* - with specific DRepr argument:
* typed container. Trivially de-virtualizable
*
* Example:
@ -88,7 +88,7 @@ namespace xo {
* - same strategy for holding state (naked / unique / refcounted ...)
**/
template <typename DOther>
obj(const obj<AFacet, DOther> && other)
obj(obj<AFacet, DOther> && other)
requires (std::is_same_v<DRepr, DVariantPlaceholder>
|| std::is_convertible_v<DRepr, DOther>)
: Super()
@ -98,7 +98,7 @@ namespace xo {
}
obj & operator=(const obj & rhs) {
/* ensure we replace .iface_ along w/ .ata_ */
/* ensure we replace .iface_ along w/ .data_ */
this->from_obj(rhs);
return *this;
}

View file

@ -5,6 +5,7 @@
#pragma once
#include "X1CollectorConfig.hpp"
#include "GCObject.hpp"
#include "generation.hpp"
#include "object_age.hpp"
@ -40,104 +41,6 @@ namespace xo {
};
#endif
struct CollectorConfig {
using size_type = std::size_t;
#ifdef OBSOLETE // get from arena_config_.header_
/*
* alloc header
* TTTTTTTTTTTTGGGGGZZZZZZZZZZZZ
* < tseq ><gen>< size >
*
* masking
*
* ..432107654321076543210 bit
*
* > < .gen_bits
* 0..............01111111 gen_mask_unshifted
* 0..011111110..........0 gen_mask_shifted
* > < gen_shift
*/
//constexpr std::uint64_t gen_mult() const;
constexpr std::uint64_t gen_shift() const;
constexpr std::uint64_t gen_mask_unshifted() const;
constexpr std::uint64_t gen_mask_shifted() const;
//constexpr std::uint64_t tseq_mult() const;
constexpr std::uint64_t tseq_shift() const;
constexpr std::uint64_t tseq_mask_unshifted() const;
constexpr std::uint64_t tseq_mask_shifted() const;
#endif
/** copy of this config,
* with @c arena_config_.size_ set to @p gen_z
**/
CollectorConfig with_size(std::size_t gen_z);
generation age2gen(object_age age) const noexcept {
return generation(age % n_survive_threshold_);
}
public:
// ----- Instance Variables -----
/** optional name, for diagnostics **/
std::string name_;
/** Configuration for collector spaces.
* Will have at least {nursery,tenured} x {from,to} spaces.
* Not using name_ member.
*
* REQUIRE:
* - arena_config_.store_header_flag_ must be true
**/
ArenaConfig arena_config_;
/** storage for N object types requires 8*N bytes **/
std::size_t object_types_z_ = 2*1024*1024;
/** storage for N object roots requires 8*N bytes **/
std::size_t object_roots_z_ = 16*1024;
/** number of bits to represent generation **/
std::uint64_t gen_bits_ = 8;
/** number of bits to represent tseq **/
std::uint64_t tseq_bits_ = 24;
/** Number of generations.
* Must be at least 2.
**/
uint32_t n_generation_ = 2;
/** Number of promotion steps.
* An object that survives this number of collections
* advances to the next generation.
**/
uint32_t n_survive_threshold_ = 2;
/** Trigger garbage collection when to-space allocation for
* generation g reaches gc_trigger_v_[g]
**/
std::array<size_type, c_max_generation> gc_trigger_v_;
/** true -> enable incremental collection.
* false -> only do full collection.
*
* Incremental collection requires mutation logs.
**/
bool allow_incremental_gc_ = true;
/** If non-zero remember statistics for
* the last @p stats_history_z_ collections.
**/
uint32_t stats_history_z_ = false;
/** true to enable debug logging **/
bool debug_flag_ = false;
};
// ----- GCRunState -----
/** @class GCRunState
@ -173,7 +76,7 @@ namespace xo {
static constexpr size_t c_max_typeseq = 4096;
/** Create X1 collector instance. **/
explicit DX1Collector(const CollectorConfig & cfg);
explicit DX1Collector(const X1CollectorConfig & cfg);
/** faceted object pointer to this instance */
template <typename AFacet = AAllocator>
@ -344,7 +247,7 @@ namespace xo {
public:
/** garbage collector configuration **/
CollectorConfig config_;
X1CollectorConfig config_;
/** current gc state **/
GCRunState runstate_;

View file

@ -0,0 +1,92 @@
/** @file X1CollectorConfig.hpp
*
* @author Roland Conybeare, Jan 2026
**/
#pragma once
#include "object_age.hpp"
#include "generation.hpp"
#include <xo/arena/ArenaConfig.hpp>
#include <array>
#include <cstdint>
namespace xo {
namespace mm {
struct X1CollectorConfig {
using size_type = std::size_t;
/** copy of this config,
* with @c arena_config_.size_ set to @p gen_z
**/
X1CollectorConfig with_size(std::size_t gen_z);
generation age2gen(object_age age) const noexcept {
return generation(age % n_survive_threshold_);
}
public:
// ----- Instance Variables -----
/** optional name, for diagnostics **/
std::string name_;
/** Configuration for collector spaces.
* Will have at least {nursery,tenured} x {from,to} spaces.
* Not using name_ member.
*
* REQUIRE:
* - arena_config_.store_header_flag_ must be true
**/
ArenaConfig arena_config_;
/** storage for N object types requires 8*N bytes **/
std::size_t object_types_z_ = 2*1024*1024;
/** storage for N object roots requires 8*N bytes **/
std::size_t object_roots_z_ = 16*1024;
/** number of bits to represent generation **/
std::uint64_t gen_bits_ = 8;
/** number of bits to represent tseq **/
std::uint64_t tseq_bits_ = 24;
/** Number of generations.
* Must be at least 2.
**/
uint32_t n_generation_ = 2;
/** Number of promotion steps.
* An object that survives this number of collections
* advances to the next generation.
**/
uint32_t n_survive_threshold_ = 2;
/** Trigger garbage collection when to-space allocation for
* generation g reaches gc_trigger_v_[g]
**/
std::array<size_type, c_max_generation> gc_trigger_v_;
/** true -> enable incremental collection.
* false -> only do full collection.
*
* Incremental collection requires mutation logs.
**/
bool allow_incremental_gc_ = true;
/** If non-zero remember statistics for
* the last @p stats_history_z_ collections.
**/
uint32_t stats_history_z_ = false;
/** true to enable debug logging **/
bool debug_flag_ = false;
};
} /*namespace mm*/
} /*namespace xo*/
/* end X1CollectorConfig.hpp */

View file

@ -25,24 +25,24 @@ namespace xo {
namespace mm {
CollectorConfig
CollectorConfig::with_size(std::size_t gen_z)
X1CollectorConfig
X1CollectorConfig::with_size(std::size_t gen_z)
{
CollectorConfig copy = *this;
X1CollectorConfig copy = *this;
copy.arena_config_ = arena_config_.with_size(gen_z);
return copy;
}
#ifdef NOT_USING
constexpr std::uint64_t
CollectorConfig::gen_mult() const {
X1CollectorConfig::gen_mult() const {
return 1ul << arena_config_.header_size_bits_;
}
#endif
#ifdef NOT_USING
constexpr std::uint64_t
CollectorConfig::tseq_mult() const {
X1CollectorConfig::tseq_mult() const {
return 1ul << (gen_bits_ + arena_config_.header_size_bits_);
}
#endif
@ -69,7 +69,7 @@ namespace xo {
using size_type = xo::mm::DX1Collector::size_type;
DX1Collector::DX1Collector(const CollectorConfig & cfg) : config_{cfg}
DX1Collector::DX1Collector(const X1CollectorConfig & cfg) : config_{cfg}
{
assert(config_.arena_config_.header_.size_bits_ +
config_.arena_config_.header_.age_bits_ +

View file

@ -23,7 +23,7 @@
namespace xo {
using xo::mm::AAllocator;
using xo::mm::ACollector;
using xo::mm::CollectorConfig;
using xo::mm::X1CollectorConfig;
using xo::mm::DX1Collector;
using xo::mm::ArenaConfig;
using xo::mm::AllocHeaderConfig;
@ -61,12 +61,12 @@ namespace xo {
0 /*tseq_bits*/,
0 /*age_bits*/,
16 /*size_bits*/), };
CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 2,
.gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
X1CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 2,
.gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
DX1Collector gc = DX1Collector{cfg};
@ -109,12 +109,12 @@ namespace xo {
0 /*tseq_bits*/,
0 /*age_bits*/,
16 /*size_bits*/), };
CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 2,
.gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
X1CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 2,
.gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
DX1Collector gc = DX1Collector{cfg};
@ -135,12 +135,12 @@ namespace xo {
0 /*tseq-bits*/,
0 /*age-bits*/,
16 /*size-bits*/), };
CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 2,
.gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
X1CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 2,
.gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
DX1Collector gc = DX1Collector{cfg};
@ -165,12 +165,12 @@ namespace xo {
16 /*size-bits*/), };
/* collector with one generation collapses to a non-generational copying collector */
CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 1,
.gc_trigger_v_ = {{64*1024, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
X1CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 1,
.gc_trigger_v_ = {{64*1024, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
DX1Collector x1state = DX1Collector{cfg};
@ -209,12 +209,12 @@ namespace xo {
};
/* collector with one generation collapses to a non-generational copying collector */
CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 1,
.gc_trigger_v_ = {{64*1024, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
X1CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 1,
.gc_trigger_v_ = {{64*1024, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
/* X1 allocator+collector */
DX1Collector x1state = DX1Collector{cfg};

View file

@ -24,7 +24,7 @@ namespace xo {
using xo::mm::DX1CollectorIterator;
using xo::mm::DArena;
using xo::mm::DArenaIterator;
using xo::mm::CollectorConfig;
using xo::mm::X1CollectorConfig;
using xo::mm::ArenaConfig;
using xo::mm::AllocHeaderConfig;
using xo::mm::cmpresult;
@ -51,12 +51,12 @@ namespace xo {
0 /*tseq_bits*/,
0 /*age_bits*/,
16 /*size_bits*/), };
CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 2,
.gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
X1CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 2,
.gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
DX1Collector gc = DX1Collector{cfg};
@ -94,12 +94,12 @@ namespace xo {
0 /*tseq_bits*/,
0 /*age_bits*/,
16 /*size_bits*/), };
CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 2,
.gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
X1CollectorConfig cfg = { .arena_config_ = arena_cfg,
.n_generation_ = 2,
.gc_trigger_v_ = {{64*1024, 1024*1024, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0}} };
DX1Collector gc = DX1Collector{cfg};
obj<AAllocator, DX1Collector> a1o{&gc};

View file

@ -21,7 +21,7 @@ add_definitions(${PROJECT_CXX_FLAGS})
# output targets
add_subdirectory(src/interpreter2)
#add_subdirectory(utest)
add_subdirectory(utest)
xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets)

View file

@ -5,9 +5,12 @@
#pragma once
#include "VsmConfig.hpp"
#include "VsmInstr.hpp"
#include <xo/reader2/SchematikaReader.hpp>
#include <xo/expression2/Expression.hpp>
#include <xo/gc/GCObject.hpp>
#include <xo/facet/box.hpp>
namespace xo {
namespace scm {
@ -18,10 +21,11 @@ namespace xo {
public:
// will be DArenaVector<obj<StackFrame>> probably
using Stack = void *;
using AAllocator = xo::mm::AAllocator;
using AGCObject = xo::mm::AGCObject;
public:
VirtualSchematikaMachine();
VirtualSchematikaMachine(const VsmConfig & config);
/** borrow calling thread to run indefinitely,
* until halt instruction
@ -93,6 +97,14 @@ namespace xo {
* value_
*/
/** configuration **/
VsmConfig config_;
box<AAllocator> mm_;
/** reader: text -> expression **/
SchematikaReader reader_;
/** program counter **/
VsmInstr pc_ = VsmInstr::halt();

View file

@ -0,0 +1,28 @@
/** @file VsmConfig.hpp
*
* @author Roland Conybeare, Jan 2026
**/
#pragma once
#include <xo/reader2/ReaderConfig.hpp>
#include <xo/gc/X1CollectorConfig.hpp>
namespace xo {
namespace scm {
/** Configuration for virtual schematika machine
**/
struct VsmConfig {
using X1CollectorConfig = xo::mm::X1CollectorConfig;
/** reader configuration **/
ReaderConfig rdr_config_;
/** Configuration for allocator/collector.
* TODO: may want to make CollectorConfig polymorphic
**/
X1CollectorConfig x1_config_ = X1CollectorConfig().with_size(4*1024*1024);
};
} /*namespace scm*/
} /*namespace xo*/
/* end VsmConfig.hpp */

View file

@ -0,0 +1,21 @@
/** @file init_interpreter2.hpp
*
* @author Roland Conybeare, Jan 2026
**/
#pragma once
#include <xo/subsys/Subsystem.hpp>
namespace xo {
/* tag to represent the xo-interpreter2/ subsystem within ordered initialization */
enum S_interpreter2_tag {};
template <>
struct InitSubsys<S_interpreter2_tag> {
static void init();
static InitEvidence require();
};
} /*namespace xo*/
/* end init_interpreter2.hpp */

View file

@ -2,6 +2,7 @@
set(SELF_LIB xo_interpreter2)
set(SELF_SRCS
init_interpreter2.cpp
VirtualSchematikaMachine.cpp
#IExpression_Any.cpp
#interpreter2_register_facets.cpp
@ -9,7 +10,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_interpreter2Config.cmake.in
xo_dependency(${SELF_LIB} xo_expression2)
xo_dependency(${SELF_LIB} xo_reader2)
xo_dependency(${SELF_LIB} xo_gc)
#xo_dependency(${SELF_LIB} reflect)
#xo_dependency(${SELF_LIB} xo_printable2)

View file

@ -6,12 +6,19 @@
#include "VirtualSchematikaMachine.hpp"
#include <xo/expression2/detail/IExpression_DConstant.hpp>
#include <xo/expression2/DConstant.hpp>
#include <xo/gc/DX1Collector.hpp>
#include <xo/gc/detail/IAllocator_DX1Collector.hpp>
#include <cassert>
namespace xo {
using xo::mm::DX1Collector;
namespace scm {
VirtualSchematikaMachine::VirtualSchematikaMachine()
VirtualSchematikaMachine::VirtualSchematikaMachine(const VsmConfig & config)
: config_{config},
mm_(box<AAllocator,DX1Collector>(new DX1Collector(config.x1_config_))),
reader_{config.rdr_config_, mm_.to_op()}
{}
void

View file

@ -0,0 +1,50 @@
/** @file init_interpreter2.cpp
*
* @author Roland Conybeare, Jan 2026
**/
#include "init_interpreter2.hpp"
#ifdef NOT_YET
#include "interpreter2_register_facets.hpp"
#include "interpreter2_register_types.hpp"
#endif
#include <xo/reader2/init_reader2.hpp>
#ifdef NOT_YET
#include <xo/gc/CollectorTypeRegistry.hpp>
#endif
namespace xo {
#ifdef NOT_YET
using xo::scm::interpreter2_register_facets;
using xo::scm::interpreter2_register_types;
using xo::mm::CollectorTypeRegistry;
#endif
void
InitSubsys<S_interpreter2_tag>::init()
{
#ifdef NOT_YET
interpreter2_register_facets();
CollectorTypeRegistry::instance().register_types(&interpreter2_register_types);
#endif
}
InitEvidence
InitSubsys<S_interpreter2_tag>::require()
{
InitEvidence retval;
/* direct subsystem deps for xo-interpreter2/ */
retval ^= InitSubsys<S_reader2_tag>::require();
/* xo-interpreter2/'s own initialization code */
retval ^= Subsystem::provide<S_interpreter2_tag>("interpreter2", &init);
return retval;
}
} /*namespace xo*/
/* end init_interpreter2.cpp */

View file

@ -0,0 +1,11 @@
# build unittest xo-interpreter2/utest
set(UTEST_EXE utest.interpreter2)
set(UTEST_SRCS
interpreter2_utest_main.cpp
VirtualSchematikaMachine.test.cpp
)
xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS})
xo_self_dependency(${UTEST_EXE} xo_interpreter2)
xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2)

View file

@ -0,0 +1,63 @@
/** @file VirtualSchematikaMachine.test.cpp
*
* @author Roland Conybeare, Jan 2026
**/
#include <xo/interpreter2/VirtualSchematikaMachine.hpp>
#ifdef NOT_YET
#include <xo/reader2/SchematikaParser.hpp>
#include <xo/reader2/DDefineSsm.hpp>
#include <xo/reader2/DExpectExprSsm.hpp>
#include <xo/reader2/ssm/ISyntaxStateMachine_DExpectExprSsm.hpp>
#include <xo/reader2/ssm/ISyntaxStateMachine_DDefineSsm.hpp>
#endif
#include <xo/interpreter2/init_interpreter2.hpp>
#ifdef NOT_YET
#include <xo/alloc2/arena/IAllocator_DArena.hpp>
#endif
#include <catch2/catch.hpp>
namespace xo {
#ifdef NOT_YET
using xo::scm::SchematikaParser;
using xo::scm::ASyntaxStateMachine;
using xo::scm::syntaxstatetype;
// using xo::scm::DDefineSsm;
using xo::scm::DExpectExprSsm;
// using xo::scm::defexprstatetype;
//using xo::scm::ParserResult;
//using xo::scm::parser_result_type;
using xo::scm::Token;
using xo::scm::DString;
using xo::mm::ArenaConfig;
using xo::mm::AAllocator;
using xo::mm::DArena;
using xo::facet::with_facet;
#endif
static InitEvidence s_init = (InitSubsys<S_interpreter2_tag>::require());
namespace ut {
TEST_CASE("VirtualSchematikaMachine-ctor", "[interpreter2][VSM]")
{
#ifdef NOT_YET
ArenaConfig config;
config.name_ = "test-arena";
config.size_ = 16 * 1024;
DArena expr_arena = DArena::map(config);
obj<AAllocator> expr_alloc = with_facet<AAllocator>::mkobj(&expr_arena);
SchematikaParser parser(config, 4096, expr_alloc, false /*debug_flag*/);
REQUIRE(parser.debug_flag() == false);
REQUIRE(parser.is_at_toplevel() == true);
#endif
}
} /*namespace ut*/
} /*namespace xo*/
/* end SchematikaParser.test.cpp */

View file

@ -0,0 +1,27 @@
/** @file interpreter2_utest_main.cpp
*
* @author Roland Conybeare, Jan 2026
**/
#include <xo/subsys/Subsystem.hpp>
#define CATCH_CONFIG_RUNNER
#include "catch2/catch.hpp"
int
main(int argc, char* argv[])
{
using xo::Subsystem;
// initialize subsystems
Subsystem::initialize_all();
// Run Catch2's test session
int result = Catch::Session().run(argc, argv);
// cleanup here, if any
return result;
}
/* end interpreter2_utest_main.cpp */

View file

@ -44,7 +44,7 @@ namespace ut {
using xo::mm::ACollector;
using xo::mm::AGCObject;
using xo::mm::DX1Collector;
using xo::mm::CollectorConfig;
using xo::mm::X1CollectorConfig;
using xo::mm::ArenaConfig;
using xo::print::APrintable;
using xo::facet::FacetRegistry;
@ -99,15 +99,14 @@ namespace ut {
try {
const testcase_pp & tc = s_testcase_v[i_tc];
CollectorConfig cfg{
.name_ = "pp_test",
.arena_config_ = ArenaConfig{
.size_ = tc.gc_gen_size_,
.store_header_flag_ = true},
.object_types_z_ = 16384,
.gc_trigger_v_{{tc.gc_trigger_threshold_,
tc.gc_trigger_threshold_}},
.debug_flag_ = c_debug_flag
X1CollectorConfig cfg{ .name_ = "pp_test",
.arena_config_ = ArenaConfig{
.size_ = tc.gc_gen_size_,
.store_header_flag_ = true},
.object_types_z_ = 16384,
.gc_trigger_v_{{tc.gc_trigger_threshold_,
tc.gc_trigger_threshold_}},
.debug_flag_ = c_debug_flag
};
DX1Collector gc(cfg);

View file

@ -48,7 +48,7 @@ namespace ut {
using xo::mm::AGCObject;
using xo::mm::DX1Collector;
using xo::mm::DArena;
using xo::mm::CollectorConfig;
using xo::mm::X1CollectorConfig;
using xo::mm::ArenaConfig;
using xo::mm::generation;
using xo::mm::role;
@ -108,16 +108,15 @@ namespace ut {
try {
const testcase_x1 & tc = s_testcase_v[i_tc];
CollectorConfig cfg{
.name_ = "x1_test",
.arena_config_ = ArenaConfig{
.size_ = tc.tenured_z_,
.store_header_flag_ = true},
.object_types_z_ = 16384,
.gc_trigger_v_{{
tc.incr_gc_threshold_,
tc.full_gc_threshold_}},
.debug_flag_ = c_debug_flag,
X1CollectorConfig cfg{ .name_ = "x1_test",
.arena_config_ = ArenaConfig{
.size_ = tc.tenured_z_,
.store_header_flag_ = true},
.object_types_z_ = 16384,
.gc_trigger_v_{{
tc.incr_gc_threshold_,
tc.full_gc_threshold_}},
.debug_flag_ = c_debug_flag,
};
DX1Collector gc(cfg);

View file

@ -136,7 +136,7 @@ namespace {
struct AppConfig {
using ReaderConfig = xo::scm::ReaderConfig;
using CollectorConfig = xo::mm::CollectorConfig;
using X1CollectorConfig = xo::mm::X1CollectorConfig;
AppConfig() {
rdr_config_.reader_debug_flag_ = true;
@ -146,17 +146,17 @@ struct AppConfig {
std::size_t max_history_size_ = 1000;
std::string repl_history_fname_ = "repl_history.txt";;
CollectorConfig x1_config_ = (CollectorConfig().with_size(4*1024*1024));
ReaderConfig rdr_config_;
X1CollectorConfig x1_config_ = (X1CollectorConfig().with_size(4*1024*1024));
};
struct AppContext {
using DX1Collector = xo::mm::DX1Collector;
using CollectorConfig = xo::mm::CollectorConfig;
using X1CollectorConfig = xo::mm::X1CollectorConfig;
using Replxx = replxx::Replxx;
AppContext(const AppConfig & cfg = AppConfig()) : config_{cfg},
x1_{CollectorConfig().with_size(4*1024*1024)},
x1_{X1CollectorConfig().with_size(4*1024*1024)},
rdr_{config_.rdr_config_, x1_.ref()}
{
rx_.set_max_history_size(config_.max_history_size_);